3 * Copyright (C) 2008-2009 QUALCOMM Incorporated.
7 #include <linux/workqueue.h>
8 #include <linux/delay.h>
9 #include <linux/types.h>
10 #include <linux/list.h>
11 #include <linux/ioctl.h>
12 #include <linux/spinlock.h>
13 #include <linux/videodev2.h>
14 #include <linux/proc_fs.h>
15 #include <linux/slab.h>
16 #include <media/v4l2-dev.h>
17 #include <media/msm_camera.h>
18 #include <mach/camera.h>
19 #include <media/v4l2-ioctl.h>
20 /*#include <linux/platform_device.h>*/
22 #define MSM_V4L2_START_SNAPSHOT _IOWR('V', BASE_VIDIOC_PRIVATE+1, \
25 #define MSM_V4L2_GET_PICTURE _IOWR('V', BASE_VIDIOC_PRIVATE+2, \
28 #define MSM_V4L2_DEVICE_NAME "msm_v4l2"
30 #define MSM_V4L2_PROC_NAME "msm_v4l2"
32 #define MSM_V4L2_DEVNUM_MPEG2 0
33 #define MSM_V4L2_DEVNUM_YUV 20
35 /* HVGA-P (portrait) and HVGA-L (landscape) */
36 #define MSM_V4L2_WIDTH 480
37 #define MSM_V4L2_HEIGHT 320
39 #define D(fmt, args...) printk(KERN_INFO "msm_v4l2: " fmt, ##args)
41 #define PREVIEW_FRAMES_NUM 4
43 struct msm_v4l2_device
{
44 struct list_head read_queue
;
45 struct v4l2_format current_cap_format
;
46 struct v4l2_format current_pix_format
;
47 struct video_device
*pvdev
;
48 struct msm_v4l2_driver
*drv
;
51 spinlock_t read_queue_lock
;
54 static struct msm_v4l2_device
*g_pmsm_v4l2_dev
;
57 static DEFINE_MUTEX(msm_v4l2_opencnt_lock
);
59 static int msm_v4l2_open(struct file
*f
)
63 mutex_lock(&msm_v4l2_opencnt_lock
);
64 if (!g_pmsm_v4l2_dev
->opencnt
) {
65 rc
= g_pmsm_v4l2_dev
->drv
->open(
66 g_pmsm_v4l2_dev
->drv
->sync
,
69 g_pmsm_v4l2_dev
->opencnt
++;
70 mutex_unlock(&msm_v4l2_opencnt_lock
);
74 static int msm_v4l2_release(struct file
*f
)
78 mutex_lock(&msm_v4l2_opencnt_lock
);
79 if (!g_pmsm_v4l2_dev
->opencnt
) {
80 g_pmsm_v4l2_dev
->opencnt
--;
81 if (!g_pmsm_v4l2_dev
->opencnt
) {
82 rc
= g_pmsm_v4l2_dev
->drv
->release(
83 g_pmsm_v4l2_dev
->drv
->sync
);
86 mutex_unlock(&msm_v4l2_opencnt_lock
);
90 static unsigned int msm_v4l2_poll(struct file
*f
, struct poll_table_struct
*w
)
92 return g_pmsm_v4l2_dev
->drv
->drv_poll(g_pmsm_v4l2_dev
->drv
->sync
, f
, w
);
95 static long msm_v4l2_ioctl(struct file
*filep
,
96 unsigned int cmd
, unsigned long arg
)
98 struct msm_ctrl_cmd
*ctrlcmd
;
100 D("msm_v4l2_ioctl, cmd = %d, %d\n", cmd
, __LINE__
);
103 case MSM_V4L2_START_SNAPSHOT
:
105 ctrlcmd
= kmalloc(sizeof(struct msm_ctrl_cmd
), GFP_ATOMIC
);
107 CDBG("msm_v4l2_ioctl: cannot allocate buffer\n");
112 ctrlcmd
->value
= NULL
;
113 ctrlcmd
->timeout_ms
= 10000;
115 D("msm_v4l2_ioctl, MSM_V4L2_START_SNAPSHOT v4l2 ioctl %d\n",
117 ctrlcmd
->type
= MSM_V4L2_SNAPSHOT
;
118 return g_pmsm_v4l2_dev
->drv
->ctrl(g_pmsm_v4l2_dev
->drv
->sync
,
121 case MSM_V4L2_GET_PICTURE
:
122 D("msm_v4l2_ioctl, MSM_V4L2_GET_PICTURE v4l2 ioctl %d\n", cmd
);
123 ctrlcmd
= (struct msm_ctrl_cmd
*)arg
;
124 return g_pmsm_v4l2_dev
->drv
->get_pict(
125 g_pmsm_v4l2_dev
->drv
->sync
, ctrlcmd
);
128 D("msm_v4l2_ioctl, standard v4l2 ioctl %d\n", cmd
);
129 return video_ioctl2(filep
, cmd
, arg
);
133 static void msm_v4l2_release_dev(struct video_device
*d
)
138 static int msm_v4l2_querycap(struct file
*f
,
139 void *pctx
, struct v4l2_capability
*pcaps
)
142 strncpy(pcaps
->driver
, MSM_APPS_ID_V4L2
, sizeof(pcaps
->driver
));
144 MSM_V4L2_DEVICE_NAME
, sizeof(pcaps
->card
));
145 pcaps
->capabilities
= V4L2_CAP_VIDEO_CAPTURE
| V4L2_CAP_STREAMING
;
149 static int msm_v4l2_s_std(struct file
*f
, void *pctx
, v4l2_std_id
*pnorm
)
155 static int msm_v4l2_queryctrl(struct file
*f
,
156 void *pctx
, struct v4l2_queryctrl
*pqctrl
)
159 struct msm_ctrl_cmd
*ctrlcmd
;
163 ctrlcmd
= kmalloc(sizeof(struct msm_ctrl_cmd
), GFP_ATOMIC
);
165 CDBG("msm_v4l2_queryctrl: cannot allocate buffer\n");
169 ctrlcmd
->type
= MSM_V4L2_QUERY_CTRL
;
170 ctrlcmd
->length
= sizeof(struct v4l2_queryctrl
);
171 ctrlcmd
->value
= pqctrl
;
172 ctrlcmd
->timeout_ms
= 10000;
174 rc
= g_pmsm_v4l2_dev
->drv
->ctrl(g_pmsm_v4l2_dev
->drv
->sync
, ctrlcmd
);
178 return ctrlcmd
->status
;
181 static int msm_v4l2_g_ctrl(struct file
*f
, void *pctx
, struct v4l2_control
*c
)
184 struct msm_ctrl_cmd
*ctrlcmd
;
188 ctrlcmd
= kmalloc(sizeof(struct msm_ctrl_cmd
), GFP_ATOMIC
);
190 CDBG("msm_v4l2_g_ctrl: cannot allocate buffer\n");
194 ctrlcmd
->type
= MSM_V4L2_GET_CTRL
;
195 ctrlcmd
->length
= sizeof(struct v4l2_control
);
197 ctrlcmd
->timeout_ms
= 10000;
199 rc
= g_pmsm_v4l2_dev
->drv
->ctrl(g_pmsm_v4l2_dev
->drv
->sync
, ctrlcmd
);
203 return ctrlcmd
->status
;
206 static int msm_v4l2_s_ctrl(struct file
*f
, void *pctx
, struct v4l2_control
*c
)
209 struct msm_ctrl_cmd
*ctrlcmd
;
211 ctrlcmd
= kmalloc(sizeof(struct msm_ctrl_cmd
), GFP_ATOMIC
);
213 CDBG("msm_v4l2_s_ctrl: cannot allocate buffer\n");
217 ctrlcmd
->type
= MSM_V4L2_SET_CTRL
;
218 ctrlcmd
->length
= sizeof(struct v4l2_control
);
220 ctrlcmd
->timeout_ms
= 10000;
224 rc
= g_pmsm_v4l2_dev
->drv
->ctrl(g_pmsm_v4l2_dev
->drv
->sync
, ctrlcmd
);
228 return ctrlcmd
->status
;
231 static int msm_v4l2_reqbufs(struct file
*f
,
232 void *pctx
, struct v4l2_requestbuffers
*b
)
238 static int msm_v4l2_querybuf(struct file
*f
, void *pctx
, struct v4l2_buffer
*pb
)
240 struct msm_pmem_info pmem_buf
;
242 __u32 y_pad
= pb
->bytesused
% 4;
244 /* V4L2 videodev will do the copy_from_user. */
246 memset(&pmem_buf
, 0, sizeof(struct msm_pmem_info
));
247 pmem_buf
.type
= MSM_PMEM_OUTPUT2
;
248 pmem_buf
.vaddr
= (void *)pb
->m
.userptr
;
250 pmem_buf
.fd
= (int)pb
->reserved
;
251 /* pmem_buf.cbcr_off = (y_size + y_pad); */
252 pmem_buf
.cbcr_off
= (pb
->bytesused
+ y_pad
);
254 g_pmsm_v4l2_dev
->drv
->reg_pmem(g_pmsm_v4l2_dev
->drv
->sync
, &pmem_buf
);
259 static int msm_v4l2_qbuf(struct file
*f
, void *pctx
, struct v4l2_buffer
*pb
)
270 struct msm_pmem_info meminfo
;
271 struct msm_frame frame
;
274 if ((pb
->flags
>> 16) & 0x0001) {
275 /* this is for previwe */
277 y_pad
= pb
->bytesused
% 4;
279 if (pb
->type
== V4L2_BUF_TYPE_PRIVATE
) {
280 /* this qbuf is actually for releasing */
282 frame
.buffer
= pb
->m
.userptr
;
284 /* frame.cbcr_off = (y_size + y_pad); */
285 frame
.cbcr_off
= (pb
->bytesused
+ y_pad
);
286 frame
.fd
= pb
->reserved
;
288 D("V4L2_BUF_TYPE_PRIVATE: pb->bytesused = %d \n",
291 g_pmsm_v4l2_dev
->drv
->put_frame(
292 g_pmsm_v4l2_dev
->drv
->sync
,
298 D("V4L2_BUF_TYPE_VIDEO_CAPTURE: pb->bytesused = %d \n",
301 meminfo
.type
= MSM_PMEM_OUTPUT2
;
302 meminfo
.fd
= (int)pb
->reserved
;
303 meminfo
.vaddr
= (void *)pb
->m
.userptr
;
305 /* meminfo.cbcr_off = (y_size + y_pad); */
306 meminfo
.cbcr_off
= (pb
->bytesused
+ y_pad
);
307 if (cnt
== PREVIEW_FRAMES_NUM
- 1)
312 g_pmsm_v4l2_dev
->drv
->reg_pmem(g_pmsm_v4l2_dev
->drv
->sync
,
314 } else if ((pb
->flags
) & 0x0001) {
315 /* this is for snapshot */
319 if ((pb
->flags
>> 8) & 0x01) {
321 y_size
= pb
->bytesused
;
323 meminfo
.type
= MSM_PMEM_THUMBAIL
;
324 } else if ((pb
->flags
>> 9) & 0x01) {
326 y_size
= pb
->bytesused
;
328 meminfo
.type
= MSM_PMEM_MAINIMG
;
333 meminfo
.fd
= (int)pb
->reserved
;
334 meminfo
.vaddr
= (void *)pb
->m
.userptr
;
336 /* meminfo.cbcr_off = (y_size + y_pad); */
337 meminfo
.cbcr_off
= (y_size
+ y_pad
);
339 g_pmsm_v4l2_dev
->drv
->reg_pmem(g_pmsm_v4l2_dev
->drv
->sync
,
346 static int msm_v4l2_dqbuf(struct file
*f
, void *pctx
, struct v4l2_buffer
*pb
)
348 struct msm_frame frame
;
351 /* V4L2 videodev will do the copy_to_user. */
352 if (pb
->type
== V4L2_BUF_TYPE_VIDEO_CAPTURE
) {
354 D("%s, %d\n", __func__
, __LINE__
);
356 g_pmsm_v4l2_dev
->drv
->get_frame(
357 g_pmsm_v4l2_dev
->drv
->sync
,
360 pb
->type
= V4L2_BUF_TYPE_VIDEO_CAPTURE
;
361 pb
->m
.userptr
= (unsigned long)frame
.buffer
;
362 pb
->reserved
= (int)frame
.fd
;
363 /* pb->length = (int)frame.cbcr_off; */
365 pb
->bytesused
= frame
.cbcr_off
;
367 } else if (pb
->type
== V4L2_BUF_TYPE_PRIVATE
) {
368 __u32 y_pad
= pb
->bytesused
% 4;
370 frame
.buffer
= pb
->m
.userptr
;
372 /* frame.cbcr_off = (y_size + y_pad); */
373 frame
.cbcr_off
= (pb
->bytesused
+ y_pad
);
374 frame
.fd
= pb
->reserved
;
376 g_pmsm_v4l2_dev
->drv
->put_frame(
377 g_pmsm_v4l2_dev
->drv
->sync
,
384 static int msm_v4l2_streamon(struct file
*f
, void *pctx
, enum v4l2_buf_type i
)
386 struct msm_ctrl_cmd
*ctrlcmd
;
388 ctrlcmd
= kmalloc(sizeof(struct msm_ctrl_cmd
), GFP_ATOMIC
);
390 CDBG("msm_v4l2_s_fmt_cap: cannot allocate buffer\n");
394 ctrlcmd
->type
= MSM_V4L2_STREAM_ON
;
395 ctrlcmd
->timeout_ms
= 10000;
397 ctrlcmd
->value
= NULL
;
401 g_pmsm_v4l2_dev
->drv
->ctrl(
402 g_pmsm_v4l2_dev
->drv
->sync
,
405 D("%s after drv->ctrl \n", __func__
);
410 static int msm_v4l2_streamoff(struct file
*f
, void *pctx
, enum v4l2_buf_type i
)
412 struct msm_ctrl_cmd
*ctrlcmd
;
414 ctrlcmd
= kmalloc(sizeof(struct msm_ctrl_cmd
), GFP_ATOMIC
);
416 CDBG("msm_v4l2_s_fmt_cap: cannot allocate buffer\n");
420 ctrlcmd
->type
= MSM_V4L2_STREAM_OFF
;
421 ctrlcmd
->timeout_ms
= 10000;
423 ctrlcmd
->value
= NULL
;
428 g_pmsm_v4l2_dev
->drv
->ctrl(
429 g_pmsm_v4l2_dev
->drv
->sync
,
435 static int msm_v4l2_enum_fmt_overlay(struct file
*f
,
436 void *pctx
, struct v4l2_fmtdesc
*pfmtdesc
)
442 static int msm_v4l2_enum_fmt_cap(struct file
*f
,
443 void *pctx
, struct v4l2_fmtdesc
*pfmtdesc
)
447 switch (pfmtdesc
->index
) {
449 pfmtdesc
->type
= V4L2_BUF_TYPE_VIDEO_CAPTURE
;
451 strncpy(pfmtdesc
->description
, "YUV 4:2:0",
452 sizeof(pfmtdesc
->description
));
453 pfmtdesc
->pixelformat
= V4L2_PIX_FMT_YVU420
;
462 static int msm_v4l2_g_fmt_cap(struct file
*f
,
463 void *pctx
, struct v4l2_format
*pfmt
)
466 pfmt
->type
= V4L2_BUF_TYPE_VIDEO_CAPTURE
;
467 pfmt
->fmt
.pix
.width
= MSM_V4L2_WIDTH
;
468 pfmt
->fmt
.pix
.height
= MSM_V4L2_HEIGHT
;
469 pfmt
->fmt
.pix
.pixelformat
= V4L2_PIX_FMT_YVU420
;
470 pfmt
->fmt
.pix
.field
= V4L2_FIELD_ANY
;
471 pfmt
->fmt
.pix
.bytesperline
= 0;
472 pfmt
->fmt
.pix
.sizeimage
= 0;
473 pfmt
->fmt
.pix
.colorspace
= V4L2_COLORSPACE_JPEG
;
474 pfmt
->fmt
.pix
.priv
= 0;
478 static int msm_v4l2_s_fmt_cap(struct file
*f
,
479 void *pctx
, struct v4l2_format
*pfmt
)
481 struct msm_ctrl_cmd
*ctrlcmd
;
485 ctrlcmd
= kmalloc(sizeof(struct msm_ctrl_cmd
), GFP_ATOMIC
);
487 CDBG("msm_v4l2_s_fmt_cap: cannot allocate buffer\n");
491 ctrlcmd
->type
= MSM_V4L2_VID_CAP_TYPE
;
492 ctrlcmd
->length
= sizeof(struct v4l2_format
);
493 ctrlcmd
->value
= pfmt
;
494 ctrlcmd
->timeout_ms
= 10000;
496 if (pfmt
->type
!= V4L2_BUF_TYPE_VIDEO_CAPTURE
) {
502 /* Ok, but check other params, too. */
505 g_pmsm_v4l2_dev
->drv
->ctrl(g_pmsm_v4l2_dev
->drv
->sync
, ctrlcmd
);
510 static int msm_v4l2_g_fmt_overlay(struct file
*f
,
511 void *pctx
, struct v4l2_format
*pfmt
)
514 pfmt
->type
= V4L2_BUF_TYPE_VIDEO_OVERLAY
;
515 pfmt
->fmt
.pix
.width
= MSM_V4L2_WIDTH
;
516 pfmt
->fmt
.pix
.height
= MSM_V4L2_HEIGHT
;
517 pfmt
->fmt
.pix
.pixelformat
= V4L2_PIX_FMT_YVU420
;
518 pfmt
->fmt
.pix
.field
= V4L2_FIELD_ANY
;
519 pfmt
->fmt
.pix
.bytesperline
= 0;
520 pfmt
->fmt
.pix
.sizeimage
= 0;
521 pfmt
->fmt
.pix
.colorspace
= V4L2_COLORSPACE_JPEG
;
522 pfmt
->fmt
.pix
.priv
= 0;
526 static int msm_v4l2_s_fmt_overlay(struct file
*f
,
527 void *pctx
, struct v4l2_format
*pfmt
)
533 static int msm_v4l2_overlay(struct file
*f
, void *pctx
, unsigned int i
)
539 static int msm_v4l2_g_jpegcomp(struct file
*f
,
540 void *pctx
, struct v4l2_jpegcompression
*pcomp
)
546 static int msm_v4l2_s_jpegcomp(struct file
*f
,
547 void *pctx
, struct v4l2_jpegcompression
*pcomp
)
553 #ifdef CONFIG_PROC_FS
554 int msm_v4l2_read_proc(char *pbuf
, char **start
, off_t offset
,
555 int count
, int *eof
, void *data
)
558 len
+= snprintf(pbuf
, strlen("stats\n") + 1, "stats\n");
560 if (g_pmsm_v4l2_dev
) {
561 len
+= snprintf(pbuf
, strlen("mode: ") + 1, "mode: ");
563 if (g_pmsm_v4l2_dev
->current_cap_format
.type
564 == V4L2_BUF_TYPE_VIDEO_CAPTURE
)
565 len
+= snprintf(pbuf
, strlen("capture\n") + 1,
568 len
+= snprintf(pbuf
, strlen("unknown\n") + 1,
571 len
+= snprintf(pbuf
, 21, "resolution: %dx%d\n",
572 g_pmsm_v4l2_dev
->current_cap_format
.fmt
.pix
.
574 g_pmsm_v4l2_dev
->current_cap_format
.fmt
.pix
.
577 len
+= snprintf(pbuf
,
578 strlen("pixel format: ") + 1, "pixel format: ");
579 if (g_pmsm_v4l2_dev
->current_cap_format
.fmt
.pix
.pixelformat
580 == V4L2_PIX_FMT_YVU420
)
581 len
+= snprintf(pbuf
, strlen("yvu420\n") + 1,
584 len
+= snprintf(pbuf
, strlen("unknown\n") + 1,
587 len
+= snprintf(pbuf
, strlen("colorspace: ") + 1,
589 if (g_pmsm_v4l2_dev
->current_cap_format
.fmt
.pix
.colorspace
590 == V4L2_COLORSPACE_JPEG
)
591 len
+= snprintf(pbuf
, strlen("jpeg\n") + 1, "jpeg\n");
593 len
+= snprintf(pbuf
, strlen("unknown\n") + 1,
602 static const struct v4l2_file_operations msm_v4l2_fops
= {
603 .owner
= THIS_MODULE
,
604 .open
= msm_v4l2_open
,
605 .poll
= msm_v4l2_poll
,
606 .release
= msm_v4l2_release
,
607 .ioctl
= msm_v4l2_ioctl
,
610 static void msm_v4l2_dev_init(struct msm_v4l2_device
*pmsm_v4l2_dev
)
612 pmsm_v4l2_dev
->read_queue_lock
=
613 __SPIN_LOCK_UNLOCKED(pmsm_v4l2_dev
->read_queue_lock
);
614 INIT_LIST_HEAD(&pmsm_v4l2_dev
->read_queue
);
617 static int msm_v4l2_try_fmt_cap(struct file
*file
,
618 void *fh
, struct v4l2_format
*f
)
623 static int mm_v4l2_try_fmt_type_private(struct file
*file
,
624 void *fh
, struct v4l2_format
*f
)
630 * should the following structure be used instead of the code in the function?
631 * static const struct v4l2_ioctl_ops msm_v4l2_ioctl_ops = {
632 * .vidioc_querycap = ....
635 static const struct v4l2_ioctl_ops msm_ioctl_ops
= {
636 .vidioc_querycap
= msm_v4l2_querycap
,
637 .vidioc_s_std
= msm_v4l2_s_std
,
639 .vidioc_queryctrl
= msm_v4l2_queryctrl
,
640 .vidioc_g_ctrl
= msm_v4l2_g_ctrl
,
641 .vidioc_s_ctrl
= msm_v4l2_s_ctrl
,
643 .vidioc_reqbufs
= msm_v4l2_reqbufs
,
644 .vidioc_querybuf
= msm_v4l2_querybuf
,
645 .vidioc_qbuf
= msm_v4l2_qbuf
,
646 .vidioc_dqbuf
= msm_v4l2_dqbuf
,
648 .vidioc_streamon
= msm_v4l2_streamon
,
649 .vidioc_streamoff
= msm_v4l2_streamoff
,
651 .vidioc_enum_fmt_vid_overlay
= msm_v4l2_enum_fmt_overlay
,
652 .vidioc_enum_fmt_vid_cap
= msm_v4l2_enum_fmt_cap
,
654 .vidioc_try_fmt_vid_cap
= msm_v4l2_try_fmt_cap
,
655 .vidioc_try_fmt_type_private
= mm_v4l2_try_fmt_type_private
,
657 .vidioc_g_fmt_vid_cap
= msm_v4l2_g_fmt_cap
,
658 .vidioc_s_fmt_vid_cap
= msm_v4l2_s_fmt_cap
,
659 .vidioc_g_fmt_vid_overlay
= msm_v4l2_g_fmt_overlay
,
660 .vidioc_s_fmt_vid_overlay
= msm_v4l2_s_fmt_overlay
,
661 .vidioc_overlay
= msm_v4l2_overlay
,
663 .vidioc_g_jpegcomp
= msm_v4l2_g_jpegcomp
,
664 .vidioc_s_jpegcomp
= msm_v4l2_s_jpegcomp
,
667 static int msm_v4l2_video_dev_init(struct video_device
*pvd
)
669 strncpy(pvd
->name
, MSM_APPS_ID_V4L2
, sizeof(pvd
->name
));
671 pvd
->fops
= &msm_v4l2_fops
;
672 pvd
->release
= msm_v4l2_release_dev
;
674 pvd
->ioctl_ops
= &msm_ioctl_ops
;
675 return msm_v4l2_register(g_pmsm_v4l2_dev
->drv
);
678 static int __init
msm_v4l2_init(void)
681 struct video_device
*pvdev
= NULL
;
682 struct msm_v4l2_device
*pmsm_v4l2_dev
= NULL
;
685 pvdev
= video_device_alloc();
690 kzalloc(sizeof(struct msm_v4l2_device
), GFP_KERNEL
);
691 if (pmsm_v4l2_dev
== NULL
) {
692 video_device_release(pvdev
);
696 msm_v4l2_dev_init(pmsm_v4l2_dev
);
698 g_pmsm_v4l2_dev
= pmsm_v4l2_dev
;
699 g_pmsm_v4l2_dev
->pvdev
= pvdev
;
701 g_pmsm_v4l2_dev
->drv
=
702 kzalloc(sizeof(struct msm_v4l2_driver
), GFP_KERNEL
);
703 if (!g_pmsm_v4l2_dev
->drv
) {
704 video_device_release(pvdev
);
705 kfree(pmsm_v4l2_dev
);
709 rc
= msm_v4l2_video_dev_init(pvdev
);
711 video_device_release(pvdev
);
712 kfree(g_pmsm_v4l2_dev
->drv
);
713 kfree(pmsm_v4l2_dev
);
717 if (video_register_device(pvdev
, VFL_TYPE_GRABBER
,
718 MSM_V4L2_DEVNUM_YUV
)) {
719 D("failed to register device\n");
720 video_device_release(pvdev
);
721 kfree(g_pmsm_v4l2_dev
);
722 g_pmsm_v4l2_dev
= NULL
;
725 #ifdef CONFIG_PROC_FS
726 create_proc_read_entry(MSM_V4L2_PROC_NAME
,
727 0, NULL
, msm_v4l2_read_proc
, NULL
);
733 static void __exit
msm_v4l2_exit(void)
735 struct video_device
*pvdev
= g_pmsm_v4l2_dev
->pvdev
;
737 #ifdef CONFIG_PROC_FS
738 remove_proc_entry(MSM_V4L2_PROC_NAME
, NULL
);
740 video_unregister_device(pvdev
);
741 video_device_release(pvdev
);
743 msm_v4l2_unregister(g_pmsm_v4l2_dev
->drv
);
745 kfree(g_pmsm_v4l2_dev
->drv
);
746 g_pmsm_v4l2_dev
->drv
= NULL
;
748 kfree(g_pmsm_v4l2_dev
);
749 g_pmsm_v4l2_dev
= NULL
;
752 module_init(msm_v4l2_init
);
753 module_exit(msm_v4l2_exit
);
755 MODULE_DESCRIPTION("MSM V4L2 driver");
756 MODULE_LICENSE("GPL v2");