public inbox for linux-media@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 1/3] [media] uvcvideo: variable size controls
@ 2017-07-16 14:53 Philipp Zabel
  2017-07-16 14:53 ` [PATCH v2 2/3] [media] uvcvideo: flag variable length control on Oculus Rift CV1 Sensor Philipp Zabel
  2017-07-16 14:53 ` [PATCH v2 3/3] [media] uvcvideo: skip non-extension unit controls on Oculus Rift Sensors Philipp Zabel
  0 siblings, 2 replies; 3+ messages in thread
From: Philipp Zabel @ 2017-07-16 14:53 UTC (permalink / raw)
  To: linux-media; +Cc: Laurent Pinchart, Philipp Zabel

Some USB webcam controllers have extension unit controls that report
different lengths via GET_LEN, depending on internal state. Add a flag
to mark these controls as variable length and issue GET_LEN before
GET/SET_CUR transfers to verify the current length.

Signed-off-by: Philipp Zabel <philipp.zabel@gmail.com>
---
Changes since v1:
 - Split uvc_ctrl_fill_xu_info_size and uvc_ctrl_fill_xu_info_flags out of
   uvc_ctrl_fill_xu_info.
 - Add uvc_ctrl_update_xu_info_size and reuse uvc_ctrl_fill_xu_info_size.
 - Call uvc_ctrl_update_xu_info_size from uvc_xu_ctrl_query instead of open
   coding the size update, thereby fixing a double kfree.
---
 drivers/media/usb/uvc/uvc_ctrl.c | 98 ++++++++++++++++++++++++++++++++++------
 include/uapi/linux/uvcvideo.h    |  2 +
 2 files changed, 87 insertions(+), 13 deletions(-)

diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
index c2ee6e39fd0c..43e8851cc381 100644
--- a/drivers/media/usb/uvc/uvc_ctrl.c
+++ b/drivers/media/usb/uvc/uvc_ctrl.c
@@ -1597,7 +1597,7 @@ static void uvc_ctrl_fixup_xu_info(struct uvc_device *dev,
 		struct usb_device_id id;
 		u8 entity;
 		u8 selector;
-		u8 flags;
+		u16 flags;
 	};
 
 	static const struct uvc_ctrl_fixup fixups[] = {
@@ -1629,10 +1629,7 @@ static void uvc_ctrl_fixup_xu_info(struct uvc_device *dev,
 	}
 }
 
