[PATCH] usb: gadget: f_fs: OS descriptors support

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Add support for OS descriptors. The new format of descriptors is used,
because the "flags" field is required for extensions. os_count gives
the number of OSDesc[] elements.
The format of descriptors is given in include/uapi/linux/usb/functionfs.h.

For extended properties descriptor the usb_ext_prop_desc structure covers
only a part of a descriptor, because the wPropertyNameLength is unknown
up front.

Signed-off-by: Andrzej Pietrasiewicz <andrzej.p@xxxxxxxxxxx>
---
Rebased onto Felipe's testing/next with gadget directory cleanup patches
applied:

http://www.spinics.net/lists/linux-usb/msg109928.html

This is meant for 3.17.

@Michal: I kindly ask for your review. Your comments will be very valuable.

 drivers/usb/gadget/function/f_fs.c  | 345 +++++++++++++++++++++++++++++++++++-
 drivers/usb/gadget/function/u_fs.h  |   7 +
 include/uapi/linux/usb/functionfs.h |  87 ++++++++-
 3 files changed, 432 insertions(+), 7 deletions(-)

diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c
index 88d6fa2..55c0db7 100644
--- a/drivers/usb/gadget/function/f_fs.c
+++ b/drivers/usb/gadget/function/f_fs.c
@@ -34,6 +34,7 @@
 
 #include "u_fs.h"
 #include "u_f.h"
+#include "u_os_desc.h"
 #include "configfs.h"
 
 #define FUNCTIONFS_MAGIC	0xa647361 /* Chosen by a honest dice roll ;) */
@@ -1644,11 +1645,18 @@ enum ffs_entity_type {
 	FFS_DESCRIPTOR, FFS_INTERFACE, FFS_STRING, FFS_ENDPOINT
 };
 
+enum ffs_os_desc_type {
+	FFS_OS_DESC, FFS_OS_DESC_EXT_COMPAT, FFS_OS_DESC_EXT_PROP
+};
+
 typedef int (*ffs_entity_callback)(enum ffs_entity_type entity,
 				   u8 *valuep,
 				   struct usb_descriptor_header *desc,
 				   void *priv);
 
