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)
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.
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.
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.
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
28 #include <linux/errno.h>
29 #include <linux/init.h>
31 #include <linux/module.h>
32 #include <linux/poll.h>
33 #include <linux/vmalloc.h>
38 static struct v4l2_queryctrl pwc_controls
[] = {
40 .id
= V4L2_CID_BRIGHTNESS
,
41 .type
= V4L2_CTRL_TYPE_INTEGER
,
49 .id
= V4L2_CID_CONTRAST
,
50 .type
= V4L2_CTRL_TYPE_INTEGER
,
58 .id
= V4L2_CID_SATURATION
,
59 .type
= V4L2_CTRL_TYPE_INTEGER
,
68 .type
= V4L2_CTRL_TYPE_INTEGER
,
76 .id
= V4L2_CID_RED_BALANCE
,
77 .type
= V4L2_CTRL_TYPE_INTEGER
,
85 .id
= V4L2_CID_BLUE_BALANCE
,
86 .type
= V4L2_CTRL_TYPE_INTEGER
,
94 .id
= V4L2_CID_AUTO_WHITE_BALANCE
,
95 .type
= V4L2_CTRL_TYPE_BOOLEAN
,
96 .name
= "Auto White Balance",
103 .id
= V4L2_CID_EXPOSURE
,
104 .type
= V4L2_CTRL_TYPE_INTEGER
,
105 .name
= "Shutter Speed (Exposure)",
109 .default_value
= 200,
112 .id
= V4L2_CID_AUTOGAIN
,
113 .type
= V4L2_CTRL_TYPE_BOOLEAN
,
114 .name
= "Auto Gain Enabled",
122 .type
= V4L2_CTRL_TYPE_INTEGER
,
123 .name
= "Gain Level",
130 .id
= V4L2_CID_PRIVATE_SAVE_USER
,
131 .type
= V4L2_CTRL_TYPE_BUTTON
,
132 .name
= "Save User Settings",
139 .id
= V4L2_CID_PRIVATE_RESTORE_USER
,
140 .type
= V4L2_CTRL_TYPE_BUTTON
,
141 .name
= "Restore User Settings",
148 .id
= V4L2_CID_PRIVATE_RESTORE_FACTORY
,
149 .type
= V4L2_CTRL_TYPE_BUTTON
,
150 .name
= "Restore Factory Settings",
157 .id
= V4L2_CID_PRIVATE_COLOUR_MODE
,
158 .type
= V4L2_CTRL_TYPE_BOOLEAN
,
159 .name
= "Colour mode",
166 .id
= V4L2_CID_PRIVATE_AUTOCONTOUR
,
167 .type
= V4L2_CTRL_TYPE_BOOLEAN
,
168 .name
= "Auto contour",
175 .id
= V4L2_CID_PRIVATE_CONTOUR
,
176 .type
= V4L2_CTRL_TYPE_INTEGER
,
184 .id
= V4L2_CID_PRIVATE_BACKLIGHT
,
185 .type
= V4L2_CTRL_TYPE_BOOLEAN
,
186 .name
= "Backlight compensation",
193 .id
= V4L2_CID_PRIVATE_FLICKERLESS
,
194 .type
= V4L2_CTRL_TYPE_BOOLEAN
,
195 .name
= "Flickerless",
202 .id
= V4L2_CID_PRIVATE_NOISE_REDUCTION
,
203 .type
= V4L2_CTRL_TYPE_INTEGER
,
204 .name
= "Noise reduction",
213 static void pwc_vidioc_fill_fmt(const struct pwc_device
*pdev
, struct v4l2_format
*f
)
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
;
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
;
230 f
->fmt
.pix
.pixelformat
= V4L2_PIX_FMT_PWC2
;
232 PWC_DEBUG_IOCTL("pwc_vidioc_fill_fmt() "
233 "width=%d, height=%d, bytesperline=%d, sizeimage=%d, pixelformat=%c%c%c%c\n",
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);
244 /* ioctl(VIDIOC_TRY_FMT) */
245 static int pwc_vidioc_try_fmt(struct pwc_device
*pdev
, struct v4l2_format
*f
)
247 if (f
->type
!= V4L2_BUF_TYPE_VIDEO_CAPTURE
) {
248 PWC_DEBUG_IOCTL("Bad video type must be V4L2_BUF_TYPE_VIDEO_CAPTURE\n");
252 switch (f
->fmt
.pix
.pixelformat
) {
253 case V4L2_PIX_FMT_YUV420
:
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");
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");
268 PWC_DEBUG_IOCTL("Unsupported pixel format\n");
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
;
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
;
286 /* ioctl(VIDIOC_SET_FMT) */
287 static int pwc_vidioc_set_fmt(struct pwc_device
*pdev
, struct v4l2_format
*f
)
289 int ret
, fps
, snapshot
, compression
, pixelformat
;
291 ret
= pwc_vidioc_try_fmt(pdev
, f
);
295 pixelformat
= f
->fmt
.pix
.pixelformat
;
296 compression
= pdev
->vcompression
;
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
;
307 if (pixelformat
== V4L2_PIX_FMT_YUV420
)
308 pdev
->vpalette
= VIDEO_PALETTE_YUV420P
;
310 pdev
->vpalette
= VIDEO_PALETTE_RAW
;
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
,
317 (pixelformat
>>8)&255,
318 (pixelformat
>>16)&255,
319 (pixelformat
>>24)&255);
321 ret
= pwc_try_video_mode(pdev
,
328 PWC_DEBUG_IOCTL("pwc_try_video_mode(), return=%d\n", ret
);
333 pwc_vidioc_fill_fmt(pdev
, f
);
339 long pwc_video_do_ioctl(struct file
*file
, unsigned int cmd
, void *arg
)
341 struct video_device
*vdev
= video_devdata(file
);
342 struct pwc_device
*pdev
;
343 DECLARE_WAITQUEUE(wait
, current
);
347 pdev
= video_get_drvdata(vdev
);
351 #ifdef CONFIG_USB_PWC_DEBUG
352 if (PWC_DEBUG_LEVEL_IOCTL
& pwc_trace
) {
353 v4l_printk_ioctl(cmd
);
360 /* Query cabapilities */
363 struct video_capability
*caps
= arg
;
365 strcpy(caps
->name
, vdev
->name
);
366 caps
->type
= VID_TYPE_CAPTURE
;
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
;
376 /* Channel functions (simulate 1 channel) */
379 struct video_channel
*v
= arg
;
385 v
->type
= VIDEO_TYPE_CAMERA
;
386 strcpy(v
->name
, "Webcam");
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.
396 struct video_channel
*v
= arg
;
403 /* Picture functions; contrast etc. */
406 struct video_picture
*p
= arg
;
409 val
= pwc_get_brightness(pdev
);
411 p
->brightness
= (val
<<9);
413 p
->brightness
= 0xffff;
414 val
= pwc_get_contrast(pdev
);
416 p
->contrast
= (val
<<10);
418 p
->contrast
= 0xffff;
419 /* Gamma, Whiteness, what's the difference? :) */
420 val
= pwc_get_gamma(pdev
);
422 p
->whiteness
= (val
<<11);
424 p
->whiteness
= 0xffff;
425 if (pwc_get_saturation(pdev
, &val
)<0)
428 p
->colour
= 32768 + val
* 327;
430 p
->palette
= pdev
->vpalette
;
431 p
->hue
= 0xFFFF; /* N/A */
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
);
457 /* Window/size parameters */
460 struct video_window
*vw
= arg
;
464 vw
->width
= pdev
->view
.x
;
465 vw
->height
= pdev
->view
.y
;
467 vw
->flags
= (pdev
->vframes
<< PWC_FPS_SHIFT
) |
468 (pdev
->vsnapshot
? PWC_FPS_SNAPSHOT
: 0);
474 struct video_window
*vw
= arg
;
475 int fps
, snapshot
, ret
;
477 fps
= (vw
->flags
& PWC_FPS_FRMASK
) >> PWC_FPS_SHIFT
;
478 snapshot
= vw
->flags
& PWC_FPS_SNAPSHOT
;
481 if (pdev
->view
.x
== vw
->width
&& pdev
->view
.y
&& fps
== pdev
->vframes
&& snapshot
== pdev
->vsnapshot
)
483 ret
= pwc_try_video_mode(pdev
, vw
->width
, vw
->height
, fps
, pdev
->vcompression
, snapshot
);
489 /* We don't have overlay support (yet) */
492 struct video_buffer
*vb
= arg
;
494 memset(vb
,0,sizeof(*vb
));
498 /* mmap() functions */
501 /* Tell the user program how much memory is needed for a mmap() */
502 struct video_mbuf
*vm
= arg
;
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
;
515 /* Start capture into a given image buffer (called 'frame' in video_mmap structure) */
516 struct video_mmap
*vm
= arg
;
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
)
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.
531 case VIDEO_PALETTE_YUV420P
:
532 case VIDEO_PALETTE_RAW
:
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
)) {
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
);
548 } /* ... size mismatch */
550 if (pdev
->image_used
[vm
->frame
])
551 return -EBUSY
; /* buffer wasn't available. Bummer */
552 pdev
->image_used
[vm
->frame
] = 1;
554 /* Okay, we're done here. In the SYNC call we wait until a
555 frame comes available, then expand image into the given
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.
562 PWC_DEBUG_READ("VIDIOCMCAPTURE done.\n");
568 /* The doc says: "Whenever a buffer is used it should
569 call VIDIOCSYNC to free this frame up and continue."
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
585 PWC_DEBUG_READ("VIDIOCSYNC called (%d).\n", *mbuf
);
588 if (*mbuf
< 0 || *mbuf
>= pwc_mbufs
)
590 /* check if this buffer was requested anyway */
591 if (pdev
->image_used
[*mbuf
] == 0)
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
;
603 if (signal_pending(current
)) {
604 remove_wait_queue(&pdev
->frameq
, &wait
);
605 set_current_state(TASK_RUNNING
);
609 set_current_state(TASK_INTERRUPTIBLE
);
611 remove_wait_queue(&pdev
->frameq
, &wait
);
612 set_current_state(TASK_RUNNING
);
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.
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;
632 struct video_audio
*v
= arg
;
634 strcpy(v
->name
, "Microphone");
635 v
->audio
= -1; /* unknown audio minor */
637 v
->mode
= VIDEO_SOUND_MONO
;
648 /* Dummy: nothing can be set */
654 struct video_unit
*vu
= arg
;
656 vu
->video
= pdev
->vdev
->minor
& 0x3F;
657 vu
->audio
= -1; /* not known yet */
665 case VIDIOC_QUERYCAP
:
667 struct v4l2_capability
*cap
= arg
;
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
;
676 V4L2_CAP_VIDEO_CAPTURE
|
682 case VIDIOC_ENUMINPUT
:
684 struct v4l2_input
*i
= arg
;
686 if ( i
->index
) /* Only one INPUT is supported */
689 memset(i
, 0, sizeof(struct v4l2_input
));
690 strcpy(i
->name
, "usb");
697 *i
= 0; /* Only one INPUT is supported */
704 if ( *i
) { /* Only one INPUT is supported */
705 PWC_DEBUG_IOCTL("Only one input source is"\
706 " supported with this webcam.\n");
713 case VIDIOC_QUERYCTRL
:
715 struct v4l2_queryctrl
*c
= arg
;
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
));
726 PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYCTRL) not found\n");
732 struct v4l2_control
*c
= arg
;
737 case V4L2_CID_BRIGHTNESS
:
738 c
->value
= pwc_get_brightness(pdev
);
742 case V4L2_CID_CONTRAST
:
743 c
->value
= pwc_get_contrast(pdev
);
747 case V4L2_CID_SATURATION
:
748 ret
= pwc_get_saturation(pdev
, &c
->value
);
753 c
->value
= pwc_get_gamma(pdev
);
757 case V4L2_CID_RED_BALANCE
:
758 ret
= pwc_get_red_gain(pdev
, &c
->value
);
763 case V4L2_CID_BLUE_BALANCE
:
764 ret
= pwc_get_blue_gain(pdev
, &c
->value
);
769 case V4L2_CID_AUTO_WHITE_BALANCE
:
770 ret
= pwc_get_awb(pdev
);
773 c
->value
= (ret
== PWC_WB_MANUAL
)?0:1;
776 ret
= pwc_get_agc(pdev
, &c
->value
);
781 case V4L2_CID_AUTOGAIN
:
782 ret
= pwc_get_agc(pdev
, &c
->value
);
785 c
->value
= (c
->value
< 0)?1:0;
787 case V4L2_CID_EXPOSURE
:
788 ret
= pwc_get_shutter_speed(pdev
, &c
->value
);
792 case V4L2_CID_PRIVATE_COLOUR_MODE
:
793 ret
= pwc_get_colour_mode(pdev
, &c
->value
);
797 case V4L2_CID_PRIVATE_AUTOCONTOUR
:
798 ret
= pwc_get_contour(pdev
, &c
->value
);
801 c
->value
=(c
->value
== -1?1:0);
803 case V4L2_CID_PRIVATE_CONTOUR
:
804 ret
= pwc_get_contour(pdev
, &c
->value
);
809 case V4L2_CID_PRIVATE_BACKLIGHT
:
810 ret
= pwc_get_backlight(pdev
, &c
->value
);
814 case V4L2_CID_PRIVATE_FLICKERLESS
:
815 ret
= pwc_get_flicker(pdev
, &c
->value
);
818 c
->value
=(c
->value
?1:0);
820 case V4L2_CID_PRIVATE_NOISE_REDUCTION
:
821 ret
= pwc_get_dynamic_noise(pdev
, &c
->value
);
826 case V4L2_CID_PRIVATE_SAVE_USER
:
827 case V4L2_CID_PRIVATE_RESTORE_USER
:
828 case V4L2_CID_PRIVATE_RESTORE_FACTORY
:
835 struct v4l2_control
*c
= arg
;
840 case V4L2_CID_BRIGHTNESS
:
842 ret
= pwc_set_brightness(pdev
, c
->value
);
846 case V4L2_CID_CONTRAST
:
848 ret
= pwc_set_contrast(pdev
, c
->value
);
852 case V4L2_CID_SATURATION
:
853 ret
= pwc_set_saturation(pdev
, c
->value
);
859 ret
= pwc_set_gamma(pdev
, c
->value
);
863 case V4L2_CID_RED_BALANCE
:
865 ret
= pwc_set_red_gain(pdev
, c
->value
);
869 case V4L2_CID_BLUE_BALANCE
:
871 ret
= pwc_set_blue_gain(pdev
, c
->value
);
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
);
881 case V4L2_CID_EXPOSURE
:
883 ret
= pwc_set_shutter_speed(pdev
, c
->value
?0:1, c
->value
);
887 case V4L2_CID_AUTOGAIN
:
888 /* autogain off means nothing without a gain */
891 ret
= pwc_set_agc(pdev
, c
->value
, 0);
897 ret
= pwc_set_agc(pdev
, 0, c
->value
);
901 case V4L2_CID_PRIVATE_SAVE_USER
:
902 if (pwc_save_user(pdev
))
905 case V4L2_CID_PRIVATE_RESTORE_USER
:
906 if (pwc_restore_user(pdev
))
909 case V4L2_CID_PRIVATE_RESTORE_FACTORY
:
910 if (pwc_restore_factory(pdev
))
913 case V4L2_CID_PRIVATE_COLOUR_MODE
:
914 ret
= pwc_set_colour_mode(pdev
, c
->value
);
918 case V4L2_CID_PRIVATE_AUTOCONTOUR
:
919 c
->value
=(c
->value
== 1)?-1:0;
920 ret
= pwc_set_contour(pdev
, c
->value
);
924 case V4L2_CID_PRIVATE_CONTOUR
:
926 ret
= pwc_set_contour(pdev
, c
->value
);
930 case V4L2_CID_PRIVATE_BACKLIGHT
:
931 ret
= pwc_set_backlight(pdev
, c
->value
);
935 case V4L2_CID_PRIVATE_FLICKERLESS
:
936 ret
= pwc_set_flicker(pdev
, c
->value
);
939 case V4L2_CID_PRIVATE_NOISE_REDUCTION
:
940 ret
= pwc_set_dynamic_noise(pdev
, c
->value
);
949 case VIDIOC_ENUM_FMT
:
951 struct v4l2_fmtdesc
*f
= arg
;
954 if (f
->type
!= V4L2_BUF_TYPE_VIDEO_CAPTURE
)
957 /* We only support two format: the raw format, and YUV */
959 memset(f
,0,sizeof(struct v4l2_fmtdesc
));
960 f
->type
= V4L2_BUF_TYPE_VIDEO_CAPTURE
;
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
));
971 f
->pixelformat
= V4L2_PIX_FMT_YUV420
;
972 strlcpy(f
->description
,"4:2:0, planar, Y-Cb-Cr",sizeof(f
->description
));
982 struct v4l2_format
*f
= arg
;
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
)
988 pwc_vidioc_fill_fmt(pdev
, f
);
994 return pwc_vidioc_try_fmt(pdev
, arg
);
997 return pwc_vidioc_set_fmt(pdev
, arg
);
1001 v4l2_std_id
*std
= arg
;
1002 *std
= V4L2_STD_UNKNOWN
;
1008 v4l2_std_id
*std
= arg
;
1009 if (*std
!= V4L2_STD_UNKNOWN
)
1014 case VIDIOC_ENUMSTD
:
1016 struct v4l2_standard
*std
= arg
;
1017 if (std
->index
!= 0)
1019 std
->id
= V4L2_STD_UNKNOWN
;
1020 strlcpy(std
->name
, "webcam", sizeof(std
->name
));
1024 case VIDIOC_REQBUFS
:
1026 struct v4l2_requestbuffers
*rb
= arg
;
1029 PWC_DEBUG_IOCTL("ioctl(VIDIOC_REQBUFS) count=%d\n",rb
->count
);
1030 if (rb
->type
!= V4L2_BUF_TYPE_VIDEO_CAPTURE
)
1032 if (rb
->memory
!= V4L2_MEMORY_MMAP
)
1035 nbuffers
= rb
->count
;
1038 else if (nbuffers
> pwc_mbufs
)
1039 nbuffers
= pwc_mbufs
;
1040 /* Force to use our # of buffers */
1041 rb
->count
= pwc_mbufs
;
1045 case VIDIOC_QUERYBUF
:
1047 struct v4l2_buffer
*buf
= arg
;
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");
1055 if (buf
->memory
!= V4L2_MEMORY_MMAP
) {
1056 PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYBUF) Bad memory type\n");
1060 if (index
< 0 || index
>= pwc_mbufs
) {
1061 PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYBUF) Bad index %d\n", buf
->index
);
1065 memset(buf
, 0, sizeof(struct v4l2_buffer
));
1066 buf
->type
= V4L2_BUF_TYPE_VIDEO_CAPTURE
;
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
);
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
;
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
);
1087 struct v4l2_buffer
*buf
= arg
;
1089 PWC_DEBUG_IOCTL("ioctl(VIDIOC_QBUF) index=%d\n",buf
->index
);
1090 if (buf
->type
!= V4L2_BUF_TYPE_VIDEO_CAPTURE
)
1092 if (buf
->memory
!= V4L2_MEMORY_MMAP
)
1094 if (buf
->index
>= pwc_mbufs
)
1097 buf
->flags
|= V4L2_BUF_FLAG_QUEUED
;
1098 buf
->flags
&= ~V4L2_BUF_FLAG_DONE
;
1105 struct v4l2_buffer
*buf
= arg
;
1108 PWC_DEBUG_IOCTL("ioctl(VIDIOC_DQBUF)\n");
1110 if (buf
->type
!= V4L2_BUF_TYPE_VIDEO_CAPTURE
)
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
;
1121 if (signal_pending(current
)) {
1122 remove_wait_queue(&pdev
->frameq
, &wait
);
1123 set_current_state(TASK_RUNNING
);
1124 return -ERESTARTSYS
;
1127 set_current_state(TASK_INTERRUPTIBLE
);
1129 remove_wait_queue(&pdev
->frameq
, &wait
);
1130 set_current_state(TASK_RUNNING
);
1132 PWC_DEBUG_IOCTL("VIDIOC_DQBUF: frame ready.\n");
1133 /* Decompress data in pdev->images[pdev->fill_image] */
1134 ret
= pwc_handle_frame(pdev
);
1137 PWC_DEBUG_IOCTL("VIDIOC_DQBUF: after pwc_handle_frame\n");
1139 buf
->index
= pdev
->fill_image
;
1140 if (pdev
->vpalette
== VIDEO_PALETTE_RAW
)
1141 buf
->bytesused
= pdev
->frame_size
+ sizeof(struct pwc_raw_frame
);
1143 buf
->bytesused
= pdev
->view
.size
;
1144 buf
->flags
= V4L2_BUF_FLAG_MAPPED
;
1145 buf
->field
= V4L2_FIELD_NONE
;
1146 do_gettimeofday(&buf
->timestamp
);
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
);
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");
1162 case VIDIOC_STREAMON
:
1164 /* WARNING: pwc_try_video_mode() called pwc_isoc_init */
1165 pwc_isoc_init(pdev
);
1169 case VIDIOC_STREAMOFF
:
1171 pwc_isoc_cleanup(pdev
);
1175 case VIDIOC_ENUM_FRAMESIZES
:
1177 struct v4l2_frmsizeenum
*fsize
= arg
;
1178 unsigned int i
= 0, index
= fsize
->index
;
1180 if (fsize
->pixel_format
== V4L2_PIX_FMT_YUV420
) {
1181 for (i
= 0; i
< PSZ_MAX
; i
++) {
1182 if (pdev
->image_mask
& (1UL << i
)) {
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
;
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
)))) {
1195 fsize
->type
= V4L2_FRMSIZE_TYPE_DISCRETE
;
1196 fsize
->discrete
.width
= pdev
->abs_max
.x
;
1197 fsize
->discrete
.height
= pdev
->abs_max
.y
;
1203 case VIDIOC_ENUM_FRAMEINTERVALS
:
1205 struct v4l2_frmivalenum
*fival
= arg
;
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
) {
1217 /* TODO: Support raw format */
1218 if (size
< 0 || fival
->pixel_format
!= V4L2_PIX_FMT_YUV420
) {
1222 i
= pwc_get_fps(pdev
, fival
->index
, size
);
1226 fival
->type
= V4L2_FRMIVAL_TYPE_DISCRETE
;
1227 fival
->discrete
.numerator
= 1;
1228 fival
->discrete
.denominator
= i
;
1234 return pwc_ioctl(pdev
, cmd
, arg
);
1239 /* vim: set cino= formatoptions=croql cindent shiftwidth=8 tabstop=8: */