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/slab.h>
34 #include <linux/vmalloc.h>
39 static struct v4l2_queryctrl pwc_controls
[] = {
41 .id
= V4L2_CID_BRIGHTNESS
,
42 .type
= V4L2_CTRL_TYPE_INTEGER
,
50 .id
= V4L2_CID_CONTRAST
,
51 .type
= V4L2_CTRL_TYPE_INTEGER
,
59 .id
= V4L2_CID_SATURATION
,
60 .type
= V4L2_CTRL_TYPE_INTEGER
,
69 .type
= V4L2_CTRL_TYPE_INTEGER
,
77 .id
= V4L2_CID_RED_BALANCE
,
78 .type
= V4L2_CTRL_TYPE_INTEGER
,
86 .id
= V4L2_CID_BLUE_BALANCE
,
87 .type
= V4L2_CTRL_TYPE_INTEGER
,
95 .id
= V4L2_CID_AUTO_WHITE_BALANCE
,
96 .type
= V4L2_CTRL_TYPE_BOOLEAN
,
97 .name
= "Auto White Balance",
104 .id
= V4L2_CID_EXPOSURE
,
105 .type
= V4L2_CTRL_TYPE_INTEGER
,
106 .name
= "Shutter Speed (Exposure)",
110 .default_value
= 200,
113 .id
= V4L2_CID_AUTOGAIN
,
114 .type
= V4L2_CTRL_TYPE_BOOLEAN
,
115 .name
= "Auto Gain Enabled",
123 .type
= V4L2_CTRL_TYPE_INTEGER
,
124 .name
= "Gain Level",
131 .id
= V4L2_CID_PRIVATE_SAVE_USER
,
132 .type
= V4L2_CTRL_TYPE_BUTTON
,
133 .name
= "Save User Settings",
140 .id
= V4L2_CID_PRIVATE_RESTORE_USER
,
141 .type
= V4L2_CTRL_TYPE_BUTTON
,
142 .name
= "Restore User Settings",
149 .id
= V4L2_CID_PRIVATE_RESTORE_FACTORY
,
150 .type
= V4L2_CTRL_TYPE_BUTTON
,
151 .name
= "Restore Factory Settings",
158 .id
= V4L2_CID_PRIVATE_COLOUR_MODE
,
159 .type
= V4L2_CTRL_TYPE_BOOLEAN
,
160 .name
= "Colour mode",
167 .id
= V4L2_CID_PRIVATE_AUTOCONTOUR
,
168 .type
= V4L2_CTRL_TYPE_BOOLEAN
,
169 .name
= "Auto contour",
176 .id
= V4L2_CID_PRIVATE_CONTOUR
,
177 .type
= V4L2_CTRL_TYPE_INTEGER
,
185 .id
= V4L2_CID_PRIVATE_BACKLIGHT
,
186 .type
= V4L2_CTRL_TYPE_BOOLEAN
,
187 .name
= "Backlight compensation",
194 .id
= V4L2_CID_PRIVATE_FLICKERLESS
,
195 .type
= V4L2_CTRL_TYPE_BOOLEAN
,
196 .name
= "Flickerless",
203 .id
= V4L2_CID_PRIVATE_NOISE_REDUCTION
,
204 .type
= V4L2_CTRL_TYPE_INTEGER
,
205 .name
= "Noise reduction",
214 static void pwc_vidioc_fill_fmt(const struct pwc_device
*pdev
, struct v4l2_format
*f
)
216 memset(&f
->fmt
.pix
, 0, sizeof(struct v4l2_pix_format
));
217 f
->fmt
.pix
.width
= pdev
->view
.x
;
218 f
->fmt
.pix
.height
= pdev
->view
.y
;
219 f
->fmt
.pix
.field
= V4L2_FIELD_NONE
;
220 if (pdev
->vpalette
== VIDEO_PALETTE_YUV420P
) {
221 f
->fmt
.pix
.pixelformat
= V4L2_PIX_FMT_YUV420
;
222 f
->fmt
.pix
.bytesperline
= (f
->fmt
.pix
.width
* 3)/2;
223 f
->fmt
.pix
.sizeimage
= f
->fmt
.pix
.height
* f
->fmt
.pix
.bytesperline
;
225 /* vbandlength contains 4 lines ... */
226 f
->fmt
.pix
.bytesperline
= pdev
->vbandlength
/4;
227 f
->fmt
.pix
.sizeimage
= pdev
->frame_size
+ sizeof(struct pwc_raw_frame
);
228 if (DEVICE_USE_CODEC1(pdev
->type
))
229 f
->fmt
.pix
.pixelformat
= V4L2_PIX_FMT_PWC1
;
231 f
->fmt
.pix
.pixelformat
= V4L2_PIX_FMT_PWC2
;
233 PWC_DEBUG_IOCTL("pwc_vidioc_fill_fmt() "
234 "width=%d, height=%d, bytesperline=%d, sizeimage=%d, pixelformat=%c%c%c%c\n",
237 f
->fmt
.pix
.bytesperline
,
238 f
->fmt
.pix
.sizeimage
,
239 (f
->fmt
.pix
.pixelformat
)&255,
240 (f
->fmt
.pix
.pixelformat
>>8)&255,
241 (f
->fmt
.pix
.pixelformat
>>16)&255,
242 (f
->fmt
.pix
.pixelformat
>>24)&255);
245 /* ioctl(VIDIOC_TRY_FMT) */
246 static int pwc_vidioc_try_fmt(struct pwc_device
*pdev
, struct v4l2_format
*f
)
248 if (f
->type
!= V4L2_BUF_TYPE_VIDEO_CAPTURE
) {
249 PWC_DEBUG_IOCTL("Bad video type must be V4L2_BUF_TYPE_VIDEO_CAPTURE\n");
253 switch (f
->fmt
.pix
.pixelformat
) {
254 case V4L2_PIX_FMT_YUV420
:
256 case V4L2_PIX_FMT_PWC1
:
257 if (DEVICE_USE_CODEC23(pdev
->type
)) {
258 PWC_DEBUG_IOCTL("codec1 is only supported for old pwc webcam\n");
262 case V4L2_PIX_FMT_PWC2
:
263 if (DEVICE_USE_CODEC1(pdev
->type
)) {
264 PWC_DEBUG_IOCTL("codec23 is only supported for new pwc webcam\n");
269 PWC_DEBUG_IOCTL("Unsupported pixel format\n");
274 if (f
->fmt
.pix
.width
> pdev
->view_max
.x
)
275 f
->fmt
.pix
.width
= pdev
->view_max
.x
;
276 else if (f
->fmt
.pix
.width
< pdev
->view_min
.x
)
277 f
->fmt
.pix
.width
= pdev
->view_min
.x
;
279 if (f
->fmt
.pix
.height
> pdev
->view_max
.y
)
280 f
->fmt
.pix
.height
= pdev
->view_max
.y
;
281 else if (f
->fmt
.pix
.height
< pdev
->view_min
.y
)
282 f
->fmt
.pix
.height
= pdev
->view_min
.y
;
287 /* ioctl(VIDIOC_SET_FMT) */
288 static int pwc_vidioc_set_fmt(struct pwc_device
*pdev
, struct v4l2_format
*f
)
290 int ret
, fps
, snapshot
, compression
, pixelformat
;
292 ret
= pwc_vidioc_try_fmt(pdev
, f
);
296 pixelformat
= f
->fmt
.pix
.pixelformat
;
297 compression
= pdev
->vcompression
;
300 if (f
->fmt
.pix
.priv
) {
301 compression
= (f
->fmt
.pix
.priv
& PWC_QLT_MASK
) >> PWC_QLT_SHIFT
;
302 snapshot
= !!(f
->fmt
.pix
.priv
& PWC_FPS_SNAPSHOT
);
303 fps
= (f
->fmt
.pix
.priv
& PWC_FPS_FRMASK
) >> PWC_FPS_SHIFT
;
308 if (pixelformat
== V4L2_PIX_FMT_YUV420
)
309 pdev
->vpalette
= VIDEO_PALETTE_YUV420P
;
311 pdev
->vpalette
= VIDEO_PALETTE_RAW
;
313 PWC_DEBUG_IOCTL("Try to change format to: width=%d height=%d fps=%d "
314 "compression=%d snapshot=%d format=%c%c%c%c\n",
315 f
->fmt
.pix
.width
, f
->fmt
.pix
.height
, fps
,
316 compression
, snapshot
,
318 (pixelformat
>>8)&255,
319 (pixelformat
>>16)&255,
320 (pixelformat
>>24)&255);
322 ret
= pwc_try_video_mode(pdev
,
329 PWC_DEBUG_IOCTL("pwc_try_video_mode(), return=%d\n", ret
);
334 pwc_vidioc_fill_fmt(pdev
, f
);
340 int pwc_video_do_ioctl(struct inode
*inode
, struct file
*file
,
341 unsigned int cmd
, void *arg
)
343 struct video_device
*vdev
= video_devdata(file
);
344 struct pwc_device
*pdev
;
345 DECLARE_WAITQUEUE(wait
, current
);
353 #ifdef CONFIG_USB_PWC_DEBUG
354 if (PWC_DEBUG_LEVEL_IOCTL
& pwc_trace
) {
355 v4l_printk_ioctl(cmd
);
362 /* Query cabapilities */
365 struct video_capability
*caps
= arg
;
367 strcpy(caps
->name
, vdev
->name
);
368 caps
->type
= VID_TYPE_CAPTURE
;
371 caps
->minwidth
= pdev
->view_min
.x
;
372 caps
->minheight
= pdev
->view_min
.y
;
373 caps
->maxwidth
= pdev
->view_max
.x
;
374 caps
->maxheight
= pdev
->view_max
.y
;
378 /* Channel functions (simulate 1 channel) */
381 struct video_channel
*v
= arg
;
387 v
->type
= VIDEO_TYPE_CAMERA
;
388 strcpy(v
->name
, "Webcam");
394 /* The spec says the argument is an integer, but
395 the bttv driver uses a video_channel arg, which
396 makes sense becasue it also has the norm flag.
398 struct video_channel
*v
= arg
;
405 /* Picture functions; contrast etc. */
408 struct video_picture
*p
= arg
;
411 val
= pwc_get_brightness(pdev
);
413 p
->brightness
= (val
<<9);
415 p
->brightness
= 0xffff;
416 val
= pwc_get_contrast(pdev
);
418 p
->contrast
= (val
<<10);
420 p
->contrast
= 0xffff;
421 /* Gamma, Whiteness, what's the difference? :) */
422 val
= pwc_get_gamma(pdev
);
424 p
->whiteness
= (val
<<11);
426 p
->whiteness
= 0xffff;
427 if (pwc_get_saturation(pdev
, &val
)<0)
430 p
->colour
= 32768 + val
* 327;
432 p
->palette
= pdev
->vpalette
;
433 p
->hue
= 0xFFFF; /* N/A */
439 struct video_picture
*p
= arg
;
441 * FIXME: Suppose we are mid read
442 ANSWER: No problem: the firmware of the camera
443 can handle brightness/contrast/etc
444 changes at _any_ time, and the palette
445 is used exactly once in the uncompress
448 pwc_set_brightness(pdev
, p
->brightness
);
449 pwc_set_contrast(pdev
, p
->contrast
);
450 pwc_set_gamma(pdev
, p
->whiteness
);
451 pwc_set_saturation(pdev
, (p
->colour
-32768)/327);
452 if (p
->palette
&& p
->palette
!= pdev
->vpalette
) {
453 switch (p
->palette
) {
454 case VIDEO_PALETTE_YUV420P
:
455 case VIDEO_PALETTE_RAW
:
456 pdev
->vpalette
= p
->palette
;
457 return pwc_try_video_mode(pdev
, pdev
->image
.x
, pdev
->image
.y
, pdev
->vframes
, pdev
->vcompression
, pdev
->vsnapshot
);
467 /* Window/size parameters */
470 struct video_window
*vw
= arg
;
474 vw
->width
= pdev
->view
.x
;
475 vw
->height
= pdev
->view
.y
;
477 vw
->flags
= (pdev
->vframes
<< PWC_FPS_SHIFT
) |
478 (pdev
->vsnapshot
? PWC_FPS_SNAPSHOT
: 0);
484 struct video_window
*vw
= arg
;
485 int fps
, snapshot
, ret
;
487 fps
= (vw
->flags
& PWC_FPS_FRMASK
) >> PWC_FPS_SHIFT
;
488 snapshot
= vw
->flags
& PWC_FPS_SNAPSHOT
;
491 if (pdev
->view
.x
== vw
->width
&& pdev
->view
.y
&& fps
== pdev
->vframes
&& snapshot
== pdev
->vsnapshot
)
493 ret
= pwc_try_video_mode(pdev
, vw
->width
, vw
->height
, fps
, pdev
->vcompression
, snapshot
);
499 /* We don't have overlay support (yet) */
502 struct video_buffer
*vb
= arg
;
504 memset(vb
,0,sizeof(*vb
));
508 /* mmap() functions */
511 /* Tell the user program how much memory is needed for a mmap() */
512 struct video_mbuf
*vm
= arg
;
515 memset(vm
, 0, sizeof(*vm
));
516 vm
->size
= pwc_mbufs
* pdev
->len_per_image
;
517 vm
->frames
= pwc_mbufs
; /* double buffering should be enough for most applications */
518 for (i
= 0; i
< pwc_mbufs
; i
++)
519 vm
->offsets
[i
] = i
* pdev
->len_per_image
;
525 /* Start capture into a given image buffer (called 'frame' in video_mmap structure) */
526 struct video_mmap
*vm
= arg
;
528 PWC_DEBUG_READ("VIDIOCMCAPTURE: %dx%d, frame %d, format %d\n", vm
->width
, vm
->height
, vm
->frame
, vm
->format
);
529 if (vm
->frame
< 0 || vm
->frame
>= pwc_mbufs
)
532 /* xawtv is nasty. It probes the available palettes
533 by setting a very small image size and trying
534 various palettes... The driver doesn't support
535 such small images, so I'm working around it.
541 case VIDEO_PALETTE_YUV420P
:
542 case VIDEO_PALETTE_RAW
:
550 if ((vm
->width
!= pdev
->view
.x
|| vm
->height
!= pdev
->view
.y
) &&
551 (vm
->width
>= pdev
->view_min
.x
&& vm
->height
>= pdev
->view_min
.y
)) {
554 PWC_DEBUG_OPEN("VIDIOCMCAPTURE: changing size to please xawtv :-(.\n");
555 ret
= pwc_try_video_mode(pdev
, vm
->width
, vm
->height
, pdev
->vframes
, pdev
->vcompression
, pdev
->vsnapshot
);
558 } /* ... size mismatch */
560 /* FIXME: should we lock here? */
561 if (pdev
->image_used
[vm
->frame
])
562 return -EBUSY
; /* buffer wasn't available. Bummer */
563 pdev
->image_used
[vm
->frame
] = 1;
565 /* Okay, we're done here. In the SYNC call we wait until a
566 frame comes available, then expand image into the given
568 In contrast to the CPiA cam the Philips cams deliver a
569 constant stream, almost like a grabber card. Also,
570 we have separate buffers for the rawdata and the image,
571 meaning we can nearly always expand into the requested buffer.
573 PWC_DEBUG_READ("VIDIOCMCAPTURE done.\n");
579 /* The doc says: "Whenever a buffer is used it should
580 call VIDIOCSYNC to free this frame up and continue."
582 The only odd thing about this whole procedure is
583 that MCAPTURE flags the buffer as "in use", and
584 SYNC immediately unmarks it, while it isn't
585 after SYNC that you know that the buffer actually
586 got filled! So you better not start a CAPTURE in
587 the same frame immediately (use double buffering).
588 This is not a problem for this cam, since it has
589 extra intermediate buffers, but a hardware
590 grabber card will then overwrite the buffer
596 PWC_DEBUG_READ("VIDIOCSYNC called (%d).\n", *mbuf
);
599 if (*mbuf
< 0 || *mbuf
>= pwc_mbufs
)
601 /* check if this buffer was requested anyway */
602 if (pdev
->image_used
[*mbuf
] == 0)
605 /* Add ourselves to the frame wait-queue.
607 FIXME: needs auditing for safety.
608 QUESTION: In what respect? I think that using the
611 add_wait_queue(&pdev
->frameq
, &wait
);
612 while (pdev
->full_frames
== NULL
) {
613 /* Check for unplugged/etc. here */
614 if (pdev
->error_status
) {
615 remove_wait_queue(&pdev
->frameq
, &wait
);
616 set_current_state(TASK_RUNNING
);
617 return -pdev
->error_status
;
620 if (signal_pending(current
)) {
621 remove_wait_queue(&pdev
->frameq
, &wait
);
622 set_current_state(TASK_RUNNING
);
626 set_current_state(TASK_INTERRUPTIBLE
);
628 remove_wait_queue(&pdev
->frameq
, &wait
);
629 set_current_state(TASK_RUNNING
);
631 /* The frame is ready. Expand in the image buffer
632 requested by the user. I don't care if you
633 mmap() 5 buffers and request data in this order:
634 buffer 4 2 3 0 1 2 3 0 4 3 1 . . .
635 Grabber hardware may not be so forgiving.
637 PWC_DEBUG_READ("VIDIOCSYNC: frame ready.\n");
638 pdev
->fill_image
= *mbuf
; /* tell in which buffer we want the image to be expanded */
639 /* Decompress, etc */
640 ret
= pwc_handle_frame(pdev
);
641 pdev
->image_used
[*mbuf
] = 0;
649 struct video_audio
*v
= arg
;
651 strcpy(v
->name
, "Microphone");
652 v
->audio
= -1; /* unknown audio minor */
654 v
->mode
= VIDEO_SOUND_MONO
;
665 /* Dummy: nothing can be set */
671 struct video_unit
*vu
= arg
;
673 vu
->video
= pdev
->vdev
->minor
& 0x3F;
674 vu
->audio
= -1; /* not known yet */
682 case VIDIOC_QUERYCAP
:
684 struct v4l2_capability
*cap
= arg
;
686 PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYCAP) This application "\
687 "try to use the v4l2 layer\n");
688 strcpy(cap
->driver
,PWC_NAME
);
689 strlcpy(cap
->card
, vdev
->name
, sizeof(cap
->card
));
690 usb_make_path(pdev
->udev
,cap
->bus_info
,sizeof(cap
->bus_info
));
691 cap
->version
= PWC_VERSION_CODE
;
693 V4L2_CAP_VIDEO_CAPTURE
|
699 case VIDIOC_ENUMINPUT
:
701 struct v4l2_input
*i
= arg
;
703 if ( i
->index
) /* Only one INPUT is supported */
706 memset(i
, 0, sizeof(struct v4l2_input
));
707 strcpy(i
->name
, "usb");
714 *i
= 0; /* Only one INPUT is supported */
721 if ( *i
) { /* Only one INPUT is supported */
722 PWC_DEBUG_IOCTL("Only one input source is"\
723 " supported with this webcam.\n");
730 case VIDIOC_QUERYCTRL
:
732 struct v4l2_queryctrl
*c
= arg
;
735 PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYCTRL) query id=%d\n", c
->id
);
736 for (i
=0; i
<sizeof(pwc_controls
)/sizeof(struct v4l2_queryctrl
); i
++) {
737 if (pwc_controls
[i
].id
== c
->id
) {
738 PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYCTRL) found\n");
739 memcpy(c
,&pwc_controls
[i
],sizeof(struct v4l2_queryctrl
));
743 PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYCTRL) not found\n");
749 struct v4l2_control
*c
= arg
;
754 case V4L2_CID_BRIGHTNESS
:
755 c
->value
= pwc_get_brightness(pdev
);
759 case V4L2_CID_CONTRAST
:
760 c
->value
= pwc_get_contrast(pdev
);
764 case V4L2_CID_SATURATION
:
765 ret
= pwc_get_saturation(pdev
, &c
->value
);
770 c
->value
= pwc_get_gamma(pdev
);
774 case V4L2_CID_RED_BALANCE
:
775 ret
= pwc_get_red_gain(pdev
, &c
->value
);
780 case V4L2_CID_BLUE_BALANCE
:
781 ret
= pwc_get_blue_gain(pdev
, &c
->value
);
786 case V4L2_CID_AUTO_WHITE_BALANCE
:
787 ret
= pwc_get_awb(pdev
);
790 c
->value
= (ret
== PWC_WB_MANUAL
)?0:1;
793 ret
= pwc_get_agc(pdev
, &c
->value
);
798 case V4L2_CID_AUTOGAIN
:
799 ret
= pwc_get_agc(pdev
, &c
->value
);
802 c
->value
= (c
->value
< 0)?1:0;
804 case V4L2_CID_EXPOSURE
:
805 ret
= pwc_get_shutter_speed(pdev
, &c
->value
);
809 case V4L2_CID_PRIVATE_COLOUR_MODE
:
810 ret
= pwc_get_colour_mode(pdev
, &c
->value
);
814 case V4L2_CID_PRIVATE_AUTOCONTOUR
:
815 ret
= pwc_get_contour(pdev
, &c
->value
);
818 c
->value
=(c
->value
== -1?1:0);
820 case V4L2_CID_PRIVATE_CONTOUR
:
821 ret
= pwc_get_contour(pdev
, &c
->value
);
826 case V4L2_CID_PRIVATE_BACKLIGHT
:
827 ret
= pwc_get_backlight(pdev
, &c
->value
);
831 case V4L2_CID_PRIVATE_FLICKERLESS
:
832 ret
= pwc_get_flicker(pdev
, &c
->value
);
835 c
->value
=(c
->value
?1:0);
837 case V4L2_CID_PRIVATE_NOISE_REDUCTION
:
838 ret
= pwc_get_dynamic_noise(pdev
, &c
->value
);
843 case V4L2_CID_PRIVATE_SAVE_USER
:
844 case V4L2_CID_PRIVATE_RESTORE_USER
:
845 case V4L2_CID_PRIVATE_RESTORE_FACTORY
:
852 struct v4l2_control
*c
= arg
;
857 case V4L2_CID_BRIGHTNESS
:
859 ret
= pwc_set_brightness(pdev
, c
->value
);
863 case V4L2_CID_CONTRAST
:
865 ret
= pwc_set_contrast(pdev
, c
->value
);
869 case V4L2_CID_SATURATION
:
870 ret
= pwc_set_saturation(pdev
, c
->value
);
876 ret
= pwc_set_gamma(pdev
, c
->value
);
880 case V4L2_CID_RED_BALANCE
:
882 ret
= pwc_set_red_gain(pdev
, c
->value
);
886 case V4L2_CID_BLUE_BALANCE
:
888 ret
= pwc_set_blue_gain(pdev
, c
->value
);
892 case V4L2_CID_AUTO_WHITE_BALANCE
:
893 c
->value
= (c
->value
== 0)?PWC_WB_MANUAL
:PWC_WB_AUTO
;
894 ret
= pwc_set_awb(pdev
, c
->value
);
898 case V4L2_CID_EXPOSURE
:
900 ret
= pwc_set_shutter_speed(pdev
, c
->value
?0:1, c
->value
);
904 case V4L2_CID_AUTOGAIN
:
905 /* autogain off means nothing without a gain */
908 ret
= pwc_set_agc(pdev
, c
->value
, 0);
914 ret
= pwc_set_agc(pdev
, 0, c
->value
);
918 case V4L2_CID_PRIVATE_SAVE_USER
:
919 if (pwc_save_user(pdev
))
922 case V4L2_CID_PRIVATE_RESTORE_USER
:
923 if (pwc_restore_user(pdev
))
926 case V4L2_CID_PRIVATE_RESTORE_FACTORY
:
927 if (pwc_restore_factory(pdev
))
930 case V4L2_CID_PRIVATE_COLOUR_MODE
:
931 ret
= pwc_set_colour_mode(pdev
, c
->value
);
935 case V4L2_CID_PRIVATE_AUTOCONTOUR
:
936 c
->value
=(c
->value
== 1)?-1:0;
937 ret
= pwc_set_contour(pdev
, c
->value
);
941 case V4L2_CID_PRIVATE_CONTOUR
:
943 ret
= pwc_set_contour(pdev
, c
->value
);
947 case V4L2_CID_PRIVATE_BACKLIGHT
:
948 ret
= pwc_set_backlight(pdev
, c
->value
);
952 case V4L2_CID_PRIVATE_FLICKERLESS
:
953 ret
= pwc_set_flicker(pdev
, c
->value
);
956 case V4L2_CID_PRIVATE_NOISE_REDUCTION
:
957 ret
= pwc_set_dynamic_noise(pdev
, c
->value
);
966 case VIDIOC_ENUM_FMT
:
968 struct v4l2_fmtdesc
*f
= arg
;
971 if (f
->type
!= V4L2_BUF_TYPE_VIDEO_CAPTURE
)
974 /* We only support two format: the raw format, and YUV */
976 memset(f
,0,sizeof(struct v4l2_fmtdesc
));
977 f
->type
= V4L2_BUF_TYPE_VIDEO_CAPTURE
;
983 f
->pixelformat
= pdev
->type
<=646?V4L2_PIX_FMT_PWC1
:V4L2_PIX_FMT_PWC2
;
984 f
->flags
= V4L2_FMT_FLAG_COMPRESSED
;
985 strlcpy(f
->description
,"Raw Philips Webcam",sizeof(f
->description
));
988 f
->pixelformat
= V4L2_PIX_FMT_YUV420
;
989 strlcpy(f
->description
,"4:2:0, planar, Y-Cb-Cr",sizeof(f
->description
));
999 struct v4l2_format
*f
= arg
;
1001 PWC_DEBUG_IOCTL("ioctl(VIDIOC_G_FMT) return size %dx%d\n",pdev
->image
.x
,pdev
->image
.y
);
1002 if (f
->type
!= V4L2_BUF_TYPE_VIDEO_CAPTURE
)
1005 pwc_vidioc_fill_fmt(pdev
, f
);
1010 case VIDIOC_TRY_FMT
:
1011 return pwc_vidioc_try_fmt(pdev
, arg
);
1014 return pwc_vidioc_set_fmt(pdev
, arg
);
1018 v4l2_std_id
*std
= arg
;
1019 *std
= V4L2_STD_UNKNOWN
;
1025 v4l2_std_id
*std
= arg
;
1026 if (*std
!= V4L2_STD_UNKNOWN
)
1031 case VIDIOC_ENUMSTD
:
1033 struct v4l2_standard
*std
= arg
;
1034 if (std
->index
!= 0)
1036 std
->id
= V4L2_STD_UNKNOWN
;
1037 strncpy(std
->name
, "webcam", sizeof(std
->name
));
1041 case VIDIOC_REQBUFS
:
1043 struct v4l2_requestbuffers
*rb
= arg
;
1046 PWC_DEBUG_IOCTL("ioctl(VIDIOC_REQBUFS) count=%d\n",rb
->count
);
1047 if (rb
->type
!= V4L2_BUF_TYPE_VIDEO_CAPTURE
)
1049 if (rb
->memory
!= V4L2_MEMORY_MMAP
)
1052 nbuffers
= rb
->count
;
1055 else if (nbuffers
> pwc_mbufs
)
1056 nbuffers
= pwc_mbufs
;
1057 /* Force to use our # of buffers */
1058 rb
->count
= pwc_mbufs
;
1062 case VIDIOC_QUERYBUF
:
1064 struct v4l2_buffer
*buf
= arg
;
1067 PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYBUF) index=%d\n",buf
->index
);
1068 if (buf
->type
!= V4L2_BUF_TYPE_VIDEO_CAPTURE
) {
1069 PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYBUF) Bad type\n");
1072 if (buf
->memory
!= V4L2_MEMORY_MMAP
) {
1073 PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYBUF) Bad memory type\n");
1077 if (index
< 0 || index
>= pwc_mbufs
) {
1078 PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYBUF) Bad index %d\n", buf
->index
);
1082 memset(buf
, 0, sizeof(struct v4l2_buffer
));
1083 buf
->type
= V4L2_BUF_TYPE_VIDEO_CAPTURE
;
1085 buf
->m
.offset
= index
* pdev
->len_per_image
;
1086 if (pdev
->vpalette
== VIDEO_PALETTE_RAW
)
1087 buf
->bytesused
= pdev
->frame_size
+ sizeof(struct pwc_raw_frame
);
1089 buf
->bytesused
= pdev
->view
.size
;
1090 buf
->field
= V4L2_FIELD_NONE
;
1091 buf
->memory
= V4L2_MEMORY_MMAP
;
1092 //buf->flags = V4L2_BUF_FLAG_MAPPED;
1093 buf
->length
= pdev
->len_per_image
;
1095 PWC_DEBUG_READ("VIDIOC_QUERYBUF: index=%d\n",buf
->index
);
1096 PWC_DEBUG_READ("VIDIOC_QUERYBUF: m.offset=%d\n",buf
->m
.offset
);
1097 PWC_DEBUG_READ("VIDIOC_QUERYBUF: bytesused=%d\n",buf
->bytesused
);
1104 struct v4l2_buffer
*buf
= arg
;
1106 PWC_DEBUG_IOCTL("ioctl(VIDIOC_QBUF) index=%d\n",buf
->index
);
1107 if (buf
->type
!= V4L2_BUF_TYPE_VIDEO_CAPTURE
)
1109 if (buf
->memory
!= V4L2_MEMORY_MMAP
)
1111 if (buf
->index
< 0 || buf
->index
>= pwc_mbufs
)
1114 buf
->flags
|= V4L2_BUF_FLAG_QUEUED
;
1115 buf
->flags
&= ~V4L2_BUF_FLAG_DONE
;
1122 struct v4l2_buffer
*buf
= arg
;
1125 PWC_DEBUG_IOCTL("ioctl(VIDIOC_DQBUF)\n");
1127 if (buf
->type
!= V4L2_BUF_TYPE_VIDEO_CAPTURE
)
1130 /* Add ourselves to the frame wait-queue.
1132 FIXME: needs auditing for safety.
1133 QUESTION: In what respect? I think that using the
1136 add_wait_queue(&pdev
->frameq
, &wait
);
1137 while (pdev
->full_frames
== NULL
) {
1138 if (pdev
->error_status
) {
1139 remove_wait_queue(&pdev
->frameq
, &wait
);
1140 set_current_state(TASK_RUNNING
);
1141 return -pdev
->error_status
;
1144 if (signal_pending(current
)) {
1145 remove_wait_queue(&pdev
->frameq
, &wait
);
1146 set_current_state(TASK_RUNNING
);
1147 return -ERESTARTSYS
;
1150 set_current_state(TASK_INTERRUPTIBLE
);
1152 remove_wait_queue(&pdev
->frameq
, &wait
);
1153 set_current_state(TASK_RUNNING
);
1155 PWC_DEBUG_IOCTL("VIDIOC_DQBUF: frame ready.\n");
1156 /* Decompress data in pdev->images[pdev->fill_image] */
1157 ret
= pwc_handle_frame(pdev
);
1160 PWC_DEBUG_IOCTL("VIDIOC_DQBUF: after pwc_handle_frame\n");
1162 buf
->index
= pdev
->fill_image
;
1163 if (pdev
->vpalette
== VIDEO_PALETTE_RAW
)
1164 buf
->bytesused
= pdev
->frame_size
+ sizeof(struct pwc_raw_frame
);
1166 buf
->bytesused
= pdev
->view
.size
;
1167 buf
->flags
= V4L2_BUF_FLAG_MAPPED
;
1168 buf
->field
= V4L2_FIELD_NONE
;
1169 do_gettimeofday(&buf
->timestamp
);
1171 buf
->memory
= V4L2_MEMORY_MMAP
;
1172 buf
->m
.offset
= pdev
->fill_image
* pdev
->len_per_image
;
1173 buf
->length
= pdev
->len_per_image
;
1174 pwc_next_image(pdev
);
1176 PWC_DEBUG_IOCTL("VIDIOC_DQBUF: buf->index=%d\n",buf
->index
);
1177 PWC_DEBUG_IOCTL("VIDIOC_DQBUF: buf->length=%d\n",buf
->length
);
1178 PWC_DEBUG_IOCTL("VIDIOC_DQBUF: m.offset=%d\n",buf
->m
.offset
);
1179 PWC_DEBUG_IOCTL("VIDIOC_DQBUF: bytesused=%d\n",buf
->bytesused
);
1180 PWC_DEBUG_IOCTL("VIDIOC_DQBUF: leaving\n");
1185 case VIDIOC_STREAMON
:
1187 /* WARNING: pwc_try_video_mode() called pwc_isoc_init */
1188 pwc_isoc_init(pdev
);
1192 case VIDIOC_STREAMOFF
:
1194 pwc_isoc_cleanup(pdev
);
1198 case VIDIOC_ENUM_FRAMESIZES
:
1200 struct v4l2_frmsizeenum
*fsize
= arg
;
1201 unsigned int i
= 0, index
= fsize
->index
;
1203 if (fsize
->pixel_format
== V4L2_PIX_FMT_YUV420
) {
1204 for (i
= 0; i
< PSZ_MAX
; i
++) {
1205 if (pdev
->image_mask
& (1UL << i
)) {
1207 fsize
->type
= V4L2_FRMSIZE_TYPE_DISCRETE
;
1208 fsize
->discrete
.width
= pwc_image_sizes
[i
].x
;
1209 fsize
->discrete
.height
= pwc_image_sizes
[i
].y
;
1214 } else if (fsize
->index
== 0 &&
1215 ((fsize
->pixel_format
== V4L2_PIX_FMT_PWC1
&& DEVICE_USE_CODEC1(pdev
->type
)) ||
1216 (fsize
->pixel_format
== V4L2_PIX_FMT_PWC2
&& DEVICE_USE_CODEC23(pdev
->type
)))) {
1218 fsize
->type
= V4L2_FRMSIZE_TYPE_DISCRETE
;
1219 fsize
->discrete
.width
= pdev
->abs_max
.x
;
1220 fsize
->discrete
.height
= pdev
->abs_max
.y
;
1226 case VIDIOC_ENUM_FRAMEINTERVALS
:
1228 struct v4l2_frmivalenum
*fival
= arg
;
1232 for (i
= 0; i
< PSZ_MAX
; i
++) {
1233 if (pwc_image_sizes
[i
].x
== fival
->width
&&
1234 pwc_image_sizes
[i
].y
== fival
->height
) {
1240 /* TODO: Support raw format */
1241 if (size
< 0 || fival
->pixel_format
!= V4L2_PIX_FMT_YUV420
) {
1245 i
= pwc_get_fps(pdev
, fival
->index
, size
);
1249 fival
->type
= V4L2_FRMIVAL_TYPE_DISCRETE
;
1250 fival
->discrete
.numerator
= 1;
1251 fival
->discrete
.denominator
= i
;
1257 return pwc_ioctl(pdev
, cmd
, arg
);
1262 /* vim: set cino= formatoptions=croql cindent shiftwidth=8 tabstop=8: */