+typedef int (*ffs_os_desc_callback)(enum ffs_os_desc_type entity,
+				    u8 *valuep, void *data, void *priv);
+
 static int __must_check ffs_do_desc(char *data, unsigned len,
 				    ffs_entity_callback entity, void *priv)
 {
@@ -1855,11 +1863,190 @@ static int __ffs_data_do_entity(enum ffs_entity_type type,
 	return 0;
 }
 
+/*
+ * Process all extended compatibility/extended property descriptors
+ * of a feature descriptor
+ */
+static int __must_check ffs_do_os_desc(char *data, unsigned len, u8 *valuep,
+				       u16 feature_count,
+				       ffs_os_desc_callback entity, void *priv,
+				       struct usb_os_desc_header *desc)
+{
+	int ret;
+	enum ffs_os_desc_type *type = (enum ffs_os_desc_type *)valuep;
+	const unsigned _len = len;
+
+	ENTER();
+
+	/* loop over all ext compat/ext prop descriptors */
+	while (feature_count--) {
+		ret = entity(*type, (u8 *)desc, (void *)data, priv);
+		if (unlikely(ret < 0)) {
+			pr_debug("bad OS descriptor, type: %d\n", *valuep);
+			return ret;
+		}
+		data += ret;
+		len -= ret;
+	}
+	return _len - len;
+}
+
+/* Process a number of complete Feature Descriptors (Ext Compat or Ext Prop) */
+static int __must_check ffs_do_os_descs(unsigned count,
+					char *data, unsigned len,
+					ffs_os_desc_callback entity, void *priv)
+{
+	const unsigned _len = len;
+	unsigned long num = 0;
+
+	ENTER();
+
+	for (;;) {
+		int ret;
+		enum ffs_os_desc_type type;
+		u16 feature_count;
+		struct usb_os_desc_header *desc = (void *)data;
+
+		if (num == count)
+			return _len - len;
+
+		/* Record "descriptor" entity */
+		/*
+		 * Process dwLength, bcdVersion, wIndex,
+		 * get b/wCount.
+		 * Move the data pointer to the beginning of
+		 * extended compatibilities proper or
+		 * extended properties proper portions of the
+		 * data
+		 */
+		ret = entity(FFS_OS_DESC, (u8 *)&type, desc, priv);
+		if (unlikely(ret < 0)) {
+			pr_debug("entity OS_DESCRIPTOR(%02lx); ret = %d\n",
+				 num, ret);
+			return ret;
+		}
+		if (type == FFS_OS_DESC_EXT_COMPAT) {
+			struct usb_ext_compat_desc_header *h =
+				(struct usb_ext_compat_desc_header *)data;
+			feature_count = h->bCount;
+		} else if (type == FFS_OS_DESC_EXT_PROP) {
+			struct usb_ext_prop_desc_header *h = (void *)data;
+
+			feature_count = le16_to_cpu(h->wCount);
+		} else {
+			return -EINVAL;
+		}
+		len -= (ret + 2);
+		data += (ret + 2);
+
+		/*
+		 * Process all function/property descriptors
+		 * of this Feature Descriptor
+		 */
+		ret = ffs_do_os_desc(data, len, (u8 *)&type, feature_count,
+				     entity, priv, desc);
+		if (unlikely(ret < 0)) {
+			pr_debug("%s returns %d\n", __func__, ret);
+			return ret;
+		}
+
+		len -= ret;
+		data += ret;
+		++num;
+	}
+}
+
+/**
+ * Validate contents of the buffer from userspace related to OS descriptors.
+ */
+static int __ffs_data_do_os_desc(enum ffs_os_desc_type type,
+				 u8 *valuep, void *data, void *priv)
+{
+	struct ffs_data *ffs = priv;
+	__u8 length;
+
+	ENTER();
+
+	switch (type) {
+	case FFS_OS_DESC: {
+		struct usb_os_desc_header *desc = data;
+		enum ffs_os_desc_type *next_type =
+			(enum ffs_os_desc_type *)valuep;
+		__u16 bcd_version = le16_to_cpu(desc->bcdVersion);
+		__u16 w_index = le16_to_cpu(desc->wIndex);
+
+		if (bcd_version != 0x1) {
+			pr_vdebug("unsupported os descriptors version: %d",
+				  bcd_version);
+			return -EINVAL;
+		}
+		if (w_index != 0x4 && w_index != 0x5) {
+			pr_vdebug("unsupported os descriptor type: %d",
+				  w_index);
+			return -EINVAL;
+		}
+		switch (w_index) {
+		case 0x4:
+			*next_type = FFS_OS_DESC_EXT_COMPAT;
+			break;
+		case 0x5:
+			*next_type = FFS_OS_DESC_EXT_PROP;
+			break;
+		}
+		length = sizeof(*desc);
+	}
+		break;
+	case FFS_OS_DESC_EXT_COMPAT: {
+		struct usb_ext_compat_desc *d = data;
+
+		if (d->bFirstInterfaceNumber >= ffs->interfaces_count)
+			return -EINVAL;
+
+		length = sizeof(struct usb_ext_compat_desc);
+	}
+		break;
+	case FFS_OS_DESC_EXT_PROP: {
+		struct usb_os_desc_header *desc =
+			(struct usb_os_desc_header *)valuep;
+		struct usb_ext_prop_desc *d = data;
+		__le32 type, pdl;
+		__le16 pnl;
+
+		if (desc->interface >= ffs->interfaces_count)
+			return -EINVAL;
+		length = le32_to_cpu(d->dwSize);
+		type = le32_to_cpu(d->dwPropertyDataType);
+		if (type < USB_EXT_PROP_UNICODE ||
+		    type > USB_EXT_PROP_UNICODE_MULTI) {
+			pr_vdebug("unsupported os descriptor property type: %d",
+				  type);
+			return -EINVAL;
+		}
+		pnl = le16_to_cpu(d->wPropertyNameLength);
+		pdl = le32_to_cpu(*(u32 *)(data + 10 + pnl));
+		if (length != 14 + pnl + pdl) {
+#define FMT "invalid os descriptor length: %d pnl:%d pdl:%d (descriptor %d)\n"
+			pr_vdebug(FMT, length, pnl, pdl, type);
+#undef FMT
+			return -EINVAL;
+		}
+		++ffs->ms_os_descs_ext_prop_count;
+		ffs->ms_os_descs_ext_prop_name_len += (pnl << 1);
+		ffs->ms_os_descs_ext_prop_data_len += pdl;
+	}
+		break;
+	default:
+		pr_vdebug("unknown descriptor: %d\n", type);
+		return -EINVAL;
+	}
+	return length;
+}
+
 static int __ffs_data_got_descs(struct ffs_data *ffs,
 				char *const _data, size_t len)
 {
 	char *data = _data, *raw_descs;
-	unsigned counts[3], flags;
+	unsigned os_descs_count = 0, counts[3], flags;
 	int ret = -EINVAL, i;
 
 	ENTER();
@@ -1877,7 +2064,8 @@ static int __ffs_data_got_descs(struct ffs_data *ffs,
 		flags = get_unaligned_le32(data + 8);
 		if (flags & ~(FUNCTIONFS_HAS_FS_DESC |
 			      FUNCTIONFS_HAS_HS_DESC |
-			      FUNCTIONFS_HAS_SS_DESC)) {
+			      FUNCTIONFS_HAS_SS_DESC |
+			      FUNCTIONFS_HAS_MS_OS_DESC)) {
 			ret = -ENOSYS;
 			goto error;
 		}
@@ -1900,6 +2088,11 @@ static int __ffs_data_got_descs(struct ffs_data *ffs,
 			len  -= 4;
 		}
 	}
+	if (flags & (1 << i)) {
+		os_descs_count = get_unaligned_le32(data);
+		data += 4;
+		len -= 4;
+	};
 
 	/* Read descriptors */
 	raw_descs = data;
@@ -1913,6 +2106,14 @@ static int __ffs_data_got_descs(struct ffs_data *ffs,
 		data += ret;
 		len  -= ret;
 	}
+	if (os_descs_count) {
+		ret = ffs_do_os_descs(os_descs_count, data, len,
+				      __ffs_data_do_os_desc, ffs);
+		if (ret < 0)
+			goto error;
+		data += ret;
+		len -= ret;
+	}
 
 	if (raw_descs == data || len) {
 		ret = -EINVAL;
@@ -1925,6 +2126,7 @@ static int __ffs_data_got_descs(struct ffs_data *ffs,
 	ffs->fs_descs_count	= counts[0];
 	ffs->hs_descs_count	= counts[1];
 	ffs->ss_descs_count	= counts[2];
+	ffs->ms_os_descs_count	= os_descs_count;
 
 	return 0;
 
@@ -2091,6 +2293,7 @@ static void __ffs_event_add(struct ffs_data *ffs,
 		rem_type2 = FUNCTIONFS_SUSPEND;
 		/* FALL THROUGH */
 	case FUNCTIONFS_SUSPEND:
+
 	case FUNCTIONFS_SETUP:
 		rem_type1 = type;
 		/* Discard all similar events */
@@ -2266,6 +2469,88 @@ static int __ffs_func_bind_do_nums(enum ffs_entity_type type, u8 *valuep,
 	return 0;
 }
 
+static int __ffs_func_bind_do_os_desc(enum ffs_os_desc_type type,
+				      u8 *valuep, void *data, void *priv)
+{
+	struct ffs_function *func = priv;
+	__u8 length = 0;
+
+	switch (type) {
+	case FFS_OS_DESC: {
+		struct usb_os_desc_header *desc = data;
+		enum ffs_os_desc_type *next_type =
+			(enum ffs_os_desc_type *)valuep;
+		__u16 w_index = le16_to_cpu(desc->wIndex);
+
+		switch (w_index) {
+		case 0x4:
+			*next_type = FFS_OS_DESC_EXT_COMPAT;
+			break;
+		case 0x5:
+			*next_type = FFS_OS_DESC_EXT_PROP;
+			break;
+		}
+		length = sizeof(*desc);
+	}
+		break;
+	case FFS_OS_DESC_EXT_COMPAT: {
+		struct usb_ext_compat_desc *desc = data;
+		struct usb_os_desc_table *t;
+
+		t = &func->function.os_desc_table[desc->bFirstInterfaceNumber];
+		t->if_id = func->interfaces_nums[desc->bFirstInterfaceNumber];
+		memcpy(t->os_desc->ext_compat_id, (void *)desc + 2, 16);
+		length = sizeof(*desc);
+	}
+		break;
+	case FFS_OS_DESC_EXT_PROP: {
+		struct usb_os_desc_header *h =
+			(struct usb_os_desc_header *)valuep;
+		struct usb_ext_prop_desc *desc = data;
+		struct usb_os_desc_table *t;
+		struct usb_os_desc_ext_prop *ext_prop;
+		char *ext_prop_name;
+		char *ext_prop_data;
+
+		t = &func->function.os_desc_table[h->interface];
+		t->if_id = func->interfaces_nums[h->interface];
+
+		ext_prop = func->ffs->ms_os_descs_ext_prop_avail;
+		func->ffs->ms_os_descs_ext_prop_avail += sizeof(*ext_prop);
+
+		ext_prop->type = le32_to_cpu(desc->dwPropertyDataType);
+		ext_prop->name_len = le16_to_cpu(desc->wPropertyNameLength);
+		ext_prop->data_len =
+			le32_to_cpu(*(u32 *)(data + 10 + ext_prop->name_len));
+		length = ext_prop->name_len + ext_prop->data_len + 14;
+
+		ext_prop_name = func->ffs->ms_os_descs_ext_prop_name_avail;
+		func->ffs->ms_os_descs_ext_prop_name_avail +=
+			ext_prop->name_len;
+
+		ext_prop_data = func->ffs->ms_os_descs_ext_prop_data_avail;
+		func->ffs->ms_os_descs_ext_prop_data_avail +=
+			ext_prop->data_len;
+		memcpy(ext_prop_data, data + 14 + ext_prop->name_len,
+		       ext_prop->data_len);
+		ext_prop->data_len <<= 1;
+		ext_prop->data = ext_prop_data;
+
+		memcpy(ext_prop_name, data + 10, ext_prop->name_len);
+		ext_prop->name_len <<= 1;
+		ext_prop->name = ext_prop_name;
+
+		t->os_desc->ext_prop_len +=
+			(ext_prop->name_len + ext_prop->data_len + 14);
+		++t->os_desc->ext_prop_count;
+		list_add_tail(&ext_prop->entry, &t->os_desc->ext_prop);
+	}
+		break;
+	}
+
+	return length;
+}
+
 static inline struct f_fs_opts *ffs_do_functionfs_bind(struct usb_function *f,
 						struct usb_configuration *c)
 {
@@ -2327,7 +2612,7 @@ static int _ffs_func_bind(struct usb_configuration *c,
 	const int super = gadget_is_superspeed(func->gadget) &&
 		func->ffs->ss_descs_count;
 
-	int fs_len, hs_len, ret;
+	int fs_len, hs_len, ss_len, ret, i;
 
 	/* Make it a single chunk, less management later on */
 	vla_group(d);
@@ -2339,6 +2624,18 @@ static int _ffs_func_bind(struct usb_configuration *c,
 	vla_item_with_sz(d, struct usb_descriptor_header *, ss_descs,
 		super ? ffs->ss_descs_count + 1 : 0);
 	vla_item_with_sz(d, short, inums, ffs->interfaces_count);
+	vla_item_with_sz(d, struct usb_os_desc_table, os_desc_table,
+			 c->cdev->use_os_string ? ffs->interfaces_count : 0);
+	vla_item_with_sz(d, char[16], ext_compat,
+			 c->cdev->use_os_string ? ffs->interfaces_count : 0);
+	vla_item_with_sz(d, struct usb_os_desc, os_desc,
+			 c->cdev->use_os_string ? ffs->interfaces_count : 0);
+	vla_item_with_sz(d, struct usb_os_desc_ext_prop, ext_prop,
+			 ffs->ms_os_descs_ext_prop_count);
+	vla_item_with_sz(d, char, ext_prop_name,
+			 ffs->ms_os_descs_ext_prop_name_len);
+	vla_item_with_sz(d, char, ext_prop_data,
+			 ffs->ms_os_descs_ext_prop_data_len);
 	vla_item_with_sz(d, char, raw_descs, ffs->raw_descs_length);
 	char *vlabuf;
 
@@ -2353,8 +2650,20 @@ static int _ffs_func_bind(struct usb_configuration *c,
 	if (unlikely(!vlabuf))
 		return -ENOMEM;
 
+	ffs->ms_os_descs_ext_prop_avail = vla_ptr(vlabuf, d, ext_prop);
+	ffs->ms_os_descs_ext_prop_name_avail =
+		vla_ptr(vlabuf, d, ext_prop_name);
+	ffs->ms_os_descs_ext_prop_data_avail =
+		vla_ptr(vlabuf, d, ext_prop_data);
+
 	/* Zero */
 	memset(vla_ptr(vlabuf, d, eps), 0, d_eps__sz);
+	memset(vla_ptr(vlabuf, d, os_desc_table), 0, d_os_desc_table__sz);
+	memset(vla_ptr(vlabuf, d, ext_compat), 0, d_ext_compat__sz);
+	memset(vla_ptr(vlabuf, d, os_desc), 0, d_os_desc__sz);
+	memset(vla_ptr(vlabuf, d, ext_prop), 0, d_ext_prop__sz);
+	memset(vla_ptr(vlabuf, d, ext_prop_name), 0, d_ext_prop_name__sz);
+	memset(vla_ptr(vlabuf, d, ext_prop_data), 0, d_ext_prop_data__sz);
 	/* Copy descriptors  */
 	memcpy(vla_ptr(vlabuf, d, raw_descs), ffs->raw_descs,
 	       ffs->raw_descs_length);
@@ -2408,12 +2717,16 @@ static int _ffs_func_bind(struct usb_configuration *c,
 
 	if (likely(super)) {
 		func->function.ss_descriptors = vla_ptr(vlabuf, d, ss_descs);
-		ret = ffs_do_descs(ffs->ss_descs_count,
+		ss_len = ffs_do_descs(ffs->ss_descs_count,
 				vla_ptr(vlabuf, d, raw_descs) + fs_len + hs_len,
 				d_raw_descs__sz - fs_len - hs_len,
 				__ffs_func_bind_do_descs, func);
-		if (unlikely(ret < 0))
+		if (unlikely(ss_len < 0)) {
+			ret = ss_len;
 			goto error;
+		}
+	} else {
+		ss_len = 0;
 	}
 
 	/*
@@ -2429,6 +2742,28 @@ static int _ffs_func_bind(struct usb_configuration *c,
 	if (unlikely(ret < 0))
 		goto error;
 
+	func->function.os_desc_table = vla_ptr(vlabuf, d, os_desc_table);
+	if (c->cdev->use_os_string)
+		for (i = 0; i < ffs->interfaces_count; ++i) {
+			struct usb_os_desc *desc;
+
+			desc = func->function.os_desc_table[i].os_desc =
+				vla_ptr(vlabuf, d, os_desc) +
+				i * sizeof(struct usb_os_desc);
+			desc->ext_compat_id =
+				vla_ptr(vlabuf, d, ext_compat) + i * 16;
+			INIT_LIST_HEAD(&desc->ext_prop);
+		}
+	ret = ffs_do_os_descs(ffs->ms_os_descs_count,
+			      vla_ptr(vlabuf, d, raw_descs) +
+			      fs_len + hs_len + ss_len,
+			      d_raw_descs__sz - fs_len - hs_len - ss_len,
+			      __ffs_func_bind_do_os_desc, func);
+	func->function.os_desc_n =
+		c->cdev->use_os_string ? ffs->interfaces_count : 0;
+	if (unlikely(ret < 0))
+		goto error;
+
 	/* And we're done */
 	ffs_event_add(ffs, FUNCTIONFS_BIND);
 	return 0;
diff --git a/drivers/usb/gadget/function/u_fs.h b/drivers/usb/gadget/function/u_fs.h
index bf0ba37..63d6e71 100644
--- a/drivers/usb/gadget/function/u_fs.h
+++ b/drivers/usb/gadget/function/u_fs.h
@@ -216,6 +216,13 @@ struct ffs_data {
 	unsigned			fs_descs_count;
 	unsigned			hs_descs_count;
 	unsigned			ss_descs_count;
+	unsigned			ms_os_descs_count;
+	unsigned			ms_os_descs_ext_prop_count;
+	unsigned			ms_os_descs_ext_prop_name_len;
+	unsigned			ms_os_descs_ext_prop_data_len;
+	void				*ms_os_descs_ext_prop_avail;
+	void				*ms_os_descs_ext_prop_name_avail;
+	void				*ms_os_descs_ext_prop_data_avail;
 
 	unsigned short			strings_count;
 	unsigned short			interfaces_count;
diff --git a/include/uapi/linux/usb/functionfs.h b/include/uapi/linux/usb/functionfs.h
index 2a4b4a7..4ec3798 100644
--- a/include/uapi/linux/usb/functionfs.h
+++ b/include/uapi/linux/usb/functionfs.h
@@ -18,10 +18,9 @@ enum functionfs_flags {
 	FUNCTIONFS_HAS_FS_DESC = 1,
 	FUNCTIONFS_HAS_HS_DESC = 2,
 	FUNCTIONFS_HAS_SS_DESC = 4,
+	FUNCTIONFS_HAS_MS_OS_DESC = 8,
 };
 
-#ifndef __KERNEL__
-
 /* Descriptor of an non-audio endpoint */
 struct usb_endpoint_descriptor_no_audio {
 	__u8  bLength;
@@ -33,6 +32,42 @@ struct usb_endpoint_descriptor_no_audio {
 	__u8  bInterval;
 } __attribute__((packed));
 
+/* MS OS Descriptor header */
+struct usb_os_desc_header {
+	__u8	interface;
+	__u32	dwLength;
+	__u16	bcdVersion;
+	__u16	wIndex;
+} __attribute__((packed));
+
+/* MS OS Extended Compatibility Descriptor header */
+struct usb_ext_compat_desc_header {
+	struct	usb_os_desc_header header;
+	__u8	bCount;
+	__u8	Reserved;
+} __attribute__((packed));
+
+struct usb_ext_compat_desc {
+	__u8	bFirstInterfaceNumber;
+	__u8	Reserved1;
+	__u8	CompatibleID[8];
+	__u8	SubCompatibleID[8];
+	__u8	Reserved2[6];
+};
+
+/* MS OS Extended Properties Descriptor header */
+struct usb_ext_prop_desc_header {
+	struct	usb_os_desc_header header;
+	__u16	wCount;
+} __attribute__((packed));
+
+struct usb_ext_prop_desc {
+	__u32	dwSize;
+	__u32	dwPropertyDataType;
+	__u16	wPropertyNameLength;
+} __attribute__((packed));
+
+#ifndef __KERNEL__
 
 /*
  * Descriptors format:
@@ -45,9 +80,11 @@ struct usb_endpoint_descriptor_no_audio {
  * |     | fs_count  | LE32         | number of full-speed descriptors     |
  * |     | hs_count  | LE32         | number of high-speed descriptors     |
  * |     | ss_count  | LE32         | number of super-speed descriptors    |
+ * |     | os_count  | LE32         | number of MS OS descriptors          |
  * |     | fs_descrs | Descriptor[] | list of full-speed descriptors       |
  * |     | hs_descrs | Descriptor[] | list of high-speed descriptors       |
  * |     | ss_descrs | Descriptor[] | list of super-speed descriptors      |
+ * |     | os_descrs | OSDesc[]     | list of MS OS descriptors            |
  *
  * Depending on which flags are set, various fields may be missing in the
  * structure.  Any flags that are not recognised cause the whole block to be
@@ -74,6 +111,52 @@ struct usb_endpoint_descriptor_no_audio {
  * |   0 | bLength         | U8   | length of the descriptor |
  * |   1 | bDescriptorType | U8   | descriptor type          |
  * |   2 | payload         |      | descriptor's payload     |
+ *
+ * OSDesc[] is an array of valid MS OS Feature Descriptors which have one of
+ * the following formats:
+ *
+ * | off | name            | type | description              |
+ * |-----+-----------------+------+--------------------------|
+ * |   0 | inteface        | U8   | related interface number |
+ * |   1 | dwLength        | U32  | length of the descriptor |
+ * |   5 | bcdVersion      | U16  | currently supported: 1   |
+ * |   7 | wIndex          | U16  | currently supported: 4   |
+ * |   9 | bCount          | U8   | number of ext. compat.   |
+ * |  10 | Reserved        | U8   | 0                        |
+ * |  11 | ExtCompat[]     |      | list of ext. compat. d.  |
+ *
+ * | off | name            | type | description              |
+ * |-----+-----------------+------+--------------------------|
+ * |   0 | inteface        | U8   | related interface number |
+ * |   1 | dwLength        | U32  | length of the descriptor |
+ * |   5 | bcdVersion      | U16  | currently supported: 1   |
+ * |   7 | wIndex          | U16  | currently supported: 5   |
+ * |   9 | wCount          | U16  | number of ext. compat.   |
+ * |  11 | ExtProp[]       |      | list of ext. prop. d.    |
+ *
+ * ExtCompat[] is an array of valid Extended Compatiblity descriptors
+ * which have the following format:
+ *
+ * | off | name                  | type | description                         |
+ * |-----+-----------------------+------+-------------------------------------|
+ * |   0 | bFirstInterfaceNumber | U8   | index of the interface or of the 1st|
+ * |     |                       |      | interface in an IAD group           |
+ * |   1 | Reserved              | U8   | 0                                   |
+ * |   2 | CompatibleID          | U8[8]| compatible ID string                |
+ * |  10 | SubCompatibleID       | U8[8]| subcompatible ID string             |
+ * |  18 | Reserved              | U8[6]| 0                                   |
+ *
+ * ExtProp[] is an array of valid Extended Properties descriptors
+ * which have the following format:
+ *
+ * | off | name                  | type | description                         |
+ * |-----+-----------------------+------+-------------------------------------|
+ * |   0 | dwSize                | U32  | length of the descriptor            |
+ * |   4 | dwPropertyDataType    | U32  | 1..7                                |
+ * |   8 | wPropertyNameLength   | U16  | bPropertyName length (NL)           |
+ * |  10 | bPropertyName         |U8[NL]| name of this property               |
+ * |10+NL| dwPropertyDataLength  | U32  | bPropertyData length (DL)           |
+ * |14+NL| bProperty             |U8[DL]| payload of this property            |
  */
 
 struct usb_functionfs_strings_head {
-- 
1.8.3.2

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux