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 long pwc_video_do_ioctl(struct file
*file
, unsigned int cmd
, void *arg
)
342 struct video_device
*vdev
= video_devdata(file
);
343 struct pwc_device
*pdev
;
344 DECLARE_WAITQUEUE(wait
, current
);
348 pdev
= video_get_drvdata(vdev
);
352 #ifdef CONFIG_USB_PWC_DEBUG
353 if (PWC_DEBUG_LEVEL_IOCTL
& pwc_trace
) {
354 v4l_printk_ioctl(cmd
);
361 /* Query cabapilities */
364 struct video_capability
*caps
= arg
;
366 strcpy(caps
->name
, vdev
->name
);
367 caps
->type
= VID_TYPE_CAPTURE
;
370 caps
->minwidth
= pdev
->view_min
.x
;
371 caps
->minheight
= pdev
->view_min
.y
;
372 caps
->maxwidth
= pdev
->view_max
.x
;
373 caps
->maxheight
= pdev
->view_max
.y
;
377 /* Channel functions (simulate 1 channel) */
380 struct video_channel
*v
= arg
;
386 v
->type
= VIDEO_TYPE_CAMERA
;
387 strcpy(v
->name
, "Webcam");
393 /* The spec says the argument is an integer, but
394 the bttv driver uses a video_channel arg, which
395 makes sense becasue it also has the norm flag.
397 struct video_channel
*v
= arg
;
404 /* Picture functions; contrast etc. */
407 struct video_picture
*p
= arg
;
410 val
= pwc_get_brightness(pdev
);
412 p
->brightness
= (val
<<9);
414 p
->brightness
= 0xffff;
415 val
= pwc_get_contrast(pdev
);
417 p
->contrast
= (val
<<10);
419 p
->contrast
= 0xffff;
420 /* Gamma, Whiteness, what's the difference? :) */
421 val
= pwc_get_gamma(pdev
);
423 p
->whiteness
= (val
<<11);
425 p
->whiteness
= 0xffff;
426 if (pwc_get_saturation(pdev
, &val
)<0)
429 p
->colour
= 32768 + val
* 327;
431 p
->palette
= pdev
->vpalette
;
432 p
->hue
= 0xFFFF; /* N/A */
438 struct video_picture
*p
= arg
;
440 * FIXME: Suppose we are mid read
441 ANSWER: No problem: the firmware of the camera
442 can handle brightness/contrast/etc
443 changes at _any_ time, and the palette
444 is used exactly once in the uncompress
447 pwc_set_brightness(pdev
, p
->brightness
);
448 pwc_set_contrast(pdev
, p
->contrast
);
449 pwc_set_gamma(pdev
, p
->whiteness
);
450 pwc_set_saturation(pdev
, (p
->colour
-32768)/327);
451 if (p
->palette
&& p
->palette
!= pdev
->vpalette
) {
452 switch (p
->palette
) {
453 case VIDEO_PALETTE_YUV420P
:
454 case VIDEO_PALETTE_RAW
:
455 pdev
->vpalette
= p
->palette
;
456 return pwc_try_video_mode(pdev
, pdev
->image
.x
, pdev
->image
.y
, pdev
->vframes
, pdev
->vcompression
, pdev
->vsnapshot
);
466 /* Window/size parameters */
469 struct video_window
*vw
= arg
;
473 vw
->width
= pdev
->view
.x
;
474 vw
->height
= pdev
->view
.y
;
476 vw
->flags
= (pdev
->vframes
<< PWC_FPS_SHIFT
) |
477 (pdev
->vsnapshot
? PWC_FPS_SNAPSHOT
: 0);
483 struct video_window
*vw
= arg
;
484 int fps
, snapshot
, ret
;
486 fps
= (vw
->flags
& PWC_FPS_FRMASK
) >> PWC_FPS_SHIFT
;
487 snapshot
= vw
->flags
& PWC_FPS_SNAPSHOT
;
490 if (pdev
->view
.x
== vw
->width
&& pdev
->view
.y
&& fps
== pdev
->vframes
&& snapshot
== pdev
->vsnapshot
)
492 ret
= pwc_try_video_mode(pdev
, vw
->width
, vw
->height
, fps
, pdev
->vcompression
, snapshot
);
498 /* We don't have overlay support (yet) */
501 struct video_buffer
*vb
= arg
;
503 memset(vb
,0,sizeof(*vb
));
507 /* mmap() functions */
510 /* Tell the user program how much memory is needed for a mmap() */
511 struct video_mbuf
*vm
= arg
;
514 memset(vm
, 0, sizeof(*vm
));
515 vm
->size
= pwc_mbufs
* pdev
->len_per_image
;
516 vm
->frames
= pwc_mbufs
; /* double buffering should be enough for most applications */
517 for (i
= 0; i
< pwc_mbufs
; i
++)
518 vm
->offsets
[i
] = i
* pdev
->len_per_image
;
524 /* Start capture into a given image buffer (called 'frame' in video_mmap structure) */
525 struct video_mmap
*vm
= arg
;
527 PWC_DEBUG_READ("VIDIOCMCAPTURE: %dx%d, frame %d, format %d\n", vm
->width
, vm
->height
, vm
->frame
, vm
->format
);
528 if (vm
->frame
< 0 || vm
->frame
>= pwc_mbufs
)
531 /* xawtv is nasty. It probes the available palettes
532 by setting a very small image size and trying
533 various palettes... The driver doesn't support
534 such small images, so I'm working around it.
540 case VIDEO_PALETTE_YUV420P
:
541 case VIDEO_PALETTE_RAW
:
549 if ((vm
->width
!= pdev
->view
.x
|| vm
->height
!= pdev
->view
.y
) &&
550 (vm
->width
>= pdev
->view_min
.x
&& vm
->height
>= pdev
->view_min
.y
)) {
553 PWC_DEBUG_OPEN("VIDIOCMCAPTURE: changing size to please xawtv :-(.\n");
554 ret
= pwc_try_video_mode(pdev
, vm
->width
, vm
->height
, pdev
->vframes
, pdev
->vcompression
, pdev
->vsnapshot
);
557 } /* ... size mismatch */
559 /* FIXME: should we lock here? */
560 if (pdev
->image_used
[vm
->frame
])
561 return -EBUSY
; /* buffer wasn't available. Bummer */
562 pdev
->image_used
[vm
->frame
] = 1;
564 /* Okay, we're done here. In the SYNC call we wait until a
565 frame comes available, then expand image into the given
567 In contrast to the CPiA cam the Philips cams deliver a
568 constant stream, almost like a grabber card. Also,
569 we have separate buffers for the rawdata and the image,
570 meaning we can nearly always expand into the requested buffer.
572 PWC_DEBUG_READ("VIDIOCMCAPTURE done.\n");
578 /* The doc says: "Whenever a buffer is used it should
579 call VIDIOCSYNC to free this frame up and continue."
581 The only odd thing about this whole procedure is
582 that MCAPTURE flags the buffer as "in use", and
583 SYNC immediately unmarks it, while it isn't
584 after SYNC that you know that the buffer actually
585 got filled! So you better not start a CAPTURE in
586 the same frame immediately (use double buffering).
587 This is not a problem for this cam, since it has
588 extra intermediate buffers, but a hardware
589 grabber card will then overwrite the buffer
595 PWC_DEBUG_READ("VIDIOCSYNC called (%d).\n", *mbuf
);
598 if (*mbuf
< 0 || *mbuf
>= pwc_mbufs
)
600 /* check if this buffer was requested anyway */
601 if (pdev
->image_used
[*mbuf
] == 0)
604 /* Add ourselves to the frame wait-queue.
606 FIXME: needs auditing for safety.
607 QUESTION: In what respect? I think that using the
610 add_wait_queue(&pdev
->frameq
, &wait
);
611 while (pdev
->full_frames
== NULL
) {
612 /* Check for unplugged/etc. here */
613 if (pdev
->error_status
) {
614 remove_wait_queue(&pdev
->frameq
, &wait
);
615 set_current_state(TASK_RUNNING
);
616 return -pdev
->error_status
;
619 if (signal_pending(current
)) {
620 remove_wait_queue(&pdev
->frameq
, &wait
);
621 set_current_state(TASK_RUNNING
);
625 set_current_state(TASK_INTERRUPTIBLE
);
627 remove_wait_queue(&pdev
->frameq
, &wait
);
628 set_current_state(TASK_RUNNING
);
630 /* The frame is ready. Expand in the image buffer
631 requested by the user. I don't care if you
632 mmap() 5 buffers and request data in this order:
633 buffer 4 2 3 0 1 2 3 0 4 3 1 . . .
634 Grabber hardware may not be so forgiving.
636 PWC_DEBUG_READ("VIDIOCSYNC: frame ready.\n");
637 pdev
->fill_image
= *mbuf
; /* tell in which buffer we want the image to be expanded */
638 /* Decompress, etc */
639 ret
= pwc_handle_frame(pdev
);
640 pdev
->image_used
[*mbuf
] = 0;
648 struct video_audio
*v
= arg
;
650 strcpy(v
->name
, "Microphone");
651 v
->audio
= -1; /* unknown audio minor */
653 v
->mode
= VIDEO_SOUND_MONO
;
664 /* Dummy: nothing can be set */
670 struct video_unit
*vu
= arg
;
672 vu
->video
= pdev
->vdev
->minor
& 0x3F;
673 vu
->audio
= -1; /* not known yet */
681 case VIDIOC_QUERYCAP
:
683 struct v4l2_capability
*cap
= arg
;
685 PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYCAP) This application "\
686 "try to use the v4l2 layer\n");
687 strcpy(cap
->driver
,PWC_NAME
);
688 strlcpy(cap
->card
, vdev
->name
, sizeof(cap
->card
));
689 usb_make_path(pdev
->udev
,cap
->bus_info
,sizeof(cap
->bus_info
));
690 cap
->version
= PWC_VERSION_CODE
;
692 V4L2_CAP_VIDEO_CAPTURE
|
698 case VIDIOC_ENUMINPUT
:
700 struct v4l2_input
*i
= arg
;
702 if ( i
->index
) /* Only one INPUT is supported */
705 memset(i
, 0, sizeof(struct v4l2_input
));
706 strcpy(i
->name
, "usb");
713 *i
= 0; /* Only one INPUT is supported */
720 if ( *i
) { /* Only one INPUT is supported */
721 PWC_DEBUG_IOCTL("Only one input source is"\
722 " supported with this webcam.\n");
729 case VIDIOC_QUERYCTRL
:
731 struct v4l2_queryctrl
*c
= arg
;
734 PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYCTRL) query id=%d\n", c
->id
);
735 for (i
=0; i
<sizeof(pwc_controls
)/sizeof(struct v4l2_queryctrl
); i
++) {
736 if (pwc_controls
[i
].id
== c
->id
) {
737 PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYCTRL) found\n");
738 memcpy(c
,&pwc_controls
[i
],sizeof(struct v4l2_queryctrl
));
742 PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYCTRL) not found\n");
748 struct v4l2_control
*c
= arg
;
753 case V4L2_CID_BRIGHTNESS
:
754 c
->value
= pwc_get_brightness(pdev
);
758 case V4L2_CID_CONTRAST
:
759 c
->value
= pwc_get_contrast(pdev
);
763 case V4L2_CID_SATURATION
:
764 ret
= pwc_get_saturation(pdev
, &c
->value
);
769 c
->value
= pwc_get_gamma(pdev
);
773 case V4L2_CID_RED_BALANCE
:
774 ret
= pwc_get_red_gain(pdev
, &c
->value
);
779 case V4L2_CID_BLUE_BALANCE
:
780 ret
= pwc_get_blue_gain(pdev
, &c
->value
);
785 case V4L2_CID_AUTO_WHITE_BALANCE
:
786 ret
= pwc_get_awb(pdev
);
789 c
->value
= (ret
== PWC_WB_MANUAL
)?0:1;
792 ret
= pwc_get_agc(pdev
, &c
->value
);
797 case V4L2_CID_AUTOGAIN
:
798 ret
= pwc_get_agc(pdev
, &c
->value
);
801 c
->value
= (c
->value
< 0)?1:0;
803 case V4L2_CID_EXPOSURE
:
804 ret
= pwc_get_shutter_speed(pdev
, &c
->value
);
808 case V4L2_CID_PRIVATE_COLOUR_MODE
:
809 ret
= pwc_get_colour_mode(pdev
, &c
->value
);
813 case V4L2_CID_PRIVATE_AUTOCONTOUR
:
814 ret
= pwc_get_contour(pdev
, &c
->value
);
817 c
->value
=(c
->value
== -1?1:0);
819 case V4L2_CID_PRIVATE_CONTOUR
:
820 ret
= pwc_get_contour(pdev
, &c
->value
);
825 case V4L2_CID_PRIVATE_BACKLIGHT
:
826 ret
= pwc_get_backlight(pdev
, &c
->value
);
830 case V4L2_CID_PRIVATE_FLICKERLESS
:
831 ret
= pwc_get_flicker(pdev
, &c
->value
);
834 c
->value
=(c
->value
?1:0);
836 case V4L2_CID_PRIVATE_NOISE_REDUCTION
:
837 ret
= pwc_get_dynamic_noise(pdev
, &c
->value
);
842 case V4L2_CID_PRIVATE_SAVE_USER
:
843 case V4L2_CID_PRIVATE_RESTORE_USER
:
844 case V4L2_CID_PRIVATE_RESTORE_FACTORY
:
851 struct v4l2_control
*c
= arg
;
856 case V4L2_CID_BRIGHTNESS
:
858 ret
= pwc_set_brightness(pdev
, c
->value
);
862 case V4L2_CID_CONTRAST
:
864 ret
= pwc_set_contrast(pdev
, c
->value
);
868 case V4L2_CID_SATURATION
:
869 ret
= pwc_set_saturation(pdev
, c
->value
);
875 ret
= pwc_set_gamma(pdev
, c
->value
);
879 case V4L2_CID_RED_BALANCE
:
881 ret
= pwc_set_red_gain(pdev
, c
->value
);
885 case V4L2_CID_BLUE_BALANCE
:
887 ret
= pwc_set_blue_gain(pdev
, c
->value
);
891 case V4L2_CID_AUTO_WHITE_BALANCE
:
892 c
->value
= (c
->value
== 0)?PWC_WB_MANUAL
:PWC_WB_AUTO
;
893 ret
= pwc_set_awb(pdev
, c
->value
);
897 case V4L2_CID_EXPOSURE
:
899 ret
= pwc_set_shutter_speed(pdev
, c
->value
?0:1, c
->value
);
903 case V4L2_CID_AUTOGAIN
:
904 /* autogain off means nothing without a gain */
907 ret
= pwc_set_agc(pdev
, c
->value
, 0);
913 ret
= pwc_set_agc(pdev
, 0, c
->value
);
917 case V4L2_CID_PRIVATE_SAVE_USER
:
918 if (pwc_save_user(pdev
))
921 case V4L2_CID_PRIVATE_RESTORE_USER
:
922 if (pwc_restore_user(pdev
))
925 case V4L2_CID_PRIVATE_RESTORE_FACTORY
:
926 if (pwc_restore_factory(pdev
))
929 case V4L2_CID_PRIVATE_COLOUR_MODE
:
930 ret
= pwc_set_colour_mode(pdev
, c
->value
);
934 case V4L2_CID_PRIVATE_AUTOCONTOUR
:
935 c
->value
=(c
->value
== 1)?-1:0;
936 ret
= pwc_set_contour(pdev
, c
->value
);
940 case V4L2_CID_PRIVATE_CONTOUR
:
942 ret
= pwc_set_contour(pdev
, c
->value
);
946 case V4L2_CID_PRIVATE_BACKLIGHT
:
947 ret
= pwc_set_backlight(pdev
, c
->value
);
951 case V4L2_CID_PRIVATE_FLICKERLESS
:
952 ret
= pwc_set_flicker(pdev
, c
->value
);
955 case V4L2_CID_PRIVATE_NOISE_REDUCTION
:
956 ret
= pwc_set_dynamic_noise(pdev
, c
->value
);
965 case VIDIOC_ENUM_FMT
:
967 struct v4l2_fmtdesc
*f
= arg
;
970 if (f
->type
!= V4L2_BUF_TYPE_VIDEO_CAPTURE
)
973 /* We only support two format: the raw format, and YUV */
975 memset(f
,0,sizeof(struct v4l2_fmtdesc
));
976 f
->type
= V4L2_BUF_TYPE_VIDEO_CAPTURE
;
982 f
->pixelformat
= pdev
->type
<=646?V4L2_PIX_FMT_PWC1
:V4L2_PIX_FMT_PWC2
;
983 f
->flags
= V4L2_FMT_FLAG_COMPRESSED
;
984 strlcpy(f
->description
,"Raw Philips Webcam",sizeof(f
->description
));
987 f
->pixelformat
= V4L2_PIX_FMT_YUV420
;
988 strlcpy(f
->description
,"4:2:0, planar, Y-Cb-Cr",sizeof(f
->description
));
998 struct v4l2_format
*f
= arg
;
1000 PWC_DEBUG_IOCTL("ioctl(VIDIOC_G_FMT) return size %dx%d\n",pdev
->image
.x
,pdev
->image
.y
);
1001 if (f
->type
!= V4L2_BUF_TYPE_VIDEO_CAPTURE
)
1004 pwc_vidioc_fill_fmt(pdev
, f
);
1009 case VIDIOC_TRY_FMT
:
1010 return pwc_vidioc_try_fmt(pdev
, arg
);
1013 return pwc_vidioc_set_fmt(pdev
, arg
);
1017 v4l2_std_id
*std
= arg
;
1018 *std
= V4L2_STD_UNKNOWN
;
1024 v4l2_std_id
*std
= arg
;
1025 if (*std
!= V4L2_STD_UNKNOWN
)
1030 case VIDIOC_ENUMSTD
:
1032 struct v4l2_standard
*std
= arg
;
1033 if (std
->index
!= 0)
1035 std
->id
= V4L2_STD_UNKNOWN
;
1036 strlcpy(std
->name
, "webcam", sizeof(std
->name
));
1040 case VIDIOC_REQBUFS
:
1042 struct v4l2_requestbuffers
*rb
= arg
;
1045 PWC_DEBUG_IOCTL("ioctl(VIDIOC_REQBUFS) count=%d\n",rb
->count
);
1046 if (rb
->type
!= V4L2_BUF_TYPE_VIDEO_CAPTURE
)
1048 if (rb
->memory
!= V4L2_MEMORY_MMAP
)
1051 nbuffers
= rb
->count
;
1054 else if (nbuffers
> pwc_mbufs
)
1055 nbuffers
= pwc_mbufs
;
1056 /* Force to use our # of buffers */
1057 rb
->count
= pwc_mbufs
;
1061 case VIDIOC_QUERYBUF
:
1063 struct v4l2_buffer
*buf
= arg
;
1066 PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYBUF) index=%d\n",buf
->index
);
1067 if (buf
->type
!= V4L2_BUF_TYPE_VIDEO_CAPTURE
) {
1068 PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYBUF) Bad type\n");
1071 if (buf
->memory
!= V4L2_MEMORY_MMAP
) {
1072 PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYBUF) Bad memory type\n");
1076 if (index
< 0 || index
>= pwc_mbufs
) {
1077 PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYBUF) Bad index %d\n", buf
->index
);
1081 memset(buf
, 0, sizeof(struct v4l2_buffer
));
1082 buf
->type
= V4L2_BUF_TYPE_VIDEO_CAPTURE
;
1084 buf
->m
.offset
= index
* pdev
->len_per_image
;
1085 if (pdev
->vpalette
== VIDEO_PALETTE_RAW
)
1086 buf
->bytesused
= pdev
->frame_size
+ sizeof(struct pwc_raw_frame
);
1088 buf
->bytesused
= pdev
->view
.size
;
1089 buf
->field
= V4L2_FIELD_NONE
;
1090 buf
->memory
= V4L2_MEMORY_MMAP
;
1091 //buf->flags = V4L2_BUF_FLAG_MAPPED;
1092 buf
->length
= pdev
->len_per_image
;
1094 PWC_DEBUG_READ("VIDIOC_QUERYBUF: index=%d\n",buf
->index
);
1095 PWC_DEBUG_READ("VIDIOC_QUERYBUF: m.offset=%d\n",buf
->m
.offset
);
1096 PWC_DEBUG_READ("VIDIOC_QUERYBUF: bytesused=%d\n",buf
->bytesused
);
1103 struct v4l2_buffer
*buf
= arg
;
1105 PWC_DEBUG_IOCTL("ioctl(VIDIOC_QBUF) index=%d\n",buf
->index
);
1106 if (buf
->type
!= V4L2_BUF_TYPE_VIDEO_CAPTURE
)
1108 if (buf
->memory
!= V4L2_MEMORY_MMAP
)
1110 if (buf
->index
>= pwc_mbufs
)
1113 buf
->flags
|= V4L2_BUF_FLAG_QUEUED
;
1114 buf
->flags
&= ~V4L2_BUF_FLAG_DONE
;
1121 struct v4l2_buffer
*buf
= arg
;
1124 PWC_DEBUG_IOCTL("ioctl(VIDIOC_DQBUF)\n");
1126 if (buf
->type
!= V4L2_BUF_TYPE_VIDEO_CAPTURE
)
1129 /* Add ourselves to the frame wait-queue.
1131 FIXME: needs auditing for safety.
1132 QUESTION: In what respect? I think that using the
1135 add_wait_queue(&pdev
->frameq
, &wait
);
1136 while (pdev
->full_frames
== NULL
) {
1137 if (pdev
->error_status
) {
1138 remove_wait_queue(&pdev
->frameq
, &wait
);
1139 set_current_state(TASK_RUNNING
);
1140 return -pdev
->error_status
;
1143 if (signal_pending(current
)) {
1144 remove_wait_queue(&pdev
->frameq
, &wait
);
1145 set_current_state(TASK_RUNNING
);
1146 return -ERESTARTSYS
;
1149 set_current_state(TASK_INTERRUPTIBLE
);
1151 remove_wait_queue(&pdev
->frameq
, &wait
);
1152 set_current_state(TASK_RUNNING
);
1154 PWC_DEBUG_IOCTL("VIDIOC_DQBUF: frame ready.\n");
1155 /* Decompress data in pdev->images[pdev->fill_image] */
1156 ret
= pwc_handle_frame(pdev
);
1159 PWC_DEBUG_IOCTL("VIDIOC_DQBUF: after pwc_handle_frame\n");
1161 buf
->index
= pdev
->fill_image
;
1162 if (pdev
->vpalette
== VIDEO_PALETTE_RAW
)
1163 buf
->bytesused
= pdev
->frame_size
+ sizeof(struct pwc_raw_frame
);
1165 buf
->bytesused
= pdev
->view
.size
;
1166 buf
->flags
= V4L2_BUF_FLAG_MAPPED
;
1167 buf
->field
= V4L2_FIELD_NONE
;
1168 do_gettimeofday(&buf
->timestamp
);
1170 buf
->memory
= V4L2_MEMORY_MMAP
;
1171 buf
->m
.offset
= pdev
->fill_image
* pdev
->len_per_image
;
1172 buf
->length
= pdev
->len_per_image
;
1173 pwc_next_image(pdev
);
1175 PWC_DEBUG_IOCTL("VIDIOC_DQBUF: buf->index=%d\n",buf
->index
);
1176 PWC_DEBUG_IOCTL("VIDIOC_DQBUF: buf->length=%d\n",buf
->length
);
1177 PWC_DEBUG_IOCTL("VIDIOC_DQBUF: m.offset=%d\n",buf
->m
.offset
);
1178 PWC_DEBUG_IOCTL("VIDIOC_DQBUF: bytesused=%d\n",buf
->bytesused
);
1179 PWC_DEBUG_IOCTL("VIDIOC_DQBUF: leaving\n");
1184 case VIDIOC_STREAMON
:
1186 /* WARNING: pwc_try_video_mode() called pwc_isoc_init */
1187 pwc_isoc_init(pdev
);
1191 case VIDIOC_STREAMOFF
:
1193 pwc_isoc_cleanup(pdev
);
1197 case VIDIOC_ENUM_FRAMESIZES
:
1199 struct v4l2_frmsizeenum
*fsize
= arg
;
1200 unsigned int i
= 0, index
= fsize
->index
;
1202 if (fsize
->pixel_format
== V4L2_PIX_FMT_YUV420
) {
1203 for (i
= 0; i
< PSZ_MAX
; i
++) {
1204 if (pdev
->image_mask
& (1UL << i
)) {
1206 fsize
->type
= V4L2_FRMSIZE_TYPE_DISCRETE
;
1207 fsize
->discrete
.width
= pwc_image_sizes
[i
].x
;
1208 fsize
->discrete
.height
= pwc_image_sizes
[i
].y
;
1213 } else if (fsize
->index
== 0 &&
1214 ((fsize
->pixel_format
== V4L2_PIX_FMT_PWC1
&& DEVICE_USE_CODEC1(pdev
->type
)) ||
1215 (fsize
->pixel_format
== V4L2_PIX_FMT_PWC2
&& DEVICE_USE_CODEC23(pdev
->type
)))) {
1217 fsize
->type
= V4L2_FRMSIZE_TYPE_DISCRETE
;
1218 fsize
->discrete
.width
= pdev
->abs_max
.x
;
1219 fsize
->discrete
.height
= pdev
->abs_max
.y
;
1225 case VIDIOC_ENUM_FRAMEINTERVALS
:
1227 struct v4l2_frmivalenum
*fival
= arg
;
1231 for (i
= 0; i
< PSZ_MAX
; i
++) {
1232 if (pwc_image_sizes
[i
].x
== fival
->width
&&
1233 pwc_image_sizes
[i
].y
== fival
->height
) {
1239 /* TODO: Support raw format */
1240 if (size
< 0 || fival
->pixel_format
!= V4L2_PIX_FMT_YUV420
) {
1244 i
= pwc_get_fps(pdev
, fival
->index
, size
);
1248 fival
->type
= V4L2_FRMIVAL_TYPE_DISCRETE
;
1249 fival
->discrete
.numerator
= 1;
1250 fival
->discrete
.denominator
= i
;
1256 return pwc_ioctl(pdev
, cmd
, arg
);
1261 /* vim: set cino= formatoptions=croql cindent shiftwidth=8 tabstop=8: */