Merge master.kernel.org:/home/rmk/linux-2.6-arm
[safe/jmp/linux-2.6] / drivers / media / video / uvc / uvc_v4l2.c
index 624bf74..a2bdd80 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *      uvc_v4l2.c  --  USB Video Class driver - V4L2 API
  *
- *      Copyright (C) 2005-2008
+ *      Copyright (C) 2005-2009
  *          Laurent Pinchart (laurent.pinchart@skynet.be)
  *
  *      This program is free software; you can redistribute it and/or modify
  * must be grouped (for instance the Red Balance, Blue Balance and Do White
  * Balance V4L2 controls use the White Balance Component UVC control) or
  * otherwise translated. The approach we take here is to use a translation
- * table for the controls which can be mapped directly, and handle the others
+ * table for the controls that can be mapped directly, and handle the others
  * manually.
  */
-static int uvc_v4l2_query_menu(struct uvc_video_device *video,
+static int uvc_v4l2_query_menu(struct uvc_video_chain *chain,
        struct v4l2_querymenu *query_menu)
 {
        struct uvc_menu_info *menu_info;
        struct uvc_control_mapping *mapping;
        struct uvc_control *ctrl;
+       u32 index = query_menu->index;
+       u32 id = query_menu->id;
 
-       ctrl = uvc_find_control(video, query_menu->id, &mapping);
+       ctrl = uvc_find_control(chain, query_menu->id, &mapping);
        if (ctrl == NULL || mapping->v4l2_type != V4L2_CTRL_TYPE_MENU)
                return -EINVAL;
 
        if (query_menu->index >= mapping->menu_count)
                return -EINVAL;
 
+       memset(query_menu, 0, sizeof(*query_menu));
+       query_menu->id = id;
+       query_menu->index = index;
+
        menu_info = &mapping->menu_info[query_menu->index];
-       strncpy(query_menu->name, menu_info->name, 32);
+       strlcpy(query_menu->name, menu_info->name, sizeof query_menu->name);
        return 0;
 }
 
@@ -97,7 +103,7 @@ static __u32 uvc_try_frame_interval(struct uvc_frame *frame, __u32 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 uvc_format **uvc_format, struct uvc_frame **uvc_frame)
 {
@@ -110,7 +116,7 @@ static int uvc_v4l2_try_format(struct uvc_video_device *video,
        int ret = 0;
        __u8 *fcc;
 
-       if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+       if (fmt->type != stream->type)
                return -EINVAL;
 
        fcc = (__u8 *)&fmt->fmt.pix.pixelformat;
@@ -120,8 +126,8 @@ static int uvc_v4l2_try_format(struct uvc_video_device *video,
                        fmt->fmt.pix.width, fmt->fmt.pix.height);
 
        /* Check if the hardware supports the requested format. */
-       for (i = 0; i < video->streaming->nformats; ++i) {
-               format = &video->streaming->format[i];
+       for (i = 0; i < stream->nformats; ++i) {
+               format = &stream->format[i];
                if (format->fcc == fmt->fmt.pix.pixelformat)
                        break;
        }
@@ -185,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
         * the Windows driver).
         */
-       if (video->dev->quirks & UVC_QUIRK_PROBE_EXTRAFIELDS)
+       if (stream->dev->quirks & UVC_QUIRK_PROBE_EXTRAFIELDS)
                probe->dwMaxVideoFrameSize =
-                       video->streaming->ctrl.dwMaxVideoFrameSize;
+                       stream->ctrl.dwMaxVideoFrameSize;
 
-       /* Probe the device */
-       if ((ret = uvc_probe_video(video, probe)) < 0)
+       /* Probe the device. */
+       ret = uvc_probe_video(stream, probe);
+       if (ret < 0)
                goto done;
 
        fmt->fmt.pix.width = frame->wWidth;
@@ -210,13 +217,13 @@ done:
        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 uvc_format *format = video->streaming->cur_format;
-       struct uvc_frame *frame = video->streaming->cur_frame;
+       struct uvc_format *format = stream->cur_format;
+       struct uvc_frame *frame = stream->cur_frame;
 
-       if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+       if (fmt->type != stream->type)
                return -EINVAL;
 
        if (format == NULL || frame == NULL)
@@ -227,14 +234,14 @@ static int uvc_v4l2_get_format(struct uvc_video_device *video,
        fmt->fmt.pix.height = frame->wHeight;
        fmt->fmt.pix.field = V4L2_FIELD_NONE;
        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.priv = 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 uvc_streaming_control probe;
@@ -242,91 +249,100 @@ static int uvc_v4l2_set_format(struct uvc_video_device *video,
        struct uvc_frame *frame;
        int ret;
 
-       if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+       if (fmt->type != stream->type)
                return -EINVAL;
 
-       if (uvc_queue_streaming(&video->queue))
+       if (uvc_queue_allocated(&stream->queue))
                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)
                return ret;
 
-       if ((ret = uvc_commit_video(video, &probe)) < 0)
-               return ret;
-
-       memcpy(&video->streaming->ctrl, &probe, sizeof probe);
-       video->streaming->cur_format = format;
-       video->streaming->cur_frame = frame;
+       memcpy(&stream->ctrl, &probe, sizeof probe);
+       stream->cur_format = format;
+       stream->cur_frame = frame;
 
        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)
 {
        uint32_t numerator, denominator;
 
-       if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+       if (parm->type != stream->type)
                return -EINVAL;
 
-       numerator = video->streaming->ctrl.dwFrameInterval;
+       numerator = stream->ctrl.dwFrameInterval;
        denominator = 10000000;
        uvc_simplify_fraction(&numerator, &denominator, 8, 333);
 
        memset(parm, 0, sizeof *parm);
-       parm->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-       parm->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
-       parm->parm.capture.capturemode = 0;
-       parm->parm.capture.timeperframe.numerator = numerator;
-       parm->parm.capture.timeperframe.denominator = denominator;
-       parm->parm.capture.extendedmode = 0;
-       parm->parm.capture.readbuffers = 0;
+       parm->type = stream->type;
+
+       if (stream->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+               parm->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
+               parm->parm.capture.capturemode = 0;
+               parm->parm.capture.timeperframe.numerator = numerator;
+               parm->parm.capture.timeperframe.denominator = denominator;
+               parm->parm.capture.extendedmode = 0;
+               parm->parm.capture.readbuffers = 0;
+       } else {
+               parm->parm.output.capability = V4L2_CAP_TIMEPERFRAME;
+               parm->parm.output.outputmode = 0;
+               parm->parm.output.timeperframe.numerator = numerator;
+               parm->parm.output.timeperframe.denominator = denominator;
+       }
 
        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 uvc_frame *frame = video->streaming->cur_frame;
+       struct uvc_frame *frame = stream->cur_frame;
        struct uvc_streaming_control probe;
+       struct v4l2_fract timeperframe;
        uint32_t interval;
        int ret;
 
-       if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+       if (parm->type != stream->type)
                return -EINVAL;
 
-       if (uvc_queue_streaming(&video->queue))
+       if (uvc_queue_streaming(&stream->queue))
                return -EBUSY;
 
-       memcpy(&probe, &video->streaming->ctrl, sizeof probe);
-       interval = uvc_fraction_to_interval(
-                       parm->parm.capture.timeperframe.numerator,
-                       parm->parm.capture.timeperframe.denominator);
+       if (parm->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               timeperframe = parm->parm.capture.timeperframe;
+       else
+               timeperframe = parm->parm.output.timeperframe;
+
+       memcpy(&probe, &stream->ctrl, sizeof probe);
+       interval = uvc_fraction_to_interval(timeperframe.numerator,
+               timeperframe.denominator);
 
        uvc_trace(UVC_TRACE_FORMAT, "Setting frame interval to %u/%u (%u).\n",
-                       parm->parm.capture.timeperframe.numerator,
-                       parm->parm.capture.timeperframe.denominator,
-                       interval);
+               timeperframe.numerator, timeperframe.denominator, interval);
        probe.dwFrameInterval = uvc_try_frame_interval(frame, interval);
 
        /* Probe the device with the new settings. */
-       if ((ret = uvc_probe_video(video, &probe)) < 0)
-               return ret;
-
-       /* Commit the new settings. */
-       if ((ret = uvc_commit_video(video, &probe)) < 0)
+       ret = uvc_probe_video(stream, &probe);
+       if (ret < 0)
                return ret;
 
-       memcpy(&video->streaming->ctrl, &probe, sizeof probe);
+       memcpy(&stream->ctrl, &probe, sizeof probe);
 
        /* Return the actual frame period. */
-       parm->parm.capture.timeperframe.numerator = probe.dwFrameInterval;
-       parm->parm.capture.timeperframe.denominator = 10000000;
-       uvc_simplify_fraction(&parm->parm.capture.timeperframe.numerator,
-                               &parm->parm.capture.timeperframe.denominator,
-                               8, 333);
+       timeperframe.numerator = probe.dwFrameInterval;
+       timeperframe.denominator = 10000000;
+       uvc_simplify_fraction(&timeperframe.numerator,
+               &timeperframe.denominator, 8, 333);
+
+       if (parm->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               parm->parm.capture.timeperframe = timeperframe;
+       else
+               parm->parm.output.timeperframe = timeperframe;
 
        return 0;
 }
@@ -346,11 +362,11 @@ static int uvc_v4l2_set_streamparm(struct uvc_video_device *video,
  *
  * Each open instance of a UVC device can either be in a privileged or
  * unprivileged state. Only a single instance can be in a privileged state at
- * a given time. Trying to perform an operation which requires privileges will
+ * a given time. Trying to perform an operation that requires privileges will
  * automatically acquire the required privileges if possible, or return -EBUSY
  * otherwise. Privileges are dismissed when closing the instance.
  *
- * Operations which require privileges are:
+ * Operations that require privileges are:
  *
  * - VIDIOC_S_INPUT
  * - VIDIOC_S_PARM
@@ -368,8 +384,8 @@ static int uvc_acquire_privileges(struct uvc_fh *handle)
 
        /* Check if the device already has a privileged handle. */
        mutex_lock(&uvc_driver.open_mutex);
-       if (atomic_inc_return(&handle->device->active) != 1) {
-               atomic_dec(&handle->device->active);
+       if (atomic_inc_return(&handle->stream->active) != 1) {
+               atomic_dec(&handle->stream->active);
                ret = -EBUSY;
                goto done;
        }
@@ -384,7 +400,7 @@ done:
 static void uvc_dismiss_privileges(struct uvc_fh *handle)
 {
        if (handle->state == UVC_HANDLE_ACTIVE)
-               atomic_dec(&handle->device->active);
+               atomic_dec(&handle->stream->active);
 
        handle->state = UVC_HANDLE_PASSIVE;
 }
@@ -398,60 +414,71 @@ static int uvc_has_privileges(struct uvc_fh *handle)
  * V4L2 file operations
  */
 
-static int uvc_v4l2_open(struct inode *inode, struct file *file)
+static int uvc_v4l2_open(struct file *file)
 {
-       struct uvc_video_device *video;
+       struct uvc_streaming *stream;
        struct uvc_fh *handle;
        int ret = 0;
 
        uvc_trace(UVC_TRACE_CALLS, "uvc_v4l2_open\n");
        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;
                goto done;
        }
 
-       ret = usb_autopm_get_interface(video->dev->intf);
+       ret = usb_autopm_get_interface(stream->dev->intf);
        if (ret < 0)
                goto done;
 
        /* Create the device handle. */
        handle = kzalloc(sizeof *handle, GFP_KERNEL);
        if (handle == NULL) {
-               usb_autopm_put_interface(video->dev->intf);
+               usb_autopm_put_interface(stream->dev->intf);
                ret = -ENOMEM;
                goto done;
        }
 
-       handle->device = video;
+       if (atomic_inc_return(&stream->dev->users) == 1) {
+               ret = uvc_status_start(stream->dev);
+               if (ret < 0) {
+                       usb_autopm_put_interface(stream->dev->intf);
+                       atomic_dec(&stream->dev->users);
+                       kfree(handle);
+                       goto done;
+               }
+       }
+
+       handle->chain = stream->chain;
+       handle->stream = stream;
        handle->state = UVC_HANDLE_PASSIVE;
        file->private_data = handle;
 
-       kref_get(&video->dev->kref);
+       kref_get(&stream->dev->kref);
 
 done:
        mutex_unlock(&uvc_driver.open_mutex);
        return ret;
 }
 
-static int uvc_v4l2_release(struct inode *inode, 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_streaming *stream = handle->stream;
 
        uvc_trace(UVC_TRACE_CALLS, "uvc_v4l2_release\n");
 
        /* Only free resources if this is a privileged handle. */
        if (uvc_has_privileges(handle)) {
-               uvc_video_enable(video, 0);
+               uvc_video_enable(stream, 0);
 
-               mutex_lock(&video->queue.mutex);
-               if (uvc_free_buffers(&video->queue) < 0)
+               mutex_lock(&stream->queue.mutex);
+               if (uvc_free_buffers(&stream->queue) < 0)
                        uvc_printk(KERN_ERR, "uvc_v4l2_release: Unable to "
                                        "free buffers.\n");
-               mutex_unlock(&video->queue.mutex);
+               mutex_unlock(&stream->queue.mutex);
        }
 
        /* Release the file handle. */
@@ -459,20 +486,21 @@ static int uvc_v4l2_release(struct inode *inode, struct file *file)
        kfree(handle);
        file->private_data = NULL;
 
-       usb_autopm_put_interface(video->dev->intf);
-       kref_put(&video->dev->kref, uvc_delete);
+       if (atomic_dec_return(&stream->dev->users) == 0)
+               uvc_status_stop(stream->dev);
+
+       usb_autopm_put_interface(stream->dev->intf);
+       kref_put(&stream->dev->kref, uvc_delete);
        return 0;
 }
 
-static int 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 uvc_video_device *video = video_get_drvdata(vdev);
        struct uvc_fh *handle = (struct uvc_fh *)file->private_data;
-       int ret = 0;
-
-       if (uvc_trace_param & UVC_TRACE_IOCTL)
-               v4l_printk_ioctl(cmd);
+       struct uvc_video_chain *chain = handle->chain;
+       struct uvc_streaming *stream = handle->stream;
+       long ret = 0;
 
        switch (cmd) {
        /* Query capabilities */
@@ -481,19 +509,23 @@ static int uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
                struct v4l2_capability *cap = arg;
 
                memset(cap, 0, sizeof *cap);
-               strncpy(cap->driver, "uvcvideo", sizeof cap->driver);
-               strncpy(cap->card, vdev->name, 32);
-               strncpy(cap->bus_info, video->dev->udev->bus->bus_name,
-                       sizeof cap->bus_info);
+               strlcpy(cap->driver, "uvcvideo", sizeof cap->driver);
+               strlcpy(cap->card, vdev->name, sizeof cap->card);
+               usb_make_path(stream->dev->udev,
+                             cap->bus_info, sizeof(cap->bus_info));
                cap->version = DRIVER_VERSION_NUMBER;
-               cap->capabilities = V4L2_CAP_VIDEO_CAPTURE
-                                 | V4L2_CAP_STREAMING;
+               if (stream->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+                       cap->capabilities = V4L2_CAP_VIDEO_CAPTURE
+                                         | V4L2_CAP_STREAMING;
+               else
+                       cap->capabilities = V4L2_CAP_VIDEO_OUTPUT
+                                         | V4L2_CAP_STREAMING;
                break;
        }
 
        /* Get, Set & Query control */
        case VIDIOC_QUERYCTRL:
-               return uvc_query_v4l2_ctrl(video, arg);
+               return uvc_query_v4l2_ctrl(chain, arg);
 
        case VIDIOC_G_CTRL:
        {
@@ -503,9 +535,12 @@ static int uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
                memset(&xctrl, 0, sizeof xctrl);
                xctrl.id = ctrl->id;
 
-               uvc_ctrl_begin(video);
-               ret = uvc_ctrl_get(video, &xctrl);
-               uvc_ctrl_rollback(video);
+               ret = uvc_ctrl_begin(chain);
+               if (ret < 0)
+                       return ret;
+
+               ret = uvc_ctrl_get(chain, &xctrl);
+               uvc_ctrl_rollback(chain);
                if (ret >= 0)
                        ctrl->value = xctrl.value;
                break;
@@ -520,18 +555,21 @@ static int uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
                xctrl.id = ctrl->id;
                xctrl.value = ctrl->value;
 
-               uvc_ctrl_begin(video);
-               ret = uvc_ctrl_set(video, &xctrl);
+               uvc_ctrl_begin(chain);
+               if (ret < 0)
+                       return ret;
+
+               ret = uvc_ctrl_set(chain, &xctrl);
                if (ret < 0) {
-                       uvc_ctrl_rollback(video);
+                       uvc_ctrl_rollback(chain);
                        return ret;
                }
-               ret = uvc_ctrl_commit(video);
+               ret = uvc_ctrl_commit(chain);
                break;
        }
 
        case VIDIOC_QUERYMENU:
-               return uvc_v4l2_query_menu(video, arg);
+               return uvc_v4l2_query_menu(chain, arg);
 
        case VIDIOC_G_EXT_CTRLS:
        {
@@ -539,17 +577,20 @@ static int uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
                struct v4l2_ext_control *ctrl = ctrls->controls;
                unsigned int i;
 
-               uvc_ctrl_begin(video);
+               ret = uvc_ctrl_begin(chain);
+               if (ret < 0)
+                       return ret;
+
                for (i = 0; i < ctrls->count; ++ctrl, ++i) {
-                       ret = uvc_ctrl_get(video, ctrl);
+                       ret = uvc_ctrl_get(chain, ctrl);
                        if (ret < 0) {
-                               uvc_ctrl_rollback(video);
+                               uvc_ctrl_rollback(chain);
                                ctrls->error_idx = i;
                                return ret;
                        }
                }
                ctrls->error_idx = 0;
-               ret = uvc_ctrl_rollback(video);
+               ret = uvc_ctrl_rollback(chain);
                break;
        }
 
@@ -560,14 +601,14 @@ static int uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
                struct v4l2_ext_control *ctrl = ctrls->controls;
                unsigned int i;
 
-               ret = uvc_ctrl_begin(video);
+               ret = uvc_ctrl_begin(chain);
                if (ret < 0)
                        return ret;
 
                for (i = 0; i < ctrls->count; ++ctrl, ++i) {
-                       ret = uvc_ctrl_set(video, ctrl);
+                       ret = uvc_ctrl_set(chain, ctrl);
                        if (ret < 0) {
-                               uvc_ctrl_rollback(video);
+                               uvc_ctrl_rollback(chain);
                                ctrls->error_idx = i;
                                return ret;
                        }
@@ -576,31 +617,31 @@ static int uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
                ctrls->error_idx = 0;
 
                if (cmd == VIDIOC_S_EXT_CTRLS)
-                       ret = uvc_ctrl_commit(video);
+                       ret = uvc_ctrl_commit(chain);
                else
-                       ret = uvc_ctrl_rollback(video);
+                       ret = uvc_ctrl_rollback(chain);
                break;
        }
 
        /* Get, Set & Enum input */
        case VIDIOC_ENUMINPUT:
        {
-               const struct uvc_entity *selector = video->selector;
+               const struct uvc_entity *selector = chain->selector;
                struct v4l2_input *input = arg;
                struct uvc_entity *iterm = NULL;
                u32 index = input->index;
                int pin = 0;
 
                if (selector == NULL ||
-                   (video->dev->quirks & UVC_QUIRK_IGNORE_SELECTOR_UNIT)) {
+                   (chain->dev->quirks & UVC_QUIRK_IGNORE_SELECTOR_UNIT)) {
                        if (index != 0)
                                return -EINVAL;
-                       iterm = list_first_entry(&video->iterms,
+                       iterm = list_first_entry(&chain->iterms,
                                        struct uvc_entity, chain);
                        pin = iterm->id;
                } else if (pin < selector->selector.bNrInPins) {
                        pin = selector->selector.baSourceID[index];
-                       list_for_each_entry(iterm, video->iterms.next, chain) {
+                       list_for_each_entry(iterm, chain->iterms.next, chain) {
                                if (iterm->id == pin)
                                        break;
                        }
@@ -611,8 +652,8 @@ static int uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
 
                memset(input, 0, sizeof *input);
                input->index = index;
-               strncpy(input->name, iterm->name, sizeof input->name);
-               if (UVC_ENTITY_TYPE(iterm) == ITT_CAMERA)
+               strlcpy(input->name, iterm->name, sizeof input->name);
+               if (UVC_ENTITY_TYPE(iterm) == UVC_ITT_CAMERA)
                        input->type = V4L2_INPUT_TYPE_CAMERA;
                break;
        }
@@ -621,15 +662,15 @@ static int uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
        {
                u8 input;
 
-               if (video->selector == NULL ||
-                   (video->dev->quirks & UVC_QUIRK_IGNORE_SELECTOR_UNIT)) {
+               if (chain->selector == NULL ||
+                   (chain->dev->quirks & UVC_QUIRK_IGNORE_SELECTOR_UNIT)) {
                        *(int *)arg = 0;
                        break;
                }
 
-               ret = uvc_query_ctrl(video->dev, GET_CUR, video->selector->id,
-                       video->dev->intfnum, SU_INPUT_SELECT_CONTROL,
-                       &input, 1);
+               ret = uvc_query_ctrl(chain->dev, UVC_GET_CUR,
+                       chain->selector->id, chain->dev->intfnum,
+                       UVC_SU_INPUT_SELECT_CONTROL, &input, 1);
                if (ret < 0)
                        return ret;
 
@@ -639,24 +680,24 @@ static int uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
 
        case VIDIOC_S_INPUT:
        {
-               u8 input = *(u32 *)arg + 1;
+               u32 input = *(u32 *)arg + 1;
 
                if ((ret = uvc_acquire_privileges(handle)) < 0)
                        return ret;
 
-               if (video->selector == NULL ||
-                   (video->dev->quirks & UVC_QUIRK_IGNORE_SELECTOR_UNIT)) {
+               if (chain->selector == NULL ||
+                   (chain->dev->quirks & UVC_QUIRK_IGNORE_SELECTOR_UNIT)) {
                        if (input != 1)
                                return -EINVAL;
                        break;
                }
 
-               if (input > video->selector->selector.bNrInPins)
+               if (input == 0 || input > chain->selector->selector.bNrInPins)
                        return -EINVAL;
 
-               return uvc_query_ctrl(video->dev, SET_CUR, video->selector->id,
-                       video->dev->intfnum, SU_INPUT_SELECT_CONTROL,
-                       &input, 1);
+               return uvc_query_ctrl(chain->dev, UVC_SET_CUR,
+                       chain->selector->id, chain->dev->intfnum,
+                       UVC_SU_INPUT_SELECT_CONTROL, &input, 1);
        }
 
        /* Try, Get, Set & Enum format */
@@ -664,16 +705,22 @@ static int uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
        {
                struct v4l2_fmtdesc *fmt = arg;
                struct uvc_format *format;
+               enum v4l2_buf_type type = fmt->type;
+               __u32 index = fmt->index;
 
-               if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
-                   fmt->index >= video->streaming->nformats)
+               if (fmt->type != stream->type ||
+                   fmt->index >= stream->nformats)
                        return -EINVAL;
 
-               format = &video->streaming->format[fmt->index];
+               memset(fmt, 0, sizeof(*fmt));
+               fmt->index = index;
+               fmt->type = type;
+
+               format = &stream->format[fmt->index];
                fmt->flags = 0;
                if (format->flags & UVC_FMT_FLAG_COMPRESSED)
                        fmt->flags |= V4L2_FMT_FLAG_COMPRESSED;
-               strncpy(fmt->description, format->name,
+               strlcpy(fmt->description, format->name,
                        sizeof fmt->description);
                fmt->description[sizeof fmt->description - 1] = 0;
                fmt->pixelformat = format->fcc;
@@ -687,17 +734,17 @@ static int uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
                if ((ret = uvc_acquire_privileges(handle)) < 0)
                        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:
                if ((ret = uvc_acquire_privileges(handle)) < 0)
                        return ret;
 
-               return uvc_v4l2_set_format(video, arg);
+               return uvc_v4l2_set_format(stream, arg);
 
        case VIDIOC_G_FMT:
-               return uvc_v4l2_get_format(video, arg);
+               return uvc_v4l2_get_format(stream, arg);
 
        /* Frame size enumeration */
        case VIDIOC_ENUM_FRAMESIZES:
@@ -708,10 +755,10 @@ static int uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
                int i;
 
                /* Look for the given pixel format */
-               for (i = 0; i < video->streaming->nformats; i++) {
-                       if (video->streaming->format[i].fcc ==
+               for (i = 0; i < stream->nformats; i++) {
+                       if (stream->format[i].fcc ==
                                        fsize->pixel_format) {
-                               format = &video->streaming->format[i];
+                               format = &stream->format[i];
                                break;
                        }
                }
@@ -737,10 +784,10 @@ static int uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
                int i;
 
                /* Look for the given pixel format and frame size */
-               for (i = 0; i < video->streaming->nformats; i++) {
-                       if (video->streaming->format[i].fcc ==
+               for (i = 0; i < stream->nformats; i++) {
+                       if (stream->format[i].fcc ==
                                        fival->pixel_format) {
-                               format = &video->streaming->format[i];
+                               format = &stream->format[i];
                                break;
                        }
                }
@@ -790,21 +837,21 @@ static int uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
 
        /* Get & Set streaming parameters */
        case VIDIOC_G_PARM:
-               return uvc_v4l2_get_streamparm(video, arg);
+               return uvc_v4l2_get_streamparm(stream, arg);
 
        case VIDIOC_S_PARM:
                if ((ret = uvc_acquire_privileges(handle)) < 0)
                        return ret;
 
-               return uvc_v4l2_set_streamparm(video, arg);
+               return uvc_v4l2_set_streamparm(stream, arg);
 
        /* Cropping and scaling */
        case VIDIOC_CROPCAP:
        {
                struct v4l2_cropcap *ccap = arg;
-               struct uvc_frame *frame = video->streaming->cur_frame;
+               struct uvc_frame *frame = stream->cur_frame;
 
-               if (ccap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               if (ccap->type != stream->type)
                        return -EINVAL;
 
                ccap->bounds.left = 0;
@@ -828,16 +875,16 @@ static int uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
        {
                struct v4l2_requestbuffers *rb = arg;
                unsigned int bufsize =
-                       video->streaming->ctrl.dwMaxVideoFrameSize;
+                       stream->ctrl.dwMaxVideoFrameSize;
 
-               if (rb->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+               if (rb->type != stream->type ||
                    rb->memory != V4L2_MEMORY_MMAP)
                        return -EINVAL;
 
                if ((ret = uvc_acquire_privileges(handle)) < 0)
                        return ret;
 
-               ret = uvc_alloc_buffers(&video->queue, rb->count, bufsize);
+               ret = uvc_alloc_buffers(&stream->queue, rb->count, bufsize);
                if (ret < 0)
                        return ret;
 
@@ -850,39 +897,40 @@ static int uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
        {
                struct v4l2_buffer *buf = arg;
 
-               if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               if (buf->type != stream->type)
                        return -EINVAL;
 
                if (!uvc_has_privileges(handle))
                        return -EBUSY;
 
-               return uvc_query_buffer(&video->queue, buf);
+               return uvc_query_buffer(&stream->queue, buf);
        }
 
        case VIDIOC_QBUF:
                if (!uvc_has_privileges(handle))
                        return -EBUSY;
 
-               return uvc_queue_buffer(&video->queue, arg);
+               return uvc_queue_buffer(&stream->queue, arg);
 
        case VIDIOC_DQBUF:
                if (!uvc_has_privileges(handle))
                        return -EBUSY;
 
-               return uvc_dequeue_buffer(&video->queue, arg,
+               return uvc_dequeue_buffer(&stream->queue, arg,
                        file->f_flags & O_NONBLOCK);
 
        case VIDIOC_STREAMON:
        {
                int *type = arg;
 
-               if (*type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               if (*type != stream->type)
                        return -EINVAL;
 
                if (!uvc_has_privileges(handle))
                        return -EBUSY;
 
-               if ((ret = uvc_video_enable(video, 1)) < 0)
+               ret = uvc_video_enable(stream, 1);
+               if (ret < 0)
                        return ret;
                break;
        }
@@ -891,13 +939,13 @@ static int uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
        {
                int *type = arg;
 
-               if (*type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               if (*type != stream->type)
                        return -EINVAL;
 
                if (!uvc_has_privileges(handle))
                        return -EBUSY;
 
-               return uvc_video_enable(video, 0);
+               return uvc_video_enable(stream, 0);
        }
 
        /* Analog video standards make no sense for digital cameras. */
@@ -924,7 +972,7 @@ static int uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
                if (!capable(CAP_SYS_ADMIN))
                        return -EPERM;
 
-               info = kmalloc(sizeof *info, GFP_KERNEL);
+               info = kzalloc(sizeof *info, GFP_KERNEL);
                if (info == NULL)
                        return -ENOMEM;
 
@@ -951,7 +999,7 @@ static int uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
                if (!capable(CAP_SYS_ADMIN))
                        return -EPERM;
 
-               map = kmalloc(sizeof *map, GFP_KERNEL);
+               map = kzalloc(sizeof *map, GFP_KERNEL);
                if (map == NULL)
                        return -ENOMEM;
 
@@ -971,10 +1019,10 @@ static int uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
        }
 
        case UVCIOC_CTRL_GET:
-               return uvc_xu_ctrl_query(video, arg, 0);
+               return uvc_xu_ctrl_query(chain, arg, 0);
 
        case UVCIOC_CTRL_SET:
-               return uvc_xu_ctrl_query(video, arg, 1);
+               return uvc_xu_ctrl_query(chain, arg, 1);
 
        default:
                if ((ret = v4l_compat_translate_ioctl(file, cmd, arg,
@@ -987,10 +1035,15 @@ static int uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
        return ret;
 }
 
-static int uvc_v4l2_ioctl(struct inode *inode, struct file *file,
+static long uvc_v4l2_ioctl(struct file *file,
                     unsigned int cmd, unsigned long arg)
 {
-       uvc_trace(UVC_TRACE_CALLS, "uvc_v4l2_ioctl\n");
+       if (uvc_trace_param & UVC_TRACE_IOCTL) {
+               uvc_printk(KERN_DEBUG, "uvc_v4l2_ioctl(");
+               v4l_printk_ioctl(cmd);
+               printk(")\n");
+       }
+
        return video_usercopy(file, cmd, arg, uvc_v4l2_do_ioctl);
 }
 
@@ -1016,14 +1069,16 @@ static void uvc_vm_close(struct vm_area_struct *vma)
        buffer->vma_use_count--;
 }
 
-static struct vm_operations_struct uvc_vm_ops = {
+static const struct vm_operations_struct uvc_vm_ops = {
        .open           = uvc_vm_open,
        .close          = uvc_vm_close,
 };
 
 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 page *page;
        unsigned long addr, start, size;
@@ -1035,15 +1090,15 @@ static int uvc_v4l2_mmap(struct file *file, struct vm_area_struct *vma)
        start = 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) {
-               buffer = &video->queue.buffer[i];
+       for (i = 0; i < queue->count; ++i) {
+               buffer = &queue->buffer[i];
                if ((buffer->buf.m.offset >> PAGE_SHIFT) == vma->vm_pgoff)
                        break;
        }
 
-       if (i == video->queue.count || size != video->queue.buf_size) {
+       if (i == queue->count || size != queue->buf_size) {
                ret = -EINVAL;
                goto done;
        }
@@ -1054,7 +1109,7 @@ static int uvc_v4l2_mmap(struct file *file, struct vm_area_struct *vma)
         */
        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) {
                page = vmalloc_to_page((void *)addr);
                if ((ret = vm_insert_page(vma, start, page)) < 0)
@@ -1070,26 +1125,25 @@ static int uvc_v4l2_mmap(struct file *file, struct vm_area_struct *vma)
        uvc_vm_open(vma);
 
 done:
-       mutex_unlock(&video->queue.mutex);
+       mutex_unlock(&queue->mutex);
        return ret;
 }
 
 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");
 
-       return uvc_queue_poll(&video->queue, file, wait);
+       return uvc_queue_poll(&stream->queue, file, wait);
 }
 
-struct file_operations uvc_fops = {
+const struct v4l2_file_operations uvc_fops = {
        .owner          = THIS_MODULE,
        .open           = uvc_v4l2_open,
        .release        = uvc_v4l2_release,
        .ioctl          = uvc_v4l2_ioctl,
-       .compat_ioctl   = v4l_compat_ioctl32,
-       .llseek         = no_llseek,
        .read           = uvc_v4l2_read,
        .mmap           = uvc_v4l2_mmap,
        .poll           = uvc_v4l2_poll,