-/*
- * Query control information (size and flags) for XU controls.
- */
-static int uvc_ctrl_fill_xu_info(struct uvc_device *dev,
+static int uvc_ctrl_fill_xu_info_size(struct uvc_device *dev,
 	const struct uvc_control *ctrl, struct uvc_control_info *info)
 {
 	u8 *data;
@@ -1642,11 +1639,6 @@ static int uvc_ctrl_fill_xu_info(struct uvc_device *dev,
 	if (data == NULL)
 		return -ENOMEM;
 
-	memcpy(info->entity, ctrl->entity->extension.guidExtensionCode,
-	       sizeof(info->entity));
-	info->index = ctrl->index;
-	info->selector = ctrl->index + 1;
-
 	/* Query and verify the control length (GET_LEN) */
 	ret = uvc_query_ctrl(dev, UVC_GET_LEN, ctrl->entity->id, dev->intfnum,
 			     info->selector, data, 2);
@@ -1659,6 +1651,21 @@ static int uvc_ctrl_fill_xu_info(struct uvc_device *dev,
 
 	info->size = le16_to_cpup((__le16 *)data);
 
+done:
+	kfree(data);
+	return ret;
+}
+
+static int uvc_ctrl_fill_xu_info_flags(struct uvc_device *dev,
+	const struct uvc_control *ctrl, struct uvc_control_info *info)
+{
+	u8 *data;
+	int ret;
+
+	data = kmalloc(1, GFP_KERNEL);
+	if (data == NULL)
+		return -ENOMEM;
+
 	/* Query the control information (GET_INFO) */
 	ret = uvc_query_ctrl(dev, UVC_GET_INFO, ctrl->entity->id, dev->intfnum,
 			     info->selector, data, 1);
@@ -1678,6 +1685,32 @@ static int uvc_ctrl_fill_xu_info(struct uvc_device *dev,
 		    | (data[0] & UVC_CONTROL_CAP_AUTOUPDATE ?
 		       UVC_CTRL_FLAG_AUTO_UPDATE : 0);
 
+done:
+	kfree(data);
+	return ret;
+}
+
+/*
+ * Query control information (size and flags) for XU controls.
+ */
+static int uvc_ctrl_fill_xu_info(struct uvc_device *dev,
+	const struct uvc_control *ctrl, struct uvc_control_info *info)
+{
+	int ret;
+
+	memcpy(info->entity, ctrl->entity->extension.guidExtensionCode,
+	       sizeof(info->entity));
+	info->index = ctrl->index;
+	info->selector = ctrl->index + 1;
+
+	ret = uvc_ctrl_fill_xu_info_size(dev, ctrl, info);
+	if (ret < 0)
+		return ret;
+
+	ret = uvc_ctrl_fill_xu_info_flags(dev, ctrl, info);
+	if (ret < 0)
+		return ret;
+
 	uvc_ctrl_fixup_xu_info(dev, ctrl, info);
 
 	uvc_trace(UVC_TRACE_CONTROL, "XU control %pUl/%u queried: len %u, "
@@ -1687,9 +1720,7 @@ static int uvc_ctrl_fill_xu_info(struct uvc_device *dev,
 		  (info->flags & UVC_CTRL_FLAG_SET_CUR) ? 1 : 0,
 		  (info->flags & UVC_CTRL_FLAG_AUTO_UPDATE) ? 1 : 0);
 
-done:
-	kfree(data);
-	return ret;
+	return 0;
 }
 
 static int uvc_ctrl_add_info(struct uvc_device *dev, struct uvc_control *ctrl,
@@ -1717,6 +1748,40 @@ static int uvc_ctrl_init_xu_ctrl(struct uvc_device *dev,
 	return ret;
 }
 
+/*
+ * Update control size for variable length XU controls.
+ */
+static int uvc_ctrl_update_xu_info_size(struct uvc_device *dev,
+	struct uvc_control *ctrl)
+{
+	u16 size = ctrl->info.size;
+	int ret;
+
+	if (!(ctrl->info.flags & UVC_CTRL_FLAG_VARIABLE_LEN))
+		return 0;
+
+	/* Check if the control size has changed */
+	ret = uvc_ctrl_fill_xu_info_size(dev, ctrl, &ctrl->info);
+	if (ret < 0)
+		return ret;
+
+	if (ctrl->info.size != size) {
+		uvc_trace(UVC_TRACE_CONTROL,
+			  "XU control %pUl/%u queried: len %u -> %u\n",
+			  ctrl->info.entity, ctrl->info.selector,
+			  size, ctrl->info.size);
+
+		/* Resize array for saved control values */
+		kfree(ctrl->uvc_data);
+		ctrl->uvc_data = kzalloc(ctrl->info.size * UVC_CTRL_DATA_LAST +
+					 1, GFP_KERNEL);
+		if (ctrl->uvc_data == NULL)
+			return -ENOMEM;
+	}
+
+	return 0;
+}
+
 int uvc_xu_ctrl_query(struct uvc_video_chain *chain,
 	struct uvc_xu_control_query *xqry)
 {
@@ -1799,6 +1864,13 @@ int uvc_xu_ctrl_query(struct uvc_video_chain *chain,
 		goto done;
 	}
 
+	if (reqflags) {
+		ret = uvc_ctrl_update_xu_info_size(chain->dev, ctrl);
+		if (ret < 0)
+			goto done;
+		size = ctrl->info.size;
+	}
+
 	if (size != xqry->size) {
 		ret = -ENOBUFS;
 		goto done;
diff --git a/include/uapi/linux/uvcvideo.h b/include/uapi/linux/uvcvideo.h
index 3b081862b9e8..0f0d63e79045 100644
--- a/include/uapi/linux/uvcvideo.h
+++ b/include/uapi/linux/uvcvideo.h
@@ -27,6 +27,8 @@
 #define UVC_CTRL_FLAG_RESTORE		(1 << 6)
 /* Control can be updated by the camera. */
 #define UVC_CTRL_FLAG_AUTO_UPDATE	(1 << 7)
+/* Control can change LEN */
+#define UVC_CTRL_FLAG_VARIABLE_LEN	(1 << 8)
 
 #define UVC_CTRL_FLAG_GET_RANGE \
 	(UVC_CTRL_FLAG_GET_CUR | UVC_CTRL_FLAG_GET_MIN | \
-- 
2.13.2

^ permalink raw reply related	[flat|nested] 3+ messages in thread

* [PATCH v2 2/3] [media] uvcvideo: flag variable length control on Oculus Rift CV1 Sensor
  2017-07-16 14:53 [PATCH v2 1/3] [media] uvcvideo: variable size controls Philipp Zabel
@ 2017-07-16 14:53 ` Philipp Zabel
  2017-07-16 14:53 ` [PATCH v2 3/3] [media] uvcvideo: skip non-extension unit controls on Oculus Rift Sensors Philipp Zabel
  1 sibling, 0 replies; 3+ messages in thread
From: Philipp Zabel @ 2017-07-16 14:53 UTC (permalink / raw)
  To: linux-media; +Cc: Laurent Pinchart, Philipp Zabel, Philipp Zabel

The extension unit controls with selectors 11 and 12 are used to make the
eSP770u webcam controller issue SPI transfers to configure the nRF51288
radio or to read the flash storage. Depending on internal state controlled
by selector 11, selector 12 reports different lengths.

Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
---
 drivers/media/usb/uvc/uvc_ctrl.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
index 43e8851cc381..1d60321a6777 100644
--- a/drivers/media/usb/uvc/uvc_ctrl.c
+++ b/drivers/media/usb/uvc/uvc_ctrl.c
@@ -1613,6 +1613,9 @@ static void uvc_ctrl_fixup_xu_info(struct uvc_device *dev,
 			UVC_CTRL_FLAG_GET_MIN | UVC_CTRL_FLAG_GET_MAX |
 			UVC_CTRL_FLAG_GET_DEF | UVC_CTRL_FLAG_SET_CUR |
 			UVC_CTRL_FLAG_AUTO_UPDATE },
+		{ { USB_DEVICE(0x2833, 0x0211) }, 4, 12,
+			UVC_CTRL_FLAG_GET_RANGE | UVC_CTRL_FLAG_SET_CUR |
+			UVC_CTRL_FLAG_VARIABLE_LEN },
 	};
 
 	unsigned int i;
-- 
2.13.2

^ permalink raw reply related	[flat|nested] 3+ messages in thread

* [PATCH v2 3/3] [media] uvcvideo: skip non-extension unit controls on Oculus Rift Sensors
  2017-07-16 14:53 [PATCH v2 1/3] [media] uvcvideo: variable size controls Philipp Zabel
  2017-07-16 14:53 ` [PATCH v2 2/3] [media] uvcvideo: flag variable length control on Oculus Rift CV1 Sensor Philipp Zabel
@ 2017-07-16 14:53 ` Philipp Zabel
  1 sibling, 0 replies; 3+ messages in thread
From: Philipp Zabel @ 2017-07-16 14:53 UTC (permalink / raw)
  To: linux-media; +Cc: Laurent Pinchart, Philipp Zabel

The Oculus Rift Sensors (DK2 and CV1) allow to configure their sensor chips
directly via I2C commands using extension unit controls. The processing and
camera unit controls do not function at all.

Signed-off-by: Philipp Zabel <philipp.zabel@gmail.com>
---
 drivers/media/usb/uvc/uvc_ctrl.c | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
index 1d60321a6777..738edb81bc0a 100644
--- a/drivers/media/usb/uvc/uvc_ctrl.c
+++ b/drivers/media/usb/uvc/uvc_ctrl.c
@@ -2213,6 +2213,10 @@ int uvc_ctrl_init_device(struct uvc_device *dev)
 {
 	struct uvc_entity *entity;
 	unsigned int i;
+	const struct usb_device_id xu_only[] = {
+		{ USB_DEVICE(0x2833, 0x0201) },
+		{ USB_DEVICE(0x2833, 0x0211) },
+	};
 
 	/* Walk the entities list and instantiate controls */
 	list_for_each_entry(entity, &dev->entities, list) {
@@ -2220,6 +2224,16 @@ int uvc_ctrl_init_device(struct uvc_device *dev)
 		unsigned int bControlSize = 0, ncontrols;
 		__u8 *bmControls = NULL;
 
+		/* Oculus Sensors only handle extension unit controls */
+		if (UVC_ENTITY_TYPE(entity) != UVC_VC_EXTENSION_UNIT) {
+			for (i = 0; i < ARRAY_SIZE(xu_only); i++) {
+				if (usb_match_one_id(dev->intf, &xu_only[i]))
+					break;
+			}
+			if (i != ARRAY_SIZE(xu_only))
+				continue;
+		}
+
 		if (UVC_ENTITY_TYPE(entity) == UVC_VC_EXTENSION_UNIT) {
 			bmControls = entity->extension.bmControls;
 			bControlSize = entity->extension.bControlSize;
-- 
2.13.2

^ permalink raw reply related	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2017-07-16 14:53 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2017-07-16 14:53 [PATCH v2 1/3] [media] uvcvideo: variable size controls Philipp Zabel
2017-07-16 14:53 ` [PATCH v2 2/3] [media] uvcvideo: flag variable length control on Oculus Rift CV1 Sensor Philipp Zabel
2017-07-16 14:53 ` [PATCH v2 3/3] [media] uvcvideo: skip non-extension unit controls on Oculus Rift Sensors Philipp Zabel

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox