• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2 *
3 * SPDX-License-Identifier: GPL-2.0
4 *
5 * Copyright (C) 2011-2018 ARM or its affiliates
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; version 2.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 *
18 */
19 
20 #include <linux/kernel.h>
21 #include <linux/compat.h>
22 #include <linux/slab.h>
23 #include <linux/mm.h>
24 #include <linux/fs.h>
25 #include <linux/miscdevice.h>
26 #include <linux/uaccess.h>
27 #include <linux/kfifo.h>
28 #include <linux/sched.h>
29 #include <linux/wait.h>
30 #include "acamera_logger.h"
31 #include "system_stdlib.h"
32 #include "acamera_command_api.h"
33 #include "acamera_ctrl_channel.h"
34 #include "acamera_3aalg_preset.h"
35 
36 #define CTRL_CHANNEL_FIFO_INPUT_SIZE ( 4 * 1024 )
37 #define CTRL_CHANNEL_FIFO_OUTPUT_SIZE ( 8 * 1024 )
38 
39 struct ctrl_channel_dev_context {
40     uint8_t dev_inited;
41     int dev_minor_id;
42     char *dev_name;
43     int dev_opened;
44 
45     struct miscdevice ctrl_dev;
46     struct mutex fops_lock;
47 
48     struct kfifo ctrl_kfifo_in;
49     struct kfifo ctrl_kfifo_out;
50 
51     struct ctrl_cmd_item cmd_item;
52 
53 	isp_ae_preset_t ae_param;
54 	isp_awb_preset_t awb_param;
55 	isp_gamma_preset_t gamma_param;
56 	isp_iridix_preset_t iridix_param;
57 };
58 
59 static struct ctrl_channel_dev_context ctrl_channel_ctx;
60 
ctrl_channel_fops_open(struct inode * inode,struct file * f)61 static int ctrl_channel_fops_open( struct inode *inode, struct file *f )
62 {
63     int rc;
64     struct ctrl_channel_dev_context *p_ctx = &ctrl_channel_ctx;
65     int minor = iminor( inode );
66 
67     LOG( LOG_DEBUG, "client is opening..., minor: %d.", minor );
68 
69     if ( minor != p_ctx->dev_minor_id ) {
70         LOG( LOG_CRIT, "Not matched ID, minor_id: %d, exptect: %d(dev name: %s)", minor, p_ctx->dev_minor_id, p_ctx->dev_name );
71         return -ERESTARTSYS;
72     }
73 
74     rc = mutex_lock_interruptible( &p_ctx->fops_lock );
75     if ( rc ) {
76         LOG( LOG_ERR, "Error: lock failed of dev: %s.", p_ctx->dev_name );
77         goto lock_failure;
78     }
79 
80     if ( p_ctx->dev_opened ) {
81         LOG( LOG_ERR, "open(%s) failed, already opened.", p_ctx->dev_name );
82         rc = -EBUSY;
83     } else {
84         p_ctx->dev_opened = 1;
85         rc = 0;
86         f->private_data = p_ctx;
87     }
88 
89     mutex_unlock( &p_ctx->fops_lock );
90 
91 lock_failure:
92     return rc;
93 }
94 
ctrl_channel_fops_release(struct inode * inode,struct file * f)95 static int ctrl_channel_fops_release( struct inode *inode, struct file *f )
96 {
97     int rc;
98     struct ctrl_channel_dev_context *p_ctx = (struct ctrl_channel_dev_context *)f->private_data;
99 
100     if ( p_ctx != &ctrl_channel_ctx ) {
101         LOG( LOG_ERR, "Inalid paramter: %p, exptected: %p.", p_ctx, &ctrl_channel_ctx );
102         return -EINVAL;
103     }
104 
105     rc = mutex_lock_interruptible( &p_ctx->fops_lock );
106     if ( rc ) {
107         LOG( LOG_ERR, "Error: lock failed of dev: %s.", p_ctx->dev_name );
108         return rc;
109     }
110 
111     if ( p_ctx->dev_opened ) {
112         p_ctx->dev_opened = 0;
113         f->private_data = NULL;
114         kfifo_reset( &p_ctx->ctrl_kfifo_in );
115         kfifo_reset( &p_ctx->ctrl_kfifo_out );
116         LOG( LOG_DEBUG, "close(%s) succeed, private_data: %p.", p_ctx->dev_name, p_ctx );
117     } else {
118         LOG( LOG_CRIT, "Fatal error: wrong state of dev: %s, dev_opened: %d.", p_ctx->dev_name, p_ctx->dev_opened );
119         rc = -EINVAL;
120     }
121 
122     mutex_unlock( &p_ctx->fops_lock );
123 
124     return 0;
125 }
126 
ctrl_channel_fops_write(struct file * file,const char __user * buf,size_t count,loff_t * ppos)127 static ssize_t ctrl_channel_fops_write( struct file *file, const char __user *buf, size_t count, loff_t *ppos )
128 {
129     int rc;
130     unsigned int copied;
131     struct ctrl_channel_dev_context *p_ctx = (struct ctrl_channel_dev_context *)file->private_data;
132 
133     if ( p_ctx != &ctrl_channel_ctx ) {
134         LOG( LOG_ERR, "Inalid paramter: %p, exptected: %p.", p_ctx, &ctrl_channel_ctx );
135         return -EINVAL;
136     }
137 
138     if ( mutex_lock_interruptible( &p_ctx->fops_lock ) ) {
139         LOG( LOG_CRIT, "Fatal error: access lock failed." );
140         return -ERESTARTSYS;
141     }
142 
143     rc = kfifo_from_user( &p_ctx->ctrl_kfifo_in, buf, count, &copied );
144 
145     mutex_unlock( &p_ctx->fops_lock );
146 
147     LOG( LOG_DEBUG, "wake up reader." );
148 
149     return rc ? rc : copied;
150 }
151 
ctrl_channel_fops_read(struct file * file,char __user * buf,size_t count,loff_t * ppos)152 static ssize_t ctrl_channel_fops_read( struct file *file, char __user *buf, size_t count, loff_t *ppos )
153 {
154     int rc = 0;
155     unsigned int copied = 0;
156     struct ctrl_channel_dev_context *p_ctx = (struct ctrl_channel_dev_context *)file->private_data;
157 
158     if ( p_ctx != &ctrl_channel_ctx ) {
159         LOG( LOG_ERR, "Inalid paramter: %p, exptected: %p.", p_ctx, &ctrl_channel_ctx );
160         return -EINVAL;
161     }
162 
163     if ( mutex_lock_interruptible( &p_ctx->fops_lock ) ) {
164         LOG( LOG_CRIT, "Fatal error: access lock failed." );
165         return -ERESTARTSYS;
166     }
167 
168     if ( !kfifo_is_empty( &p_ctx->ctrl_kfifo_out ) ) {
169         rc = kfifo_to_user( &p_ctx->ctrl_kfifo_out, buf, count, &copied );
170     }
171 
172     mutex_unlock( &p_ctx->fops_lock );
173 
174     return rc ? rc : copied;
175 }
176 
ctrl_channel_fops_ioctl(struct file * pfile,unsigned int cmd,unsigned long args)177 long ctrl_channel_fops_ioctl (struct file *pfile, unsigned int cmd, unsigned long args)
178 {
179     int rc;
180 
181 	switch (cmd)
182 	{
183 		case IOCTL_3AALG_AEPRE:
184 			rc = copy_to_user((void *)args, &ctrl_channel_ctx.ae_param, sizeof(isp_ae_preset_t));
185 			if ( rc ) {
186                  LOG( LOG_CRIT, "ae copy_to_user failed, rc: %d.", rc );
187             }
188 			break;
189 		case IOCTL_3AALG_AWBPRE:
190 			rc = copy_to_user((void *)args, &ctrl_channel_ctx.awb_param, sizeof(isp_awb_preset_t));
191 			if ( rc ) {
192                  LOG( LOG_CRIT, "awb copy_to_user failed, rc: %d.", rc );
193             }
194 			break;
195 		case IOCTL_3AALG_GAMMAPRE:
196 			rc = copy_to_user((void *)args, &ctrl_channel_ctx.gamma_param, sizeof(isp_gamma_preset_t));
197 			if ( rc ) {
198                  LOG( LOG_CRIT, "gamma copy_to_user failed, rc: %d.", rc );
199             }
200 			break;
201 		case IOCTL_3AALG_IRIDIXPRE:
202 			rc = copy_to_user((void *)args, &ctrl_channel_ctx.iridix_param, sizeof(isp_iridix_preset_t));
203 			if ( rc ) {
204                  LOG( LOG_CRIT, "iridix copy_to_user failed, rc: %d.", rc );
205             }
206 			break;
207 		default:
208 		    LOG(LOG_CRIT, "invalid cmd");
209 		    break;
210 	}
211 
212     return 0;
213 }
214 
215 #ifdef CONFIG_COMPAT
ctrl_compat_ioctl(struct file * pfile,unsigned int cmd,unsigned long args)216 long ctrl_compat_ioctl (struct file *pfile, unsigned int cmd, unsigned long args)
217 {
218 	int rc;
219 	void  *arg64 = compat_ptr(args);
220 
221 	switch (cmd)
222 	{
223 		case IOCTL_3AALG_AEPRE:
224 			rc = copy_to_user((void *)arg64, &ctrl_channel_ctx.ae_param, sizeof(isp_ae_preset_t));
225 			if ( rc ) {
226                  LOG( LOG_CRIT, "ae copy_to_user failed, rc: %d.", rc );
227             }
228 			break;
229 		case IOCTL_3AALG_AWBPRE:
230 			rc = copy_to_user((void *)arg64, &ctrl_channel_ctx.awb_param, sizeof(isp_awb_preset_t));
231 			if ( rc ) {
232                  LOG( LOG_CRIT, "awb copy_to_user failed, rc: %d.", rc );
233             }
234 			break;
235 		case IOCTL_3AALG_GAMMAPRE:
236 			rc = copy_to_user((void *)arg64, &ctrl_channel_ctx.gamma_param, sizeof(isp_gamma_preset_t));
237 			if ( rc ) {
238                  LOG( LOG_CRIT, "gamma copy_to_user failed, rc: %d.", rc );
239             }
240 			break;
241 		case IOCTL_3AALG_IRIDIXPRE:
242 			rc = copy_to_user((void *)arg64, &ctrl_channel_ctx.iridix_param, sizeof(isp_iridix_preset_t));
243 			if ( rc ) {
244                  LOG( LOG_CRIT, "iridix copy_to_user failed, rc: %d.", rc );
245             }
246 			break;
247 		default:
248 		    LOG(LOG_CRIT, "invalid cmd");
249 		    break;
250 	}
251 
252     return 0;
253 }
254 #endif
255 
ctrl_channel_3aalg_param_init(isp_ae_preset_t * ae,isp_awb_preset_t * awb,isp_gamma_preset_t * gamma,isp_iridix_preset_t * iridix)256 int ctrl_channel_3aalg_param_init(isp_ae_preset_t *ae, isp_awb_preset_t *awb, isp_gamma_preset_t *gamma, isp_iridix_preset_t *iridix)
257 {
258     system_memcpy(&ctrl_channel_ctx.ae_param, ae, sizeof(isp_ae_preset_t));
259 	system_memcpy(&ctrl_channel_ctx.awb_param, awb, sizeof(isp_awb_preset_t));
260 	system_memcpy(&ctrl_channel_ctx.gamma_param, gamma, sizeof(isp_gamma_preset_t));
261 	system_memcpy(&ctrl_channel_ctx.iridix_param, iridix, sizeof(isp_iridix_preset_t));
262 
263 	LOG(LOG_INFO, "ctrl_channel_3aalg_param_init: %d,%d,%d,%d,%d",ctrl_channel_ctx.ae_param.exposure_log2,\
264 		ctrl_channel_ctx.ae_param.integrator,ctrl_channel_ctx.ae_param.error_log2,ctrl_channel_ctx.iridix_param.strength_target,ctrl_channel_ctx.iridix_param.iridix_global_DG);
265 
266 	return 0;
267 }
268 
269 static struct file_operations isp_fops = {
270     .owner = THIS_MODULE,
271     .open = ctrl_channel_fops_open,
272     .release = ctrl_channel_fops_release,
273     .read = ctrl_channel_fops_read,
274     .write = ctrl_channel_fops_write,
275     .unlocked_ioctl = ctrl_channel_fops_ioctl,
276 #ifdef CONFIG_COMPAT
277 	.compat_ioctl = ctrl_compat_ioctl,
278 #endif
279     .llseek = noop_llseek,
280 };
281 
282 #if defined( CTRL_CHANNEL_BIDIRECTION )
ctrl_channel_read(char * data,int size)283 int ctrl_channel_read( char *data, int size )
284 {
285     int rc = 0;
286 
287     if ( !ctrl_channel_ctx.dev_inited ) {
288         LOG( LOG_ERR, "dev is not inited, failed to read." );
289         return -1;
290     }
291 
292     mutex_lock( &ctrl_channel_ctx.fops_lock );
293 
294     if ( !kfifo_is_empty( &ctrl_channel_ctx.ctrl_kfifo_in ) ) {
295         rc = kfifo_out( &ctrl_channel_ctx.ctrl_kfifo_in, data, size );
296     }
297 
298     mutex_unlock( &ctrl_channel_ctx.fops_lock );
299 
300     return rc;
301 }
302 #endif
303 
ctrl_channel_write(const struct ctrl_cmd_item * p_cmd,const void * data,uint32_t data_size)304 static int ctrl_channel_write( const struct ctrl_cmd_item *p_cmd, const void *data, uint32_t data_size )
305 {
306     int rc;
307 
308     if ( !ctrl_channel_ctx.dev_inited ) {
309         LOG( LOG_ERR, "dev is not inited, failed to write." );
310         return -1;
311     }
312 
313     mutex_lock( &ctrl_channel_ctx.fops_lock );
314 
315     rc = kfifo_in( &ctrl_channel_ctx.ctrl_kfifo_out, p_cmd, sizeof( struct ctrl_cmd_item ) );
316     if ( data )
317         kfifo_in( &ctrl_channel_ctx.ctrl_kfifo_out, data, data_size );
318 
319     mutex_unlock( &ctrl_channel_ctx.fops_lock );
320 
321     return rc;
322 }
323 
ctrl_channel_init(void)324 int ctrl_channel_init( void )
325 {
326     int rc;
327 
328     memset( &ctrl_channel_ctx, 0, sizeof( ctrl_channel_ctx ) );
329     ctrl_channel_ctx.ctrl_dev.name = CTRL_CHANNEL_DEV_NAME;
330     ctrl_channel_ctx.dev_name = CTRL_CHANNEL_DEV_NAME;
331     ctrl_channel_ctx.ctrl_dev.minor = MISC_DYNAMIC_MINOR;
332     ctrl_channel_ctx.ctrl_dev.fops = &isp_fops;
333 
334     rc = misc_register( &ctrl_channel_ctx.ctrl_dev );
335     if ( rc ) {
336         LOG( LOG_ERR, "Error: register ISP ctrl channel device failed, ret: %d.", rc );
337         return rc;
338     }
339 
340     ctrl_channel_ctx.dev_minor_id = ctrl_channel_ctx.ctrl_dev.minor;
341     mutex_init( &ctrl_channel_ctx.fops_lock );
342 
343     rc = kfifo_alloc( &ctrl_channel_ctx.ctrl_kfifo_in, CTRL_CHANNEL_FIFO_INPUT_SIZE, GFP_KERNEL );
344     if ( rc ) {
345         LOG( LOG_ERR, "Error: kfifo_in alloc failed, ret: %d.", rc );
346         goto failed_kfifo_in_alloc;
347     }
348 
349     rc = kfifo_alloc( &ctrl_channel_ctx.ctrl_kfifo_out, CTRL_CHANNEL_FIFO_OUTPUT_SIZE, GFP_KERNEL );
350     if ( rc ) {
351         LOG( LOG_ERR, "Error: kfifo_out alloc failed, ret: %d.", rc );
352         goto failed_kfifo_out_alloc;
353     }
354 
355     ctrl_channel_ctx.dev_inited = 1;
356 
357     return 0;
358 
359 failed_kfifo_out_alloc:
360     kfifo_free( &ctrl_channel_ctx.ctrl_kfifo_in );
361 failed_kfifo_in_alloc:
362     misc_deregister( &ctrl_channel_ctx.ctrl_dev );
363 
364     LOG( LOG_ERR, "Error: init failed for dev: %s.", ctrl_channel_ctx.ctrl_dev.name );
365     return rc;
366 }
367 
ctrl_channel_deinit(void)368 void ctrl_channel_deinit( void )
369 {
370     if ( ctrl_channel_ctx.dev_inited ) {
371         kfifo_free( &ctrl_channel_ctx.ctrl_kfifo_in );
372 
373         kfifo_free( &ctrl_channel_ctx.ctrl_kfifo_out );
374 
375         misc_deregister( &ctrl_channel_ctx.ctrl_dev );
376     } else {
377         LOG( LOG_DEBUG, "dev not inited, do nothing." );
378     }
379 }
380 
is_uf_needed_command(uint8_t command_type,uint8_t command,uint8_t direction)381 static uint8_t is_uf_needed_command( uint8_t command_type, uint8_t command, uint8_t direction )
382 {
383     uint8_t rc = 0;
384 
385     // we only support SET in user-FW.
386     if ( COMMAND_GET == direction )
387         return rc;
388 
389     switch ( command_type ) {
390 #ifdef TALGORITHMS
391     case TALGORITHMS:
392         LOG( LOG_DEBUG, "TALGORITHMS is supported, cmd_type: %u, cmd: %u, direction: %u",
393              command_type, command, direction );
394         rc = 1;
395         break;
396 #endif
397 
398 #ifdef TGENERAL
399     case TGENERAL:
400         switch ( command ) {
401         case ACTIVE_CONTEXT:
402             LOG( LOG_DEBUG, "TGENERAL is supported, cmd_type: %u, cmd: %u, direction: %u",
403                  command_type, command, direction );
404             rc = 1;
405             break;
406         }
407 
408         break;
409 #endif
410 
411 #ifdef TSENSOR
412     case TSENSOR:
413         LOG( LOG_DEBUG, "TSENSOR is supported, cmd_type: %u, cmd: %u, direction: %u",
414              command_type, command, direction );
415         rc = 1;
416         break;
417 #endif
418 
419 #ifdef TSYSTEM
420     case TSYSTEM:
421 
422         if ( command != SYSTEM_FREEZE_FIRMWARE ) {
423             rc = 1;
424             LOG( LOG_DEBUG, "TSYSTEM is supported, cmd_type: %u, cmd: %u, direction: %u",
425                  command_type, command, direction );
426         } else {
427             LOG( LOG_INFO, "SYSTEM_FREEZE_FIRMWARE is not needed" );
428         }
429 
430         break;
431 #endif
432 
433 #ifdef TSCENE_MODES
434     case TSCENE_MODES:
435         LOG( LOG_DEBUG, "TSCENE_MODES is supported, cmd_type: %u, cmd: %u, direction: %u",
436              command_type, command, direction );
437         rc = 1;
438         break;
439 #endif
440 
441 #ifdef TISP_MODULES
442     case TISP_MODULES:
443         LOG( LOG_DEBUG, "TISP_MODULES is supported, cmd_type: %u, cmd: %u, direction: %u",
444              command_type, command, direction );
445         rc = 1;
446         break;
447 #endif
448     }
449 
450     return rc;
451 }
452 
ctrl_channel_handle_command(uint32_t cmd_ctx_id,uint8_t type,uint8_t command,uint32_t value,uint8_t direction)453 void ctrl_channel_handle_command( uint32_t cmd_ctx_id, uint8_t type, uint8_t command, uint32_t value, uint8_t direction )
454 {
455     struct ctrl_cmd_item *p_cmd = &ctrl_channel_ctx.cmd_item;
456 
457     if ( !ctrl_channel_ctx.dev_inited ) {
458         LOG( LOG_ERR, "FW ctrl channel is not inited." );
459         return;
460     }
461 
462     if ( !ctrl_channel_ctx.dev_opened ) {
463         LOG( LOG_DEBUG, "FW ctrl channel is not opened, skip." );
464         return;
465     }
466 
467     /* If user-FW is not needed this command, we do nothing */
468     if ( !is_uf_needed_command( type, command, direction ) ) {
469         return;
470     }
471 
472     p_cmd->cmd_category = CTRL_CMD_CATEGORY_API_COMMAND;
473     p_cmd->cmd_len = sizeof( struct ctrl_cmd_item );
474 #if FIRMWARE_CONTEXT_NUMBER == 2
475     p_cmd->cmd_ctx_id = cmd_ctx_id;
476 #endif
477     p_cmd->cmd_type = type;
478     p_cmd->cmd_id = command;
479     p_cmd->cmd_direction = direction;
480     p_cmd->cmd_value = value;
481 
482     LOG( LOG_INFO, "api_command: cmd_type: %u, cmd_id: %u, cmd_direction: %u, cmd_value: %u.", p_cmd->cmd_type, p_cmd->cmd_id, p_cmd->cmd_direction, p_cmd->cmd_value );
483 
484     ctrl_channel_write( p_cmd, NULL, 0 );
485 }
486 
ctrl_channel_handle_api_calibration(uint32_t cmd_ctx_id,uint8_t type,uint8_t id,uint8_t direction,void * data,uint32_t data_size)487 void ctrl_channel_handle_api_calibration( uint32_t cmd_ctx_id, uint8_t type, uint8_t id, uint8_t direction, void *data, uint32_t data_size )
488 {
489     struct ctrl_cmd_item *p_cmd = &ctrl_channel_ctx.cmd_item;
490 
491     if ( !ctrl_channel_ctx.dev_inited ) {
492         LOG( LOG_ERR, "FW ctrl channel is not inited." );
493         return;
494     }
495 
496     if ( !ctrl_channel_ctx.dev_opened ) {
497         return;
498     }
499 
500     p_cmd->cmd_category = CTRL_CMD_CATEGORY_API_CALIBRATION;
501     p_cmd->cmd_len = sizeof( struct ctrl_cmd_item ) + data_size;
502     p_cmd->cmd_type = type;
503 #if FIRMWARE_CONTEXT_NUMBER == 2
504     p_cmd->cmd_ctx_id = cmd_ctx_id;
505 #endif
506     p_cmd->cmd_id = id;
507     p_cmd->cmd_direction = direction;
508     p_cmd->cmd_value = data_size;
509 
510     LOG( LOG_INFO, "api_alibration: cmd_type: %u, cmd_id: %u, cmd_direction: %u, cmd_value: %u.", p_cmd->cmd_type, p_cmd->cmd_id, p_cmd->cmd_direction, p_cmd->cmd_value );
511 
512     ctrl_channel_write( p_cmd, data, data_size );
513 }
514 
515 /* Below empty interface functions is used for build in kern-FW */
ctrl_channel_process(void)516 void ctrl_channel_process( void )
517 {
518 }
519