mirror of
https://github.com/AsahiLinux/u-boot
synced 2024-11-28 23:51:33 +00:00
- 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:
commit
b4804cdd57
28 changed files with 1006 additions and 212 deletions
98
cmd/bcb.c
98
cmd/bcb.c
|
@ -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, "", ""),
|
||||
|
|
13
cmd/dfu.c
13
cmd/dfu.c
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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" =
|
||||
|
|
|
@ -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];
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 ************************************************************** */
|
||||
|
||||
|
|
|
@ -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 ********************************************************************* */
|
||||
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
123
drivers/usb/gadget/u_os_desc.h
Normal file
123
drivers/usb/gadget/u_os_desc.h
Normal 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__ */
|
|
@ -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
21
include/bcb.h
Normal 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__ */
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
75
include/linux/utf.h
Normal 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 */
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue