Commit 2dc8b5128777818d7dcba8ce1fdf954b9e998220

Authored by Li Jun
Committed by Ye Li
1 parent 3cc5601d80

MLK-18376-3 usb: gadget: OS Feature Descriptors support

This is a proting patch from linux kernel: 37a3a533429e
("usb: gadget: OS Feature Descriptors support"), the original commit
log see below:

There is a custom (non-USB IF) extension to the USB standard:

http://msdn.microsoft.com/library/windows/hardware/gg463182

They grant permission to use the specification - there is
"Microsoft OS Descriptor Specification License Agreement"
under the link mentioned above, and its Section 2 "Grant
of License", letter (b) reads:

"Patent license. Microsoft hereby grants to You a nonexclusive,
royalty-free, nontransferable, worldwide license under Microsoft’s
patents embodied solely within the Specification and that are owned
or licensable by Microsoft to make, use, import, offer to sell,
sell and distribute directly or indirectly to Your Licensees Your
Implementation. You may sublicense this patent license to Your
Licensees under the same terms and conditions."

The said extension is maintained by Microsoft for Microsoft.

Yet it is fairly common for various devices to use it, and a
popular proprietary operating system expects devices to provide
"OS descriptors", so Linux-based USB gadgets whishing to be able
to talk to a variety of operating systems should be able to provide
the "OS descriptors".

This patch adds optional support for gadgets whishing to expose
the so called "OS Feature Descriptors", that is "Extended Compatibility ID"
and "Extended Properties".

Hosts which do request "OS descriptors" from gadgets do so during
the enumeration phase and before the configuration is set with
SET_CONFIGURATION. What is more, those hosts never ask for configurations
at indices other than 0. Therefore, gadgets whishing to provide
"OS descriptors" must designate one configuration to be used with
this kind of hosts - this is what os_desc_config is added for in
struct usb_composite_dev. There is an additional advantage to it:
if a gadget provides "OS descriptors" and designates one configuration
to be used with such non-USB-compliant hosts it can invoke
"usb_add_config" in any order because the designated configuration
will be reported to be at index 0 anyway.

This patch also adds handling vendor-specific requests addressed
at device or interface and related to handling "OS descriptors"."

Signed-off-by: Li Jun <jun.li@nxp.com>
(cherry picked from commit 859be2fc12dbd1b99e140641f2d7fa14df29c9dd)
(cherry picked from commit b524637d502ca75e6eb385b59df708f858a6da2a)
(cherry picked from commit 56ac0900c5182055a771fd2777f0bbb2295f49a8)

Showing 3 changed files with 431 additions and 1 deletions Side-by-side Diff

drivers/usb/gadget/composite.c
... ... @@ -10,6 +10,7 @@
10 10 #include <dm/devres.h>
11 11 #include <linux/bitops.h>
12 12 #include <linux/usb/composite.h>
  13 +#include "u_os_desc.h"
13 14  
14 15 #define USB_BUFSIZ 4096
15 16  
... ... @@ -242,6 +243,7 @@
242 243 u8 type = w_value >> 8;
243 244 int hs = 0;
244 245 struct usb_configuration *c;
  246 + struct list_head *pos;
