- 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
commit b4804cdd57
28 changed files with 1006 additions and 212 deletions

View File

@ -6,10 +6,12 @@
*/
#include <android_bootloader_message.h>
#include <bcb.h>
#include <command.h>
#include <common.h>
#include <log.h>
#include <part.h>
#include <malloc.h>
enum bcb_cmd {
BCB_CMD_LOAD,
@ -110,8 +112,7 @@ static int bcb_field_get(char *name, char **fieldp, int *sizep)
return 0;
}
static int do_bcb_load(struct cmd_tbl *cmdtp, int flag, int argc,
char *const argv[])
static int __bcb_load(int devnum, const char *partp)
{
struct blk_desc *desc;
struct disk_partition info;
@ -119,17 +120,19 @@ static int do_bcb_load(struct cmd_tbl *cmdtp, int flag, int argc,
char *endp;
int part, ret;
ret = blk_get_device_by_str("mmc", argv[1], &desc);
if (ret < 0)
desc = blk_get_devnum_by_type(IF_TYPE_MMC, devnum);
if (!desc) {
ret = -ENODEV;
goto err_read_fail;
}
part = simple_strtoul(argv[2], &endp, 0);
part = simple_strtoul(partp, &endp, 0);
if (*endp == '\0') {
ret = part_get_info(desc, part, &info);
if (ret)
goto err_read_fail;
} else {
part = part_get_info_by_name(desc, argv[2], &info);
part = part_get_info_by_name(desc, partp, &info);
if (part < 0) {
ret = part;
goto err_read_fail;
@ -151,10 +154,10 @@ static int do_bcb_load(struct cmd_tbl *cmdtp, int flag, int argc,
return CMD_RET_SUCCESS;
err_read_fail:
printf("Error: mmc %s:%s read failed (%d)\n", argv[1], argv[2], ret);
printf("Error: mmc %d:%s read failed (%d)\n", devnum, partp, ret);
goto err;
err_too_small:
printf("Error: mmc %s:%s too small!", argv[1], argv[2]);
printf("Error: mmc %d:%s too small!", devnum, partp);
goto err;
err:
bcb_dev = -1;
@ -163,33 +166,58 @@ err:
return CMD_RET_FAILURE;
}
static int do_bcb_set(struct cmd_tbl *cmdtp, int flag, int argc,
char *const argv[])
static int do_bcb_load(struct cmd_tbl *cmdtp, int flag, int argc,
char * const argv[])
{
int size, len;
char *field, *str, *found;
char *endp;
int devnum = simple_strtoul(argv[1], &endp, 0);
if (bcb_field_get(argv[1], &field, &size))
return CMD_RET_FAILURE;
len = strlen(argv[2]);
if (len >= size) {
printf("Error: sizeof('%s') = %d >= %d = sizeof(bcb.%s)\n",
argv[2], len, size, argv[1]);
if (*endp != '\0') {
printf("Error: Device id '%s' not a number\n", argv[1]);
return CMD_RET_FAILURE;
}
str = argv[2];
return __bcb_load(devnum, argv[2]);
}
static int __bcb_set(char *fieldp, const char *valp)
{
int size, len;
char *field, *str, *found, *tmp;
if (bcb_field_get(fieldp, &field, &size))
return CMD_RET_FAILURE;
len = strlen(valp);
if (len >= size) {
printf("Error: sizeof('%s') = %d >= %d = sizeof(bcb.%s)\n",
valp, len, size, fieldp);
return CMD_RET_FAILURE;
}
str = strdup(valp);
if (!str) {
printf("Error: Out of memory while strdup\n");
return CMD_RET_FAILURE;
}
tmp = str;
field[0] = '\0';
while ((found = strsep(&str, ":"))) {
while ((found = strsep(&tmp, ":"))) {
if (field[0] != '\0')
strcat(field, "\n");
strcat(field, found);
}
free(str);
return CMD_RET_SUCCESS;
}
static int do_bcb_set(struct cmd_tbl *cmdtp, int flag, int argc,
char * const argv[])
{
return __bcb_set(argv[1], argv[2]);
}
static int do_bcb_clear(struct cmd_tbl *cmdtp, int flag, int argc,
char *const argv[])
{
@ -250,8 +278,7 @@ static int do_bcb_dump(struct cmd_tbl *cmdtp, int flag, int argc,
return CMD_RET_SUCCESS;
}
static int do_bcb_store(struct cmd_tbl *cmdtp, int flag, int argc,
char *const argv[])
static int __bcb_store(void)
{
struct blk_desc *desc;
struct disk_partition info;
@ -282,6 +309,31 @@ err:
return CMD_RET_FAILURE;
}
static int do_bcb_store(struct cmd_tbl *cmdtp, int flag, int argc,
char * const argv[])
{
return __bcb_store();
}
int bcb_write_reboot_reason(int devnum, char *partp, const char *reasonp)
{
int ret;
ret = __bcb_load(devnum, partp);
if (ret != CMD_RET_SUCCESS)
return ret;
ret = __bcb_set("command", reasonp);
if (ret != CMD_RET_SUCCESS)
return ret;
ret = __bcb_store();
if (ret != CMD_RET_SUCCESS)
return ret;
return 0;
}
static struct cmd_tbl cmd_bcb_sub[] = {
U_BOOT_CMD_MKENT(load, CONFIG_SYS_MAXARGS, 1, do_bcb_load, "", ""),
U_BOOT_CMD_MKENT(set, CONFIG_SYS_MAXARGS, 1, do_bcb_set, "", ""),

View File

@ -34,7 +34,6 @@ static int do_dfu(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
#if defined(CONFIG_DFU_TIMEOUT) || defined(CONFIG_DFU_OVER_TFTP)
unsigned long value = 0;
#endif
if (argc >= 4) {
interface = argv[2];
devstring = argv[3];
@ -67,8 +66,18 @@ static int do_dfu(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
}
int controller_index = simple_strtoul(usb_controller, NULL, 0);
bool retry = false;
do {
run_usb_dnl_gadget(controller_index, "usb_dnl_dfu");
run_usb_dnl_gadget(controller_index, "usb_dnl_dfu");
if (dfu_reinit_needed) {
dfu_free_entities();
ret = dfu_init_env_entities(interface, devstring);
if (ret)
goto done;
retry = true;
}
} while (retry);
done:
dfu_free_entities();

View File

@ -52,13 +52,18 @@ int do_thor_down(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
goto exit;
}
ret = thor_handle();
if (ret) {
pr_err("THOR failed: %d\n", ret);
ret = CMD_RET_FAILURE;
goto exit;
}
do {
ret = thor_handle();
if (ret == THOR_DFU_REINIT_NEEDED) {
dfu_free_entities();
ret = dfu_init_env_entities(interface, devstring);
}
if (ret) {
pr_err("THOR failed: %d\n", ret);
ret = CMD_RET_FAILURE;
goto exit;
}
} while (ret == 0);
exit:
g_dnl_unregister();
usb_gadget_release(controller_index);

View File

@ -115,8 +115,8 @@ static int ums_init(const char *devtype, const char *devnums_part_str)
ums[ums_count].name = name;
ums[ums_count].block_dev = *block_dev;
printf("UMS: LUN %d, dev %d, hwpart %d, sector %#x, count %#x\n",
ums_count, ums[ums_count].block_dev.devnum,
printf("UMS: LUN %d, dev %s %d, hwpart %d, sector %#x, count %#x\n",
ums_count, devtype, ums[ums_count].block_dev.devnum,
ums[ums_count].block_dev.hwpart,
ums[ums_count].start_sector,
ums[ums_count].num_sectors);

View File

@ -98,6 +98,9 @@ int run_usb_dnl_gadget(int usbctrl_index, char *usb_dnl_gadget)
}
#endif
if (dfu_reinit_needed)
goto exit;
WATCHDOG_RESET();
usb_gadget_handle_interrupts(usbctrl_index);
}

View File

@ -17,7 +17,7 @@ Overview:
- The access to mediums is done in DFU backends (driver/dfu)
Today the supported DFU backends are:
- MMC (RAW or FAT / EXT2 / EXT3 / EXT4 file system)
- MMC (RAW or FAT / EXT2 / EXT3 / EXT4 file system / SKIP / SCRIPT)
- NAND
- RAM
- SF (serial flash)
@ -91,6 +91,8 @@ Commands:
<name> part <dev> <part_id> [mmcpart <num>] raw access to partition
<name> fat <dev> <part_id> [mmcpart <num>] file in FAT partition
<name> ext4 <dev> <part_id> [mmcpart <num>] file in EXT4 partition
<name> skip 0 0 ignore flashed data
<name> script 0 0 execute commands in shell
with <partid> being the GPT or DOS partition index,
with <num> being the eMMC hardware partition number.
@ -103,6 +105,32 @@ Commands:
"u-boot raw 0x80 0x800;uImage ext4 0 2"
If don't want to flash given image file to storage, use "skip" type
entity.
- It can be used to protect flashing wrong image for the specific board.
- Especailly, this layout will be useful when thor protocol is used,
which performs flashing in batch mode, where more than one file is
processed.
For example, if one makes a single tar file with support for the two
boards with u-boot-<board1>.bin and u-boot-<board2>.bin files, one
can use it to flash a proper u-boot image on both without a failure:
"u-boot-<board1>.bin raw 0x80 0x800; u-boot-<board2>.bin skip 0 0"
When flashing new system image requires do some more complex things
than just writing data to the storage medium, one can use 'script'
type. Data written to such entity will be executed as a command list
in the u-boot's shell. This for example allows to re-create partition
layout and even set new dfu_alt_info for the newly created paritions.
Such script would look like:
--->8---
setenv dfu_alt_info ...
setenv mbr_parts ...
mbr write ...
--->8---
Please note that this means that user will be able to execute any
arbitrary commands just like in the u-boot's shell.
"nand" (raw slc nand device)
cmd: dfu 0 nand <dev>
each element in "dfu_alt_info" =

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

21
include/bcb.h Normal file
View File

@ -0,0 +1,21 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2020 Eugeniu Rosca <rosca.eugeniu@gmail.com>
*
* Android Bootloader Control Block Header
*/
#ifndef __BCB_H__
#define __BCB_H__
#if CONFIG_IS_ENABLED(CMD_BCB)
int bcb_write_reboot_reason(int devnum, char *partp, const char *reasonp);
#else
#include <linux/errno.h>
static inline int bcb_write_reboot_reason(int devnum, char *partp, const char *reasonp)
{
return -EOPNOTSUPP;
}
#endif
#endif /* __BCB_H__ */

View File

@ -33,6 +33,8 @@ enum dfu_layout {
DFU_FS_EXT3,
DFU_FS_EXT4,
DFU_RAM_ADDR,
DFU_SKIP,
DFU_SCRIPT,
};
enum dfu_op {
@ -496,6 +498,8 @@ static inline int dfu_fill_entity_virt(struct dfu_entity *dfu, char *devstr,
}
#endif
extern bool dfu_reinit_needed;
#if CONFIG_IS_ENABLED(DFU_WRITE_ALT)
/**
* dfu_write_by_name() - write data to DFU medium

View File

@ -37,6 +37,53 @@
struct usb_configuration;
/**
* struct usb_os_desc_ext_prop - describes one "Extended Property"
* @entry: used to keep a list of extended properties
* @type: Extended Property type
* @name_len: Extended Property unicode name length, including terminating '\0'
* @name: Extended Property name
* @data_len: Length of Extended Property blob (for unicode store double len)
* @data: Extended Property blob
*/
struct usb_os_desc_ext_prop {
struct list_head entry;
u8 type;
int name_len;
char *name;
int data_len;
char *data;
};
/**
* struct usb_os_desc - describes OS descriptors associated with one interface
* @ext_compat_id: 16 bytes of "Compatible ID" and "Subcompatible ID"
* @ext_prop: Extended Properties list
* @ext_prop_len: Total length of Extended Properties blobs
* @ext_prop_count: Number of Extended Properties
*/
struct usb_os_desc {
char *ext_compat_id;
struct list_head ext_prop;
int ext_prop_len;
int ext_prop_count;
};
/**
* struct usb_os_desc_table - describes OS descriptors associated with one
* interface of a usb_function
* @if_id: Interface id
* @os_desc: "Extended Compatibility ID" and "Extended Properties" of the
* interface
*
* Each interface can have at most one "Extended Compatibility ID" and a
* number of "Extended Properties".
*/
struct usb_os_desc_table {
int if_id;
struct usb_os_desc *os_desc;
};
/**
* struct usb_function - describes one function of a configuration
* @name: For diagnostics, identifies the function.
@ -50,6 +97,10 @@ struct usb_configuration;
* the function will not be available at high speed.
* @config: assigned when @usb_add_function() is called; this is the
* configuration with which this function is associated.
* @os_desc_table: Table of (interface id, os descriptors) pairs. The function
* can expose more than one interface. If an interface is a member of
* an IAD, only the first interface of IAD has its entry in the table.
* @os_desc_n: Number of entries in os_desc_table
* @bind: Before the gadget can register, all of its functions bind() to the
* available resources including string and interface identifiers used
* in interface or class descriptors; endpoints; I/O buffers; and so on.
@ -95,9 +146,13 @@ struct usb_function {
struct usb_gadget_strings **strings;
struct usb_descriptor_header **descriptors;
struct usb_descriptor_header **hs_descriptors;
struct usb_descriptor_header **ss_descriptors;
struct usb_configuration *config;
struct usb_os_desc_table *os_desc_table;
unsigned os_desc_n;
/* REVISIT: bind() functions can be marked __init, which
* makes trouble for section mismatch analysis. See if
* we can't restructure things to avoid mismatching.
@ -225,6 +280,7 @@ struct usb_configuration {
u8 next_interface_id;
unsigned highspeed:1;
unsigned fullspeed:1;
unsigned superspeed:1;
struct usb_function *interface[MAX_CONFIG_INTERFACES];
};
@ -238,6 +294,7 @@ int usb_add_config(struct usb_composite_dev *,
* identifiers.
* @strings: tables of strings, keyed by identifiers assigned during bind()
* and language IDs provided in control requests
* @max_speed: Highest speed the driver supports.
* @bind: (REQUIRED) Used to allocate resources that are shared across the
* whole device, such as string IDs, and add its configurations using
* @usb_add_config(). This may fail by returning a negative errno
@ -265,6 +322,7 @@ struct usb_composite_driver {
const char *name;
const struct usb_device_descriptor *dev;
struct usb_gadget_strings **strings;
enum usb_device_speed max_speed;
/* REVISIT: bind() functions can be marked __init, which
* makes trouble for section mismatch analysis. See if
@ -284,13 +342,20 @@ struct usb_composite_driver {
extern int usb_composite_register(struct usb_composite_driver *);
extern void usb_composite_unregister(struct usb_composite_driver *);
#define OS_STRING_QW_SIGN_LEN 14
#define OS_STRING_IDX 0xEE
/**
* struct usb_composite_device - represents one composite usb gadget
* @gadget: read-only, abstracts the gadget's usb peripheral controller
* @req: used for control responses; buffer is pre-allocated
* @bufsiz: size of buffer pre-allocated in @req
* @os_desc_req: used for OS descriptors responses; buffer is pre-allocated
* @config: the currently active configuration
* @qw_sign: qwSignature part of the OS string
* @b_vendor_code: bMS_VendorCode part of the OS string
* @use_os_string: false by default, interested gadgets set it
* @os_desc_config: the configuration to be used with OS descriptors
*
* One of these devices is allocated and initialized before the
* associated device driver's bind() is called.
@ -324,6 +389,12 @@ struct usb_composite_dev {
struct usb_configuration *config;
/* OS String is a custom (yet popular) extension to the USB standard. */
u8 qw_sign[OS_STRING_QW_SIGN_LEN];
u8 b_vendor_code;
struct usb_configuration *os_desc_config;
unsigned int use_os_string:1;
/* private: */
/* internals */
unsigned int suspended:1;

View File

@ -449,6 +449,11 @@ static inline void usb_ep_fifo_flush(struct usb_ep *ep)
/*-------------------------------------------------------------------------*/
struct usb_dcd_config_params {
__u8 bU1devExitLat; /* U1 Device exit Latency */
__le16 bU2DevExitLat; /* U2 Device exit Latency */
};
struct usb_gadget;
struct usb_gadget_driver;
@ -464,12 +469,16 @@ struct usb_gadget_ops {
int (*pullup) (struct usb_gadget *, int is_on);
int (*ioctl)(struct usb_gadget *,
unsigned code, unsigned long param);
void (*get_config_params)(struct usb_dcd_config_params *);
int (*udc_start)(struct usb_gadget *,
struct usb_gadget_driver *);
int (*udc_stop)(struct usb_gadget *);
struct usb_ep *(*match_ep)(struct usb_gadget *,
struct usb_endpoint_descriptor *,
struct usb_ss_ep_comp_descriptor *);
int (*ep_conf)(struct usb_gadget *,
struct usb_ep *,
struct usb_endpoint_descriptor *);
void (*udc_set_speed)(struct usb_gadget *gadget,
enum usb_device_speed);
};

75
include/linux/utf.h Normal file
View File

@ -0,0 +1,75 @@
#ifndef _LINUX_UTF_H
#define _LINUX_UTF_H
#include <asm/unaligned.h>
static inline 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;
}
#endif /* _LINUX_UTF_H */

View File

@ -12,6 +12,8 @@
#include <linux/usb/composite.h>
#define THOR_DFU_REINIT_NEEDED 0xFFFFFFFE
int thor_handle(void);
int thor_init(void);
int thor_add(struct usb_configuration *c);

View File

@ -264,8 +264,6 @@ struct usb_bus_instance;
#define USB_REQ_SET_INTERFACE 0x0B
#define USB_REQ_SYNCH_FRAME 0x0C
#define USBD_DEVICE_REQUESTS(x) (((unsigned int)x <= USB_REQ_SYNCH_FRAME) ? usbd_device_requests[x] : "UNKNOWN")
/*
* HID requests
*/
@ -332,9 +330,6 @@ struct usb_bus_instance;
#define USB_DESCRIPTOR_TYPE_HID 0x21
#define USB_DESCRIPTOR_TYPE_REPORT 0x22
#define USBD_DEVICE_DESCRIPTORS(x) (((unsigned int)x <= USB_DESCRIPTOR_TYPE_INTERFACE_POWER) ? \
usbd_device_descriptors[x] : "UNKNOWN")
/*
* standard feature selectors
*/
@ -388,8 +383,6 @@ typedef enum usb_device_state {
STATE_UNKNOWN, /* destroyed */
} usb_device_state_t;
#define USBD_DEVICE_STATE(x) (((unsigned int)x <= STATE_UNKNOWN) ? usbd_device_states[x] : "UNKNOWN")
/*
* Device status
*
@ -402,8 +395,6 @@ typedef enum usb_device_status {
USBD_CLOSING, /* we are currently closing */
} usb_device_status_t;
#define USBD_DEVICE_STATUS(x) (((unsigned int)x <= USBD_CLOSING) ? usbd_device_status[x] : "UNKNOWN")
/*
* Device Events
*
@ -617,12 +608,6 @@ struct usb_bus_instance {
};
extern char *usbd_device_events[];
extern char *usbd_device_states[];
extern char *usbd_device_status[];
extern char *usbd_device_requests[];
extern char *usbd_device_descriptors[];
void urb_link_init (urb_link * ul);
void urb_detach (struct urb *urb);
urb_link *first_urb_link (urb_link * hd);