• 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.36/drivers/media/video/pwc/
1/* Linux driver for Philips webcam
2   USB and Video4Linux interface part.
3   (C) 1999-2004 Nemosoft Unv.
4   (C) 2004-2006 Luc Saillard (luc@saillard.org)
5
6   NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
7   driver and thus may have bugs that are not present in the original version.
8   Please send bug reports and support requests to <luc@saillard.org>.
9   The decompression routines have been implemented by reverse-engineering the
10   Nemosoft binary pwcx module. Caveat emptor.
11
12   This program is free software; you can redistribute it and/or modify
13   it under the terms of the GNU General Public License as published by
14   the Free Software Foundation; either version 2 of the License, or
15   (at your option) any later version.
16
17   This program is distributed in the hope that it will be useful,
18   but WITHOUT ANY WARRANTY; without even the implied warranty of
19   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20   GNU General Public License for more details.
21
22   You should have received a copy of the GNU General Public License
23   along with this program; if not, write to the Free Software
24   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
25
26*/
27
28#include <linux/errno.h>
29#include <linux/init.h>
30#include <linux/mm.h>
31#include <linux/module.h>
32#include <linux/poll.h>
33#include <linux/vmalloc.h>
34#include <asm/io.h>
35
36#include "pwc.h"
37
38static struct v4l2_queryctrl pwc_controls[] = {
39	{
40	    .id      = V4L2_CID_BRIGHTNESS,
41	    .type    = V4L2_CTRL_TYPE_INTEGER,
42	    .name    = "Brightness",
43	    .minimum = 0,
44	    .maximum = 128,
45	    .step    = 1,
46	    .default_value = 64,
47	},
48	{
49	    .id      = V4L2_CID_CONTRAST,
50	    .type    = V4L2_CTRL_TYPE_INTEGER,
51	    .name    = "Contrast",
52	    .minimum = 0,
53	    .maximum = 64,
54	    .step    = 1,
55	    .default_value = 0,
56	},
57	{
58	    .id      = V4L2_CID_SATURATION,
59	    .type    = V4L2_CTRL_TYPE_INTEGER,
60	    .name    = "Saturation",
61	    .minimum = -100,
62	    .maximum = 100,
63	    .step    = 1,
64	    .default_value = 0,
65	},
66	{
67	    .id      = V4L2_CID_GAMMA,
68	    .type    = V4L2_CTRL_TYPE_INTEGER,
69	    .name    = "Gamma",
70	    .minimum = 0,
71	    .maximum = 32,
72	    .step    = 1,
73	    .default_value = 0,
74	},
75	{
76	    .id      = V4L2_CID_RED_BALANCE,
77	    .type    = V4L2_CTRL_TYPE_INTEGER,
78	    .name    = "Red Gain",
79	    .minimum = 0,
80	    .maximum = 256,
81	    .step    = 1,
82	    .default_value = 0,
83	},
84	{
85	    .id      = V4L2_CID_BLUE_BALANCE,
86	    .type    = V4L2_CTRL_TYPE_INTEGER,
87	    .name    = "Blue Gain",
88	    .minimum = 0,
89	    .maximum = 256,
90	    .step    = 1,
91	    .default_value = 0,
92	},
93	{
94	    .id      = V4L2_CID_AUTO_WHITE_BALANCE,
95	    .type    = V4L2_CTRL_TYPE_BOOLEAN,
96	    .name    = "Auto White Balance",
97	    .minimum = 0,
98	    .maximum = 1,
99	    .step    = 1,
100	    .default_value = 0,
101	},
102	{
103	    .id      = V4L2_CID_EXPOSURE,
104	    .type    = V4L2_CTRL_TYPE_INTEGER,
105	    .name    = "Shutter Speed (Exposure)",
106	    .minimum = 0,
107	    .maximum = 256,
108	    .step    = 1,
109	    .default_value = 200,
110	},
111	{
112	    .id      = V4L2_CID_AUTOGAIN,
113	    .type    = V4L2_CTRL_TYPE_BOOLEAN,
114	    .name    = "Auto Gain Enabled",
115	    .minimum = 0,
116	    .maximum = 1,
117	    .step    = 1,
118	    .default_value = 1,
119	},
120	{
121	    .id      = V4L2_CID_GAIN,
122	    .type    = V4L2_CTRL_TYPE_INTEGER,
123	    .name    = "Gain Level",
124	    .minimum = 0,
125	    .maximum = 256,
126	    .step    = 1,
127	    .default_value = 0,
128	},
129	{
130	    .id      = V4L2_CID_PRIVATE_SAVE_USER,
131	    .type    = V4L2_CTRL_TYPE_BUTTON,
132	    .name    = "Save User Settings",
133	    .minimum = 0,
134	    .maximum = 0,
135	    .step    = 0,
136	    .default_value = 0,
137	},
138	{
139	    .id      = V4L2_CID_PRIVATE_RESTORE_USER,
140	    .type    = V4L2_CTRL_TYPE_BUTTON,
141	    .name    = "Restore User Settings",
142	    .minimum = 0,
143	    .maximum = 0,
144	    .step    = 0,
145	    .default_value = 0,
146	},
147	{
148	    .id      = V4L2_CID_PRIVATE_RESTORE_FACTORY,
149	    .type    = V4L2_CTRL_TYPE_BUTTON,
150	    .name    = "Restore Factory Settings",
151	    .minimum = 0,
152	    .maximum = 0,
153	    .step    = 0,
154	    .default_value = 0,
155	},
156	{
157	    .id      = V4L2_CID_PRIVATE_COLOUR_MODE,
158	    .type    = V4L2_CTRL_TYPE_BOOLEAN,
159	    .name    = "Colour mode",
160	    .minimum = 0,
161	    .maximum = 1,
162	    .step    = 1,
163	    .default_value = 0,
164	},
165	{
166	    .id      = V4L2_CID_PRIVATE_AUTOCONTOUR,
167	    .type    = V4L2_CTRL_TYPE_BOOLEAN,
168	    .name    = "Auto contour",
169	    .minimum = 0,
170	    .maximum = 1,
171	    .step    = 1,
172	    .default_value = 0,
173	},
174	{
175	    .id      = V4L2_CID_PRIVATE_CONTOUR,
176	    .type    = V4L2_CTRL_TYPE_INTEGER,
177	    .name    = "Contour",
178	    .minimum = 0,
179	    .maximum = 63,
180	    .step    = 1,
181	    .default_value = 0,
182	},
183	{
184	    .id      = V4L2_CID_PRIVATE_BACKLIGHT,
185	    .type    = V4L2_CTRL_TYPE_BOOLEAN,
186	    .name    = "Backlight compensation",
187	    .minimum = 0,
188	    .maximum = 1,
189	    .step    = 1,
190	    .default_value = 0,
191	},
192	{
193	  .id      = V4L2_CID_PRIVATE_FLICKERLESS,
194	    .type    = V4L2_CTRL_TYPE_BOOLEAN,
195	    .name    = "Flickerless",
196	    .minimum = 0,
197	    .maximum = 1,
198	    .step    = 1,
199	    .default_value = 0,
200	},
201	{
202	    .id      = V4L2_CID_PRIVATE_NOISE_REDUCTION,
203	    .type    = V4L2_CTRL_TYPE_INTEGER,
204	    .name    = "Noise reduction",
205	    .minimum = 0,
206	    .maximum = 3,
207	    .step    = 1,
208	    .default_value = 0,
209	},
210};
211
212
213static void pwc_vidioc_fill_fmt(const struct pwc_device *pdev, struct v4l2_format *f)
214{
215	memset(&f->fmt.pix, 0, sizeof(struct v4l2_pix_format));
216	f->fmt.pix.width        = pdev->view.x;
217	f->fmt.pix.height       = pdev->view.y;
218	f->fmt.pix.field        = V4L2_FIELD_NONE;
219	if (pdev->vpalette == VIDEO_PALETTE_YUV420P) {
220		f->fmt.pix.pixelformat  = V4L2_PIX_FMT_YUV420;
221		f->fmt.pix.bytesperline = (f->fmt.pix.width * 3)/2;
222		f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
223	} else {
224		/* vbandlength contains 4 lines ...  */
225		f->fmt.pix.bytesperline = pdev->vbandlength/4;
226		f->fmt.pix.sizeimage = pdev->frame_size + sizeof(struct pwc_raw_frame);
227		if (DEVICE_USE_CODEC1(pdev->type))
228			f->fmt.pix.pixelformat  = V4L2_PIX_FMT_PWC1;
229		else
230			f->fmt.pix.pixelformat  = V4L2_PIX_FMT_PWC2;
231	}
232	PWC_DEBUG_IOCTL("pwc_vidioc_fill_fmt() "
233			"width=%d, height=%d, bytesperline=%d, sizeimage=%d, pixelformat=%c%c%c%c\n",
234			f->fmt.pix.width,
235			f->fmt.pix.height,
236			f->fmt.pix.bytesperline,
237			f->fmt.pix.sizeimage,
238			(f->fmt.pix.pixelformat)&255,
239			(f->fmt.pix.pixelformat>>8)&255,
240			(f->fmt.pix.pixelformat>>16)&255,
241			(f->fmt.pix.pixelformat>>24)&255);
242}
243
244/* ioctl(VIDIOC_TRY_FMT) */
245static int pwc_vidioc_try_fmt(struct pwc_device *pdev, struct v4l2_format *f)
246{
247	if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
248		PWC_DEBUG_IOCTL("Bad video type must be V4L2_BUF_TYPE_VIDEO_CAPTURE\n");
249		return -EINVAL;
250	}
251
252	switch (f->fmt.pix.pixelformat) {
253		case V4L2_PIX_FMT_YUV420:
254			break;
255		case V4L2_PIX_FMT_PWC1:
256			if (DEVICE_USE_CODEC23(pdev->type)) {
257				PWC_DEBUG_IOCTL("codec1 is only supported for old pwc webcam\n");
258				return -EINVAL;
259			}
260			break;
261		case V4L2_PIX_FMT_PWC2:
262			if (DEVICE_USE_CODEC1(pdev->type)) {
263				PWC_DEBUG_IOCTL("codec23 is only supported for new pwc webcam\n");
264				return -EINVAL;
265			}
266			break;
267		default:
268			PWC_DEBUG_IOCTL("Unsupported pixel format\n");
269			return -EINVAL;
270
271	}
272
273	if (f->fmt.pix.width > pdev->view_max.x)
274		f->fmt.pix.width = pdev->view_max.x;
275	else if (f->fmt.pix.width < pdev->view_min.x)
276		f->fmt.pix.width = pdev->view_min.x;
277
278	if (f->fmt.pix.height > pdev->view_max.y)
279		f->fmt.pix.height = pdev->view_max.y;
280	else if (f->fmt.pix.height < pdev->view_min.y)
281		f->fmt.pix.height = pdev->view_min.y;
282
283	return 0;
284}
285
286/* ioctl(VIDIOC_SET_FMT) */
287static int pwc_vidioc_set_fmt(struct pwc_device *pdev, struct v4l2_format *f)
288{
289	int ret, fps, snapshot, compression, pixelformat;
290
291	ret = pwc_vidioc_try_fmt(pdev, f);
292	if (ret<0)
293		return ret;
294
295	pixelformat = f->fmt.pix.pixelformat;
296	compression = pdev->vcompression;
297	snapshot = 0;
298	fps = pdev->vframes;
299	if (f->fmt.pix.priv) {
300		compression = (f->fmt.pix.priv & PWC_QLT_MASK) >> PWC_QLT_SHIFT;
301		snapshot = !!(f->fmt.pix.priv & PWC_FPS_SNAPSHOT);
302		fps = (f->fmt.pix.priv & PWC_FPS_FRMASK) >> PWC_FPS_SHIFT;
303		if (fps == 0)
304			fps = pdev->vframes;
305	}
306
307	if (pixelformat == V4L2_PIX_FMT_YUV420)
308		pdev->vpalette = VIDEO_PALETTE_YUV420P;
309	else
310		pdev->vpalette = VIDEO_PALETTE_RAW;
311
312	PWC_DEBUG_IOCTL("Try to change format to: width=%d height=%d fps=%d "
313			"compression=%d snapshot=%d format=%c%c%c%c\n",
314			f->fmt.pix.width, f->fmt.pix.height, fps,
315			compression, snapshot,
316			(pixelformat)&255,
317			(pixelformat>>8)&255,
318			(pixelformat>>16)&255,
319			(pixelformat>>24)&255);
320
321	ret = pwc_try_video_mode(pdev,
322				 f->fmt.pix.width,
323				 f->fmt.pix.height,
324				 fps,
325				 compression,
326				 snapshot);
327
328	PWC_DEBUG_IOCTL("pwc_try_video_mode(), return=%d\n", ret);
329
330	if (ret)
331		return ret;
332
333	pwc_vidioc_fill_fmt(pdev, f);
334
335	return 0;
336
337}
338
339long pwc_video_do_ioctl(struct file *file, unsigned int cmd, void *arg)
340{
341	struct video_device *vdev = video_devdata(file);
342	struct pwc_device *pdev;
343	DECLARE_WAITQUEUE(wait, current);
344
345	if (vdev == NULL)
346		return -EFAULT;
347	pdev = video_get_drvdata(vdev);
348	if (pdev == NULL)
349		return -EFAULT;
350
351#ifdef CONFIG_USB_PWC_DEBUG
352	if (PWC_DEBUG_LEVEL_IOCTL & pwc_trace) {
353		v4l_printk_ioctl(cmd);
354		printk("\n");
355	}
356#endif
357
358
359	switch (cmd) {
360		/* Query cabapilities */
361		case VIDIOCGCAP:
362		{
363			struct video_capability *caps = arg;
364
365			strcpy(caps->name, vdev->name);
366			caps->type = VID_TYPE_CAPTURE;
367			caps->channels = 1;
368			caps->audios = 1;
369			caps->minwidth  = pdev->view_min.x;
370			caps->minheight = pdev->view_min.y;
371			caps->maxwidth  = pdev->view_max.x;
372			caps->maxheight = pdev->view_max.y;
373			break;
374		}
375
376		/* Channel functions (simulate 1 channel) */
377		case VIDIOCGCHAN:
378		{
379			struct video_channel *v = arg;
380
381			if (v->channel != 0)
382				return -EINVAL;
383			v->flags = 0;
384			v->tuners = 0;
385			v->type = VIDEO_TYPE_CAMERA;
386			strcpy(v->name, "Webcam");
387			return 0;
388		}
389
390		case VIDIOCSCHAN:
391		{
392			/* The spec says the argument is an integer, but
393			   the bttv driver uses a video_channel arg, which
394			   makes sense becasue it also has the norm flag.
395			 */
396			struct video_channel *v = arg;
397			if (v->channel != 0)
398				return -EINVAL;
399			return 0;
400		}
401
402
403		/* Picture functions; contrast etc. */
404		case VIDIOCGPICT:
405		{
406			struct video_picture *p = arg;
407			int val;
408
409			val = pwc_get_brightness(pdev);
410			if (val >= 0)
411				p->brightness = (val<<9);
412			else
413				p->brightness = 0xffff;
414			val = pwc_get_contrast(pdev);
415			if (val >= 0)
416				p->contrast = (val<<10);
417			else
418				p->contrast = 0xffff;
419			/* Gamma, Whiteness, what's the difference? :) */
420			val = pwc_get_gamma(pdev);
421			if (val >= 0)
422				p->whiteness = (val<<11);
423			else
424				p->whiteness = 0xffff;
425			if (pwc_get_saturation(pdev, &val)<0)
426				p->colour = 0xffff;
427			else
428				p->colour = 32768 + val * 327;
429			p->depth = 24;
430			p->palette = pdev->vpalette;
431			p->hue = 0xFFFF; /* N/A */
432			break;
433		}
434
435		case VIDIOCSPICT:
436		{
437			struct video_picture *p = arg;
438			pwc_set_brightness(pdev, p->brightness);
439			pwc_set_contrast(pdev, p->contrast);
440			pwc_set_gamma(pdev, p->whiteness);
441			pwc_set_saturation(pdev, (p->colour-32768)/327);
442			if (p->palette && p->palette != pdev->vpalette) {
443				switch (p->palette) {
444					case VIDEO_PALETTE_YUV420P:
445					case VIDEO_PALETTE_RAW:
446						pdev->vpalette = p->palette;
447						return pwc_try_video_mode(pdev, pdev->image.x, pdev->image.y, pdev->vframes, pdev->vcompression, pdev->vsnapshot);
448						break;
449					default:
450						return -EINVAL;
451						break;
452				}
453			}
454			break;
455		}
456
457		/* Window/size parameters */
458		case VIDIOCGWIN:
459		{
460			struct video_window *vw = arg;
461
462			vw->x = 0;
463			vw->y = 0;
464			vw->width = pdev->view.x;
465			vw->height = pdev->view.y;
466			vw->chromakey = 0;
467			vw->flags = (pdev->vframes << PWC_FPS_SHIFT) |
468				   (pdev->vsnapshot ? PWC_FPS_SNAPSHOT : 0);
469			break;
470		}
471
472		case VIDIOCSWIN:
473		{
474			struct video_window *vw = arg;
475			int fps, snapshot, ret;
476
477			fps = (vw->flags & PWC_FPS_FRMASK) >> PWC_FPS_SHIFT;
478			snapshot = vw->flags & PWC_FPS_SNAPSHOT;
479			if (fps == 0)
480				fps = pdev->vframes;
481			if (pdev->view.x == vw->width && pdev->view.y && fps == pdev->vframes && snapshot == pdev->vsnapshot)
482				return 0;
483			ret = pwc_try_video_mode(pdev, vw->width, vw->height, fps, pdev->vcompression, snapshot);
484			if (ret)
485				return ret;
486			break;
487		}
488
489		/* We don't have overlay support (yet) */
490		case VIDIOCGFBUF:
491		{
492			struct video_buffer *vb = arg;
493
494			memset(vb,0,sizeof(*vb));
495			break;
496		}
497
498		/* mmap() functions */
499		case VIDIOCGMBUF:
500		{
501			/* Tell the user program how much memory is needed for a mmap() */
502			struct video_mbuf *vm = arg;
503			int i;
504
505			memset(vm, 0, sizeof(*vm));
506			vm->size = pwc_mbufs * pdev->len_per_image;
507			vm->frames = pwc_mbufs; /* double buffering should be enough for most applications */
508			for (i = 0; i < pwc_mbufs; i++)
509				vm->offsets[i] = i * pdev->len_per_image;
510			break;
511		}
512
513		case VIDIOCMCAPTURE:
514		{
515			/* Start capture into a given image buffer (called 'frame' in video_mmap structure) */
516			struct video_mmap *vm = arg;
517
518			PWC_DEBUG_READ("VIDIOCMCAPTURE: %dx%d, frame %d, format %d\n", vm->width, vm->height, vm->frame, vm->format);
519			if (vm->frame < 0 || vm->frame >= pwc_mbufs)
520				return -EINVAL;
521
522			/* xawtv is nasty. It probes the available palettes
523			   by setting a very small image size and trying
524			   various palettes... The driver doesn't support
525			   such small images, so I'm working around it.
526			 */
527			if (vm->format)
528			{
529				switch (vm->format)
530				{
531					case VIDEO_PALETTE_YUV420P:
532					case VIDEO_PALETTE_RAW:
533						break;
534					default:
535						return -EINVAL;
536						break;
537				}
538			}
539
540			if ((vm->width != pdev->view.x || vm->height != pdev->view.y) &&
541			    (vm->width >= pdev->view_min.x && vm->height >= pdev->view_min.y)) {
542				int ret;
543
544				PWC_DEBUG_OPEN("VIDIOCMCAPTURE: changing size to please xawtv :-(.\n");
545				ret = pwc_try_video_mode(pdev, vm->width, vm->height, pdev->vframes, pdev->vcompression, pdev->vsnapshot);
546				if (ret)
547					return ret;
548			} /* ... size mismatch */
549
550			if (pdev->image_used[vm->frame])
551				return -EBUSY;	/* buffer wasn't available. Bummer */
552			pdev->image_used[vm->frame] = 1;
553
554			/* Okay, we're done here. In the SYNC call we wait until a
555			   frame comes available, then expand image into the given
556			   buffer.
557			   In contrast to the CPiA cam the Philips cams deliver a
558			   constant stream, almost like a grabber card. Also,
559			   we have separate buffers for the rawdata and the image,
560			   meaning we can nearly always expand into the requested buffer.
561			 */
562			PWC_DEBUG_READ("VIDIOCMCAPTURE done.\n");
563			break;
564		}
565
566		case VIDIOCSYNC:
567		{
568			/* The doc says: "Whenever a buffer is used it should
569			   call VIDIOCSYNC to free this frame up and continue."
570
571			   The only odd thing about this whole procedure is
572			   that MCAPTURE flags the buffer as "in use", and
573			   SYNC immediately unmarks it, while it isn't
574			   after SYNC that you know that the buffer actually
575			   got filled! So you better not start a CAPTURE in
576			   the same frame immediately (use double buffering).
577			   This is not a problem for this cam, since it has
578			   extra intermediate buffers, but a hardware
579			   grabber card will then overwrite the buffer
580			   you're working on.
581			 */
582			int *mbuf = arg;
583			int ret;
584
585			PWC_DEBUG_READ("VIDIOCSYNC called (%d).\n", *mbuf);
586
587			/* bounds check */
588			if (*mbuf < 0 || *mbuf >= pwc_mbufs)
589				return -EINVAL;
590			/* check if this buffer was requested anyway */
591			if (pdev->image_used[*mbuf] == 0)
592				return -EINVAL;
593
594			add_wait_queue(&pdev->frameq, &wait);
595			while (pdev->full_frames == NULL) {
596				/* Check for unplugged/etc. here */
597				if (pdev->error_status) {
598					remove_wait_queue(&pdev->frameq, &wait);
599					set_current_state(TASK_RUNNING);
600					return -pdev->error_status;
601				}
602
603				if (signal_pending(current)) {
604					remove_wait_queue(&pdev->frameq, &wait);
605					set_current_state(TASK_RUNNING);
606					return -ERESTARTSYS;
607				}
608				schedule();
609				set_current_state(TASK_INTERRUPTIBLE);
610			}
611			remove_wait_queue(&pdev->frameq, &wait);
612			set_current_state(TASK_RUNNING);
613
614			/* The frame is ready. Expand in the image buffer
615			   requested by the user. I don't care if you
616			   mmap() 5 buffers and request data in this order:
617			   buffer 4 2 3 0 1 2 3 0 4 3 1 . . .
618			   Grabber hardware may not be so forgiving.
619			 */
620			PWC_DEBUG_READ("VIDIOCSYNC: frame ready.\n");
621			pdev->fill_image = *mbuf; /* tell in which buffer we want the image to be expanded */
622			/* Decompress, etc */
623			ret = pwc_handle_frame(pdev);
624			pdev->image_used[*mbuf] = 0;
625			if (ret)
626				return -EFAULT;
627			break;
628		}
629
630		case VIDIOCGAUDIO:
631		{
632			struct video_audio *v = arg;
633
634			strcpy(v->name, "Microphone");
635			v->audio = -1; /* unknown audio minor */
636			v->flags = 0;
637			v->mode = VIDEO_SOUND_MONO;
638			v->volume = 0;
639			v->bass = 0;
640			v->treble = 0;
641			v->balance = 0x8000;
642			v->step = 1;
643			break;
644		}
645
646		case VIDIOCSAUDIO:
647		{
648			/* Dummy: nothing can be set */
649			break;
650		}
651
652		case VIDIOCGUNIT:
653		{
654			struct video_unit *vu = arg;
655
656			vu->video = pdev->vdev->minor & 0x3F;
657			vu->audio = -1; /* not known yet */
658			vu->vbi = -1;
659			vu->radio = -1;
660			vu->teletext = -1;
661			break;
662		}
663
664		/* V4L2 Layer */
665		case VIDIOC_QUERYCAP:
666		{
667		    struct v4l2_capability *cap = arg;
668
669		    PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYCAP) This application "\
670				       "try to use the v4l2 layer\n");
671		    strcpy(cap->driver,PWC_NAME);
672		    strlcpy(cap->card, vdev->name, sizeof(cap->card));
673		    usb_make_path(pdev->udev,cap->bus_info,sizeof(cap->bus_info));
674		    cap->version = PWC_VERSION_CODE;
675		    cap->capabilities =
676			V4L2_CAP_VIDEO_CAPTURE	|
677			V4L2_CAP_STREAMING	|
678			V4L2_CAP_READWRITE;
679		    return 0;
680		}
681
682		case VIDIOC_ENUMINPUT:
683		{
684		    struct v4l2_input *i = arg;
685
686		    if ( i->index )	/* Only one INPUT is supported */
687			  return -EINVAL;
688
689		    memset(i, 0, sizeof(struct v4l2_input));
690		    strcpy(i->name, "usb");
691		    return 0;
692		}
693
694		case VIDIOC_G_INPUT:
695		{
696		    int *i = arg;
697		    *i = 0;	/* Only one INPUT is supported */
698		    return 0;
699		}
700		case VIDIOC_S_INPUT:
701		{
702			int *i = arg;
703
704			if ( *i ) {	/* Only one INPUT is supported */
705				PWC_DEBUG_IOCTL("Only one input source is"\
706					" supported with this webcam.\n");
707				return -EINVAL;
708			}
709			return 0;
710		}
711
712		/* TODO: */
713		case VIDIOC_QUERYCTRL:
714		{
715			struct v4l2_queryctrl *c = arg;
716			int i;
717
718			PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYCTRL) query id=%d\n", c->id);
719			for (i=0; i<sizeof(pwc_controls)/sizeof(struct v4l2_queryctrl); i++) {
720				if (pwc_controls[i].id == c->id) {
721					PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYCTRL) found\n");
722					memcpy(c,&pwc_controls[i],sizeof(struct v4l2_queryctrl));
723					return 0;
724				}
725			}
726			PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYCTRL) not found\n");
727
728			return -EINVAL;
729		}
730		case VIDIOC_G_CTRL:
731		{
732			struct v4l2_control *c = arg;
733			int ret;
734
735			switch (c->id)
736			{
737				case V4L2_CID_BRIGHTNESS:
738					c->value = pwc_get_brightness(pdev);
739					if (c->value<0)
740						return -EINVAL;
741					return 0;
742				case V4L2_CID_CONTRAST:
743					c->value = pwc_get_contrast(pdev);
744					if (c->value<0)
745						return -EINVAL;
746					return 0;
747				case V4L2_CID_SATURATION:
748					ret = pwc_get_saturation(pdev, &c->value);
749					if (ret<0)
750						return -EINVAL;
751					return 0;
752				case V4L2_CID_GAMMA:
753					c->value = pwc_get_gamma(pdev);
754					if (c->value<0)
755						return -EINVAL;
756					return 0;
757				case V4L2_CID_RED_BALANCE:
758					ret = pwc_get_red_gain(pdev, &c->value);
759					if (ret<0)
760						return -EINVAL;
761					c->value >>= 8;
762					return 0;
763				case V4L2_CID_BLUE_BALANCE:
764					ret = pwc_get_blue_gain(pdev, &c->value);
765					if (ret<0)
766						return -EINVAL;
767					c->value >>= 8;
768					return 0;
769				case V4L2_CID_AUTO_WHITE_BALANCE:
770					ret = pwc_get_awb(pdev);
771					if (ret<0)
772						return -EINVAL;
773					c->value = (ret == PWC_WB_MANUAL)?0:1;
774					return 0;
775				case V4L2_CID_GAIN:
776					ret = pwc_get_agc(pdev, &c->value);
777					if (ret<0)
778						return -EINVAL;
779					c->value >>= 8;
780					return 0;
781				case V4L2_CID_AUTOGAIN:
782					ret = pwc_get_agc(pdev, &c->value);
783					if (ret<0)
784						return -EINVAL;
785					c->value = (c->value < 0)?1:0;
786					return 0;
787				case V4L2_CID_EXPOSURE:
788					ret = pwc_get_shutter_speed(pdev, &c->value);
789					if (ret<0)
790						return -EINVAL;
791					return 0;
792				case V4L2_CID_PRIVATE_COLOUR_MODE:
793					ret = pwc_get_colour_mode(pdev, &c->value);
794					if (ret < 0)
795						return -EINVAL;
796					return 0;
797				case V4L2_CID_PRIVATE_AUTOCONTOUR:
798					ret = pwc_get_contour(pdev, &c->value);
799					if (ret < 0)
800						return -EINVAL;
801					c->value=(c->value == -1?1:0);
802					return 0;
803				case V4L2_CID_PRIVATE_CONTOUR:
804					ret = pwc_get_contour(pdev, &c->value);
805					if (ret < 0)
806						return -EINVAL;
807					c->value >>= 10;
808					return 0;
809				case V4L2_CID_PRIVATE_BACKLIGHT:
810					ret = pwc_get_backlight(pdev, &c->value);
811					if (ret < 0)
812						return -EINVAL;
813					return 0;
814				case V4L2_CID_PRIVATE_FLICKERLESS:
815					ret = pwc_get_flicker(pdev, &c->value);
816					if (ret < 0)
817						return -EINVAL;
818					c->value=(c->value?1:0);
819					return 0;
820				case V4L2_CID_PRIVATE_NOISE_REDUCTION:
821					ret = pwc_get_dynamic_noise(pdev, &c->value);
822					if (ret < 0)
823						return -EINVAL;
824					return 0;
825
826				case V4L2_CID_PRIVATE_SAVE_USER:
827				case V4L2_CID_PRIVATE_RESTORE_USER:
828				case V4L2_CID_PRIVATE_RESTORE_FACTORY:
829					return -EINVAL;
830			}
831			return -EINVAL;
832		}
833		case VIDIOC_S_CTRL:
834		{
835			struct v4l2_control *c = arg;
836			int ret;
837
838			switch (c->id)
839			{
840				case V4L2_CID_BRIGHTNESS:
841					c->value <<= 9;
842					ret = pwc_set_brightness(pdev, c->value);
843					if (ret<0)
844						return -EINVAL;
845					return 0;
846				case V4L2_CID_CONTRAST:
847					c->value <<= 10;
848					ret = pwc_set_contrast(pdev, c->value);
849					if (ret<0)
850						return -EINVAL;
851					return 0;
852				case V4L2_CID_SATURATION:
853					ret = pwc_set_saturation(pdev, c->value);
854					if (ret<0)
855					  return -EINVAL;
856					return 0;
857				case V4L2_CID_GAMMA:
858					c->value <<= 11;
859					ret = pwc_set_gamma(pdev, c->value);
860					if (ret<0)
861						return -EINVAL;
862					return 0;
863				case V4L2_CID_RED_BALANCE:
864					c->value <<= 8;
865					ret = pwc_set_red_gain(pdev, c->value);
866					if (ret<0)
867						return -EINVAL;
868					return 0;
869				case V4L2_CID_BLUE_BALANCE:
870					c->value <<= 8;
871					ret = pwc_set_blue_gain(pdev, c->value);
872					if (ret<0)
873						return -EINVAL;
874					return 0;
875				case V4L2_CID_AUTO_WHITE_BALANCE:
876					c->value = (c->value == 0)?PWC_WB_MANUAL:PWC_WB_AUTO;
877					ret = pwc_set_awb(pdev, c->value);
878					if (ret<0)
879						return -EINVAL;
880					return 0;
881				case V4L2_CID_EXPOSURE:
882					c->value <<= 8;
883					ret = pwc_set_shutter_speed(pdev, c->value?0:1, c->value);
884					if (ret<0)
885						return -EINVAL;
886					return 0;
887				case V4L2_CID_AUTOGAIN:
888					/* autogain off means nothing without a gain */
889					if (c->value == 0)
890						return 0;
891					ret = pwc_set_agc(pdev, c->value, 0);
892					if (ret<0)
893						return -EINVAL;
894					return 0;
895				case V4L2_CID_GAIN:
896					c->value <<= 8;
897					ret = pwc_set_agc(pdev, 0, c->value);
898					if (ret<0)
899						return -EINVAL;
900					return 0;
901				case V4L2_CID_PRIVATE_SAVE_USER:
902					if (pwc_save_user(pdev))
903						return -EINVAL;
904					return 0;
905				case V4L2_CID_PRIVATE_RESTORE_USER:
906					if (pwc_restore_user(pdev))
907						return -EINVAL;
908					return 0;
909				case V4L2_CID_PRIVATE_RESTORE_FACTORY:
910					if (pwc_restore_factory(pdev))
911						return -EINVAL;
912					return 0;
913				case V4L2_CID_PRIVATE_COLOUR_MODE:
914					ret = pwc_set_colour_mode(pdev, c->value);
915					if (ret < 0)
916					  return -EINVAL;
917					return 0;
918				case V4L2_CID_PRIVATE_AUTOCONTOUR:
919				  c->value=(c->value == 1)?-1:0;
920				  ret = pwc_set_contour(pdev, c->value);
921				  if (ret < 0)
922				    return -EINVAL;
923				  return 0;
924				case V4L2_CID_PRIVATE_CONTOUR:
925				  c->value <<= 10;
926				  ret = pwc_set_contour(pdev, c->value);
927				  if (ret < 0)
928				    return -EINVAL;
929				  return 0;
930				case V4L2_CID_PRIVATE_BACKLIGHT:
931				  ret = pwc_set_backlight(pdev, c->value);
932				  if (ret < 0)
933				    return -EINVAL;
934				  return 0;
935				case V4L2_CID_PRIVATE_FLICKERLESS:
936				  ret = pwc_set_flicker(pdev, c->value);
937				  if (ret < 0)
938				    return -EINVAL;
939				case V4L2_CID_PRIVATE_NOISE_REDUCTION:
940				  ret = pwc_set_dynamic_noise(pdev, c->value);
941				  if (ret < 0)
942				    return -EINVAL;
943				  return 0;
944
945			}
946			return -EINVAL;
947		}
948
949		case VIDIOC_ENUM_FMT:
950		{
951			struct v4l2_fmtdesc *f = arg;
952			int index;
953
954			if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
955			      return -EINVAL;
956
957			/* We only support two format: the raw format, and YUV */
958			index = f->index;
959			memset(f,0,sizeof(struct v4l2_fmtdesc));
960			f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
961			f->index = index;
962			switch(index)
963			{
964				case 0:
965					/* RAW format */
966					f->pixelformat = pdev->type<=646?V4L2_PIX_FMT_PWC1:V4L2_PIX_FMT_PWC2;
967					f->flags = V4L2_FMT_FLAG_COMPRESSED;
968					strlcpy(f->description,"Raw Philips Webcam",sizeof(f->description));
969					break;
970				case 1:
971					f->pixelformat = V4L2_PIX_FMT_YUV420;
972					strlcpy(f->description,"4:2:0, planar, Y-Cb-Cr",sizeof(f->description));
973					break;
974				default:
975					return -EINVAL;
976			}
977			return 0;
978		}
979
980		case VIDIOC_G_FMT:
981		{
982			struct v4l2_format *f = arg;
983
984			PWC_DEBUG_IOCTL("ioctl(VIDIOC_G_FMT) return size %dx%d\n",pdev->image.x,pdev->image.y);
985			if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
986			      return -EINVAL;
987
988			pwc_vidioc_fill_fmt(pdev, f);
989
990			return 0;
991		}
992
993		case VIDIOC_TRY_FMT:
994			return pwc_vidioc_try_fmt(pdev, arg);
995
996		case VIDIOC_S_FMT:
997			return pwc_vidioc_set_fmt(pdev, arg);
998
999		case VIDIOC_G_STD:
1000		{
1001			v4l2_std_id *std = arg;
1002			*std = V4L2_STD_UNKNOWN;
1003			return 0;
1004		}
1005
1006		case VIDIOC_S_STD:
1007		{
1008			v4l2_std_id *std = arg;
1009			if (*std != V4L2_STD_UNKNOWN)
1010				return -EINVAL;
1011			return 0;
1012		}
1013
1014		case VIDIOC_ENUMSTD:
1015		{
1016			struct v4l2_standard *std = arg;
1017			if (std->index != 0)
1018				return -EINVAL;
1019			std->id = V4L2_STD_UNKNOWN;
1020			strlcpy(std->name, "webcam", sizeof(std->name));
1021			return 0;
1022		}
1023
1024		case VIDIOC_REQBUFS:
1025		{
1026			struct v4l2_requestbuffers *rb = arg;
1027			int nbuffers;
1028
1029			PWC_DEBUG_IOCTL("ioctl(VIDIOC_REQBUFS) count=%d\n",rb->count);
1030			if (rb->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
1031				return -EINVAL;
1032			if (rb->memory != V4L2_MEMORY_MMAP)
1033				return -EINVAL;
1034
1035			nbuffers = rb->count;
1036			if (nbuffers < 2)
1037				nbuffers = 2;
1038			else if (nbuffers > pwc_mbufs)
1039				nbuffers = pwc_mbufs;
1040			/* Force to use our # of buffers */
1041			rb->count = pwc_mbufs;
1042			return 0;
1043		}
1044
1045		case VIDIOC_QUERYBUF:
1046		{
1047			struct v4l2_buffer *buf = arg;
1048			int index;
1049
1050			PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYBUF) index=%d\n",buf->index);
1051			if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
1052				PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYBUF) Bad type\n");
1053				return -EINVAL;
1054			}
1055			if (buf->memory != V4L2_MEMORY_MMAP) {
1056				PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYBUF) Bad memory type\n");
1057				return -EINVAL;
1058			}
1059			index = buf->index;
1060			if (index < 0 || index >= pwc_mbufs) {
1061				PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYBUF) Bad index %d\n", buf->index);
1062				return -EINVAL;
1063			}
1064
1065			memset(buf, 0, sizeof(struct v4l2_buffer));
1066			buf->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1067			buf->index = index;
1068			buf->m.offset = index * pdev->len_per_image;
1069			if (pdev->vpalette == VIDEO_PALETTE_RAW)
1070				buf->bytesused = pdev->frame_size + sizeof(struct pwc_raw_frame);
1071			else
1072				buf->bytesused = pdev->view.size;
1073			buf->field = V4L2_FIELD_NONE;
1074			buf->memory = V4L2_MEMORY_MMAP;
1075			//buf->flags = V4L2_BUF_FLAG_MAPPED;
1076			buf->length = pdev->len_per_image;
1077
1078			PWC_DEBUG_READ("VIDIOC_QUERYBUF: index=%d\n",buf->index);
1079			PWC_DEBUG_READ("VIDIOC_QUERYBUF: m.offset=%d\n",buf->m.offset);
1080			PWC_DEBUG_READ("VIDIOC_QUERYBUF: bytesused=%d\n",buf->bytesused);
1081
1082			return 0;
1083		}
1084
1085		case VIDIOC_QBUF:
1086		{
1087			struct v4l2_buffer *buf = arg;
1088
1089			PWC_DEBUG_IOCTL("ioctl(VIDIOC_QBUF) index=%d\n",buf->index);
1090			if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
1091				return -EINVAL;
1092			if (buf->memory != V4L2_MEMORY_MMAP)
1093				return -EINVAL;
1094			if (buf->index >= pwc_mbufs)
1095				return -EINVAL;
1096
1097			buf->flags |= V4L2_BUF_FLAG_QUEUED;
1098			buf->flags &= ~V4L2_BUF_FLAG_DONE;
1099
1100			return 0;
1101		}
1102
1103		case VIDIOC_DQBUF:
1104		{
1105			struct v4l2_buffer *buf = arg;
1106			int ret;
1107
1108			PWC_DEBUG_IOCTL("ioctl(VIDIOC_DQBUF)\n");
1109
1110			if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
1111				return -EINVAL;
1112
1113			add_wait_queue(&pdev->frameq, &wait);
1114			while (pdev->full_frames == NULL) {
1115				if (pdev->error_status) {
1116					remove_wait_queue(&pdev->frameq, &wait);
1117					set_current_state(TASK_RUNNING);
1118					return -pdev->error_status;
1119				}
1120
1121				if (signal_pending(current)) {
1122					remove_wait_queue(&pdev->frameq, &wait);
1123					set_current_state(TASK_RUNNING);
1124					return -ERESTARTSYS;
1125				}
1126				schedule();
1127				set_current_state(TASK_INTERRUPTIBLE);
1128			}
1129			remove_wait_queue(&pdev->frameq, &wait);
1130			set_current_state(TASK_RUNNING);
1131
1132			PWC_DEBUG_IOCTL("VIDIOC_DQBUF: frame ready.\n");
1133			/* Decompress data in pdev->images[pdev->fill_image] */
1134			ret = pwc_handle_frame(pdev);
1135			if (ret)
1136				return -EFAULT;
1137			PWC_DEBUG_IOCTL("VIDIOC_DQBUF: after pwc_handle_frame\n");
1138
1139			buf->index = pdev->fill_image;
1140			if (pdev->vpalette == VIDEO_PALETTE_RAW)
1141				buf->bytesused = pdev->frame_size + sizeof(struct pwc_raw_frame);
1142			else
1143				buf->bytesused = pdev->view.size;
1144			buf->flags = V4L2_BUF_FLAG_MAPPED;
1145			buf->field = V4L2_FIELD_NONE;
1146			do_gettimeofday(&buf->timestamp);
1147			buf->sequence = 0;
1148			buf->memory = V4L2_MEMORY_MMAP;
1149			buf->m.offset = pdev->fill_image * pdev->len_per_image;
1150			buf->length = pdev->len_per_image;
1151			pwc_next_image(pdev);
1152
1153			PWC_DEBUG_IOCTL("VIDIOC_DQBUF: buf->index=%d\n",buf->index);
1154			PWC_DEBUG_IOCTL("VIDIOC_DQBUF: buf->length=%d\n",buf->length);
1155			PWC_DEBUG_IOCTL("VIDIOC_DQBUF: m.offset=%d\n",buf->m.offset);
1156			PWC_DEBUG_IOCTL("VIDIOC_DQBUF: bytesused=%d\n",buf->bytesused);
1157			PWC_DEBUG_IOCTL("VIDIOC_DQBUF: leaving\n");
1158			return 0;
1159
1160		}
1161
1162		case VIDIOC_STREAMON:
1163		{
1164			/* WARNING: pwc_try_video_mode() called pwc_isoc_init */
1165			pwc_isoc_init(pdev);
1166			return 0;
1167		}
1168
1169		case VIDIOC_STREAMOFF:
1170		{
1171			pwc_isoc_cleanup(pdev);
1172			return 0;
1173		}
1174
1175		case VIDIOC_ENUM_FRAMESIZES:
1176		{
1177			struct v4l2_frmsizeenum *fsize = arg;
1178			unsigned int i = 0, index = fsize->index;
1179
1180			if (fsize->pixel_format == V4L2_PIX_FMT_YUV420) {
1181				for (i = 0; i < PSZ_MAX; i++) {
1182					if (pdev->image_mask & (1UL << i)) {
1183						if (!index--) {
1184							fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
1185							fsize->discrete.width = pwc_image_sizes[i].x;
1186							fsize->discrete.height = pwc_image_sizes[i].y;
1187							return 0;
1188						}
1189					}
1190				}
1191			} else if (fsize->index == 0 &&
1192				   ((fsize->pixel_format == V4L2_PIX_FMT_PWC1 && DEVICE_USE_CODEC1(pdev->type)) ||
1193				    (fsize->pixel_format == V4L2_PIX_FMT_PWC2 && DEVICE_USE_CODEC23(pdev->type)))) {
1194
1195				fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
1196				fsize->discrete.width = pdev->abs_max.x;
1197				fsize->discrete.height = pdev->abs_max.y;
1198				return 0;
1199			}
1200			return -EINVAL;
1201		}
1202
1203		case VIDIOC_ENUM_FRAMEINTERVALS:
1204		{
1205			struct v4l2_frmivalenum *fival = arg;
1206			int size = -1;
1207			unsigned int i;
1208
1209			for (i = 0; i < PSZ_MAX; i++) {
1210				if (pwc_image_sizes[i].x == fival->width &&
1211				    pwc_image_sizes[i].y == fival->height) {
1212					size = i;
1213					break;
1214				}
1215			}
1216
1217			/* TODO: Support raw format */
1218			if (size < 0 || fival->pixel_format != V4L2_PIX_FMT_YUV420) {
1219				return -EINVAL;
1220			}
1221
1222			i = pwc_get_fps(pdev, fival->index, size);
1223			if (!i)
1224				return -EINVAL;
1225
1226			fival->type = V4L2_FRMIVAL_TYPE_DISCRETE;
1227			fival->discrete.numerator = 1;
1228			fival->discrete.denominator = i;
1229
1230			return 0;
1231		}
1232
1233		default:
1234			return pwc_ioctl(pdev, cmd, arg);
1235	} /* ..switch */
1236	return 0;
1237}
1238
1239/* vim: set cino= formatoptions=croql cindent shiftwidth=8 tabstop=8: */
1240