Commit afa38521 authored by Hans Verkuil's avatar Hans Verkuil Committed by Mauro Carvalho Chehab

[media] pwc: convert to video_ioctl2

Tested with a Logitech QuickCam Pro 4000.
Signed-off-by: default avatarHans Verkuil <hverkuil@xs4all.nl>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent b577f962
...@@ -151,8 +151,6 @@ static int pwc_video_close(struct file *file); ...@@ -151,8 +151,6 @@ static int pwc_video_close(struct file *file);
static ssize_t pwc_video_read(struct file *file, char __user *buf, static ssize_t pwc_video_read(struct file *file, char __user *buf,
size_t count, loff_t *ppos); size_t count, loff_t *ppos);
static unsigned int pwc_video_poll(struct file *file, poll_table *wait); static unsigned int pwc_video_poll(struct file *file, poll_table *wait);
static long pwc_video_ioctl(struct file *file,
unsigned int ioctlnr, unsigned long arg);
static int pwc_video_mmap(struct file *file, struct vm_area_struct *vma); static int pwc_video_mmap(struct file *file, struct vm_area_struct *vma);
static const struct v4l2_file_operations pwc_fops = { static const struct v4l2_file_operations pwc_fops = {
...@@ -162,7 +160,7 @@ static const struct v4l2_file_operations pwc_fops = { ...@@ -162,7 +160,7 @@ static const struct v4l2_file_operations pwc_fops = {
.read = pwc_video_read, .read = pwc_video_read,
.poll = pwc_video_poll, .poll = pwc_video_poll,
.mmap = pwc_video_mmap, .mmap = pwc_video_mmap,
.unlocked_ioctl = pwc_video_ioctl, .unlocked_ioctl = video_ioctl2,
}; };
static struct video_device pwc_template = { static struct video_device pwc_template = {
.name = "Philips Webcam", /* Filled in later */ .name = "Philips Webcam", /* Filled in later */
...@@ -1378,23 +1376,6 @@ static unsigned int pwc_video_poll(struct file *file, poll_table *wait) ...@@ -1378,23 +1376,6 @@ static unsigned int pwc_video_poll(struct file *file, poll_table *wait)
return 0; return 0;
} }
static long pwc_video_ioctl(struct file *file,
unsigned int cmd, unsigned long arg)
{
struct video_device *vdev = file->private_data;
struct pwc_device *pdev;
long r = -ENODEV;
if (!vdev)
goto out;
pdev = video_get_drvdata(vdev);
if (!pdev->unplugged)
r = video_usercopy(file, cmd, arg, pwc_video_do_ioctl);
out:
return r;
}
static int pwc_video_mmap(struct file *file, struct vm_area_struct *vma) static int pwc_video_mmap(struct file *file, struct vm_area_struct *vma)
{ {
struct video_device *vdev = file->private_data; struct video_device *vdev = file->private_data;
...@@ -1744,6 +1725,7 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id ...@@ -1744,6 +1725,7 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
memcpy(pdev->vdev, &pwc_template, sizeof(pwc_template)); memcpy(pdev->vdev, &pwc_template, sizeof(pwc_template));
pdev->vdev->parent = &intf->dev; pdev->vdev->parent = &intf->dev;
pdev->vdev->lock = &pdev->modlock; pdev->vdev->lock = &pdev->modlock;
pdev->vdev->ioctl_ops = &pwc_ioctl_ops;
strcpy(pdev->vdev->name, name); strcpy(pdev->vdev->name, name);
video_set_drvdata(pdev->vdev, pdev); video_set_drvdata(pdev->vdev, pdev);
......
...@@ -341,606 +341,554 @@ static int pwc_vidioc_set_fmt(struct pwc_device *pdev, struct v4l2_format *f) ...@@ -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 video_device *vdev = video_devdata(file);
struct pwc_device *pdev; struct pwc_device *pdev = video_drvdata(file);
DECLARE_WAITQUEUE(wait, current);
strcpy(cap->driver, PWC_NAME);
if (vdev == NULL) strlcpy(cap->card, vdev->name, sizeof(cap->card));
return -EFAULT; usb_make_path(pdev->udev, cap->bus_info, sizeof(cap->bus_info));
pdev = video_get_drvdata(vdev); cap->version = PWC_VERSION_CODE;
if (pdev == NULL) cap->capabilities =
return -EFAULT; V4L2_CAP_VIDEO_CAPTURE |
V4L2_CAP_STREAMING |
V4L2_CAP_READWRITE;
return 0;
}
#ifdef CONFIG_USB_PWC_DEBUG static int pwc_enum_input(struct file *file, void *fh, struct v4l2_input *i)
if (PWC_DEBUG_LEVEL_IOCTL & pwc_trace) { {
v4l_printk_ioctl(cmd); if (i->index) /* Only one INPUT is supported */
printk("\n"); return -EINVAL;
}
#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;
}
case VIDIOC_ENUMINPUT: strcpy(i->name, "usb");
{ return 0;
struct v4l2_input *i = arg; }
if ( i->index ) /* Only one INPUT is supported */ static int pwc_g_input(struct file *file, void *fh, unsigned int *i)
return -EINVAL; {
*i = 0;
return 0;
}
memset(i, 0, sizeof(struct v4l2_input)); static int pwc_s_input(struct file *file, void *fh, unsigned int i)
strcpy(i->name, "usb"); {
return 0; return i ? -EINVAL : 0;
} }
case VIDIOC_G_INPUT: static int pwc_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *c)
{ {
int *i = arg; int i;
*i = 0; /* Only one INPUT is supported */
return 0;
}
case VIDIOC_S_INPUT:
{
int *i = arg;
if ( *i ) { /* Only one INPUT is supported */ for (i = 0; i < sizeof(pwc_controls) / sizeof(struct v4l2_queryctrl); i++) {
PWC_DEBUG_IOCTL("Only one input source is"\ if (pwc_controls[i].id == c->id) {
" supported with this webcam.\n"); PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYCTRL) found\n");
return -EINVAL; memcpy(c, &pwc_controls[i], sizeof(struct v4l2_queryctrl));
}
return 0; return 0;
} }
}
return -EINVAL;
}
/* TODO: */ static int pwc_g_ctrl(struct file *file, void *fh, struct v4l2_control *c)
case VIDIOC_QUERYCTRL: {
{ struct pwc_device *pdev = video_drvdata(file);
struct v4l2_queryctrl *c = arg; int ret;
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");
switch (c->id) {
case V4L2_CID_BRIGHTNESS:
c->value = pwc_get_brightness(pdev);
if (c->value < 0)
return -EINVAL; return -EINVAL;
} return 0;
case VIDIOC_G_CTRL: case V4L2_CID_CONTRAST:
{ c->value = pwc_get_contrast(pdev);
struct v4l2_control *c = arg; if (c->value < 0)
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 -EINVAL; return -EINVAL;
} return 0;
case VIDIOC_S_CTRL: case V4L2_CID_SATURATION:
{ ret = pwc_get_saturation(pdev, &c->value);
struct v4l2_control *c = arg; if (ret < 0)
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 -EINVAL; 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: case V4L2_CID_PRIVATE_SAVE_USER:
{ case V4L2_CID_PRIVATE_RESTORE_USER:
struct v4l2_fmtdesc *f = arg; case V4L2_CID_PRIVATE_RESTORE_FACTORY:
int index; return -EINVAL;
}
if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL;
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 VIDIOC_G_FMT: static int pwc_s_ctrl(struct file *file, void *fh, struct v4l2_control *c)
{ {
struct v4l2_format *f = arg; 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: PWC_DEBUG_IOCTL("ioctl(VIDIOC_G_FMT) return size %dx%d\n",
return pwc_vidioc_try_fmt(pdev, arg); pdev->image.x, pdev->image.y);
pwc_vidioc_fill_fmt(pdev, f);
return 0;
}
case VIDIOC_S_FMT: static int pwc_try_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f)
return pwc_vidioc_set_fmt(pdev, arg); {
struct pwc_device *pdev = video_drvdata(file);
case VIDIOC_G_STD: return pwc_vidioc_try_fmt(pdev, f);
{ }
v4l2_std_id *std = arg;
*std = V4L2_STD_UNKNOWN;
return 0;
}
case VIDIOC_S_STD: static int pwc_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f)
{ {
v4l2_std_id *std = arg; struct pwc_device *pdev = video_drvdata(file);
if (*std != V4L2_STD_UNKNOWN)
return -EINVAL;
return 0;
}
case VIDIOC_ENUMSTD: return pwc_vidioc_set_fmt(pdev, f);
{ }
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;
}
case VIDIOC_REQBUFS: static int pwc_reqbufs(struct file *file, void *fh, struct v4l2_requestbuffers *rb)
{ {
struct v4l2_requestbuffers *rb = arg; int nbuffers;
int nbuffers;
PWC_DEBUG_IOCTL("ioctl(VIDIOC_REQBUFS) count=%d\n",rb->count); PWC_DEBUG_IOCTL("ioctl(VIDIOC_REQBUFS) count=%d\n", rb->count);
if (rb->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) if (rb->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL; return -EINVAL;
if (rb->memory != V4L2_MEMORY_MMAP) if (rb->memory != V4L2_MEMORY_MMAP)
return -EINVAL; return -EINVAL;
nbuffers = rb->count; nbuffers = rb->count;
if (nbuffers < 2) if (nbuffers < 2)
nbuffers = 2; nbuffers = 2;
else if (nbuffers > pwc_mbufs) else if (nbuffers > pwc_mbufs)
nbuffers = pwc_mbufs; nbuffers = pwc_mbufs;
/* Force to use our # of buffers */ /* Force to use our # of buffers */
rb->count = pwc_mbufs; rb->count = pwc_mbufs;
return 0; return 0;
} }
case VIDIOC_QUERYBUF: static int pwc_querybuf(struct file *file, void *fh, struct v4l2_buffer *buf)
{ {
struct v4l2_buffer *buf = arg; struct pwc_device *pdev = video_drvdata(file);
int index; int index;
PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYBUF) index=%d\n",buf->index); PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYBUF) index=%d\n", buf->index);
if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYBUF) Bad type\n"); PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYBUF) Bad type\n");
return -EINVAL; return -EINVAL;
} }
if (buf->memory != V4L2_MEMORY_MMAP) { index = buf->index;
PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYBUF) Bad memory type\n"); if (index < 0 || index >= pwc_mbufs) {
return -EINVAL; PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYBUF) Bad index %d\n", buf->index);
} 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->m.offset = index * pdev->len_per_image;
buf->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; if (pdev->pixfmt != V4L2_PIX_FMT_YUV420)
buf->index = index; buf->bytesused = pdev->frame_size + sizeof(struct pwc_raw_frame);
buf->m.offset = index * pdev->len_per_image; else
if (pdev->pixfmt != V4L2_PIX_FMT_YUV420) buf->bytesused = pdev->view.size;
buf->bytesused = pdev->frame_size + sizeof(struct pwc_raw_frame); buf->field = V4L2_FIELD_NONE;
else buf->memory = V4L2_MEMORY_MMAP;
buf->bytesused = pdev->view.size; /*buf->flags = V4L2_BUF_FLAG_MAPPED;*/
buf->field = V4L2_FIELD_NONE; buf->length = pdev->len_per_image;
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);
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: return 0;
{ }
struct v4l2_buffer *buf = arg;
PWC_DEBUG_IOCTL("ioctl(VIDIOC_QBUF) index=%d\n",buf->index); static int pwc_qbuf(struct file *file, void *fh, struct v4l2_buffer *buf)
if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
return -EINVAL; PWC_DEBUG_IOCTL("ioctl(VIDIOC_QBUF) index=%d\n", buf->index);
if (buf->memory != V4L2_MEMORY_MMAP) if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL; return -EINVAL;
if (buf->index >= pwc_mbufs) if (buf->memory != V4L2_MEMORY_MMAP)
return -EINVAL; return -EINVAL;
if (buf->index >= pwc_mbufs)
return -EINVAL;
buf->flags |= V4L2_BUF_FLAG_QUEUED; buf->flags |= V4L2_BUF_FLAG_QUEUED;
buf->flags &= ~V4L2_BUF_FLAG_DONE; buf->flags &= ~V4L2_BUF_FLAG_DONE;
return 0; return 0;
} }
case VIDIOC_DQBUF: static int pwc_dqbuf(struct file *file, void *fh, struct v4l2_buffer *buf)
{ {
struct v4l2_buffer *buf = arg; DECLARE_WAITQUEUE(wait, current);
int ret; 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) if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL; return -EINVAL;
/* Add ourselves to the frame wait-queue. add_wait_queue(&pdev->frameq, &wait);
while (pdev->full_frames == NULL) {
FIXME: needs auditing for safety. if (pdev->error_status) {
QUESTION: In what respect? I think that using the remove_wait_queue(&pdev->frameq, &wait);
frameq is safe now. 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)) { 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); remove_wait_queue(&pdev->frameq, &wait);
set_current_state(TASK_RUNNING); 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"); PWC_DEBUG_IOCTL("VIDIOC_DQBUF: frame ready.\n");
/* Decompress data in pdev->images[pdev->fill_image] */ /* Decompress data in pdev->images[pdev->fill_image] */
ret = pwc_handle_frame(pdev); ret = pwc_handle_frame(pdev);
if (ret) if (ret)
return -EFAULT; return -EFAULT;
PWC_DEBUG_IOCTL("VIDIOC_DQBUF: after pwc_handle_frame\n"); PWC_DEBUG_IOCTL("VIDIOC_DQBUF: after pwc_handle_frame\n");
buf->index = pdev->fill_image; buf->index = pdev->fill_image;
if (pdev->pixfmt != V4L2_PIX_FMT_YUV420) if (pdev->pixfmt != V4L2_PIX_FMT_YUV420)
buf->bytesused = pdev->frame_size + sizeof(struct pwc_raw_frame); buf->bytesused = pdev->frame_size + sizeof(struct pwc_raw_frame);
else else
buf->bytesused = pdev->view.size; buf->bytesused = pdev->view.size;
buf->flags = V4L2_BUF_FLAG_MAPPED; buf->flags = V4L2_BUF_FLAG_MAPPED;
buf->field = V4L2_FIELD_NONE; buf->field = V4L2_FIELD_NONE;
do_gettimeofday(&buf->timestamp); do_gettimeofday(&buf->timestamp);
buf->sequence = 0; buf->sequence = 0;
buf->memory = V4L2_MEMORY_MMAP; buf->memory = V4L2_MEMORY_MMAP;
buf->m.offset = pdev->fill_image * pdev->len_per_image; buf->m.offset = pdev->fill_image * pdev->len_per_image;
buf->length = pdev->len_per_image; buf->length = pdev->len_per_image;
pwc_next_image(pdev); pwc_next_image(pdev);
PWC_DEBUG_IOCTL("VIDIOC_DQBUF: buf->index=%d\n",buf->index); 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: buf->length=%d\n", buf->length);
PWC_DEBUG_IOCTL("VIDIOC_DQBUF: m.offset=%d\n",buf->m.offset); 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: bytesused=%d\n", buf->bytesused);
PWC_DEBUG_IOCTL("VIDIOC_DQBUF: leaving\n"); PWC_DEBUG_IOCTL("VIDIOC_DQBUF: leaving\n");
return 0; return 0;
} }
case VIDIOC_STREAMON: static int pwc_streamon(struct file *file, void *fh, enum v4l2_buf_type i)
{ {
return pwc_isoc_init(pdev); struct pwc_device *pdev = video_drvdata(file);
}
case VIDIOC_STREAMOFF: return pwc_isoc_init(pdev);
{ }
pwc_isoc_cleanup(pdev);
return 0;
}
case VIDIOC_ENUM_FRAMESIZES: static int pwc_streamoff(struct file *file, void *fh, enum v4l2_buf_type i)
{ {
struct v4l2_frmsizeenum *fsize = arg; 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;
}
case VIDIOC_ENUM_FRAMEINTERVALS: pwc_isoc_cleanup(pdev);
{ return 0;
struct v4l2_frmivalenum *fival = arg; }
int size = -1;
unsigned int i; static int pwc_enum_framesizes(struct file *file, void *fh,
struct v4l2_frmsizeenum *fsize)
for (i = 0; i < PSZ_MAX; i++) { {
if (pwc_image_sizes[i].x == fival->width && struct pwc_device *pdev = video_drvdata(file);
pwc_image_sizes[i].y == fival->height) { unsigned int i = 0, index = fsize->index;
size = i;
break; 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 */ static int pwc_enum_frameintervals(struct file *file, void *fh,
if (size < 0 || fival->pixel_format != V4L2_PIX_FMT_YUV420) { struct v4l2_frmivalenum *fival)
return -EINVAL; {
} 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); /* TODO: Support raw format */
if (!i) if (size < 0 || fival->pixel_format != V4L2_PIX_FMT_YUV420)
return -EINVAL; return -EINVAL;
fival->type = V4L2_FRMIVAL_TYPE_DISCRETE; i = pwc_get_fps(pdev, fival->index, size);
fival->discrete.numerator = 1; if (!i)
fival->discrete.denominator = 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; 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: */ /* vim: set cino= formatoptions=croql cindent shiftwidth=8 tabstop=8: */
...@@ -339,8 +339,7 @@ extern int pwc_camera_power(struct pwc_device *pdev, int power); ...@@ -339,8 +339,7 @@ extern int pwc_camera_power(struct pwc_device *pdev, int power);
/* Private ioctl()s; see pwc-ioctl.h */ /* Private ioctl()s; see pwc-ioctl.h */
extern long pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg); extern long pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg);
/** Functions in pwc-v4l.c */ extern const struct v4l2_ioctl_ops pwc_ioctl_ops;
extern long pwc_video_do_ioctl(struct file *file, unsigned int cmd, void *arg);
/** pwc-uncompress.c */ /** pwc-uncompress.c */
/* Expand frame to image, possibly including decompression. Uses read_frame and fill_image */ /* Expand frame to image, possibly including decompression. Uses read_frame and fill_image */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment