• 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/version.h>
21 #include <linux/module.h>
22 #include <linux/slab.h>
23 #include <linux/mutex.h>
24 #include <linux/videodev2.h>
25 #include <media/videobuf2-core.h>
26 #include <media/videobuf2-vmalloc.h>
27 #include <media/v4l2-ioctl.h>
28 #include <media/v4l2-fh.h>
29 #include <media/v4l2-event.h>
30 
31 #include "acamera_logger.h"
32 
33 #include "isp-v4l2-common.h"
34 #include "isp-v4l2.h"
35 #include "isp-v4l2-ctrl.h"
36 #include "isp-v4l2-stream.h"
37 #include "isp-vb2.h"
38 #include "fw-interface.h"
39 #include <linux/dma-mapping.h>
40 #include <linux/of_reserved_mem.h>
41 #if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 0, 0))
42 #include <linux/dma-contiguous.h>
43 #else
44 #include <linux/dma-map-ops.h>
45 #endif
46 #include "system_am_sc.h"
47 
48 #define ISP_V4L2_NUM_INPUTS 1
49 
50 
51 /* isp_v4l2_dev_t to destroy video device */
52 static isp_v4l2_dev_t *g_isp_v4l2_devs[FIRMWARE_CONTEXT_NUMBER];
53 static isp_v4l2_dev_t *g_isp_v4l2_dev;
54 void *isp_kaddr = NULL;
55 resource_size_t isp_paddr = 0;
56 #define SIZE_1M (1024 * 1024UL)
57 #define DEFAULT_TEMPER_BUFFER_SIZE    16
58 #define DEFAULT_TEMPER_LINE_OFFSET    3840*3
59 #define DEFAULT_TEMPER_FRAME_NUM      1
60 #define DEFAULT_TEMPER_FRAME_SIZE     3840*2160*6
61 #define ENFORCE_TEMPER3_DISABLE       0
62 #define ENFORCE_TEMPER3_ENABLE        3
63 unsigned int temper_line_offset = DEFAULT_TEMPER_LINE_OFFSET;
64 unsigned int temper_frame_num = DEFAULT_TEMPER_FRAME_NUM;
65 unsigned int temper_frame_size = DEFAULT_TEMPER_FRAME_SIZE;
66 unsigned int temper3 = 1;
67 module_param(temper3, uint, 0664);
68 MODULE_PARM_DESC(temper3, "\n temper3 enable\n");
69 /* ----------------------------------------------------------------
70  * V4L2 file handle structures and functions
71  * : implementing multi stream
72  */
73 #define fh_to_private( __fh ) \
74     container_of( __fh, struct isp_v4l2_fh, fh )
75 
76 struct isp_v4l2_fh {
77     struct v4l2_fh fh;
78     unsigned int stream_id;
79     struct vb2_queue vb2_q;
80 };
81 
isp_v4l2_fh_open(struct file * file)82 static int isp_v4l2_fh_open( struct file *file )
83 {
84     isp_v4l2_dev_t *dev = video_drvdata( file );
85     struct isp_v4l2_fh *sp;
86     int i;
87 
88     sp = kzalloc( sizeof( struct isp_v4l2_fh ), GFP_KERNEL );
89     if ( !sp )
90         return -ENOMEM;
91 
92     unsigned int stream_opened = atomic_read( &dev->opened );
93     /* update open counter */
94 
95     if ( stream_opened > V4L2_STREAM_TYPE_MAX ) {
96         LOG( LOG_CRIT, "too many open streams." );
97 #if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 0, 0))
98         kzfree( sp );
99 #else
100         kfree_sensitive( sp );
101 #endif
102         return -EBUSY;
103     }
104 
105     file->private_data = &sp->fh;
106 
107     if ( mutex_lock_interruptible( &dev->file_lock ) )
108         LOG( LOG_CRIT, "mutex_lock_interruptible failed.\n" );
109     for ( i = 0; i < V4L2_STREAM_TYPE_MAX; i++ ) {
110         if ( ( dev->stream_mask & ( 1 << i ) ) == 0 ) {
111             dev->stream_mask |= ( 1 << i );
112             sp->stream_id = i;
113             break;
114         }
115     }
116     mutex_unlock( &dev->file_lock );
117 
118     v4l2_fh_init( &sp->fh, &dev->video_dev );
119     v4l2_fh_add( &sp->fh );
120 
121     return 0;
122 }
123 
isp_v4l2_fh_release(struct file * file)124 static int isp_v4l2_fh_release( struct file *file )
125 {
126     struct isp_v4l2_fh *sp = fh_to_private( file->private_data );
127 
128     if ( sp ) {
129         v4l2_fh_del( &sp->fh );
130         v4l2_fh_exit( &sp->fh );
131     }
132 
133 #if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 0, 0))
134     kzfree( sp );
135 #else
136     kfree_sensitive( sp );
137 #endif
138 
139     return 0;
140 }
141 
142 
143 /* ----------------------------------------------------------------
144  * V4L2 file operations
145  */
isp_v4l2_fop_open(struct file * file)146 static int isp_v4l2_fop_open( struct file *file )
147 {
148     int rc = 0;
149     isp_v4l2_dev_t *dev = video_drvdata( file );
150     struct isp_v4l2_fh *sp;
151 
152     atomic_add( 1, &dev->opened );
153     /* open file header */
154     rc = isp_v4l2_fh_open( file );
155     if ( rc < 0 ) {
156         LOG( LOG_ERR, "Error, file handle open fail (rc=%d)", rc );
157         goto fh_open_fail;
158     }
159     sp = fh_to_private( file->private_data );
160 
161     LOG( LOG_INFO, "isp_v4l2: %s: called for sid:%d.", __func__, sp->stream_id );
162     /* init stream */
163     isp_v4l2_stream_init( &dev->pstreams[sp->stream_id], sp->stream_id, dev->ctx_id );
164     if ( sp->stream_id == 0 ) {
165         // stream_id 0 is a full resolution
166         dev->stream_id_index[V4L2_STREAM_TYPE_FR] = sp->stream_id;
167         acamera_api_dma_buff_queue_reset(dev->ctx_id, dma_fr);
168     }
169 #if ISP_HAS_DS1
170     else if ( sp->stream_id == V4L2_STREAM_TYPE_DS1 ) {
171         dev->stream_id_index[V4L2_STREAM_TYPE_DS1] = sp->stream_id;
172         acamera_api_dma_buff_queue_reset(dev->ctx_id, dma_ds1);
173     }
174 #endif
175 #if ISP_HAS_DS2
176     else if (sp->stream_id == V4L2_STREAM_TYPE_DS2) {
177         dev->stream_id_index[V4L2_STREAM_TYPE_DS2] = sp->stream_id;
178     }
179 #endif
180 
181     /* init vb2 queue */
182 
183     rc = isp_vb2_queue_init( &sp->vb2_q, &dev->mlock, dev->pstreams[sp->stream_id], dev->v4l2_dev->dev );
184     if ( rc < 0 ) {
185         LOG( LOG_ERR, "Error, vb2 queue init fail (rc=%d)", rc );
186         goto vb2_q_fail;
187     }
188     if (sp->stream_id == V4L2_STREAM_TYPE_FR ||
189         sp->stream_id == V4L2_STREAM_TYPE_DS1) {
190 
191         sp->vb2_q.dev = g_isp_v4l2_devs[dev->ctx_id]->pdev;
192     }
193 #if ISP_HAS_DS2
194     else if (sp->stream_id == V4L2_STREAM_TYPE_DS2) {
195         sp->vb2_q.dev = g_isp_v4l2_devs[dev->ctx_id]->pdev;
196     }
197 #endif
198 
199     g_isp_v4l2_dev = g_isp_v4l2_devs[dev->ctx_id];
200     fw_intf_isp_set_current_ctx_id(dev->ctx_id);
201 
202 	dev->pstreams[sp->stream_id]->vb2_q = &sp->vb2_q;
203     /* init fh_ptr */
204     if ( mutex_lock_interruptible( &dev->notify_lock ) )
205         LOG( LOG_CRIT, "mutex_lock_interruptible failed.\n" );
206     dev->fh_ptr[sp->stream_id] = &( sp->fh );
207     mutex_unlock( &dev->notify_lock );
208 
209     return rc;
210 
211 vb2_q_fail:
212     isp_v4l2_stream_deinit( dev->pstreams[sp->stream_id], atomic_read(&dev->stream_on_cnt) );
213 
214     //too_many_stream:
215     isp_v4l2_fh_release( file );
216 
217 fh_open_fail:
218     atomic_sub( 1, &dev->opened );
219     return rc;
220 }
221 
isp_v4l2_fop_close(struct file * file)222 static int isp_v4l2_fop_close( struct file *file )
223 {
224     isp_v4l2_dev_t *dev = video_drvdata( file );
225     struct isp_v4l2_fh *sp = fh_to_private( file->private_data );
226     isp_v4l2_stream_t *pstream = dev->pstreams[sp->stream_id];
227     int open_counter;
228 
229     LOG( LOG_INFO, "isp_v4l2: %s: called for sid:%d.", __func__, sp->stream_id );
230 
231     /* deinit fh_ptr */
232     if ( mutex_lock_interruptible( &dev->notify_lock ) )
233         LOG( LOG_CRIT, "mutex_lock_interruptible failed.\n" );
234     dev->fh_ptr[sp->stream_id] = NULL;
235     mutex_unlock( &dev->notify_lock );
236 
237     /* deinit stream */
238     if ( pstream ) {
239         if ( pstream->stream_type < V4L2_STREAM_TYPE_MAX )
240             dev->stream_id_index[pstream->stream_type] = -1;
241         if (pstream->stream_started)
242         {
243             isp_v4l2_stream_type_t type = pstream->stream_type;
244             isp_v4l2_stream_deinit( pstream, atomic_read(&dev->stream_on_cnt) );
245 			if (atomic_read(&dev->stream_on_cnt) && ( type != V4L2_STREAM_TYPE_META))
246 				atomic_sub_return( 1, &dev->stream_on_cnt );
247             dev->pstreams[sp->stream_id] = NULL;
248         }
249         if ( dev->pstreams[sp->stream_id] ) {
250 #if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 0, 0))
251             kzfree( dev->pstreams[sp->stream_id] );
252 #else
253             kfree_sensitive( dev->pstreams[sp->stream_id] );
254 #endif
255             dev->pstreams[sp->stream_id] = NULL;
256         }
257     }
258 
259     /* release vb2 queue */
260     if ( sp->vb2_q.lock )
261         mutex_lock( sp->vb2_q.lock );
262 
263     isp_vb2_queue_release( &sp->vb2_q, pstream );
264 
265     if ( sp->vb2_q.lock )
266         mutex_unlock( sp->vb2_q.lock );
267 
268     if ( mutex_lock_interruptible( &dev->file_lock ) )
269         LOG( LOG_CRIT, "mutex_lock_interruptible failed.\n" );
270 
271     dev->stream_mask &= ~( 1 << sp->stream_id );
272     mutex_unlock( &dev->file_lock );
273     open_counter = atomic_sub_return( 1, &dev->opened );
274 
275     /* release file handle */
276     isp_v4l2_fh_release( file );
277 
278     return 0;
279 }
280 
isp_v4l2_fop_read(struct file * filep,char __user * buf,size_t count,loff_t * ppos)281 static ssize_t isp_v4l2_fop_read( struct file *filep,
282                                   char __user *buf, size_t count, loff_t *ppos )
283 {
284     struct isp_v4l2_fh *sp = fh_to_private( filep->private_data );
285     int rc = 0;
286 
287     rc = vb2_read( &sp->vb2_q, buf, count, ppos, filep->f_flags & O_NONBLOCK );
288 
289     return rc;
290 }
291 
isp_v4l2_fop_poll(struct file * filep,struct poll_table_struct * wait)292 static unsigned int isp_v4l2_fop_poll( struct file *filep,
293                                        struct poll_table_struct *wait )
294 {
295     struct isp_v4l2_fh *sp = fh_to_private( filep->private_data );
296     int rc = 0;
297 
298     if ( sp->vb2_q.lock && mutex_lock_interruptible( sp->vb2_q.lock ) )
299         return POLLERR;
300 
301     rc = vb2_poll( &sp->vb2_q, filep, wait );
302 
303     if ( sp->vb2_q.lock )
304         mutex_unlock( sp->vb2_q.lock );
305 
306     return rc;
307 }
308 
isp_v4l2_fop_mmap(struct file * file,struct vm_area_struct * vma)309 static int isp_v4l2_fop_mmap( struct file *file, struct vm_area_struct *vma )
310 {
311     struct isp_v4l2_fh *sp = fh_to_private( file->private_data );
312     int rc = 0;
313 
314     rc = vb2_mmap( &sp->vb2_q, vma );
315 
316     return rc;
317 }
318 
319 static const struct v4l2_file_operations isp_v4l2_fops = {
320     .owner = THIS_MODULE,
321     .open = isp_v4l2_fop_open,
322     .release = isp_v4l2_fop_close,
323     .read = isp_v4l2_fop_read,
324     .poll = isp_v4l2_fop_poll,
325     .unlocked_ioctl = video_ioctl2,
326     .mmap = isp_v4l2_fop_mmap,
327 };
328 
329 
330 /* ----------------------------------------------------------------
331  * V4L2 ioctl operations
332  */
isp_v4l2_querycap(struct file * file,void * priv,struct v4l2_capability * cap)333 static int isp_v4l2_querycap( struct file *file, void *priv, struct v4l2_capability *cap )
334 {
335     isp_v4l2_dev_t *dev = video_drvdata( file );
336 
337     LOG( LOG_DEBUG, "dev: %p, file: %p, priv: %p.\n", dev, file, priv );
338 
339     strcpy( cap->driver, "ARM-camera-isp" );
340     strcpy( cap->card, "juno R2" );
341     snprintf( cap->bus_info, sizeof( cap->bus_info ), "platform:%s", dev->v4l2_dev->name );
342 
343     /* V4L2_CAP_VIDEO_CAPTURE_MPLANE */
344 
345     cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING | V4L2_CAP_READWRITE;
346     cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
347 
348     return 0;
349 }
350 
351 
352 /* format related, will be moved to isp-v4l2-stream.c */
isp_v4l2_g_fmt_vid_cap(struct file * file,void * priv,struct v4l2_format * f)353 static int isp_v4l2_g_fmt_vid_cap( struct file *file, void *priv, struct v4l2_format *f )
354 {
355     isp_v4l2_dev_t *dev = video_drvdata( file );
356     struct isp_v4l2_fh *sp = fh_to_private( file->private_data );
357     isp_v4l2_stream_t *pstream = dev->pstreams[sp->stream_id];
358 
359     LOG( LOG_DEBUG, "isp_v4l2_g_fmt_vid_cap sid:%d", sp->stream_id );
360 
361     isp_v4l2_stream_get_format( pstream, f );
362 
363     LOG( LOG_DEBUG, "v4l2_format: type: %u, w: %u, h: %u, pixelformat: 0x%x, field: %u, colorspace: %u, sizeimage: %u, bytesperline: %u, flags: %u.\n",
364          f->type,
365          f->fmt.pix.width,
366          f->fmt.pix.height,
367          f->fmt.pix.pixelformat,
368          f->fmt.pix.field,
369          f->fmt.pix.colorspace,
370          f->fmt.pix.sizeimage,
371          f->fmt.pix.bytesperline,
372          f->fmt.pix.flags );
373 
374     return 0;
375 }
376 
isp_v4l2_enum_fmt_vid_cap(struct file * file,void * priv,struct v4l2_fmtdesc * f)377 static int isp_v4l2_enum_fmt_vid_cap( struct file *file, void *priv, struct v4l2_fmtdesc *f )
378 {
379     isp_v4l2_dev_t *dev = video_drvdata( file );
380     struct isp_v4l2_fh *sp = fh_to_private( file->private_data );
381     isp_v4l2_stream_t *pstream = dev->pstreams[sp->stream_id];
382 
383     return isp_v4l2_stream_enum_format( pstream, f );
384 }
385 
isp_v4l2_try_fmt_vid_cap(struct file * file,void * priv,struct v4l2_format * f)386 static int isp_v4l2_try_fmt_vid_cap( struct file *file, void *priv, struct v4l2_format *f )
387 {
388     isp_v4l2_dev_t *dev = video_drvdata( file );
389     struct isp_v4l2_fh *sp = fh_to_private( file->private_data );
390     isp_v4l2_stream_t *pstream = dev->pstreams[sp->stream_id];
391     LOG( LOG_CRIT, "isp_v4l2_try_fmt_vid_cap" );
392     return isp_v4l2_stream_try_format( pstream, f );
393 }
394 
isp_v4l2_s_fmt_vid_cap(struct file * file,void * priv,struct v4l2_format * f)395 static int isp_v4l2_s_fmt_vid_cap( struct file *file, void *priv, struct v4l2_format *f )
396 {
397     isp_v4l2_dev_t *dev = video_drvdata( file );
398     struct isp_v4l2_fh *sp = fh_to_private( file->private_data );
399     isp_v4l2_stream_t *pstream = dev->pstreams[sp->stream_id];
400     struct vb2_queue *q = &sp->vb2_q;
401     int rc = 0;
402     LOG( LOG_CRIT, "isp_v4l2_s_fmt_vid_cap sid:%d", sp->stream_id );
403     if ( vb2_is_busy( q ) )
404         return -EBUSY;
405 
406     rc = isp_v4l2_stream_set_format( pstream, f );
407     if ( rc < 0 ) {
408         LOG( LOG_ERR, "set format failed." );
409         return rc;
410     }
411 
412     /* update stream pointer index */
413     dev->stream_id_index[pstream->stream_type] = pstream->stream_id;
414 
415     return 0;
416 }
417 
isp_v4l2_enum_framesizes(struct file * file,void * priv,struct v4l2_frmsizeenum * fsize)418 static int isp_v4l2_enum_framesizes( struct file *file, void *priv, struct v4l2_frmsizeenum *fsize )
419 {
420     isp_v4l2_dev_t *dev = video_drvdata( file );
421     struct isp_v4l2_fh *sp = fh_to_private( file->private_data );
422     isp_v4l2_stream_t *pstream = dev->pstreams[sp->stream_id];
423 
424     return isp_v4l2_stream_enum_framesizes( pstream, fsize );
425 }
426 
427 
428 /* Per-stream control operations */
isp_v4l2_is_q_busy(struct vb2_queue * queue,struct file * file)429 static inline bool isp_v4l2_is_q_busy( struct vb2_queue *queue, struct file *file )
430 {
431     return queue->owner && queue->owner != file->private_data;
432 }
433 
isp_v4l2_streamon(struct file * file,void * priv,enum v4l2_buf_type i)434 static int isp_v4l2_streamon( struct file *file, void *priv, enum v4l2_buf_type i )
435 {
436     isp_v4l2_dev_t *dev = video_drvdata( file );
437     struct isp_v4l2_fh *sp = fh_to_private( priv );
438     isp_v4l2_stream_t *pstream = dev->pstreams[sp->stream_id];
439     int rc = 0;
440 
441     if ( isp_v4l2_is_q_busy( &sp->vb2_q, file ) )
442         return -EBUSY;
443     else
444         if (pstream->stream_started)
445             return -EBUSY;
446 
447     rc = vb2_streamon( &sp->vb2_q, i );
448     if ( rc != 0 ) {
449         LOG( LOG_ERR, "fail to vb2_streamon. (rc=%d)", rc );
450         return rc;
451     }
452 
453     /* Start hardware */
454     rc = isp_v4l2_stream_on( pstream );
455     if ( rc != 0 ) {
456         LOG( LOG_ERR, "fail to isp_stream_on. (stream_id = %d, rc=%d)", sp->stream_id, rc );
457         isp_v4l2_stream_off( pstream, atomic_read(&dev->stream_on_cnt) );
458         return rc;
459     }
460 
461     if (pstream->stream_type != V4L2_STREAM_TYPE_META)
462     	atomic_add( 1, &dev->stream_on_cnt );
463 
464     return rc;
465 }
466 
isp_v4l2_streamoff(struct file * file,void * priv,enum v4l2_buf_type i)467 static int isp_v4l2_streamoff( struct file *file, void *priv, enum v4l2_buf_type i )
468 {
469     isp_v4l2_dev_t *dev = video_drvdata( file );
470     struct isp_v4l2_fh *sp = fh_to_private( priv );
471     isp_v4l2_stream_t *pstream = dev->pstreams[sp->stream_id];
472     int rc = 0;
473 
474     if ( isp_v4l2_is_q_busy( &sp->vb2_q, file ) )
475         return -EBUSY;
476 
477     /* Stop hardware */
478     isp_v4l2_stream_off( pstream, atomic_read(&dev->stream_on_cnt) );
479 
480     /* vb streamoff */
481     rc = vb2_streamoff( &sp->vb2_q, i );
482 
483 	if (atomic_read(&dev->stream_on_cnt) && (pstream->stream_type != V4L2_STREAM_TYPE_META))
484 		atomic_sub_return( 1, &dev->stream_on_cnt );
485 
486     return rc;
487 }
488 
489 
490 /* input control */
isp_v4l2_enum_input(struct file * file,void * fh,struct v4l2_input * input)491 static int isp_v4l2_enum_input( struct file *file, void *fh, struct v4l2_input *input )
492 {
493     /* currently only support general camera input */
494     if ( input->index > 0 )
495         return -EINVAL;
496 
497     strlcpy( input->name, "camera", sizeof( input->name ) );
498     input->type = V4L2_INPUT_TYPE_CAMERA;
499 
500     return 0;
501 }
502 
isp_v4l2_g_input(struct file * file,void * fh,unsigned int * input)503 static int isp_v4l2_g_input( struct file *file, void *fh, unsigned int *input )
504 {
505     /* currently only support general camera input */
506     *input = 0;
507 
508     return 0;
509 }
510 
isp_v4l2_s_input(struct file * file,void * fh,unsigned int input)511 static int isp_v4l2_s_input( struct file *file, void *fh, unsigned int input )
512 {
513     /* currently only support general camera input */
514     return input == 0 ? 0 : -EINVAL;
515 }
516 
517 
518 /* vb2 customization for multi-stream support */
isp_v4l2_reqbufs(struct file * file,void * priv,struct v4l2_requestbuffers * p)519 static int isp_v4l2_reqbufs( struct file *file, void *priv,
520                              struct v4l2_requestbuffers *p )
521 {
522     struct isp_v4l2_fh *sp = fh_to_private( file->private_data );
523     int rc = 0;
524 
525     LOG( LOG_DEBUG, "(stream_id = %d, ownermatch=%d)", sp->stream_id, isp_v4l2_is_q_busy( &sp->vb2_q, file ) );
526     if ( isp_v4l2_is_q_busy( &sp->vb2_q, file ) )
527         return -EBUSY;
528 
529     rc = vb2_reqbufs( &sp->vb2_q, p );
530     if ( rc == 0 )
531         sp->vb2_q.owner = p->count ? file->private_data : NULL;
532 
533 #if ISP_HAS_DS2
534     if (sp->stream_id == V4L2_STREAM_TYPE_DS2) {
535         am_sc_set_buf_num(p->count);
536         am_sc_system_init();
537     }
538 #endif
539 
540     LOG( LOG_DEBUG, "sid:%d reqbuf p->type:%d p->memory %d p->count %d rc %d", sp->stream_id, p->type, p->memory, p->count, rc );
541     return rc;
542 }
543 
isp_v4l2_querybuf(struct file * file,void * priv,struct v4l2_buffer * p)544 static int isp_v4l2_querybuf( struct file *file, void *priv, struct v4l2_buffer *p )
545 {
546     struct isp_v4l2_fh *sp = fh_to_private( file->private_data );
547     int rc = 0;
548 
549     rc = vb2_querybuf( &sp->vb2_q, p );
550 
551     LOG( LOG_DEBUG, "sid:%d querybuf p->type:%d p->index:%d , rc %d",
552             sp->stream_id, p->type, p->index, rc );
553 
554     return rc;
555 }
556 
isp_v4l2_qbuf(struct file * file,void * priv,struct v4l2_buffer * p)557 static int isp_v4l2_qbuf( struct file *file, void *priv, struct v4l2_buffer *p )
558 {
559     struct isp_v4l2_fh *sp = fh_to_private( file->private_data );
560     int rc = 0;
561 
562     LOG( LOG_DEBUG, "(stream_id = %d, ownermatch=%d)", sp->stream_id, isp_v4l2_is_q_busy( &sp->vb2_q, file ) );
563     if ( isp_v4l2_is_q_busy( &sp->vb2_q, file ) ) {
564         return -EBUSY;
565     }
566 
567 #if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 0, 0))
568     rc = vb2_qbuf( &sp->vb2_q, p );
569 #else
570     struct video_device *vdev = video_devdata(file);
571     rc = vb2_qbuf( &sp->vb2_q, vdev->v4l2_dev->mdev, p );
572 #endif
573 
574     LOG( LOG_DEBUG, "sid:%d qbuf p->type:%d p->index:%d, rc %d", sp->stream_id, p->type, p->index, rc );
575     return rc;
576 }
577 
isp_v4l2_dqbuf(struct file * file,void * priv,struct v4l2_buffer * p)578 static int isp_v4l2_dqbuf( struct file *file, void *priv, struct v4l2_buffer *p )
579 {
580     struct isp_v4l2_fh *sp = fh_to_private( file->private_data );
581     int rc = 0;
582     LOG( LOG_DEBUG, "(stream_id = %d, ownermatch=%d)", sp->stream_id, isp_v4l2_is_q_busy( &sp->vb2_q, file ) );
583     if ( isp_v4l2_is_q_busy( &sp->vb2_q, file ) )
584         return -EBUSY;
585 
586     rc = vb2_dqbuf( &sp->vb2_q, p, file->f_flags & O_NONBLOCK );
587     LOG( LOG_DEBUG, "sid:%d qbuf p->type:%d p->index:%d, rc %d", sp->stream_id, p->type, p->index, rc );
588     return rc;
589 }
590 
591 #if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 0, 0))
isp_v4l2_cropcap(struct file * file,void * fh,struct v4l2_cropcap * cap)592 static int isp_v4l2_cropcap(struct file *file, void *fh,
593                                     struct v4l2_cropcap *cap)
594 {
595     int ret = -1;
596     isp_v4l2_dev_t *dev = video_drvdata(file);
597     struct isp_v4l2_fh *sp = fh_to_private(fh);
598     isp_v4l2_stream_t *pstream = dev->pstreams[sp->stream_id];
599 
600     if (pstream->stream_type == V4L2_STREAM_TYPE_FR ||
601                 pstream->stream_type == V4L2_STREAM_TYPE_DS1)
602         ret = isp_v4l2_get_cropcap(pstream, cap);
603     else
604         LOG(LOG_ERR, "Error support this stream type: %d", pstream->stream_type);
605 
606     return ret;
607 }
608 
isp_v4l2_g_crop(struct file * file,void * fh,struct v4l2_crop * crop)609 static int isp_v4l2_g_crop(struct file *file, void *fh,
610                                     struct v4l2_crop *crop)
611 {
612     int ret = -1;
613     isp_v4l2_dev_t *dev = video_drvdata(file);
614     struct isp_v4l2_fh *sp = fh_to_private(fh);
615     isp_v4l2_stream_t *pstream = dev->pstreams[sp->stream_id];
616 
617     if (pstream->stream_type == V4L2_STREAM_TYPE_FR ||
618                 pstream->stream_type == V4L2_STREAM_TYPE_DS1)
619         ret = isp_v4l2_get_crop(pstream, crop);
620     else
621         LOG(LOG_ERR, "Error support this stream type: %d", pstream->stream_type);
622 
623     return ret;
624 }
625 
isp_v4l2_s_crop(struct file * file,void * fh,const struct v4l2_crop * crop)626 static int isp_v4l2_s_crop(struct file *file, void *fh,
627                                 const struct v4l2_crop *crop)
628 {
629     int ret = -1;
630     isp_v4l2_dev_t *dev = video_drvdata(file);
631     struct isp_v4l2_fh *sp = fh_to_private(fh);
632     isp_v4l2_stream_t *pstream = dev->pstreams[sp->stream_id];
633 
634     if (pstream->stream_type == V4L2_STREAM_TYPE_FR ||
635                 pstream->stream_type == V4L2_STREAM_TYPE_DS1)
636         ret = isp_v4l2_set_crop(pstream, crop);
637     else
638         LOG(LOG_ERR, "Error support this stream type: %d", pstream->stream_type);
639 
640     return ret;
641 }
642 #else
isp_v4l2_g_pixelaspect(struct file * file,void * fh,int buf_type,struct v4l2_fract * aspect)643 static int isp_v4l2_g_pixelaspect(struct file *file, void *fh,
644 			int buf_type, struct v4l2_fract *aspect)
645 {
646     int ret = -1;
647     isp_v4l2_dev_t *dev = video_drvdata(file);
648     struct isp_v4l2_fh *sp = fh_to_private(fh);
649     isp_v4l2_stream_t *pstream = dev->pstreams[sp->stream_id];
650 
651     if (pstream->stream_type == V4L2_STREAM_TYPE_FR ||
652                 pstream->stream_type == V4L2_STREAM_TYPE_DS1) {
653         struct v4l2_crop crop;
654         ret = isp_v4l2_get_crop(pstream, &crop);
655         if (!ret) {
656             aspect->numerator = crop.c.width;
657             aspect->denominator = crop.c.height;
658         }
659         pr_info("%s: aspect = (%u, %u), ret=%d\n", __func__, aspect->numerator, aspect->denominator, ret);
660     } else
661         LOG(LOG_ERR, "isp_v4l2_g_pixelaspect Error support this stream type: %d", pstream->stream_type);
662 
663     return ret;
664 }
665 #endif
666 
isp_v4l2_expbuf(struct file * file,void * priv,struct v4l2_exportbuffer * ex_buf)667 static int isp_v4l2_expbuf(struct file *file, void *priv, struct v4l2_exportbuffer *ex_buf)
668 {
669     struct isp_v4l2_fh *sp = fh_to_private( file->private_data );
670 
671     if (sp == NULL || ex_buf == NULL) {
672         LOG(LOG_ERR, "Error invalid input param");
673         return -EINVAL;
674     }
675 
676     return vb2_expbuf(&sp->vb2_q, ex_buf);
677 }
678 
isp_v4l2_enum_frameintervals(struct file * file,void * fh,struct v4l2_frmivalenum * fival)679 int isp_v4l2_enum_frameintervals(struct file *file, void *fh,
680                                         struct v4l2_frmivalenum *fival)
681 {
682     isp_v4l2_dev_t *dev = video_drvdata( file );
683     struct isp_v4l2_fh *sp = fh_to_private( file->private_data );
684     isp_v4l2_stream_t *pstream = dev->pstreams[sp->stream_id];
685 
686     return isp_v4l2_stream_enum_frameintervals( pstream, fival);
687 }
688 
689 
690 static const struct v4l2_ioctl_ops isp_v4l2_ioctl_ops = {
691     .vidioc_querycap = isp_v4l2_querycap,
692 
693     /* Per-stream config operations */
694     .vidioc_g_fmt_vid_cap_mplane = isp_v4l2_g_fmt_vid_cap,
695 #if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 0, 0))
696     .vidioc_enum_fmt_vid_cap_mplane = isp_v4l2_enum_fmt_vid_cap,
697 #else
698     .vidioc_enum_fmt_sdr_cap = isp_v4l2_enum_fmt_vid_cap,
699 #endif
700     .vidioc_try_fmt_vid_cap_mplane = isp_v4l2_try_fmt_vid_cap,
701     .vidioc_s_fmt_vid_cap_mplane = isp_v4l2_s_fmt_vid_cap,
702 
703     .vidioc_g_fmt_vid_cap = isp_v4l2_g_fmt_vid_cap,
704     .vidioc_enum_fmt_vid_cap = isp_v4l2_enum_fmt_vid_cap,
705     .vidioc_try_fmt_vid_cap = isp_v4l2_try_fmt_vid_cap,
706     .vidioc_s_fmt_vid_cap = isp_v4l2_s_fmt_vid_cap,
707     .vidioc_enum_framesizes = isp_v4l2_enum_framesizes,
708 
709     /* Per-stream control operations */
710     .vidioc_streamon = isp_v4l2_streamon,
711     .vidioc_streamoff = isp_v4l2_streamoff,
712 
713     /* input control */
714     .vidioc_enum_input = isp_v4l2_enum_input,
715     .vidioc_g_input = isp_v4l2_g_input,
716     .vidioc_s_input = isp_v4l2_s_input,
717 
718     /* vb2 customization for multi-stream support */
719     .vidioc_reqbufs = isp_v4l2_reqbufs,
720 
721     .vidioc_querybuf = isp_v4l2_querybuf,
722     .vidioc_qbuf = isp_v4l2_qbuf,
723     .vidioc_dqbuf = isp_v4l2_dqbuf,
724 
725     /* v4l2 event ioctls */
726     .vidioc_log_status = v4l2_ctrl_log_status,
727     .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
728     .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
729 
730     /* crop ioctls */
731 #if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 0, 0))
732     .vidioc_cropcap = isp_v4l2_cropcap,
733     .vidioc_g_crop = isp_v4l2_g_crop,
734     .vidioc_s_crop = isp_v4l2_s_crop,
735 #else
736     .vidioc_g_pixelaspect = isp_v4l2_g_pixelaspect,
737 #endif
738 
739     .vidioc_expbuf = isp_v4l2_expbuf,
740  #ifdef CONFIG_ANDROID_OS
741 	.vidioc_enum_frameintervals = isp_v4l2_enum_frameintervals,
742  #endif
743 };
744 
isp_cma_alloc(struct platform_device * pdev,unsigned long size)745 static int isp_cma_alloc(struct platform_device *pdev, unsigned long size)
746 {
747     struct page *cma_pages = NULL;
748 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 10, 0))
749     cma_pages = dma_alloc_from_contiguous(
750 			&(pdev->dev), size >> PAGE_SHIFT, 0, false);
751 #else
752     cma_pages = dma_alloc_from_contiguous(
753 			&(pdev->dev), size >> PAGE_SHIFT, 0);
754 #endif
755     if (cma_pages) {
756         isp_paddr = page_to_phys(cma_pages);
757     } else {
758         LOG(LOG_ERR, "Failed alloc cma pages.\n");
759         return -1;
760     }
761     isp_kaddr = (void *)cma_pages;
762 
763     return 0;
764 }
765 
isp_cma_free(struct platform_device * pdev,void * kaddr,unsigned long size)766 static void isp_cma_free(struct platform_device *pdev, void *kaddr, unsigned long size)
767 {
768     struct page *cma_pages = NULL;
769     bool rc = false;
770 
771     if (pdev == NULL || kaddr == NULL) {
772         LOG(LOG_ERR, "Error input param\n");
773         return;
774     }
775 
776     cma_pages = kaddr;
777 
778     rc = dma_release_from_contiguous(&(pdev->dev), cma_pages, size >> PAGE_SHIFT);
779     if (rc == false) {
780         LOG(LOG_ERR, "Failed to release cma buffer\n");
781         return;
782     }
783 }
784 
isp_v4l2_init_dev(uint32_t ctx_id,struct v4l2_device * v4l2_dev)785 static int isp_v4l2_init_dev( uint32_t ctx_id, struct v4l2_device *v4l2_dev )
786 {
787     isp_v4l2_dev_t *dev;
788     struct video_device *vfd;
789     v4l2_std_id tvnorms_cap = 0;
790     int rc = 0;
791     int i;
792 
793     if ( ctx_id >= FIRMWARE_CONTEXT_NUMBER ) {
794         LOG( LOG_ERR, "Invalid ctx numbr: %d, max: %d.", ctx_id, FIRMWARE_CONTEXT_NUMBER - 1 );
795         return -EINVAL;
796     }
797 
798     /* allocate main isp_v4l2 state structure */
799     dev = kzalloc( sizeof( *dev ), GFP_KERNEL );
800     if ( !dev )
801         return -ENOMEM;
802 
803     memset( dev, 0x0, sizeof( isp_v4l2_dev_t ) );
804 
805     /* register v4l2_device */
806 
807     dev->v4l2_dev = v4l2_dev;
808     dev->ctx_id = ctx_id;
809 
810     /* init v4l2 controls */
811     dev->isp_v4l2_ctrl.v4l2_dev = dev->v4l2_dev;
812     dev->isp_v4l2_ctrl.video_dev = &dev->video_dev;
813     rc = isp_v4l2_ctrl_init( ctx_id, &dev->isp_v4l2_ctrl );
814     if ( rc )
815         goto free_dev;
816 
817     /* initialize locks */
818     mutex_init( &dev->mlock );
819     mutex_init( &dev->notify_lock );
820 	mutex_init( &dev->file_lock);
821 
822     /* initialize stream id table */
823     for ( i = 0; i < V4L2_STREAM_TYPE_MAX; i++ ) {
824         dev->stream_id_index[i] = -1;
825     }
826 
827     /* initialize open counter */
828     atomic_set( &dev->stream_on_cnt, 0 );
829     atomic_set( &dev->opened, 0 );
830 
831     /* finally start creating the device nodes */
832     vfd = &dev->video_dev;
833     strlcpy( vfd->name, "isp_v4l2-vid-cap", sizeof( vfd->name ) );
834     vfd->fops = &isp_v4l2_fops;
835     vfd->ioctl_ops = &isp_v4l2_ioctl_ops;
836     vfd->release = video_device_release_empty;
837     vfd->v4l2_dev = dev->v4l2_dev;
838     vfd->queue = NULL; // queue will be customized in file handle
839     vfd->tvnorms = tvnorms_cap;
840     vfd->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING | V4L2_CAP_READWRITE;
841 #if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 0, 0))
842     vfd->vfl_type = VFL_TYPE_GRABBER;
843 #else
844     vfd->vfl_type = VFL_TYPE_VIDEO;
845 #endif
846 
847     /*
848      * Provide a mutex to v4l2 core. It will be used to protect
849      * all fops and v4l2 ioctls.
850      */
851     vfd->lock = &dev->mlock;
852     video_set_drvdata( vfd, dev );
853 
854     /* store dev pointer to destroy later and find stream */
855     g_isp_v4l2_devs[ctx_id] = dev;
856 
857     /* videoX start number, -1 is autodetect */
858 #if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 0, 0))
859     rc = video_register_device( vfd, VFL_TYPE_GRABBER, VIDEO_NODE_NUM );
860 #else
861     rc = video_register_device( vfd, VFL_TYPE_VIDEO, VIDEO_NODE_NUM );
862 #endif
863     if ( rc < 0 )
864         goto unreg_dev;
865 
866     LOG( LOG_INFO, "V4L2 capture device registered as %s.",
867          video_device_node_name( vfd ) );
868 
869 
870     return rc;
871 
872 unreg_dev:
873     video_unregister_device( &dev->video_dev );
874     isp_v4l2_ctrl_deinit( &dev->isp_v4l2_ctrl );
875 
876 free_dev:
877     g_isp_v4l2_devs[ctx_id] = NULL;
878     kfree( dev );
879 
880     return rc;
881 }
882 
isp_v4l2_destroy_dev(int ctx_id)883 static void isp_v4l2_destroy_dev( int ctx_id )
884 {
885     if ( g_isp_v4l2_devs[ctx_id] ) {
886         LOG( LOG_INFO, "unregistering %s.", video_device_node_name( &g_isp_v4l2_devs[ctx_id]->video_dev ) );
887 
888         /* unregister video device */
889         video_unregister_device( &g_isp_v4l2_devs[ctx_id]->video_dev );
890 
891         isp_v4l2_ctrl_deinit( &g_isp_v4l2_devs[ctx_id]->isp_v4l2_ctrl );
892 
893         kfree( g_isp_v4l2_devs[ctx_id] );
894         g_isp_v4l2_devs[ctx_id] = NULL;
895     } else {
896         LOG( LOG_INFO, "isp_v4l2_dev ctx_id: %d is NULL, skip.", ctx_id );
897     }
898 }
899 
900 /* ----------------------------------------------------------------
901  * V4L2 external interface for probe
902  */
isp_v4l2_create_instance(struct v4l2_device * v4l2_dev,struct platform_device * pdev,uint32_t hw_isp_addr)903 int isp_v4l2_create_instance( struct v4l2_device *v4l2_dev, struct platform_device *pdev, uint32_t hw_isp_addr )
904 {
905     uint32_t ctx_id;
906     uint32_t ret_value;
907     unsigned int temper_buf_size;
908     int rc = 0;
909 
910     if ( v4l2_dev == NULL ) {
911         LOG( LOG_ERR, "Invalid parameter" );
912         return -EINVAL;
913     }
914 
915     rc = of_property_read_u32(pdev->dev.of_node, "temper-frame-num",
916                                &temper_frame_num);
917     if ( rc != 0 ) {
918         temper_frame_num = DEFAULT_TEMPER_FRAME_NUM * temper3;
919     }
920     else
921     {
922         if ( temper3 == ENFORCE_TEMPER3_DISABLE )
923             temper_frame_num = DEFAULT_TEMPER_FRAME_NUM;
924         else if ( temper3 == ENFORCE_TEMPER3_ENABLE )
925             temper_frame_num = DEFAULT_TEMPER_FRAME_NUM * 2;
926     }
927 
928     rc = of_property_read_u32(pdev->dev.of_node, "temper-frame-size",
929                                &temper_frame_size);
930     if ( rc != 0 ) {
931         temper_frame_size = DEFAULT_TEMPER_FRAME_SIZE;
932     }
933 
934     rc = of_property_read_u32(pdev->dev.of_node, "temper-buf-size",
935                                &temper_buf_size);
936     if ( rc != 0 ) {
937         LOG(LOG_ERR, "failed to get temper-buf-size from dts, use default value\n");
938         temper_buf_size = DEFAULT_TEMPER_BUFFER_SIZE;
939     }
940 
941     if ( temper_buf_size < (( temper_frame_num * temper_frame_size) / SIZE_1M) )
942         temper_buf_size = (temper_frame_num * temper_frame_size) / SIZE_1M;
943 
944     rc = isp_cma_alloc(pdev, temper_buf_size * SIZE_1M);
945     if (rc < 0)
946         return rc;
947 
948     rc = of_property_read_u32(pdev->dev.of_node, "temper-line-offset", &temper_line_offset);
949     if (rc != 0) {
950         LOG(LOG_ERR, "failed to get temper_line_offset from dts, use default value\n");
951         temper_line_offset = DEFAULT_TEMPER_LINE_OFFSET;
952     }
953 
954     /* initialize isp */
955     rc = fw_intf_isp_init(hw_isp_addr);
956     if ( rc < 0 )
957         goto free_cma;
958 
959     /* initialize stream related resources to prepare for streaming.
960      * It should be called after sensor initialized.
961      */
962     for ( ctx_id = 0; ctx_id < FIRMWARE_CONTEXT_NUMBER; ctx_id++ ) {
963         rc = isp_v4l2_stream_init_static_resources( pdev, ctx_id );
964         if ( rc < 0 )
965             goto deinit_fw_intf;
966     }
967 
968     /* check sensor devices */
969     for ( ctx_id = 0; ctx_id < FIRMWARE_CONTEXT_NUMBER; ctx_id++ ) {
970         rc = acamera_command(ctx_id, TSENSOR, SENSOR_HWID, 0, COMMAND_GET, &ret_value);
971         if ( rc ) {
972             LOG( LOG_CRIT, "isp_v4l2_init ctx_id: %d failed.", ctx_id );
973             rc = 0;
974             goto deinit_fw_intf;
975         }
976     }
977 
978     /* initialize v4l2 layer devices */
979     for ( ctx_id = 0; ctx_id < FIRMWARE_CONTEXT_NUMBER; ctx_id++ ) {
980         rc = isp_v4l2_init_dev( ctx_id, v4l2_dev );
981         if ( rc ) {
982             LOG( LOG_ERR, "isp_v4l2_init ctx_id: %d failed.", ctx_id );
983             goto unreg_dev;
984         }
985         g_isp_v4l2_devs[ctx_id]->pdev = &pdev->dev;
986     }
987 
988     g_isp_v4l2_dev = g_isp_v4l2_devs[0];
989     g_isp_v4l2_dev->temper_buf_size = temper_buf_size;
990 
991     return 0;
992 
993 unreg_dev:
994     for ( ctx_id = 0; ctx_id < FIRMWARE_CONTEXT_NUMBER; ctx_id++ ) {
995         isp_v4l2_destroy_dev( ctx_id );
996     }
997 
998 deinit_fw_intf:
999     fw_intf_isp_deinit();
1000 
1001 free_cma:
1002     isp_cma_free(pdev, isp_kaddr, temper_buf_size * SIZE_1M);
1003 
1004     return rc;
1005 }
1006 
isp_v4l2_destroy_instance(struct platform_device * pdev)1007 void isp_v4l2_destroy_instance( struct platform_device *pdev )
1008 {
1009 	if ( g_isp_v4l2_devs[0] ) {
1010         int ctx_id;
1011 
1012         /* deinitialize firmware & stream resources */
1013         fw_intf_isp_deinit();
1014         isp_v4l2_stream_deinit_static_resources(pdev);
1015 
1016         isp_cma_free(pdev, isp_kaddr,
1017              (g_isp_v4l2_dev->temper_buf_size) * SIZE_1M);
1018 
1019         for ( ctx_id = 0; ctx_id < FIRMWARE_CONTEXT_NUMBER; ctx_id++ ) {
1020             isp_v4l2_destroy_dev( ctx_id );
1021         }
1022     }
1023 }
1024 
1025 
1026 /* ----------------------------------------------------------------
1027  * stream finder utility function
1028  */
isp_v4l2_find_stream(isp_v4l2_stream_t ** ppstream,int ctx_number,isp_v4l2_stream_type_t stream_type)1029 int isp_v4l2_find_stream( isp_v4l2_stream_t **ppstream,
1030                           int ctx_number, isp_v4l2_stream_type_t stream_type )
1031 {
1032     int stream_id;
1033 
1034     *ppstream = NULL;
1035 
1036     if ( g_isp_v4l2_dev == NULL ) {
1037         return -EBUSY;
1038     }
1039 
1040     if ( stream_type >= V4L2_STREAM_TYPE_MAX || stream_type < 0 ) {
1041         return -EINVAL;
1042     }
1043 
1044     stream_id = g_isp_v4l2_devs[ctx_number]->stream_id_index[stream_type];
1045     if ( stream_id < 0 || stream_id >= V4L2_STREAM_TYPE_MAX || g_isp_v4l2_dev->pstreams[stream_id] == NULL ) {
1046         return -EBUSY;
1047     }
1048 
1049     *ppstream = g_isp_v4l2_devs[ctx_number]->pstreams[stream_id];
1050 
1051     return 0;
1052 }
1053 
isp_v4l2_get_dev(uint32_t ctx_number)1054 isp_v4l2_dev_t *isp_v4l2_get_dev( uint32_t ctx_number )
1055 {
1056     return g_isp_v4l2_devs[ctx_number];
1057 }
1058 
1059 /* ----------------------------------------------------------------
1060  * event notifier utility function
1061  */
isp_v4l2_notify_event(int ctx_id,int stream_id,uint32_t event_type)1062 int isp_v4l2_notify_event( int ctx_id, int stream_id, uint32_t event_type )
1063 {
1064     struct v4l2_event event;
1065 
1066     if ( g_isp_v4l2_devs[ctx_id] == NULL ) {
1067         return -EBUSY;
1068     }
1069 
1070     if ( mutex_lock_interruptible( &g_isp_v4l2_devs[ctx_id]->notify_lock ) )
1071         LOG( LOG_CRIT, "mutex_lock_interruptible failed.\n" );
1072     if ( g_isp_v4l2_devs[ctx_id]->fh_ptr[stream_id] == NULL ) {
1073         LOG( LOG_ERR, "Error, no fh_ptr exists for stream id %d (event_type = %d)", stream_id, event_type );
1074         mutex_unlock( &g_isp_v4l2_devs[ctx_id]->notify_lock );
1075         return -EINVAL;
1076     }
1077 
1078     memset( &event, 0, sizeof( event ) );
1079     event.type = event_type;
1080 
1081     v4l2_event_queue_fh( g_isp_v4l2_devs[ctx_id]->fh_ptr[stream_id], &event );
1082     mutex_unlock( &g_isp_v4l2_devs[ctx_id]->notify_lock );
1083 
1084     return 0;
1085 }
1086