245 247  
246 248 if (gadget_is_dualspeed(gadget)) {
247 249 if (gadget->speed == USB_SPEED_HIGH)
... ... @@ -253,7 +255,20 @@
253 255 }
254 256  
255 257 w_value &= 0xff;
256   - list_for_each_entry(c, &cdev->configs, list) {
  258 +
  259 + pos = &cdev->configs;
  260 + c = cdev->os_desc_config;
  261 + if (c)
  262 + goto check_config;
  263 +
  264 + while ((pos = pos->next) != &cdev->configs) {
  265 + c = list_entry(pos, typeof(*c), list);
  266 +
  267 + /* skip OS Descriptors config which is handled separately */
  268 + if (c == cdev->os_desc_config)
  269 + continue;
  270 +
  271 +check_config:
257 272 if (speed == USB_SPEED_HIGH) {
258 273 if (!c->highspeed)
259 274 continue;
... ... @@ -777,6 +792,156 @@
777 792 return le16_to_cpu(bos->wTotalLength);
778 793 }
779 794  
  795 +static int count_ext_compat(struct usb_configuration *c)
  796 +{
  797 + int i, res;
  798 +
  799 + res = 0;
  800 + for (i = 0; i < c->next_interface_id; ++i) {
  801 + struct usb_function *f;
  802 + int j;
  803 +
  804 + f = c->interface[i];
  805 + for (j = 0; j < f->os_desc_n; ++j) {
  806 + struct usb_os_desc *d;
  807 +
  808 + if (i != f->os_desc_table[j].if_id)
  809 + continue;
  810 + d = f->os_desc_table[j].os_desc;
  811 + if (d && d->ext_compat_id)
  812 + ++res;
  813 + }
  814 + }
  815 + BUG_ON(res > 255);
  816 + return res;
  817 +}
  818 +
  819 +static void fill_ext_compat(struct usb_configuration *c, u8 *buf)
  820 +{
  821 + int i, count;
  822 +
  823 + count = 16;
  824 + for (i = 0; i < c->next_interface_id; ++i) {
  825 + struct usb_function *f;
  826 + int j;
  827 +
  828 + f = c->interface[i];
  829 + for (j = 0; j < f->os_desc_n; ++j) {
  830 + struct usb_os_desc *d;
  831 +
  832 + if (i != f->os_desc_table[j].if_id)
  833 + continue;
  834 + d = f->os_desc_table[j].os_desc;
  835 + if (d && d->ext_compat_id) {
  836 + *buf++ = i;
  837 + *buf++ = 0x01;
  838 + memcpy(buf, d->ext_compat_id, 16);
  839 + buf += 22;
  840 + } else {
  841 + ++buf;
  842 + *buf = 0x01;
  843 + buf += 23;
  844 + }
  845 + count += 24;
  846 + if (count >= 4096)
  847 + return;
  848 + }
  849 + }
  850 +}
  851 +
  852 +static int count_ext_prop(struct usb_configuration *c, int interface)
  853 +{
  854 + struct usb_function *f;
  855 + int j;
  856 +
  857 + f = c->interface[interface];
  858 + for (j = 0; j < f->os_desc_n; ++j) {
  859 + struct usb_os_desc *d;
  860 +
  861 + if (interface != f->os_desc_table[j].if_id)
  862 + continue;
  863 + d = f->os_desc_table[j].os_desc;
  864 + if (d && d->ext_compat_id)
  865 + return d->ext_prop_count;
  866 + }
  867 + return 0;
  868 +}
  869 +
  870 +static int len_ext_prop(struct usb_configuration *c, int interface)
  871 +{
  872 + struct usb_function *f;
  873 + struct usb_os_desc *d;
  874 + int j, res;
  875 +
  876 + res = 10; /* header length */
  877 + f = c->interface[interface];
  878 + for (j = 0; j < f->os_desc_n; ++j) {
  879 + if (interface != f->os_desc_table[j].if_id)
  880 + continue;
  881 + d = f->os_desc_table[j].os_desc;
  882 + if (d)
  883 + return min(res + d->ext_prop_len, 4096);
  884 + }
  885 + return res;
  886 +}
  887 +
  888 +static int fill_ext_prop(struct usb_configuration *c, int interface, u8 *buf)
  889 +{
  890 + struct usb_function *f;
  891 + struct usb_os_desc *d;
  892 + struct usb_os_desc_ext_prop *ext_prop;
  893 + int j, count, n, ret;
  894 + u8 *start = buf;
  895 +
  896 + f = c->interface[interface];
  897 + for (j = 0; j < f->os_desc_n; ++j) {
  898 + if (interface != f->os_desc_table[j].if_id)
  899 + continue;
  900 + d = f->os_desc_table[j].os_desc;
  901 + if (d)
  902 + list_for_each_entry(ext_prop, &d->ext_prop, entry) {
  903 + /* 4kB minus header length */
  904 + n = buf - start;
  905 + if (n >= 4086)
  906 + return 0;
  907 +
  908 + count = ext_prop->data_len +
  909 + ext_prop->name_len + 14;
  910 + if (count > 4086 - n)
  911 + return -EINVAL;
  912 + usb_ext_prop_put_size(buf, count);
  913 + usb_ext_prop_put_type(buf, ext_prop->type);
  914 + ret = usb_ext_prop_put_name(buf, ext_prop->name,
  915 + ext_prop->name_len);
  916 + if (ret < 0)
  917 + return ret;
  918 + switch (ext_prop->type) {
  919 + case USB_EXT_PROP_UNICODE:
  920 + case USB_EXT_PROP_UNICODE_ENV:
  921 + case USB_EXT_PROP_UNICODE_LINK:
  922 + usb_ext_prop_put_unicode(buf, ret,
  923 + ext_prop->data,
  924 + ext_prop->data_len);
  925 + break;
  926 + case USB_EXT_PROP_BINARY:
  927 + usb_ext_prop_put_binary(buf, ret,
  928 + ext_prop->data,
  929 + ext_prop->data_len);
  930 + break;
  931 + case USB_EXT_PROP_LE32:
  932 + /* not implemented */
  933 + case USB_EXT_PROP_BE32:
  934 + /* not implemented */
  935 + default:
  936 + return -EINVAL;
  937 + }
  938 + buf += count;
  939 + }
  940 + }
  941 +
  942 + return 0;
  943 +}
  944 +
780 945 /*
781 946 * The setup() callback implements all the ep0 functionality that's
782 947 * not handled lower down, in hardware or the hardware driver(like
... ... @@ -933,6 +1098,91 @@
933 1098 break;
934 1099 default:
935 1100 unknown:
  1101 + /*
  1102 + * OS descriptors handling
  1103 + */
  1104 + if (cdev->use_os_string && cdev->os_desc_config &&
  1105 + (ctrl->bRequestType & USB_TYPE_VENDOR) &&
  1106 + ctrl->bRequest == cdev->b_vendor_code) {
  1107 + struct usb_configuration *os_desc_cfg;
  1108 + u8 *buf;
  1109 + int interface;
  1110 + int count = 0;
  1111 +
  1112 + buf = req->buf;
  1113 + os_desc_cfg = cdev->os_desc_config;
  1114 + memset(buf, 0, w_length);
  1115 + buf[5] = 0x01;
  1116 + switch (ctrl->bRequestType & USB_RECIP_MASK) {
  1117 + case USB_RECIP_DEVICE:
  1118 + if (w_index != 0x4 || (w_value >> 8))
  1119 + break;
  1120 + buf[6] = w_index;
  1121 + if (w_length == 0x10) {
  1122 + /* Number of ext compat interfaces */
  1123 + count = count_ext_compat(os_desc_cfg);
  1124 + buf[8] = count;
  1125 + count *= 24; /* 24 B/ext compat desc */
  1126 + count += 16; /* header */
  1127 + put_unaligned_le32(count, buf);
  1128 + value = w_length;
  1129 + } else {
  1130 + /* "extended compatibility ID"s */
  1131 + count = count_ext_compat(os_desc_cfg);
  1132 + buf[8] = count;
  1133 + count *= 24; /* 24 B/ext compat desc */
  1134 + count += 16; /* header */
  1135 + put_unaligned_le32(count, buf);
  1136 + buf += 16;
  1137 + fill_ext_compat(os_desc_cfg, buf);
  1138 + value = w_length;
  1139 + }
  1140 + break;
  1141 + case USB_RECIP_INTERFACE:
  1142 + if (w_index != 0x5 || (w_value >> 8))
  1143 + break;
  1144 + interface = w_value & 0xFF;
  1145 + buf[6] = w_index;
  1146 + if (w_length == 0x0A) {
  1147 + count = count_ext_prop(os_desc_cfg,
  1148 + interface);
  1149 + put_unaligned_le16(count, buf + 8);
  1150 + count = len_ext_prop(os_desc_cfg,
  1151 + interface);
  1152 + put_unaligned_le32(count, buf);
  1153 +
  1154 + value = w_length;
  1155 + } else {
  1156 + count = count_ext_prop(os_desc_cfg,
  1157 + interface);
  1158 + put_unaligned_le16(count, buf + 8);
  1159 + count = len_ext_prop(os_desc_cfg,
  1160 + interface);
  1161 + put_unaligned_le32(count, buf);
  1162 + buf += 10;
  1163 + value = fill_ext_prop(os_desc_cfg,
  1164 + interface, buf);
  1165 + if (value < 0)
  1166 + return value;
  1167 +
  1168 + value = w_length;
  1169 + }
  1170 + break;
  1171 + }
  1172 +
  1173 + if (value >= 0) {
  1174 + req->length = value;
  1175 + req->zero = value < w_length;
  1176 + value = usb_ep_queue(gadget->ep0, req, GFP_KERNEL);
  1177 + if (value < 0) {
  1178 + debug("ep_queue --> %d\n", value);
  1179 + req->status = 0;
  1180 + composite_setup_complete(gadget->ep0, req);
  1181 + }
  1182 + }
  1183 + return value;
  1184 + }
  1185 +
936 1186 debug("non-core control req%02x.%02x v%04x i%04x l%d\n",
937 1187 ctrl->bRequestType, ctrl->bRequest,
938 1188 w_value, w_index, w_length);
drivers/usb/gadget/u_os_desc.h
  1 +/*
  2 + * u_os_desc.h
  3 + *
  4 + * Utility definitions for "OS Descriptors" support
  5 + *
  6 + * Copyright (c) 2014 Samsung Electronics Co., Ltd.
  7 + * http://www.samsung.com
  8 + *
  9 + * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com>
  10 + *
  11 + * This program is free software; you can redistribute it and/or modify
  12 + * it under the terms of the GNU General Public License version 2 as
  13 + * published by the Free Software Foundation.
  14 + */
  15 +
  16 +#ifndef __U_OS_DESC_H__
  17 +#define __U_OS_DESC_H__
  18 +
  19 +#include <linux/utf.h>
  20 +
  21 +#define USB_EXT_PROP_DW_SIZE 0
  22 +#define USB_EXT_PROP_DW_PROPERTY_DATA_TYPE 4
  23 +#define USB_EXT_PROP_W_PROPERTY_NAME_LENGTH 8
  24 +#define USB_EXT_PROP_B_PROPERTY_NAME 10
  25 +#define USB_EXT_PROP_DW_PROPERTY_DATA_LENGTH 10
  26 +#define USB_EXT_PROP_B_PROPERTY_DATA 14
  27 +
  28 +#define USB_EXT_PROP_RESERVED 0
  29 +#define USB_EXT_PROP_UNICODE 1
  30 +#define USB_EXT_PROP_UNICODE_ENV 2
  31 +#define USB_EXT_PROP_BINARY 3
  32 +#define USB_EXT_PROP_LE32 4
  33 +#define USB_EXT_PROP_BE32 5
  34 +#define USB_EXT_PROP_UNICODE_LINK 6
  35 +#define USB_EXT_PROP_UNICODE_MULTI 7
  36 +
  37 +static inline u8 *__usb_ext_prop_ptr(u8 *buf, size_t offset)
  38 +{
  39 + return buf + offset;
  40 +}
  41 +
  42 +static inline u8 *usb_ext_prop_size_ptr(u8 *buf)
  43 +{
  44 + return __usb_ext_prop_ptr(buf, USB_EXT_PROP_DW_SIZE);
  45 +}
  46 +
  47 +static inline u8 *usb_ext_prop_type_ptr(u8 *buf)
  48 +{
  49 + return __usb_ext_prop_ptr(buf, USB_EXT_PROP_DW_PROPERTY_DATA_TYPE);
  50 +}
  51 +
  52 +static inline u8 *usb_ext_prop_name_len_ptr(u8 *buf)
  53 +{
  54 + return __usb_ext_prop_ptr(buf, USB_EXT_PROP_W_PROPERTY_NAME_LENGTH);
  55 +}
  56 +
  57 +static inline u8 *usb_ext_prop_name_ptr(u8 *buf)
  58 +{
  59 + return __usb_ext_prop_ptr(buf, USB_EXT_PROP_B_PROPERTY_NAME);
  60 +}
  61 +
  62 +static inline u8 *usb_ext_prop_data_len_ptr(u8 *buf, size_t off)
  63 +{
  64 + return __usb_ext_prop_ptr(buf,
  65 + USB_EXT_PROP_DW_PROPERTY_DATA_LENGTH + off);
  66 +}
  67 +
  68 +static inline u8 *usb_ext_prop_data_ptr(u8 *buf, size_t off)
  69 +{
  70 + return __usb_ext_prop_ptr(buf, USB_EXT_PROP_B_PROPERTY_DATA + off);
  71 +}
  72 +
  73 +static inline void usb_ext_prop_put_size(u8 *buf, int dw_size)
  74 +{
  75 + put_unaligned_le32(dw_size, usb_ext_prop_size_ptr(buf));
  76 +}
  77 +
  78 +static inline void usb_ext_prop_put_type(u8 *buf, int type)
  79 +{
  80 + put_unaligned_le32(type, usb_ext_prop_type_ptr(buf));
  81 +}
  82 +
  83 +static inline int usb_ext_prop_put_name(u8 *buf, const char *name, int pnl)
  84 +{
  85 + int result;
  86 +
  87 + put_unaligned_le16(pnl, usb_ext_prop_name_len_ptr(buf));
  88 + memset(usb_ext_prop_name_ptr(buf), 0, 2 * strlen(name));
  89 + result = utf8_to_utf16le(name, (__le16 *)usb_ext_prop_name_ptr(buf),
  90 + strlen(name));
  91 + if (result < 0)
  92 + return result;
  93 +
  94 + put_unaligned_le16(0, &buf[USB_EXT_PROP_B_PROPERTY_NAME + pnl - 2]);
  95 +
  96 + return pnl;
  97 +}
  98 +
  99 +static inline void usb_ext_prop_put_binary(u8 *buf, int pnl, const char *data,
  100 + int data_len)
  101 +{
  102 + put_unaligned_le32(data_len, usb_ext_prop_data_len_ptr(buf, pnl));
  103 + memcpy(usb_ext_prop_data_ptr(buf, pnl), data, data_len);
  104 +}
  105 +
  106 +static inline int usb_ext_prop_put_unicode(u8 *buf, int pnl, const char *string,
  107 + int data_len)
  108 +{
  109 + int result;
  110 + put_unaligned_le32(data_len, usb_ext_prop_data_len_ptr(buf, pnl));
  111 + memset(usb_ext_prop_data_ptr(buf, pnl), 0, 2 * (data_len >> 1));
  112 + result = utf8_to_utf16le(string, (__le16 *) usb_ext_prop_data_ptr(buf, pnl),
  113 + data_len >> 1);
  114 + if (result < 0)
  115 + return result;
  116 +
  117 + put_unaligned_le16(0,
  118 + &buf[USB_EXT_PROP_B_PROPERTY_DATA + pnl + data_len - 2]);
  119 +
  120 + return data_len;
  121 +}
  122 +
  123 +#endif /* __U_OS_DESC_H__ */
include/linux/usb/composite.h
... ... @@ -38,6 +38,53 @@
38 38 struct usb_configuration;
39 39  
40 40 /**
  41 + * struct usb_os_desc_ext_prop - describes one "Extended Property"
  42 + * @entry: used to keep a list of extended properties
  43 + * @type: Extended Property type
  44 + * @name_len: Extended Property unicode name length, including terminating '\0'
  45 + * @name: Extended Property name
  46 + * @data_len: Length of Extended Property blob (for unicode store double len)
  47 + * @data: Extended Property blob
  48 + */
  49 +struct usb_os_desc_ext_prop {
  50 + struct list_head entry;
  51 + u8 type;
  52 + int name_len;
  53 + char *name;
  54 + int data_len;
  55 + char *data;
  56 +};
  57 +
  58 +/**
  59 + * struct usb_os_desc - describes OS descriptors associated with one interface
  60 + * @ext_compat_id: 16 bytes of "Compatible ID" and "Subcompatible ID"
  61 + * @ext_prop: Extended Properties list
  62 + * @ext_prop_len: Total length of Extended Properties blobs
  63 + * @ext_prop_count: Number of Extended Properties
  64 + */
  65 +struct usb_os_desc {
  66 + char *ext_compat_id;
  67 + struct list_head ext_prop;
  68 + int ext_prop_len;
  69 + int ext_prop_count;
  70 +};
  71 +
  72 +/**
  73 + * struct usb_os_desc_table - describes OS descriptors associated with one
  74 + * interface of a usb_function
  75 + * @if_id: Interface id
  76 + * @os_desc: "Extended Compatibility ID" and "Extended Properties" of the
  77 + * interface
  78 + *
  79 + * Each interface can have at most one "Extended Compatibility ID" and a
  80 + * number of "Extended Properties".
  81 + */
  82 +struct usb_os_desc_table {
  83 + int if_id;
  84 + struct usb_os_desc *os_desc;
  85 +};
  86 +
  87 +/**
41 88 * struct usb_function - describes one function of a configuration
42 89 * @name: For diagnostics, identifies the function.
43 90 * @strings: tables of strings, keyed by identifiers assigned during bind()
... ... @@ -50,6 +97,10 @@
50 97 * the function will not be available at high speed.
51 98 * @config: assigned when @usb_add_function() is called; this is the
52 99 * configuration with which this function is associated.
  100 + * @os_desc_table: Table of (interface id, os descriptors) pairs. The function
  101 + * can expose more than one interface. If an interface is a member of
  102 + * an IAD, only the first interface of IAD has its entry in the table.
  103 + * @os_desc_n: Number of entries in os_desc_table
53 104 * @bind: Before the gadget can register, all of its functions bind() to the
54 105 * available resources including string and interface identifiers used
55 106 * in interface or class descriptors; endpoints; I/O buffers; and so on.
... ... @@ -98,6 +149,9 @@
98 149  
99 150 struct usb_configuration *config;
100 151  
  152 + struct usb_os_desc_table *os_desc_table;
  153 + unsigned os_desc_n;
  154 +
101 155 /* REVISIT: bind() functions can be marked __init, which
102 156 * makes trouble for section mismatch analysis. See if
103 157 * we can't restructure things to avoid mismatching.
104 158  
... ... @@ -292,10 +346,12 @@
292 346 * @gadget: read-only, abstracts the gadget's usb peripheral controller
293 347 * @req: used for control responses; buffer is pre-allocated
294 348 * @bufsiz: size of buffer pre-allocated in @req
  349 + * @os_desc_req: used for OS descriptors responses; buffer is pre-allocated
295 350 * @config: the currently active configuration
296 351 * @qw_sign: qwSignature part of the OS string
297 352 * @b_vendor_code: bMS_VendorCode part of the OS string
298 353 * @use_os_string: false by default, interested gadgets set it
  354 + * @os_desc_config: the configuration to be used with OS descriptors
299 355 *
300 356 * One of these devices is allocated and initialized before the
301 357 * associated device driver's bind() is called.
... ... @@ -332,6 +388,7 @@
332 388 /* OS String is a custom (yet popular) extension to the USB standard. */
333 389 u8 qw_sign[OS_STRING_QW_SIGN_LEN];
334 390 u8 b_vendor_code;
  391 + struct usb_configuration *os_desc_config;
335 392 unsigned int use_os_string:1;
336 393  
337 394 /* private: */