- 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
This commit is contained in:
Tom Rini
2021-01-31 14:24:35 -05:00
28 changed files with 1006 additions and 212 deletions

View File

@@ -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];
}

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -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

View File

@@ -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);

View File

@@ -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,12 +20,32 @@
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)
{
var->val = cpu_to_le16(le16_to_cpu(var->val) + 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
@@ -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,

View File

@@ -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 ************************************************************** */

View File

@@ -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 ********************************************************************* */

View File

@@ -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)

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -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,

View File

@@ -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__ */

View File

@@ -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