]> bbs.cooldavid.org Git - net-next-2.6.git/blame - drivers/staging/dream/camera/msm_v4l2.c
Merge branch 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jwessel...
[net-next-2.6.git] / drivers / staging / dream / camera / msm_v4l2.c
CommitLineData
eb7b797b
BS
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>
5a0e3ad6 15#include <linux/slab.h>
eb7b797b
BS
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
47struct 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
58static struct msm_v4l2_device *g_pmsm_v4l2_dev;
59
60
61static DEFINE_MUTEX(msm_v4l2_opencnt_lock);
62
63static 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
78static 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
94static 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
99static 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
137static void msm_v4l2_release_dev(struct video_device *d)
138{
139 D("%s\n", __func__);
140}
141
142static 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
153static 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
159static 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
185static 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
210static 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
235static 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
242static 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
279static 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
375static 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
413static 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
439static 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
464static 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
471static 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
491static 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
507static 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
2bb6a12a
JL
525 if (pfmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
526 kfree(ctrlcmd);
eb7b797b 527 return -1;
2bb6a12a 528 }
eb7b797b
BS
529
530#if 0
531 /* FIXEME */
2bb6a12a
JL
532 if (pfmt->fmt.pix.pixelformat != V4L2_PIX_FMT_YVU420) {
533 kfree(ctrlcmd);
eb7b797b 534 return -EINVAL;
2bb6a12a 535 }
eb7b797b
BS
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
550static 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
566static 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
573static int msm_v4l2_overlay(struct file *f, void *pctx, unsigned int i)
574{
575 D("%s\n", __func__);
576 return 0;
577}
578
579static 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
586static 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
594int 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
642static 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
650static 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
657static int msm_v4l2_try_fmt_cap(struct file *file,
658 void *fh, struct v4l2_format *f)
659{
660 /* FIXME */
661 return 0;
662}
663
664static 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 */
677static 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
709static 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
720static 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
775static 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
794module_init(msm_v4l2_init);
795module_exit(msm_v4l2_exit);
796
797MODULE_DESCRIPTION("MSM V4L2 driver");
798MODULE_LICENSE("GPL v2");