diff options
Diffstat (limited to 'drivers/media/usb/uvc')
-rw-r--r-- | drivers/media/usb/uvc/uvc_ctrl.c | 56 | ||||
-rw-r--r-- | drivers/media/usb/uvc/uvc_driver.c | 115 | ||||
-rw-r--r-- | drivers/media/usb/uvc/uvc_entity.c | 4 | ||||
-rw-r--r-- | drivers/media/usb/uvc/uvc_metadata.c | 71 | ||||
-rw-r--r-- | drivers/media/usb/uvc/uvc_status.c | 7 | ||||
-rw-r--r-- | drivers/media/usb/uvc/uvc_v4l2.c | 128 | ||||
-rw-r--r-- | drivers/media/usb/uvc/uvc_video.c | 10 | ||||
-rw-r--r-- | drivers/media/usb/uvc/uvcvideo.h | 21 |
8 files changed, 209 insertions, 203 deletions
diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c index efe609d70877..2905505c240c 100644 --- a/drivers/media/usb/uvc/uvc_ctrl.c +++ b/drivers/media/usb/uvc/uvc_ctrl.c @@ -376,6 +376,15 @@ static const struct uvc_control_info uvc_ctrls[] = { | UVC_CTRL_FLAG_GET_DEF | UVC_CTRL_FLAG_AUTO_UPDATE, }, + { + .entity = UVC_GUID_CHROMEOS_XU, + .selector = UVC_CROSXU_CONTROL_IQ_PROFILE, + .index = 3, + .size = 1, + .flags = UVC_CTRL_FLAG_SET_CUR + | UVC_CTRL_FLAG_GET_RANGE + | UVC_CTRL_FLAG_RESTORE, + }, }; static const u32 uvc_control_classes[] = { @@ -384,6 +393,19 @@ static const u32 uvc_control_classes[] = { }; static const int exposure_auto_mapping[] = { 2, 1, 4, 8 }; +static const int cros_colorfx_mapping[] = { + 1, /* V4L2_COLORFX_NONE */ + -1, /* V4L2_COLORFX_BW */ + -1, /* V4L2_COLORFX_SEPIA */ + -1, /* V4L2_COLORFX_NEGATIVE */ + -1, /* V4L2_COLORFX_EMBOSS */ + -1, /* V4L2_COLORFX_SKETCH */ + -1, /* V4L2_COLORFX_SKY_BLUE */ + -1, /* V4L2_COLORFX_GRASS_GREEN */ + -1, /* V4L2_COLORFX_SKIN_WHITEN */ + 0, /* V4L2_COLORFX_VIVID */ +}; + static bool uvc_ctrl_mapping_is_compound(struct uvc_control_mapping *mapping) { @@ -975,6 +997,18 @@ static const struct uvc_control_mapping uvc_ctrl_mappings[] = { .data_type = UVC_CTRL_DATA_TYPE_BITMASK, .name = "Region of Interest Auto Ctrls", }, + { + .id = V4L2_CID_COLORFX, + .entity = UVC_GUID_CHROMEOS_XU, + .selector = UVC_CROSXU_CONTROL_IQ_PROFILE, + .size = 8, + .offset = 0, + .v4l2_type = V4L2_CTRL_TYPE_MENU, + .data_type = UVC_CTRL_DATA_TYPE_ENUM, + .menu_mapping = cros_colorfx_mapping, + .menu_mask = BIT(V4L2_COLORFX_VIVID) | + BIT(V4L2_COLORFX_NONE), + }, }; /* ------------------------------------------------------------------------ @@ -1619,7 +1653,7 @@ static int __uvc_query_v4l2_ctrl(struct uvc_video_chain *chain, } if (ret == -EIO) { - dev_warn_ratelimited(&chain->dev->udev->dev, + dev_warn_ratelimited(&chain->dev->intf->dev, "UVC non compliance: Error %d querying master control %x (%s)\n", ret, master_map->id, uvc_map_get_name(master_map)); @@ -1643,7 +1677,7 @@ static int __uvc_query_v4l2_ctrl(struct uvc_video_chain *chain, ret = __uvc_queryctrl_boundaries(chain, ctrl, mapping, v4l2_ctrl); if (ret && !mapping->disabled) { - dev_warn(&chain->dev->udev->dev, + dev_warn(&chain->dev->intf->dev, "UVC non compliance: permanently disabling control %x (%s), due to error %d\n", mapping->id, uvc_map_get_name(mapping), ret); mapping->disabled = true; @@ -1858,7 +1892,7 @@ static int uvc_ctrl_set_handle(struct uvc_control *ctrl, struct uvc_fh *handle) lockdep_assert_held(&handle->chain->ctrl_mutex); if (ctrl->handle) { - dev_warn_ratelimited(&handle->stream->dev->udev->dev, + dev_warn_ratelimited(&handle->stream->dev->intf->dev, "UVC non compliance: Setting an async control with a pending operation."); if (ctrl->handle == handle) @@ -1956,7 +1990,7 @@ static void uvc_ctrl_status_event_work(struct work_struct *work) w->urb->interval = dev->int_ep->desc.bInterval; ret = usb_submit_urb(w->urb, GFP_KERNEL); if (ret < 0) - dev_err(&dev->udev->dev, + dev_err(&dev->intf->dev, "Failed to resubmit status URB (%d).\n", ret); } @@ -2895,7 +2929,7 @@ int uvc_ctrl_restore_values(struct uvc_device *dev) if (!ctrl->initialized || !ctrl->modified || (ctrl->info.flags & UVC_CTRL_FLAG_RESTORE) == 0) continue; - dev_dbg(&dev->udev->dev, + dev_dbg(&dev->intf->dev, "restoring control %pUl/%u/%u\n", ctrl->info.entity, ctrl->info.index, ctrl->info.selector); @@ -3181,15 +3215,6 @@ static void uvc_ctrl_init_ctrl(struct uvc_video_chain *chain, { unsigned int i; - /* - * XU controls initialization requires querying the device for control - * information. As some buggy UVC devices will crash when queried - * repeatedly in a tight loop, delay XU controls initialization until - * first use. - */ - if (UVC_ENTITY_TYPE(ctrl->entity) == UVC_VC_EXTENSION_UNIT) - return; - for (i = 0; i < ARRAY_SIZE(uvc_ctrls); ++i) { const struct uvc_control_info *info = &uvc_ctrls[i]; @@ -3307,7 +3332,6 @@ int uvc_ctrl_init_device(struct uvc_device *dev) void uvc_ctrl_cleanup_fh(struct uvc_fh *handle) { struct uvc_entity *entity; - int i; guard(mutex)(&handle->chain->ctrl_mutex); @@ -3325,7 +3349,7 @@ void uvc_ctrl_cleanup_fh(struct uvc_fh *handle) if (!WARN_ON(handle->pending_async_ctrls)) return; - for (i = 0; i < handle->pending_async_ctrls; i++) + for (unsigned int i = 0; i < handle->pending_async_ctrls; i++) uvc_pm_put(handle->stream->dev); } diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c index 775bede0d93d..fa61f1d0ea2c 100644 --- a/drivers/media/usb/uvc/uvc_driver.c +++ b/drivers/media/usb/uvc/uvc_driver.c @@ -137,6 +137,9 @@ struct uvc_entity *uvc_entity_by_id(struct uvc_device *dev, int id) { struct uvc_entity *entity; + if (id == UVC_INVALID_ENTITY_ID) + return NULL; + list_for_each_entry(entity, &dev->entities, list) { if (entity->id == id) return entity; @@ -183,8 +186,6 @@ static void uvc_stream_delete(struct uvc_streaming *stream) if (stream->async_wq) destroy_workqueue(stream->async_wq); - mutex_destroy(&stream->mutex); - usb_put_intf(stream->intf); kfree(stream->formats); @@ -201,8 +202,6 @@ static struct uvc_streaming *uvc_stream_new(struct uvc_device *dev, if (stream == NULL) return NULL; - mutex_init(&stream->mutex); - stream->dev = dev; stream->intf = usb_get_intf(intf); stream->intfnum = intf->cur_altsetting->desc.bInterfaceNumber; @@ -795,14 +794,27 @@ static const u8 uvc_media_transport_input_guid[16] = UVC_GUID_UVC_MEDIA_TRANSPORT_INPUT; static const u8 uvc_processing_guid[16] = UVC_GUID_UVC_PROCESSING; -static struct uvc_entity *uvc_alloc_entity(u16 type, u16 id, - unsigned int num_pads, unsigned int extra_size) +static struct uvc_entity *uvc_alloc_new_entity(struct uvc_device *dev, u16 type, + u16 id, unsigned int num_pads, + unsigned int extra_size) { struct uvc_entity *entity; unsigned int num_inputs; unsigned int size; unsigned int i; + /* Per UVC 1.1+ spec 3.7.2, the ID should be non-zero. */ + if (id == 0) { + dev_err(&dev->intf->dev, "Found Unit with invalid ID 0\n"); + id = UVC_INVALID_ENTITY_ID; + } + + /* Per UVC 1.1+ spec 3.7.2, the ID is unique. */ + if (uvc_entity_by_id(dev, id)) { + dev_err(&dev->intf->dev, "Found multiple Units with ID %u\n", id); + id = UVC_INVALID_ENTITY_ID; + } + extra_size = roundup(extra_size, sizeof(*entity->pads)); if (num_pads) num_inputs = type & UVC_TERM_OUTPUT ? num_pads : num_pads - 1; @@ -812,7 +824,7 @@ static struct uvc_entity *uvc_alloc_entity(u16 type, u16 id, + num_inputs; entity = kzalloc(size, GFP_KERNEL); if (entity == NULL) - return NULL; + return ERR_PTR(-ENOMEM); entity->id = id; entity->type = type; @@ -882,7 +894,7 @@ static int uvc_parse_vendor_control(struct uvc_device *dev, unsigned int n, p; int handled = 0; - switch (le16_to_cpu(dev->udev->descriptor.idVendor)) { + switch (le16_to_cpu(udev->descriptor.idVendor)) { case 0x046d: /* Logitech */ if (buffer[1] != 0x41 || buffer[2] != 0x01) break; @@ -924,10 +936,10 @@ static int uvc_parse_vendor_control(struct uvc_device *dev, break; } - unit = uvc_alloc_entity(UVC_VC_EXTENSION_UNIT, buffer[3], - p + 1, 2*n); - if (unit == NULL) - return -ENOMEM; + unit = uvc_alloc_new_entity(dev, UVC_VC_EXTENSION_UNIT, + buffer[3], p + 1, 2 * n); + if (IS_ERR(unit)) + return PTR_ERR(unit); memcpy(unit->guid, &buffer[4], 16); unit->extension.bNumControls = buffer[20]; @@ -1036,10 +1048,10 @@ static int uvc_parse_standard_control(struct uvc_device *dev, return -EINVAL; } - term = uvc_alloc_entity(type | UVC_TERM_INPUT, buffer[3], - 1, n + p); - if (term == NULL) - return -ENOMEM; + term = uvc_alloc_new_entity(dev, type | UVC_TERM_INPUT, + buffer[3], 1, n + p); + if (IS_ERR(term)) + return PTR_ERR(term); if (UVC_ENTITY_TYPE(term) == UVC_ITT_CAMERA) { term->camera.bControlSize = n; @@ -1095,10 +1107,10 @@ static int uvc_parse_standard_control(struct uvc_device *dev, return 0; } - term = uvc_alloc_entity(type | UVC_TERM_OUTPUT, buffer[3], - 1, 0); - if (term == NULL) - return -ENOMEM; + term = uvc_alloc_new_entity(dev, type | UVC_TERM_OUTPUT, + buffer[3], 1, 0); + if (IS_ERR(term)) + return PTR_ERR(term); memcpy(term->baSourceID, &buffer[7], 1); @@ -1117,9 +1129,10 @@ static int uvc_parse_standard_control(struct uvc_device *dev, return -EINVAL; } - unit = uvc_alloc_entity(buffer[2], buffer[3], p + 1, 0); - if (unit == NULL) - return -ENOMEM; + unit = uvc_alloc_new_entity(dev, buffer[2], buffer[3], + p + 1, 0); + if (IS_ERR(unit)) + return PTR_ERR(unit); memcpy(unit->baSourceID, &buffer[5], p); @@ -1139,9 +1152,9 @@ static int uvc_parse_standard_control(struct uvc_device *dev, return -EINVAL; } - unit = uvc_alloc_entity(buffer[2], buffer[3], 2, n); - if (unit == NULL) - return -ENOMEM; + unit = uvc_alloc_new_entity(dev, buffer[2], buffer[3], 2, n); + if (IS_ERR(unit)) + return PTR_ERR(unit); memcpy(unit->baSourceID, &buffer[4], 1); unit->processing.wMaxMultiplier = @@ -1168,9 +1181,10 @@ static int uvc_parse_standard_control(struct uvc_device *dev, return -EINVAL; } - unit = uvc_alloc_entity(buffer[2], buffer[3], p + 1, n); - if (unit == NULL) - return -ENOMEM; + unit = uvc_alloc_new_entity(dev, buffer[2], buffer[3], + p + 1, n); + if (IS_ERR(unit)) + return PTR_ERR(unit); memcpy(unit->guid, &buffer[4], 16); unit->extension.bNumControls = buffer[20]; @@ -1315,9 +1329,10 @@ static int uvc_gpio_parse(struct uvc_device *dev) return dev_err_probe(&dev->intf->dev, irq, "No IRQ for privacy GPIO\n"); - unit = uvc_alloc_entity(UVC_EXT_GPIO_UNIT, UVC_EXT_GPIO_UNIT_ID, 0, 1); - if (!unit) - return -ENOMEM; + unit = uvc_alloc_new_entity(dev, UVC_EXT_GPIO_UNIT, + UVC_EXT_GPIO_UNIT_ID, 0, 1); + if (IS_ERR(unit)) + return PTR_ERR(unit); unit->gpio.gpio_privacy = gpio_privacy; unit->gpio.irq = irq; @@ -1868,7 +1883,7 @@ static int uvc_scan_device(struct uvc_device *dev) uvc_scan_fallback(dev); if (list_empty(&dev->chains)) { - dev_info(&dev->udev->dev, "No valid video chain found.\n"); + dev_info(&dev->intf->dev, "No valid video chain found.\n"); return -ENODEV; } @@ -1958,11 +1973,11 @@ static void uvc_unregister_video(struct uvc_device *dev) list_for_each_entry(stream, &dev->streams, list) { /* Nothing to do here, continue. */ - if (!video_is_registered(&stream->vdev)) + if (!video_is_registered(&stream->queue.vdev)) continue; - vb2_video_unregister_device(&stream->vdev); - vb2_video_unregister_device(&stream->meta.vdev); + vb2_video_unregister_device(&stream->queue.vdev); + vb2_video_unregister_device(&stream->meta.queue.vdev); /* * Now both vdevs are not streaming and all the ioctls will @@ -1984,12 +1999,12 @@ static void uvc_unregister_video(struct uvc_device *dev) int uvc_register_video_device(struct uvc_device *dev, struct uvc_streaming *stream, - struct video_device *vdev, struct uvc_video_queue *queue, enum v4l2_buf_type type, const struct v4l2_file_operations *fops, const struct v4l2_ioctl_ops *ioctl_ops) { + struct video_device *vdev = &queue->vdev; int ret; /* Initialize the video buffers queue. */ @@ -2071,9 +2086,9 @@ static int uvc_register_video(struct uvc_device *dev, uvc_debugfs_init_stream(stream); /* Register the device with V4L. */ - return uvc_register_video_device(dev, stream, &stream->vdev, - &stream->queue, stream->type, - &uvc_fops, &uvc_ioctl_ops); + return uvc_register_video_device(dev, stream, &stream->queue, + stream->type, &uvc_fops, + &uvc_ioctl_ops); } /* @@ -2092,7 +2107,7 @@ static int uvc_register_terms(struct uvc_device *dev, stream = uvc_stream_by_id(dev, term->id); if (stream == NULL) { - dev_info(&dev->udev->dev, + dev_info(&dev->intf->dev, "No streaming interface found for terminal %u.", term->id); continue; @@ -2109,7 +2124,7 @@ static int uvc_register_terms(struct uvc_device *dev, */ uvc_meta_register(stream); - term->vdev = &stream->vdev; + term->vdev = &stream->queue.vdev; } return 0; @@ -2128,7 +2143,7 @@ static int uvc_register_chains(struct uvc_device *dev) #ifdef CONFIG_MEDIA_CONTROLLER ret = uvc_mc_register_entities(chain); if (ret < 0) - dev_info(&dev->udev->dev, + dev_info(&dev->intf->dev, "Failed to register entities (%d).\n", ret); #endif } @@ -2229,23 +2244,23 @@ static int uvc_probe(struct usb_interface *intf, if (ret < 0) goto error; - dev_info(&dev->udev->dev, "Found UVC %u.%02x device %s (%04x:%04x)\n", + dev_info(&dev->intf->dev, "Found UVC %u.%02x device %s (%04x:%04x)\n", dev->uvc_version >> 8, dev->uvc_version & 0xff, udev->product ? udev->product : "<unnamed>", le16_to_cpu(udev->descriptor.idVendor), le16_to_cpu(udev->descriptor.idProduct)); if (dev->quirks != dev->info->quirks) { - dev_info(&dev->udev->dev, + dev_info(&dev->intf->dev, "Forcing device quirks to 0x%x by module parameter for testing purpose.\n", dev->quirks); - dev_info(&dev->udev->dev, + dev_info(&dev->intf->dev, "Please report required quirks to the linux-media mailing list.\n"); } if (dev->info->uvc_version) { dev->uvc_version = dev->info->uvc_version; - dev_info(&dev->udev->dev, "Forcing UVC version to %u.%02x\n", + dev_info(&dev->intf->dev, "Forcing UVC version to %u.%02x\n", dev->uvc_version >> 8, dev->uvc_version & 0xff); } @@ -2281,21 +2296,21 @@ static int uvc_probe(struct usb_interface *intf, /* Initialize the interrupt URB. */ ret = uvc_status_init(dev); if (ret < 0) { - dev_info(&dev->udev->dev, + dev_info(&dev->intf->dev, "Unable to initialize the status endpoint (%d), status interrupt will not be supported.\n", ret); } ret = uvc_gpio_init_irq(dev); if (ret < 0) { - dev_err(&dev->udev->dev, + dev_err(&dev->intf->dev, "Unable to request privacy GPIO IRQ (%d)\n", ret); goto error; } ret = uvc_meta_init(dev); if (ret < 0) { - dev_err(&dev->udev->dev, + dev_err(&dev->intf->dev, "Error initializing the metadata formats (%d)\n", ret); goto error; } diff --git a/drivers/media/usb/uvc/uvc_entity.c b/drivers/media/usb/uvc/uvc_entity.c index cc68dd24eb42..3823ac9c8045 100644 --- a/drivers/media/usb/uvc/uvc_entity.c +++ b/drivers/media/usb/uvc/uvc_entity.c @@ -140,7 +140,7 @@ int uvc_mc_register_entities(struct uvc_video_chain *chain) list_for_each_entry(entity, &chain->entities, chain) { ret = uvc_mc_init_entity(chain, entity); if (ret < 0) { - dev_info(&chain->dev->udev->dev, + dev_info(&chain->dev->intf->dev, "Failed to initialize entity for entity %u\n", entity->id); return ret; @@ -150,7 +150,7 @@ int uvc_mc_register_entities(struct uvc_video_chain *chain) list_for_each_entry(entity, &chain->entities, chain) { ret = uvc_mc_create_links(chain, entity); if (ret < 0) { - dev_info(&chain->dev->udev->dev, + dev_info(&chain->dev->intf->dev, "Failed to create links for entity %u\n", entity->id); return ret; diff --git a/drivers/media/usb/uvc/uvc_metadata.c b/drivers/media/usb/uvc/uvc_metadata.c index 229e08ff323e..c23b174965c3 100644 --- a/drivers/media/usb/uvc/uvc_metadata.c +++ b/drivers/media/usb/uvc/uvc_metadata.c @@ -23,10 +23,10 @@ * V4L2 ioctls */ -static int uvc_meta_v4l2_querycap(struct file *file, void *fh, +static int uvc_meta_v4l2_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { - struct v4l2_fh *vfh = file->private_data; + struct v4l2_fh *vfh = file_to_v4l2_fh(file); struct uvc_streaming *stream = video_get_drvdata(vfh->vdev); struct uvc_video_chain *chain = stream->chain; @@ -39,28 +39,26 @@ static int uvc_meta_v4l2_querycap(struct file *file, void *fh, return 0; } -static int uvc_meta_v4l2_get_format(struct file *file, void *fh, +static int uvc_meta_v4l2_get_format(struct file *file, void *priv, struct v4l2_format *format) { - struct v4l2_fh *vfh = file->private_data; + struct v4l2_fh *vfh = file_to_v4l2_fh(file); struct uvc_streaming *stream = video_get_drvdata(vfh->vdev); struct v4l2_meta_format *fmt = &format->fmt.meta; if (format->type != vfh->vdev->queue->type) return -EINVAL; - memset(fmt, 0, sizeof(*fmt)); - fmt->dataformat = stream->meta.format; fmt->buffersize = UVC_METADATA_BUF_SIZE; return 0; } -static int uvc_meta_v4l2_try_format(struct file *file, void *fh, +static int uvc_meta_v4l2_try_format(struct file *file, void *priv, struct v4l2_format *format) { - struct v4l2_fh *vfh = file->private_data; + struct v4l2_fh *vfh = file_to_v4l2_fh(file); struct uvc_streaming *stream = video_get_drvdata(vfh->vdev); struct uvc_device *dev = stream->dev; struct v4l2_meta_format *fmt = &format->fmt.meta; @@ -69,11 +67,12 @@ static int uvc_meta_v4l2_try_format(struct file *file, void *fh, if (format->type != vfh->vdev->queue->type) return -EINVAL; - for (unsigned int i = 0; i < dev->nmeta_formats; i++) + for (unsigned int i = 0; i < dev->nmeta_formats; i++) { if (dev->meta_formats[i] == fmt->dataformat) { fmeta = fmt->dataformat; break; } + } memset(fmt, 0, sizeof(*fmt)); @@ -83,15 +82,15 @@ static int uvc_meta_v4l2_try_format(struct file *file, void *fh, return 0; } -static int uvc_meta_v4l2_set_format(struct file *file, void *fh, +static int uvc_meta_v4l2_set_format(struct file *file, void *priv, struct v4l2_format *format) { - struct v4l2_fh *vfh = file->private_data; + struct v4l2_fh *vfh = file_to_v4l2_fh(file); struct uvc_streaming *stream = video_get_drvdata(vfh->vdev); struct v4l2_meta_format *fmt = &format->fmt.meta; int ret; - ret = uvc_meta_v4l2_try_format(file, fh, format); + ret = uvc_meta_v4l2_try_format(file, priv, format); if (ret < 0) return ret; @@ -100,37 +99,28 @@ static int uvc_meta_v4l2_set_format(struct file *file, void *fh, * Metadata buffers would still be perfectly parseable, but it's more * consistent and cleaner to disallow that. */ - mutex_lock(&stream->mutex); - if (vb2_is_busy(&stream->meta.queue.queue)) - ret = -EBUSY; - else - stream->meta.format = fmt->dataformat; + return -EBUSY; - mutex_unlock(&stream->mutex); + stream->meta.format = fmt->dataformat; - return ret; + return 0; } -static int uvc_meta_v4l2_enum_formats(struct file *file, void *fh, +static int uvc_meta_v4l2_enum_formats(struct file *file, void *priv, struct v4l2_fmtdesc *fdesc) { - struct v4l2_fh *vfh = file->private_data; + struct v4l2_fh *vfh = file_to_v4l2_fh(file); struct uvc_streaming *stream = video_get_drvdata(vfh->vdev); struct uvc_device *dev = stream->dev; - u32 i = fdesc->index; if (fdesc->type != vfh->vdev->queue->type) return -EINVAL; - if (i >= dev->nmeta_formats) + if (fdesc->index >= dev->nmeta_formats) return -EINVAL; - memset(fdesc, 0, sizeof(*fdesc)); - - fdesc->type = vfh->vdev->queue->type; - fdesc->index = i; - fdesc->pixelformat = dev->meta_formats[i]; + fdesc->pixelformat = dev->meta_formats[fdesc->index]; return 0; } @@ -177,7 +167,6 @@ static struct uvc_entity *uvc_meta_find_msxu(struct uvc_device *dev) return NULL; } -#define MSXU_CONTROL_METADATA 0x9 static int uvc_meta_detect_msxu(struct uvc_device *dev) { u32 *data __free(kfree) = NULL; @@ -196,9 +185,12 @@ static int uvc_meta_detect_msxu(struct uvc_device *dev) if (!data) return -ENOMEM; - /* Check if the metadata is already enabled. */ + /* + * Check if the metadata is already enabled, or if the device always + * returns metadata. + */ ret = uvc_query_ctrl(dev, UVC_GET_CUR, entity->id, dev->intfnum, - MSXU_CONTROL_METADATA, data, sizeof(*data)); + UVC_MSXU_CONTROL_METADATA, data, sizeof(*data)); if (ret) return 0; @@ -208,21 +200,23 @@ static int uvc_meta_detect_msxu(struct uvc_device *dev) } /* - * We have seen devices that require 1 to enable the metadata, others - * requiring a value != 1 and others requiring a value >1. Luckily for - * us, the value from GET_MAX seems to work all the time. + * Set the value of UVC_MSXU_CONTROL_METADATA to the value reported by + * GET_MAX to enable production of MSXU metadata. The GET_MAX request + * reports the maximum size of the metadata, if its value is 0 then MSXU + * metadata is not supported. For more information, see + * https://learn.microsoft.com/en-us/windows-hardware/drivers/stream/uvc-extensions-1-5#2229-metadata-control */ ret = uvc_query_ctrl(dev, UVC_GET_MAX, entity->id, dev->intfnum, - MSXU_CONTROL_METADATA, data, sizeof(*data)); + UVC_MSXU_CONTROL_METADATA, data, sizeof(*data)); if (ret || !*data) return 0; /* - * If we can set MSXU_CONTROL_METADATA, the device will report + * If we can set UVC_MSXU_CONTROL_METADATA, the device will report * metadata. */ ret = uvc_query_ctrl(dev, UVC_SET_CUR, entity->id, dev->intfnum, - MSXU_CONTROL_METADATA, data, sizeof(*data)); + UVC_MSXU_CONTROL_METADATA, data, sizeof(*data)); if (!ret) dev->quirks |= UVC_QUIRK_MSXU_META; @@ -232,12 +226,11 @@ static int uvc_meta_detect_msxu(struct uvc_device *dev) int uvc_meta_register(struct uvc_streaming *stream) { struct uvc_device *dev = stream->dev; - struct video_device *vdev = &stream->meta.vdev; struct uvc_video_queue *queue = &stream->meta.queue; stream->meta.format = V4L2_META_FMT_UVC; - return uvc_register_video_device(dev, stream, vdev, queue, + return uvc_register_video_device(dev, stream, queue, V4L2_BUF_TYPE_META_CAPTURE, &uvc_meta_fops, &uvc_meta_ioctl_ops); } diff --git a/drivers/media/usb/uvc/uvc_status.c b/drivers/media/usb/uvc/uvc_status.c index ee01dce4b783..231cfee8e7c2 100644 --- a/drivers/media/usb/uvc/uvc_status.c +++ b/drivers/media/usb/uvc/uvc_status.c @@ -62,7 +62,8 @@ static int uvc_input_init(struct uvc_device *dev) __set_bit(EV_KEY, input->evbit); __set_bit(KEY_CAMERA, input->keybit); - if ((ret = input_register_device(input)) < 0) + ret = input_register_device(input); + if (ret < 0) goto error; dev->input = input; @@ -215,7 +216,7 @@ static void uvc_status_complete(struct urb *urb) return; default: - dev_warn(&dev->udev->dev, + dev_warn(&dev->intf->dev, "Non-zero status (%d) in status completion handler.\n", urb->status); return; @@ -247,7 +248,7 @@ static void uvc_status_complete(struct urb *urb) urb->interval = dev->int_ep->desc.bInterval; ret = usb_submit_urb(urb, GFP_ATOMIC); if (ret < 0) - dev_err(&dev->udev->dev, + dev_err(&dev->intf->dev, "Failed to resubmit status URB (%d).\n", ret); } diff --git a/drivers/media/usb/uvc/uvc_v4l2.c b/drivers/media/usb/uvc/uvc_v4l2.c index 160f9cf6e6db..9e4a251eca88 100644 --- a/drivers/media/usb/uvc/uvc_v4l2.c +++ b/drivers/media/usb/uvc/uvc_v4l2.c @@ -329,14 +329,12 @@ static int uvc_v4l2_try_format(struct uvc_streaming *stream, * developers test their webcams with the Linux driver as well as with * the Windows driver). */ - mutex_lock(&stream->mutex); if (stream->dev->quirks & UVC_QUIRK_PROBE_EXTRAFIELDS) probe->dwMaxVideoFrameSize = stream->ctrl.dwMaxVideoFrameSize; /* Probe the device. */ ret = uvc_probe_video(stream, probe); - mutex_unlock(&stream->mutex); if (ret < 0) return ret; @@ -388,26 +386,22 @@ static int uvc_v4l2_try_format(struct uvc_streaming *stream, return ret; } -static int uvc_ioctl_g_fmt(struct file *file, void *fh, +static int uvc_ioctl_g_fmt(struct file *file, void *priv, struct v4l2_format *fmt) { - struct uvc_fh *handle = fh; + struct uvc_fh *handle = to_uvc_fh(file); struct uvc_streaming *stream = handle->stream; const struct uvc_format *format; const struct uvc_frame *frame; - int ret = 0; if (fmt->type != stream->type) return -EINVAL; - mutex_lock(&stream->mutex); format = stream->cur_format; frame = stream->cur_frame; - if (format == NULL || frame == NULL) { - ret = -EINVAL; - goto done; - } + if (!format || !frame) + return -EINVAL; fmt->fmt.pix.pixelformat = format->fcc; fmt->fmt.pix.width = frame->wWidth; @@ -419,15 +413,13 @@ static int uvc_ioctl_g_fmt(struct file *file, void *fh, fmt->fmt.pix.xfer_func = format->xfer_func; fmt->fmt.pix.ycbcr_enc = format->ycbcr_enc; -done: - mutex_unlock(&stream->mutex); - return ret; + return 0; } -static int uvc_ioctl_s_fmt(struct file *file, void *fh, +static int uvc_ioctl_s_fmt(struct file *file, void *priv, struct v4l2_format *fmt) { - struct uvc_fh *handle = fh; + struct uvc_fh *handle = to_uvc_fh(file); struct uvc_streaming *stream = handle->stream; struct uvc_streaming_control probe; const struct uvc_format *format; @@ -441,35 +433,27 @@ static int uvc_ioctl_s_fmt(struct file *file, void *fh, if (ret < 0) return ret; - mutex_lock(&stream->mutex); - if (vb2_is_busy(&stream->queue.queue)) { - ret = -EBUSY; - goto done; - } + if (vb2_is_busy(&stream->queue.queue)) + return -EBUSY; stream->ctrl = probe; stream->cur_format = format; stream->cur_frame = frame; -done: - mutex_unlock(&stream->mutex); - return ret; + return 0; } -static int uvc_ioctl_g_parm(struct file *file, void *fh, +static int uvc_ioctl_g_parm(struct file *file, void *priv, struct v4l2_streamparm *parm) { u32 numerator, denominator; - struct uvc_fh *handle = fh; + struct uvc_fh *handle = to_uvc_fh(file); struct uvc_streaming *stream = handle->stream; if (parm->type != stream->type) return -EINVAL; - mutex_lock(&stream->mutex); numerator = stream->ctrl.dwFrameInterval; - mutex_unlock(&stream->mutex); - denominator = 10000000; v4l2_simplify_fraction(&numerator, &denominator, 8, 333); @@ -493,10 +477,10 @@ static int uvc_ioctl_g_parm(struct file *file, void *fh, return 0; } -static int uvc_ioctl_s_parm(struct file *file, void *fh, +static int uvc_ioctl_s_parm(struct file *file, void *priv, struct v4l2_streamparm *parm) { - struct uvc_fh *handle = fh; + struct uvc_fh *handle = to_uvc_fh(file); struct uvc_streaming *stream = handle->stream; struct uvc_streaming_control probe; struct v4l2_fract timeperframe; @@ -519,12 +503,8 @@ static int uvc_ioctl_s_parm(struct file *file, void *fh, uvc_dbg(stream->dev, FORMAT, "Setting frame interval to %u/%u (%u)\n", timeperframe.numerator, timeperframe.denominator, interval); - mutex_lock(&stream->mutex); - - if (uvc_queue_streaming(&stream->queue)) { - mutex_unlock(&stream->mutex); + if (uvc_queue_streaming(&stream->queue)) return -EBUSY; - } format = stream->cur_format; frame = stream->cur_frame; @@ -556,14 +536,11 @@ static int uvc_ioctl_s_parm(struct file *file, void *fh, /* Probe the device with the new settings. */ ret = uvc_probe_video(stream, &probe); - if (ret < 0) { - mutex_unlock(&stream->mutex); + if (ret < 0) return ret; - } stream->ctrl = probe; stream->cur_frame = frame; - mutex_unlock(&stream->mutex); /* Return the actual frame period. */ timeperframe.numerator = probe.dwFrameInterval; @@ -599,18 +576,17 @@ static int uvc_v4l2_open(struct file *file) if (!handle) return -ENOMEM; - v4l2_fh_init(&handle->vfh, &stream->vdev); - v4l2_fh_add(&handle->vfh); + v4l2_fh_init(&handle->vfh, &stream->queue.vdev); + v4l2_fh_add(&handle->vfh, file); handle->chain = stream->chain; handle->stream = stream; - file->private_data = handle; return 0; } static int uvc_v4l2_release(struct file *file) { - struct uvc_fh *handle = file->private_data; + struct uvc_fh *handle = to_uvc_fh(file); struct uvc_streaming *stream = handle->stream; uvc_dbg(stream->dev, CALLS, "%s\n", __func__); @@ -623,10 +599,10 @@ static int uvc_v4l2_release(struct file *file) return 0; } -static int uvc_ioctl_querycap(struct file *file, void *fh, +static int uvc_ioctl_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { - struct uvc_fh *handle = file->private_data; + struct uvc_fh *handle = to_uvc_fh(file); struct uvc_video_chain *chain = handle->chain; struct uvc_streaming *stream = handle->stream; @@ -639,10 +615,10 @@ static int uvc_ioctl_querycap(struct file *file, void *fh, return 0; } -static int uvc_ioctl_enum_fmt(struct file *file, void *fh, +static int uvc_ioctl_enum_fmt(struct file *file, void *priv, struct v4l2_fmtdesc *fmt) { - struct uvc_fh *handle = fh; + struct uvc_fh *handle = to_uvc_fh(file); struct uvc_streaming *stream = handle->stream; enum v4l2_buf_type type = fmt->type; const struct uvc_format *format; @@ -663,20 +639,20 @@ static int uvc_ioctl_enum_fmt(struct file *file, void *fh, return 0; } -static int uvc_ioctl_try_fmt(struct file *file, void *fh, +static int uvc_ioctl_try_fmt(struct file *file, void *priv, struct v4l2_format *fmt) { - struct uvc_fh *handle = fh; + struct uvc_fh *handle = to_uvc_fh(file); struct uvc_streaming *stream = handle->stream; struct uvc_streaming_control probe; return uvc_v4l2_try_format(stream, fmt, &probe, NULL, NULL); } -static int uvc_ioctl_enum_input(struct file *file, void *fh, +static int uvc_ioctl_enum_input(struct file *file, void *priv, struct v4l2_input *input) { - struct uvc_fh *handle = fh; + struct uvc_fh *handle = to_uvc_fh(file); struct uvc_video_chain *chain = handle->chain; const struct uvc_entity *selector = chain->selector; struct uvc_entity *iterm = NULL; @@ -716,9 +692,9 @@ static int uvc_ioctl_enum_input(struct file *file, void *fh, return 0; } -static int uvc_ioctl_g_input(struct file *file, void *fh, unsigned int *input) +static int uvc_ioctl_g_input(struct file *file, void *priv, unsigned int *input) { - struct uvc_fh *handle = fh; + struct uvc_fh *handle = to_uvc_fh(file); struct uvc_video_chain *chain = handle->chain; u8 *buf; int ret; @@ -744,9 +720,9 @@ static int uvc_ioctl_g_input(struct file *file, void *fh, unsigned int *input) return ret; } -static int uvc_ioctl_s_input(struct file *file, void *fh, unsigned int input) +static int uvc_ioctl_s_input(struct file *file, void *priv, unsigned int input) { - struct uvc_fh *handle = fh; + struct uvc_fh *handle = to_uvc_fh(file); struct uvc_streaming *stream = handle->stream; struct uvc_video_chain *chain = handle->chain; u8 *buf; @@ -778,10 +754,10 @@ static int uvc_ioctl_s_input(struct file *file, void *fh, unsigned int input) return ret; } -static int uvc_ioctl_query_ext_ctrl(struct file *file, void *fh, +static int uvc_ioctl_query_ext_ctrl(struct file *file, void *priv, struct v4l2_query_ext_ctrl *qec) { - struct uvc_fh *handle = fh; + struct uvc_fh *handle = to_uvc_fh(file); struct uvc_video_chain *chain = handle->chain; return uvc_query_v4l2_ctrl(chain, qec); @@ -806,10 +782,10 @@ static int uvc_ctrl_check_access(struct uvc_video_chain *chain, return ret; } -static int uvc_ioctl_g_ext_ctrls(struct file *file, void *fh, +static int uvc_ioctl_g_ext_ctrls(struct file *file, void *priv, struct v4l2_ext_controls *ctrls) { - struct uvc_fh *handle = fh; + struct uvc_fh *handle = to_uvc_fh(file); struct uvc_video_chain *chain = handle->chain; struct v4l2_ext_control *ctrl = ctrls->controls; unsigned int i; @@ -890,35 +866,35 @@ static int uvc_ioctl_s_try_ext_ctrls(struct uvc_fh *handle, return uvc_ctrl_rollback(handle); } -static int uvc_ioctl_s_ext_ctrls(struct file *file, void *fh, +static int uvc_ioctl_s_ext_ctrls(struct file *file, void *priv, struct v4l2_ext_controls *ctrls) { - struct uvc_fh *handle = fh; + struct uvc_fh *handle = to_uvc_fh(file); return uvc_ioctl_s_try_ext_ctrls(handle, ctrls, VIDIOC_S_EXT_CTRLS); } -static int uvc_ioctl_try_ext_ctrls(struct file *file, void *fh, +static int uvc_ioctl_try_ext_ctrls(struct file *file, void *priv, struct v4l2_ext_controls *ctrls) { - struct uvc_fh *handle = fh; + struct uvc_fh *handle = to_uvc_fh(file); return uvc_ioctl_s_try_ext_ctrls(handle, ctrls, VIDIOC_TRY_EXT_CTRLS); } -static int uvc_ioctl_querymenu(struct file *file, void *fh, +static int uvc_ioctl_querymenu(struct file *file, void *priv, struct v4l2_querymenu *qm) { - struct uvc_fh *handle = fh; + struct uvc_fh *handle = to_uvc_fh(file); struct uvc_video_chain *chain = handle->chain; return uvc_query_v4l2_menu(chain, qm); } -static int uvc_ioctl_g_selection(struct file *file, void *fh, +static int uvc_ioctl_g_selection(struct file *file, void *priv, struct v4l2_selection *sel) { - struct uvc_fh *handle = fh; + struct uvc_fh *handle = to_uvc_fh(file); struct uvc_streaming *stream = handle->stream; if (sel->type != stream->type) @@ -941,18 +917,16 @@ static int uvc_ioctl_g_selection(struct file *file, void *fh, sel->r.left = 0; sel->r.top = 0; - mutex_lock(&stream->mutex); sel->r.width = stream->cur_frame->wWidth; sel->r.height = stream->cur_frame->wHeight; - mutex_unlock(&stream->mutex); return 0; } -static int uvc_ioctl_enum_framesizes(struct file *file, void *fh, +static int uvc_ioctl_enum_framesizes(struct file *file, void *priv, struct v4l2_frmsizeenum *fsize) { - struct uvc_fh *handle = fh; + struct uvc_fh *handle = to_uvc_fh(file); struct uvc_streaming *stream = handle->stream; const struct uvc_format *format = NULL; const struct uvc_frame *frame = NULL; @@ -989,10 +963,10 @@ static int uvc_ioctl_enum_framesizes(struct file *file, void *fh, return 0; } -static int uvc_ioctl_enum_frameintervals(struct file *file, void *fh, +static int uvc_ioctl_enum_frameintervals(struct file *file, void *priv, struct v4l2_frmivalenum *fival) { - struct uvc_fh *handle = fh; + struct uvc_fh *handle = to_uvc_fh(file); struct uvc_streaming *stream = handle->stream; const struct uvc_format *format = NULL; const struct uvc_frame *frame = NULL; @@ -1061,10 +1035,10 @@ static int uvc_ioctl_subscribe_event(struct v4l2_fh *fh, } } -static long uvc_ioctl_default(struct file *file, void *fh, bool valid_prio, +static long uvc_ioctl_default(struct file *file, void *priv, bool valid_prio, unsigned int cmd, void *arg) { - struct uvc_fh *handle = fh; + struct uvc_fh *handle = to_uvc_fh(file); struct uvc_video_chain *chain = handle->chain; switch (cmd) { @@ -1170,7 +1144,7 @@ static int uvc_v4l2_put_xu_query(const struct uvc_xu_control_query *kp, static long uvc_v4l2_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg) { - struct uvc_fh *handle = file->private_data; + struct uvc_fh *handle = to_uvc_fh(file); union { struct uvc_xu_control_mapping xmap; struct uvc_xu_control_query xqry; @@ -1221,7 +1195,7 @@ static long uvc_v4l2_compat_ioctl32(struct file *file, static long uvc_v4l2_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { - struct uvc_fh *handle = file->private_data; + struct uvc_fh *handle = to_uvc_fh(file); unsigned int converted_cmd = v4l2_translate_cmd(cmd); int ret; diff --git a/drivers/media/usb/uvc/uvc_video.c b/drivers/media/usb/uvc/uvc_video.c index a5013a7fbca4..784be9330320 100644 --- a/drivers/media/usb/uvc/uvc_video.c +++ b/drivers/media/usb/uvc/uvc_video.c @@ -95,14 +95,14 @@ int uvc_query_ctrl(struct uvc_device *dev, u8 query, u8 unit, */ if (ret > 0 && query != UVC_GET_INFO) { memset(data + ret, 0, size - ret); - dev_warn_once(&dev->udev->dev, + dev_warn_once(&dev->intf->dev, "UVC non compliance: %s control %u on unit %u returned %d bytes when we expected %u.\n", uvc_query_name(query), cs, unit, ret, size); return 0; } if (ret != -EPIPE) { - dev_err(&dev->udev->dev, + dev_err(&dev->intf->dev, "Failed to query (%s) UVC control %u on unit %u: %d (exp. %u).\n", uvc_query_name(query), cs, unit, ret, size); return ret < 0 ? ret : -EPIPE; @@ -119,7 +119,7 @@ int uvc_query_ctrl(struct uvc_device *dev, u8 query, u8 unit, *(u8 *)data = tmp; if (ret != 1) { - dev_err_ratelimited(&dev->udev->dev, + dev_err_ratelimited(&dev->intf->dev, "Failed to query (%s) UVC error code control %u on unit %u: %d (exp. 1).\n", uvc_query_name(query), cs, unit, ret); return ret < 0 ? ret : -EPIPE; @@ -266,7 +266,7 @@ static void uvc_fixup_video_ctrl(struct uvc_streaming *stream, if (stream->intf->num_altsetting > 1 && ctrl->dwMaxPayloadTransferSize > stream->maxpsize) { dev_warn_ratelimited(&stream->intf->dev, - "UVC non compliance: the max payload transmission size (%u) exceeds the size of the ep max packet (%u). Using the max size.\n", + "UVC non compliance: Reducing max payload transfer size (%u) to fit endpoint limit (%u).\n", ctrl->dwMaxPayloadTransferSize, stream->maxpsize); ctrl->dwMaxPayloadTransferSize = stream->maxpsize; @@ -1691,7 +1691,7 @@ static void uvc_video_complete(struct urb *urb) struct uvc_streaming *stream = uvc_urb->stream; struct uvc_video_queue *queue = &stream->queue; struct uvc_video_queue *qmeta = &stream->meta.queue; - struct vb2_queue *vb2_qmeta = stream->meta.vdev.queue; + struct vb2_queue *vb2_qmeta = stream->meta.queue.vdev.queue; struct uvc_buffer *buf = NULL; struct uvc_buffer *buf_meta = NULL; unsigned long flags; diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h index 757254fc4fe9..24292efbe47d 100644 --- a/drivers/media/usb/uvc/uvcvideo.h +++ b/drivers/media/usb/uvc/uvcvideo.h @@ -41,6 +41,8 @@ #define UVC_EXT_GPIO_UNIT 0x7ffe #define UVC_EXT_GPIO_UNIT_ID 0x100 +#define UVC_INVALID_ENTITY_ID 0xffff + /* ------------------------------------------------------------------------ * Driver specific constants. */ @@ -328,6 +330,7 @@ struct uvc_buffer { #define UVC_QUEUE_DISCONNECTED (1 << 0) struct uvc_video_queue { + struct video_device vdev; struct vb2_queue queue; struct mutex mutex; /* * Serializes vb2_queue and @@ -450,7 +453,6 @@ struct uvc_urb { struct uvc_streaming { struct list_head list; struct uvc_device *dev; - struct video_device vdev; struct uvc_video_chain *chain; atomic_t active; @@ -469,12 +471,6 @@ struct uvc_streaming { const struct uvc_format *cur_format; const struct uvc_frame *cur_frame; - /* - * Protect access to ctrl, cur_format, cur_frame and hardware video - * probe control. - */ - struct mutex mutex; - /* Buffers queue. */ unsigned int frozen : 1; struct uvc_video_queue queue; @@ -483,7 +479,6 @@ struct uvc_streaming { struct uvc_buffer *meta_buf); struct { - struct video_device vdev; struct uvc_video_queue queue; u32 format; } meta; @@ -637,6 +632,11 @@ struct uvc_fh { unsigned int pending_async_ctrls; }; +static inline struct uvc_fh *to_uvc_fh(struct file *filp) +{ + return container_of(file_to_v4l2_fh(filp), struct uvc_fh, vfh); +} + /* ------------------------------------------------------------------------ * Debugging, printing and logging */ @@ -667,7 +667,7 @@ extern unsigned int uvc_hw_timestamps_param; #define uvc_dbg(_dev, flag, fmt, ...) \ do { \ if (uvc_dbg_param & UVC_DBG_##flag) \ - dev_printk(KERN_DEBUG, &(_dev)->udev->dev, fmt, \ + dev_printk(KERN_DEBUG, &(_dev)->intf->dev, fmt, \ ##__VA_ARGS__); \ } while (0) @@ -680,7 +680,7 @@ do { \ #define uvc_warn_once(_dev, warn, fmt, ...) \ do { \ if (!test_and_set_bit(warn, &(_dev)->warnings)) \ - dev_info(&(_dev)->udev->dev, fmt, ##__VA_ARGS__); \ + dev_info(&(_dev)->intf->dev, fmt, ##__VA_ARGS__); \ } while (0) /* -------------------------------------------------------------------------- @@ -733,7 +733,6 @@ int uvc_meta_register(struct uvc_streaming *stream); int uvc_register_video_device(struct uvc_device *dev, struct uvc_streaming *stream, - struct video_device *vdev, struct uvc_video_queue *queue, enum v4l2_buf_type type, const struct v4l2_file_operations *fops, |