Merge branch 'master' of git://www.denx.de/git/u-boot-usb
This commit is contained in:
commit
e6a3652899
|
@ -54,19 +54,26 @@ static int dfu_read_medium_ram(struct dfu_entity *dfu, u64 offset,
|
|||
|
||||
int dfu_fill_entity_ram(struct dfu_entity *dfu, char *devstr, char *s)
|
||||
{
|
||||
char *st;
|
||||
const char *argv[3];
|
||||
const char **parg = argv;
|
||||
|
||||
for (; parg < argv + sizeof(argv) / sizeof(*argv); ++parg) {
|
||||
*parg = strsep(&s, " ");
|
||||
if (*parg == NULL) {
|
||||
error("Invalid number of arguments.\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
}
|
||||
|
||||
dfu->dev_type = DFU_DEV_RAM;
|
||||
st = strsep(&s, " ");
|
||||
if (strcmp(st, "ram")) {
|
||||
error("unsupported device: %s\n", st);
|
||||
if (strcmp(argv[0], "ram")) {
|
||||
error("unsupported device: %s\n", argv[0]);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
dfu->layout = DFU_RAM_ADDR;
|
||||
dfu->data.ram.start = (void *)simple_strtoul(s, &s, 16);
|
||||
s++;
|
||||
dfu->data.ram.size = simple_strtoul(s, &s, 16);
|
||||
dfu->data.ram.start = (void *)simple_strtoul(argv[1], NULL, 16);
|
||||
dfu->data.ram.size = simple_strtoul(argv[2], NULL, 16);
|
||||
|
||||
dfu->write_medium = dfu_write_medium_ram;
|
||||
dfu->get_medium_size = dfu_get_medium_size_ram;
|
||||
|
|
|
@ -229,13 +229,13 @@ static void complete_rx(struct dwc2_udc *dev, u8 ep_num)
|
|||
ROUND(xfer_size, CONFIG_SYS_CACHELINE_SIZE));
|
||||
|
||||
req->req.actual += min(xfer_size, req->req.length - req->req.actual);
|
||||
is_short = (xfer_size < ep->ep.maxpacket);
|
||||
is_short = !!(xfer_size % ep->ep.maxpacket);
|
||||
|
||||
debug_cond(DEBUG_OUT_EP != 0,
|
||||
"%s: RX DMA done : ep = %d, rx bytes = %d/%d, "
|
||||
"is_short = %d, DOEPTSIZ = 0x%x, remained bytes = %d\n",
|
||||
__func__, ep_num, req->req.actual, req->req.length,
|
||||
is_short, ep_tsr, xfer_size);
|
||||
is_short, ep_tsr, req->req.length - req->req.actual);
|
||||
|
||||
if (is_short || req->req.actual == req->req.length) {
|
||||
if (ep_num == EP0_CON && dev->ep0state == DATA_STATE_RECV) {
|
||||
|
@ -292,7 +292,7 @@ static void complete_tx(struct dwc2_udc *dev, u8 ep_num)
|
|||
"%s: TX DMA done : ep = %d, tx bytes = %d/%d, "
|
||||
"is_short = %d, DIEPTSIZ = 0x%x, remained bytes = %d\n",
|
||||
__func__, ep_num, req->req.actual, req->req.length,
|
||||
is_short, ep_tsr, xfer_size);
|
||||
is_short, ep_tsr, req->req.length - req->req.actual);
|
||||
|
||||
if (ep_num == 0) {
|
||||
if (dev->ep0state == DATA_STATE_XMIT) {
|
||||
|
|
|
@ -39,6 +39,11 @@
|
|||
#define TX_ENDPOINT_MAXIMUM_PACKET_SIZE (0x0040)
|
||||
|
||||
#define EP_BUFFER_SIZE 4096
|
||||
/*
|
||||
* EP_BUFFER_SIZE must always be an integral multiple of maxpacket size
|
||||
* (64 or 512 or 1024), else we break on certain controllers like DWC3
|
||||
* that expect bulk OUT requests to be divisible by maxpacket size.
|
||||
*/
|
||||
|
||||
struct f_fastboot {
|
||||
struct usb_function usb_function;
|
||||
|
@ -57,15 +62,13 @@ static struct f_fastboot *fastboot_func;
|
|||
static unsigned int fastboot_flash_session_id;
|
||||
static unsigned int download_size;
|
||||
static unsigned int download_bytes;
|
||||
static bool is_high_speed;
|
||||
|
||||
static struct usb_endpoint_descriptor fs_ep_in = {
|
||||
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
.bEndpointAddress = USB_DIR_IN,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_BULK,
|
||||
.wMaxPacketSize = TX_ENDPOINT_MAXIMUM_PACKET_SIZE,
|
||||
.bInterval = 0x00,
|
||||
.wMaxPacketSize = cpu_to_le16(64),
|
||||
};
|
||||
|
||||
static struct usb_endpoint_descriptor fs_ep_out = {
|
||||
|
@ -73,8 +76,15 @@ static struct usb_endpoint_descriptor fs_ep_out = {
|
|||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
.bEndpointAddress = USB_DIR_OUT,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_BULK,
|
||||
.wMaxPacketSize = RX_ENDPOINT_MAXIMUM_PACKET_SIZE_1_1,
|
||||
.bInterval = 0x00,
|
||||
.wMaxPacketSize = cpu_to_le16(64),
|
||||
};
|
||||
|
||||
static struct usb_endpoint_descriptor hs_ep_in = {
|
||||
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
.bEndpointAddress = USB_DIR_IN,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_BULK,
|
||||
.wMaxPacketSize = cpu_to_le16(512),
|
||||
};
|
||||
|
||||
static struct usb_endpoint_descriptor hs_ep_out = {
|
||||
|
@ -82,8 +92,7 @@ static struct usb_endpoint_descriptor hs_ep_out = {
|
|||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
.bEndpointAddress = USB_DIR_OUT,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_BULK,
|
||||
.wMaxPacketSize = RX_ENDPOINT_MAXIMUM_PACKET_SIZE_2_0,
|
||||
.bInterval = 0x00,
|
||||
.wMaxPacketSize = cpu_to_le16(512),
|
||||
};
|
||||
|
||||
static struct usb_interface_descriptor interface_desc = {
|
||||
|
@ -97,13 +106,28 @@ static struct usb_interface_descriptor interface_desc = {
|
|||
.bInterfaceProtocol = FASTBOOT_INTERFACE_PROTOCOL,
|
||||
};
|
||||
|
||||
static struct usb_descriptor_header *fb_runtime_descs[] = {
|
||||
static struct usb_descriptor_header *fb_fs_function[] = {
|
||||
(struct usb_descriptor_header *)&interface_desc,
|
||||
(struct usb_descriptor_header *)&fs_ep_in,
|
||||
(struct usb_descriptor_header *)&fs_ep_out,
|
||||
};
|
||||
|
||||
static struct usb_descriptor_header *fb_hs_function[] = {
|
||||
(struct usb_descriptor_header *)&interface_desc,
|
||||
(struct usb_descriptor_header *)&hs_ep_in,
|
||||
(struct usb_descriptor_header *)&hs_ep_out,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static struct usb_endpoint_descriptor *
|
||||
fb_ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor *fs,
|
||||
struct usb_endpoint_descriptor *hs)
|
||||
{
|
||||
if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH)
|
||||
return hs;
|
||||
return fs;
|
||||
}
|
||||
|
||||
/*
|
||||
* static strings, in UTF-8
|
||||
*/
|
||||
|
@ -177,7 +201,15 @@ static int fastboot_bind(struct usb_configuration *c, struct usb_function *f)
|
|||
return -ENODEV;
|
||||
f_fb->out_ep->driver_data = c->cdev;
|
||||
|
||||
hs_ep_out.bEndpointAddress = fs_ep_out.bEndpointAddress;
|
||||
f->descriptors = fb_fs_function;
|
||||
|
||||
if (gadget_is_dualspeed(gadget)) {
|
||||
/* Assume endpoint addresses are the same for both speeds */
|
||||
hs_ep_in.bEndpointAddress = fs_ep_in.bEndpointAddress;
|
||||
hs_ep_out.bEndpointAddress = fs_ep_out.bEndpointAddress;
|
||||
/* copy HS descriptors */
|
||||
f->hs_descriptors = fb_hs_function;
|
||||
}
|
||||
|
||||
s = getenv("serial#");
|
||||
if (s)
|
||||
|
@ -236,18 +268,13 @@ static int fastboot_set_alt(struct usb_function *f,
|
|||
struct usb_composite_dev *cdev = f->config->cdev;
|
||||
struct usb_gadget *gadget = cdev->gadget;
|
||||
struct f_fastboot *f_fb = func_to_fastboot(f);
|
||||
const struct usb_endpoint_descriptor *d;
|
||||
|
||||
debug("%s: func: %s intf: %d alt: %d\n",
|
||||
__func__, f->name, interface, alt);
|
||||
|
||||
/* make sure we don't enable the ep twice */
|
||||
if (gadget->speed == USB_SPEED_HIGH) {
|
||||
ret = usb_ep_enable(f_fb->out_ep, &hs_ep_out);
|
||||
is_high_speed = true;
|
||||
} else {
|
||||
ret = usb_ep_enable(f_fb->out_ep, &fs_ep_out);
|
||||
is_high_speed = false;
|
||||
}
|
||||
d = fb_ep_desc(gadget, &fs_ep_out, &hs_ep_out);
|
||||
ret = usb_ep_enable(f_fb->out_ep, d);
|
||||
if (ret) {
|
||||
puts("failed to enable out ep\n");
|
||||
return ret;
|
||||
|
@ -261,7 +288,8 @@ static int fastboot_set_alt(struct usb_function *f,
|
|||
}
|
||||
f_fb->out_req->complete = rx_handler_command;
|
||||
|
||||
ret = usb_ep_enable(f_fb->in_ep, &fs_ep_in);
|
||||
d = fb_ep_desc(gadget, &fs_ep_in, &hs_ep_in);
|
||||
ret = usb_ep_enable(f_fb->in_ep, d);
|
||||
if (ret) {
|
||||
puts("failed to enable in ep\n");
|
||||
goto err;
|
||||
|
@ -302,7 +330,6 @@ static int fastboot_add(struct usb_configuration *c)
|
|||
}
|
||||
|
||||
f_fb->usb_function.name = "f_fastboot";
|
||||
f_fb->usb_function.hs_descriptors = fb_runtime_descs;
|
||||
f_fb->usb_function.bind = fastboot_bind;
|
||||
f_fb->usb_function.unbind = fastboot_unbind;
|
||||
f_fb->usb_function.set_alt = fastboot_set_alt;
|
||||
|
@ -427,20 +454,27 @@ static void cb_getvar(struct usb_ep *ep, struct usb_request *req)
|
|||
fastboot_tx_write_str(response);
|
||||
}
|
||||
|
||||
static unsigned int rx_bytes_expected(unsigned int maxpacket)
|
||||
static unsigned int rx_bytes_expected(struct usb_ep *ep)
|
||||
{
|
||||
int rx_remain = download_size - download_bytes;
|
||||
int rem = 0;
|
||||
if (rx_remain < 0)
|
||||
unsigned int rem;
|
||||
unsigned int maxpacket = ep->maxpacket;
|
||||
|
||||
if (rx_remain <= 0)
|
||||
return 0;
|
||||
if (rx_remain > EP_BUFFER_SIZE)
|
||||
else if (rx_remain > EP_BUFFER_SIZE)
|
||||
return EP_BUFFER_SIZE;
|
||||
if (rx_remain < maxpacket) {
|
||||
rx_remain = maxpacket;
|
||||
} else if (rx_remain % maxpacket != 0) {
|
||||
rem = rx_remain % maxpacket;
|
||||
|
||||
/*
|
||||
* Some controllers e.g. DWC3 don't like OUT transfers to be
|
||||
* not ending in maxpacket boundary. So just make them happy by
|
||||
* always requesting for integral multiple of maxpackets.
|
||||
* This shouldn't bother controllers that don't care about it.
|
||||
*/
|
||||
rem = rx_remain % maxpacket;
|
||||
if (rem > 0)
|
||||
rx_remain = rx_remain + (maxpacket - rem);
|
||||
}
|
||||
|
||||
return rx_remain;
|
||||
}
|
||||
|
||||
|
@ -452,7 +486,6 @@ static void rx_handler_dl_image(struct usb_ep *ep, struct usb_request *req)
|
|||
const unsigned char *buffer = req->buf;
|
||||
unsigned int buffer_size = req->actual;
|
||||
unsigned int pre_dot_num, now_dot_num;
|
||||
unsigned int max;
|
||||
|
||||
if (req->status != 0) {
|
||||
printf("Bad status: %d\n", req->status);
|
||||
|
@ -490,11 +523,7 @@ static void rx_handler_dl_image(struct usb_ep *ep, struct usb_request *req)
|
|||
|
||||
printf("\ndownloading of %d bytes finished\n", download_bytes);
|
||||
} else {
|
||||
max = is_high_speed ? hs_ep_out.wMaxPacketSize :
|
||||
fs_ep_out.wMaxPacketSize;
|
||||
req->length = rx_bytes_expected(max);
|
||||
if (req->length < ep->maxpacket)
|
||||
req->length = ep->maxpacket;
|
||||
req->length = rx_bytes_expected(ep);
|
||||
}
|
||||
|
||||
req->actual = 0;
|
||||
|
@ -505,7 +534,6 @@ static void cb_download(struct usb_ep *ep, struct usb_request *req)
|
|||
{
|
||||
char *cmd = req->buf;
|
||||
char response[FASTBOOT_RESPONSE_LEN];
|
||||
unsigned int max;
|
||||
|
||||
strsep(&cmd, ":");
|
||||
download_size = simple_strtoul(cmd, NULL, 16);
|
||||
|
@ -521,11 +549,7 @@ static void cb_download(struct usb_ep *ep, struct usb_request *req)
|
|||
} else {
|
||||
sprintf(response, "DATA%08x", download_size);
|
||||
req->complete = rx_handler_dl_image;
|
||||
max = is_high_speed ? hs_ep_out.wMaxPacketSize :
|
||||
fs_ep_out.wMaxPacketSize;
|
||||
req->length = rx_bytes_expected(max);
|
||||
if (req->length < ep->maxpacket)
|
||||
req->length = ep->maxpacket;
|
||||
req->length = rx_bytes_expected(ep);
|
||||
}
|
||||
fastboot_tx_write_str(response);
|
||||
}
|
||||
|
|
|
@ -30,6 +30,13 @@ env__usb_dev_ports = (
|
|||
},
|
||||
)
|
||||
|
||||
# Optional entries (required only when "alt_id_test_file" and
|
||||
# "alt_id_dummy_file" are specified).
|
||||
test_file_name = "/dfu_test.bin"
|
||||
dummy_file_name = "/dfu_dummy.bin"
|
||||
# Above files are used to generate proper "alt_info" entry
|
||||
"alt_info": "/%s ext4 0 2;/%s ext4 0 2" % (test_file_name, dummy_file_name),
|
||||
|
||||
env__dfu_configs = (
|
||||
# eMMC, partition 1
|
||||
{
|
||||
|
@ -44,6 +51,24 @@ env__dfu_configs = (
|
|||
# configurations, but don't want to test every single transfer size
|
||||
# on each, to avoid bloating the overall time taken by testing.
|
||||
"test_sizes": (63, 64, 65),
|
||||
# This value is optional.
|
||||
# The name of the environment variable that the the dfu command reads
|
||||
# alt info from. If unspecified, this defaults to dfu_alt_info, which is
|
||||
# valid for most systems. Some systems use a different variable name.
|
||||
# One example is the Odroid XU3, which automatically generates
|
||||
# $dfu_alt_info, each time the dfu command is run, by concatenating
|
||||
# $dfu_alt_boot and $dfu_alt_system.
|
||||
"alt_info_env_name": "dfu_alt_system",
|
||||
# This value is optional.
|
||||
# For boards which require the "test file" alt setting number other than
|
||||
# default (0) it is possible to specify exact file name to be used as
|
||||
# this parameter.
|
||||
"alt_id_test_file": test_file_name,
|
||||
# This value is optional.
|
||||
# For boards which require the "dummy file" alt setting number other
|
||||
# than default (1) it is possible to specify exact file name to be used
|
||||
# as this parameter.
|
||||
"alt_id_dummy_file": dummy_file_name,
|
||||
},
|
||||
)
|
||||
|
||||
|
@ -120,7 +145,11 @@ def test_dfu(u_boot_console, env__usb_dev_port, env__dfu_config):
|
|||
u_boot_console.log.action(
|
||||
'Starting long-running U-Boot dfu shell command')
|
||||
|
||||
cmd = 'setenv dfu_alt_info "%s"' % env__dfu_config['alt_info']
|
||||
dfu_alt_info_env = env__dfu_config.get('alt_info_env_name', \
|
||||
'dfu_alt_info')
|
||||
|
||||
cmd = 'setenv "%s" "%s"' % (dfu_alt_info_env,
|
||||
env__dfu_config['alt_info'])
|
||||
u_boot_console.run_command(cmd)
|
||||
|
||||
cmd = 'dfu 0 ' + env__dfu_config['cmd_params']
|
||||
|
@ -172,7 +201,7 @@ def test_dfu(u_boot_console, env__usb_dev_port, env__dfu_config):
|
|||
Nothing.
|
||||
"""
|
||||
|
||||
cmd = ['dfu-util', '-a', str(alt_setting), up_dn_load_arg, fn]
|
||||
cmd = ['dfu-util', '-a', alt_setting, up_dn_load_arg, fn]
|
||||
if 'host_usb_port_path' in env__usb_dev_port:
|
||||
cmd += ['-p', env__usb_dev_port['host_usb_port_path']]
|
||||
u_boot_utils.run_and_log(u_boot_console, cmd)
|
||||
|
@ -229,15 +258,15 @@ def test_dfu(u_boot_console, env__usb_dev_port, env__dfu_config):
|
|||
|
||||
u_boot_console.log.action('Writing test data to DFU primary ' +
|
||||
'altsetting')
|
||||
dfu_write(0, test_f.abs_fn)
|
||||
dfu_write(alt_setting_test_file, test_f.abs_fn)
|
||||
|
||||
u_boot_console.log.action('Writing dummy data to DFU secondary ' +
|
||||
'altsetting to clear DFU buffers')
|
||||
dfu_write(1, dummy_f.abs_fn)
|
||||
dfu_write(alt_setting_dummy_file, dummy_f.abs_fn)
|
||||
|
||||
u_boot_console.log.action('Reading DFU primary altsetting for ' +
|
||||
'comparison')
|
||||
dfu_read(0, readback_fn)
|
||||
dfu_read(alt_setting_test_file, readback_fn)
|
||||
|
||||
u_boot_console.log.action('Comparing written and read data')
|
||||
written_hash = test_f.content_hash
|
||||
|
@ -260,13 +289,16 @@ def test_dfu(u_boot_console, env__usb_dev_port, env__dfu_config):
|
|||
dummy_f = u_boot_utils.PersistentRandomFile(u_boot_console,
|
||||
'dfu_dummy.bin', 1024)
|
||||
|
||||
alt_setting_test_file = env__dfu_config.get('alt_id_test_file', '0')
|
||||
alt_setting_dummy_file = env__dfu_config.get('alt_id_dummy_file', '1')
|
||||
|
||||
ignore_cleanup_errors = True
|
||||
try:
|
||||
start_dfu()
|
||||
|
||||
u_boot_console.log.action(
|
||||
'Overwriting DFU primary altsetting with dummy data')
|
||||
dfu_write(0, dummy_f.abs_fn)
|
||||
dfu_write(alt_setting_test_file, dummy_f.abs_fn)
|
||||
|
||||
for size in sizes:
|
||||
with u_boot_console.log.section('Data size %d' % size):
|
||||
|
|
Loading…
Reference in New Issue