@@ -2354,6 +2354,9 @@ int uvc_ctrl_init_device(struct uvc_device *dev)
} else if (UVC_ENTITY_TYPE(entity) == UVC_EXT_GPIO_UNIT) {
bmControls = entity->gpio.bmControls;
bControlSize = entity->gpio.bControlSize;
+ } else if (UVC_ENTITY_TYPE(entity) == UVC_CTRL_CLASS_UNIT) {
+ bmControls = entity->ctrl_class.bmControls;
+ bControlSize = entity->ctrl_class.bControlSize;
}
/* Remove bogus/blacklisted controls */
@@ -1025,6 +1025,7 @@ static int uvc_parse_streaming(struct uvc_device *dev,
}
static const u8 uvc_camera_guid[16] = UVC_GUID_UVC_CAMERA;
+static const u8 uvc_ctrl_class_guid[16] = UVC_GUID_CTRL_CLASS;
static const u8 uvc_gpio_guid[16] = UVC_GUID_EXT_GPIO_CONTROLLER;
static const u8 uvc_media_transport_input_guid[16] =
UVC_GUID_UVC_MEDIA_TRANSPORT_INPUT;
@@ -1057,6 +1058,9 @@ static struct uvc_entity *uvc_alloc_entity(u16 type, u16 id,
* is initialized by the caller.
*/
switch (type) {
+ case UVC_CTRL_CLASS_UNIT:
+ memcpy(entity->guid, uvc_ctrl_class_guid, 16);
+ break;
case UVC_EXT_GPIO_UNIT:
memcpy(entity->guid, uvc_gpio_guid, 16);
break;
@@ -1474,6 +1478,39 @@ static int uvc_parse_control(struct uvc_device *dev)
return 0;
}
+/* -----------------------------------------------------------------------------
+ * Control Class
+ */
+
+static int uvc_ctrl_class_get_info(struct uvc_device *dev,
+ struct uvc_entity *entity,
+ u8 cs, u8 *caps)
+{
+ *caps = 0;
+ return 0;
+}
+
+static int uvc_ctrl_class_parse(struct uvc_device *dev)
+{
+ struct uvc_entity *unit;
+
+ unit = uvc_alloc_entity(UVC_CTRL_CLASS_UNIT,
+ UVC_CTRL_CLASS_UNIT_ID, 0, 1);
+ if (!unit)
+ return -ENOMEM;
+
+ unit->ctrl_class.bControlSize = 1;
+ unit->ctrl_class.bmControls = (u8 *)unit + sizeof(*unit);
+ unit->ctrl_class.bmControls[0] = (1 << (UVC_CC_LAST_CLASS + 1)) - 1;
+ unit->get_info = uvc_ctrl_class_get_info;
+ strncpy(unit->name, "Control Class", sizeof(unit->name) - 1);
+
+ list_add_tail(&unit->list, &dev->entities);
+ dev->ctrl_class_unit = unit;
+
+ return 0;
+}
+
/* -----------------------------------------------------------------------------
* Privacy GPIO
*/
@@ -2054,12 +2091,11 @@ static int uvc_scan_device(struct uvc_device *dev)
return -1;
}
- /* Add GPIO entity to the first chain. */
- if (dev->gpio_unit) {
- chain = list_first_entry(&dev->chains,
- struct uvc_video_chain, list);
+ /* Add virtual entities to the first chain. */
+ chain = list_first_entry(&dev->chains, struct uvc_video_chain, list);
+ list_add_tail(&dev->ctrl_class_unit->chain, &chain->entities);
+ if (dev->gpio_unit)
list_add_tail(&dev->gpio_unit->chain, &chain->entities);
- }
return 0;
}
@@ -2399,6 +2435,12 @@ static int uvc_probe(struct usb_interface *intf,
goto error;
}
+ /* Parse the control class. */
+ if (uvc_ctrl_class_parse(dev) < 0) {
+ uvc_dbg(dev, PROBE, "Unable to parse UVC CTRL CLASS\n");
+ goto error;
+ }
+
dev_info(&dev->udev->dev, "Found UVC %u.%02x device %s (%04x:%04x)\n",
dev->uvc_version >> 8, dev->uvc_version & 0xff,
udev->product ? udev->product : "<unnamed>",
@@ -106,6 +106,7 @@ static int uvc_mc_init_entity(struct uvc_video_chain *chain,
case UVC_OTT_MEDIA_TRANSPORT_OUTPUT:
case UVC_EXTERNAL_VENDOR_SPECIFIC:
case UVC_EXT_GPIO_UNIT:
+ case UVC_CTRL_CLASS_UNIT:
default:
function = MEDIA_ENT_F_V4L2_SUBDEV_UNKNOWN;
break;
@@ -41,6 +41,9 @@
#define UVC_EXT_GPIO_UNIT 0x7ffe
#define UVC_EXT_GPIO_UNIT_ID 0x100
+#define UVC_CTRL_CLASS_UNIT 0x7ffd
+#define UVC_CTRL_CLASS_UNIT_ID 0x101
+
/* ------------------------------------------------------------------------
* GUIDs
*/
@@ -183,6 +186,7 @@
*/
#define UVC_CC_CAMERA_CLASS 0
#define UVC_CC_USER_CLASS 1
+#define UVC_CC_LAST_CLASS UVC_CC_USER_CLASS
/* ------------------------------------------------------------------------
* Driver specific constants.
@@ -375,6 +379,11 @@ struct uvc_entity {
struct gpio_desc *gpio_privacy;
int irq;
} gpio;
+
+ struct {
+ u8 bControlSize;
+ u8 *bmControls;
+ } ctrl_class;
};
u8 bNrInPins;
@@ -715,6 +724,7 @@ struct uvc_device {
} async_ctrl;
struct uvc_entity *gpio_unit;
+ struct uvc_entity *ctrl_class_unit;
};
enum uvc_handle_state {
Create a virtual entity that holds all the class control. Fixes v4l2-compliance: Control ioctls (Input 0): fail: v4l2-test-controls.cpp(216): missing control class for class 00980000 fail: v4l2-test-controls.cpp(253): missing control class for class 009a0000 test VIDIOC_QUERY_EXT_CTRL/QUERYMENU: FAIL Signed-off-by: Ricardo Ribalda <ribalda@chromium.org> --- drivers/media/usb/uvc/uvc_ctrl.c | 3 ++ drivers/media/usb/uvc/uvc_driver.c | 52 +++++++++++++++++++++++++++--- drivers/media/usb/uvc/uvc_entity.c | 1 + drivers/media/usb/uvc/uvcvideo.h | 10 ++++++ 4 files changed, 61 insertions(+), 5 deletions(-)