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