|
@@ -341,606 +341,554 @@ static int pwc_vidioc_set_fmt(struct pwc_device *pdev, struct v4l2_format *f)
|
|
|
|
|
|
}
|
|
|
|
|
|
-long pwc_video_do_ioctl(struct file *file, unsigned int cmd, void *arg)
|
|
|
+static int pwc_querycap(struct file *file, void *fh, struct v4l2_capability *cap)
|
|
|
{
|
|
|
struct video_device *vdev = video_devdata(file);
|
|
|
- struct pwc_device *pdev;
|
|
|
- DECLARE_WAITQUEUE(wait, current);
|
|
|
-
|
|
|
- if (vdev == NULL)
|
|
|
- return -EFAULT;
|
|
|
- pdev = video_get_drvdata(vdev);
|
|
|
- if (pdev == NULL)
|
|
|
- return -EFAULT;
|
|
|
+ struct pwc_device *pdev = video_drvdata(file);
|
|
|
+
|
|
|
+ strcpy(cap->driver, PWC_NAME);
|
|
|
+ strlcpy(cap->card, vdev->name, sizeof(cap->card));
|
|
|
+ usb_make_path(pdev->udev, cap->bus_info, sizeof(cap->bus_info));
|
|
|
+ cap->version = PWC_VERSION_CODE;
|
|
|
+ cap->capabilities =
|
|
|
+ V4L2_CAP_VIDEO_CAPTURE |
|
|
|
+ V4L2_CAP_STREAMING |
|
|
|
+ V4L2_CAP_READWRITE;
|
|
|
+ return 0;
|
|
|
+}
|
|
|
|
|
|
-#ifdef CONFIG_USB_PWC_DEBUG
|
|
|
- if (PWC_DEBUG_LEVEL_IOCTL & pwc_trace) {
|
|
|
- v4l_printk_ioctl(cmd);
|
|
|
- printk("\n");
|
|
|
- }
|
|
|
-#endif
|
|
|
-
|
|
|
-
|
|
|
- switch (cmd) {
|
|
|
- /* V4L2 Layer */
|
|
|
- case VIDIOC_QUERYCAP:
|
|
|
- {
|
|
|
- struct v4l2_capability *cap = arg;
|
|
|
-
|
|
|
- PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYCAP) This application "\
|
|
|
- "try to use the v4l2 layer\n");
|
|
|
- strcpy(cap->driver,PWC_NAME);
|
|
|
- strlcpy(cap->card, vdev->name, sizeof(cap->card));
|
|
|
- usb_make_path(pdev->udev,cap->bus_info,sizeof(cap->bus_info));
|
|
|
- cap->version = PWC_VERSION_CODE;
|
|
|
- cap->capabilities =
|
|
|
- V4L2_CAP_VIDEO_CAPTURE |
|
|
|
- V4L2_CAP_STREAMING |
|
|
|
- V4L2_CAP_READWRITE;
|
|
|
- return 0;
|
|
|
- }
|
|
|
+static int pwc_enum_input(struct file *file, void *fh, struct v4l2_input *i)
|
|
|
+{
|
|
|
+ if (i->index) /* Only one INPUT is supported */
|
|
|
+ return -EINVAL;
|
|
|
|
|
|
- case VIDIOC_ENUMINPUT:
|
|
|
- {
|
|
|
- struct v4l2_input *i = arg;
|
|
|
+ strcpy(i->name, "usb");
|
|
|
+ return 0;
|
|
|
+}
|
|
|
|
|
|
- if ( i->index ) /* Only one INPUT is supported */
|
|
|
- return -EINVAL;
|
|
|
+static int pwc_g_input(struct file *file, void *fh, unsigned int *i)
|
|
|
+{
|
|
|
+ *i = 0;
|
|
|
+ return 0;
|
|
|
+}
|
|
|
|
|
|
- memset(i, 0, sizeof(struct v4l2_input));
|
|
|
- strcpy(i->name, "usb");
|
|
|
- return 0;
|
|
|
- }
|
|
|
+static int pwc_s_input(struct file *file, void *fh, unsigned int i)
|
|
|
+{
|
|
|
+ return i ? -EINVAL : 0;
|
|
|
+}
|
|
|
|
|
|
- case VIDIOC_G_INPUT:
|
|
|
- {
|
|
|
- int *i = arg;
|
|
|
- *i = 0; /* Only one INPUT is supported */
|
|
|
- return 0;
|
|
|
- }
|
|
|
- case VIDIOC_S_INPUT:
|
|
|
- {
|
|
|
- int *i = arg;
|
|
|
+static int pwc_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *c)
|
|
|
+{
|
|
|
+ int i;
|
|
|
|
|
|
- if ( *i ) { /* Only one INPUT is supported */
|
|
|
- PWC_DEBUG_IOCTL("Only one input source is"\
|
|
|
- " supported with this webcam.\n");
|
|
|
- return -EINVAL;
|
|
|
- }
|
|
|
+ for (i = 0; i < sizeof(pwc_controls) / sizeof(struct v4l2_queryctrl); i++) {
|
|
|
+ if (pwc_controls[i].id == c->id) {
|
|
|
+ PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYCTRL) found\n");
|
|
|
+ memcpy(c, &pwc_controls[i], sizeof(struct v4l2_queryctrl));
|
|
|
return 0;
|
|
|
}
|
|
|
+ }
|
|
|
+ return -EINVAL;
|
|
|
+}
|
|
|
|
|
|
- /* TODO: */
|
|
|
- case VIDIOC_QUERYCTRL:
|
|
|
- {
|
|
|
- struct v4l2_queryctrl *c = arg;
|
|
|
- int i;
|
|
|
-
|
|
|
- PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYCTRL) query id=%d\n", c->id);
|
|
|
- for (i=0; i<sizeof(pwc_controls)/sizeof(struct v4l2_queryctrl); i++) {
|
|
|
- if (pwc_controls[i].id == c->id) {
|
|
|
- PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYCTRL) found\n");
|
|
|
- memcpy(c,&pwc_controls[i],sizeof(struct v4l2_queryctrl));
|
|
|
- return 0;
|
|
|
- }
|
|
|
- }
|
|
|
- PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYCTRL) not found\n");
|
|
|
+static int pwc_g_ctrl(struct file *file, void *fh, struct v4l2_control *c)
|
|
|
+{
|
|
|
+ struct pwc_device *pdev = video_drvdata(file);
|
|
|
+ int ret;
|
|
|
|
|
|
+ switch (c->id) {
|
|
|
+ case V4L2_CID_BRIGHTNESS:
|
|
|
+ c->value = pwc_get_brightness(pdev);
|
|
|
+ if (c->value < 0)
|
|
|
return -EINVAL;
|
|
|
- }
|
|
|
- case VIDIOC_G_CTRL:
|
|
|
- {
|
|
|
- struct v4l2_control *c = arg;
|
|
|
- int ret;
|
|
|
-
|
|
|
- switch (c->id)
|
|
|
- {
|
|
|
- case V4L2_CID_BRIGHTNESS:
|
|
|
- c->value = pwc_get_brightness(pdev);
|
|
|
- if (c->value<0)
|
|
|
- return -EINVAL;
|
|
|
- return 0;
|
|
|
- case V4L2_CID_CONTRAST:
|
|
|
- c->value = pwc_get_contrast(pdev);
|
|
|
- if (c->value<0)
|
|
|
- return -EINVAL;
|
|
|
- return 0;
|
|
|
- case V4L2_CID_SATURATION:
|
|
|
- ret = pwc_get_saturation(pdev, &c->value);
|
|
|
- if (ret<0)
|
|
|
- return -EINVAL;
|
|
|
- return 0;
|
|
|
- case V4L2_CID_GAMMA:
|
|
|
- c->value = pwc_get_gamma(pdev);
|
|
|
- if (c->value<0)
|
|
|
- return -EINVAL;
|
|
|
- return 0;
|
|
|
- case V4L2_CID_RED_BALANCE:
|
|
|
- ret = pwc_get_red_gain(pdev, &c->value);
|
|
|
- if (ret<0)
|
|
|
- return -EINVAL;
|
|
|
- c->value >>= 8;
|
|
|
- return 0;
|
|
|
- case V4L2_CID_BLUE_BALANCE:
|
|
|
- ret = pwc_get_blue_gain(pdev, &c->value);
|
|
|
- if (ret<0)
|
|
|
- return -EINVAL;
|
|
|
- c->value >>= 8;
|
|
|
- return 0;
|
|
|
- case V4L2_CID_AUTO_WHITE_BALANCE:
|
|
|
- ret = pwc_get_awb(pdev);
|
|
|
- if (ret<0)
|
|
|
- return -EINVAL;
|
|
|
- c->value = (ret == PWC_WB_MANUAL)?0:1;
|
|
|
- return 0;
|
|
|
- case V4L2_CID_GAIN:
|
|
|
- ret = pwc_get_agc(pdev, &c->value);
|
|
|
- if (ret<0)
|
|
|
- return -EINVAL;
|
|
|
- c->value >>= 8;
|
|
|
- return 0;
|
|
|
- case V4L2_CID_AUTOGAIN:
|
|
|
- ret = pwc_get_agc(pdev, &c->value);
|
|
|
- if (ret<0)
|
|
|
- return -EINVAL;
|
|
|
- c->value = (c->value < 0)?1:0;
|
|
|
- return 0;
|
|
|
- case V4L2_CID_EXPOSURE:
|
|
|
- ret = pwc_get_shutter_speed(pdev, &c->value);
|
|
|
- if (ret<0)
|
|
|
- return -EINVAL;
|
|
|
- return 0;
|
|
|
- case V4L2_CID_PRIVATE_COLOUR_MODE:
|
|
|
- ret = pwc_get_colour_mode(pdev, &c->value);
|
|
|
- if (ret < 0)
|
|
|
- return -EINVAL;
|
|
|
- return 0;
|
|
|
- case V4L2_CID_PRIVATE_AUTOCONTOUR:
|
|
|
- ret = pwc_get_contour(pdev, &c->value);
|
|
|
- if (ret < 0)
|
|
|
- return -EINVAL;
|
|
|
- c->value=(c->value == -1?1:0);
|
|
|
- return 0;
|
|
|
- case V4L2_CID_PRIVATE_CONTOUR:
|
|
|
- ret = pwc_get_contour(pdev, &c->value);
|
|
|
- if (ret < 0)
|
|
|
- return -EINVAL;
|
|
|
- c->value >>= 10;
|
|
|
- return 0;
|
|
|
- case V4L2_CID_PRIVATE_BACKLIGHT:
|
|
|
- ret = pwc_get_backlight(pdev, &c->value);
|
|
|
- if (ret < 0)
|
|
|
- return -EINVAL;
|
|
|
- return 0;
|
|
|
- case V4L2_CID_PRIVATE_FLICKERLESS:
|
|
|
- ret = pwc_get_flicker(pdev, &c->value);
|
|
|
- if (ret < 0)
|
|
|
- return -EINVAL;
|
|
|
- c->value=(c->value?1:0);
|
|
|
- return 0;
|
|
|
- case V4L2_CID_PRIVATE_NOISE_REDUCTION:
|
|
|
- ret = pwc_get_dynamic_noise(pdev, &c->value);
|
|
|
- if (ret < 0)
|
|
|
- return -EINVAL;
|
|
|
- return 0;
|
|
|
-
|
|
|
- case V4L2_CID_PRIVATE_SAVE_USER:
|
|
|
- case V4L2_CID_PRIVATE_RESTORE_USER:
|
|
|
- case V4L2_CID_PRIVATE_RESTORE_FACTORY:
|
|
|
- return -EINVAL;
|
|
|
- }
|
|
|
+ return 0;
|
|
|
+ case V4L2_CID_CONTRAST:
|
|
|
+ c->value = pwc_get_contrast(pdev);
|
|
|
+ if (c->value < 0)
|
|
|
return -EINVAL;
|
|
|
- }
|
|
|
- case VIDIOC_S_CTRL:
|
|
|
- {
|
|
|
- struct v4l2_control *c = arg;
|
|
|
- int ret;
|
|
|
-
|
|
|
- switch (c->id)
|
|
|
- {
|
|
|
- case V4L2_CID_BRIGHTNESS:
|
|
|
- c->value <<= 9;
|
|
|
- ret = pwc_set_brightness(pdev, c->value);
|
|
|
- if (ret<0)
|
|
|
- return -EINVAL;
|
|
|
- return 0;
|
|
|
- case V4L2_CID_CONTRAST:
|
|
|
- c->value <<= 10;
|
|
|
- ret = pwc_set_contrast(pdev, c->value);
|
|
|
- if (ret<0)
|
|
|
- return -EINVAL;
|
|
|
- return 0;
|
|
|
- case V4L2_CID_SATURATION:
|
|
|
- ret = pwc_set_saturation(pdev, c->value);
|
|
|
- if (ret<0)
|
|
|
- return -EINVAL;
|
|
|
- return 0;
|
|
|
- case V4L2_CID_GAMMA:
|
|
|
- c->value <<= 11;
|
|
|
- ret = pwc_set_gamma(pdev, c->value);
|
|
|
- if (ret<0)
|
|
|
- return -EINVAL;
|
|
|
- return 0;
|
|
|
- case V4L2_CID_RED_BALANCE:
|
|
|
- c->value <<= 8;
|
|
|
- ret = pwc_set_red_gain(pdev, c->value);
|
|
|
- if (ret<0)
|
|
|
- return -EINVAL;
|
|
|
- return 0;
|
|
|
- case V4L2_CID_BLUE_BALANCE:
|
|
|
- c->value <<= 8;
|
|
|
- ret = pwc_set_blue_gain(pdev, c->value);
|
|
|
- if (ret<0)
|
|
|
- return -EINVAL;
|
|
|
- return 0;
|
|
|
- case V4L2_CID_AUTO_WHITE_BALANCE:
|
|
|
- c->value = (c->value == 0)?PWC_WB_MANUAL:PWC_WB_AUTO;
|
|
|
- ret = pwc_set_awb(pdev, c->value);
|
|
|
- if (ret<0)
|
|
|
- return -EINVAL;
|
|
|
- return 0;
|
|
|
- case V4L2_CID_EXPOSURE:
|
|
|
- c->value <<= 8;
|
|
|
- ret = pwc_set_shutter_speed(pdev, c->value?0:1, c->value);
|
|
|
- if (ret<0)
|
|
|
- return -EINVAL;
|
|
|
- return 0;
|
|
|
- case V4L2_CID_AUTOGAIN:
|
|
|
- /* autogain off means nothing without a gain */
|
|
|
- if (c->value == 0)
|
|
|
- return 0;
|
|
|
- ret = pwc_set_agc(pdev, c->value, 0);
|
|
|
- if (ret<0)
|
|
|
- return -EINVAL;
|
|
|
- return 0;
|
|
|
- case V4L2_CID_GAIN:
|
|
|
- c->value <<= 8;
|
|
|
- ret = pwc_set_agc(pdev, 0, c->value);
|
|
|
- if (ret<0)
|
|
|
- return -EINVAL;
|
|
|
- return 0;
|
|
|
- case V4L2_CID_PRIVATE_SAVE_USER:
|
|
|
- if (pwc_save_user(pdev))
|
|
|
- return -EINVAL;
|
|
|
- return 0;
|
|
|
- case V4L2_CID_PRIVATE_RESTORE_USER:
|
|
|
- if (pwc_restore_user(pdev))
|
|
|
- return -EINVAL;
|
|
|
- return 0;
|
|
|
- case V4L2_CID_PRIVATE_RESTORE_FACTORY:
|
|
|
- if (pwc_restore_factory(pdev))
|
|
|
- return -EINVAL;
|
|
|
- return 0;
|
|
|
- case V4L2_CID_PRIVATE_COLOUR_MODE:
|
|
|
- ret = pwc_set_colour_mode(pdev, c->value);
|
|
|
- if (ret < 0)
|
|
|
- return -EINVAL;
|
|
|
- return 0;
|
|
|
- case V4L2_CID_PRIVATE_AUTOCONTOUR:
|
|
|
- c->value=(c->value == 1)?-1:0;
|
|
|
- ret = pwc_set_contour(pdev, c->value);
|
|
|
- if (ret < 0)
|
|
|
- return -EINVAL;
|
|
|
- return 0;
|
|
|
- case V4L2_CID_PRIVATE_CONTOUR:
|
|
|
- c->value <<= 10;
|
|
|
- ret = pwc_set_contour(pdev, c->value);
|
|
|
- if (ret < 0)
|
|
|
- return -EINVAL;
|
|
|
- return 0;
|
|
|
- case V4L2_CID_PRIVATE_BACKLIGHT:
|
|
|
- ret = pwc_set_backlight(pdev, c->value);
|
|
|
- if (ret < 0)
|
|
|
- return -EINVAL;
|
|
|
- return 0;
|
|
|
- case V4L2_CID_PRIVATE_FLICKERLESS:
|
|
|
- ret = pwc_set_flicker(pdev, c->value);
|
|
|
- if (ret < 0)
|
|
|
- return -EINVAL;
|
|
|
- case V4L2_CID_PRIVATE_NOISE_REDUCTION:
|
|
|
- ret = pwc_set_dynamic_noise(pdev, c->value);
|
|
|
- if (ret < 0)
|
|
|
- return -EINVAL;
|
|
|
- return 0;
|
|
|
-
|
|
|
- }
|
|
|
+ return 0;
|
|
|
+ case V4L2_CID_SATURATION:
|
|
|
+ ret = pwc_get_saturation(pdev, &c->value);
|
|
|
+ if (ret < 0)
|
|
|
return -EINVAL;
|
|
|
- }
|
|
|
+ return 0;
|
|
|
+ case V4L2_CID_GAMMA:
|
|
|
+ c->value = pwc_get_gamma(pdev);
|
|
|
+ if (c->value < 0)
|
|
|
+ return -EINVAL;
|
|
|
+ return 0;
|
|
|
+ case V4L2_CID_RED_BALANCE:
|
|
|
+ ret = pwc_get_red_gain(pdev, &c->value);
|
|
|
+ if (ret < 0)
|
|
|
+ return -EINVAL;
|
|
|
+ c->value >>= 8;
|
|
|
+ return 0;
|
|
|
+ case V4L2_CID_BLUE_BALANCE:
|
|
|
+ ret = pwc_get_blue_gain(pdev, &c->value);
|
|
|
+ if (ret < 0)
|
|
|
+ return -EINVAL;
|
|
|
+ c->value >>= 8;
|
|
|
+ return 0;
|
|
|
+ case V4L2_CID_AUTO_WHITE_BALANCE:
|
|
|
+ ret = pwc_get_awb(pdev);
|
|
|
+ if (ret < 0)
|
|
|
+ return -EINVAL;
|
|
|
+ c->value = (ret == PWC_WB_MANUAL) ? 0 : 1;
|
|
|
+ return 0;
|
|
|
+ case V4L2_CID_GAIN:
|
|
|
+ ret = pwc_get_agc(pdev, &c->value);
|
|
|
+ if (ret < 0)
|
|
|
+ return -EINVAL;
|
|
|
+ c->value >>= 8;
|
|
|
+ return 0;
|
|
|
+ case V4L2_CID_AUTOGAIN:
|
|
|
+ ret = pwc_get_agc(pdev, &c->value);
|
|
|
+ if (ret < 0)
|
|
|
+ return -EINVAL;
|
|
|
+ c->value = (c->value < 0) ? 1 : 0;
|
|
|
+ return 0;
|
|
|
+ case V4L2_CID_EXPOSURE:
|
|
|
+ ret = pwc_get_shutter_speed(pdev, &c->value);
|
|
|
+ if (ret < 0)
|
|
|
+ return -EINVAL;
|
|
|
+ return 0;
|
|
|
+ case V4L2_CID_PRIVATE_COLOUR_MODE:
|
|
|
+ ret = pwc_get_colour_mode(pdev, &c->value);
|
|
|
+ if (ret < 0)
|
|
|
+ return -EINVAL;
|
|
|
+ return 0;
|
|
|
+ case V4L2_CID_PRIVATE_AUTOCONTOUR:
|
|
|
+ ret = pwc_get_contour(pdev, &c->value);
|
|
|
+ if (ret < 0)
|
|
|
+ return -EINVAL;
|
|
|
+ c->value = (c->value == -1 ? 1 : 0);
|
|
|
+ return 0;
|
|
|
+ case V4L2_CID_PRIVATE_CONTOUR:
|
|
|
+ ret = pwc_get_contour(pdev, &c->value);
|
|
|
+ if (ret < 0)
|
|
|
+ return -EINVAL;
|
|
|
+ c->value >>= 10;
|
|
|
+ return 0;
|
|
|
+ case V4L2_CID_PRIVATE_BACKLIGHT:
|
|
|
+ ret = pwc_get_backlight(pdev, &c->value);
|
|
|
+ if (ret < 0)
|
|
|
+ return -EINVAL;
|
|
|
+ return 0;
|
|
|
+ case V4L2_CID_PRIVATE_FLICKERLESS:
|
|
|
+ ret = pwc_get_flicker(pdev, &c->value);
|
|
|
+ if (ret < 0)
|
|
|
+ return -EINVAL;
|
|
|
+ c->value = (c->value ? 1 : 0);
|
|
|
+ return 0;
|
|
|
+ case V4L2_CID_PRIVATE_NOISE_REDUCTION:
|
|
|
+ ret = pwc_get_dynamic_noise(pdev, &c->value);
|
|
|
+ if (ret < 0)
|
|
|
+ return -EINVAL;
|
|
|
+ return 0;
|
|
|
|
|
|
- case VIDIOC_ENUM_FMT:
|
|
|
- {
|
|
|
- struct v4l2_fmtdesc *f = arg;
|
|
|
- int index;
|
|
|
-
|
|
|
- if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
|
|
|
- return -EINVAL;
|
|
|
-
|
|
|
- /* We only support two format: the raw format, and YUV */
|
|
|
- index = f->index;
|
|
|
- memset(f,0,sizeof(struct v4l2_fmtdesc));
|
|
|
- f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
|
|
- f->index = index;
|
|
|
- switch(index)
|
|
|
- {
|
|
|
- case 0:
|
|
|
- /* RAW format */
|
|
|
- f->pixelformat = pdev->type<=646?V4L2_PIX_FMT_PWC1:V4L2_PIX_FMT_PWC2;
|
|
|
- f->flags = V4L2_FMT_FLAG_COMPRESSED;
|
|
|
- strlcpy(f->description,"Raw Philips Webcam",sizeof(f->description));
|
|
|
- break;
|
|
|
- case 1:
|
|
|
- f->pixelformat = V4L2_PIX_FMT_YUV420;
|
|
|
- strlcpy(f->description,"4:2:0, planar, Y-Cb-Cr",sizeof(f->description));
|
|
|
- break;
|
|
|
- default:
|
|
|
- return -EINVAL;
|
|
|
- }
|
|
|
- return 0;
|
|
|
- }
|
|
|
+ case V4L2_CID_PRIVATE_SAVE_USER:
|
|
|
+ case V4L2_CID_PRIVATE_RESTORE_USER:
|
|
|
+ case V4L2_CID_PRIVATE_RESTORE_FACTORY:
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+ return -EINVAL;
|
|
|
+}
|
|
|
|
|
|
- case VIDIOC_G_FMT:
|
|
|
- {
|
|
|
- struct v4l2_format *f = arg;
|
|
|
+static int pwc_s_ctrl(struct file *file, void *fh, struct v4l2_control *c)
|
|
|
+{
|
|
|
+ struct pwc_device *pdev = video_drvdata(file);
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ switch (c->id) {
|
|
|
+ case V4L2_CID_BRIGHTNESS:
|
|
|
+ c->value <<= 9;
|
|
|
+ ret = pwc_set_brightness(pdev, c->value);
|
|
|
+ if (ret < 0)
|
|
|
+ return -EINVAL;
|
|
|
+ return 0;
|
|
|
+ case V4L2_CID_CONTRAST:
|
|
|
+ c->value <<= 10;
|
|
|
+ ret = pwc_set_contrast(pdev, c->value);
|
|
|
+ if (ret < 0)
|
|
|
+ return -EINVAL;
|
|
|
+ return 0;
|
|
|
+ case V4L2_CID_SATURATION:
|
|
|
+ ret = pwc_set_saturation(pdev, c->value);
|
|
|
+ if (ret < 0)
|
|
|
+ return -EINVAL;
|
|
|
+ return 0;
|
|
|
+ case V4L2_CID_GAMMA:
|
|
|
+ c->value <<= 11;
|
|
|
+ ret = pwc_set_gamma(pdev, c->value);
|
|
|
+ if (ret < 0)
|
|
|
+ return -EINVAL;
|
|
|
+ return 0;
|
|
|
+ case V4L2_CID_RED_BALANCE:
|
|
|
+ c->value <<= 8;
|
|
|
+ ret = pwc_set_red_gain(pdev, c->value);
|
|
|
+ if (ret < 0)
|
|
|
+ return -EINVAL;
|
|
|
+ return 0;
|
|
|
+ case V4L2_CID_BLUE_BALANCE:
|
|
|
+ c->value <<= 8;
|
|
|
+ ret = pwc_set_blue_gain(pdev, c->value);
|
|
|
+ if (ret < 0)
|
|
|
+ return -EINVAL;
|
|
|
+ return 0;
|
|
|
+ case V4L2_CID_AUTO_WHITE_BALANCE:
|
|
|
+ c->value = (c->value == 0) ? PWC_WB_MANUAL : PWC_WB_AUTO;
|
|
|
+ ret = pwc_set_awb(pdev, c->value);
|
|
|
+ if (ret < 0)
|
|
|
+ return -EINVAL;
|
|
|
+ return 0;
|
|
|
+ case V4L2_CID_EXPOSURE:
|
|
|
+ c->value <<= 8;
|
|
|
+ ret = pwc_set_shutter_speed(pdev, c->value ? 0 : 1, c->value);
|
|
|
+ if (ret < 0)
|
|
|
+ return -EINVAL;
|
|
|
+ return 0;
|
|
|
+ case V4L2_CID_AUTOGAIN:
|
|
|
+ /* autogain off means nothing without a gain */
|
|
|
+ if (c->value == 0)
|
|
|
+ return 0;
|
|
|
+ ret = pwc_set_agc(pdev, c->value, 0);
|
|
|
+ if (ret < 0)
|
|
|
+ return -EINVAL;
|
|
|
+ return 0;
|
|
|
+ case V4L2_CID_GAIN:
|
|
|
+ c->value <<= 8;
|
|
|
+ ret = pwc_set_agc(pdev, 0, c->value);
|
|
|
+ if (ret < 0)
|
|
|
+ return -EINVAL;
|
|
|
+ return 0;
|
|
|
+ case V4L2_CID_PRIVATE_SAVE_USER:
|
|
|
+ if (pwc_save_user(pdev))
|
|
|
+ return -EINVAL;
|
|
|
+ return 0;
|
|
|
+ case V4L2_CID_PRIVATE_RESTORE_USER:
|
|
|
+ if (pwc_restore_user(pdev))
|
|
|
+ return -EINVAL;
|
|
|
+ return 0;
|
|
|
+ case V4L2_CID_PRIVATE_RESTORE_FACTORY:
|
|
|
+ if (pwc_restore_factory(pdev))
|
|
|
+ return -EINVAL;
|
|
|
+ return 0;
|
|
|
+ case V4L2_CID_PRIVATE_COLOUR_MODE:
|
|
|
+ ret = pwc_set_colour_mode(pdev, c->value);
|
|
|
+ if (ret < 0)
|
|
|
+ return -EINVAL;
|
|
|
+ return 0;
|
|
|
+ case V4L2_CID_PRIVATE_AUTOCONTOUR:
|
|
|
+ c->value = (c->value == 1) ? -1 : 0;
|
|
|
+ ret = pwc_set_contour(pdev, c->value);
|
|
|
+ if (ret < 0)
|
|
|
+ return -EINVAL;
|
|
|
+ return 0;
|
|
|
+ case V4L2_CID_PRIVATE_CONTOUR:
|
|
|
+ c->value <<= 10;
|
|
|
+ ret = pwc_set_contour(pdev, c->value);
|
|
|
+ if (ret < 0)
|
|
|
+ return -EINVAL;
|
|
|
+ return 0;
|
|
|
+ case V4L2_CID_PRIVATE_BACKLIGHT:
|
|
|
+ ret = pwc_set_backlight(pdev, c->value);
|
|
|
+ if (ret < 0)
|
|
|
+ return -EINVAL;
|
|
|
+ return 0;
|
|
|
+ case V4L2_CID_PRIVATE_FLICKERLESS:
|
|
|
+ ret = pwc_set_flicker(pdev, c->value);
|
|
|
+ if (ret < 0)
|
|
|
+ return -EINVAL;
|
|
|
+ case V4L2_CID_PRIVATE_NOISE_REDUCTION:
|
|
|
+ ret = pwc_set_dynamic_noise(pdev, c->value);
|
|
|
+ if (ret < 0)
|
|
|
+ return -EINVAL;
|
|
|
+ return 0;
|
|
|
|
|
|
- PWC_DEBUG_IOCTL("ioctl(VIDIOC_G_FMT) return size %dx%d\n",pdev->image.x,pdev->image.y);
|
|
|
- if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
|
|
|
- return -EINVAL;
|
|
|
+ }
|
|
|
+ return -EINVAL;
|
|
|
+}
|
|
|
|
|
|
- pwc_vidioc_fill_fmt(pdev, f);
|
|
|
+static int pwc_enum_fmt_vid_cap(struct file *file, void *fh, struct v4l2_fmtdesc *f)
|
|
|
+{
|
|
|
+ struct pwc_device *pdev = video_drvdata(file);
|
|
|
+
|
|
|
+ /* We only support two format: the raw format, and YUV */
|
|
|
+ switch (f->index) {
|
|
|
+ case 0:
|
|
|
+ /* RAW format */
|
|
|
+ f->pixelformat = pdev->type <= 646 ? V4L2_PIX_FMT_PWC1 : V4L2_PIX_FMT_PWC2;
|
|
|
+ f->flags = V4L2_FMT_FLAG_COMPRESSED;
|
|
|
+ strlcpy(f->description, "Raw Philips Webcam", sizeof(f->description));
|
|
|
+ break;
|
|
|
+ case 1:
|
|
|
+ f->pixelformat = V4L2_PIX_FMT_YUV420;
|
|
|
+ strlcpy(f->description, "4:2:0, planar, Y-Cb-Cr", sizeof(f->description));
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
+}
|
|
|
|
|
|
- return 0;
|
|
|
- }
|
|
|
+static int pwc_g_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f)
|
|
|
+{
|
|
|
+ struct pwc_device *pdev = video_drvdata(file);
|
|
|
|
|
|
- case VIDIOC_TRY_FMT:
|
|
|
- return pwc_vidioc_try_fmt(pdev, arg);
|
|
|
+ PWC_DEBUG_IOCTL("ioctl(VIDIOC_G_FMT) return size %dx%d\n",
|
|
|
+ pdev->image.x, pdev->image.y);
|
|
|
+ pwc_vidioc_fill_fmt(pdev, f);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
|
|
|
- case VIDIOC_S_FMT:
|
|
|
- return pwc_vidioc_set_fmt(pdev, arg);
|
|
|
+static int pwc_try_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f)
|
|
|
+{
|
|
|
+ struct pwc_device *pdev = video_drvdata(file);
|
|
|
|
|
|
- case VIDIOC_G_STD:
|
|
|
- {
|
|
|
- v4l2_std_id *std = arg;
|
|
|
- *std = V4L2_STD_UNKNOWN;
|
|
|
- return 0;
|
|
|
- }
|
|
|
+ return pwc_vidioc_try_fmt(pdev, f);
|
|
|
+}
|
|
|
|
|
|
- case VIDIOC_S_STD:
|
|
|
- {
|
|
|
- v4l2_std_id *std = arg;
|
|
|
- if (*std != V4L2_STD_UNKNOWN)
|
|
|
- return -EINVAL;
|
|
|
- return 0;
|
|
|
- }
|
|
|
+static int pwc_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f)
|
|
|
+{
|
|
|
+ struct pwc_device *pdev = video_drvdata(file);
|
|
|
|
|
|
- case VIDIOC_ENUMSTD:
|
|
|
- {
|
|
|
- struct v4l2_standard *std = arg;
|
|
|
- if (std->index != 0)
|
|
|
- return -EINVAL;
|
|
|
- std->id = V4L2_STD_UNKNOWN;
|
|
|
- strlcpy(std->name, "webcam", sizeof(std->name));
|
|
|
- return 0;
|
|
|
- }
|
|
|
+ return pwc_vidioc_set_fmt(pdev, f);
|
|
|
+}
|
|
|
|
|
|
- case VIDIOC_REQBUFS:
|
|
|
- {
|
|
|
- struct v4l2_requestbuffers *rb = arg;
|
|
|
- int nbuffers;
|
|
|
+static int pwc_reqbufs(struct file *file, void *fh, struct v4l2_requestbuffers *rb)
|
|
|
+{
|
|
|
+ int nbuffers;
|
|
|
|
|
|
- PWC_DEBUG_IOCTL("ioctl(VIDIOC_REQBUFS) count=%d\n",rb->count);
|
|
|
- if (rb->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
|
|
|
- return -EINVAL;
|
|
|
- if (rb->memory != V4L2_MEMORY_MMAP)
|
|
|
- return -EINVAL;
|
|
|
+ PWC_DEBUG_IOCTL("ioctl(VIDIOC_REQBUFS) count=%d\n", rb->count);
|
|
|
+ if (rb->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
|
|
|
+ return -EINVAL;
|
|
|
+ if (rb->memory != V4L2_MEMORY_MMAP)
|
|
|
+ return -EINVAL;
|
|
|
|
|
|
- nbuffers = rb->count;
|
|
|
- if (nbuffers < 2)
|
|
|
- nbuffers = 2;
|
|
|
- else if (nbuffers > pwc_mbufs)
|
|
|
- nbuffers = pwc_mbufs;
|
|
|
- /* Force to use our # of buffers */
|
|
|
- rb->count = pwc_mbufs;
|
|
|
- return 0;
|
|
|
- }
|
|
|
+ nbuffers = rb->count;
|
|
|
+ if (nbuffers < 2)
|
|
|
+ nbuffers = 2;
|
|
|
+ else if (nbuffers > pwc_mbufs)
|
|
|
+ nbuffers = pwc_mbufs;
|
|
|
+ /* Force to use our # of buffers */
|
|
|
+ rb->count = pwc_mbufs;
|
|
|
+ return 0;
|
|
|
+}
|
|
|
|
|
|
- case VIDIOC_QUERYBUF:
|
|
|
- {
|
|
|
- struct v4l2_buffer *buf = arg;
|
|
|
- int index;
|
|
|
+static int pwc_querybuf(struct file *file, void *fh, struct v4l2_buffer *buf)
|
|
|
+{
|
|
|
+ struct pwc_device *pdev = video_drvdata(file);
|
|
|
+ int index;
|
|
|
|
|
|
- PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYBUF) index=%d\n",buf->index);
|
|
|
- if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
|
|
|
- PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYBUF) Bad type\n");
|
|
|
- return -EINVAL;
|
|
|
- }
|
|
|
- if (buf->memory != V4L2_MEMORY_MMAP) {
|
|
|
- PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYBUF) Bad memory type\n");
|
|
|
- return -EINVAL;
|
|
|
- }
|
|
|
- index = buf->index;
|
|
|
- if (index < 0 || index >= pwc_mbufs) {
|
|
|
- PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYBUF) Bad index %d\n", buf->index);
|
|
|
- return -EINVAL;
|
|
|
- }
|
|
|
+ PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYBUF) index=%d\n", buf->index);
|
|
|
+ if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
|
|
|
+ PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYBUF) Bad type\n");
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+ index = buf->index;
|
|
|
+ if (index < 0 || index >= pwc_mbufs) {
|
|
|
+ PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYBUF) Bad index %d\n", buf->index);
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
|
|
|
- memset(buf, 0, sizeof(struct v4l2_buffer));
|
|
|
- buf->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
|
|
- buf->index = index;
|
|
|
- buf->m.offset = index * pdev->len_per_image;
|
|
|
- if (pdev->pixfmt != V4L2_PIX_FMT_YUV420)
|
|
|
- buf->bytesused = pdev->frame_size + sizeof(struct pwc_raw_frame);
|
|
|
- else
|
|
|
- buf->bytesused = pdev->view.size;
|
|
|
- buf->field = V4L2_FIELD_NONE;
|
|
|
- buf->memory = V4L2_MEMORY_MMAP;
|
|
|
- //buf->flags = V4L2_BUF_FLAG_MAPPED;
|
|
|
- buf->length = pdev->len_per_image;
|
|
|
-
|
|
|
- PWC_DEBUG_READ("VIDIOC_QUERYBUF: index=%d\n",buf->index);
|
|
|
- PWC_DEBUG_READ("VIDIOC_QUERYBUF: m.offset=%d\n",buf->m.offset);
|
|
|
- PWC_DEBUG_READ("VIDIOC_QUERYBUF: bytesused=%d\n",buf->bytesused);
|
|
|
+ buf->m.offset = index * pdev->len_per_image;
|
|
|
+ if (pdev->pixfmt != V4L2_PIX_FMT_YUV420)
|
|
|
+ buf->bytesused = pdev->frame_size + sizeof(struct pwc_raw_frame);
|
|
|
+ else
|
|
|
+ buf->bytesused = pdev->view.size;
|
|
|
+ buf->field = V4L2_FIELD_NONE;
|
|
|
+ buf->memory = V4L2_MEMORY_MMAP;
|
|
|
+ /*buf->flags = V4L2_BUF_FLAG_MAPPED;*/
|
|
|
+ buf->length = pdev->len_per_image;
|
|
|
|
|
|
- return 0;
|
|
|
- }
|
|
|
+ PWC_DEBUG_READ("VIDIOC_QUERYBUF: index=%d\n", buf->index);
|
|
|
+ PWC_DEBUG_READ("VIDIOC_QUERYBUF: m.offset=%d\n", buf->m.offset);
|
|
|
+ PWC_DEBUG_READ("VIDIOC_QUERYBUF: bytesused=%d\n", buf->bytesused);
|
|
|
|
|
|
- case VIDIOC_QBUF:
|
|
|
- {
|
|
|
- struct v4l2_buffer *buf = arg;
|
|
|
+ return 0;
|
|
|
+}
|
|
|
|
|
|
- PWC_DEBUG_IOCTL("ioctl(VIDIOC_QBUF) index=%d\n",buf->index);
|
|
|
- if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
|
|
|
- return -EINVAL;
|
|
|
- if (buf->memory != V4L2_MEMORY_MMAP)
|
|
|
- return -EINVAL;
|
|
|
- if (buf->index >= pwc_mbufs)
|
|
|
- return -EINVAL;
|
|
|
+static int pwc_qbuf(struct file *file, void *fh, struct v4l2_buffer *buf)
|
|
|
+{
|
|
|
+ PWC_DEBUG_IOCTL("ioctl(VIDIOC_QBUF) index=%d\n", buf->index);
|
|
|
+ if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
|
|
|
+ return -EINVAL;
|
|
|
+ if (buf->memory != V4L2_MEMORY_MMAP)
|
|
|
+ return -EINVAL;
|
|
|
+ if (buf->index >= pwc_mbufs)
|
|
|
+ return -EINVAL;
|
|
|
|
|
|
- buf->flags |= V4L2_BUF_FLAG_QUEUED;
|
|
|
- buf->flags &= ~V4L2_BUF_FLAG_DONE;
|
|
|
+ buf->flags |= V4L2_BUF_FLAG_QUEUED;
|
|
|
+ buf->flags &= ~V4L2_BUF_FLAG_DONE;
|
|
|
|
|
|
- return 0;
|
|
|
- }
|
|
|
+ return 0;
|
|
|
+}
|
|
|
|
|
|
- case VIDIOC_DQBUF:
|
|
|
- {
|
|
|
- struct v4l2_buffer *buf = arg;
|
|
|
- int ret;
|
|
|
+static int pwc_dqbuf(struct file *file, void *fh, struct v4l2_buffer *buf)
|
|
|
+{
|
|
|
+ DECLARE_WAITQUEUE(wait, current);
|
|
|
+ struct pwc_device *pdev = video_drvdata(file);
|
|
|
+ int ret;
|
|
|
|
|
|
- PWC_DEBUG_IOCTL("ioctl(VIDIOC_DQBUF)\n");
|
|
|
+ PWC_DEBUG_IOCTL("ioctl(VIDIOC_DQBUF)\n");
|
|
|
|
|
|
- if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
|
|
|
- return -EINVAL;
|
|
|
+ if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
|
|
|
+ return -EINVAL;
|
|
|
|
|
|
- /* Add ourselves to the frame wait-queue.
|
|
|
-
|
|
|
- FIXME: needs auditing for safety.
|
|
|
- QUESTION: In what respect? I think that using the
|
|
|
- frameq is safe now.
|
|
|
- */
|
|
|
- add_wait_queue(&pdev->frameq, &wait);
|
|
|
- while (pdev->full_frames == NULL) {
|
|
|
- if (pdev->error_status) {
|
|
|
- remove_wait_queue(&pdev->frameq, &wait);
|
|
|
- set_current_state(TASK_RUNNING);
|
|
|
- return -pdev->error_status;
|
|
|
- }
|
|
|
+ add_wait_queue(&pdev->frameq, &wait);
|
|
|
+ while (pdev->full_frames == NULL) {
|
|
|
+ if (pdev->error_status) {
|
|
|
+ remove_wait_queue(&pdev->frameq, &wait);
|
|
|
+ set_current_state(TASK_RUNNING);
|
|
|
+ return -pdev->error_status;
|
|
|
+ }
|
|
|
|
|
|
- if (signal_pending(current)) {
|
|
|
- remove_wait_queue(&pdev->frameq, &wait);
|
|
|
- set_current_state(TASK_RUNNING);
|
|
|
- return -ERESTARTSYS;
|
|
|
- }
|
|
|
- mutex_unlock(&pdev->modlock);
|
|
|
- schedule();
|
|
|
- set_current_state(TASK_INTERRUPTIBLE);
|
|
|
- mutex_lock(&pdev->modlock);
|
|
|
- }
|
|
|
+ if (signal_pending(current)) {
|
|
|
remove_wait_queue(&pdev->frameq, &wait);
|
|
|
set_current_state(TASK_RUNNING);
|
|
|
+ return -ERESTARTSYS;
|
|
|
+ }
|
|
|
+ mutex_unlock(&pdev->modlock);
|
|
|
+ schedule();
|
|
|
+ set_current_state(TASK_INTERRUPTIBLE);
|
|
|
+ mutex_lock(&pdev->modlock);
|
|
|
+ }
|
|
|
+ remove_wait_queue(&pdev->frameq, &wait);
|
|
|
+ set_current_state(TASK_RUNNING);
|
|
|
|
|
|
- PWC_DEBUG_IOCTL("VIDIOC_DQBUF: frame ready.\n");
|
|
|
- /* Decompress data in pdev->images[pdev->fill_image] */
|
|
|
- ret = pwc_handle_frame(pdev);
|
|
|
- if (ret)
|
|
|
- return -EFAULT;
|
|
|
- PWC_DEBUG_IOCTL("VIDIOC_DQBUF: after pwc_handle_frame\n");
|
|
|
-
|
|
|
- buf->index = pdev->fill_image;
|
|
|
- if (pdev->pixfmt != V4L2_PIX_FMT_YUV420)
|
|
|
- buf->bytesused = pdev->frame_size + sizeof(struct pwc_raw_frame);
|
|
|
- else
|
|
|
- buf->bytesused = pdev->view.size;
|
|
|
- buf->flags = V4L2_BUF_FLAG_MAPPED;
|
|
|
- buf->field = V4L2_FIELD_NONE;
|
|
|
- do_gettimeofday(&buf->timestamp);
|
|
|
- buf->sequence = 0;
|
|
|
- buf->memory = V4L2_MEMORY_MMAP;
|
|
|
- buf->m.offset = pdev->fill_image * pdev->len_per_image;
|
|
|
- buf->length = pdev->len_per_image;
|
|
|
- pwc_next_image(pdev);
|
|
|
-
|
|
|
- PWC_DEBUG_IOCTL("VIDIOC_DQBUF: buf->index=%d\n",buf->index);
|
|
|
- PWC_DEBUG_IOCTL("VIDIOC_DQBUF: buf->length=%d\n",buf->length);
|
|
|
- PWC_DEBUG_IOCTL("VIDIOC_DQBUF: m.offset=%d\n",buf->m.offset);
|
|
|
- PWC_DEBUG_IOCTL("VIDIOC_DQBUF: bytesused=%d\n",buf->bytesused);
|
|
|
- PWC_DEBUG_IOCTL("VIDIOC_DQBUF: leaving\n");
|
|
|
- return 0;
|
|
|
+ PWC_DEBUG_IOCTL("VIDIOC_DQBUF: frame ready.\n");
|
|
|
+ /* Decompress data in pdev->images[pdev->fill_image] */
|
|
|
+ ret = pwc_handle_frame(pdev);
|
|
|
+ if (ret)
|
|
|
+ return -EFAULT;
|
|
|
+ PWC_DEBUG_IOCTL("VIDIOC_DQBUF: after pwc_handle_frame\n");
|
|
|
+
|
|
|
+ buf->index = pdev->fill_image;
|
|
|
+ if (pdev->pixfmt != V4L2_PIX_FMT_YUV420)
|
|
|
+ buf->bytesused = pdev->frame_size + sizeof(struct pwc_raw_frame);
|
|
|
+ else
|
|
|
+ buf->bytesused = pdev->view.size;
|
|
|
+ buf->flags = V4L2_BUF_FLAG_MAPPED;
|
|
|
+ buf->field = V4L2_FIELD_NONE;
|
|
|
+ do_gettimeofday(&buf->timestamp);
|
|
|
+ buf->sequence = 0;
|
|
|
+ buf->memory = V4L2_MEMORY_MMAP;
|
|
|
+ buf->m.offset = pdev->fill_image * pdev->len_per_image;
|
|
|
+ buf->length = pdev->len_per_image;
|
|
|
+ pwc_next_image(pdev);
|
|
|
+
|
|
|
+ PWC_DEBUG_IOCTL("VIDIOC_DQBUF: buf->index=%d\n", buf->index);
|
|
|
+ PWC_DEBUG_IOCTL("VIDIOC_DQBUF: buf->length=%d\n", buf->length);
|
|
|
+ PWC_DEBUG_IOCTL("VIDIOC_DQBUF: m.offset=%d\n", buf->m.offset);
|
|
|
+ PWC_DEBUG_IOCTL("VIDIOC_DQBUF: bytesused=%d\n", buf->bytesused);
|
|
|
+ PWC_DEBUG_IOCTL("VIDIOC_DQBUF: leaving\n");
|
|
|
+ return 0;
|
|
|
|
|
|
- }
|
|
|
+}
|
|
|
|
|
|
- case VIDIOC_STREAMON:
|
|
|
- {
|
|
|
- return pwc_isoc_init(pdev);
|
|
|
- }
|
|
|
+static int pwc_streamon(struct file *file, void *fh, enum v4l2_buf_type i)
|
|
|
+{
|
|
|
+ struct pwc_device *pdev = video_drvdata(file);
|
|
|
|
|
|
- case VIDIOC_STREAMOFF:
|
|
|
- {
|
|
|
- pwc_isoc_cleanup(pdev);
|
|
|
- return 0;
|
|
|
- }
|
|
|
+ return pwc_isoc_init(pdev);
|
|
|
+}
|
|
|
|
|
|
- case VIDIOC_ENUM_FRAMESIZES:
|
|
|
- {
|
|
|
- struct v4l2_frmsizeenum *fsize = arg;
|
|
|
- unsigned int i = 0, index = fsize->index;
|
|
|
-
|
|
|
- if (fsize->pixel_format == V4L2_PIX_FMT_YUV420) {
|
|
|
- for (i = 0; i < PSZ_MAX; i++) {
|
|
|
- if (pdev->image_mask & (1UL << i)) {
|
|
|
- if (!index--) {
|
|
|
- fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
|
|
|
- fsize->discrete.width = pwc_image_sizes[i].x;
|
|
|
- fsize->discrete.height = pwc_image_sizes[i].y;
|
|
|
- return 0;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- } else if (fsize->index == 0 &&
|
|
|
- ((fsize->pixel_format == V4L2_PIX_FMT_PWC1 && DEVICE_USE_CODEC1(pdev->type)) ||
|
|
|
- (fsize->pixel_format == V4L2_PIX_FMT_PWC2 && DEVICE_USE_CODEC23(pdev->type)))) {
|
|
|
-
|
|
|
- fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
|
|
|
- fsize->discrete.width = pdev->abs_max.x;
|
|
|
- fsize->discrete.height = pdev->abs_max.y;
|
|
|
- return 0;
|
|
|
- }
|
|
|
- return -EINVAL;
|
|
|
- }
|
|
|
+static int pwc_streamoff(struct file *file, void *fh, enum v4l2_buf_type i)
|
|
|
+{
|
|
|
+ struct pwc_device *pdev = video_drvdata(file);
|
|
|
|
|
|
- case VIDIOC_ENUM_FRAMEINTERVALS:
|
|
|
- {
|
|
|
- struct v4l2_frmivalenum *fival = arg;
|
|
|
- int size = -1;
|
|
|
- unsigned int i;
|
|
|
-
|
|
|
- for (i = 0; i < PSZ_MAX; i++) {
|
|
|
- if (pwc_image_sizes[i].x == fival->width &&
|
|
|
- pwc_image_sizes[i].y == fival->height) {
|
|
|
- size = i;
|
|
|
- break;
|
|
|
+ pwc_isoc_cleanup(pdev);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static int pwc_enum_framesizes(struct file *file, void *fh,
|
|
|
+ struct v4l2_frmsizeenum *fsize)
|
|
|
+{
|
|
|
+ struct pwc_device *pdev = video_drvdata(file);
|
|
|
+ unsigned int i = 0, index = fsize->index;
|
|
|
+
|
|
|
+ if (fsize->pixel_format == V4L2_PIX_FMT_YUV420) {
|
|
|
+ for (i = 0; i < PSZ_MAX; i++) {
|
|
|
+ if (pdev->image_mask & (1UL << i)) {
|
|
|
+ if (!index--) {
|
|
|
+ fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
|
|
|
+ fsize->discrete.width = pwc_image_sizes[i].x;
|
|
|
+ fsize->discrete.height = pwc_image_sizes[i].y;
|
|
|
+ return 0;
|
|
|
}
|
|
|
}
|
|
|
+ }
|
|
|
+ } else if (fsize->index == 0 &&
|
|
|
+ ((fsize->pixel_format == V4L2_PIX_FMT_PWC1 && DEVICE_USE_CODEC1(pdev->type)) ||
|
|
|
+ (fsize->pixel_format == V4L2_PIX_FMT_PWC2 && DEVICE_USE_CODEC23(pdev->type)))) {
|
|
|
+
|
|
|
+ fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
|
|
|
+ fsize->discrete.width = pdev->abs_max.x;
|
|
|
+ fsize->discrete.height = pdev->abs_max.y;
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ return -EINVAL;
|
|
|
+}
|
|
|
|
|
|
- /* TODO: Support raw format */
|
|
|
- if (size < 0 || fival->pixel_format != V4L2_PIX_FMT_YUV420) {
|
|
|
- return -EINVAL;
|
|
|
- }
|
|
|
+static int pwc_enum_frameintervals(struct file *file, void *fh,
|
|
|
+ struct v4l2_frmivalenum *fival)
|
|
|
+{
|
|
|
+ struct pwc_device *pdev = video_drvdata(file);
|
|
|
+ int size = -1;
|
|
|
+ unsigned int i;
|
|
|
+
|
|
|
+ for (i = 0; i < PSZ_MAX; i++) {
|
|
|
+ if (pwc_image_sizes[i].x == fival->width &&
|
|
|
+ pwc_image_sizes[i].y == fival->height) {
|
|
|
+ size = i;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- i = pwc_get_fps(pdev, fival->index, size);
|
|
|
- if (!i)
|
|
|
- return -EINVAL;
|
|
|
+ /* TODO: Support raw format */
|
|
|
+ if (size < 0 || fival->pixel_format != V4L2_PIX_FMT_YUV420)
|
|
|
+ return -EINVAL;
|
|
|
|
|
|
- fival->type = V4L2_FRMIVAL_TYPE_DISCRETE;
|
|
|
- fival->discrete.numerator = 1;
|
|
|
- fival->discrete.denominator = i;
|
|
|
+ i = pwc_get_fps(pdev, fival->index, size);
|
|
|
+ if (!i)
|
|
|
+ return -EINVAL;
|
|
|
|
|
|
- return 0;
|
|
|
- }
|
|
|
+ fival->type = V4L2_FRMIVAL_TYPE_DISCRETE;
|
|
|
+ fival->discrete.numerator = 1;
|
|
|
+ fival->discrete.denominator = i;
|
|
|
|
|
|
- default:
|
|
|
- return pwc_ioctl(pdev, cmd, arg);
|
|
|
- } /* ..switch */
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+static long pwc_default(struct file *file, void *fh, int cmd, void *arg)
|
|
|
+{
|
|
|
+ struct pwc_device *pdev = video_drvdata(file);
|
|
|
+
|
|
|
+ return pwc_ioctl(pdev, cmd, arg);
|
|
|
+}
|
|
|
+
|
|
|
+const struct v4l2_ioctl_ops pwc_ioctl_ops = {
|
|
|
+ .vidioc_querycap = pwc_querycap,
|
|
|
+ .vidioc_enum_input = pwc_enum_input,
|
|
|
+ .vidioc_g_input = pwc_g_input,
|
|
|
+ .vidioc_s_input = pwc_s_input,
|
|
|
+ .vidioc_enum_fmt_vid_cap = pwc_enum_fmt_vid_cap,
|
|
|
+ .vidioc_g_fmt_vid_cap = pwc_g_fmt_vid_cap,
|
|
|
+ .vidioc_s_fmt_vid_cap = pwc_s_fmt_vid_cap,
|
|
|
+ .vidioc_try_fmt_vid_cap = pwc_try_fmt_vid_cap,
|
|
|
+ .vidioc_queryctrl = pwc_queryctrl,
|
|
|
+ .vidioc_g_ctrl = pwc_g_ctrl,
|
|
|
+ .vidioc_s_ctrl = pwc_s_ctrl,
|
|
|
+ .vidioc_reqbufs = pwc_reqbufs,
|
|
|
+ .vidioc_querybuf = pwc_querybuf,
|
|
|
+ .vidioc_qbuf = pwc_qbuf,
|
|
|
+ .vidioc_dqbuf = pwc_dqbuf,
|
|
|
+ .vidioc_streamon = pwc_streamon,
|
|
|
+ .vidioc_streamoff = pwc_streamoff,
|
|
|
+ .vidioc_enum_framesizes = pwc_enum_framesizes,
|
|
|
+ .vidioc_enum_frameintervals = pwc_enum_frameintervals,
|
|
|
+ .vidioc_default = pwc_default,
|
|
|
+};
|
|
|
+
|
|
|
+
|
|
|
/* vim: set cino= formatoptions=croql cindent shiftwidth=8 tabstop=8: */
|