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
40 #define D(fmt, args...) printk(KERN_INFO "msm_v4l2: " fmt, ##args)
42 #define D(fmt, args...) do {} while (0)
45 #define PREVIEW_FRAMES_NUM 4
47 struct msm_v4l2_device
{
48 struct list_head read_queue
;
49 struct v4l2_format current_cap_format
;
50 struct v4l2_format current_pix_format
;
51 struct video_device
*pvdev
;
52 struct msm_v4l2_driver
*drv
;
55 spinlock_t read_queue_lock
;
58 static struct msm_v4l2_device
*g_pmsm_v4l2_dev
;
61 static DEFINE_MUTEX(msm_v4l2_opencnt_lock
);
63 static int msm_v4l2_open(struct file
*f
)
67 mutex_lock(&msm_v4l2_opencnt_lock
);
68 if (!g_pmsm_v4l2_dev
->opencnt
) {
69 rc
= g_pmsm_v4l2_dev
->drv
->open(
70 g_pmsm_v4l2_dev
->drv
->sync
,
73 g_pmsm_v4l2_dev
->opencnt
++;
74 mutex_unlock(&msm_v4l2_opencnt_lock
);
78 static int msm_v4l2_release(struct file
*f
)
82 mutex_lock(&msm_v4l2_opencnt_lock
);
83 if (!g_pmsm_v4l2_dev
->opencnt
) {
84 g_pmsm_v4l2_dev
->opencnt
--;
85 if (!g_pmsm_v4l2_dev
->opencnt
) {
86 rc
= g_pmsm_v4l2_dev
->drv
->release(
87 g_pmsm_v4l2_dev
->drv
->sync
);
90 mutex_unlock(&msm_v4l2_opencnt_lock
);
94 static unsigned int msm_v4l2_poll(struct file
*f
, struct poll_table_struct
*w
)
96 return g_pmsm_v4l2_dev
->drv
->drv_poll(g_pmsm_v4l2_dev
->drv
->sync
, f
, w
);
99 static long msm_v4l2_ioctl(struct file
*filep
,
100 unsigned int cmd
, unsigned long arg
)
102 struct msm_ctrl_cmd
*ctrlcmd
;
104 D("msm_v4l2_ioctl, cmd = %d, %d\n", cmd
, __LINE__
);
107 case MSM_V4L2_START_SNAPSHOT
:
109 ctrlcmd
= kmalloc(sizeof(struct msm_ctrl_cmd
), GFP_ATOMIC
);
111 CDBG("msm_v4l2_ioctl: cannot allocate buffer\n");
116 ctrlcmd
->value
= NULL
;
117 ctrlcmd
->timeout_ms
= 10000;
119 D("msm_v4l2_ioctl, MSM_V4L2_START_SNAPSHOT v4l2 ioctl %d\n",
121 ctrlcmd
->type
= MSM_V4L2_SNAPSHOT
;
122 return g_pmsm_v4l2_dev
->drv
->ctrl(g_pmsm_v4l2_dev
->drv
->sync
,
125 case MSM_V4L2_GET_PICTURE
:
126 D("msm_v4l2_ioctl, MSM_V4L2_GET_PICTURE v4l2 ioctl %d\n", cmd
);
127 ctrlcmd
= (struct msm_ctrl_cmd
*)arg
;
128 return g_pmsm_v4l2_dev
->drv
->get_pict(
129 g_pmsm_v4l2_dev
->drv
->sync
, ctrlcmd
);
132 D("msm_v4l2_ioctl, standard v4l2 ioctl %d\n", cmd
);
133 return video_ioctl2(filep
, cmd
, arg
);
137 static void msm_v4l2_release_dev(struct video_device
*d
)
142 static int msm_v4l2_querycap(struct file
*f
,
143 void *pctx
, struct v4l2_capability
*pcaps
)
146 strncpy(pcaps
->driver
, MSM_APPS_ID_V4L2
, sizeof(pcaps
->driver
));
148 MSM_V4L2_DEVICE_NAME
, sizeof(pcaps
->card
));
149 pcaps
->capabilities
= V4L2_CAP_VIDEO_CAPTURE
| V4L2_CAP_STREAMING
;
153 static int msm_v4l2_s_std(struct file
*f
, void *pctx
, v4l2_std_id
*pnorm
)
159 static int msm_v4l2_queryctrl(struct file
*f
,
160 void *pctx
, struct v4l2_queryctrl
*pqctrl
)
163 struct msm_ctrl_cmd
*ctrlcmd
;
167 ctrlcmd
= kmalloc(sizeof(struct msm_ctrl_cmd
), GFP_ATOMIC
);
169 CDBG("msm_v4l2_queryctrl: cannot allocate buffer\n");
173 ctrlcmd
->type
= MSM_V4L2_QUERY_CTRL
;
174 ctrlcmd
->length
= sizeof(struct v4l2_queryctrl
);
175 ctrlcmd
->value
= pqctrl
;
176 ctrlcmd
->timeout_ms
= 10000;
178 rc
= g_pmsm_v4l2_dev
->drv
->ctrl(g_pmsm_v4l2_dev
->drv
->sync
, ctrlcmd
);
182 return ctrlcmd
->status
;
185 static int msm_v4l2_g_ctrl(struct file
*f
, void *pctx
, struct v4l2_control
*c
)
188 struct msm_ctrl_cmd
*ctrlcmd
;
192 ctrlcmd
= kmalloc(sizeof(struct msm_ctrl_cmd
), GFP_ATOMIC
);
194 CDBG("msm_v4l2_g_ctrl: cannot allocate buffer\n");
198 ctrlcmd
->type
= MSM_V4L2_GET_CTRL
;
199 ctrlcmd
->length
= sizeof(struct v4l2_control
);
201 ctrlcmd
->timeout_ms
= 10000;
203 rc
= g_pmsm_v4l2_dev
->drv
->ctrl(g_pmsm_v4l2_dev
->drv
->sync
, ctrlcmd
);
207 return ctrlcmd
->status
;
210 static int msm_v4l2_s_ctrl(struct file
*f
, void *pctx
, struct v4l2_control
*c
)
213 struct msm_ctrl_cmd
*ctrlcmd
;
215 ctrlcmd
= kmalloc(sizeof(struct msm_ctrl_cmd
), GFP_ATOMIC
);
217 CDBG("msm_v4l2_s_ctrl: cannot allocate buffer\n");
221 ctrlcmd
->type
= MSM_V4L2_SET_CTRL
;
222 ctrlcmd
->length
= sizeof(struct v4l2_control
);
224 ctrlcmd
->timeout_ms
= 10000;
228 rc
= g_pmsm_v4l2_dev
->drv
->ctrl(g_pmsm_v4l2_dev
->drv
->sync
, ctrlcmd
);
232 return ctrlcmd
->status
;
235 static int msm_v4l2_reqbufs(struct file
*f
,
236 void *pctx
, struct v4l2_requestbuffers
*b
)
242 static int msm_v4l2_querybuf(struct file
*f
, void *pctx
, struct v4l2_buffer
*pb
)
244 struct msm_pmem_info pmem_buf
;
251 /* FIXME: g_pmsm_v4l2_dev->current_pix_format.fmt.pix.width; */
253 /* FIXME: g_pmsm_v4l2_dev->current_pix_format.fmt.pix.height; */
256 D("%s: width = %d, height = %d\n", __func__
, width
, height
);
258 y_size
= width
* height
;
262 __u32 y_pad
= pb
->bytesused
% 4;
264 /* V4L2 videodev will do the copy_from_user. */
266 memset(&pmem_buf
, 0, sizeof(struct msm_pmem_info
));
267 pmem_buf
.type
= MSM_PMEM_OUTPUT2
;
268 pmem_buf
.vaddr
= (void *)pb
->m
.userptr
;
270 pmem_buf
.fd
= (int)pb
->reserved
;
271 /* pmem_buf.cbcr_off = (y_size + y_pad); */
272 pmem_buf
.cbcr_off
= (pb
->bytesused
+ y_pad
);
274 g_pmsm_v4l2_dev
->drv
->reg_pmem(g_pmsm_v4l2_dev
->drv
->sync
, &pmem_buf
);
279 static int msm_v4l2_qbuf(struct file
*f
, void *pctx
, struct v4l2_buffer
*pb
)
290 struct msm_pmem_info meminfo
;
291 struct msm_frame frame
;
294 if ((pb
->flags
>> 16) & 0x0001) {
295 /* this is for previwe */
300 /* V4L2 videodev will do the copy_from_user. */
301 D("%s: width = %d, height = %d\n", __func__
, width
, height
);
302 y_size
= width
* height
;
306 y_pad
= pb
->bytesused
% 4;
308 if (pb
->type
== V4L2_BUF_TYPE_PRIVATE
) {
309 /* this qbuf is actually for releasing */
311 frame
.buffer
= pb
->m
.userptr
;
313 /* frame.cbcr_off = (y_size + y_pad); */
314 frame
.cbcr_off
= (pb
->bytesused
+ y_pad
);
315 frame
.fd
= pb
->reserved
;
317 D("V4L2_BUF_TYPE_PRIVATE: pb->bytesused = %d \n",
320 g_pmsm_v4l2_dev
->drv
->put_frame(
321 g_pmsm_v4l2_dev
->drv
->sync
,
327 D("V4L2_BUF_TYPE_VIDEO_CAPTURE: pb->bytesused = %d \n",
330 meminfo
.type
= MSM_PMEM_OUTPUT2
;
331 meminfo
.fd
= (int)pb
->reserved
;
332 meminfo
.vaddr
= (void *)pb
->m
.userptr
;
334 /* meminfo.cbcr_off = (y_size + y_pad); */
335 meminfo
.cbcr_off
= (pb
->bytesused
+ y_pad
);
336 if (cnt
== PREVIEW_FRAMES_NUM
- 1)
341 g_pmsm_v4l2_dev
->drv
->reg_pmem(g_pmsm_v4l2_dev
->drv
->sync
,
343 } else if ((pb
->flags
) & 0x0001) {
344 /* this is for snapshot */
348 if ((pb
->flags
>> 8) & 0x01) {
350 y_size
= pb
->bytesused
;
352 meminfo
.type
= MSM_PMEM_THUMBAIL
;
353 } else if ((pb
->flags
>> 9) & 0x01) {
355 y_size
= pb
->bytesused
;
357 meminfo
.type
= MSM_PMEM_MAINIMG
;
362 meminfo
.fd
= (int)pb
->reserved
;
363 meminfo
.vaddr
= (void *)pb
->m
.userptr
;
365 /* meminfo.cbcr_off = (y_size + y_pad); */
366 meminfo
.cbcr_off
= (y_size
+ y_pad
);
368 g_pmsm_v4l2_dev
->drv
->reg_pmem(g_pmsm_v4l2_dev
->drv
->sync
,
375 static int msm_v4l2_dqbuf(struct file
*f
, void *pctx
, struct v4l2_buffer
*pb
)
377 struct msm_frame frame
;
380 /* V4L2 videodev will do the copy_to_user. */
381 if (pb
->type
== V4L2_BUF_TYPE_VIDEO_CAPTURE
) {
383 D("%s, %d\n", __func__
, __LINE__
);
385 g_pmsm_v4l2_dev
->drv
->get_frame(
386 g_pmsm_v4l2_dev
->drv
->sync
,
389 pb
->type
= V4L2_BUF_TYPE_VIDEO_CAPTURE
;
390 pb
->m
.userptr
= (unsigned long)frame
.buffer
; /* FIXME */
391 pb
->reserved
= (int)frame
.fd
;
392 /* pb->length = (int)frame.cbcr_off; */
394 pb
->bytesused
= frame
.cbcr_off
;
396 } else if (pb
->type
== V4L2_BUF_TYPE_PRIVATE
) {
397 __u32 y_pad
= pb
->bytesused
% 4;
399 frame
.buffer
= pb
->m
.userptr
;
401 /* frame.cbcr_off = (y_size + y_pad); */
402 frame
.cbcr_off
= (pb
->bytesused
+ y_pad
);
403 frame
.fd
= pb
->reserved
;
405 g_pmsm_v4l2_dev
->drv
->put_frame(
406 g_pmsm_v4l2_dev
->drv
->sync
,
413 static int msm_v4l2_streamon(struct file
*f
, void *pctx
, enum v4l2_buf_type i
)
415 struct msm_ctrl_cmd
*ctrlcmd
;
417 ctrlcmd
= kmalloc(sizeof(struct msm_ctrl_cmd
), GFP_ATOMIC
);
419 CDBG("msm_v4l2_s_fmt_cap: cannot allocate buffer\n");
423 ctrlcmd
->type
= MSM_V4L2_STREAM_ON
;
424 ctrlcmd
->timeout_ms
= 10000;
426 ctrlcmd
->value
= NULL
;
430 g_pmsm_v4l2_dev
->drv
->ctrl(
431 g_pmsm_v4l2_dev
->drv
->sync
,
434 D("%s after drv->ctrl \n", __func__
);
439 static int msm_v4l2_streamoff(struct file
*f
, void *pctx
, enum v4l2_buf_type i
)
441 struct msm_ctrl_cmd
*ctrlcmd
;
443 ctrlcmd
= kmalloc(sizeof(struct msm_ctrl_cmd
), GFP_ATOMIC
);
445 CDBG("msm_v4l2_s_fmt_cap: cannot allocate buffer\n");
449 ctrlcmd
->type
= MSM_V4L2_STREAM_OFF
;
450 ctrlcmd
->timeout_ms
= 10000;
452 ctrlcmd
->value
= NULL
;
457 g_pmsm_v4l2_dev
->drv
->ctrl(
458 g_pmsm_v4l2_dev
->drv
->sync
,
464 static int msm_v4l2_enum_fmt_overlay(struct file
*f
,
465 void *pctx
, struct v4l2_fmtdesc
*pfmtdesc
)
471 static int msm_v4l2_enum_fmt_cap(struct file
*f
,
472 void *pctx
, struct v4l2_fmtdesc
*pfmtdesc
)
476 switch (pfmtdesc
->index
) {
478 pfmtdesc
->type
= V4L2_BUF_TYPE_VIDEO_CAPTURE
;
480 strncpy(pfmtdesc
->description
, "YUV 4:2:0",
481 sizeof(pfmtdesc
->description
));
482 pfmtdesc
->pixelformat
= V4L2_PIX_FMT_YVU420
;
491 static int msm_v4l2_g_fmt_cap(struct file
*f
,
492 void *pctx
, struct v4l2_format
*pfmt
)
495 pfmt
->type
= V4L2_BUF_TYPE_VIDEO_CAPTURE
;
496 pfmt
->fmt
.pix
.width
= MSM_V4L2_WIDTH
;
497 pfmt
->fmt
.pix
.height
= MSM_V4L2_HEIGHT
;
498 pfmt
->fmt
.pix
.pixelformat
= V4L2_PIX_FMT_YVU420
;
499 pfmt
->fmt
.pix
.field
= V4L2_FIELD_ANY
;
500 pfmt
->fmt
.pix
.bytesperline
= 0;
501 pfmt
->fmt
.pix
.sizeimage
= 0;
502 pfmt
->fmt
.pix
.colorspace
= V4L2_COLORSPACE_JPEG
;
503 pfmt
->fmt
.pix
.priv
= 0;
507 static int msm_v4l2_s_fmt_cap(struct file
*f
,
508 void *pctx
, struct v4l2_format
*pfmt
)
510 struct msm_ctrl_cmd
*ctrlcmd
;
514 ctrlcmd
= kmalloc(sizeof(struct msm_ctrl_cmd
), GFP_ATOMIC
);
516 CDBG("msm_v4l2_s_fmt_cap: cannot allocate buffer\n");
520 ctrlcmd
->type
= MSM_V4L2_VID_CAP_TYPE
;
521 ctrlcmd
->length
= sizeof(struct v4l2_format
);
522 ctrlcmd
->value
= pfmt
;
523 ctrlcmd
->timeout_ms
= 10000;
525 if (pfmt
->type
!= V4L2_BUF_TYPE_VIDEO_CAPTURE
) {
532 if (pfmt
->fmt
.pix
.pixelformat
!= V4L2_PIX_FMT_YVU420
) {
538 /* Ok, but check other params, too. */
541 memcpy(&g_pmsm_v4l2_dev
->current_pix_format
.fmt
.pix
, pfmt
,
542 sizeof(struct v4l2_format
));
545 g_pmsm_v4l2_dev
->drv
->ctrl(g_pmsm_v4l2_dev
->drv
->sync
, ctrlcmd
);
550 static int msm_v4l2_g_fmt_overlay(struct file
*f
,
551 void *pctx
, struct v4l2_format
*pfmt
)
554 pfmt
->type
= V4L2_BUF_TYPE_VIDEO_OVERLAY
;
555 pfmt
->fmt
.pix
.width
= MSM_V4L2_WIDTH
;
556 pfmt
->fmt
.pix
.height
= MSM_V4L2_HEIGHT
;
557 pfmt
->fmt
.pix
.pixelformat
= V4L2_PIX_FMT_YVU420
;
558 pfmt
->fmt
.pix
.field
= V4L2_FIELD_ANY
;
559 pfmt
->fmt
.pix
.bytesperline
= 0;
560 pfmt
->fmt
.pix
.sizeimage
= 0;
561 pfmt
->fmt
.pix
.colorspace
= V4L2_COLORSPACE_JPEG
;
562 pfmt
->fmt
.pix
.priv
= 0;
566 static int msm_v4l2_s_fmt_overlay(struct file
*f
,
567 void *pctx
, struct v4l2_format
*pfmt
)
573 static int msm_v4l2_overlay(struct file
*f
, void *pctx
, unsigned int i
)
579 static int msm_v4l2_g_jpegcomp(struct file
*f
,
580 void *pctx
, struct v4l2_jpegcompression
*pcomp
)
586 static int msm_v4l2_s_jpegcomp(struct file
*f
,
587 void *pctx
, struct v4l2_jpegcompression
*pcomp
)
593 #ifdef CONFIG_PROC_FS
594 int msm_v4l2_read_proc(char *pbuf
, char **start
, off_t offset
,
595 int count
, int *eof
, void *data
)
598 len
+= snprintf(pbuf
, strlen("stats\n") + 1, "stats\n");
600 if (g_pmsm_v4l2_dev
) {
601 len
+= snprintf(pbuf
, strlen("mode: ") + 1, "mode: ");
603 if (g_pmsm_v4l2_dev
->current_cap_format
.type
604 == V4L2_BUF_TYPE_VIDEO_CAPTURE
)
605 len
+= snprintf(pbuf
, strlen("capture\n") + 1,
608 len
+= snprintf(pbuf
, strlen("unknown\n") + 1,
611 len
+= snprintf(pbuf
, 21, "resolution: %dx%d\n",
612 g_pmsm_v4l2_dev
->current_cap_format
.fmt
.pix
.
614 g_pmsm_v4l2_dev
->current_cap_format
.fmt
.pix
.
617 len
+= snprintf(pbuf
,
618 strlen("pixel format: ") + 1, "pixel format: ");
619 if (g_pmsm_v4l2_dev
->current_cap_format
.fmt
.pix
.pixelformat
620 == V4L2_PIX_FMT_YVU420
)
621 len
+= snprintf(pbuf
, strlen("yvu420\n") + 1,
624 len
+= snprintf(pbuf
, strlen("unknown\n") + 1,
627 len
+= snprintf(pbuf
, strlen("colorspace: ") + 1,
629 if (g_pmsm_v4l2_dev
->current_cap_format
.fmt
.pix
.colorspace
630 == V4L2_COLORSPACE_JPEG
)
631 len
+= snprintf(pbuf
, strlen("jpeg\n") + 1, "jpeg\n");
633 len
+= snprintf(pbuf
, strlen("unknown\n") + 1,
642 static const struct v4l2_file_operations msm_v4l2_fops
= {
643 .owner
= THIS_MODULE
,
644 .open
= msm_v4l2_open
,
645 .poll
= msm_v4l2_poll
,
646 .release
= msm_v4l2_release
,
647 .ioctl
= msm_v4l2_ioctl
,
650 static void msm_v4l2_dev_init(struct msm_v4l2_device
*pmsm_v4l2_dev
)
652 pmsm_v4l2_dev
->read_queue_lock
=
653 __SPIN_LOCK_UNLOCKED(pmsm_v4l2_dev
->read_queue_lock
);
654 INIT_LIST_HEAD(&pmsm_v4l2_dev
->read_queue
);
657 static int msm_v4l2_try_fmt_cap(struct file
*file
,
658 void *fh
, struct v4l2_format
*f
)
664 static int mm_v4l2_try_fmt_type_private(struct file
*file
,
665 void *fh
, struct v4l2_format
*f
)
672 * should the following structure be used instead of the code in the function?
673 * static const struct v4l2_ioctl_ops msm_v4l2_ioctl_ops = {
674 * .vidioc_querycap = ....
677 static const struct v4l2_ioctl_ops msm_ioctl_ops
= {
678 .vidioc_querycap
= msm_v4l2_querycap
,
679 .vidioc_s_std
= msm_v4l2_s_std
,
681 .vidioc_queryctrl
= msm_v4l2_queryctrl
,
682 .vidioc_g_ctrl
= msm_v4l2_g_ctrl
,
683 .vidioc_s_ctrl
= msm_v4l2_s_ctrl
,
685 .vidioc_reqbufs
= msm_v4l2_reqbufs
,
686 .vidioc_querybuf
= msm_v4l2_querybuf
,
687 .vidioc_qbuf
= msm_v4l2_qbuf
,
688 .vidioc_dqbuf
= msm_v4l2_dqbuf
,
690 .vidioc_streamon
= msm_v4l2_streamon
,
691 .vidioc_streamoff
= msm_v4l2_streamoff
,
693 .vidioc_enum_fmt_vid_overlay
= msm_v4l2_enum_fmt_overlay
,
694 .vidioc_enum_fmt_vid_cap
= msm_v4l2_enum_fmt_cap
,
696 .vidioc_try_fmt_vid_cap
= msm_v4l2_try_fmt_cap
,
697 .vidioc_try_fmt_type_private
= mm_v4l2_try_fmt_type_private
,
699 .vidioc_g_fmt_vid_cap
= msm_v4l2_g_fmt_cap
,
700 .vidioc_s_fmt_vid_cap
= msm_v4l2_s_fmt_cap
,
701 .vidioc_g_fmt_vid_overlay
= msm_v4l2_g_fmt_overlay
,
702 .vidioc_s_fmt_vid_overlay
= msm_v4l2_s_fmt_overlay
,
703 .vidioc_overlay
= msm_v4l2_overlay
,
705 .vidioc_g_jpegcomp
= msm_v4l2_g_jpegcomp
,
706 .vidioc_s_jpegcomp
= msm_v4l2_s_jpegcomp
,
709 static int msm_v4l2_video_dev_init(struct video_device
*pvd
)
711 strncpy(pvd
->name
, MSM_APPS_ID_V4L2
, sizeof(pvd
->name
));
713 pvd
->fops
= &msm_v4l2_fops
;
714 pvd
->release
= msm_v4l2_release_dev
;
716 pvd
->ioctl_ops
= &msm_ioctl_ops
;
717 return msm_v4l2_register(g_pmsm_v4l2_dev
->drv
);
720 static int __init
msm_v4l2_init(void)
723 struct video_device
*pvdev
= NULL
;
724 struct msm_v4l2_device
*pmsm_v4l2_dev
= NULL
;
727 pvdev
= video_device_alloc();
732 kzalloc(sizeof(struct msm_v4l2_device
), GFP_KERNEL
);
733 if (pmsm_v4l2_dev
== NULL
) {
734 video_device_release(pvdev
);
738 msm_v4l2_dev_init(pmsm_v4l2_dev
);
740 g_pmsm_v4l2_dev
= pmsm_v4l2_dev
;
741 g_pmsm_v4l2_dev
->pvdev
= pvdev
;
743 g_pmsm_v4l2_dev
->drv
=
744 kzalloc(sizeof(struct msm_v4l2_driver
), GFP_KERNEL
);
745 if (!g_pmsm_v4l2_dev
->drv
) {
746 video_device_release(pvdev
);
747 kfree(pmsm_v4l2_dev
);
751 rc
= msm_v4l2_video_dev_init(pvdev
);
753 video_device_release(pvdev
);
754 kfree(g_pmsm_v4l2_dev
->drv
);
755 kfree(pmsm_v4l2_dev
);
759 if (video_register_device(pvdev
, VFL_TYPE_GRABBER
,
760 MSM_V4L2_DEVNUM_YUV
)) {
761 D("failed to register device\n");
762 video_device_release(pvdev
);
763 kfree(g_pmsm_v4l2_dev
);
764 g_pmsm_v4l2_dev
= NULL
;
767 #ifdef CONFIG_PROC_FS
768 create_proc_read_entry(MSM_V4L2_PROC_NAME
,
769 0, NULL
, msm_v4l2_read_proc
, NULL
);
775 static void __exit
msm_v4l2_exit(void)
777 struct video_device
*pvdev
= g_pmsm_v4l2_dev
->pvdev
;
779 #ifdef CONFIG_PROC_FS
780 remove_proc_entry(MSM_V4L2_PROC_NAME
, NULL
);
782 video_unregister_device(pvdev
);
783 video_device_release(pvdev
);
785 msm_v4l2_unregister(g_pmsm_v4l2_dev
->drv
);
787 kfree(g_pmsm_v4l2_dev
->drv
);
788 g_pmsm_v4l2_dev
->drv
= NULL
;
790 kfree(g_pmsm_v4l2_dev
);
791 g_pmsm_v4l2_dev
= NULL
;
794 module_init(msm_v4l2_init
);
795 module_exit(msm_v4l2_exit
);
797 MODULE_DESCRIPTION("MSM V4L2 driver");
798 MODULE_LICENSE("GPL v2");