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