summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorTom Rini <trini@konsulko.com>2021-01-31 14:24:35 -0500
committerTom Rini <trini@konsulko.com>2021-01-31 14:24:35 -0500
commitb4804cdd5747d1d932bd338e0ca102ade51b8b6b (patch)
treedd3aa210c95de630ee7e62a58e7924e73ee0458a /drivers
parentfad42d3afbeb23e86fae2bb56ba863a2a5a133e1 (diff)
parent723fd5668ff2c8dd19e808778b5670d0fa6bdc4b (diff)
downloadu-boot-b4804cdd5747d1d932bd338e0ca102ade51b8b6b.tar.gz
u-boot-b4804cdd5747d1d932bd338e0ca102ade51b8b6b.tar.bz2
u-boot-b4804cdd5747d1d932bd338e0ca102ade51b8b6b.zip
Merge https://gitlab.denx.de/u-boot/custodians/u-boot-usb
- Assorted gadget changes including: - dfu: Fix handling of UBI partitions in MTD backend - gadget: f_thor: fix wrong file size cast - Extend cmd: bcb - Fixes for fastboot and rockchip gadgets - dfu: Add SCRIPT and SKIP entities - dfu/thor: Add `dfu_alt_info` reinitialization from flashed script - u-boot: Reduce size of u-boot as usbd_device_* arrays are not exported
Diffstat (limited to 'drivers')
-rw-r--r--drivers/dfu/dfu.c7
-rw-r--r--drivers/dfu/dfu_mmc.c39
-rw-r--r--drivers/dfu/dfu_mtd.c4
-rw-r--r--drivers/usb/gadget/Kconfig9
-rw-r--r--drivers/usb/gadget/ci_udc.c5
-rw-r--r--drivers/usb/gadget/composite.c392
-rw-r--r--drivers/usb/gadget/core.c45
-rw-r--r--drivers/usb/gadget/ep0.c46
-rw-r--r--drivers/usb/gadget/epautoconf.c6
-rw-r--r--drivers/usb/gadget/f_fastboot.c85
-rw-r--r--drivers/usb/gadget/f_rockusb.c7
-rw-r--r--drivers/usb/gadget/f_thor.c11
-rw-r--r--drivers/usb/gadget/g_dnl.c1
-rw-r--r--drivers/usb/gadget/u_os_desc.h123
-rw-r--r--drivers/usb/gadget/usbstring.c74
15 files changed, 692 insertions, 162 deletions
diff --git a/drivers/dfu/dfu.c b/drivers/dfu/dfu.c
index 501a60b344..213a20e7bc 100644
--- a/drivers/dfu/dfu.c
+++ b/drivers/dfu/dfu.c
@@ -26,6 +26,8 @@ static struct hash_algo *dfu_hash_algo;
static unsigned long dfu_timeout = 0;
#endif
+bool dfu_reinit_needed = false;
+
/*
* The purpose of the dfu_flush_callback() function is to
* provide callback for dfu user
@@ -139,6 +141,8 @@ int dfu_init_env_entities(char *interface, char *devstr)
char *env_bkp;
int ret = 0;
+ dfu_reinit_needed = false;
+
#ifdef CONFIG_SET_DFU_ALT_INFO
set_dfu_alt_info(interface, devstr);
#endif
@@ -614,7 +618,8 @@ const char *dfu_get_dev_type(enum dfu_device_type t)
const char *dfu_get_layout(enum dfu_layout l)
{
const char *const dfu_layout[] = {NULL, "RAW_ADDR", "FAT", "EXT2",
- "EXT3", "EXT4", "RAM_ADDR" };
+ "EXT3", "EXT4", "RAM_ADDR", "SKIP",
+ "SCRIPT" };
return dfu_layout[l];
}
diff --git a/drivers/dfu/dfu_mmc.c b/drivers/dfu/dfu_mmc.c
index 691d01c7eb..e63fa84ce4 100644
--- a/drivers/dfu/dfu_mmc.c
+++ b/drivers/dfu/dfu_mmc.c
@@ -16,6 +16,7 @@
#include <fat.h>
#include <mmc.h>
#include <part.h>
+#include <command.h>
static unsigned char *dfu_file_buf;
static u64 dfu_file_buf_len;
@@ -108,6 +109,8 @@ static int mmc_file_op(enum dfu_op op, struct dfu_entity *dfu,
case DFU_FS_EXT4:
fstype = FS_TYPE_EXT;
break;
+ case DFU_SKIP:
+ return 0;
default:
printf("%s: Layout (%s) not (yet) supported!\n", __func__,
dfu_get_layout(dfu->layout));
@@ -204,6 +207,12 @@ int dfu_write_medium_mmc(struct dfu_entity *dfu,
case DFU_FS_EXT4:
ret = mmc_file_buf_write(dfu, offset, buf, len);
break;
+ case DFU_SCRIPT:
+ ret = run_command_list(buf, *len, 0);
+ break;
+ case DFU_SKIP:
+ ret = 0;
+ break;
default:
printf("%s: Layout (%s) not (yet) supported!\n", __func__,
dfu_get_layout(dfu->layout));
@@ -216,9 +225,21 @@ int dfu_flush_medium_mmc(struct dfu_entity *dfu)
{
int ret = 0;
- if (dfu->layout != DFU_RAW_ADDR) {
- /* Do stuff here. */
+ switch (dfu->layout) {
+ case DFU_FS_FAT:
+ case DFU_FS_EXT4:
ret = mmc_file_buf_write_finish(dfu);
+ break;
+ case DFU_SCRIPT:
+ /* script may have changed the dfu_alt_info */
+ dfu_reinit_needed = true;
+ break;
+ case DFU_RAW_ADDR:
+ case DFU_SKIP:
+ break;
+ default:
+ printf("%s: Layout (%s) not (yet) supported!\n", __func__,
+ dfu_get_layout(dfu->layout));
}
return ret;
@@ -238,6 +259,9 @@ int dfu_get_medium_size_mmc(struct dfu_entity *dfu, u64 *size)
if (ret < 0)
return ret;
return 0;
+ case DFU_SCRIPT:
+ case DFU_SKIP:
+ return 0;
default:
printf("%s: Layout (%s) not (yet) supported!\n", __func__,
dfu_get_layout(dfu->layout));
@@ -316,7 +340,7 @@ void dfu_free_entity_mmc(struct dfu_entity *dfu)
int dfu_fill_entity_mmc(struct dfu_entity *dfu, char *devstr, char *s)
{
const char *entity_type;
- size_t second_arg;
+ ssize_t second_arg;
size_t third_arg;
struct mmc *mmc;
@@ -339,7 +363,7 @@ int dfu_fill_entity_mmc(struct dfu_entity *dfu, char *devstr, char *s)
* Base 0 means we'll accept (prefixed with 0x or 0) base 16, 8,
* with default 10.
*/
- second_arg = simple_strtoul(argv[1], NULL, 0);
+ second_arg = simple_strtol(argv[1], NULL, 0);
third_arg = simple_strtoul(argv[2], NULL, 0);
mmc = find_mmc_device(dfu->data.mmc.dev_num);
@@ -399,6 +423,10 @@ int dfu_fill_entity_mmc(struct dfu_entity *dfu, char *devstr, char *s)
dfu->layout = DFU_FS_FAT;
} else if (!strcmp(entity_type, "ext4")) {
dfu->layout = DFU_FS_EXT4;
+ } else if (!strcmp(entity_type, "skip")) {
+ dfu->layout = DFU_SKIP;
+ } else if (!strcmp(entity_type, "script")) {
+ dfu->layout = DFU_SCRIPT;
} else {
pr_err("Memory layout (%s) not supported!\n", entity_type);
return -ENODEV;
@@ -406,7 +434,8 @@ int dfu_fill_entity_mmc(struct dfu_entity *dfu, char *devstr, char *s)
/* if it's NOT a raw write */
if (strcmp(entity_type, "raw")) {
- dfu->data.mmc.dev = second_arg;
+ dfu->data.mmc.dev = (second_arg != -1) ? second_arg :
+ dfu->data.mmc.dev_num;
dfu->data.mmc.part = third_arg;
}
diff --git a/drivers/dfu/dfu_mtd.c b/drivers/dfu/dfu_mtd.c
index b34975dbb0..ca67585a7e 100644
--- a/drivers/dfu/dfu_mtd.c
+++ b/drivers/dfu/dfu_mtd.c
@@ -204,7 +204,7 @@ static int dfu_flush_medium_mtd(struct dfu_entity *dfu)
int ret;
/* in case of ubi partition, erase rest of the partition */
- if (dfu->data.nand.ubi) {
+ if (dfu->data.mtd.ubi) {
struct erase_info erase_op = {};
erase_op.mtd = dfu->data.mtd.info;
@@ -242,7 +242,7 @@ static unsigned int dfu_polltimeout_mtd(struct dfu_entity *dfu)
* ubi partition, as sectors which are not used need
* to be erased
*/
- if (dfu->data.nand.ubi)
+ if (dfu->data.mtd.ubi)
return DFU_MANIFEST_POLL_TIMEOUT;
return DFU_DEFAULT_POLL_TIMEOUT;
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index 7c0df5c264..4a3b22e6de 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -98,6 +98,15 @@ config USB_GADGET_DWC2_OTG_PHY_BUS_WIDTH_8
endif # USB_GADGET_DWC2_OTG
+config USB_GADGET_OS_DESCRIPTORS
+ bool "USB OS Feature Descriptors support"
+ help
+ This is a porting 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
+
config CI_UDC
bool "ChipIdea device controller"
select USB_GADGET_DUALSPEED
diff --git a/drivers/usb/gadget/ci_udc.c b/drivers/usb/gadget/ci_udc.c
index cdb8f6fb3d..226a9e6d67 100644
--- a/drivers/usb/gadget/ci_udc.c
+++ b/drivers/usb/gadget/ci_udc.c
@@ -145,6 +145,7 @@ static struct ci_drv controller = {
.name = "ci_udc",
.ops = &ci_udc_ops,
.is_dualspeed = 1,
+ .max_speed = USB_SPEED_HIGH,
},
};
@@ -335,6 +336,7 @@ static int ci_ep_enable(struct usb_ep *ep,
num = desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
in = (desc->bEndpointAddress & USB_DIR_IN) != 0;
ci_ep->desc = desc;
+ ep->desc = desc;
if (num) {
int max = get_unaligned_le16(&desc->wMaxPacketSize);
@@ -357,6 +359,7 @@ static int ci_ep_disable(struct usb_ep *ep)
struct ci_ep *ci_ep = container_of(ep, struct ci_ep, ep);
ci_ep->desc = NULL;
+ ep->desc = NULL;
return 0;
}
@@ -1015,8 +1018,6 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver)
return -EINVAL;
if (!driver->bind || !driver->setup || !driver->disconnect)
return -EINVAL;
- if (driver->speed != USB_SPEED_FULL && driver->speed != USB_SPEED_HIGH)
- return -EINVAL;
#if CONFIG_IS_ENABLED(DM_USB)
ret = usb_setup_ehci_gadget(&controller.ctrl);
diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
index 91ed7fcec5..2a309e624e 100644
--- a/drivers/usb/gadget/composite.c
+++ b/drivers/usb/gadget/composite.c
@@ -12,6 +12,7 @@
#include <linux/bitops.h>
#include <linux/bug.h>
#include <linux/usb/composite.h>
+#include "u_os_desc.h"
#define USB_BUFSIZ 4096
@@ -19,6 +20,10 @@
typedef struct { __le16 val; } __packed __le16_packed;
static struct usb_composite_driver *composite;
+static struct usb_configuration *os_desc_config;
+
+/* Microsoft OS String Descriptor */
+static char qw_sign_buf[OS_STRING_QW_SIGN_LEN / 2] = {'M', 'S', 'F', 'T', '1', '0', '0'};
static inline void le16_add_cpu_packed(__le16_packed *var, u16 val)
{
@@ -26,6 +31,22 @@ static inline void le16_add_cpu_packed(__le16_packed *var, u16 val)
}
/**
+ * struct usb_os_string - represents OS String to be reported by a gadget
+ * @bLength: total length of the entire descritor, always 0x12
+ * @bDescriptorType: USB_DT_STRING
+ * @qwSignature: the OS String proper
+ * @bMS_VendorCode: code used by the host for subsequent requests
+ * @bPad: not used, must be zero
+ */
+struct usb_os_string {
+ __u8 bLength;
+ __u8 bDescriptorType;
+ __u8 qwSignature[OS_STRING_QW_SIGN_LEN];
+ __u8 bMS_VendorCode;
+ __u8 bPad;
+} __packed;
+
+/**
* usb_add_function() - add a function to a configuration
* @config: the configuration
* @function: the function being added
@@ -67,6 +88,8 @@ int usb_add_function(struct usb_configuration *config,
config->fullspeed = 1;
if (!config->highspeed && function->hs_descriptors)
config->highspeed = 1;
+ if (!config->superspeed && function->ss_descriptors)
+ config->superspeed = 1;
done:
if (value)
@@ -202,7 +225,9 @@ static int config_buf(struct usb_configuration *config,
/* add each function's descriptors */
list_for_each_entry(f, &config->functions, list) {
- if (speed == USB_SPEED_HIGH)
+ if (speed == USB_SPEED_SUPER)
+ descriptors = f->ss_descriptors;
+ else if (speed == USB_SPEED_HIGH)
descriptors = f->hs_descriptors;
else
descriptors = f->descriptors;
@@ -228,8 +253,11 @@ static int config_desc(struct usb_composite_dev *cdev, unsigned w_value)
u8 type = w_value >> 8;
int hs = 0;
struct usb_configuration *c;
+ struct list_head *pos;
- if (gadget_is_dualspeed(gadget)) {
+ if (gadget_is_superspeed(gadget)) {
+ speed = gadget->speed;
+ } else if (gadget_is_dualspeed(gadget)) {
if (gadget->speed == USB_SPEED_HIGH)
hs = 1;
if (type == USB_DT_OTHER_SPEED_CONFIG)
@@ -239,8 +267,24 @@ static int config_desc(struct usb_composite_dev *cdev, unsigned w_value)
}
w_value &= 0xff;
- list_for_each_entry(c, &cdev->configs, list) {
- if (speed == USB_SPEED_HIGH) {
+
+ pos = &cdev->configs;
+ c = cdev->os_desc_config;
+ if (c)
+ goto check_config;
+
+ while ((pos = pos->next) != &cdev->configs) {
+ c = list_entry(pos, typeof(*c), list);
+
+ /* skip OS Descriptors config which is handled separately */
+ if (c == cdev->os_desc_config)
+ continue;
+
+check_config:
+ if (speed == USB_SPEED_SUPER) {
+ if (!c->superspeed)
+ continue;
+ } else if (speed == USB_SPEED_HIGH) {
if (!c->highspeed)
continue;
} else {
@@ -259,8 +303,12 @@ static int count_configs(struct usb_composite_dev *cdev, unsigned type)
struct usb_gadget *gadget = cdev->gadget;
unsigned count = 0;
int hs = 0;
+ int ss = 0;
struct usb_configuration *c;
+ if (gadget->speed == USB_SPEED_SUPER)
+ ss = 1;
+
if (gadget_is_dualspeed(gadget)) {
if (gadget->speed == USB_SPEED_HIGH)
hs = 1;
@@ -269,7 +317,10 @@ static int count_configs(struct usb_composite_dev *cdev, unsigned type)
}
list_for_each_entry(c, &cdev->configs, list) {
/* ignore configs that won't work at this speed */
- if (hs) {
+ if (ss) {
+ if (!c->superspeed)
+ continue;
+ } else if (hs) {
if (!c->highspeed)
continue;
} else {
@@ -353,6 +404,9 @@ static int set_config(struct usb_composite_dev *cdev,
case USB_SPEED_HIGH:
speed = "high";
break;
+ case USB_SPEED_SUPER:
+ speed = "super";
+ break;
default:
speed = "?";
break;
@@ -377,7 +431,9 @@ static int set_config(struct usb_composite_dev *cdev,
* function's setup callback instead of the current
* configuration's setup callback.
*/
- if (gadget->speed == USB_SPEED_HIGH)
+ if (gadget->speed == USB_SPEED_SUPER)
+ descriptors = f->ss_descriptors;
+ else if (gadget->speed == USB_SPEED_HIGH)
descriptors = f->hs_descriptors;
else
descriptors = f->descriptors;
@@ -457,8 +513,9 @@ int usb_add_config(struct usb_composite_dev *cdev,
list_del(&config->list);
config->cdev = NULL;
} else {
- debug("cfg %d/%p speeds:%s%s\n",
+ debug("cfg %d/%p speeds:%s%s%s\n",
config->bConfigurationValue, config,
+ config->superspeed ? " super" : "",
config->highspeed ? " high" : "",
config->fullspeed
? (gadget_is_dualspeed(cdev->gadget)
@@ -475,8 +532,24 @@ int usb_add_config(struct usb_composite_dev *cdev,
}
}
+ /*
+ * If one function of config is not super speed capable,
+ * force the gadget to be high speed so controller driver
+ * can init HW to be USB 2.0
+ */
+ if (gadget_is_superspeed(cdev->gadget)) {
+ list_for_each_entry(f, &config->functions, list) {
+ if (!f->ss_descriptors)
+ cdev->gadget->max_speed =
+ USB_SPEED_HIGH;
+ }
+ }
+
usb_ep_autoconfig_reset(cdev->gadget);
+ os_desc_config = config;
+ cdev->os_desc_config = os_desc_config;
+
done:
if (status)
debug("added config '%s'/%u --> %d\n", config->label,
@@ -577,6 +650,16 @@ static int get_string(struct usb_composite_dev *cdev,
return s->bLength;
}
+ if (cdev->use_os_string && language == 0 && id == OS_STRING_IDX) {
+ struct usb_os_string *b = buf;
+ b->bLength = sizeof(*b);
+ b->bDescriptorType = USB_DT_STRING;
+ memcpy(&b->qwSignature, cdev->qw_sign, sizeof(b->qwSignature));
+ b->bMS_VendorCode = cdev->b_vendor_code;
+ b->bPad = 0;
+ return sizeof(*b);
+ }
+
/*
* Otherwise, look up and return a specified string. String IDs
* are device-scoped, so we look up each string table we're told
@@ -703,6 +786,7 @@ static void composite_setup_complete(struct usb_ep *ep, struct usb_request *req)
static int bos_desc(struct usb_composite_dev *cdev)
{
struct usb_ext_cap_descriptor *usb_ext;
+ struct usb_dcd_config_params dcd_config_params;
struct usb_bos_descriptor *bos = cdev->req->buf;
bos->bLength = USB_DT_BOS_SIZE;
@@ -746,13 +830,173 @@ static int bos_desc(struct usb_composite_dev *cdev)
USB_HIGH_SPEED_OPERATION |
USB_5GBPS_OPERATION);
ss_cap->bFunctionalitySupport = USB_LOW_SPEED_OPERATION;
- ss_cap->bU1devExitLat = USB_DEFAULT_U1_DEV_EXIT_LAT;
- ss_cap->bU2DevExitLat =
- cpu_to_le16(USB_DEFAULT_U2_DEV_EXIT_LAT);
+
+ /* Get Controller configuration */
+ if (cdev->gadget->ops->get_config_params) {
+ cdev->gadget->ops->get_config_params(
+ &dcd_config_params);
+ } else {
+ dcd_config_params.bU1devExitLat =
+ USB_DEFAULT_U1_DEV_EXIT_LAT;
+ dcd_config_params.bU2DevExitLat =
+ cpu_to_le16(USB_DEFAULT_U2_DEV_EXIT_LAT);
+ }
+ ss_cap->bU1devExitLat = dcd_config_params.bU1devExitLat;
+ ss_cap->bU2DevExitLat = dcd_config_params.bU2DevExitLat;
}
return le16_to_cpu(bos->wTotalLength);
}
+static int count_ext_compat(struct usb_configuration *c)
+{
+ int i, res;
+
+ res = 0;
+ for (i = 0; i < c->next_interface_id; ++i) {
+ struct usb_function *f;
+ int j;
+
+ f = c->interface[i];
+ for (j = 0; j < f->os_desc_n; ++j) {
+ struct usb_os_desc *d;
+
+ if (i != f->os_desc_table[j].if_id)
+ continue;
+ d = f->os_desc_table[j].os_desc;
+ if (d && d->ext_compat_id)
+ ++res;
+ }
+ }
+ BUG_ON(res > 255);
+ return res;
+}
+
+static void fill_ext_compat(struct usb_configuration *c, u8 *buf)
+{
+ int i, count;
+
+ count = 16;
+ for (i = 0; i < c->next_interface_id; ++i) {
+ struct usb_function *f;
+ int j;
+
+ f = c->interface[i];
+ for (j = 0; j < f->os_desc_n; ++j) {
+ struct usb_os_desc *d;
+
+ if (i != f->os_desc_table[j].if_id)
+ continue;
+ d = f->os_desc_table[j].os_desc;
+ if (d && d->ext_compat_id) {
+ *buf++ = i;
+ *buf++ = 0x01;
+ memcpy(buf, d->ext_compat_id, 16);
+ buf += 22;
+ } else {
+ ++buf;
+ *buf = 0x01;
+ buf += 23;
+ }
+ count += 24;
+ if (count >= 4096)
+ return;
+ }
+ }
+}
+
+static int count_ext_prop(struct usb_configuration *c, int interface)
+{
+ struct usb_function *f;
+ int j;
+
+ f = c->interface[interface];
+ for (j = 0; j < f->os_desc_n; ++j) {
+ struct usb_os_desc *d;
+
+ if (interface != f->os_desc_table[j].if_id)
+ continue;
+ d = f->os_desc_table[j].os_desc;
+ if (d && d->ext_compat_id)
+ return d->ext_prop_count;
+ }
+ return 0;
+}
+
+static int len_ext_prop(struct usb_configuration *c, int interface)
+{
+ struct usb_function *f;
+ struct usb_os_desc *d;
+ int j, res;
+
+ res = 10; /* header length */
+ f = c->interface[interface];
+ for (j = 0; j < f->os_desc_n; ++j) {
+ if (interface != f->os_desc_table[j].if_id)
+ continue;
+ d = f->os_desc_table[j].os_desc;
+ if (d)
+ return min(res + d->ext_prop_len, 4096);
+ }
+ return res;
+}
+
+static int fill_ext_prop(struct usb_configuration *c, int interface, u8 *buf)
+{
+ struct usb_function *f;
+ struct usb_os_desc *d;
+ struct usb_os_desc_ext_prop *ext_prop;
+ int j, count, n, ret;
+ u8 *start = buf;
+
+ f = c->interface[interface];
+ for (j = 0; j < f->os_desc_n; ++j) {
+ if (interface != f->os_desc_table[j].if_id)
+ continue;
+ d = f->os_desc_table[j].os_desc;
+ if (d)
+ list_for_each_entry(ext_prop, &d->ext_prop, entry) {
+ /* 4kB minus header length */
+ n = buf - start;
+ if (n >= 4086)
+ return 0;
+
+ count = ext_prop->data_len +
+ ext_prop->name_len + 14;
+ if (count > 4086 - n)
+ return -EINVAL;
+ usb_ext_prop_put_size(buf, count);
+ usb_ext_prop_put_type(buf, ext_prop->type);
+ ret = usb_ext_prop_put_name(buf, ext_prop->name,
+ ext_prop->name_len);
+ if (ret < 0)
+ return ret;
+ switch (ext_prop->type) {
+ case USB_EXT_PROP_UNICODE:
+ case USB_EXT_PROP_UNICODE_ENV:
+ case USB_EXT_PROP_UNICODE_LINK:
+ usb_ext_prop_put_unicode(buf, ret,
+ ext_prop->data,
+ ext_prop->data_len);
+ break;
+ case USB_EXT_PROP_BINARY:
+ usb_ext_prop_put_binary(buf, ret,
+ ext_prop->data,
+ ext_prop->data_len);
+ break;
+ case USB_EXT_PROP_LE32:
+ /* not implemented */
+ case USB_EXT_PROP_BE32:
+ /* not implemented */
+ default:
+ return -EINVAL;
+ }
+ buf += count;
+ }
+ }
+
+ return 0;
+}
+
/*
* The setup() callback implements all the ep0 functionality that's
* not handled lower down, in hardware or the hardware driver(like
@@ -801,32 +1045,28 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
cdev->desc.bNumConfigurations =
count_configs(cdev, USB_DT_DEVICE);
- /*
- * If the speed is Super speed, then the supported
- * max packet size is 512 and it should be sent as
- * exponent of 2. So, 9(2^9=512) should be filled in
- * bMaxPacketSize0. Also fill USB version as 3.0
- * if speed is Super speed.
- */
- if (cdev->gadget->speed == USB_SPEED_SUPER) {
+ cdev->desc.bMaxPacketSize0 =
+ cdev->gadget->ep0->maxpacket;
+ if (gadget->speed >= USB_SPEED_SUPER) {
+ cdev->desc.bcdUSB = cpu_to_le16(0x0310);
cdev->desc.bMaxPacketSize0 = 9;
- cdev->desc.bcdUSB = cpu_to_le16(0x0300);
} else {
- cdev->desc.bMaxPacketSize0 =
- cdev->gadget->ep0->maxpacket;
+ cdev->desc.bcdUSB = cpu_to_le16(0x0200);
}
value = min(w_length, (u16) sizeof cdev->desc);
memcpy(req->buf, &cdev->desc, value);
break;
case USB_DT_DEVICE_QUALIFIER:
- if (!gadget_is_dualspeed(gadget))
+ if (!gadget_is_dualspeed(gadget) ||
+ gadget->speed >= USB_SPEED_SUPER)
break;
device_qual(cdev);
value = min_t(int, w_length,
sizeof(struct usb_qualifier_descriptor));
break;
case USB_DT_OTHER_SPEED_CONFIG:
- if (!gadget_is_dualspeed(gadget))
+ if (!gadget_is_dualspeed(gadget) ||
+ gadget->speed >= USB_SPEED_SUPER)
break;
case USB_DT_CONFIG:
@@ -841,10 +1081,16 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
value = min(w_length, (u16) value);
break;
case USB_DT_BOS:
- if (gadget_is_superspeed(cdev->gadget))
+ /*
+ * Super speed connection should support BOS, and
+ * USB compliance test (USB 2.0 Command Verifier)
+ * also issues this request, return for now for
+ * USB 2.0 connection.
+ */
+ if (gadget->speed >= USB_SPEED_SUPER) {
value = bos_desc(cdev);
- if (value >= 0)
value = min(w_length, (u16)value);
+ }
break;
default:
goto unknown;
@@ -909,6 +1155,91 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
break;
default:
unknown:
+ /*
+ * OS descriptors handling
+ */
+ if (CONFIG_IS_ENABLED(USB_GADGET_OS_DESCRIPTORS) && cdev->use_os_string &&
+ cdev->os_desc_config && (ctrl->bRequestType & USB_TYPE_VENDOR) &&
+ ctrl->bRequest == cdev->b_vendor_code) {
+ struct usb_configuration *os_desc_cfg;
+ u8 *buf;
+ int interface;
+ int count = 0;
+
+ buf = req->buf;
+ os_desc_cfg = cdev->os_desc_config;
+ memset(buf, 0, w_length);
+ buf[5] = 0x01;
+ switch (ctrl->bRequestType & USB_RECIP_MASK) {
+ case USB_RECIP_DEVICE:
+ if (w_index != 0x4 || (w_value >> 8))
+ break;
+ buf[6] = w_index;
+ if (w_length == 0x10) {
+ /* Number of ext compat interfaces */
+ count = count_ext_compat(os_desc_cfg);
+ buf[8] = count;
+ count *= 24; /* 24 B/ext compat desc */
+ count += 16; /* header */
+ put_unaligned_le32(count, buf);
+ value = w_length;
+ } else {
+ /* "extended compatibility ID"s */
+ count = count_ext_compat(os_desc_cfg);
+ buf[8] = count;
+ count *= 24; /* 24 B/ext compat desc */
+ count += 16; /* header */
+ put_unaligned_le32(count, buf);
+ buf += 16;
+ fill_ext_compat(os_desc_cfg, buf);
+ value = w_length;
+ }
+ break;
+ case USB_RECIP_INTERFACE:
+ if (w_index != 0x5 || (w_value >> 8))
+ break;
+ interface = w_value & 0xFF;
+ buf[6] = w_index;
+ if (w_length == 0x0A) {
+ count = count_ext_prop(os_desc_cfg,
+ interface);
+ put_unaligned_le16(count, buf + 8);
+ count = len_ext_prop(os_desc_cfg,
+ interface);
+ put_unaligned_le32(count, buf);
+
+ value = w_length;
+ } else {
+ count = count_ext_prop(os_desc_cfg,
+ interface);
+ put_unaligned_le16(count, buf + 8);
+ count = len_ext_prop(os_desc_cfg,
+ interface);
+ put_unaligned_le32(count, buf);
+ buf += 10;
+ value = fill_ext_prop(os_desc_cfg,
+ interface, buf);
+ if (value < 0)
+ return value;
+
+ value = w_length;
+ }
+ break;
+ }
+
+ if (value >= 0) {
+ req->length = value;
+ req->zero = value < w_length;
+ value = usb_ep_queue(gadget->ep0, req, GFP_KERNEL);
+ if (value < 0) {
+ debug("ep_queue --> %d\n", value);
+ req->status = 0;
+ composite_setup_complete(gadget->ep0, req);
+ }
+ }
+ return value;
+ }
+
debug("non-core control req%02x.%02x v%04x i%04x l%d\n",
ctrl->bRequestType, ctrl->bRequest,
w_value, w_index, w_length);
@@ -1082,6 +1413,15 @@ static int composite_bind(struct usb_gadget *gadget)
sizeof(struct usb_device_descriptor));
cdev->desc.bMaxPacketSize0 = gadget->ep0->maxpacket;
+ if (cdev->use_os_string) {
+ /* TODO: Do we want to pass this via platform? */
+ cdev->b_vendor_code = 0x40;
+
+ /* Microsoft OS String Descriptor */
+ utf8_to_utf16le(qw_sign_buf, (__le16 *)cdev->qw_sign,
+ OS_STRING_QW_SIGN_LEN / 2);
+ }
+
debug("%s: ready\n", composite->name);
return 0;
@@ -1129,7 +1469,7 @@ composite_resume(struct usb_gadget *gadget)
}
static struct usb_gadget_driver composite_driver = {
- .speed = USB_SPEED_HIGH,
+ .speed = USB_SPEED_SUPER,
.bind = composite_bind,
.unbind = composite_unbind,
diff --git a/drivers/usb/gadget/core.c b/drivers/usb/gadget/core.c
index 3781d25fd6..888f0cfea6 100644
--- a/drivers/usb/gadget/core.c
+++ b/drivers/usb/gadget/core.c
@@ -36,7 +36,7 @@ extern struct usb_function_driver ep0_driver;
int registered_functions;
int registered_devices;
-char *usbd_device_events[] = {
+__maybe_unused static char *usbd_device_events[] = {
"DEVICE_UNKNOWN",
"DEVICE_INIT",
"DEVICE_CREATE",
@@ -56,52 +56,15 @@ char *usbd_device_events[] = {
"DEVICE_FUNCTION_PRIVATE",
};
-char *usbd_device_states[] = {
- "STATE_INIT",
- "STATE_CREATED",
- "STATE_ATTACHED",
- "STATE_POWERED",
- "STATE_DEFAULT",
- "STATE_ADDRESSED",
- "STATE_CONFIGURED",
- "STATE_UNKNOWN",
-};
-
-char *usbd_device_requests[] = {
- "GET STATUS", /* 0 */
- "CLEAR FEATURE", /* 1 */
- "RESERVED", /* 2 */
- "SET FEATURE", /* 3 */
- "RESERVED", /* 4 */
- "SET ADDRESS", /* 5 */
- "GET DESCRIPTOR", /* 6 */
- "SET DESCRIPTOR", /* 7 */
- "GET CONFIGURATION", /* 8 */
- "SET CONFIGURATION", /* 9 */
- "GET INTERFACE", /* 10 */
- "SET INTERFACE", /* 11 */
- "SYNC FRAME", /* 12 */
-};
-
-char *usbd_device_descriptors[] = {
- "UNKNOWN", /* 0 */
- "DEVICE", /* 1 */
- "CONFIG", /* 2 */
- "STRING", /* 3 */
- "INTERFACE", /* 4 */
- "ENDPOINT", /* 5 */
- "DEVICE QUALIFIER", /* 6 */
- "OTHER SPEED", /* 7 */
- "INTERFACE POWER", /* 8 */
-};
-
-char *usbd_device_status[] = {
+__maybe_unused static char *usbd_device_status[] = {
"USBD_OPENING",
"USBD_OK",
"USBD_SUSPENDED",
"USBD_CLOSING",
};
+#define USBD_DEVICE_STATUS(x) (((unsigned int)x <= USBD_CLOSING) ? usbd_device_status[x] : "UNKNOWN")
+
/* Descriptor support functions ************************************************************** */
diff --git a/drivers/usb/gadget/ep0.c b/drivers/usb/gadget/ep0.c
index 6fabee24ce..457679f0a4 100644
--- a/drivers/usb/gadget/ep0.c
+++ b/drivers/usb/gadget/ep0.c
@@ -46,6 +46,52 @@
#define dbg_ep0(lvl,fmt,args...)
#endif
+__maybe_unused static char *usbd_device_descriptors[] = {
+ "UNKNOWN", /* 0 */
+ "DEVICE", /* 1 */
+ "CONFIG", /* 2 */
+ "STRING", /* 3 */
+ "INTERFACE", /* 4 */
+ "ENDPOINT", /* 5 */
+ "DEVICE QUALIFIER", /* 6 */
+ "OTHER SPEED", /* 7 */
+ "INTERFACE POWER", /* 8 */
+};
+
+#define USBD_DEVICE_DESCRIPTORS(x) (((unsigned int)x <= USB_DESCRIPTOR_TYPE_INTERFACE_POWER) ? \
+ usbd_device_descriptors[x] : "UNKNOWN")
+
+__maybe_unused static char *usbd_device_states[] = {
+ "STATE_INIT",
+ "STATE_CREATED",
+ "STATE_ATTACHED",
+ "STATE_POWERED",
+ "STATE_DEFAULT",
+ "STATE_ADDRESSED",
+ "STATE_CONFIGURED",
+ "STATE_UNKNOWN",
+};
+
+#define USBD_DEVICE_STATE(x) (((unsigned int)x <= STATE_UNKNOWN) ? usbd_device_states[x] : "UNKNOWN")
+
+__maybe_unused static char *usbd_device_requests[] = {
+ "GET STATUS", /* 0 */
+ "CLEAR FEATURE", /* 1 */
+ "RESERVED", /* 2 */
+ "SET FEATURE", /* 3 */
+ "RESERVED", /* 4 */
+ "SET ADDRESS", /* 5 */
+ "GET DESCRIPTOR", /* 6 */
+ "SET DESCRIPTOR", /* 7 */
+ "GET CONFIGURATION", /* 8 */
+ "SET CONFIGURATION", /* 9 */
+ "GET INTERFACE", /* 10 */
+ "SET INTERFACE", /* 11 */
+ "SYNC FRAME", /* 12 */
+};
+
+#define USBD_DEVICE_REQUESTS(x) (((unsigned int)x <= USB_REQ_SYNCH_FRAME) ? usbd_device_requests[x] : "UNKNOWN")
+
/* EP0 Configuration Set ********************************************************************* */
diff --git a/drivers/usb/gadget/epautoconf.c b/drivers/usb/gadget/epautoconf.c
index e61fe5d114..7da334f5d3 100644
--- a/drivers/usb/gadget/epautoconf.c
+++ b/drivers/usb/gadget/epautoconf.c
@@ -167,6 +167,10 @@ static int ep_matches(
size = 64;
put_unaligned(cpu_to_le16(size), &desc->wMaxPacketSize);
}
+
+ if (gadget->ops->ep_conf)
+ return gadget->ops->ep_conf(gadget, ep, desc);
+
return 1;
}
@@ -258,6 +262,7 @@ struct usb_ep *usb_ep_autoconfig(
ep = find_ep(gadget, "ep1-bulk");
if (ep && ep_matches(gadget, ep, desc))
return ep;
+#ifndef CONFIG_SPL_BUILD
} else if (gadget_is_dwc3(gadget)) {
const char *name = NULL;
/*
@@ -280,6 +285,7 @@ struct usb_ep *usb_ep_autoconfig(
ep = find_ep(gadget, name);
if (ep && ep_matches(gadget, ep, desc))
return ep;
+#endif
}
if (gadget->ops->match_ep)
diff --git a/drivers/usb/gadget/f_fastboot.c b/drivers/usb/gadget/f_fastboot.c
index d1d087e12b..950cc11949 100644
--- a/drivers/usb/gadget/f_fastboot.c
+++ b/drivers/usb/gadget/f_fastboot.c
@@ -46,6 +46,25 @@ struct f_fastboot {
struct usb_request *in_req, *out_req;
};
+static char fb_ext_prop_name[] = "DeviceInterfaceGUID";
+static char fb_ext_prop_data[] = "{4866319A-F4D6-4374-93B9-DC2DEB361BA9}";
+
+static struct usb_os_desc_ext_prop fb_ext_prop = {
+ .type = 1, /* NUL-terminated Unicode String (REG_SZ) */
+ .name = fb_ext_prop_name,
+ .data = fb_ext_prop_data,
+};
+
+/* 16 bytes of "Compatible ID" and "Subcompatible ID" */
+static char fb_cid[16] = {'W', 'I', 'N', 'U', 'S', 'B'};
+static struct usb_os_desc fb_os_desc = {
+ .ext_compat_id = fb_cid,
+};
+
+static struct usb_os_desc_table fb_os_desc_table = {
+ .os_desc = &fb_os_desc,
+};
+
static inline struct f_fastboot *func_to_fastboot(struct usb_function *f)
{
return container_of(f, struct f_fastboot, usb_function);
@@ -109,10 +128,45 @@ static struct usb_descriptor_header *fb_hs_function[] = {
NULL,
};
+/* Super speed */
+static struct usb_endpoint_descriptor ss_ep_in = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = USB_DIR_IN,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = cpu_to_le16(1024),
+};
+
+static struct usb_endpoint_descriptor ss_ep_out = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = USB_DIR_OUT,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = cpu_to_le16(1024),
+};
+
+static struct usb_ss_ep_comp_descriptor fb_ss_bulk_comp_desc = {
+ .bLength = sizeof(fb_ss_bulk_comp_desc),
+ .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
+};
+
+static struct usb_descriptor_header *fb_ss_function[] = {
+ (struct usb_descriptor_header *)&interface_desc,
+ (struct usb_descriptor_header *)&ss_ep_in,
+ (struct usb_descriptor_header *)&fb_ss_bulk_comp_desc,
+ (struct usb_descriptor_header *)&ss_ep_out,
+ (struct usb_descriptor_header *)&fb_ss_bulk_comp_desc,
+ NULL,
+};
+
static struct usb_endpoint_descriptor *
fb_ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor *fs,
- struct usb_endpoint_descriptor *hs)
+ struct usb_endpoint_descriptor *hs,
+ struct usb_endpoint_descriptor *ss)
{
+ if (gadget_is_superspeed(g) && g->speed >= USB_SPEED_SUPER)
+ return ss;
+
if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH)
return hs;
return fs;
@@ -161,6 +215,19 @@ static int fastboot_bind(struct usb_configuration *c, struct usb_function *f)
return id;
interface_desc.bInterfaceNumber = id;
+ /* Enable OS and Extended Properties Feature Descriptor */
+ c->cdev->use_os_string = 1;
+ f->os_desc_table = &fb_os_desc_table;
+ f->os_desc_n = 1;
+ f->os_desc_table->if_id = id;
+ INIT_LIST_HEAD(&fb_os_desc.ext_prop);
+ fb_ext_prop.name_len = strlen(fb_ext_prop.name) * 2 + 2;
+ fb_os_desc.ext_prop_len = 10 + fb_ext_prop.name_len;
+ fb_os_desc.ext_prop_count = 1;
+ fb_ext_prop.data_len = strlen(fb_ext_prop.data) * 2 + 2;
+ fb_os_desc.ext_prop_len += fb_ext_prop.data_len + 4;
+ list_add_tail(&fb_ext_prop.entry, &fb_os_desc.ext_prop);
+
id = usb_string_id(c->cdev);
if (id < 0)
return id;
@@ -187,6 +254,12 @@ static int fastboot_bind(struct usb_configuration *c, struct usb_function *f)
f->hs_descriptors = fb_hs_function;
}
+ if (gadget_is_superspeed(gadget)) {
+ ss_ep_in.bEndpointAddress = fs_ep_in.bEndpointAddress;
+ ss_ep_out.bEndpointAddress = fs_ep_out.bEndpointAddress;
+ f->ss_descriptors = fb_ss_function;
+ }
+
s = env_get("serial#");
if (s)
g_dnl_set_serialnumber((char *)s);
@@ -196,6 +269,8 @@ static int fastboot_bind(struct usb_configuration *c, struct usb_function *f)
static void fastboot_unbind(struct usb_configuration *c, struct usb_function *f)
{
+ f->os_desc_table = NULL;
+ list_del(&fb_os_desc.ext_prop);
memset(fastboot_func, 0, sizeof(*fastboot_func));
}
@@ -249,7 +324,7 @@ static int fastboot_set_alt(struct usb_function *f,
debug("%s: func: %s intf: %d alt: %d\n",
__func__, f->name, interface, alt);
- d = fb_ep_desc(gadget, &fs_ep_out, &hs_ep_out);
+ d = fb_ep_desc(gadget, &fs_ep_out, &hs_ep_out, &ss_ep_out);
ret = usb_ep_enable(f_fb->out_ep, d);
if (ret) {
puts("failed to enable out ep\n");
@@ -264,7 +339,7 @@ static int fastboot_set_alt(struct usb_function *f,
}
f_fb->out_req->complete = rx_handler_command;
- d = fb_ep_desc(gadget, &fs_ep_in, &hs_ep_in);
+ d = fb_ep_desc(gadget, &fs_ep_in, &hs_ep_in, &ss_ep_in);
ret = usb_ep_enable(f_fb->in_ep, d);
if (ret) {
puts("failed to enable in ep\n");
@@ -315,7 +390,7 @@ static int fastboot_add(struct usb_configuration *c)
status = usb_add_function(c, &f_fb->usb_function);
if (status) {
free(f_fb);
- fastboot_func = f_fb;
+ fastboot_func = NULL;
}
return status;
@@ -352,7 +427,7 @@ static unsigned int rx_bytes_expected(struct usb_ep *ep)
{
int rx_remain = fastboot_data_remaining();
unsigned int rem;
- unsigned int maxpacket = ep->maxpacket;
+ unsigned int maxpacket = usb_endpoint_maxp(ep->desc);
if (rx_remain <= 0)
return 0;
diff --git a/drivers/usb/gadget/f_rockusb.c b/drivers/usb/gadget/f_rockusb.c
index 9ae02ae78c..bd846ce9a7 100644
--- a/drivers/usb/gadget/f_rockusb.c
+++ b/drivers/usb/gadget/f_rockusb.c
@@ -110,7 +110,7 @@ struct f_rockusb *get_rkusb(void)
if (!f_rkusb) {
f_rkusb = memalign(CONFIG_SYS_CACHELINE_SIZE, sizeof(*f_rkusb));
if (!f_rkusb)
- return 0;
+ return NULL;
rockusb_func = f_rkusb;
memset(f_rkusb, 0, sizeof(*f_rkusb));
@@ -120,7 +120,7 @@ struct f_rockusb *get_rkusb(void)
f_rkusb->buf_head = memalign(CONFIG_SYS_CACHELINE_SIZE,
RKUSB_BUF_SIZE);
if (!f_rkusb->buf_head)
- return 0;
+ return NULL;
f_rkusb->buf = f_rkusb->buf_head;
memset(f_rkusb->buf_head, 0, RKUSB_BUF_SIZE);
@@ -309,8 +309,9 @@ static int rockusb_add(struct usb_configuration *c)
status = usb_add_function(c, &f_rkusb->usb_function);
if (status) {
+ free(f_rkusb->buf_head);
free(f_rkusb);
- rockusb_func = f_rkusb;
+ rockusb_func = NULL;
}
return status;
}
diff --git a/drivers/usb/gadget/f_thor.c b/drivers/usb/gadget/f_thor.c
index 88fc87f2e9..47ef55b2fd 100644
--- a/drivers/usb/gadget/f_thor.c
+++ b/drivers/usb/gadget/f_thor.c
@@ -30,6 +30,7 @@
#include <linux/usb/cdc.h>
#include <g_dnl.h>
#include <dfu.h>
+#include <thor.h>
#include "f_thor.h"
@@ -266,8 +267,8 @@ static long long int process_rqt_download(const struct rqt_box *rqt)
switch (rqt->rqt_data) {
case RQT_DL_INIT:
- thor_file_size = (unsigned long long int)rqt->int_data[0] +
- (((unsigned long long int)rqt->int_data[1])
+ thor_file_size = (uint64_t)(uint32_t)rqt->int_data[0] +
+ (((uint64_t)(uint32_t)rqt->int_data[1])
<< 32);
debug("INIT: total %llu bytes\n", thor_file_size);
break;
@@ -280,8 +281,8 @@ static long long int process_rqt_download(const struct rqt_box *rqt)
break;
}
- thor_file_size = (unsigned long long int)rqt->int_data[1] +
- (((unsigned long long int)rqt->int_data[2])
+ thor_file_size = (uint64_t)(uint32_t)rqt->int_data[1] +
+ (((uint64_t)(uint32_t)rqt->int_data[2])
<< 32);
memcpy(f_name, rqt->str_data[0], F_NAME_BUF_SIZE);
f_name[F_NAME_BUF_SIZE] = '\0';
@@ -735,6 +736,8 @@ int thor_handle(void)
printf("%s: No data received!\n", __func__);
break;
}
+ if (dfu_reinit_needed)
+ return THOR_DFU_REINIT_NEEDED;
}
return 0;
diff --git a/drivers/usb/gadget/g_dnl.c b/drivers/usb/gadget/g_dnl.c
index 86fdd16b01..afb7b74f30 100644
--- a/drivers/usb/gadget/g_dnl.c
+++ b/drivers/usb/gadget/g_dnl.c
@@ -286,6 +286,7 @@ static struct usb_composite_driver g_dnl_driver = {
.name = NULL,
.dev = &device_desc,
.strings = g_dnl_composite_strings,
+ .max_speed = USB_SPEED_SUPER,
.bind = g_dnl_bind,
.unbind = g_dnl_unbind,
diff --git a/drivers/usb/gadget/u_os_desc.h b/drivers/usb/gadget/u_os_desc.h
new file mode 100644
index 0000000000..4dab4814a3
--- /dev/null
+++ b/drivers/usb/gadget/u_os_desc.h
@@ -0,0 +1,123 @@
+/*
+ * u_os_desc.h
+ *
+ * Utility definitions for "OS Descriptors" support
+ *
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __U_OS_DESC_H__
+#define __U_OS_DESC_H__
+
+#include <linux/utf.h>
+
+#define USB_EXT_PROP_DW_SIZE 0
+#define USB_EXT_PROP_DW_PROPERTY_DATA_TYPE 4
+#define USB_EXT_PROP_W_PROPERTY_NAME_LENGTH 8
+#define USB_EXT_PROP_B_PROPERTY_NAME 10
+#define USB_EXT_PROP_DW_PROPERTY_DATA_LENGTH 10
+#define USB_EXT_PROP_B_PROPERTY_DATA 14
+
+#define USB_EXT_PROP_RESERVED 0
+#define USB_EXT_PROP_UNICODE 1
+#define USB_EXT_PROP_UNICODE_ENV 2
+#define USB_EXT_PROP_BINARY 3
+#define USB_EXT_PROP_LE32 4
+#define USB_EXT_PROP_BE32 5
+#define USB_EXT_PROP_UNICODE_LINK 6
+#define USB_EXT_PROP_UNICODE_MULTI 7
+
+static inline u8 *__usb_ext_prop_ptr(u8 *buf, size_t offset)
+{
+ return buf + offset;
+}
+
+static inline u8 *usb_ext_prop_size_ptr(u8 *buf)
+{
+ return __usb_ext_prop_ptr(buf, USB_EXT_PROP_DW_SIZE);
+}
+
+static inline u8 *usb_ext_prop_type_ptr(u8 *buf)
+{
+ return __usb_ext_prop_ptr(buf, USB_EXT_PROP_DW_PROPERTY_DATA_TYPE);
+}
+
+static inline u8 *usb_ext_prop_name_len_ptr(u8 *buf)
+{
+ return __usb_ext_prop_ptr(buf, USB_EXT_PROP_W_PROPERTY_NAME_LENGTH);
+}
+
+static inline u8 *usb_ext_prop_name_ptr(u8 *buf)
+{
+ return __usb_ext_prop_ptr(buf, USB_EXT_PROP_B_PROPERTY_NAME);
+}
+
+static inline u8 *usb_ext_prop_data_len_ptr(u8 *buf, size_t off)
+{
+ return __usb_ext_prop_ptr(buf,
+ USB_EXT_PROP_DW_PROPERTY_DATA_LENGTH + off);
+}
+
+static inline u8 *usb_ext_prop_data_ptr(u8 *buf, size_t off)
+{
+ return __usb_ext_prop_ptr(buf, USB_EXT_PROP_B_PROPERTY_DATA + off);
+}
+
+static inline void usb_ext_prop_put_size(u8 *buf, int dw_size)
+{
+ put_unaligned_le32(dw_size, usb_ext_prop_size_ptr(buf));
+}
+
+static inline void usb_ext_prop_put_type(u8 *buf, int type)
+{
+ put_unaligned_le32(type, usb_ext_prop_type_ptr(buf));
+}
+
+static inline int usb_ext_prop_put_name(u8 *buf, const char *name, int pnl)
+{
+ int result;
+
+ put_unaligned_le16(pnl, usb_ext_prop_name_len_ptr(buf));
+ memset(usb_ext_prop_name_ptr(buf), 0, 2 * strlen(name));
+ result = utf8_to_utf16le(name, (__le16 *)usb_ext_prop_name_ptr(buf),
+ strlen(name));
+ if (result < 0)
+ return result;
+
+ put_unaligned_le16(0, &buf[USB_EXT_PROP_B_PROPERTY_NAME + pnl - 2]);
+
+ return pnl;
+}
+
+static inline void usb_ext_prop_put_binary(u8 *buf, int pnl, const char *data,
+ int data_len)
+{
+ put_unaligned_le32(data_len, usb_ext_prop_data_len_ptr(buf, pnl));
+ memcpy(usb_ext_prop_data_ptr(buf, pnl), data, data_len);
+}
+
+static inline int usb_ext_prop_put_unicode(u8 *buf, int pnl, const char *string,
+ int data_len)
+{
+ int result;
+ put_unaligned_le32(data_len, usb_ext_prop_data_len_ptr(buf, pnl));
+ memset(usb_ext_prop_data_ptr(buf, pnl), 0, 2 * (data_len >> 1));
+ result = utf8_to_utf16le(string, (__le16 *) usb_ext_prop_data_ptr(buf, pnl),
+ data_len >> 1);
+ if (result < 0)
+ return result;
+
+ put_unaligned_le16(0,
+ &buf[USB_EXT_PROP_B_PROPERTY_DATA + pnl + data_len - 2]);
+
+ return data_len;
+}
+
+#endif /* __U_OS_DESC_H__ */
diff --git a/drivers/usb/gadget/usbstring.c b/drivers/usb/gadget/usbstring.c
index 83cdd8a259..e2464ad923 100644
--- a/drivers/usb/gadget/usbstring.c
+++ b/drivers/usb/gadget/usbstring.c
@@ -10,79 +10,7 @@
#include <linux/errno.h>
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
-
-#include <asm/unaligned.h>
-
-
-static int utf8_to_utf16le(const char *s, __le16 *cp, unsigned len)
-{
- int count = 0;
- u8 c;
- u16 uchar;
-
- /*
- * this insists on correct encodings, though not minimal ones.
- * BUT it currently rejects legit 4-byte UTF-8 code points,
- * which need surrogate pairs. (Unicode 3.1 can use them.)
- */
- while (len != 0 && (c = (u8) *s++) != 0) {
- if ((c & 0x80)) {
- /*
- * 2-byte sequence:
- * 00000yyyyyxxxxxx = 110yyyyy 10xxxxxx
- */
- if ((c & 0xe0) == 0xc0) {
- uchar = (c & 0x1f) << 6;
-
- c = (u8) *s++;
- if ((c & 0xc0) != 0x80)
- goto fail;
- c &= 0x3f;
- uchar |= c;
-
- /*
- * 3-byte sequence (most CJKV characters):
- * zzzzyyyyyyxxxxxx = 1110zzzz 10yyyyyy 10xxxxxx
- */
- } else if ((c & 0xf0) == 0xe0) {
- uchar = (c & 0x0f) << 12;
-
- c = (u8) *s++;
- if ((c & 0xc0) != 0x80)
- goto fail;
- c &= 0x3f;
- uchar |= c << 6;
-
- c = (u8) *s++;
- if ((c & 0xc0) != 0x80)
- goto fail;
- c &= 0x3f;
- uchar |= c;
-
- /* no bogus surrogates */
- if (0xd800 <= uchar && uchar <= 0xdfff)
- goto fail;
-
- /*
- * 4-byte sequence (surrogate pairs, currently rare):
- * 11101110wwwwzzzzyy + 110111yyyyxxxxxx
- * = 11110uuu 10uuzzzz 10yyyyyy 10xxxxxx
- * (uuuuu = wwww + 1)
- * FIXME accept the surrogate code points (only)
- */
- } else
- goto fail;
- } else
- uchar = c;
- put_unaligned_le16(uchar, cp++);
- count++;
- len--;
- }
- return count;
-fail:
- return -1;
-}
-
+#include <linux/utf.h>
/**
* usb_gadget_get_string - fill out a string descriptor