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
);
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
;
439 * FIXME: Suppose we are mid read
440 ANSWER: No problem: the firmware of the camera
441 can handle brightness/contrast/etc
442 changes at _any_ time, and the palette
443 is used exactly once in the uncompress
446 pwc_set_brightness(pdev
, p
->brightness
);
447 pwc_set_contrast(pdev
, p
->contrast
);
448 pwc_set_gamma(pdev
, p
->whiteness
);
449 pwc_set_saturation(pdev
, (p
->colour
-32768)/327);
450 if (p
->palette
&& p
->palette
!= pdev
->vpalette
) {
451 switch (p
->palette
) {
452 case VIDEO_PALETTE_YUV420P
:
453 case VIDEO_PALETTE_RAW
:
454 pdev
->vpalette
= p
->palette
;
455 return pwc_try_video_mode(pdev
, pdev
->image
.x
, pdev
->image
.y
, pdev
->vframes
, pdev
->vcompression
, pdev
->vsnapshot
);
465 /* Window/size parameters */
468 struct video_window
*vw
= arg
;
472 vw
->width
= pdev
->view
.x
;
473 vw
->height
= pdev
->view
.y
;
475 vw
->flags
= (pdev
->vframes
<< PWC_FPS_SHIFT
) |
476 (pdev
->vsnapshot
? PWC_FPS_SNAPSHOT
: 0);
482 struct video_window
*vw
= arg
;
483 int fps
, snapshot
, ret
;
485 fps
= (vw
->flags
& PWC_FPS_FRMASK
) >> PWC_FPS_SHIFT
;
486 snapshot
= vw
->flags
& PWC_FPS_SNAPSHOT
;
489 if (pdev
->view
.x
== vw
->width
&& pdev
->view
.y
&& fps
== pdev
->vframes
&& snapshot
== pdev
->vsnapshot
)
491 ret
= pwc_try_video_mode(pdev
, vw
->width
, vw
->height
, fps
, pdev
->vcompression
, snapshot
);
497 /* We don't have overlay support (yet) */
500 struct video_buffer
*vb
= arg
;
502 memset(vb
,0,sizeof(*vb
));
506 /* mmap() functions */
509 /* Tell the user program how much memory is needed for a mmap() */
510 struct video_mbuf
*vm
= arg
;
513 memset(vm
, 0, sizeof(*vm
));
514 vm
->size
= pwc_mbufs
* pdev
->len_per_image
;
515 vm
->frames
= pwc_mbufs
; /* double buffering should be enough for most applications */
516 for (i
= 0; i
< pwc_mbufs
; i
++)
517 vm
->offsets
[i
] = i
* pdev
->len_per_image
;
523 /* Start capture into a given image buffer (called 'frame' in video_mmap structure) */
524 struct video_mmap
*vm
= arg
;
526 PWC_DEBUG_READ("VIDIOCMCAPTURE: %dx%d, frame %d, format %d\n", vm
->width
, vm
->height
, vm
->frame
, vm
->format
);
527 if (vm
->frame
< 0 || vm
->frame
>= pwc_mbufs
)
530 /* xawtv is nasty. It probes the available palettes
531 by setting a very small image size and trying
532 various palettes... The driver doesn't support
533 such small images, so I'm working around it.
539 case VIDEO_PALETTE_YUV420P
:
540 case VIDEO_PALETTE_RAW
:
548 if ((vm
->width
!= pdev
->view
.x
|| vm
->height
!= pdev
->view
.y
) &&
549 (vm
->width
>= pdev
->view_min
.x
&& vm
->height
>= pdev
->view_min
.y
)) {
552 PWC_DEBUG_OPEN("VIDIOCMCAPTURE: changing size to please xawtv :-(.\n");
553 ret
= pwc_try_video_mode(pdev
, vm
->width
, vm
->height
, pdev
->vframes
, pdev
->vcompression
, pdev
->vsnapshot
);
556 } /* ... size mismatch */
558 /* FIXME: should we lock here? */
559 if (pdev
->image_used
[vm
->frame
])
560 return -EBUSY
; /* buffer wasn't available. Bummer */
561 pdev
->image_used
[vm
->frame
] = 1;
563 /* Okay, we're done here. In the SYNC call we wait until a
564 frame comes available, then expand image into the given
566 In contrast to the CPiA cam the Philips cams deliver a
567 constant stream, almost like a grabber card. Also,
568 we have separate buffers for the rawdata and the image,
569 meaning we can nearly always expand into the requested buffer.
571 PWC_DEBUG_READ("VIDIOCMCAPTURE done.\n");
577 /* The doc says: "Whenever a buffer is used it should
578 call VIDIOCSYNC to free this frame up and continue."
580 The only odd thing about this whole procedure is
581 that MCAPTURE flags the buffer as "in use", and
582 SYNC immediately unmarks it, while it isn't
583 after SYNC that you know that the buffer actually
584 got filled! So you better not start a CAPTURE in
585 the same frame immediately (use double buffering).
586 This is not a problem for this cam, since it has
587 extra intermediate buffers, but a hardware
588 grabber card will then overwrite the buffer
594 PWC_DEBUG_READ("VIDIOCSYNC called (%d).\n", *mbuf
);
597 if (*mbuf
< 0 || *mbuf
>= pwc_mbufs
)
599 /* check if this buffer was requested anyway */
600 if (pdev
->image_used
[*mbuf
] == 0)
603 /* Add ourselves to the frame wait-queue.
605 FIXME: needs auditing for safety.
606 QUESTION: In what respect? I think that using the
609 add_wait_queue(&pdev
->frameq
, &wait
);
610 while (pdev
->full_frames
== NULL
) {
611 /* Check for unplugged/etc. here */
612 if (pdev
->error_status
) {
613 remove_wait_queue(&pdev
->frameq
, &wait
);
614 set_current_state(TASK_RUNNING
);
615 return -pdev
->error_status
;
618 if (signal_pending(current
)) {
619 remove_wait_queue(&pdev
->frameq
, &wait
);
620 set_current_state(TASK_RUNNING
);
624 set_current_state(TASK_INTERRUPTIBLE
);
626 remove_wait_queue(&pdev
->frameq
, &wait
);
627 set_current_state(TASK_RUNNING
);
629 /* The frame is ready. Expand in the image buffer
630 requested by the user. I don't care if you
631 mmap() 5 buffers and request data in this order:
632 buffer 4 2 3 0 1 2 3 0 4 3 1 . . .
633 Grabber hardware may not be so forgiving.
635 PWC_DEBUG_READ("VIDIOCSYNC: frame ready.\n");
636 pdev
->fill_image
= *mbuf
; /* tell in which buffer we want the image to be expanded */
637 /* Decompress, etc */
638 ret
= pwc_handle_frame(pdev
);
639 pdev
->image_used
[*mbuf
] = 0;
647 struct video_audio
*v
= arg
;
649 strcpy(v
->name
, "Microphone");
650 v
->audio
= -1; /* unknown audio minor */
652 v
->mode
= VIDEO_SOUND_MONO
;
663 /* Dummy: nothing can be set */
669 struct video_unit
*vu
= arg
;
671 vu
->video
= pdev
->vdev
->minor
& 0x3F;
672 vu
->audio
= -1; /* not known yet */
680 case VIDIOC_QUERYCAP
:
682 struct v4l2_capability
*cap
= arg
;
684 PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYCAP) This application "\
685 "try to use the v4l2 layer\n");
686 strcpy(cap
->driver
,PWC_NAME
);
687 strlcpy(cap
->card
, vdev
->name
, sizeof(cap
->card
));
688 usb_make_path(pdev
->udev
,cap
->bus_info
,sizeof(cap
->bus_info
));
689 cap
->version
= PWC_VERSION_CODE
;
691 V4L2_CAP_VIDEO_CAPTURE
|
697 case VIDIOC_ENUMINPUT
:
699 struct v4l2_input
*i
= arg
;
701 if ( i
->index
) /* Only one INPUT is supported */
704 memset(i
, 0, sizeof(struct v4l2_input
));
705 strcpy(i
->name
, "usb");
712 *i
= 0; /* Only one INPUT is supported */
719 if ( *i
) { /* Only one INPUT is supported */
720 PWC_DEBUG_IOCTL("Only one input source is"\
721 " supported with this webcam.\n");
728 case VIDIOC_QUERYCTRL
:
730 struct v4l2_queryctrl
*c
= arg
;
733 PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYCTRL) query id=%d\n", c
->id
);
734 for (i
=0; i
<sizeof(pwc_controls
)/sizeof(struct v4l2_queryctrl
); i
++) {
735 if (pwc_controls
[i
].id
== c
->id
) {
736 PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYCTRL) found\n");
737 memcpy(c
,&pwc_controls
[i
],sizeof(struct v4l2_queryctrl
));
741 PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYCTRL) not found\n");
747 struct v4l2_control
*c
= arg
;
752 case V4L2_CID_BRIGHTNESS
:
753 c
->value
= pwc_get_brightness(pdev
);
757 case V4L2_CID_CONTRAST
:
758 c
->value
= pwc_get_contrast(pdev
);
762 case V4L2_CID_SATURATION
:
763 ret
= pwc_get_saturation(pdev
, &c
->value
);
768 c
->value
= pwc_get_gamma(pdev
);
772 case V4L2_CID_RED_BALANCE
:
773 ret
= pwc_get_red_gain(pdev
, &c
->value
);
778 case V4L2_CID_BLUE_BALANCE
:
779 ret
= pwc_get_blue_gain(pdev
, &c
->value
);
784 case V4L2_CID_AUTO_WHITE_BALANCE
:
785 ret
= pwc_get_awb(pdev
);
788 c
->value
= (ret
== PWC_WB_MANUAL
)?0:1;
791 ret
= pwc_get_agc(pdev
, &c
->value
);
796 case V4L2_CID_AUTOGAIN
:
797 ret
= pwc_get_agc(pdev
, &c
->value
);
800 c
->value
= (c
->value
< 0)?1:0;
802 case V4L2_CID_EXPOSURE
:
803 ret
= pwc_get_shutter_speed(pdev
, &c
->value
);
807 case V4L2_CID_PRIVATE_COLOUR_MODE
:
808 ret
= pwc_get_colour_mode(pdev
, &c
->value
);
812 case V4L2_CID_PRIVATE_AUTOCONTOUR
:
813 ret
= pwc_get_contour(pdev
, &c
->value
);
816 c
->value
=(c
->value
== -1?1:0);
818 case V4L2_CID_PRIVATE_CONTOUR
:
819 ret
= pwc_get_contour(pdev
, &c
->value
);
824 case V4L2_CID_PRIVATE_BACKLIGHT
:
825 ret
= pwc_get_backlight(pdev
, &c
->value
);
829 case V4L2_CID_PRIVATE_FLICKERLESS
:
830 ret
= pwc_get_flicker(pdev
, &c
->value
);
833 c
->value
=(c
->value
?1:0);
835 case V4L2_CID_PRIVATE_NOISE_REDUCTION
:
836 ret
= pwc_get_dynamic_noise(pdev
, &c
->value
);
841 case V4L2_CID_PRIVATE_SAVE_USER
:
842 case V4L2_CID_PRIVATE_RESTORE_USER
:
843 case V4L2_CID_PRIVATE_RESTORE_FACTORY
:
850 struct v4l2_control
*c
= arg
;
855 case V4L2_CID_BRIGHTNESS
:
857 ret
= pwc_set_brightness(pdev
, c
->value
);
861 case V4L2_CID_CONTRAST
:
863 ret
= pwc_set_contrast(pdev
, c
->value
);
867 case V4L2_CID_SATURATION
:
868 ret
= pwc_set_saturation(pdev
, c
->value
);
874 ret
= pwc_set_gamma(pdev
, c
->value
);
878 case V4L2_CID_RED_BALANCE
:
880 ret
= pwc_set_red_gain(pdev
, c
->value
);
884 case V4L2_CID_BLUE_BALANCE
:
886 ret
= pwc_set_blue_gain(pdev
, c
->value
);
890 case V4L2_CID_AUTO_WHITE_BALANCE
:
891 c
->value
= (c
->value
== 0)?PWC_WB_MANUAL
:PWC_WB_AUTO
;
892 ret
= pwc_set_awb(pdev
, c
->value
);
896 case V4L2_CID_EXPOSURE
:
898 ret
= pwc_set_shutter_speed(pdev
, c
->value
?0:1, c
->value
);
902 case V4L2_CID_AUTOGAIN
:
903 /* autogain off means nothing without a gain */
906 ret
= pwc_set_agc(pdev
, c
->value
, 0);
912 ret
= pwc_set_agc(pdev
, 0, c
->value
);
916 case V4L2_CID_PRIVATE_SAVE_USER
:
917 if (pwc_save_user(pdev
))
920 case V4L2_CID_PRIVATE_RESTORE_USER
:
921 if (pwc_restore_user(pdev
))
924 case V4L2_CID_PRIVATE_RESTORE_FACTORY
:
925 if (pwc_restore_factory(pdev
))
928 case V4L2_CID_PRIVATE_COLOUR_MODE
:
929 ret
= pwc_set_colour_mode(pdev
, c
->value
);
933 case V4L2_CID_PRIVATE_AUTOCONTOUR
:
934 c
->value
=(c
->value
== 1)?-1:0;
935 ret
= pwc_set_contour(pdev
, c
->value
);
939 case V4L2_CID_PRIVATE_CONTOUR
:
941 ret
= pwc_set_contour(pdev
, c
->value
);
945 case V4L2_CID_PRIVATE_BACKLIGHT
:
946 ret
= pwc_set_backlight(pdev
, c
->value
);
950 case V4L2_CID_PRIVATE_FLICKERLESS
:
951 ret
= pwc_set_flicker(pdev
, c
->value
);
954 case V4L2_CID_PRIVATE_NOISE_REDUCTION
:
955 ret
= pwc_set_dynamic_noise(pdev
, c
->value
);
964 case VIDIOC_ENUM_FMT
:
966 struct v4l2_fmtdesc
*f
= arg
;
969 if (f
->type
!= V4L2_BUF_TYPE_VIDEO_CAPTURE
)
972 /* We only support two format: the raw format, and YUV */
974 memset(f
,0,sizeof(struct v4l2_fmtdesc
));
975 f
->type
= V4L2_BUF_TYPE_VIDEO_CAPTURE
;
981 f
->pixelformat
= pdev
->type
<=646?V4L2_PIX_FMT_PWC1
:V4L2_PIX_FMT_PWC2
;
982 f
->flags
= V4L2_FMT_FLAG_COMPRESSED
;
983 strlcpy(f
->description
,"Raw Philips Webcam",sizeof(f
->description
));
986 f
->pixelformat
= V4L2_PIX_FMT_YUV420
;
987 strlcpy(f
->description
,"4:2:0, planar, Y-Cb-Cr",sizeof(f
->description
));
997 struct v4l2_format
*f
= arg
;
999 PWC_DEBUG_IOCTL("ioctl(VIDIOC_G_FMT) return size %dx%d\n",pdev
->image
.x
,pdev
->image
.y
);
1000 if (f
->type
!= V4L2_BUF_TYPE_VIDEO_CAPTURE
)
1003 pwc_vidioc_fill_fmt(pdev
, f
);
1008 case VIDIOC_TRY_FMT
:
1009 return pwc_vidioc_try_fmt(pdev
, arg
);
1012 return pwc_vidioc_set_fmt(pdev
, arg
);
1016 v4l2_std_id
*std
= arg
;
1017 *std
= V4L2_STD_UNKNOWN
;
1023 v4l2_std_id
*std
= arg
;
1024 if (*std
!= V4L2_STD_UNKNOWN
)
1029 case VIDIOC_ENUMSTD
:
1031 struct v4l2_standard
*std
= arg
;
1032 if (std
->index
!= 0)
1034 std
->id
= V4L2_STD_UNKNOWN
;
1035 strncpy(std
->name
, "webcam", sizeof(std
->name
));
1039 case VIDIOC_REQBUFS
:
1041 struct v4l2_requestbuffers
*rb
= arg
;
1044 PWC_DEBUG_IOCTL("ioctl(VIDIOC_REQBUFS) count=%d\n",rb
->count
);
1045 if (rb
->type
!= V4L2_BUF_TYPE_VIDEO_CAPTURE
)
1047 if (rb
->memory
!= V4L2_MEMORY_MMAP
)
1050 nbuffers
= rb
->count
;
1053 else if (nbuffers
> pwc_mbufs
)
1054 nbuffers
= pwc_mbufs
;
1055 /* Force to use our # of buffers */
1056 rb
->count
= pwc_mbufs
;
1060 case VIDIOC_QUERYBUF
:
1062 struct v4l2_buffer
*buf
= arg
;
1065 PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYBUF) index=%d\n",buf
->index
);
1066 if (buf
->type
!= V4L2_BUF_TYPE_VIDEO_CAPTURE
) {
1067 PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYBUF) Bad type\n");
1070 if (buf
->memory
!= V4L2_MEMORY_MMAP
) {
1071 PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYBUF) Bad memory type\n");
1075 if (index
< 0 || index
>= pwc_mbufs
) {
1076 PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYBUF) Bad index %d\n", buf
->index
);
1080 memset(buf
, 0, sizeof(struct v4l2_buffer
));
1081 buf
->type
= V4L2_BUF_TYPE_VIDEO_CAPTURE
;
1083 buf
->m
.offset
= index
* pdev
->len_per_image
;
1084 if (pdev
->vpalette
== VIDEO_PALETTE_RAW
)
1085 buf
->bytesused
= pdev
->frame_size
+ sizeof(struct pwc_raw_frame
);
1087 buf
->bytesused
= pdev
->view
.size
;
1088 buf
->field
= V4L2_FIELD_NONE
;
1089 buf
->memory
= V4L2_MEMORY_MMAP
;
1090 //buf->flags = V4L2_BUF_FLAG_MAPPED;
1091 buf
->length
= pdev
->len_per_image
;
1093 PWC_DEBUG_READ("VIDIOC_QUERYBUF: index=%d\n",buf
->index
);
1094 PWC_DEBUG_READ("VIDIOC_QUERYBUF: m.offset=%d\n",buf
->m
.offset
);
1095 PWC_DEBUG_READ("VIDIOC_QUERYBUF: bytesused=%d\n",buf
->bytesused
);
1102 struct v4l2_buffer
*buf
= arg
;
1104 PWC_DEBUG_IOCTL("ioctl(VIDIOC_QBUF) index=%d\n",buf
->index
);
1105 if (buf
->type
!= V4L2_BUF_TYPE_VIDEO_CAPTURE
)
1107 if (buf
->memory
!= V4L2_MEMORY_MMAP
)
1109 if (buf
->index
< 0 || buf
->index
>= pwc_mbufs
)
1112 buf
->flags
|= V4L2_BUF_FLAG_QUEUED
;
1113 buf
->flags
&= ~V4L2_BUF_FLAG_DONE
;
1120 struct v4l2_buffer
*buf
= arg
;
1123 PWC_DEBUG_IOCTL("ioctl(VIDIOC_DQBUF)\n");
1125 if (buf
->type
!= V4L2_BUF_TYPE_VIDEO_CAPTURE
)
1128 /* Add ourselves to the frame wait-queue.
1130 FIXME: needs auditing for safety.
1131 QUESTION: In what respect? I think that using the
1134 add_wait_queue(&pdev
->frameq
, &wait
);
1135 while (pdev
->full_frames
== NULL
) {
1136 if (pdev
->error_status
) {
1137 remove_wait_queue(&pdev
->frameq
, &wait
);
1138 set_current_state(TASK_RUNNING
);
1139 return -pdev
->error_status
;
1142 if (signal_pending(current
)) {
1143 remove_wait_queue(&pdev
->frameq
, &wait
);
1144 set_current_state(TASK_RUNNING
);
1145 return -ERESTARTSYS
;
1148 set_current_state(TASK_INTERRUPTIBLE
);
1150 remove_wait_queue(&pdev
->frameq
, &wait
);
1151 set_current_state(TASK_RUNNING
);
1153 PWC_DEBUG_IOCTL("VIDIOC_DQBUF: frame ready.\n");
1154 /* Decompress data in pdev->images[pdev->fill_image] */
1155 ret
= pwc_handle_frame(pdev
);
1158 PWC_DEBUG_IOCTL("VIDIOC_DQBUF: after pwc_handle_frame\n");
1160 buf
->index
= pdev
->fill_image
;
1161 if (pdev
->vpalette
== VIDEO_PALETTE_RAW
)
1162 buf
->bytesused
= pdev
->frame_size
+ sizeof(struct pwc_raw_frame
);
1164 buf
->bytesused
= pdev
->view
.size
;
1165 buf
->flags
= V4L2_BUF_FLAG_MAPPED
;
1166 buf
->field
= V4L2_FIELD_NONE
;
1167 do_gettimeofday(&buf
->timestamp
);
1169 buf
->memory
= V4L2_MEMORY_MMAP
;
1170 buf
->m
.offset
= pdev
->fill_image
* pdev
->len_per_image
;
1171 buf
->length
= pdev
->len_per_image
;
1172 pwc_next_image(pdev
);
1174 PWC_DEBUG_IOCTL("VIDIOC_DQBUF: buf->index=%d\n",buf
->index
);
1175 PWC_DEBUG_IOCTL("VIDIOC_DQBUF: buf->length=%d\n",buf
->length
);
1176 PWC_DEBUG_IOCTL("VIDIOC_DQBUF: m.offset=%d\n",buf
->m
.offset
);
1177 PWC_DEBUG_IOCTL("VIDIOC_DQBUF: bytesused=%d\n",buf
->bytesused
);
1178 PWC_DEBUG_IOCTL("VIDIOC_DQBUF: leaving\n");
1183 case VIDIOC_STREAMON
:
1185 /* WARNING: pwc_try_video_mode() called pwc_isoc_init */
1186 pwc_isoc_init(pdev
);
1190 case VIDIOC_STREAMOFF
:
1192 pwc_isoc_cleanup(pdev
);
1196 case VIDIOC_ENUM_FRAMESIZES
:
1198 struct v4l2_frmsizeenum
*fsize
= arg
;
1199 unsigned int i
= 0, index
= fsize
->index
;
1201 if (fsize
->pixel_format
== V4L2_PIX_FMT_YUV420
) {
1202 for (i
= 0; i
< PSZ_MAX
; i
++) {
1203 if (pdev
->image_mask
& (1UL << i
)) {
1205 fsize
->type
= V4L2_FRMSIZE_TYPE_DISCRETE
;
1206 fsize
->discrete
.width
= pwc_image_sizes
[i
].x
;
1207 fsize
->discrete
.height
= pwc_image_sizes
[i
].y
;
1212 } else if (fsize
->index
== 0 &&
1213 ((fsize
->pixel_format
== V4L2_PIX_FMT_PWC1
&& DEVICE_USE_CODEC1(pdev
->type
)) ||
1214 (fsize
->pixel_format
== V4L2_PIX_FMT_PWC2
&& DEVICE_USE_CODEC23(pdev
->type
)))) {
1216 fsize
->type
= V4L2_FRMSIZE_TYPE_DISCRETE
;
1217 fsize
->discrete
.width
= pdev
->abs_max
.x
;
1218 fsize
->discrete
.height
= pdev
->abs_max
.y
;
1224 case VIDIOC_ENUM_FRAMEINTERVALS
:
1226 struct v4l2_frmivalenum
*fival
= arg
;
1230 for (i
= 0; i
< PSZ_MAX
; i
++) {
1231 if (pwc_image_sizes
[i
].x
== fival
->width
&&
1232 pwc_image_sizes
[i
].y
== fival
->height
) {
1238 /* TODO: Support raw format */
1239 if (size
< 0 || fival
->pixel_format
!= V4L2_PIX_FMT_YUV420
) {
1243 i
= pwc_get_fps(pdev
, fival
->index
, size
);
1247 fival
->type
= V4L2_FRMIVAL_TYPE_DISCRETE
;
1248 fival
->discrete
.numerator
= 1;
1249 fival
->discrete
.denominator
= i
;
1255 return pwc_ioctl(pdev
, cmd
, arg
);
1260 /* vim: set cino= formatoptions=croql cindent shiftwidth=8 tabstop=8: */