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