V4L/DVB (12378): uvcvideo: Restructure the driver to support multiple simultaneous streams.

As a first step towards multiple streaming interfaces support, reorganize the
driver's data structures to cleanly separate video control and video streaming
data.

Signed-off-by: Laurent Pinchart <laurent.pinchart@skynet.be>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
This commit is contained in:
Laurent Pinchart 2009-06-28 08:37:50 -03:00 committed by Mauro Carvalho Chehab
parent 6c428b578b
commit 35f02a681b
5 changed files with 458 additions and 423 deletions

View File

@ -551,6 +551,7 @@ static int uvc_parse_streaming(struct uvc_device *dev,
} }
mutex_init(&streaming->mutex); mutex_init(&streaming->mutex);
streaming->dev = dev;
streaming->intf = usb_get_intf(intf); streaming->intf = usb_get_intf(intf);
streaming->intfnum = intf->cur_altsetting->desc.bInterfaceNumber; streaming->intfnum = intf->cur_altsetting->desc.bInterfaceNumber;
@ -751,7 +752,7 @@ static int uvc_parse_streaming(struct uvc_device *dev,
streaming->maxpsize = psize; streaming->maxpsize = psize;
} }
list_add_tail(&streaming->list, &dev->streaming); list_add_tail(&streaming->list, &dev->streams);
return 0; return 0;
error: error:
@ -1167,15 +1168,77 @@ next_descriptor:
*/ */
static void uvc_unregister_video(struct uvc_device *dev) static void uvc_unregister_video(struct uvc_device *dev)
{ {
if (dev->video.vdev) { struct uvc_streaming *streaming;
if (dev->video.vdev->minor == -1)
video_device_release(dev->video.vdev); list_for_each_entry(streaming, &dev->streams, list) {
if (streaming->vdev == NULL)
continue;
if (streaming->vdev->minor == -1)
video_device_release(streaming->vdev);
else else
video_unregister_device(dev->video.vdev); video_unregister_device(streaming->vdev);
dev->video.vdev = NULL; streaming->vdev = NULL;
} }
} }
static int uvc_register_video(struct uvc_device *dev,
struct uvc_streaming *stream)
{
struct video_device *vdev;
struct uvc_entity *term;
int ret;
if (uvc_trace_param & UVC_TRACE_PROBE) {
uvc_printk(KERN_INFO, "Found a valid video chain (");
list_for_each_entry(term, &dev->video.iterms, chain) {
printk("%d", term->id);
if (term->chain.next != &dev->video.iterms)
printk(",");
}
printk(" -> %d).\n", dev->video.oterm->id);
}
/* Initialize the streaming interface with default streaming
* parameters.
*/
ret = uvc_video_init(stream);
if (ret < 0) {
uvc_printk(KERN_ERR, "Failed to initialize the device "
"(%d).\n", ret);
return ret;
}
/* Register the device with V4L. */
vdev = video_device_alloc();
if (vdev == NULL)
return -1;
/* We already hold a reference to dev->udev. The video device will be
* unregistered before the reference is released, so we don't need to
* get another one.
*/
vdev->parent = &dev->intf->dev;
vdev->minor = -1;
vdev->fops = &uvc_fops;
vdev->release = video_device_release;
strlcpy(vdev->name, dev->name, sizeof vdev->name);
/* Set the driver data before calling video_register_device, otherwise
* uvc_v4l2_open might race us.
*/
stream->vdev = vdev;
video_set_drvdata(vdev, stream);
if (video_register_device(vdev, VFL_TYPE_GRABBER, -1) < 0) {
stream->vdev = NULL;
video_device_release(vdev);
return -1;
}
return 0;
}
/* /*
* Scan the UVC descriptors to locate a chain starting at an Output Terminal * Scan the UVC descriptors to locate a chain starting at an Output Terminal
* and containing the following units: * and containing the following units:
@ -1419,7 +1482,7 @@ static int uvc_scan_chain(struct uvc_video_device *video)
} }
/* /*
* Register the video devices. * Scan the device for video chains and register video devices.
* *
* The driver currently supports a single video device per control interface * The driver currently supports a single video device per control interface
* only. The terminal and units must match the following structure: * only. The terminal and units must match the following structure:
@ -1432,15 +1495,14 @@ static int uvc_scan_chain(struct uvc_video_device *video)
* Extension Units connected to the main chain as single-unit branches are * Extension Units connected to the main chain as single-unit branches are
* also supported. * also supported.
*/ */
static int uvc_register_video(struct uvc_device *dev) static int uvc_scan_device(struct uvc_device *dev)
{ {
struct video_device *vdev;
struct uvc_entity *term; struct uvc_entity *term;
int found = 0, ret; int found = 0;
/* Check if the control interface matches the structure we expect. */ /* Check if the control interface matches the structure we expect. */
list_for_each_entry(term, &dev->entities, list) { list_for_each_entry(term, &dev->entities, list) {
struct uvc_streaming *streaming; struct uvc_streaming *stream;
if (!UVC_ENTITY_IS_TERM(term) || !UVC_ENTITY_IS_OTERM(term)) if (!UVC_ENTITY_IS_TERM(term) || !UVC_ENTITY_IS_OTERM(term))
continue; continue;
@ -1454,17 +1516,14 @@ static int uvc_register_video(struct uvc_device *dev)
if (uvc_scan_chain(&dev->video) < 0) if (uvc_scan_chain(&dev->video) < 0)
continue; continue;
list_for_each_entry(streaming, &dev->streaming, list) { list_for_each_entry(stream, &dev->streams, list) {
if (streaming->header.bTerminalLink == if (stream->header.bTerminalLink ==
dev->video.sterm->id) { dev->video.sterm->id) {
dev->video.streaming = streaming; uvc_register_video(dev, stream);
found = 1; found = 1;
break; break;
} }
} }
if (found)
break;
} }
if (!found) { if (!found) {
@ -1472,55 +1531,6 @@ static int uvc_register_video(struct uvc_device *dev)
return -1; return -1;
} }
if (uvc_trace_param & UVC_TRACE_PROBE) {
uvc_printk(KERN_INFO, "Found a valid video chain (");
list_for_each_entry(term, &dev->video.iterms, chain) {
printk("%d", term->id);
if (term->chain.next != &dev->video.iterms)
printk(",");
}
printk(" -> %d).\n", dev->video.oterm->id);
}
/* Initialize the video buffers queue. */
uvc_queue_init(&dev->video.queue, dev->video.streaming->type);
/* Initialize the streaming interface with default streaming
* parameters.
*/
if ((ret = uvc_video_init(&dev->video)) < 0) {
uvc_printk(KERN_ERR, "Failed to initialize the device "
"(%d).\n", ret);
return ret;
}
/* Register the device with V4L. */
vdev = video_device_alloc();
if (vdev == NULL)
return -1;
/* We already hold a reference to dev->udev. The video device will be
* unregistered before the reference is released, so we don't need to
* get another one.
*/
vdev->parent = &dev->intf->dev;
vdev->minor = -1;
vdev->fops = &uvc_fops;
vdev->release = video_device_release;
strlcpy(vdev->name, dev->name, sizeof vdev->name);
/* Set the driver data before calling video_register_device, otherwise
* uvc_v4l2_open might race us.
*/
dev->video.vdev = vdev;
video_set_drvdata(vdev, &dev->video);
if (video_register_device(vdev, VFL_TYPE_GRABBER, -1) < 0) {
dev->video.vdev = NULL;
video_device_release(vdev);
return -1;
}
return 0; return 0;
} }
@ -1559,7 +1569,7 @@ void uvc_delete(struct kref *kref)
kfree(entity); kfree(entity);
} }
list_for_each_safe(p, n, &dev->streaming) { list_for_each_safe(p, n, &dev->streams) {
struct uvc_streaming *streaming; struct uvc_streaming *streaming;
streaming = list_entry(p, struct uvc_streaming, list); streaming = list_entry(p, struct uvc_streaming, list);
usb_driver_release_interface(&uvc_driver.driver, usb_driver_release_interface(&uvc_driver.driver,
@ -1593,7 +1603,7 @@ static int uvc_probe(struct usb_interface *intf,
return -ENOMEM; return -ENOMEM;
INIT_LIST_HEAD(&dev->entities); INIT_LIST_HEAD(&dev->entities);
INIT_LIST_HEAD(&dev->streaming); INIT_LIST_HEAD(&dev->streams);
kref_init(&dev->kref); kref_init(&dev->kref);
atomic_set(&dev->users, 0); atomic_set(&dev->users, 0);
@ -1634,8 +1644,8 @@ static int uvc_probe(struct usb_interface *intf,
if (uvc_ctrl_init_device(dev) < 0) if (uvc_ctrl_init_device(dev) < 0)
goto error; goto error;
/* Register the video devices. */ /* Scan the device for video chains and register video devices. */
if (uvc_register_video(dev) < 0) if (uvc_scan_device(dev) < 0)
goto error; goto error;
/* Save our data pointer in the interface data. */ /* Save our data pointer in the interface data. */
@ -1689,6 +1699,7 @@ static void uvc_disconnect(struct usb_interface *intf)
static int uvc_suspend(struct usb_interface *intf, pm_message_t message) static int uvc_suspend(struct usb_interface *intf, pm_message_t message)
{ {
struct uvc_device *dev = usb_get_intfdata(intf); struct uvc_device *dev = usb_get_intfdata(intf);
struct uvc_streaming *stream;
uvc_trace(UVC_TRACE_SUSPEND, "Suspending interface %u\n", uvc_trace(UVC_TRACE_SUSPEND, "Suspending interface %u\n",
intf->cur_altsetting->desc.bInterfaceNumber); intf->cur_altsetting->desc.bInterfaceNumber);
@ -1698,18 +1709,20 @@ static int uvc_suspend(struct usb_interface *intf, pm_message_t message)
UVC_SC_VIDEOCONTROL) UVC_SC_VIDEOCONTROL)
return uvc_status_suspend(dev); return uvc_status_suspend(dev);
if (dev->video.streaming->intf != intf) { list_for_each_entry(stream, &dev->streams, list) {
uvc_trace(UVC_TRACE_SUSPEND, "Suspend: video streaming USB " if (stream->intf == intf)
"interface mismatch.\n"); return uvc_video_suspend(stream);
return -EINVAL;
} }
return uvc_video_suspend(&dev->video); uvc_trace(UVC_TRACE_SUSPEND, "Suspend: video streaming USB interface "
"mismatch.\n");
return -EINVAL;
} }
static int __uvc_resume(struct usb_interface *intf, int reset) static int __uvc_resume(struct usb_interface *intf, int reset)
{ {
struct uvc_device *dev = usb_get_intfdata(intf); struct uvc_device *dev = usb_get_intfdata(intf);
struct uvc_streaming *stream;
uvc_trace(UVC_TRACE_SUSPEND, "Resuming interface %u\n", uvc_trace(UVC_TRACE_SUSPEND, "Resuming interface %u\n",
intf->cur_altsetting->desc.bInterfaceNumber); intf->cur_altsetting->desc.bInterfaceNumber);
@ -1726,13 +1739,14 @@ static int __uvc_resume(struct usb_interface *intf, int reset)
return uvc_status_resume(dev); return uvc_status_resume(dev);
} }
if (dev->video.streaming->intf != intf) { list_for_each_entry(stream, &dev->streams, list) {
uvc_trace(UVC_TRACE_SUSPEND, "Resume: video streaming USB " if (stream->intf == intf)
"interface mismatch.\n"); return uvc_video_resume(stream);
return -EINVAL;
} }
return uvc_video_resume(&dev->video); uvc_trace(UVC_TRACE_SUSPEND, "Resume: video streaming USB interface "
"mismatch.\n");
return -EINVAL;
} }
static int uvc_resume(struct usb_interface *intf) static int uvc_resume(struct usb_interface *intf)

View File

@ -99,7 +99,7 @@ static int isight_decode(struct uvc_video_queue *queue, struct uvc_buffer *buf,
return 0; return 0;
} }
void uvc_video_decode_isight(struct urb *urb, struct uvc_video_device *video, void uvc_video_decode_isight(struct urb *urb, struct uvc_streaming *stream,
struct uvc_buffer *buf) struct uvc_buffer *buf)
{ {
int ret, i; int ret, i;
@ -120,7 +120,7 @@ void uvc_video_decode_isight(struct urb *urb, struct uvc_video_device *video,
* processes the data of the first payload of the new frame. * processes the data of the first payload of the new frame.
*/ */
do { do {
ret = isight_decode(&video->queue, buf, ret = isight_decode(&stream->queue, buf,
urb->transfer_buffer + urb->transfer_buffer +
urb->iso_frame_desc[i].offset, urb->iso_frame_desc[i].offset,
urb->iso_frame_desc[i].actual_length); urb->iso_frame_desc[i].actual_length);
@ -130,7 +130,8 @@ void uvc_video_decode_isight(struct urb *urb, struct uvc_video_device *video,
if (buf->state == UVC_BUF_STATE_DONE || if (buf->state == UVC_BUF_STATE_DONE ||
buf->state == UVC_BUF_STATE_ERROR) buf->state == UVC_BUF_STATE_ERROR)
buf = uvc_queue_next_buffer(&video->queue, buf); buf = uvc_queue_next_buffer(&stream->queue,
buf);
} while (ret == -EAGAIN); } while (ret == -EAGAIN);
} }
} }

View File

@ -103,7 +103,7 @@ static __u32 uvc_try_frame_interval(struct uvc_frame *frame, __u32 interval)
return interval; return interval;
} }
static int uvc_v4l2_try_format(struct uvc_video_device *video, static int uvc_v4l2_try_format(struct uvc_streaming *stream,
struct v4l2_format *fmt, struct uvc_streaming_control *probe, struct v4l2_format *fmt, struct uvc_streaming_control *probe,
struct uvc_format **uvc_format, struct uvc_frame **uvc_frame) struct uvc_format **uvc_format, struct uvc_frame **uvc_frame)
{ {
@ -116,7 +116,7 @@ static int uvc_v4l2_try_format(struct uvc_video_device *video,
int ret = 0; int ret = 0;
__u8 *fcc; __u8 *fcc;
if (fmt->type != video->streaming->type) if (fmt->type != stream->type)
return -EINVAL; return -EINVAL;
fcc = (__u8 *)&fmt->fmt.pix.pixelformat; fcc = (__u8 *)&fmt->fmt.pix.pixelformat;
@ -126,8 +126,8 @@ static int uvc_v4l2_try_format(struct uvc_video_device *video,
fmt->fmt.pix.width, fmt->fmt.pix.height); fmt->fmt.pix.width, fmt->fmt.pix.height);
/* Check if the hardware supports the requested format. */ /* Check if the hardware supports the requested format. */
for (i = 0; i < video->streaming->nformats; ++i) { for (i = 0; i < stream->nformats; ++i) {
format = &video->streaming->format[i]; format = &stream->format[i];
if (format->fcc == fmt->fmt.pix.pixelformat) if (format->fcc == fmt->fmt.pix.pixelformat)
break; break;
} }
@ -191,12 +191,13 @@ static int uvc_v4l2_try_format(struct uvc_video_device *video,
* developers test their webcams with the Linux driver as well as with * developers test their webcams with the Linux driver as well as with
* the Windows driver). * the Windows driver).
*/ */
if (video->dev->quirks & UVC_QUIRK_PROBE_EXTRAFIELDS) if (stream->dev->quirks & UVC_QUIRK_PROBE_EXTRAFIELDS)
probe->dwMaxVideoFrameSize = probe->dwMaxVideoFrameSize =
video->streaming->ctrl.dwMaxVideoFrameSize; stream->ctrl.dwMaxVideoFrameSize;
/* Probe the device. */ /* Probe the device. */
if ((ret = uvc_probe_video(video, probe)) < 0) ret = uvc_probe_video(stream, probe);
if (ret < 0)
goto done; goto done;
fmt->fmt.pix.width = frame->wWidth; fmt->fmt.pix.width = frame->wWidth;
@ -216,13 +217,13 @@ done:
return ret; return ret;
} }
static int uvc_v4l2_get_format(struct uvc_video_device *video, static int uvc_v4l2_get_format(struct uvc_streaming *stream,
struct v4l2_format *fmt) struct v4l2_format *fmt)
{ {
struct uvc_format *format = video->streaming->cur_format; struct uvc_format *format = stream->cur_format;
struct uvc_frame *frame = video->streaming->cur_frame; struct uvc_frame *frame = stream->cur_frame;
if (fmt->type != video->streaming->type) if (fmt->type != stream->type)
return -EINVAL; return -EINVAL;
if (format == NULL || frame == NULL) if (format == NULL || frame == NULL)
@ -233,14 +234,14 @@ static int uvc_v4l2_get_format(struct uvc_video_device *video,
fmt->fmt.pix.height = frame->wHeight; fmt->fmt.pix.height = frame->wHeight;
fmt->fmt.pix.field = V4L2_FIELD_NONE; fmt->fmt.pix.field = V4L2_FIELD_NONE;
fmt->fmt.pix.bytesperline = format->bpp * frame->wWidth / 8; fmt->fmt.pix.bytesperline = format->bpp * frame->wWidth / 8;
fmt->fmt.pix.sizeimage = video->streaming->ctrl.dwMaxVideoFrameSize; fmt->fmt.pix.sizeimage = stream->ctrl.dwMaxVideoFrameSize;
fmt->fmt.pix.colorspace = format->colorspace; fmt->fmt.pix.colorspace = format->colorspace;
fmt->fmt.pix.priv = 0; fmt->fmt.pix.priv = 0;
return 0; return 0;
} }
static int uvc_v4l2_set_format(struct uvc_video_device *video, static int uvc_v4l2_set_format(struct uvc_streaming *stream,
struct v4l2_format *fmt) struct v4l2_format *fmt)
{ {
struct uvc_streaming_control probe; struct uvc_streaming_control probe;
@ -248,39 +249,39 @@ static int uvc_v4l2_set_format(struct uvc_video_device *video,
struct uvc_frame *frame; struct uvc_frame *frame;
int ret; int ret;
if (fmt->type != video->streaming->type) if (fmt->type != stream->type)
return -EINVAL; return -EINVAL;
if (uvc_queue_allocated(&video->queue)) if (uvc_queue_allocated(&stream->queue))
return -EBUSY; return -EBUSY;
ret = uvc_v4l2_try_format(video, fmt, &probe, &format, &frame); ret = uvc_v4l2_try_format(stream, fmt, &probe, &format, &frame);
if (ret < 0) if (ret < 0)
return ret; return ret;
memcpy(&video->streaming->ctrl, &probe, sizeof probe); memcpy(&stream->ctrl, &probe, sizeof probe);
video->streaming->cur_format = format; stream->cur_format = format;
video->streaming->cur_frame = frame; stream->cur_frame = frame;
return 0; return 0;
} }
static int uvc_v4l2_get_streamparm(struct uvc_video_device *video, static int uvc_v4l2_get_streamparm(struct uvc_streaming *stream,
struct v4l2_streamparm *parm) struct v4l2_streamparm *parm)
{ {
uint32_t numerator, denominator; uint32_t numerator, denominator;
if (parm->type != video->streaming->type) if (parm->type != stream->type)
return -EINVAL; return -EINVAL;
numerator = video->streaming->ctrl.dwFrameInterval; numerator = stream->ctrl.dwFrameInterval;
denominator = 10000000; denominator = 10000000;
uvc_simplify_fraction(&numerator, &denominator, 8, 333); uvc_simplify_fraction(&numerator, &denominator, 8, 333);
memset(parm, 0, sizeof *parm); memset(parm, 0, sizeof *parm);
parm->type = video->streaming->type; parm->type = stream->type;
if (video->streaming->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { if (stream->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
parm->parm.capture.capability = V4L2_CAP_TIMEPERFRAME; parm->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
parm->parm.capture.capturemode = 0; parm->parm.capture.capturemode = 0;
parm->parm.capture.timeperframe.numerator = numerator; parm->parm.capture.timeperframe.numerator = numerator;
@ -297,19 +298,19 @@ static int uvc_v4l2_get_streamparm(struct uvc_video_device *video,
return 0; return 0;
} }
static int uvc_v4l2_set_streamparm(struct uvc_video_device *video, static int uvc_v4l2_set_streamparm(struct uvc_streaming *stream,
struct v4l2_streamparm *parm) struct v4l2_streamparm *parm)
{ {
struct uvc_frame *frame = video->streaming->cur_frame; struct uvc_frame *frame = stream->cur_frame;
struct uvc_streaming_control probe; struct uvc_streaming_control probe;
struct v4l2_fract timeperframe; struct v4l2_fract timeperframe;
uint32_t interval; uint32_t interval;
int ret; int ret;
if (parm->type != video->streaming->type) if (parm->type != stream->type)
return -EINVAL; return -EINVAL;
if (uvc_queue_streaming(&video->queue)) if (uvc_queue_streaming(&stream->queue))
return -EBUSY; return -EBUSY;
if (parm->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) if (parm->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
@ -317,7 +318,7 @@ static int uvc_v4l2_set_streamparm(struct uvc_video_device *video,
else else
timeperframe = parm->parm.output.timeperframe; timeperframe = parm->parm.output.timeperframe;
memcpy(&probe, &video->streaming->ctrl, sizeof probe); memcpy(&probe, &stream->ctrl, sizeof probe);
interval = uvc_fraction_to_interval(timeperframe.numerator, interval = uvc_fraction_to_interval(timeperframe.numerator,
timeperframe.denominator); timeperframe.denominator);
@ -326,10 +327,11 @@ static int uvc_v4l2_set_streamparm(struct uvc_video_device *video,
probe.dwFrameInterval = uvc_try_frame_interval(frame, interval); probe.dwFrameInterval = uvc_try_frame_interval(frame, interval);
/* Probe the device with the new settings. */ /* Probe the device with the new settings. */
if ((ret = uvc_probe_video(video, &probe)) < 0) ret = uvc_probe_video(stream, &probe);
if (ret < 0)
return ret; return ret;
memcpy(&video->streaming->ctrl, &probe, sizeof probe); memcpy(&stream->ctrl, &probe, sizeof probe);
/* Return the actual frame period. */ /* Return the actual frame period. */
timeperframe.numerator = probe.dwFrameInterval; timeperframe.numerator = probe.dwFrameInterval;
@ -382,8 +384,8 @@ static int uvc_acquire_privileges(struct uvc_fh *handle)
/* Check if the device already has a privileged handle. */ /* Check if the device already has a privileged handle. */
mutex_lock(&uvc_driver.open_mutex); mutex_lock(&uvc_driver.open_mutex);
if (atomic_inc_return(&handle->device->active) != 1) { if (atomic_inc_return(&handle->stream->active) != 1) {
atomic_dec(&handle->device->active); atomic_dec(&handle->stream->active);
ret = -EBUSY; ret = -EBUSY;
goto done; goto done;
} }
@ -398,7 +400,7 @@ done:
static void uvc_dismiss_privileges(struct uvc_fh *handle) static void uvc_dismiss_privileges(struct uvc_fh *handle)
{ {
if (handle->state == UVC_HANDLE_ACTIVE) if (handle->state == UVC_HANDLE_ACTIVE)
atomic_dec(&handle->device->active); atomic_dec(&handle->stream->active);
handle->state = UVC_HANDLE_PASSIVE; handle->state = UVC_HANDLE_PASSIVE;
} }
@ -414,45 +416,47 @@ static int uvc_has_privileges(struct uvc_fh *handle)
static int uvc_v4l2_open(struct file *file) static int uvc_v4l2_open(struct file *file)
{ {
struct uvc_video_device *video; struct uvc_streaming *stream;
struct uvc_fh *handle; struct uvc_fh *handle;
int ret = 0; int ret = 0;
uvc_trace(UVC_TRACE_CALLS, "uvc_v4l2_open\n"); uvc_trace(UVC_TRACE_CALLS, "uvc_v4l2_open\n");
mutex_lock(&uvc_driver.open_mutex); mutex_lock(&uvc_driver.open_mutex);
video = video_drvdata(file); stream = video_drvdata(file);
if (video->dev->state & UVC_DEV_DISCONNECTED) { if (stream->dev->state & UVC_DEV_DISCONNECTED) {
ret = -ENODEV; ret = -ENODEV;
goto done; goto done;
} }
ret = usb_autopm_get_interface(video->dev->intf); ret = usb_autopm_get_interface(stream->dev->intf);
if (ret < 0) if (ret < 0)
goto done; goto done;
/* Create the device handle. */ /* Create the device handle. */
handle = kzalloc(sizeof *handle, GFP_KERNEL); handle = kzalloc(sizeof *handle, GFP_KERNEL);
if (handle == NULL) { if (handle == NULL) {
usb_autopm_put_interface(video->dev->intf); usb_autopm_put_interface(stream->dev->intf);
ret = -ENOMEM; ret = -ENOMEM;
goto done; goto done;
} }
if (atomic_inc_return(&video->dev->users) == 1) { if (atomic_inc_return(&stream->dev->users) == 1) {
if ((ret = uvc_status_start(video->dev)) < 0) { ret = uvc_status_start(stream->dev);
usb_autopm_put_interface(video->dev->intf); if (ret < 0) {
atomic_dec(&video->dev->users); usb_autopm_put_interface(stream->dev->intf);
atomic_dec(&stream->dev->users);
kfree(handle); kfree(handle);
goto done; goto done;
} }
} }
handle->device = video; handle->video = &stream->dev->video;
handle->stream = stream;
handle->state = UVC_HANDLE_PASSIVE; handle->state = UVC_HANDLE_PASSIVE;
file->private_data = handle; file->private_data = handle;
kref_get(&video->dev->kref); kref_get(&stream->dev->kref);
done: done:
mutex_unlock(&uvc_driver.open_mutex); mutex_unlock(&uvc_driver.open_mutex);
@ -461,20 +465,20 @@ done:
static int uvc_v4l2_release(struct file *file) static int uvc_v4l2_release(struct file *file)
{ {
struct uvc_video_device *video = video_drvdata(file);
struct uvc_fh *handle = (struct uvc_fh *)file->private_data; struct uvc_fh *handle = (struct uvc_fh *)file->private_data;
struct uvc_streaming *stream = handle->stream;
uvc_trace(UVC_TRACE_CALLS, "uvc_v4l2_release\n"); uvc_trace(UVC_TRACE_CALLS, "uvc_v4l2_release\n");
/* Only free resources if this is a privileged handle. */ /* Only free resources if this is a privileged handle. */
if (uvc_has_privileges(handle)) { if (uvc_has_privileges(handle)) {
uvc_video_enable(video, 0); uvc_video_enable(stream, 0);
mutex_lock(&video->queue.mutex); mutex_lock(&stream->queue.mutex);
if (uvc_free_buffers(&video->queue) < 0) if (uvc_free_buffers(&stream->queue) < 0)
uvc_printk(KERN_ERR, "uvc_v4l2_release: Unable to " uvc_printk(KERN_ERR, "uvc_v4l2_release: Unable to "
"free buffers.\n"); "free buffers.\n");
mutex_unlock(&video->queue.mutex); mutex_unlock(&stream->queue.mutex);
} }
/* Release the file handle. */ /* Release the file handle. */
@ -482,19 +486,20 @@ static int uvc_v4l2_release(struct file *file)
kfree(handle); kfree(handle);
file->private_data = NULL; file->private_data = NULL;
if (atomic_dec_return(&video->dev->users) == 0) if (atomic_dec_return(&stream->dev->users) == 0)
uvc_status_stop(video->dev); uvc_status_stop(stream->dev);
usb_autopm_put_interface(video->dev->intf); usb_autopm_put_interface(stream->dev->intf);
kref_put(&video->dev->kref, uvc_delete); kref_put(&stream->dev->kref, uvc_delete);
return 0; return 0;
} }
static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
{ {
struct video_device *vdev = video_devdata(file); struct video_device *vdev = video_devdata(file);
struct uvc_video_device *video = video_get_drvdata(vdev);
struct uvc_fh *handle = (struct uvc_fh *)file->private_data; struct uvc_fh *handle = (struct uvc_fh *)file->private_data;
struct uvc_video_device *video = handle->video;
struct uvc_streaming *stream = handle->stream;
long ret = 0; long ret = 0;
switch (cmd) { switch (cmd) {
@ -506,10 +511,10 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
memset(cap, 0, sizeof *cap); memset(cap, 0, sizeof *cap);
strlcpy(cap->driver, "uvcvideo", sizeof cap->driver); strlcpy(cap->driver, "uvcvideo", sizeof cap->driver);
strlcpy(cap->card, vdev->name, sizeof cap->card); strlcpy(cap->card, vdev->name, sizeof cap->card);
usb_make_path(video->dev->udev, usb_make_path(stream->dev->udev,
cap->bus_info, sizeof(cap->bus_info)); cap->bus_info, sizeof(cap->bus_info));
cap->version = DRIVER_VERSION_NUMBER; cap->version = DRIVER_VERSION_NUMBER;
if (video->streaming->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) if (stream->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
cap->capabilities = V4L2_CAP_VIDEO_CAPTURE cap->capabilities = V4L2_CAP_VIDEO_CAPTURE
| V4L2_CAP_STREAMING; | V4L2_CAP_STREAMING;
else else
@ -703,15 +708,15 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
enum v4l2_buf_type type = fmt->type; enum v4l2_buf_type type = fmt->type;
__u32 index = fmt->index; __u32 index = fmt->index;
if (fmt->type != video->streaming->type || if (fmt->type != stream->type ||
fmt->index >= video->streaming->nformats) fmt->index >= stream->nformats)
return -EINVAL; return -EINVAL;
memset(fmt, 0, sizeof(*fmt)); memset(fmt, 0, sizeof(*fmt));
fmt->index = index; fmt->index = index;
fmt->type = type; fmt->type = type;
format = &video->streaming->format[fmt->index]; format = &stream->format[fmt->index];
fmt->flags = 0; fmt->flags = 0;
if (format->flags & UVC_FMT_FLAG_COMPRESSED) if (format->flags & UVC_FMT_FLAG_COMPRESSED)
fmt->flags |= V4L2_FMT_FLAG_COMPRESSED; fmt->flags |= V4L2_FMT_FLAG_COMPRESSED;
@ -729,17 +734,17 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
if ((ret = uvc_acquire_privileges(handle)) < 0) if ((ret = uvc_acquire_privileges(handle)) < 0)
return ret; return ret;
return uvc_v4l2_try_format(video, arg, &probe, NULL, NULL); return uvc_v4l2_try_format(stream, arg, &probe, NULL, NULL);
} }
case VIDIOC_S_FMT: case VIDIOC_S_FMT:
if ((ret = uvc_acquire_privileges(handle)) < 0) if ((ret = uvc_acquire_privileges(handle)) < 0)
return ret; return ret;
return uvc_v4l2_set_format(video, arg); return uvc_v4l2_set_format(stream, arg);
case VIDIOC_G_FMT: case VIDIOC_G_FMT:
return uvc_v4l2_get_format(video, arg); return uvc_v4l2_get_format(stream, arg);
/* Frame size enumeration */ /* Frame size enumeration */
case VIDIOC_ENUM_FRAMESIZES: case VIDIOC_ENUM_FRAMESIZES:
@ -750,10 +755,10 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
int i; int i;
/* Look for the given pixel format */ /* Look for the given pixel format */
for (i = 0; i < video->streaming->nformats; i++) { for (i = 0; i < stream->nformats; i++) {
if (video->streaming->format[i].fcc == if (stream->format[i].fcc ==
fsize->pixel_format) { fsize->pixel_format) {
format = &video->streaming->format[i]; format = &stream->format[i];
break; break;
} }
} }
@ -779,10 +784,10 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
int i; int i;
/* Look for the given pixel format and frame size */ /* Look for the given pixel format and frame size */
for (i = 0; i < video->streaming->nformats; i++) { for (i = 0; i < stream->nformats; i++) {
if (video->streaming->format[i].fcc == if (stream->format[i].fcc ==
fival->pixel_format) { fival->pixel_format) {
format = &video->streaming->format[i]; format = &stream->format[i];
break; break;
} }
} }
@ -832,21 +837,21 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
/* Get & Set streaming parameters */ /* Get & Set streaming parameters */
case VIDIOC_G_PARM: case VIDIOC_G_PARM:
return uvc_v4l2_get_streamparm(video, arg); return uvc_v4l2_get_streamparm(stream, arg);
case VIDIOC_S_PARM: case VIDIOC_S_PARM:
if ((ret = uvc_acquire_privileges(handle)) < 0) if ((ret = uvc_acquire_privileges(handle)) < 0)
return ret; return ret;
return uvc_v4l2_set_streamparm(video, arg); return uvc_v4l2_set_streamparm(stream, arg);
/* Cropping and scaling */ /* Cropping and scaling */
case VIDIOC_CROPCAP: case VIDIOC_CROPCAP:
{ {
struct v4l2_cropcap *ccap = arg; struct v4l2_cropcap *ccap = arg;
struct uvc_frame *frame = video->streaming->cur_frame; struct uvc_frame *frame = stream->cur_frame;
if (ccap->type != video->streaming->type) if (ccap->type != stream->type)
return -EINVAL; return -EINVAL;
ccap->bounds.left = 0; ccap->bounds.left = 0;
@ -870,16 +875,16 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
{ {
struct v4l2_requestbuffers *rb = arg; struct v4l2_requestbuffers *rb = arg;
unsigned int bufsize = unsigned int bufsize =
video->streaming->ctrl.dwMaxVideoFrameSize; stream->ctrl.dwMaxVideoFrameSize;
if (rb->type != video->streaming->type || if (rb->type != stream->type ||
rb->memory != V4L2_MEMORY_MMAP) rb->memory != V4L2_MEMORY_MMAP)
return -EINVAL; return -EINVAL;
if ((ret = uvc_acquire_privileges(handle)) < 0) if ((ret = uvc_acquire_privileges(handle)) < 0)
return ret; return ret;
ret = uvc_alloc_buffers(&video->queue, rb->count, bufsize); ret = uvc_alloc_buffers(&stream->queue, rb->count, bufsize);
if (ret < 0) if (ret < 0)
return ret; return ret;
@ -892,39 +897,40 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
{ {
struct v4l2_buffer *buf = arg; struct v4l2_buffer *buf = arg;
if (buf->type != video->streaming->type) if (buf->type != stream->type)
return -EINVAL; return -EINVAL;
if (!uvc_has_privileges(handle)) if (!uvc_has_privileges(handle))
return -EBUSY; return -EBUSY;
return uvc_query_buffer(&video->queue, buf); return uvc_query_buffer(&stream->queue, buf);
} }
case VIDIOC_QBUF: case VIDIOC_QBUF:
if (!uvc_has_privileges(handle)) if (!uvc_has_privileges(handle))
return -EBUSY; return -EBUSY;
return uvc_queue_buffer(&video->queue, arg); return uvc_queue_buffer(&stream->queue, arg);
case VIDIOC_DQBUF: case VIDIOC_DQBUF:
if (!uvc_has_privileges(handle)) if (!uvc_has_privileges(handle))
return -EBUSY; return -EBUSY;
return uvc_dequeue_buffer(&video->queue, arg, return uvc_dequeue_buffer(&stream->queue, arg,
file->f_flags & O_NONBLOCK); file->f_flags & O_NONBLOCK);
case VIDIOC_STREAMON: case VIDIOC_STREAMON:
{ {
int *type = arg; int *type = arg;
if (*type != video->streaming->type) if (*type != stream->type)
return -EINVAL; return -EINVAL;
if (!uvc_has_privileges(handle)) if (!uvc_has_privileges(handle))
return -EBUSY; return -EBUSY;
if ((ret = uvc_video_enable(video, 1)) < 0) ret = uvc_video_enable(stream, 1);
if (ret < 0)
return ret; return ret;
break; break;
} }
@ -933,13 +939,13 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
{ {
int *type = arg; int *type = arg;
if (*type != video->streaming->type) if (*type != stream->type)
return -EINVAL; return -EINVAL;
if (!uvc_has_privileges(handle)) if (!uvc_has_privileges(handle))
return -EBUSY; return -EBUSY;
return uvc_video_enable(video, 0); return uvc_video_enable(stream, 0);
} }
/* Analog video standards make no sense for digital cameras. */ /* Analog video standards make no sense for digital cameras. */
@ -1070,7 +1076,9 @@ static struct vm_operations_struct uvc_vm_ops = {
static int uvc_v4l2_mmap(struct file *file, struct vm_area_struct *vma) static int uvc_v4l2_mmap(struct file *file, struct vm_area_struct *vma)
{ {
struct uvc_video_device *video = video_drvdata(file); struct uvc_fh *handle = (struct uvc_fh *)file->private_data;
struct uvc_streaming *stream = handle->stream;
struct uvc_video_queue *queue = &stream->queue;
struct uvc_buffer *uninitialized_var(buffer); struct uvc_buffer *uninitialized_var(buffer);
struct page *page; struct page *page;
unsigned long addr, start, size; unsigned long addr, start, size;
@ -1082,15 +1090,15 @@ static int uvc_v4l2_mmap(struct file *file, struct vm_area_struct *vma)
start = vma->vm_start; start = vma->vm_start;
size = vma->vm_end - vma->vm_start; size = vma->vm_end - vma->vm_start;
mutex_lock(&video->queue.mutex); mutex_lock(&queue->mutex);
for (i = 0; i < video->queue.count; ++i) { for (i = 0; i < queue->count; ++i) {
buffer = &video->queue.buffer[i]; buffer = &queue->buffer[i];
if ((buffer->buf.m.offset >> PAGE_SHIFT) == vma->vm_pgoff) if ((buffer->buf.m.offset >> PAGE_SHIFT) == vma->vm_pgoff)
break; break;
} }
if (i == video->queue.count || size != video->queue.buf_size) { if (i == queue->count || size != queue->buf_size) {
ret = -EINVAL; ret = -EINVAL;
goto done; goto done;
} }
@ -1101,7 +1109,7 @@ static int uvc_v4l2_mmap(struct file *file, struct vm_area_struct *vma)
*/ */
vma->vm_flags |= VM_IO; vma->vm_flags |= VM_IO;
addr = (unsigned long)video->queue.mem + buffer->buf.m.offset; addr = (unsigned long)queue->mem + buffer->buf.m.offset;
while (size > 0) { while (size > 0) {
page = vmalloc_to_page((void *)addr); page = vmalloc_to_page((void *)addr);
if ((ret = vm_insert_page(vma, start, page)) < 0) if ((ret = vm_insert_page(vma, start, page)) < 0)
@ -1117,17 +1125,18 @@ static int uvc_v4l2_mmap(struct file *file, struct vm_area_struct *vma)
uvc_vm_open(vma); uvc_vm_open(vma);
done: done:
mutex_unlock(&video->queue.mutex); mutex_unlock(&queue->mutex);
return ret; return ret;
} }
static unsigned int uvc_v4l2_poll(struct file *file, poll_table *wait) static unsigned int uvc_v4l2_poll(struct file *file, poll_table *wait)
{ {
struct uvc_video_device *video = video_drvdata(file); struct uvc_fh *handle = (struct uvc_fh *)file->private_data;
struct uvc_streaming *stream = handle->stream;
uvc_trace(UVC_TRACE_CALLS, "uvc_v4l2_poll\n"); uvc_trace(UVC_TRACE_CALLS, "uvc_v4l2_poll\n");
return uvc_queue_poll(&video->queue, file, wait); return uvc_queue_poll(&stream->queue, file, wait);
} }
const struct v4l2_file_operations uvc_fops = { const struct v4l2_file_operations uvc_fops = {

View File

@ -61,7 +61,7 @@ int uvc_query_ctrl(struct uvc_device *dev, __u8 query, __u8 unit,
return 0; return 0;
} }
static void uvc_fixup_video_ctrl(struct uvc_video_device *video, static void uvc_fixup_video_ctrl(struct uvc_streaming *stream,
struct uvc_streaming_control *ctrl) struct uvc_streaming_control *ctrl)
{ {
struct uvc_format *format; struct uvc_format *format;
@ -69,10 +69,10 @@ static void uvc_fixup_video_ctrl(struct uvc_video_device *video,
unsigned int i; unsigned int i;
if (ctrl->bFormatIndex <= 0 || if (ctrl->bFormatIndex <= 0 ||
ctrl->bFormatIndex > video->streaming->nformats) ctrl->bFormatIndex > stream->nformats)
return; return;
format = &video->streaming->format[ctrl->bFormatIndex - 1]; format = &stream->format[ctrl->bFormatIndex - 1];
for (i = 0; i < format->nframes; ++i) { for (i = 0; i < format->nframes; ++i) {
if (format->frame[i].bFrameIndex == ctrl->bFrameIndex) { if (format->frame[i].bFrameIndex == ctrl->bFrameIndex) {
@ -86,12 +86,12 @@ static void uvc_fixup_video_ctrl(struct uvc_video_device *video,
if (!(format->flags & UVC_FMT_FLAG_COMPRESSED) || if (!(format->flags & UVC_FMT_FLAG_COMPRESSED) ||
(ctrl->dwMaxVideoFrameSize == 0 && (ctrl->dwMaxVideoFrameSize == 0 &&
video->dev->uvc_version < 0x0110)) stream->dev->uvc_version < 0x0110))
ctrl->dwMaxVideoFrameSize = ctrl->dwMaxVideoFrameSize =
frame->dwMaxVideoFrameBufferSize; frame->dwMaxVideoFrameBufferSize;
if (video->dev->quirks & UVC_QUIRK_FIX_BANDWIDTH && if (stream->dev->quirks & UVC_QUIRK_FIX_BANDWIDTH &&
video->streaming->intf->num_altsetting > 1) { stream->intf->num_altsetting > 1) {
u32 interval; u32 interval;
u32 bandwidth; u32 bandwidth;
@ -108,7 +108,7 @@ static void uvc_fixup_video_ctrl(struct uvc_video_device *video,
bandwidth = frame->wWidth * frame->wHeight / 8 * format->bpp; bandwidth = frame->wWidth * frame->wHeight / 8 * format->bpp;
bandwidth *= 10000000 / interval + 1; bandwidth *= 10000000 / interval + 1;
bandwidth /= 1000; bandwidth /= 1000;
if (video->dev->udev->speed == USB_SPEED_HIGH) if (stream->dev->udev->speed == USB_SPEED_HIGH)
bandwidth /= 8; bandwidth /= 8;
bandwidth += 12; bandwidth += 12;
@ -116,14 +116,14 @@ static void uvc_fixup_video_ctrl(struct uvc_video_device *video,
} }
} }
static int uvc_get_video_ctrl(struct uvc_video_device *video, static int uvc_get_video_ctrl(struct uvc_streaming *stream,
struct uvc_streaming_control *ctrl, int probe, __u8 query) struct uvc_streaming_control *ctrl, int probe, __u8 query)
{ {
__u8 *data; __u8 *data;
__u16 size; __u16 size;
int ret; int ret;
size = video->dev->uvc_version >= 0x0110 ? 34 : 26; size = stream->dev->uvc_version >= 0x0110 ? 34 : 26;
data = kmalloc(size, GFP_KERNEL); data = kmalloc(size, GFP_KERNEL);
if (data == NULL) if (data == NULL)
return -ENOMEM; return -ENOMEM;
@ -131,7 +131,7 @@ static int uvc_get_video_ctrl(struct uvc_video_device *video,
if ((video->dev->quirks & UVC_QUIRK_PROBE_DEF) && query == UVC_GET_DEF) if ((video->dev->quirks & UVC_QUIRK_PROBE_DEF) && query == UVC_GET_DEF)
return -EIO; return -EIO;
ret = __uvc_query_ctrl(video->dev, query, 0, video->streaming->intfnum, ret = __uvc_query_ctrl(stream->dev, query, 0, stream->intfnum,
probe ? UVC_VS_PROBE_CONTROL : UVC_VS_COMMIT_CONTROL, data, probe ? UVC_VS_PROBE_CONTROL : UVC_VS_COMMIT_CONTROL, data,
size, UVC_CTRL_STREAMING_TIMEOUT); size, UVC_CTRL_STREAMING_TIMEOUT);
@ -140,7 +140,7 @@ static int uvc_get_video_ctrl(struct uvc_video_device *video,
* answer a GET_MIN or GET_MAX request with the wCompQuality * answer a GET_MIN or GET_MAX request with the wCompQuality
* field only. * field only.
*/ */
uvc_warn_once(video->dev, UVC_WARN_MINMAX, "UVC non " uvc_warn_once(stream->dev, UVC_WARN_MINMAX, "UVC non "
"compliance - GET_MIN/MAX(PROBE) incorrectly " "compliance - GET_MIN/MAX(PROBE) incorrectly "
"supported. Enabling workaround.\n"); "supported. Enabling workaround.\n");
memset(ctrl, 0, sizeof ctrl); memset(ctrl, 0, sizeof ctrl);
@ -152,7 +152,7 @@ static int uvc_get_video_ctrl(struct uvc_video_device *video,
* video probe control. Warn once and return, the caller will * video probe control. Warn once and return, the caller will
* fall back to GET_CUR. * fall back to GET_CUR.
*/ */
uvc_warn_once(video->dev, UVC_WARN_PROBE_DEF, "UVC non " uvc_warn_once(stream->dev, UVC_WARN_PROBE_DEF, "UVC non "
"compliance - GET_DEF(PROBE) not supported. " "compliance - GET_DEF(PROBE) not supported. "
"Enabling workaround.\n"); "Enabling workaround.\n");
ret = -EIO; ret = -EIO;
@ -184,7 +184,7 @@ static int uvc_get_video_ctrl(struct uvc_video_device *video,
ctrl->bMinVersion = data[32]; ctrl->bMinVersion = data[32];
ctrl->bMaxVersion = data[33]; ctrl->bMaxVersion = data[33];
} else { } else {
ctrl->dwClockFrequency = video->dev->clock_frequency; ctrl->dwClockFrequency = stream->dev->clock_frequency;
ctrl->bmFramingInfo = 0; ctrl->bmFramingInfo = 0;
ctrl->bPreferedVersion = 0; ctrl->bPreferedVersion = 0;
ctrl->bMinVersion = 0; ctrl->bMinVersion = 0;
@ -195,7 +195,7 @@ static int uvc_get_video_ctrl(struct uvc_video_device *video,
* dwMaxPayloadTransferSize fields. Try to get the value from the * dwMaxPayloadTransferSize fields. Try to get the value from the
* format and frame descriptors. * format and frame descriptors.
*/ */
uvc_fixup_video_ctrl(video, ctrl); uvc_fixup_video_ctrl(stream, ctrl);
ret = 0; ret = 0;
out: out:
@ -203,14 +203,14 @@ out:
return ret; return ret;
} }
static int uvc_set_video_ctrl(struct uvc_video_device *video, static int uvc_set_video_ctrl(struct uvc_streaming *stream,
struct uvc_streaming_control *ctrl, int probe) struct uvc_streaming_control *ctrl, int probe)
{ {
__u8 *data; __u8 *data;
__u16 size; __u16 size;
int ret; int ret;
size = video->dev->uvc_version >= 0x0110 ? 34 : 26; size = stream->dev->uvc_version >= 0x0110 ? 34 : 26;
data = kzalloc(size, GFP_KERNEL); data = kzalloc(size, GFP_KERNEL);
if (data == NULL) if (data == NULL)
return -ENOMEM; return -ENOMEM;
@ -235,8 +235,7 @@ static int uvc_set_video_ctrl(struct uvc_video_device *video,
data[33] = ctrl->bMaxVersion; data[33] = ctrl->bMaxVersion;
} }
ret = __uvc_query_ctrl(video->dev, UVC_SET_CUR, 0, ret = __uvc_query_ctrl(stream->dev, UVC_SET_CUR, 0, stream->intfnum,
video->streaming->intfnum,
probe ? UVC_VS_PROBE_CONTROL : UVC_VS_COMMIT_CONTROL, data, probe ? UVC_VS_PROBE_CONTROL : UVC_VS_COMMIT_CONTROL, data,
size, UVC_CTRL_STREAMING_TIMEOUT); size, UVC_CTRL_STREAMING_TIMEOUT);
if (ret != size) { if (ret != size) {
@ -250,7 +249,7 @@ static int uvc_set_video_ctrl(struct uvc_video_device *video,
return ret; return ret;
} }
int uvc_probe_video(struct uvc_video_device *video, int uvc_probe_video(struct uvc_streaming *stream,
struct uvc_streaming_control *probe) struct uvc_streaming_control *probe)
{ {
struct uvc_streaming_control probe_min, probe_max; struct uvc_streaming_control probe_min, probe_max;
@ -258,7 +257,7 @@ int uvc_probe_video(struct uvc_video_device *video,
unsigned int i; unsigned int i;
int ret; int ret;
mutex_lock(&video->streaming->mutex); mutex_lock(&stream->mutex);
/* Perform probing. The device should adjust the requested values /* Perform probing. The device should adjust the requested values
* according to its capabilities. However, some devices, namely the * according to its capabilities. However, some devices, namely the
@ -267,15 +266,16 @@ int uvc_probe_video(struct uvc_video_device *video,
* that reason, if the needed bandwidth exceeds the maximum available * that reason, if the needed bandwidth exceeds the maximum available
* bandwidth, try to lower the quality. * bandwidth, try to lower the quality.
*/ */
if ((ret = uvc_set_video_ctrl(video, probe, 1)) < 0) ret = uvc_set_video_ctrl(stream, probe, 1);
if (ret < 0)
goto done; goto done;
/* Get the minimum and maximum values for compression settings. */ /* Get the minimum and maximum values for compression settings. */
if (!(video->dev->quirks & UVC_QUIRK_PROBE_MINMAX)) { if (!(stream->dev->quirks & UVC_QUIRK_PROBE_MINMAX)) {
ret = uvc_get_video_ctrl(video, &probe_min, 1, UVC_GET_MIN); ret = uvc_get_video_ctrl(stream, &probe_min, 1, UVC_GET_MIN);
if (ret < 0) if (ret < 0)
goto done; goto done;
ret = uvc_get_video_ctrl(video, &probe_max, 1, UVC_GET_MAX); ret = uvc_get_video_ctrl(stream, &probe_max, 1, UVC_GET_MAX);
if (ret < 0) if (ret < 0)
goto done; goto done;
@ -283,21 +283,21 @@ int uvc_probe_video(struct uvc_video_device *video,
} }
for (i = 0; i < 2; ++i) { for (i = 0; i < 2; ++i) {
ret = uvc_set_video_ctrl(video, probe, 1); ret = uvc_set_video_ctrl(stream, probe, 1);
if (ret < 0) if (ret < 0)
goto done; goto done;
ret = uvc_get_video_ctrl(video, probe, 1, UVC_GET_CUR); ret = uvc_get_video_ctrl(stream, probe, 1, UVC_GET_CUR);
if (ret < 0) if (ret < 0)
goto done; goto done;
if (video->streaming->intf->num_altsetting == 1) if (stream->intf->num_altsetting == 1)
break; break;
bandwidth = probe->dwMaxPayloadTransferSize; bandwidth = probe->dwMaxPayloadTransferSize;
if (bandwidth <= video->streaming->maxpsize) if (bandwidth <= stream->maxpsize)
break; break;
if (video->dev->quirks & UVC_QUIRK_PROBE_MINMAX) { if (stream->dev->quirks & UVC_QUIRK_PROBE_MINMAX) {
ret = -ENOSPC; ret = -ENOSPC;
goto done; goto done;
} }
@ -310,14 +310,14 @@ int uvc_probe_video(struct uvc_video_device *video,
} }
done: done:
mutex_unlock(&video->streaming->mutex); mutex_unlock(&stream->mutex);
return ret; return ret;
} }
int uvc_commit_video(struct uvc_video_device *video, int uvc_commit_video(struct uvc_streaming *stream,
struct uvc_streaming_control *probe) struct uvc_streaming_control *probe)
{ {
return uvc_set_video_ctrl(video, probe, 0); return uvc_set_video_ctrl(stream, probe, 0);
} }
/* ------------------------------------------------------------------------ /* ------------------------------------------------------------------------
@ -369,7 +369,7 @@ int uvc_commit_video(struct uvc_video_device *video,
* to be called with a NULL buf parameter. uvc_video_decode_data and * to be called with a NULL buf parameter. uvc_video_decode_data and
* uvc_video_decode_end will never be called with a NULL buffer. * uvc_video_decode_end will never be called with a NULL buffer.
*/ */
static int uvc_video_decode_start(struct uvc_video_device *video, static int uvc_video_decode_start(struct uvc_streaming *stream,
struct uvc_buffer *buf, const __u8 *data, int len) struct uvc_buffer *buf, const __u8 *data, int len)
{ {
__u8 fid; __u8 fid;
@ -395,25 +395,25 @@ static int uvc_video_decode_start(struct uvc_video_device *video,
* NULL. * NULL.
*/ */
if (buf == NULL) { if (buf == NULL) {
video->last_fid = fid; stream->last_fid = fid;
return -ENODATA; return -ENODATA;
} }
/* Synchronize to the input stream by waiting for the FID bit to be /* Synchronize to the input stream by waiting for the FID bit to be
* toggled when the the buffer state is not UVC_BUF_STATE_ACTIVE. * toggled when the the buffer state is not UVC_BUF_STATE_ACTIVE.
* video->last_fid is initialized to -1, so the first isochronous * stream->last_fid is initialized to -1, so the first isochronous
* frame will always be in sync. * frame will always be in sync.
* *
* If the device doesn't toggle the FID bit, invert video->last_fid * If the device doesn't toggle the FID bit, invert stream->last_fid
* when the EOF bit is set to force synchronisation on the next packet. * when the EOF bit is set to force synchronisation on the next packet.
*/ */
if (buf->state != UVC_BUF_STATE_ACTIVE) { if (buf->state != UVC_BUF_STATE_ACTIVE) {
if (fid == video->last_fid) { if (fid == stream->last_fid) {
uvc_trace(UVC_TRACE_FRAME, "Dropping payload (out of " uvc_trace(UVC_TRACE_FRAME, "Dropping payload (out of "
"sync).\n"); "sync).\n");
if ((video->dev->quirks & UVC_QUIRK_STREAM_NO_FID) && if ((stream->dev->quirks & UVC_QUIRK_STREAM_NO_FID) &&
(data[1] & UVC_STREAM_EOF)) (data[1] & UVC_STREAM_EOF))
video->last_fid ^= UVC_STREAM_FID; stream->last_fid ^= UVC_STREAM_FID;
return -ENODATA; return -ENODATA;
} }
@ -428,7 +428,7 @@ static int uvc_video_decode_start(struct uvc_video_device *video,
* last payload can be lost anyway). We thus must check if the FID has * last payload can be lost anyway). We thus must check if the FID has
* been toggled. * been toggled.
* *
* video->last_fid is initialized to -1, so the first isochronous * stream->last_fid is initialized to -1, so the first isochronous
* frame will never trigger an end of frame detection. * frame will never trigger an end of frame detection.
* *
* Empty buffers (bytesused == 0) don't trigger end of frame detection * Empty buffers (bytesused == 0) don't trigger end of frame detection
@ -436,22 +436,22 @@ static int uvc_video_decode_start(struct uvc_video_device *video,
* avoids detecting end of frame conditions at FID toggling if the * avoids detecting end of frame conditions at FID toggling if the
* previous payload had the EOF bit set. * previous payload had the EOF bit set.
*/ */
if (fid != video->last_fid && buf->buf.bytesused != 0) { if (fid != stream->last_fid && buf->buf.bytesused != 0) {
uvc_trace(UVC_TRACE_FRAME, "Frame complete (FID bit " uvc_trace(UVC_TRACE_FRAME, "Frame complete (FID bit "
"toggled).\n"); "toggled).\n");
buf->state = UVC_BUF_STATE_DONE; buf->state = UVC_BUF_STATE_DONE;
return -EAGAIN; return -EAGAIN;
} }
video->last_fid = fid; stream->last_fid = fid;
return data[0]; return data[0];
} }
static void uvc_video_decode_data(struct uvc_video_device *video, static void uvc_video_decode_data(struct uvc_streaming *stream,
struct uvc_buffer *buf, const __u8 *data, int len) struct uvc_buffer *buf, const __u8 *data, int len)
{ {
struct uvc_video_queue *queue = &video->queue; struct uvc_video_queue *queue = &stream->queue;
unsigned int maxlen, nbytes; unsigned int maxlen, nbytes;
void *mem; void *mem;
@ -472,7 +472,7 @@ static void uvc_video_decode_data(struct uvc_video_device *video,
} }
} }
static void uvc_video_decode_end(struct uvc_video_device *video, static void uvc_video_decode_end(struct uvc_streaming *stream,
struct uvc_buffer *buf, const __u8 *data, int len) struct uvc_buffer *buf, const __u8 *data, int len)
{ {
/* Mark the buffer as done if the EOF marker is set. */ /* Mark the buffer as done if the EOF marker is set. */
@ -481,8 +481,8 @@ static void uvc_video_decode_end(struct uvc_video_device *video,
if (data[0] == len) if (data[0] == len)
uvc_trace(UVC_TRACE_FRAME, "EOF in empty payload.\n"); uvc_trace(UVC_TRACE_FRAME, "EOF in empty payload.\n");
buf->state = UVC_BUF_STATE_DONE; buf->state = UVC_BUF_STATE_DONE;
if (video->dev->quirks & UVC_QUIRK_STREAM_NO_FID) if (stream->dev->quirks & UVC_QUIRK_STREAM_NO_FID)
video->last_fid ^= UVC_STREAM_FID; stream->last_fid ^= UVC_STREAM_FID;
} }
} }
@ -497,26 +497,26 @@ static void uvc_video_decode_end(struct uvc_video_device *video,
* uvc_video_encode_data is called for every URB and copies the data from the * uvc_video_encode_data is called for every URB and copies the data from the
* video buffer to the transfer buffer. * video buffer to the transfer buffer.
*/ */
static int uvc_video_encode_header(struct uvc_video_device *video, static int uvc_video_encode_header(struct uvc_streaming *stream,
struct uvc_buffer *buf, __u8 *data, int len) struct uvc_buffer *buf, __u8 *data, int len)
{ {
data[0] = 2; /* Header length */ data[0] = 2; /* Header length */
data[1] = UVC_STREAM_EOH | UVC_STREAM_EOF data[1] = UVC_STREAM_EOH | UVC_STREAM_EOF
| (video->last_fid & UVC_STREAM_FID); | (stream->last_fid & UVC_STREAM_FID);
return 2; return 2;
} }
static int uvc_video_encode_data(struct uvc_video_device *video, static int uvc_video_encode_data(struct uvc_streaming *stream,
struct uvc_buffer *buf, __u8 *data, int len) struct uvc_buffer *buf, __u8 *data, int len)
{ {
struct uvc_video_queue *queue = &video->queue; struct uvc_video_queue *queue = &stream->queue;
unsigned int nbytes; unsigned int nbytes;
void *mem; void *mem;
/* Copy video data to the URB buffer. */ /* Copy video data to the URB buffer. */
mem = queue->mem + buf->buf.m.offset + queue->buf_used; mem = queue->mem + buf->buf.m.offset + queue->buf_used;
nbytes = min((unsigned int)len, buf->buf.bytesused - queue->buf_used); nbytes = min((unsigned int)len, buf->buf.bytesused - queue->buf_used);
nbytes = min(video->bulk.max_payload_size - video->bulk.payload_size, nbytes = min(stream->bulk.max_payload_size - stream->bulk.payload_size,
nbytes); nbytes);
memcpy(data, mem, nbytes); memcpy(data, mem, nbytes);
@ -532,8 +532,8 @@ static int uvc_video_encode_data(struct uvc_video_device *video,
/* /*
* Completion handler for video URBs. * Completion handler for video URBs.
*/ */
static void uvc_video_decode_isoc(struct urb *urb, static void uvc_video_decode_isoc(struct urb *urb, struct uvc_streaming *stream,
struct uvc_video_device *video, struct uvc_buffer *buf) struct uvc_buffer *buf)
{ {
u8 *mem; u8 *mem;
int ret, i; int ret, i;
@ -548,31 +548,32 @@ static void uvc_video_decode_isoc(struct urb *urb,
/* Decode the payload header. */ /* Decode the payload header. */
mem = urb->transfer_buffer + urb->iso_frame_desc[i].offset; mem = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
do { do {
ret = uvc_video_decode_start(video, buf, mem, ret = uvc_video_decode_start(stream, buf, mem,
urb->iso_frame_desc[i].actual_length); urb->iso_frame_desc[i].actual_length);
if (ret == -EAGAIN) if (ret == -EAGAIN)
buf = uvc_queue_next_buffer(&video->queue, buf); buf = uvc_queue_next_buffer(&stream->queue,
buf);
} while (ret == -EAGAIN); } while (ret == -EAGAIN);
if (ret < 0) if (ret < 0)
continue; continue;
/* Decode the payload data. */ /* Decode the payload data. */
uvc_video_decode_data(video, buf, mem + ret, uvc_video_decode_data(stream, buf, mem + ret,
urb->iso_frame_desc[i].actual_length - ret); urb->iso_frame_desc[i].actual_length - ret);
/* Process the header again. */ /* Process the header again. */
uvc_video_decode_end(video, buf, mem, uvc_video_decode_end(stream, buf, mem,
urb->iso_frame_desc[i].actual_length); urb->iso_frame_desc[i].actual_length);
if (buf->state == UVC_BUF_STATE_DONE || if (buf->state == UVC_BUF_STATE_DONE ||
buf->state == UVC_BUF_STATE_ERROR) buf->state == UVC_BUF_STATE_ERROR)
buf = uvc_queue_next_buffer(&video->queue, buf); buf = uvc_queue_next_buffer(&stream->queue, buf);
} }
} }
static void uvc_video_decode_bulk(struct urb *urb, static void uvc_video_decode_bulk(struct urb *urb, struct uvc_streaming *stream,
struct uvc_video_device *video, struct uvc_buffer *buf) struct uvc_buffer *buf)
{ {
u8 *mem; u8 *mem;
int len, ret; int len, ret;
@ -582,24 +583,25 @@ static void uvc_video_decode_bulk(struct urb *urb,
mem = urb->transfer_buffer; mem = urb->transfer_buffer;
len = urb->actual_length; len = urb->actual_length;
video->bulk.payload_size += len; stream->bulk.payload_size += len;
/* If the URB is the first of its payload, decode and save the /* If the URB is the first of its payload, decode and save the
* header. * header.
*/ */
if (video->bulk.header_size == 0 && !video->bulk.skip_payload) { if (stream->bulk.header_size == 0 && !stream->bulk.skip_payload) {
do { do {
ret = uvc_video_decode_start(video, buf, mem, len); ret = uvc_video_decode_start(stream, buf, mem, len);
if (ret == -EAGAIN) if (ret == -EAGAIN)
buf = uvc_queue_next_buffer(&video->queue, buf); buf = uvc_queue_next_buffer(&stream->queue,
buf);
} while (ret == -EAGAIN); } while (ret == -EAGAIN);
/* If an error occured skip the rest of the payload. */ /* If an error occured skip the rest of the payload. */
if (ret < 0 || buf == NULL) { if (ret < 0 || buf == NULL) {
video->bulk.skip_payload = 1; stream->bulk.skip_payload = 1;
} else { } else {
memcpy(video->bulk.header, mem, ret); memcpy(stream->bulk.header, mem, ret);
video->bulk.header_size = ret; stream->bulk.header_size = ret;
mem += ret; mem += ret;
len -= ret; len -= ret;
@ -612,33 +614,34 @@ static void uvc_video_decode_bulk(struct urb *urb,
*/ */
/* Process video data. */ /* Process video data. */
if (!video->bulk.skip_payload && buf != NULL) if (!stream->bulk.skip_payload && buf != NULL)
uvc_video_decode_data(video, buf, mem, len); uvc_video_decode_data(stream, buf, mem, len);
/* Detect the payload end by a URB smaller than the maximum size (or /* Detect the payload end by a URB smaller than the maximum size (or
* a payload size equal to the maximum) and process the header again. * a payload size equal to the maximum) and process the header again.
*/ */
if (urb->actual_length < urb->transfer_buffer_length || if (urb->actual_length < urb->transfer_buffer_length ||
video->bulk.payload_size >= video->bulk.max_payload_size) { stream->bulk.payload_size >= stream->bulk.max_payload_size) {
if (!video->bulk.skip_payload && buf != NULL) { if (!stream->bulk.skip_payload && buf != NULL) {
uvc_video_decode_end(video, buf, video->bulk.header, uvc_video_decode_end(stream, buf, stream->bulk.header,
video->bulk.payload_size); stream->bulk.payload_size);
if (buf->state == UVC_BUF_STATE_DONE || if (buf->state == UVC_BUF_STATE_DONE ||
buf->state == UVC_BUF_STATE_ERROR) buf->state == UVC_BUF_STATE_ERROR)
buf = uvc_queue_next_buffer(&video->queue, buf); buf = uvc_queue_next_buffer(&stream->queue,
buf);
} }
video->bulk.header_size = 0; stream->bulk.header_size = 0;
video->bulk.skip_payload = 0; stream->bulk.skip_payload = 0;
video->bulk.payload_size = 0; stream->bulk.payload_size = 0;
} }
} }
static void uvc_video_encode_bulk(struct urb *urb, static void uvc_video_encode_bulk(struct urb *urb, struct uvc_streaming *stream,
struct uvc_video_device *video, struct uvc_buffer *buf) struct uvc_buffer *buf)
{ {
u8 *mem = urb->transfer_buffer; u8 *mem = urb->transfer_buffer;
int len = video->urb_size, ret; int len = stream->urb_size, ret;
if (buf == NULL) { if (buf == NULL) {
urb->transfer_buffer_length = 0; urb->transfer_buffer_length = 0;
@ -646,40 +649,40 @@ static void uvc_video_encode_bulk(struct urb *urb,
} }
/* If the URB is the first of its payload, add the header. */ /* If the URB is the first of its payload, add the header. */
if (video->bulk.header_size == 0) { if (stream->bulk.header_size == 0) {
ret = uvc_video_encode_header(video, buf, mem, len); ret = uvc_video_encode_header(stream, buf, mem, len);
video->bulk.header_size = ret; stream->bulk.header_size = ret;
video->bulk.payload_size += ret; stream->bulk.payload_size += ret;
mem += ret; mem += ret;
len -= ret; len -= ret;
} }
/* Process video data. */ /* Process video data. */
ret = uvc_video_encode_data(video, buf, mem, len); ret = uvc_video_encode_data(stream, buf, mem, len);
video->bulk.payload_size += ret; stream->bulk.payload_size += ret;
len -= ret; len -= ret;
if (buf->buf.bytesused == video->queue.buf_used || if (buf->buf.bytesused == stream->queue.buf_used ||
video->bulk.payload_size == video->bulk.max_payload_size) { stream->bulk.payload_size == stream->bulk.max_payload_size) {
if (buf->buf.bytesused == video->queue.buf_used) { if (buf->buf.bytesused == stream->queue.buf_used) {
video->queue.buf_used = 0; stream->queue.buf_used = 0;
buf->state = UVC_BUF_STATE_DONE; buf->state = UVC_BUF_STATE_DONE;
uvc_queue_next_buffer(&video->queue, buf); uvc_queue_next_buffer(&stream->queue, buf);
video->last_fid ^= UVC_STREAM_FID; stream->last_fid ^= UVC_STREAM_FID;
} }
video->bulk.header_size = 0; stream->bulk.header_size = 0;
video->bulk.payload_size = 0; stream->bulk.payload_size = 0;
} }
urb->transfer_buffer_length = video->urb_size - len; urb->transfer_buffer_length = stream->urb_size - len;
} }
static void uvc_video_complete(struct urb *urb) static void uvc_video_complete(struct urb *urb)
{ {
struct uvc_video_device *video = urb->context; struct uvc_streaming *stream = urb->context;
struct uvc_video_queue *queue = &video->queue; struct uvc_video_queue *queue = &stream->queue;
struct uvc_buffer *buf = NULL; struct uvc_buffer *buf = NULL;
unsigned long flags; unsigned long flags;
int ret; int ret;
@ -693,7 +696,7 @@ static void uvc_video_complete(struct urb *urb)
"completion handler.\n", urb->status); "completion handler.\n", urb->status);
case -ENOENT: /* usb_kill_urb() called. */ case -ENOENT: /* usb_kill_urb() called. */
if (video->frozen) if (stream->frozen)
return; return;
case -ECONNRESET: /* usb_unlink_urb() called. */ case -ECONNRESET: /* usb_unlink_urb() called. */
@ -708,7 +711,7 @@ static void uvc_video_complete(struct urb *urb)
queue); queue);
spin_unlock_irqrestore(&queue->irqlock, flags); spin_unlock_irqrestore(&queue->irqlock, flags);
video->decode(urb, video, buf); stream->decode(urb, stream, buf);
if ((ret = usb_submit_urb(urb, GFP_ATOMIC)) < 0) { if ((ret = usb_submit_urb(urb, GFP_ATOMIC)) < 0) {
uvc_printk(KERN_ERR, "Failed to resubmit video URB (%d).\n", uvc_printk(KERN_ERR, "Failed to resubmit video URB (%d).\n",
@ -719,19 +722,19 @@ static void uvc_video_complete(struct urb *urb)
/* /*
* Free transfer buffers. * Free transfer buffers.
*/ */
static void uvc_free_urb_buffers(struct uvc_video_device *video) static void uvc_free_urb_buffers(struct uvc_streaming *stream)
{ {
unsigned int i; unsigned int i;
for (i = 0; i < UVC_URBS; ++i) { for (i = 0; i < UVC_URBS; ++i) {
if (video->urb_buffer[i]) { if (stream->urb_buffer[i]) {
usb_buffer_free(video->dev->udev, video->urb_size, usb_buffer_free(stream->dev->udev, stream->urb_size,
video->urb_buffer[i], video->urb_dma[i]); stream->urb_buffer[i], stream->urb_dma[i]);
video->urb_buffer[i] = NULL; stream->urb_buffer[i] = NULL;
} }
} }
video->urb_size = 0; stream->urb_size = 0;
} }
/* /*
@ -745,15 +748,15 @@ static void uvc_free_urb_buffers(struct uvc_video_device *video)
* *
* Return the number of allocated packets on success or 0 when out of memory. * Return the number of allocated packets on success or 0 when out of memory.
*/ */
static int uvc_alloc_urb_buffers(struct uvc_video_device *video, static int uvc_alloc_urb_buffers(struct uvc_streaming *stream,
unsigned int size, unsigned int psize, gfp_t gfp_flags) unsigned int size, unsigned int psize, gfp_t gfp_flags)
{ {
unsigned int npackets; unsigned int npackets;
unsigned int i; unsigned int i;
/* Buffers are already allocated, bail out. */ /* Buffers are already allocated, bail out. */
if (video->urb_size) if (stream->urb_size)
return video->urb_size / psize; return stream->urb_size / psize;
/* Compute the number of packets. Bulk endpoints might transfer UVC /* Compute the number of packets. Bulk endpoints might transfer UVC
* payloads accross multiple URBs. * payloads accross multiple URBs.
@ -765,17 +768,17 @@ static int uvc_alloc_urb_buffers(struct uvc_video_device *video,
/* Retry allocations until one succeed. */ /* Retry allocations until one succeed. */
for (; npackets > 1; npackets /= 2) { for (; npackets > 1; npackets /= 2) {
for (i = 0; i < UVC_URBS; ++i) { for (i = 0; i < UVC_URBS; ++i) {
video->urb_buffer[i] = usb_buffer_alloc( stream->urb_buffer[i] = usb_buffer_alloc(
video->dev->udev, psize * npackets, stream->dev->udev, psize * npackets,
gfp_flags | __GFP_NOWARN, &video->urb_dma[i]); gfp_flags | __GFP_NOWARN, &stream->urb_dma[i]);
if (!video->urb_buffer[i]) { if (!stream->urb_buffer[i]) {
uvc_free_urb_buffers(video); uvc_free_urb_buffers(stream);
break; break;
} }
} }
if (i == UVC_URBS) { if (i == UVC_URBS) {
video->urb_size = psize * npackets; stream->urb_size = psize * npackets;
return npackets; return npackets;
} }
} }
@ -786,29 +789,30 @@ static int uvc_alloc_urb_buffers(struct uvc_video_device *video,
/* /*
* Uninitialize isochronous/bulk URBs and free transfer buffers. * Uninitialize isochronous/bulk URBs and free transfer buffers.
*/ */
static void uvc_uninit_video(struct uvc_video_device *video, int free_buffers) static void uvc_uninit_video(struct uvc_streaming *stream, int free_buffers)
{ {
struct urb *urb; struct urb *urb;
unsigned int i; unsigned int i;
for (i = 0; i < UVC_URBS; ++i) { for (i = 0; i < UVC_URBS; ++i) {
if ((urb = video->urb[i]) == NULL) urb = stream->urb[i];
if (urb == NULL)
continue; continue;
usb_kill_urb(urb); usb_kill_urb(urb);
usb_free_urb(urb); usb_free_urb(urb);
video->urb[i] = NULL; stream->urb[i] = NULL;
} }
if (free_buffers) if (free_buffers)
uvc_free_urb_buffers(video); uvc_free_urb_buffers(stream);
} }
/* /*
* Initialize isochronous URBs and allocate transfer buffers. The packet size * Initialize isochronous URBs and allocate transfer buffers. The packet size
* is given by the endpoint. * is given by the endpoint.
*/ */
static int uvc_init_video_isoc(struct uvc_video_device *video, static int uvc_init_video_isoc(struct uvc_streaming *stream,
struct usb_host_endpoint *ep, gfp_t gfp_flags) struct usb_host_endpoint *ep, gfp_t gfp_flags)
{ {
struct urb *urb; struct urb *urb;
@ -818,9 +822,9 @@ static int uvc_init_video_isoc(struct uvc_video_device *video,
psize = le16_to_cpu(ep->desc.wMaxPacketSize); psize = le16_to_cpu(ep->desc.wMaxPacketSize);
psize = (psize & 0x07ff) * (1 + ((psize >> 11) & 3)); psize = (psize & 0x07ff) * (1 + ((psize >> 11) & 3));
size = video->streaming->ctrl.dwMaxVideoFrameSize; size = stream->ctrl.dwMaxVideoFrameSize;
npackets = uvc_alloc_urb_buffers(video, size, psize, gfp_flags); npackets = uvc_alloc_urb_buffers(stream, size, psize, gfp_flags);
if (npackets == 0) if (npackets == 0)
return -ENOMEM; return -ENOMEM;
@ -829,18 +833,18 @@ static int uvc_init_video_isoc(struct uvc_video_device *video,
for (i = 0; i < UVC_URBS; ++i) { for (i = 0; i < UVC_URBS; ++i) {
urb = usb_alloc_urb(npackets, gfp_flags); urb = usb_alloc_urb(npackets, gfp_flags);
if (urb == NULL) { if (urb == NULL) {
uvc_uninit_video(video, 1); uvc_uninit_video(stream, 1);
return -ENOMEM; return -ENOMEM;
} }
urb->dev = video->dev->udev; urb->dev = stream->dev->udev;
urb->context = video; urb->context = stream;
urb->pipe = usb_rcvisocpipe(video->dev->udev, urb->pipe = usb_rcvisocpipe(stream->dev->udev,
ep->desc.bEndpointAddress); ep->desc.bEndpointAddress);
urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP; urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
urb->interval = ep->desc.bInterval; urb->interval = ep->desc.bInterval;
urb->transfer_buffer = video->urb_buffer[i]; urb->transfer_buffer = stream->urb_buffer[i];
urb->transfer_dma = video->urb_dma[i]; urb->transfer_dma = stream->urb_dma[i];
urb->complete = uvc_video_complete; urb->complete = uvc_video_complete;
urb->number_of_packets = npackets; urb->number_of_packets = npackets;
urb->transfer_buffer_length = size; urb->transfer_buffer_length = size;
@ -850,7 +854,7 @@ static int uvc_init_video_isoc(struct uvc_video_device *video,
urb->iso_frame_desc[j].length = psize; urb->iso_frame_desc[j].length = psize;
} }
video->urb[i] = urb; stream->urb[i] = urb;
} }
return 0; return 0;
@ -860,7 +864,7 @@ static int uvc_init_video_isoc(struct uvc_video_device *video,
* Initialize bulk URBs and allocate transfer buffers. The packet size is * Initialize bulk URBs and allocate transfer buffers. The packet size is
* given by the endpoint. * given by the endpoint.
*/ */
static int uvc_init_video_bulk(struct uvc_video_device *video, static int uvc_init_video_bulk(struct uvc_streaming *stream,
struct usb_host_endpoint *ep, gfp_t gfp_flags) struct usb_host_endpoint *ep, gfp_t gfp_flags)
{ {
struct urb *urb; struct urb *urb;
@ -869,39 +873,39 @@ static int uvc_init_video_bulk(struct uvc_video_device *video,
u32 size; u32 size;
psize = le16_to_cpu(ep->desc.wMaxPacketSize) & 0x07ff; psize = le16_to_cpu(ep->desc.wMaxPacketSize) & 0x07ff;
size = video->streaming->ctrl.dwMaxPayloadTransferSize; size = stream->ctrl.dwMaxPayloadTransferSize;
video->bulk.max_payload_size = size; stream->bulk.max_payload_size = size;
npackets = uvc_alloc_urb_buffers(video, size, psize, gfp_flags); npackets = uvc_alloc_urb_buffers(stream, size, psize, gfp_flags);
if (npackets == 0) if (npackets == 0)
return -ENOMEM; return -ENOMEM;
size = npackets * psize; size = npackets * psize;
if (usb_endpoint_dir_in(&ep->desc)) if (usb_endpoint_dir_in(&ep->desc))
pipe = usb_rcvbulkpipe(video->dev->udev, pipe = usb_rcvbulkpipe(stream->dev->udev,
ep->desc.bEndpointAddress); ep->desc.bEndpointAddress);
else else
pipe = usb_sndbulkpipe(video->dev->udev, pipe = usb_sndbulkpipe(stream->dev->udev,
ep->desc.bEndpointAddress); ep->desc.bEndpointAddress);
if (video->streaming->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) if (stream->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
size = 0; size = 0;
for (i = 0; i < UVC_URBS; ++i) { for (i = 0; i < UVC_URBS; ++i) {
urb = usb_alloc_urb(0, gfp_flags); urb = usb_alloc_urb(0, gfp_flags);
if (urb == NULL) { if (urb == NULL) {
uvc_uninit_video(video, 1); uvc_uninit_video(stream, 1);
return -ENOMEM; return -ENOMEM;
} }
usb_fill_bulk_urb(urb, video->dev->udev, pipe, usb_fill_bulk_urb(urb, stream->dev->udev, pipe,
video->urb_buffer[i], size, uvc_video_complete, stream->urb_buffer[i], size, uvc_video_complete,
video); stream);
urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP; urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP;
urb->transfer_dma = video->urb_dma[i]; urb->transfer_dma = stream->urb_dma[i];
video->urb[i] = urb; stream->urb[i] = urb;
} }
return 0; return 0;
@ -910,35 +914,35 @@ static int uvc_init_video_bulk(struct uvc_video_device *video,
/* /*
* Initialize isochronous/bulk URBs and allocate transfer buffers. * Initialize isochronous/bulk URBs and allocate transfer buffers.
*/ */
static int uvc_init_video(struct uvc_video_device *video, gfp_t gfp_flags) static int uvc_init_video(struct uvc_streaming *stream, gfp_t gfp_flags)
{ {
struct usb_interface *intf = video->streaming->intf; struct usb_interface *intf = stream->intf;
struct usb_host_interface *alts; struct usb_host_interface *alts;
struct usb_host_endpoint *ep = NULL; struct usb_host_endpoint *ep = NULL;
int intfnum = video->streaming->intfnum; int intfnum = stream->intfnum;
unsigned int bandwidth, psize, i; unsigned int bandwidth, psize, i;
int ret; int ret;
video->last_fid = -1; stream->last_fid = -1;
video->bulk.header_size = 0; stream->bulk.header_size = 0;
video->bulk.skip_payload = 0; stream->bulk.skip_payload = 0;
video->bulk.payload_size = 0; stream->bulk.payload_size = 0;
if (intf->num_altsetting > 1) { if (intf->num_altsetting > 1) {
/* Isochronous endpoint, select the alternate setting. */ /* Isochronous endpoint, select the alternate setting. */
bandwidth = video->streaming->ctrl.dwMaxPayloadTransferSize; bandwidth = stream->ctrl.dwMaxPayloadTransferSize;
if (bandwidth == 0) { if (bandwidth == 0) {
uvc_printk(KERN_WARNING, "device %s requested null " uvc_printk(KERN_WARNING, "device %s requested null "
"bandwidth, defaulting to lowest.\n", "bandwidth, defaulting to lowest.\n",
video->vdev->name); stream->dev->name);
bandwidth = 1; bandwidth = 1;
} }
for (i = 0; i < intf->num_altsetting; ++i) { for (i = 0; i < intf->num_altsetting; ++i) {
alts = &intf->altsetting[i]; alts = &intf->altsetting[i];
ep = uvc_find_endpoint(alts, ep = uvc_find_endpoint(alts,
video->streaming->header.bEndpointAddress); stream->header.bEndpointAddress);
if (ep == NULL) if (ep == NULL)
continue; continue;
@ -952,18 +956,19 @@ static int uvc_init_video(struct uvc_video_device *video, gfp_t gfp_flags)
if (i >= intf->num_altsetting) if (i >= intf->num_altsetting)
return -EIO; return -EIO;
if ((ret = usb_set_interface(video->dev->udev, intfnum, i)) < 0) ret = usb_set_interface(stream->dev->udev, intfnum, i);
if (ret < 0)
return ret; return ret;
ret = uvc_init_video_isoc(video, ep, gfp_flags); ret = uvc_init_video_isoc(stream, ep, gfp_flags);
} else { } else {
/* Bulk endpoint, proceed to URB initialization. */ /* Bulk endpoint, proceed to URB initialization. */
ep = uvc_find_endpoint(&intf->altsetting[0], ep = uvc_find_endpoint(&intf->altsetting[0],
video->streaming->header.bEndpointAddress); stream->header.bEndpointAddress);
if (ep == NULL) if (ep == NULL)
return -EIO; return -EIO;
ret = uvc_init_video_bulk(video, ep, gfp_flags); ret = uvc_init_video_bulk(stream, ep, gfp_flags);
} }
if (ret < 0) if (ret < 0)
@ -971,10 +976,11 @@ static int uvc_init_video(struct uvc_video_device *video, gfp_t gfp_flags)
/* Submit the URBs. */ /* Submit the URBs. */
for (i = 0; i < UVC_URBS; ++i) { for (i = 0; i < UVC_URBS; ++i) {
if ((ret = usb_submit_urb(video->urb[i], gfp_flags)) < 0) { ret = usb_submit_urb(stream->urb[i], gfp_flags);
if (ret < 0) {
uvc_printk(KERN_ERR, "Failed to submit URB %u " uvc_printk(KERN_ERR, "Failed to submit URB %u "
"(%d).\n", i, ret); "(%d).\n", i, ret);
uvc_uninit_video(video, 1); uvc_uninit_video(stream, 1);
return ret; return ret;
} }
} }
@ -993,14 +999,14 @@ static int uvc_init_video(struct uvc_video_device *video, gfp_t gfp_flags)
* video buffers in any way. We mark the device as frozen to make sure the URB * video buffers in any way. We mark the device as frozen to make sure the URB
* completion handler won't try to cancel the queue when we kill the URBs. * completion handler won't try to cancel the queue when we kill the URBs.
*/ */
int uvc_video_suspend(struct uvc_video_device *video) int uvc_video_suspend(struct uvc_streaming *stream)
{ {
if (!uvc_queue_streaming(&video->queue)) if (!uvc_queue_streaming(&stream->queue))
return 0; return 0;
video->frozen = 1; stream->frozen = 1;
uvc_uninit_video(video, 0); uvc_uninit_video(stream, 0);
usb_set_interface(video->dev->udev, video->streaming->intfnum, 0); usb_set_interface(stream->dev->udev, stream->intfnum, 0);
return 0; return 0;
} }
@ -1012,22 +1018,24 @@ int uvc_video_suspend(struct uvc_video_device *video)
* buffers, making sure userspace applications are notified of the problem * buffers, making sure userspace applications are notified of the problem
* instead of waiting forever. * instead of waiting forever.
*/ */
int uvc_video_resume(struct uvc_video_device *video) int uvc_video_resume(struct uvc_streaming *stream)
{ {
int ret; int ret;
video->frozen = 0; stream->frozen = 0;
if ((ret = uvc_commit_video(video, &video->streaming->ctrl)) < 0) { ret = uvc_commit_video(stream, &stream->ctrl);
uvc_queue_enable(&video->queue, 0); if (ret < 0) {
uvc_queue_enable(&stream->queue, 0);
return ret; return ret;
} }
if (!uvc_queue_streaming(&video->queue)) if (!uvc_queue_streaming(&stream->queue))
return 0; return 0;
if ((ret = uvc_init_video(video, GFP_NOIO)) < 0) ret = uvc_init_video(stream, GFP_NOIO);
uvc_queue_enable(&video->queue, 0); if (ret < 0)
uvc_queue_enable(&stream->queue, 0);
return ret; return ret;
} }
@ -1046,48 +1054,53 @@ int uvc_video_resume(struct uvc_video_device *video)
* *
* This function is called before registering the device with V4L. * This function is called before registering the device with V4L.
*/ */
int uvc_video_init(struct uvc_video_device *video) int uvc_video_init(struct uvc_streaming *stream)
{ {
struct uvc_streaming_control *probe = &video->streaming->ctrl; struct uvc_streaming_control *probe = &stream->ctrl;
struct uvc_format *format = NULL; struct uvc_format *format = NULL;
struct uvc_frame *frame = NULL; struct uvc_frame *frame = NULL;
unsigned int i; unsigned int i;
int ret; int ret;
if (video->streaming->nformats == 0) { if (stream->nformats == 0) {
uvc_printk(KERN_INFO, "No supported video formats found.\n"); uvc_printk(KERN_INFO, "No supported video formats found.\n");
return -EINVAL; return -EINVAL;
} }
atomic_set(&stream->active, 0);
/* Initialize the video buffers queue. */
uvc_queue_init(&stream->queue, stream->type);
/* Alternate setting 0 should be the default, yet the XBox Live Vision /* Alternate setting 0 should be the default, yet the XBox Live Vision
* Cam (and possibly other devices) crash or otherwise misbehave if * Cam (and possibly other devices) crash or otherwise misbehave if
* they don't receive a SET_INTERFACE request before any other video * they don't receive a SET_INTERFACE request before any other video
* control request. * control request.
*/ */
usb_set_interface(video->dev->udev, video->streaming->intfnum, 0); usb_set_interface(stream->dev->udev, stream->intfnum, 0);
/* Set the streaming probe control with default streaming parameters /* Set the streaming probe control with default streaming parameters
* retrieved from the device. Webcams that don't suport GET_DEF * retrieved from the device. Webcams that don't suport GET_DEF
* requests on the probe control will just keep their current streaming * requests on the probe control will just keep their current streaming
* parameters. * parameters.
*/ */
if (uvc_get_video_ctrl(video, probe, 1, UVC_GET_DEF) == 0) if (uvc_get_video_ctrl(stream, probe, 1, UVC_GET_DEF) == 0)
uvc_set_video_ctrl(video, probe, 1); uvc_set_video_ctrl(stream, probe, 1);
/* Initialize the streaming parameters with the probe control current /* Initialize the streaming parameters with the probe control current
* value. This makes sure SET_CUR requests on the streaming commit * value. This makes sure SET_CUR requests on the streaming commit
* control will always use values retrieved from a successful GET_CUR * control will always use values retrieved from a successful GET_CUR
* request on the probe control, as required by the UVC specification. * request on the probe control, as required by the UVC specification.
*/ */
ret = uvc_get_video_ctrl(video, probe, 1, UVC_GET_CUR); ret = uvc_get_video_ctrl(stream, probe, 1, UVC_GET_CUR);
if (ret < 0) if (ret < 0)
return ret; return ret;
/* Check if the default format descriptor exists. Use the first /* Check if the default format descriptor exists. Use the first
* available format otherwise. * available format otherwise.
*/ */
for (i = video->streaming->nformats; i > 0; --i) { for (i = stream->nformats; i > 0; --i) {
format = &video->streaming->format[i-1]; format = &stream->format[i-1];
if (format->index == probe->bFormatIndex) if (format->index == probe->bFormatIndex)
break; break;
} }
@ -1112,21 +1125,20 @@ int uvc_video_init(struct uvc_video_device *video)
probe->bFormatIndex = format->index; probe->bFormatIndex = format->index;
probe->bFrameIndex = frame->bFrameIndex; probe->bFrameIndex = frame->bFrameIndex;
video->streaming->cur_format = format; stream->cur_format = format;
video->streaming->cur_frame = frame; stream->cur_frame = frame;
atomic_set(&video->active, 0);
/* Select the video decoding function */ /* Select the video decoding function */
if (video->streaming->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { if (stream->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
if (video->dev->quirks & UVC_QUIRK_BUILTIN_ISIGHT) if (stream->dev->quirks & UVC_QUIRK_BUILTIN_ISIGHT)
video->decode = uvc_video_decode_isight; stream->decode = uvc_video_decode_isight;
else if (video->streaming->intf->num_altsetting > 1) else if (stream->intf->num_altsetting > 1)
video->decode = uvc_video_decode_isoc; stream->decode = uvc_video_decode_isoc;
else else
video->decode = uvc_video_decode_bulk; stream->decode = uvc_video_decode_bulk;
} else { } else {
if (video->streaming->intf->num_altsetting == 1) if (stream->intf->num_altsetting == 1)
video->decode = uvc_video_encode_bulk; stream->decode = uvc_video_encode_bulk;
else { else {
uvc_printk(KERN_INFO, "Isochronous endpoints are not " uvc_printk(KERN_INFO, "Isochronous endpoints are not "
"supported for video output devices.\n"); "supported for video output devices.\n");
@ -1140,31 +1152,32 @@ int uvc_video_init(struct uvc_video_device *video)
/* /*
* Enable or disable the video stream. * Enable or disable the video stream.
*/ */
int uvc_video_enable(struct uvc_video_device *video, int enable) int uvc_video_enable(struct uvc_streaming *stream, int enable)
{ {
int ret; int ret;
if (!enable) { if (!enable) {
uvc_uninit_video(video, 1); uvc_uninit_video(stream, 1);
usb_set_interface(video->dev->udev, usb_set_interface(stream->dev->udev, stream->intfnum, 0);
video->streaming->intfnum, 0); uvc_queue_enable(&stream->queue, 0);
uvc_queue_enable(&video->queue, 0);
return 0; return 0;
} }
if ((video->streaming->cur_format->flags & UVC_FMT_FLAG_COMPRESSED) || if ((stream->cur_format->flags & UVC_FMT_FLAG_COMPRESSED) ||
uvc_no_drop_param) uvc_no_drop_param)
video->queue.flags &= ~UVC_QUEUE_DROP_INCOMPLETE; stream->queue.flags &= ~UVC_QUEUE_DROP_INCOMPLETE;
else else
video->queue.flags |= UVC_QUEUE_DROP_INCOMPLETE; stream->queue.flags |= UVC_QUEUE_DROP_INCOMPLETE;
if ((ret = uvc_queue_enable(&video->queue, 1)) < 0) ret = uvc_queue_enable(&stream->queue, 1);
if (ret < 0)
return ret; return ret;
/* Commit the streaming parameters. */ /* Commit the streaming parameters. */
if ((ret = uvc_commit_video(video, &video->streaming->ctrl)) < 0) ret = uvc_commit_video(stream, &stream->ctrl);
if (ret < 0)
return ret; return ret;
return uvc_init_video(video, GFP_KERNEL); return uvc_init_video(stream, GFP_KERNEL);
} }

View File

@ -361,26 +361,6 @@ struct uvc_streaming_header {
__u8 bTriggerUsage; __u8 bTriggerUsage;
}; };
struct uvc_streaming {
struct list_head list;
struct usb_interface *intf;
int intfnum;
__u16 maxpsize;
struct uvc_streaming_header header;
enum v4l2_buf_type type;
unsigned int nformats;
struct uvc_format *format;
struct uvc_streaming_control ctrl;
struct uvc_format *cur_format;
struct uvc_frame *cur_frame;
struct mutex mutex;
};
enum uvc_buffer_state { enum uvc_buffer_state {
UVC_BUF_STATE_IDLE = 0, UVC_BUF_STATE_IDLE = 0,
UVC_BUF_STATE_QUEUED = 1, UVC_BUF_STATE_QUEUED = 1,
@ -422,26 +402,31 @@ struct uvc_video_queue {
struct list_head irqqueue; struct list_head irqqueue;
}; };
struct uvc_video_device { struct uvc_streaming {
struct list_head list;
struct uvc_device *dev; struct uvc_device *dev;
struct video_device *vdev; struct video_device *vdev;
atomic_t active; atomic_t active;
struct usb_interface *intf;
int intfnum;
__u16 maxpsize;
struct uvc_streaming_header header;
enum v4l2_buf_type type;
unsigned int nformats;
struct uvc_format *format;
struct uvc_streaming_control ctrl;
struct uvc_format *cur_format;
struct uvc_frame *cur_frame;
struct mutex mutex;
unsigned int frozen : 1; unsigned int frozen : 1;
struct list_head iterms; /* Input terminals */
struct uvc_entity *oterm; /* Output terminal */
struct uvc_entity *sterm; /* USB streaming terminal */
struct uvc_entity *processing;
struct uvc_entity *selector;
struct list_head extensions;
struct mutex ctrl_mutex;
struct uvc_video_queue queue; struct uvc_video_queue queue;
void (*decode) (struct urb *urb, struct uvc_streaming *video,
/* Video streaming object, must always be non-NULL. */
struct uvc_streaming *streaming;
void (*decode) (struct urb *urb, struct uvc_video_device *video,
struct uvc_buffer *buf); struct uvc_buffer *buf);
/* Context data used by the bulk completion handler. */ /* Context data used by the bulk completion handler. */
@ -461,6 +446,18 @@ struct uvc_video_device {
__u8 last_fid; __u8 last_fid;
}; };
struct uvc_video_device {
struct uvc_device *dev;
struct list_head iterms; /* Input terminals */
struct uvc_entity *oterm; /* Output terminal */
struct uvc_entity *sterm; /* USB streaming terminal */
struct uvc_entity *processing;
struct uvc_entity *selector;
struct list_head extensions;
struct mutex ctrl_mutex;
};
enum uvc_device_state { enum uvc_device_state {
UVC_DEV_DISCONNECTED = 1, UVC_DEV_DISCONNECTED = 1,
}; };
@ -486,15 +483,15 @@ struct uvc_device {
struct uvc_video_device video; struct uvc_video_device video;
/* Video Streaming interfaces */
struct list_head streams;
/* Status Interrupt Endpoint */ /* Status Interrupt Endpoint */
struct usb_host_endpoint *int_ep; struct usb_host_endpoint *int_ep;
struct urb *int_urb; struct urb *int_urb;
__u8 *status; __u8 *status;
struct input_dev *input; struct input_dev *input;
char input_phys[64]; char input_phys[64];
/* Video Streaming interfaces */
struct list_head streaming;
}; };
enum uvc_handle_state { enum uvc_handle_state {
@ -503,7 +500,8 @@ enum uvc_handle_state {
}; };
struct uvc_fh { struct uvc_fh {
struct uvc_video_device *device; struct uvc_video_device *video;
struct uvc_streaming *stream;
enum uvc_handle_state state; enum uvc_handle_state state;
}; };
@ -600,13 +598,13 @@ static inline int uvc_queue_streaming(struct uvc_video_queue *queue)
extern const struct v4l2_file_operations uvc_fops; extern const struct v4l2_file_operations uvc_fops;
/* Video */ /* Video */
extern int uvc_video_init(struct uvc_video_device *video); extern int uvc_video_init(struct uvc_streaming *stream);
extern int uvc_video_suspend(struct uvc_video_device *video); extern int uvc_video_suspend(struct uvc_streaming *stream);
extern int uvc_video_resume(struct uvc_video_device *video); extern int uvc_video_resume(struct uvc_streaming *stream);
extern int uvc_video_enable(struct uvc_video_device *video, int enable); extern int uvc_video_enable(struct uvc_streaming *stream, int enable);
extern int uvc_probe_video(struct uvc_video_device *video, extern int uvc_probe_video(struct uvc_streaming *stream,
struct uvc_streaming_control *probe); struct uvc_streaming_control *probe);
extern int uvc_commit_video(struct uvc_video_device *video, extern int uvc_commit_video(struct uvc_streaming *stream,
struct uvc_streaming_control *ctrl); struct uvc_streaming_control *ctrl);
extern int uvc_query_ctrl(struct uvc_device *dev, __u8 query, __u8 unit, extern int uvc_query_ctrl(struct uvc_device *dev, __u8 query, __u8 unit,
__u8 intfnum, __u8 cs, void *data, __u16 size); __u8 intfnum, __u8 cs, void *data, __u16 size);
@ -660,7 +658,7 @@ extern struct usb_host_endpoint *uvc_find_endpoint(
struct usb_host_interface *alts, __u8 epaddr); struct usb_host_interface *alts, __u8 epaddr);
/* Quirks support */ /* Quirks support */
void uvc_video_decode_isight(struct urb *urb, struct uvc_video_device *video, void uvc_video_decode_isight(struct urb *urb, struct uvc_streaming *stream,
struct uvc_buffer *buf); struct uvc_buffer *buf);
#endif /* __KERNEL__ */ #endif /* __KERNEL__ */