Ensure FMODE_NONOTIFY is not set by userspace
[pandora-kernel.git] / drivers / staging / dream / camera / msm_v4l2.c
1 /*
2  *
3  * Copyright (C) 2008-2009 QUALCOMM Incorporated.
4  *
5  */
6
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>*/
21
22 #define MSM_V4L2_START_SNAPSHOT _IOWR('V', BASE_VIDIOC_PRIVATE+1, \
23       struct v4l2_buffer)
24
25 #define MSM_V4L2_GET_PICTURE    _IOWR('V', BASE_VIDIOC_PRIVATE+2, \
26       struct v4l2_buffer)
27
28 #define MSM_V4L2_DEVICE_NAME       "msm_v4l2"
29
30 #define MSM_V4L2_PROC_NAME         "msm_v4l2"
31
32 #define MSM_V4L2_DEVNUM_MPEG2       0
33 #define MSM_V4L2_DEVNUM_YUV         20
34
35 /* HVGA-P (portrait) and HVGA-L (landscape) */
36 #define MSM_V4L2_WIDTH              480
37 #define MSM_V4L2_HEIGHT             320
38
39 #if 1
40 #define D(fmt, args...) printk(KERN_INFO "msm_v4l2: " fmt, ##args)
41 #else
42 #define D(fmt, args...) do {} while (0)
43 #endif
44
45 #define PREVIEW_FRAMES_NUM 4
46
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;
53         uint8_t opencnt;
54
55         spinlock_t read_queue_lock;
56 };
57
58 static struct msm_v4l2_device *g_pmsm_v4l2_dev;
59
60
61 static DEFINE_MUTEX(msm_v4l2_opencnt_lock);
62
63 static int msm_v4l2_open(struct file *f)
64 {
65         int rc = 0;
66         D("%s\n", __func__);
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,
71                                 MSM_APPS_ID_V4L2);
72         }
73         g_pmsm_v4l2_dev->opencnt++;
74         mutex_unlock(&msm_v4l2_opencnt_lock);
75         return rc;
76 }
77
78 static int msm_v4l2_release(struct file *f)
79 {
80         int rc = 0;
81         D("%s\n", __func__);
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);
88                 }
89         }
90         mutex_unlock(&msm_v4l2_opencnt_lock);
91         return rc;
92 }
93
94 static unsigned int msm_v4l2_poll(struct file *f, struct poll_table_struct *w)
95 {
96         return g_pmsm_v4l2_dev->drv->drv_poll(g_pmsm_v4l2_dev->drv->sync, f, w);
97 }
98
99 static long msm_v4l2_ioctl(struct file *filep,
100                            unsigned int cmd, unsigned long arg)
101 {
102         struct msm_ctrl_cmd *ctrlcmd;
103
104         D("msm_v4l2_ioctl, cmd = %d, %d\n", cmd, __LINE__);
105
106         switch (cmd) {
107         case MSM_V4L2_START_SNAPSHOT:
108
109                 ctrlcmd = kmalloc(sizeof(struct msm_ctrl_cmd), GFP_ATOMIC);
110                 if (!ctrlcmd) {
111                         CDBG("msm_v4l2_ioctl: cannot allocate buffer\n");
112                         return -ENOMEM;
113                 }
114
115                 ctrlcmd->length     = 0;
116                 ctrlcmd->value      = NULL;
117                 ctrlcmd->timeout_ms = 10000;
118
119                 D("msm_v4l2_ioctl,  MSM_V4L2_START_SNAPSHOT v4l2 ioctl %d\n",
120                 cmd);
121                 ctrlcmd->type = MSM_V4L2_SNAPSHOT;
122                 return g_pmsm_v4l2_dev->drv->ctrl(g_pmsm_v4l2_dev->drv->sync,
123                                                         ctrlcmd);
124
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);
130
131         default:
132                 D("msm_v4l2_ioctl, standard v4l2 ioctl %d\n", cmd);
133                 return video_ioctl2(filep, cmd, arg);
134         }
135 }
136
137 static void msm_v4l2_release_dev(struct video_device *d)
138 {
139         D("%s\n", __func__);
140 }
141
142 static int msm_v4l2_querycap(struct file *f,
143                              void *pctx, struct v4l2_capability *pcaps)
144 {
145         D("%s\n", __func__);
146         strncpy(pcaps->driver, MSM_APPS_ID_V4L2, sizeof(pcaps->driver));
147         strncpy(pcaps->card,
148                 MSM_V4L2_DEVICE_NAME, sizeof(pcaps->card));
149         pcaps->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
150         return 0;
151 }
152
153 static int msm_v4l2_s_std(struct file *f, void *pctx, v4l2_std_id *pnorm)
154 {
155         D("%s\n", __func__);
156         return 0;
157 }
158
159 static int msm_v4l2_queryctrl(struct file *f,
160                                 void *pctx, struct v4l2_queryctrl *pqctrl)
161 {
162   int rc = 0;
163   struct msm_ctrl_cmd *ctrlcmd;
164
165         D("%s\n", __func__);
166
167         ctrlcmd = kmalloc(sizeof(struct msm_ctrl_cmd), GFP_ATOMIC);
168         if (!ctrlcmd) {
169                 CDBG("msm_v4l2_queryctrl: cannot allocate buffer\n");
170                 return -ENOMEM;
171         }
172
173         ctrlcmd->type       = MSM_V4L2_QUERY_CTRL;
174         ctrlcmd->length     = sizeof(struct v4l2_queryctrl);
175         ctrlcmd->value      = pqctrl;
176         ctrlcmd->timeout_ms = 10000;
177
178         rc = g_pmsm_v4l2_dev->drv->ctrl(g_pmsm_v4l2_dev->drv->sync, ctrlcmd);
179         if (rc < 0)
180                 return -1;
181
182         return ctrlcmd->status;
183 }
184
185 static int msm_v4l2_g_ctrl(struct file *f, void *pctx, struct v4l2_control *c)
186 {
187         int rc = 0;
188         struct msm_ctrl_cmd *ctrlcmd;
189
190         D("%s\n", __func__);
191
192         ctrlcmd = kmalloc(sizeof(struct msm_ctrl_cmd), GFP_ATOMIC);
193         if (!ctrlcmd) {
194                 CDBG("msm_v4l2_g_ctrl: cannot allocate buffer\n");
195                 return -ENOMEM;
196         }
197
198         ctrlcmd->type       = MSM_V4L2_GET_CTRL;
199         ctrlcmd->length     = sizeof(struct v4l2_control);
200         ctrlcmd->value      = c;
201         ctrlcmd->timeout_ms = 10000;
202
203         rc = g_pmsm_v4l2_dev->drv->ctrl(g_pmsm_v4l2_dev->drv->sync, ctrlcmd);
204         if (rc < 0)
205                 return -1;
206
207         return ctrlcmd->status;
208 }
209
210 static int msm_v4l2_s_ctrl(struct file *f, void *pctx, struct v4l2_control *c)
211 {
212         int rc = 0;
213         struct msm_ctrl_cmd *ctrlcmd;
214
215         ctrlcmd = kmalloc(sizeof(struct msm_ctrl_cmd), GFP_ATOMIC);
216         if (!ctrlcmd) {
217                 CDBG("msm_v4l2_s_ctrl: cannot allocate buffer\n");
218                 return -ENOMEM;
219         }
220
221         ctrlcmd->type       = MSM_V4L2_SET_CTRL;
222         ctrlcmd->length     = sizeof(struct v4l2_control);
223         ctrlcmd->value      = c;
224         ctrlcmd->timeout_ms = 10000;
225
226         D("%s\n", __func__);
227
228         rc = g_pmsm_v4l2_dev->drv->ctrl(g_pmsm_v4l2_dev->drv->sync, ctrlcmd);
229         if (rc < 0)
230                 return -1;
231
232         return ctrlcmd->status;
233 }
234
235 static int msm_v4l2_reqbufs(struct file *f,
236                             void *pctx, struct v4l2_requestbuffers *b)
237 {
238         D("%s\n", __func__);
239         return 0;
240 }
241
242 static int msm_v4l2_querybuf(struct file *f, void *pctx, struct v4l2_buffer *pb)
243 {
244         struct msm_pmem_info pmem_buf;
245 #if 0
246         __u32 width = 0;
247         __u32 height = 0;
248         __u32 y_size = 0;
249         __u32 y_pad = 0;
250
251         /* FIXME: g_pmsm_v4l2_dev->current_pix_format.fmt.pix.width; */
252         width = 640;
253         /* FIXME: g_pmsm_v4l2_dev->current_pix_format.fmt.pix.height; */
254         height = 480;
255
256         D("%s: width = %d, height = %d\n", __func__, width, height);
257
258         y_size = width * height;
259         y_pad = y_size % 4;
260 #endif
261
262     __u32 y_pad = pb->bytesused % 4;
263
264         /* V4L2 videodev will do the copy_from_user. */
265
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;
269         pmem_buf.y_off = 0;
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);
273
274         g_pmsm_v4l2_dev->drv->reg_pmem(g_pmsm_v4l2_dev->drv->sync, &pmem_buf);
275
276         return 0;
277 }
278
279 static int msm_v4l2_qbuf(struct file *f, void *pctx, struct v4l2_buffer *pb)
280 {
281     /*
282         __u32 y_size = 0;
283         __u32 y_pad = 0;
284         __u32 width = 0;
285         __u32 height = 0;
286     */
287
288         __u32 y_pad = 0;
289
290         struct msm_pmem_info meminfo;
291         struct msm_frame frame;
292         static int cnt;
293
294         if ((pb->flags >> 16) & 0x0001) {
295                 /* this is for previwe */
296 #if 0
297                 width = 640;
298                 height = 480;
299
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;
303                 y_pad = y_size % 4;
304 #endif
305
306                 y_pad = pb->bytesused % 4;
307
308                 if (pb->type == V4L2_BUF_TYPE_PRIVATE) {
309                         /* this qbuf is actually for releasing */
310
311                         frame.buffer           = pb->m.userptr;
312                         frame.y_off            = 0;
313                         /* frame.cbcr_off = (y_size + y_pad); */
314                         frame.cbcr_off         = (pb->bytesused + y_pad);
315                         frame.fd               = pb->reserved;
316
317                         D("V4L2_BUF_TYPE_PRIVATE: pb->bytesused = %d \n",
318                         pb->bytesused);
319
320                         g_pmsm_v4l2_dev->drv->put_frame(
321                                 g_pmsm_v4l2_dev->drv->sync,
322                                 &frame);
323
324                         return 0;
325                 }
326
327                 D("V4L2_BUF_TYPE_VIDEO_CAPTURE: pb->bytesused = %d \n",
328                 pb->bytesused);
329
330                 meminfo.type             = MSM_PMEM_OUTPUT2;
331                 meminfo.fd               = (int)pb->reserved;
332                 meminfo.vaddr            = (void *)pb->m.userptr;
333                 meminfo.y_off            = 0;
334                 /* meminfo.cbcr_off = (y_size + y_pad); */
335                 meminfo.cbcr_off         = (pb->bytesused + y_pad);
336                 if (cnt == PREVIEW_FRAMES_NUM - 1)
337                         meminfo.active = 0;
338                 else
339                         meminfo.active = 1;
340                 cnt++;
341                 g_pmsm_v4l2_dev->drv->reg_pmem(g_pmsm_v4l2_dev->drv->sync,
342                                 &meminfo);
343         } else if ((pb->flags) & 0x0001) {
344                 /* this is for snapshot */
345
346         __u32 y_size = 0;
347
348         if ((pb->flags >> 8) & 0x01) {
349
350                 y_size = pb->bytesused;
351
352                 meminfo.type = MSM_PMEM_THUMBAIL;
353         } else if ((pb->flags >> 9) & 0x01) {
354
355                 y_size = pb->bytesused;
356
357                 meminfo.type = MSM_PMEM_MAINIMG;
358         }
359
360         y_pad = y_size % 4;
361
362         meminfo.fd         = (int)pb->reserved;
363         meminfo.vaddr      = (void *)pb->m.userptr;
364         meminfo.y_off      = 0;
365         /* meminfo.cbcr_off = (y_size + y_pad); */
366         meminfo.cbcr_off   = (y_size + y_pad);
367         meminfo.active     = 1;
368         g_pmsm_v4l2_dev->drv->reg_pmem(g_pmsm_v4l2_dev->drv->sync,
369                                         &meminfo);
370         }
371
372         return 0;
373 }
374
375 static int msm_v4l2_dqbuf(struct file *f, void *pctx, struct v4l2_buffer *pb)
376 {
377         struct msm_frame frame;
378         D("%s\n", __func__);
379
380         /* V4L2 videodev will do the copy_to_user. */
381         if (pb->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
382
383                 D("%s, %d\n", __func__, __LINE__);
384
385                 g_pmsm_v4l2_dev->drv->get_frame(
386                         g_pmsm_v4l2_dev->drv->sync,
387                         &frame);
388
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; */
393
394                 pb->bytesused  = frame.cbcr_off;
395
396         } else if (pb->type == V4L2_BUF_TYPE_PRIVATE) {
397                 __u32 y_pad     = pb->bytesused % 4;
398
399                 frame.buffer   = pb->m.userptr;
400                 frame.y_off    = 0;
401                 /* frame.cbcr_off = (y_size + y_pad); */
402                 frame.cbcr_off = (pb->bytesused + y_pad);
403                 frame.fd       = pb->reserved;
404
405                 g_pmsm_v4l2_dev->drv->put_frame(
406                         g_pmsm_v4l2_dev->drv->sync,
407                         &frame);
408         }
409
410         return 0;
411 }
412
413 static int msm_v4l2_streamon(struct file *f, void *pctx, enum v4l2_buf_type i)
414 {
415   struct msm_ctrl_cmd *ctrlcmd;
416
417         ctrlcmd = kmalloc(sizeof(struct msm_ctrl_cmd), GFP_ATOMIC);
418         if (!ctrlcmd) {
419                 CDBG("msm_v4l2_s_fmt_cap: cannot allocate buffer\n");
420                 return -ENOMEM;
421         }
422
423         ctrlcmd->type       = MSM_V4L2_STREAM_ON;
424         ctrlcmd->timeout_ms = 10000;
425         ctrlcmd->length     = 0;
426         ctrlcmd->value      = NULL;
427
428         D("%s\n", __func__);
429
430         g_pmsm_v4l2_dev->drv->ctrl(
431                 g_pmsm_v4l2_dev->drv->sync,
432                 ctrlcmd);
433
434         D("%s after drv->ctrl \n", __func__);
435
436         return 0;
437 }
438
439 static int msm_v4l2_streamoff(struct file *f, void *pctx, enum v4l2_buf_type i)
440 {
441   struct msm_ctrl_cmd *ctrlcmd;
442
443         ctrlcmd = kmalloc(sizeof(struct msm_ctrl_cmd), GFP_ATOMIC);
444         if (!ctrlcmd) {
445                 CDBG("msm_v4l2_s_fmt_cap: cannot allocate buffer\n");
446                 return -ENOMEM;
447         }
448
449         ctrlcmd->type       = MSM_V4L2_STREAM_OFF;
450         ctrlcmd->timeout_ms = 10000;
451         ctrlcmd->length     = 0;
452         ctrlcmd->value      = NULL;
453
454
455         D("%s\n", __func__);
456
457         g_pmsm_v4l2_dev->drv->ctrl(
458                 g_pmsm_v4l2_dev->drv->sync,
459                 ctrlcmd);
460
461         return 0;
462 }
463
464 static int msm_v4l2_enum_fmt_overlay(struct file *f,
465                                      void *pctx, struct v4l2_fmtdesc *pfmtdesc)
466 {
467         D("%s\n", __func__);
468         return 0;
469 }
470
471 static int msm_v4l2_enum_fmt_cap(struct file *f,
472                                  void *pctx, struct v4l2_fmtdesc *pfmtdesc)
473 {
474         D("%s\n", __func__);
475
476         switch (pfmtdesc->index) {
477         case 0:
478                 pfmtdesc->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
479                 pfmtdesc->flags = 0;
480                 strncpy(pfmtdesc->description, "YUV 4:2:0",
481                         sizeof(pfmtdesc->description));
482                 pfmtdesc->pixelformat = V4L2_PIX_FMT_YVU420;
483                 break;
484         default:
485                 return -EINVAL;
486         }
487
488         return 0;
489 }
490
491 static int msm_v4l2_g_fmt_cap(struct file *f,
492                               void *pctx, struct v4l2_format *pfmt)
493 {
494         D("%s\n", __func__);
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;
504         return 0;
505 }
506
507 static int msm_v4l2_s_fmt_cap(struct file *f,
508                               void *pctx, struct v4l2_format *pfmt)
509 {
510   struct msm_ctrl_cmd *ctrlcmd;
511
512         D("%s\n", __func__);
513
514         ctrlcmd = kmalloc(sizeof(struct msm_ctrl_cmd), GFP_ATOMIC);
515         if (!ctrlcmd) {
516                 CDBG("msm_v4l2_s_fmt_cap: cannot allocate buffer\n");
517                 return -ENOMEM;
518         }
519
520   ctrlcmd->type       = MSM_V4L2_VID_CAP_TYPE;
521   ctrlcmd->length     = sizeof(struct v4l2_format);
522   ctrlcmd->value      = pfmt;
523   ctrlcmd->timeout_ms = 10000;
524
525         if (pfmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
526                 kfree(ctrlcmd);
527                 return -1;
528         }
529
530 #if 0
531         /* FIXEME */
532         if (pfmt->fmt.pix.pixelformat != V4L2_PIX_FMT_YVU420) {
533                 kfree(ctrlcmd);
534                 return -EINVAL;
535         }
536 #endif
537
538         /* Ok, but check other params, too. */
539
540 #if 0
541         memcpy(&g_pmsm_v4l2_dev->current_pix_format.fmt.pix, pfmt,
542                sizeof(struct v4l2_format));
543 #endif
544
545         g_pmsm_v4l2_dev->drv->ctrl(g_pmsm_v4l2_dev->drv->sync, ctrlcmd);
546
547         return 0;
548 }
549
550 static int msm_v4l2_g_fmt_overlay(struct file *f,
551                                   void *pctx, struct v4l2_format *pfmt)
552 {
553         D("%s\n", __func__);
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;
563         return 0;
564 }
565
566 static int msm_v4l2_s_fmt_overlay(struct file *f,
567                                   void *pctx, struct v4l2_format *pfmt)
568 {
569         D("%s\n", __func__);
570         return 0;
571 }
572
573 static int msm_v4l2_overlay(struct file *f, void *pctx, unsigned int i)
574 {
575         D("%s\n", __func__);
576         return 0;
577 }
578
579 static int msm_v4l2_g_jpegcomp(struct file *f,
580                                void *pctx, struct v4l2_jpegcompression *pcomp)
581 {
582         D("%s\n", __func__);
583         return 0;
584 }
585
586 static int msm_v4l2_s_jpegcomp(struct file *f,
587                                void *pctx, struct v4l2_jpegcompression *pcomp)
588 {
589         D("%s\n", __func__);
590         return 0;
591 }
592
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)
596 {
597         int len = 0;
598         len += snprintf(pbuf, strlen("stats\n") + 1, "stats\n");
599
600         if (g_pmsm_v4l2_dev) {
601                 len += snprintf(pbuf, strlen("mode: ") + 1, "mode: ");
602
603                 if (g_pmsm_v4l2_dev->current_cap_format.type
604                     == V4L2_BUF_TYPE_VIDEO_CAPTURE)
605                         len += snprintf(pbuf, strlen("capture\n") + 1,
606                                         "capture\n");
607                 else
608                         len += snprintf(pbuf, strlen("unknown\n") + 1,
609                                         "unknown\n");
610
611                 len += snprintf(pbuf, 21, "resolution: %dx%d\n",
612                                 g_pmsm_v4l2_dev->current_cap_format.fmt.pix.
613                                 width,
614                                 g_pmsm_v4l2_dev->current_cap_format.fmt.pix.
615                                 height);
616
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,
622                                         "yvu420\n");
623                 else
624                         len += snprintf(pbuf, strlen("unknown\n") + 1,
625                                         "unknown\n");
626
627                 len += snprintf(pbuf, strlen("colorspace: ") + 1,
628                                 "colorspace: ");
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");
632                 else
633                         len += snprintf(pbuf, strlen("unknown\n") + 1,
634                                         "unknown\n");
635         }
636
637         *eof = 1;
638         return len;
639 }
640 #endif
641
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,
648 };
649
650 static void msm_v4l2_dev_init(struct msm_v4l2_device *pmsm_v4l2_dev)
651 {
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);
655 }
656
657 static int msm_v4l2_try_fmt_cap(struct file *file,
658                                  void *fh, struct v4l2_format *f)
659 {
660         /* FIXME */
661         return 0;
662 }
663
664 static int mm_v4l2_try_fmt_type_private(struct file *file,
665                                          void *fh, struct v4l2_format *f)
666 {
667         /* FIXME */
668         return 0;
669 }
670
671 /*
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 = ....
675  * }
676  */
677 static const struct v4l2_ioctl_ops msm_ioctl_ops = {
678         .vidioc_querycap = msm_v4l2_querycap,
679         .vidioc_s_std = msm_v4l2_s_std,
680
681         .vidioc_queryctrl = msm_v4l2_queryctrl,
682         .vidioc_g_ctrl = msm_v4l2_g_ctrl,
683         .vidioc_s_ctrl = msm_v4l2_s_ctrl,
684
685         .vidioc_reqbufs = msm_v4l2_reqbufs,
686         .vidioc_querybuf = msm_v4l2_querybuf,
687         .vidioc_qbuf = msm_v4l2_qbuf,
688         .vidioc_dqbuf = msm_v4l2_dqbuf,
689
690         .vidioc_streamon = msm_v4l2_streamon,
691         .vidioc_streamoff = msm_v4l2_streamoff,
692
693         .vidioc_enum_fmt_vid_overlay = msm_v4l2_enum_fmt_overlay,
694         .vidioc_enum_fmt_vid_cap = msm_v4l2_enum_fmt_cap,
695
696         .vidioc_try_fmt_vid_cap = msm_v4l2_try_fmt_cap,
697         .vidioc_try_fmt_type_private = mm_v4l2_try_fmt_type_private,
698
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,
704
705         .vidioc_g_jpegcomp = msm_v4l2_g_jpegcomp,
706         .vidioc_s_jpegcomp = msm_v4l2_s_jpegcomp,
707 };
708
709 static int msm_v4l2_video_dev_init(struct video_device *pvd)
710 {
711         strncpy(pvd->name, MSM_APPS_ID_V4L2, sizeof(pvd->name));
712         pvd->vfl_type = 1;
713         pvd->fops = &msm_v4l2_fops;
714         pvd->release = msm_v4l2_release_dev;
715         pvd->minor = -1;
716         pvd->ioctl_ops = &msm_ioctl_ops;
717         return msm_v4l2_register(g_pmsm_v4l2_dev->drv);
718 }
719
720 static int __init msm_v4l2_init(void)
721 {
722         int rc = -ENOMEM;
723         struct video_device *pvdev = NULL;
724         struct msm_v4l2_device *pmsm_v4l2_dev = NULL;
725         D("%s\n", __func__);
726
727         pvdev = video_device_alloc();
728         if (pvdev == NULL)
729                 return rc;
730
731         pmsm_v4l2_dev =
732                 kzalloc(sizeof(struct msm_v4l2_device), GFP_KERNEL);
733         if (pmsm_v4l2_dev == NULL) {
734                 video_device_release(pvdev);
735                 return rc;
736         }
737
738         msm_v4l2_dev_init(pmsm_v4l2_dev);
739
740         g_pmsm_v4l2_dev = pmsm_v4l2_dev;
741         g_pmsm_v4l2_dev->pvdev = pvdev;
742
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);
748                 return rc;
749         }
750
751         rc = msm_v4l2_video_dev_init(pvdev);
752         if (rc < 0) {
753                 video_device_release(pvdev);
754                 kfree(g_pmsm_v4l2_dev->drv);
755                 kfree(pmsm_v4l2_dev);
756                 return rc;
757         }
758
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;
765                 return -ENOENT;
766         }
767 #ifdef CONFIG_PROC_FS
768         create_proc_read_entry(MSM_V4L2_PROC_NAME,
769                                0, NULL, msm_v4l2_read_proc, NULL);
770 #endif
771
772         return 0;
773 }
774
775 static void __exit msm_v4l2_exit(void)
776 {
777         struct video_device *pvdev = g_pmsm_v4l2_dev->pvdev;
778         D("%s\n", __func__);
779 #ifdef CONFIG_PROC_FS
780         remove_proc_entry(MSM_V4L2_PROC_NAME, NULL);
781 #endif
782         video_unregister_device(pvdev);
783         video_device_release(pvdev);
784
785         msm_v4l2_unregister(g_pmsm_v4l2_dev->drv);
786
787         kfree(g_pmsm_v4l2_dev->drv);
788         g_pmsm_v4l2_dev->drv = NULL;
789
790         kfree(g_pmsm_v4l2_dev);
791         g_pmsm_v4l2_dev = NULL;
792 }
793
794 module_init(msm_v4l2_init);
795 module_exit(msm_v4l2_exit);
796
797 MODULE_DESCRIPTION("MSM V4L2 driver");
798 MODULE_LICENSE("GPL v2");