Merge branch 'master' of git://git.denx.de/u-boot-usb

This commit is contained in:
Tom Rini 2014-05-22 12:56:15 -04:00
commit c9afa7cea8
24 changed files with 1290 additions and 179 deletions

22
README
View File

@ -1579,6 +1579,28 @@ The following options need to be configured:
entering dfuMANIFEST state. Host waits this timeout, before
sending again an USB request to the device.
- USB Device Android Fastboot support:
CONFIG_CMD_FASTBOOT
This enables the command "fastboot" which enables the Android
fastboot mode for the platform's USB device. Fastboot is a USB
protocol for downloading images, flashing and device control
used on Android devices.
See doc/README.android-fastboot for more information.
CONFIG_ANDROID_BOOT_IMAGE
This enables support for booting images which use the Android
image format header.
CONFIG_USB_FASTBOOT_BUF_ADDR
The fastboot protocol requires a large memory buffer for
downloads. Define this to the starting RAM address to use for
downloaded images.
CONFIG_USB_FASTBOOT_BUF_SIZE
The fastboot protocol requires a large memory buffer for
downloads. This buffer should be as large as possible for a
platform. Define this to the size available RAM for fastboot.
- Journaling Flash filesystem support:
CONFIG_JFFS2_NAND, CONFIG_JFFS2_NAND_OFF, CONFIG_JFFS2_NAND_SIZE,
CONFIG_JFFS2_NAND_DEV

View File

@ -7,7 +7,6 @@
obj-$(CONFIG_SOFT_I2C_MULTI_BUS) += multi_i2c.o
obj-$(CONFIG_THOR_FUNCTION) += thor.o
obj-$(CONFIG_CMD_USB_MASS_STORAGE) += ums.o
obj-$(CONFIG_MISC_COMMON) += misc.o
ifndef CONFIG_SPL_BUILD

View File

@ -1,74 +0,0 @@
/*
* Copyright (C) 2013 Samsung Electronics
* Lukasz Majewski <l.majewski@samsung.com>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <usb_mass_storage.h>
#include <part.h>
static int ums_read_sector(struct ums *ums_dev,
ulong start, lbaint_t blkcnt, void *buf)
{
block_dev_desc_t *block_dev = &ums_dev->mmc->block_dev;
lbaint_t blkstart = start + ums_dev->start_sector;
int dev_num = block_dev->dev;
return block_dev->block_read(dev_num, blkstart, blkcnt, buf);
}
static int ums_write_sector(struct ums *ums_dev,
ulong start, lbaint_t blkcnt, const void *buf)
{
block_dev_desc_t *block_dev = &ums_dev->mmc->block_dev;
lbaint_t blkstart = start + ums_dev->start_sector;
int dev_num = block_dev->dev;
return block_dev->block_write(dev_num, blkstart, blkcnt, buf);
}
static struct ums ums_dev = {
.read_sector = ums_read_sector,
.write_sector = ums_write_sector,
.name = "UMS disk",
};
static struct ums *ums_disk_init(struct mmc *mmc)
{
uint64_t mmc_end_sector = mmc->capacity / SECTOR_SIZE;
uint64_t ums_end_sector = UMS_NUM_SECTORS + UMS_START_SECTOR;
if (!mmc_end_sector) {
error("MMC capacity is not valid");
return NULL;
}
ums_dev.mmc = mmc;
if (ums_end_sector <= mmc_end_sector) {
ums_dev.start_sector = UMS_START_SECTOR;
if (UMS_NUM_SECTORS)
ums_dev.num_sectors = UMS_NUM_SECTORS;
else
ums_dev.num_sectors = mmc_end_sector - UMS_START_SECTOR;
} else {
ums_dev.num_sectors = mmc_end_sector;
puts("UMS: defined bad disk parameters. Using default.\n");
}
printf("UMS: disk start sector: %#x, count: %#x\n",
ums_dev.start_sector, ums_dev.num_sectors);
return &ums_dev;
}
struct ums *ums_init(unsigned int dev_num)
{
struct mmc *mmc = find_mmc_device(dev_num);
if (!mmc || mmc_init(mmc))
return NULL;
return ums_disk_init(mmc);
}

View File

@ -168,6 +168,8 @@ obj-y += cmd_usb.o
obj-y += usb.o usb_hub.o
obj-$(CONFIG_USB_STORAGE) += usb_storage.o
endif
obj-$(CONFIG_CMD_FASTBOOT) += cmd_fastboot.o
obj-$(CONFIG_CMD_USB_MASS_STORAGE) += cmd_usb_mass_storage.o
obj-$(CONFIG_CMD_THOR_DOWNLOAD) += cmd_thordown.o
obj-$(CONFIG_CMD_XIMG) += cmd_ximg.o
@ -237,6 +239,7 @@ obj-y += console.o
obj-$(CONFIG_CROS_EC) += cros_ec.o
obj-y += dlmalloc.o
obj-y += image.o
obj-$(CONFIG_ANDROID_BOOT_IMAGE) += image-android.o
obj-$(CONFIG_OF_LIBFDT) += image-fdt.o
obj-$(CONFIG_FIT) += image-fit.o
obj-$(CONFIG_FIT_SIGNATURE) += image-sig.o

View File

@ -222,6 +222,7 @@ static int bootm_find_os(cmd_tbl_t *cmdtp, int flag, int argc,
char * const argv[])
{
const void *os_hdr;
bool ep_found = false;
/* get kernel image header, start address and length */
os_hdr = boot_get_kernel(cmdtp, flag, argc, argv,
@ -273,6 +274,18 @@ static int bootm_find_os(cmd_tbl_t *cmdtp, int flag, int argc,
return 1;
}
break;
#endif
#ifdef CONFIG_ANDROID_BOOT_IMAGE
case IMAGE_FORMAT_ANDROID:
images.os.type = IH_TYPE_KERNEL;
images.os.comp = IH_COMP_NONE;
images.os.os = IH_OS_LINUX;
images.ep = images.os.load;
ep_found = true;
images.os.end = android_image_get_end(os_hdr);
images.os.load = android_image_get_kload(os_hdr);
break;
#endif
default:
puts("ERROR: unknown image format type!\n");
@ -293,7 +306,7 @@ static int bootm_find_os(cmd_tbl_t *cmdtp, int flag, int argc,
return 1;
}
#endif
} else {
} else if (!ep_found) {
puts("Could not find kernel entry point!\n");
return 1;
}
@ -1001,6 +1014,14 @@ static const void *boot_get_kernel(cmd_tbl_t *cmdtp, int flag, int argc,
images->fit_uname_cfg = fit_uname_config;
images->fit_noffset_os = os_noffset;
break;
#endif
#ifdef CONFIG_ANDROID_BOOT_IMAGE
case IMAGE_FORMAT_ANDROID:
printf("## Booting Android Image at 0x%08lx ...\n", img_addr);
if (android_image_get_kernel((void *)img_addr, images->verify,
os_data, os_len))
return NULL;
break;
#endif
default:
printf("Wrong Image Format for %s command\n", cmdtp->name);

36
common/cmd_fastboot.c Normal file
View File

@ -0,0 +1,36 @@
/*
* Copyright 2008 - 2009 Windriver, <www.windriver.com>
* Author: Tom Rix <Tom.Rix@windriver.com>
*
* (C) Copyright 2014 Linaro, Ltd.
* Rob Herring <robh@kernel.org>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <command.h>
#include <g_dnl.h>
static int do_fastboot(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
{
int ret;
ret = g_dnl_register("usb_dnl_fastboot");
if (ret)
return ret;
while (1) {
if (ctrlc())
break;
usb_gadget_handle_interrupts();
}
g_dnl_unregister();
return CMD_RET_SUCCESS;
}
U_BOOT_CMD(
fastboot, 1, 1, do_fastboot,
"fastboot - enter USB Fastboot protocol",
""
);

View File

@ -9,41 +9,107 @@
#include <common.h>
#include <command.h>
#include <g_dnl.h>
#include <part.h>
#include <usb.h>
#include <usb_mass_storage.h>
static int ums_read_sector(struct ums *ums_dev,
ulong start, lbaint_t blkcnt, void *buf)
{
block_dev_desc_t *block_dev = ums_dev->block_dev;
lbaint_t blkstart = start + ums_dev->start_sector;
int dev_num = block_dev->dev;
return block_dev->block_read(dev_num, blkstart, blkcnt, buf);
}
static int ums_write_sector(struct ums *ums_dev,
ulong start, lbaint_t blkcnt, const void *buf)
{
block_dev_desc_t *block_dev = ums_dev->block_dev;
lbaint_t blkstart = start + ums_dev->start_sector;
int dev_num = block_dev->dev;
return block_dev->block_write(dev_num, blkstart, blkcnt, buf);
}
static struct ums ums_dev = {
.read_sector = ums_read_sector,
.write_sector = ums_write_sector,
.name = "UMS disk",
};
struct ums *ums_init(const char *devtype, const char *devnum)
{
block_dev_desc_t *block_dev;
int ret;
ret = get_device(devtype, devnum, &block_dev);
if (ret < 0)
return NULL;
/* f_mass_storage.c assumes SECTOR_SIZE sectors */
if (block_dev->blksz != SECTOR_SIZE)
return NULL;
ums_dev.block_dev = block_dev;
ums_dev.start_sector = 0;
ums_dev.num_sectors = block_dev->lba;
printf("UMS: disk start sector: %#x, count: %#x\n",
ums_dev.start_sector, ums_dev.num_sectors);
return &ums_dev;
}
int do_usb_mass_storage(cmd_tbl_t *cmdtp, int flag,
int argc, char * const argv[])
{
const char *usb_controller;
const char *devtype;
const char *devnum;
struct ums *ums;
unsigned int controller_index;
int rc;
int cable_ready_timeout __maybe_unused;
if (argc < 3)
return CMD_RET_USAGE;
const char *usb_controller = argv[1];
const char *mmc_devstring = argv[2];
usb_controller = argv[1];
if (argc >= 4) {
devtype = argv[2];
devnum = argv[3];
} else {
devtype = "mmc";
devnum = argv[2];
}
unsigned int dev_num = simple_strtoul(mmc_devstring, NULL, 0);
struct ums *ums = ums_init(dev_num);
ums = ums_init(devtype, devnum);
if (!ums)
return CMD_RET_FAILURE;
unsigned int controller_index = (unsigned int)(simple_strtoul(
usb_controller, NULL, 0));
controller_index = (unsigned int)(simple_strtoul(
usb_controller, NULL, 0));
if (board_usb_init(controller_index, USB_INIT_DEVICE)) {
error("Couldn't init USB controller.");
return CMD_RET_FAILURE;
}
int rc = fsg_init(ums);
rc = fsg_init(ums);
if (rc) {
error("fsg_init failed");
return CMD_RET_FAILURE;
}
g_dnl_register("usb_dnl_ums");
rc = g_dnl_register("usb_dnl_ums");
if (rc) {
error("g_dnl_register failed");
return CMD_RET_FAILURE;
}
/* Timeout unit: seconds */
int cable_ready_timeout = UMS_CABLE_READY_TIMEOUT;
cable_ready_timeout = UMS_CABLE_READY_TIMEOUT;
if (!g_dnl_board_usb_cable_connected()) {
/*
@ -91,7 +157,8 @@ exit:
return CMD_RET_SUCCESS;
}
U_BOOT_CMD(ums, CONFIG_SYS_MAXARGS, 1, do_usb_mass_storage,
U_BOOT_CMD(ums, 4, 1, do_usb_mass_storage,
"Use the UMS [User Mass Storage]",
"ums <USB_controller> <mmc_dev> e.g. ums 0 0"
"ums <USB_controller> [<devtype>] <devnum> e.g. ums 0 mmc 0\n"
" devtype defaults to mmc"
);

84
common/image-android.c Normal file
View File

@ -0,0 +1,84 @@
/*
* Copyright (c) 2011 Sebastian Andrzej Siewior <bigeasy@linutronix.de>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <image.h>
#include <android_image.h>
static char andr_tmp_str[ANDR_BOOT_ARGS_SIZE + 1];
int android_image_get_kernel(const struct andr_img_hdr *hdr, int verify,
ulong *os_data, ulong *os_len)
{
/*
* Not all Android tools use the id field for signing the image with
* sha1 (or anything) so we don't check it. It is not obvious that the
* string is null terminated so we take care of this.
*/
strncpy(andr_tmp_str, hdr->name, ANDR_BOOT_NAME_SIZE);
andr_tmp_str[ANDR_BOOT_NAME_SIZE] = '\0';
if (strlen(andr_tmp_str))
printf("Android's image name: %s\n", andr_tmp_str);
printf("Kernel load addr 0x%08x size %u KiB\n",
hdr->kernel_addr, DIV_ROUND_UP(hdr->kernel_size, 1024));
strncpy(andr_tmp_str, hdr->cmdline, ANDR_BOOT_ARGS_SIZE);
andr_tmp_str[ANDR_BOOT_ARGS_SIZE] = '\0';
if (strlen(andr_tmp_str)) {
printf("Kernel command line: %s\n", andr_tmp_str);
setenv("bootargs", andr_tmp_str);
}
if (hdr->ramdisk_size)
printf("RAM disk load addr 0x%08x size %u KiB\n",
hdr->ramdisk_addr,
DIV_ROUND_UP(hdr->ramdisk_size, 1024));
if (os_data) {
*os_data = (ulong)hdr;
*os_data += hdr->page_size;
}
if (os_len)
*os_len = hdr->kernel_size;
return 0;
}
int android_image_check_header(const struct andr_img_hdr *hdr)
{
return memcmp(ANDR_BOOT_MAGIC, hdr->magic, ANDR_BOOT_MAGIC_SIZE);
}
ulong android_image_get_end(const struct andr_img_hdr *hdr)
{
u32 size = 0;
/*
* The header takes a full page, the remaining components are aligned
* on page boundary
*/
size += hdr->page_size;
size += ALIGN(hdr->kernel_size, hdr->page_size);
size += ALIGN(hdr->ramdisk_size, hdr->page_size);
size += ALIGN(hdr->second_size, hdr->page_size);
return size;
}
ulong android_image_get_kload(const struct andr_img_hdr *hdr)
{
return hdr->kernel_addr;
}
int android_image_get_ramdisk(const struct andr_img_hdr *hdr,
ulong *rd_data, ulong *rd_len)
{
if (!hdr->ramdisk_size)
return -1;
*rd_data = (unsigned long)hdr;
*rd_data += hdr->page_size;
*rd_data += ALIGN(hdr->kernel_size, hdr->page_size);
*rd_len = hdr->ramdisk_size;
return 0;
}

View File

@ -660,10 +660,12 @@ int genimg_get_format(const void *img_addr)
if (image_check_magic(hdr))
format = IMAGE_FORMAT_LEGACY;
#if defined(CONFIG_FIT) || defined(CONFIG_OF_LIBFDT)
else {
if (fdt_check_header(img_addr) == 0)
format = IMAGE_FORMAT_FIT;
}
else if (fdt_check_header(img_addr) == 0)
format = IMAGE_FORMAT_FIT;
#endif
#ifdef CONFIG_ANDROID_BOOT_IMAGE
else if (android_image_check_header(img_addr) == 0)
format = IMAGE_FORMAT_ANDROID;
#endif
return format;
@ -933,7 +935,15 @@ int boot_get_ramdisk(int argc, char * const argv[], bootm_headers_t *images,
(ulong)images->legacy_hdr_os);
image_multi_getimg(images->legacy_hdr_os, 1, &rd_data, &rd_len);
} else {
}
#ifdef CONFIG_ANDROID_BOOT_IMAGE
else if ((genimg_get_format(images) == IMAGE_FORMAT_ANDROID) &&
(!android_image_get_ramdisk((void *)images->os.start,
&rd_data, &rd_len))) {
/* empty */
}
#endif
else {
/*
* no initrd image
*/

View File

@ -0,0 +1,91 @@
Android Fastboot
~~~~~~~~~~~~~~~~
Overview
========
The protocol that is used over USB is described in
README.android-fastboot-protocol in same directory.
The current implementation does not yet support the flash and erase
commands.
Client installation
===================
The counterpart to this gadget is the fastboot client which can
be found in Android's platform/system/core repository in the fastboot
folder. It runs on Windows, Linux and even OSX. Linux user are lucky since
they only need libusb.
Windows users need to bring some time until they have Android SDK (currently
http://dl.google.com/android/installer_r12-windows.exe) installed. You
need to install ADB package which contains the required glue libraries for
accessing USB. Also you need "Google USB driver package" and "SDK platform
tools". Once installed the usb driver is placed in your SDK folder under
extras\google\usb_driver. The android_winusb.inf needs a line like
%SingleBootLoaderInterface% = USB_Install, USB\VID_0451&PID_D022
either in the [Google.NTx86] section for 32bit Windows or [Google.NTamd64]
for 64bit Windows. VID and PID should match whatever the fastboot is
advertising.
Board specific
==============
The fastboot gadget relies on the USB download gadget, so the following
options must be configured:
CONFIG_USBDOWNLOAD_GADGET
CONFIG_G_DNL_VENDOR_NUM
CONFIG_G_DNL_PRODUCT_NUM
CONFIG_G_DNL_MANUFACTURER
The fastboot function is enabled by defining CONFIG_CMD_FASTBOOT and
CONFIG_ANDROID_BOOT_IMAGE.
The fastboot protocol requires a large memory buffer for downloads. This
buffer should be as large as possible for a platform. The location of the
buffer and size are set with CONFIG_USB_FASTBOOT_BUF_ADDR and
CONFIG_USB_FASTBOOT_BUF_SIZE.
In Action
=========
Enter into fastboot by executing the fastboot command in u-boot and you
should see:
|GADGET DRIVER: usb_dnl_fastboot
On the client side you can fetch the bootloader version for instance:
|>fastboot getvar bootloader-version
|bootloader-version: U-Boot 2014.04-00005-gd24cabc
|finished. total time: 0.000s
or initiate a reboot:
|>fastboot reboot
and once the client comes back, the board should reset.
You can also specify a kernel image to boot. You have to either specify
the an image in Android format _or_ pass a binary kernel and let the
fastboot client wrap the Android suite around it. On OMAP for instance you
take zImage kernel and pass it to the fastboot client:
|>fastboot -b 0x80000000 -c "console=ttyO2 earlyprintk root=/dev/ram0
| mem=128M" boot zImage
|creating boot image...
|creating boot image - 1847296 bytes
|downloading 'boot.img'...
|OKAY [ 2.766s]
|booting...
|OKAY [ -0.000s]
|finished. total time: 2.766s
and on the gadget side you should see:
|Starting download of 1847296 bytes
|........................................................
|downloading of 1847296 bytes finished
|Booting kernel..
|## Booting Android Image at 0x81000000 ...
|Kernel load addr 0x80008000 size 1801 KiB
|Kernel command line: console=ttyO2 earlyprintk root=/dev/ram0 mem=128M
| Loading Kernel Image ... OK
|OK
|
|Starting kernel ...

View File

@ -0,0 +1,170 @@
FastBoot Version 0.4
----------------------
The fastboot protocol is a mechanism for communicating with bootloaders
over USB. It is designed to be very straightforward to implement, to
allow it to be used across a wide range of devices and from hosts running
Linux, Windows, or OSX.
Basic Requirements
------------------
* Two bulk endpoints (in, out) are required
* Max packet size must be 64 bytes for full-speed and 512 bytes for
high-speed USB
* The protocol is entirely host-driven and synchronous (unlike the
multi-channel, bi-directional, asynchronous ADB protocol)
Transport and Framing
---------------------
1. Host sends a command, which is an ascii string in a single
packet no greater than 64 bytes.
2. Client response with a single packet no greater than 64 bytes.
The first four bytes of the response are "OKAY", "FAIL", "DATA",
or "INFO". Additional bytes may contain an (ascii) informative
message.
a. INFO -> the remaining 60 bytes are an informative message
(providing progress or diagnostic messages). They should
be displayed and then step #2 repeats
b. FAIL -> the requested command failed. The remaining 60 bytes
of the response (if present) provide a textual failure message
to present to the user. Stop.
c. OKAY -> the requested command completed successfully. Go to #5
d. DATA -> the requested command is ready for the data phase.
A DATA response packet will be 12 bytes long, in the form of
DATA00000000 where the 8 digit hexidecimal number represents
the total data size to transfer.
3. Data phase. Depending on the command, the host or client will
send the indicated amount of data. Short packets are always
acceptable and zero-length packets are ignored. This phase continues
until the client has sent or received the number of bytes indicated
in the "DATA" response above.
4. Client responds with a single packet no greater than 64 bytes.
The first four bytes of the response are "OKAY", "FAIL", or "INFO".
Similar to #2:
a. INFO -> display the remaining 60 bytes and return to #4
b. FAIL -> display the remaining 60 bytes (if present) as a failure
reason and consider the command failed. Stop.
c. OKAY -> success. Go to #5
5. Success. Stop.
Example Session
---------------
Host: "getvar:version" request version variable
Client: "OKAY0.4" return version "0.4"
Host: "getvar:nonexistant" request some undefined variable
Client: "OKAY" return value ""
Host: "download:00001234" request to send 0x1234 bytes of data
Client: "DATA00001234" ready to accept data
Host: < 0x1234 bytes > send data
Client: "OKAY" success
Host: "flash:bootloader" request to flash the data to the bootloader
Client: "INFOerasing flash" indicate status / progress
"INFOwriting flash"
"OKAY" indicate success
Host: "powerdown" send a command
Client: "FAILunknown command" indicate failure
Command Reference
-----------------
* Command parameters are indicated by printf-style escape sequences.
* Commands are ascii strings and sent without the quotes (which are
for illustration only here) and without a trailing 0 byte.
* Commands that begin with a lowercase letter are reserved for this
specification. OEM-specific commands should not begin with a
lowercase letter, to prevent incompatibilities with future specs.
"getvar:%s" Read a config/version variable from the bootloader.
The variable contents will be returned after the
OKAY response.
"download:%08x" Write data to memory which will be later used
by "boot", "ramdisk", "flash", etc. The client
will reply with "DATA%08x" if it has enough
space in RAM or "FAIL" if not. The size of
the download is remembered.
"verify:%08x" Send a digital signature to verify the downloaded
data. Required if the bootloader is "secure"
otherwise "flash" and "boot" will be ignored.
"flash:%s" Write the previously downloaded image to the
named partition (if possible).
"erase:%s" Erase the indicated partition (clear to 0xFFs)
"boot" The previously downloaded data is a boot.img
and should be booted according to the normal
procedure for a boot.img
"continue" Continue booting as normal (if possible)
"reboot" Reboot the device.
"reboot-bootloader" Reboot back into the bootloader.
Useful for upgrade processes that require upgrading
the bootloader and then upgrading other partitions
using the new bootloader.
"powerdown" Power off the device.
Client Variables
----------------
The "getvar:%s" command is used to read client variables which
represent various information about the device and the software
on it.
The various currently defined names are:
version Version of FastBoot protocol supported.
It should be "0.3" for this document.
version-bootloader Version string for the Bootloader.
version-baseband Version string of the Baseband Software
product Name of the product
serialno Product serial number
secure If the value is "yes", this is a secure
bootloader requiring a signature before
it will install or boot images.
Names starting with a lowercase character are reserved by this
specification. OEM-specific names should not start with lowercase
characters.

View File

@ -163,6 +163,18 @@ static int dfu_flush_medium_nand(struct dfu_entity *dfu)
return ret;
}
unsigned int dfu_polltimeout_nand(struct dfu_entity *dfu)
{
/*
* Currently, Poll Timeout != 0 is only needed on nand
* ubi partition, as the not used sectors need an erase
*/
if (dfu->data.nand.ubi)
return DFU_MANIFEST_POLL_TIMEOUT;
return DFU_DEFAULT_POLL_TIMEOUT;
}
int dfu_fill_entity_nand(struct dfu_entity *dfu, char *s)
{
char *st;
@ -211,6 +223,7 @@ int dfu_fill_entity_nand(struct dfu_entity *dfu, char *s)
dfu->read_medium = dfu_read_medium_nand;
dfu->write_medium = dfu_write_medium_nand;
dfu->flush_medium = dfu_flush_medium_nand;
dfu->poll_timeout = dfu_polltimeout_nand;
/* initial state */
dfu->inited = 0;

View File

@ -18,6 +18,7 @@ obj-$(CONFIG_THOR_FUNCTION) += f_thor.o
obj-$(CONFIG_USBDOWNLOAD_GADGET) += g_dnl.o
obj-$(CONFIG_DFU_FUNCTION) += f_dfu.o
obj-$(CONFIG_USB_GADGET_MASS_STORAGE) += f_mass_storage.o
obj-$(CONFIG_CMD_FASTBOOT) += f_fastboot.o
endif
ifdef CONFIG_USB_ETHER
obj-y += ether.o

View File

@ -205,13 +205,26 @@ static void ci_invalidate_qtd(int ep_num)
static struct usb_request *
ci_ep_alloc_request(struct usb_ep *ep, unsigned int gfp_flags)
{
struct ci_ep *ci_ep = container_of(ep, struct ci_ep, ep);
return &ci_ep->req;
struct ci_req *ci_req;
ci_req = memalign(ARCH_DMA_MINALIGN, sizeof(*ci_req));
if (!ci_req)
return NULL;
INIT_LIST_HEAD(&ci_req->queue);
ci_req->b_buf = 0;
return &ci_req->req;
}
static void ci_ep_free_request(struct usb_ep *ep, struct usb_request *_req)
static void ci_ep_free_request(struct usb_ep *ep, struct usb_request *req)
{
return;
struct ci_req *ci_req;
ci_req = container_of(req, struct ci_req, req);
if (ci_req->b_buf)
free(ci_req->b_buf);
free(ci_req);
}
static void ep_enable(int num, int in, int maxpacket)
@ -267,99 +280,102 @@ static int ci_ep_disable(struct usb_ep *ep)
return 0;
}
static int ci_bounce(struct ci_ep *ep, int in)
static int ci_bounce(struct ci_req *ci_req, int in)
{
uint32_t addr = (uint32_t)ep->req.buf;
uint32_t ba;
struct usb_request *req = &ci_req->req;
uint32_t addr = (uint32_t)req->buf;
uint32_t hwaddr;
uint32_t aligned_used_len;
/* Input buffer address is not aligned. */
if (addr & (ARCH_DMA_MINALIGN - 1))
goto align;
/* Input buffer length is not aligned. */
if (ep->req.length & (ARCH_DMA_MINALIGN - 1))
if (req->length & (ARCH_DMA_MINALIGN - 1))
goto align;
/* The buffer is well aligned, only flush cache. */
ep->b_len = ep->req.length;
ep->b_buf = ep->req.buf;
ci_req->hw_len = req->length;
ci_req->hw_buf = req->buf;
goto flush;
align:
/* Use internal buffer for small payloads. */
if (ep->req.length <= 64) {
ep->b_len = 64;
ep->b_buf = ep->b_fast;
} else {
ep->b_len = roundup(ep->req.length, ARCH_DMA_MINALIGN);
ep->b_buf = memalign(ARCH_DMA_MINALIGN, ep->b_len);
if (!ep->b_buf)
if (ci_req->b_buf && req->length > ci_req->b_len) {
free(ci_req->b_buf);
ci_req->b_buf = 0;
}
if (!ci_req->b_buf) {
ci_req->b_len = roundup(req->length, ARCH_DMA_MINALIGN);
ci_req->b_buf = memalign(ARCH_DMA_MINALIGN, ci_req->b_len);
if (!ci_req->b_buf)
return -ENOMEM;
}
ci_req->hw_len = ci_req->b_len;
ci_req->hw_buf = ci_req->b_buf;
if (in)
memcpy(ep->b_buf, ep->req.buf, ep->req.length);
memcpy(ci_req->hw_buf, req->buf, req->length);
flush:
ba = (uint32_t)ep->b_buf;
flush_dcache_range(ba, ba + ep->b_len);
hwaddr = (uint32_t)ci_req->hw_buf;
aligned_used_len = roundup(req->length, ARCH_DMA_MINALIGN);
flush_dcache_range(hwaddr, hwaddr + aligned_used_len);
return 0;
}
static void ci_debounce(struct ci_ep *ep, int in)
static void ci_debounce(struct ci_req *ci_req, int in)
{
uint32_t addr = (uint32_t)ep->req.buf;
uint32_t ba = (uint32_t)ep->b_buf;
struct usb_request *req = &ci_req->req;
uint32_t addr = (uint32_t)req->buf;
uint32_t hwaddr = (uint32_t)ci_req->hw_buf;
uint32_t aligned_used_len;
if (in) {
if (addr == ba)
return; /* not a bounce */
goto free;
}
invalidate_dcache_range(ba, ba + ep->b_len);
if (in)
return;
if (addr == ba)
return; /* not a bounce */
aligned_used_len = roundup(req->actual, ARCH_DMA_MINALIGN);
invalidate_dcache_range(hwaddr, hwaddr + aligned_used_len);
memcpy(ep->req.buf, ep->b_buf, ep->req.actual);
free:
/* Large payloads use allocated buffer, free it. */
if (ep->b_buf != ep->b_fast)
free(ep->b_buf);
if (addr == hwaddr)
return; /* not a bounce */
memcpy(req->buf, ci_req->hw_buf, req->actual);
}
static int ci_ep_queue(struct usb_ep *ep,
struct usb_request *req, gfp_t gfp_flags)
static void ci_ep_submit_next_request(struct ci_ep *ci_ep)
{
struct ci_ep *ci_ep = container_of(ep, struct ci_ep, ep);
struct ci_udc *udc = (struct ci_udc *)controller.ctrl->hcor;
struct ept_queue_item *item;
struct ept_queue_head *head;
int bit, num, len, in, ret;
int bit, num, len, in;
struct ci_req *ci_req;
ci_ep->req_primed = true;
num = ci_ep->desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
in = (ci_ep->desc->bEndpointAddress & USB_DIR_IN) != 0;
item = ci_get_qtd(num, in);
head = ci_get_qh(num, in);
len = req->length;
ret = ci_bounce(ci_ep, in);
if (ret)
return ret;
ci_req = list_first_entry(&ci_ep->queue, struct ci_req, queue);
len = ci_req->req.length;
item->next = TERMINATE;
item->info = INFO_BYTES(len) | INFO_IOC | INFO_ACTIVE;
item->page0 = (uint32_t)ci_ep->b_buf;
item->page1 = ((uint32_t)ci_ep->b_buf & 0xfffff000) + 0x1000;
item->page2 = ((uint32_t)ci_ep->b_buf & 0xfffff000) + 0x2000;
item->page3 = ((uint32_t)ci_ep->b_buf & 0xfffff000) + 0x3000;
item->page4 = ((uint32_t)ci_ep->b_buf & 0xfffff000) + 0x4000;
item->page0 = (uint32_t)ci_req->hw_buf;
item->page1 = ((uint32_t)ci_req->hw_buf & 0xfffff000) + 0x1000;
item->page2 = ((uint32_t)ci_req->hw_buf & 0xfffff000) + 0x2000;
item->page3 = ((uint32_t)ci_req->hw_buf & 0xfffff000) + 0x3000;
item->page4 = ((uint32_t)ci_req->hw_buf & 0xfffff000) + 0x4000;
ci_flush_qtd(num);
head->next = (unsigned) item;
head->info = 0;
DBG("ept%d %s queue len %x, buffer %p\n",
num, in ? "in" : "out", len, ci_ep->b_buf);
DBG("ept%d %s queue len %x, req %p, buffer %p\n",
num, in ? "in" : "out", len, ci_req, ci_req->hw_buf);
ci_flush_qh(num);
if (in)
@ -368,6 +384,29 @@ static int ci_ep_queue(struct usb_ep *ep,
bit = EPT_RX(num);
writel(bit, &udc->epprime);
}
static int ci_ep_queue(struct usb_ep *ep,
struct usb_request *req, gfp_t gfp_flags)
{
struct ci_ep *ci_ep = container_of(ep, struct ci_ep, ep);
struct ci_req *ci_req = container_of(req, struct ci_req, req);
int in, ret;
int __maybe_unused num;
num = ci_ep->desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
in = (ci_ep->desc->bEndpointAddress & USB_DIR_IN) != 0;
ret = ci_bounce(ci_req, in);
if (ret)
return ret;
DBG("ept%d %s pre-queue req %p, buffer %p\n",
num, in ? "in" : "out", ci_req, ci_req->hw_buf);
list_add_tail(&ci_req->queue, &ci_ep->queue);
if (!ci_ep->req_primed)
ci_ep_submit_next_request(ci_ep);
return 0;
}
@ -376,6 +415,8 @@ static void handle_ep_complete(struct ci_ep *ep)
{
struct ept_queue_item *item;
int num, in, len;
struct ci_req *ci_req;
num = ep->desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
in = (ep->desc->bEndpointAddress & USB_DIR_IN) != 0;
if (num == 0)
@ -387,16 +428,23 @@ static void handle_ep_complete(struct ci_ep *ep)
printf("EP%d/%s FAIL info=%x pg0=%x\n",
num, in ? "in" : "out", item->info, item->page0);
len = (item->info >> 16) & 0x7fff;
ep->req.actual = ep->req.length - len;
ci_debounce(ep, in);
ci_req = list_first_entry(&ep->queue, struct ci_req, queue);
list_del_init(&ci_req->queue);
ep->req_primed = false;
DBG("ept%d %s complete %x\n",
num, in ? "in" : "out", len);
ep->req.complete(&ep->ep, &ep->req);
if (!list_empty(&ep->queue))
ci_ep_submit_next_request(ep);
len = (item->info >> 16) & 0x7fff;
ci_req->req.actual = ci_req->req.length - len;
ci_debounce(ci_req, in);
DBG("ept%d %s req %p, complete %x\n",
num, in ? "in" : "out", ci_req, len);
ci_req->req.complete(&ep->ep, &ci_req->req);
if (num == 0) {
ep->req.length = 0;
usb_ep_queue(&ep->ep, &ep->req, 0);
ci_req->req.length = 0;
usb_ep_queue(&ep->ep, &ci_req->req, 0);
ep->desc = &ep0_in_desc;
}
}
@ -405,13 +453,18 @@ static void handle_ep_complete(struct ci_ep *ep)
static void handle_setup(void)
{
struct usb_request *req = &controller.ep[0].req;
struct ci_ep *ci_ep = &controller.ep[0];
struct ci_req *ci_req;
struct usb_request *req;
struct ci_udc *udc = (struct ci_udc *)controller.ctrl->hcor;
struct ept_queue_head *head;
struct usb_ctrlrequest r;
int status = 0;
int num, in, _num, _in, i;
char *buf;
ci_req = list_first_entry(&ci_ep->queue, struct ci_req, queue);
req = &ci_req->req;
head = ci_get_qh(0, 0); /* EP0 OUT */
ci_invalidate_qh(0);
@ -424,6 +477,9 @@ static void handle_setup(void)
DBG("handle setup %s, %x, %x index %x value %x\n", reqname(r.bRequest),
r.bRequestType, r.bRequest, r.wIndex, r.wValue);
list_del_init(&ci_req->queue);
ci_ep->req_primed = false;
switch (SETUP(r.bRequestType, r.bRequest)) {
case SETUP(USB_RECIP_ENDPOINT, USB_REQ_CLEAR_FEATURE):
_num = r.wIndex & 15;
@ -701,6 +757,8 @@ static int ci_udc_probe(void)
/* Init EP 0 */
memcpy(&controller.ep[0].ep, &ci_ep_init[0], sizeof(*ci_ep_init));
controller.ep[0].desc = &ep0_in_desc;
INIT_LIST_HEAD(&controller.ep[0].queue);
controller.ep[0].req_primed = false;
controller.gadget.ep0 = &controller.ep[0].ep;
INIT_LIST_HEAD(&controller.gadget.ep0->ep_list);
@ -708,6 +766,8 @@ static int ci_udc_probe(void)
for (i = 1; i < NUM_ENDPOINTS; i++) {
memcpy(&controller.ep[i].ep, &ci_ep_init[1],
sizeof(*ci_ep_init));
INIT_LIST_HEAD(&controller.ep[i].queue);
controller.ep[i].req_primed = false;
list_add_tail(&controller.ep[i].ep.ep_list,
&controller.gadget.ep_list);
}

View File

@ -77,15 +77,22 @@ struct ci_udc {
#define CTRL_TXT_BULK (2 << 18)
#define CTRL_RXT_BULK (2 << 2)
struct ci_req {
struct usb_request req;
struct list_head queue;
/* Bounce buffer allocated if needed to align the transfer */
uint8_t *b_buf;
uint32_t b_len;
/* Buffer for the current transfer. Either req.buf/len or b_buf/len */
uint8_t *hw_buf;
uint32_t hw_len;
};
struct ci_ep {
struct usb_ep ep;
struct list_head queue;
bool req_primed;
const struct usb_endpoint_descriptor *desc;
struct usb_request req;
uint8_t *b_buf;
uint32_t b_len;
uint8_t b_fast[64] __aligned(ARCH_DMA_MINALIGN);
};
struct ci_drv {

View File

@ -175,10 +175,17 @@ static void dnload_request_flush(struct usb_ep *ep, struct usb_request *req)
req->length, f_dfu->blk_seq_num);
}
static inline int dfu_get_manifest_timeout(struct dfu_entity *dfu)
{
return dfu->poll_timeout ? dfu->poll_timeout(dfu) :
DFU_MANIFEST_POLL_TIMEOUT;
}
static void handle_getstatus(struct usb_request *req)
{
struct dfu_status *dstat = (struct dfu_status *)req->buf;
struct f_dfu *f_dfu = req->context;
struct dfu_entity *dfu = dfu_get_entity(f_dfu->altsetting);
dfu_set_poll_timeout(dstat, 0);
@ -191,7 +198,8 @@ static void handle_getstatus(struct usb_request *req)
f_dfu->dfu_state = DFU_STATE_dfuMANIFEST;
break;
case DFU_STATE_dfuMANIFEST:
dfu_set_poll_timeout(dstat, DFU_MANIFEST_POLL_TIMEOUT);
dfu_set_poll_timeout(dstat, dfu_get_manifest_timeout(dfu));
break;
default:
break;
}

View File

@ -0,0 +1,513 @@
/*
* (C) Copyright 2008 - 2009
* Windriver, <www.windriver.com>
* Tom Rix <Tom.Rix@windriver.com>
*
* Copyright 2011 Sebastian Andrzej Siewior <bigeasy@linutronix.de>
*
* Copyright 2014 Linaro, Ltd.
* Rob Herring <robh@kernel.org>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <errno.h>
#include <malloc.h>
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
#include <linux/usb/composite.h>
#include <linux/compiler.h>
#include <version.h>
#include <g_dnl.h>
#define FASTBOOT_VERSION "0.4"
#define FASTBOOT_INTERFACE_CLASS 0xff
#define FASTBOOT_INTERFACE_SUB_CLASS 0x42
#define FASTBOOT_INTERFACE_PROTOCOL 0x03
#define RX_ENDPOINT_MAXIMUM_PACKET_SIZE_2_0 (0x0200)
#define RX_ENDPOINT_MAXIMUM_PACKET_SIZE_1_1 (0x0040)
#define TX_ENDPOINT_MAXIMUM_PACKET_SIZE (0x0040)
/* The 64 defined bytes plus \0 */
#define RESPONSE_LEN (64 + 1)
#define EP_BUFFER_SIZE 4096
struct f_fastboot {
struct usb_function usb_function;
/* IN/OUT EP's and correspoinding requests */
struct usb_ep *in_ep, *out_ep;
struct usb_request *in_req, *out_req;
};
static inline struct f_fastboot *func_to_fastboot(struct usb_function *f)
{
return container_of(f, struct f_fastboot, usb_function);
}
static struct f_fastboot *fastboot_func;
static unsigned int download_size;
static unsigned int download_bytes;
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,
};
static struct usb_endpoint_descriptor fs_ep_out = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = USB_DIR_OUT,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
.wMaxPacketSize = RX_ENDPOINT_MAXIMUM_PACKET_SIZE_1_1,
.bInterval = 0x00,
};
static struct usb_endpoint_descriptor hs_ep_out = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = USB_DIR_OUT,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
.wMaxPacketSize = RX_ENDPOINT_MAXIMUM_PACKET_SIZE_2_0,
.bInterval = 0x00,
};
static struct usb_interface_descriptor interface_desc = {
.bLength = USB_DT_INTERFACE_SIZE,
.bDescriptorType = USB_DT_INTERFACE,
.bInterfaceNumber = 0x00,
.bAlternateSetting = 0x00,
.bNumEndpoints = 0x02,
.bInterfaceClass = FASTBOOT_INTERFACE_CLASS,
.bInterfaceSubClass = FASTBOOT_INTERFACE_SUB_CLASS,
.bInterfaceProtocol = FASTBOOT_INTERFACE_PROTOCOL,
};
static struct usb_descriptor_header *fb_runtime_descs[] = {
(struct usb_descriptor_header *)&interface_desc,
(struct usb_descriptor_header *)&fs_ep_in,
(struct usb_descriptor_header *)&hs_ep_out,
NULL,
};
/*
* static strings, in UTF-8
*/
static const char fastboot_name[] = "Android Fastboot";
static struct usb_string fastboot_string_defs[] = {
[0].s = fastboot_name,
{ } /* end of list */
};
static struct usb_gadget_strings stringtab_fastboot = {
.language = 0x0409, /* en-us */
.strings = fastboot_string_defs,
};
static struct usb_gadget_strings *fastboot_strings[] = {
&stringtab_fastboot,
NULL,
};
static void rx_handler_command(struct usb_ep *ep, struct usb_request *req);
static void fastboot_complete(struct usb_ep *ep, struct usb_request *req)
{
int status = req->status;
if (!status)
return;
printf("status: %d ep '%s' trans: %d\n", status, ep->name, req->actual);
}
static int fastboot_bind(struct usb_configuration *c, struct usb_function *f)
{
int id;
struct usb_gadget *gadget = c->cdev->gadget;
struct f_fastboot *f_fb = func_to_fastboot(f);
/* DYNAMIC interface numbers assignments */
id = usb_interface_id(c, f);
if (id < 0)
return id;
interface_desc.bInterfaceNumber = id;
id = usb_string_id(c->cdev);
if (id < 0)
return id;
fastboot_string_defs[0].id = id;
interface_desc.iInterface = id;
f_fb->in_ep = usb_ep_autoconfig(gadget, &fs_ep_in);
if (!f_fb->in_ep)
return -ENODEV;
f_fb->in_ep->driver_data = c->cdev;
f_fb->out_ep = usb_ep_autoconfig(gadget, &fs_ep_out);
if (!f_fb->out_ep)
return -ENODEV;
f_fb->out_ep->driver_data = c->cdev;
hs_ep_out.bEndpointAddress = fs_ep_out.bEndpointAddress;
return 0;
}
static void fastboot_unbind(struct usb_configuration *c, struct usb_function *f)
{
memset(fastboot_func, 0, sizeof(*fastboot_func));
}
static void fastboot_disable(struct usb_function *f)
{
struct f_fastboot *f_fb = func_to_fastboot(f);
usb_ep_disable(f_fb->out_ep);
usb_ep_disable(f_fb->in_ep);
if (f_fb->out_req) {
free(f_fb->out_req->buf);
usb_ep_free_request(f_fb->out_ep, f_fb->out_req);
f_fb->out_req = NULL;
}
if (f_fb->in_req) {
free(f_fb->in_req->buf);
usb_ep_free_request(f_fb->in_ep, f_fb->in_req);
f_fb->in_req = NULL;
}
}
static struct usb_request *fastboot_start_ep(struct usb_ep *ep)
{
struct usb_request *req;
req = usb_ep_alloc_request(ep, 0);
if (!req)
return NULL;
req->length = EP_BUFFER_SIZE;
req->buf = memalign(CONFIG_SYS_CACHELINE_SIZE, EP_BUFFER_SIZE);
if (!req->buf) {
usb_ep_free_request(ep, req);
return NULL;
}
memset(req->buf, 0, req->length);
return req;
}
static int fastboot_set_alt(struct usb_function *f,
unsigned interface, unsigned alt)
{
int ret;
struct usb_composite_dev *cdev = f->config->cdev;
struct usb_gadget *gadget = cdev->gadget;
struct f_fastboot *f_fb = func_to_fastboot(f);
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);
else
ret = usb_ep_enable(f_fb->out_ep, &fs_ep_out);
if (ret) {
puts("failed to enable out ep\n");
return ret;
}
f_fb->out_req = fastboot_start_ep(f_fb->out_ep);
if (!f_fb->out_req) {
puts("failed to alloc out req\n");
ret = -EINVAL;
goto err;
}
f_fb->out_req->complete = rx_handler_command;
ret = usb_ep_enable(f_fb->in_ep, &fs_ep_in);
if (ret) {
puts("failed to enable in ep\n");
goto err;
}
f_fb->in_req = fastboot_start_ep(f_fb->in_ep);
if (!f_fb->in_req) {
puts("failed alloc req in\n");
ret = -EINVAL;
goto err;
}
f_fb->in_req->complete = fastboot_complete;
ret = usb_ep_queue(f_fb->out_ep, f_fb->out_req, 0);
if (ret)
goto err;
return 0;
err:
fastboot_disable(f);
return ret;
}
static int fastboot_add(struct usb_configuration *c)
{
struct f_fastboot *f_fb = fastboot_func;
int status;
debug("%s: cdev: 0x%p\n", __func__, c->cdev);
if (!f_fb) {
f_fb = memalign(CONFIG_SYS_CACHELINE_SIZE, sizeof(*f_fb));
if (!f_fb)
return -ENOMEM;
fastboot_func = f_fb;
memset(f_fb, 0, sizeof(*f_fb));
}
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;
f_fb->usb_function.disable = fastboot_disable;
f_fb->usb_function.strings = fastboot_strings;
status = usb_add_function(c, &f_fb->usb_function);
if (status) {
free(f_fb);
fastboot_func = f_fb;
}
return status;
}
DECLARE_GADGET_BIND_CALLBACK(usb_dnl_fastboot, fastboot_add);
int fastboot_tx_write(const char *buffer, unsigned int buffer_size)
{
struct usb_request *in_req = fastboot_func->in_req;
int ret;
memcpy(in_req->buf, buffer, buffer_size);
in_req->length = buffer_size;
ret = usb_ep_queue(fastboot_func->in_ep, in_req, 0);
if (ret)
printf("Error %d on queue\n", ret);
return 0;
}
static int fastboot_tx_write_str(const char *buffer)
{
return fastboot_tx_write(buffer, strlen(buffer));
}
static void compl_do_reset(struct usb_ep *ep, struct usb_request *req)
{
do_reset(NULL, 0, 0, NULL);
}
static void cb_reboot(struct usb_ep *ep, struct usb_request *req)
{
fastboot_func->in_req->complete = compl_do_reset;
fastboot_tx_write_str("OKAY");
}
static int strcmp_l1(const char *s1, const char *s2)
{
if (!s1 || !s2)
return -1;
return strncmp(s1, s2, strlen(s1));
}
static void cb_getvar(struct usb_ep *ep, struct usb_request *req)
{
char *cmd = req->buf;
char response[RESPONSE_LEN];
const char *s;
strcpy(response, "OKAY");
strsep(&cmd, ":");
if (!cmd) {
fastboot_tx_write_str("FAILmissing var");
return;
}
if (!strcmp_l1("version", cmd)) {
strncat(response, FASTBOOT_VERSION, sizeof(response));
} else if (!strcmp_l1("bootloader-version", cmd)) {
strncat(response, U_BOOT_VERSION, sizeof(response));
} else if (!strcmp_l1("downloadsize", cmd)) {
char str_num[12];
sprintf(str_num, "%08x", CONFIG_USB_FASTBOOT_BUF_SIZE);
strncat(response, str_num, sizeof(response));
} else if (!strcmp_l1("serialno", cmd)) {
s = getenv("serial#");
if (s)
strncat(response, s, sizeof(response));
else
strcpy(response, "FAILValue not set");
} else {
strcpy(response, "FAILVariable not implemented");
}
fastboot_tx_write_str(response);
}
static unsigned int rx_bytes_expected(void)
{
int rx_remain = download_size - download_bytes;
if (rx_remain < 0)
return 0;
if (rx_remain > EP_BUFFER_SIZE)
return EP_BUFFER_SIZE;
return rx_remain;
}
#define BYTES_PER_DOT 0x20000
static void rx_handler_dl_image(struct usb_ep *ep, struct usb_request *req)
{
char response[RESPONSE_LEN];
unsigned int transfer_size = download_size - download_bytes;
const unsigned char *buffer = req->buf;
unsigned int buffer_size = req->actual;
if (req->status != 0) {
printf("Bad status: %d\n", req->status);
return;
}
if (buffer_size < transfer_size)
transfer_size = buffer_size;
memcpy((void *)CONFIG_USB_FASTBOOT_BUF_ADDR + download_bytes,
buffer, transfer_size);
download_bytes += transfer_size;
/* Check if transfer is done */
if (download_bytes >= download_size) {
/*
* Reset global transfer variable, keep download_bytes because
* it will be used in the next possible flashing command
*/
download_size = 0;
req->complete = rx_handler_command;
req->length = EP_BUFFER_SIZE;
sprintf(response, "OKAY");
fastboot_tx_write_str(response);
printf("\ndownloading of %d bytes finished\n", download_bytes);
} else {
req->length = rx_bytes_expected();
if (req->length < ep->maxpacket)
req->length = ep->maxpacket;
}
if (download_bytes && !(download_bytes % BYTES_PER_DOT)) {
putc('.');
if (!(download_bytes % (74 * BYTES_PER_DOT)))
putc('\n');
}
req->actual = 0;
usb_ep_queue(ep, req, 0);
}
static void cb_download(struct usb_ep *ep, struct usb_request *req)
{
char *cmd = req->buf;
char response[RESPONSE_LEN];
strsep(&cmd, ":");
download_size = simple_strtoul(cmd, NULL, 16);
download_bytes = 0;
printf("Starting download of %d bytes\n", download_size);
if (0 == download_size) {
sprintf(response, "FAILdata invalid size");
} else if (download_size > CONFIG_USB_FASTBOOT_BUF_SIZE) {
download_size = 0;
sprintf(response, "FAILdata too large");
} else {
sprintf(response, "DATA%08x", download_size);
req->complete = rx_handler_dl_image;
req->length = rx_bytes_expected();
if (req->length < ep->maxpacket)
req->length = ep->maxpacket;
}
fastboot_tx_write_str(response);
}
static void do_bootm_on_complete(struct usb_ep *ep, struct usb_request *req)
{
char boot_addr_start[12];
char *bootm_args[] = { "bootm", boot_addr_start, NULL };
puts("Booting kernel..\n");
sprintf(boot_addr_start, "0x%lx", load_addr);
do_bootm(NULL, 0, 2, bootm_args);
/* This only happens if image is somehow faulty so we start over */
do_reset(NULL, 0, 0, NULL);
}
static void cb_boot(struct usb_ep *ep, struct usb_request *req)
{
fastboot_func->in_req->complete = do_bootm_on_complete;
fastboot_tx_write_str("OKAY");
}
struct cmd_dispatch_info {
char *cmd;
void (*cb)(struct usb_ep *ep, struct usb_request *req);
};
static const struct cmd_dispatch_info cmd_dispatch_info[] = {
{
.cmd = "reboot",
.cb = cb_reboot,
}, {
.cmd = "getvar:",
.cb = cb_getvar,
}, {
.cmd = "download:",
.cb = cb_download,
}, {
.cmd = "boot",
.cb = cb_boot,
},
};
static void rx_handler_command(struct usb_ep *ep, struct usb_request *req)
{
char *cmdbuf = req->buf;
void (*func_cb)(struct usb_ep *ep, struct usb_request *req) = NULL;
int i;
for (i = 0; i < ARRAY_SIZE(cmd_dispatch_info); i++) {
if (!strcmp_l1(cmd_dispatch_info[i].cmd, cmdbuf)) {
func_cb = cmd_dispatch_info[i].cb;
break;
}
}
if (!func_cb)
fastboot_tx_write_str("FAILunknown command");
else
func_cb(ep, req);
if (req->status == 0) {
*cmdbuf = '\0';
req->actual = 0;
usb_ep_queue(ep, req, 0);
}
}

View File

@ -311,11 +311,7 @@ static struct fsg_lun *fsg_lun_from_dev(struct device *dev)
#define DELAYED_STATUS (EP0_BUFSIZE + 999) /* An impossibly large value */
/* Number of buffers we will use. 2 is enough for double-buffering */
#ifndef CONFIG_CI_UDC
#define FSG_NUM_BUFFERS 2
#else
#define FSG_NUM_BUFFERS 1 /* ci_udc only allows 1 req per ep at present */
#endif
/* Default size of buffer length. */
#define FSG_BUFLEN ((u32)16384)

View File

@ -576,6 +576,10 @@ static void ep0_txstate(struct musb *musb)
} else
request = NULL;
/* send it out, triggering a "txpktrdy cleared" irq */
musb_ep_select(musb->mregs, 0);
musb_writew(regs, MUSB_CSR0, csr);
/* report completions as soon as the fifo's loaded; there's no
* win in waiting till this last packet gets acked. (other than
* very precise fault reporting, needed by USB TMC; possible with
@ -588,10 +592,6 @@ static void ep0_txstate(struct musb *musb)
return;
musb->ackpend = 0;
}
/* send it out, triggering a "txpktrdy cleared" irq */
musb_ep_select(musb->mregs, 0);
musb_writew(regs, MUSB_CSR0, csr);
}
/*

69
include/android_image.h Normal file
View File

@ -0,0 +1,69 @@
/*
* This is from the Android Project,
* Repository: https://android.googlesource.com/platform/bootable/bootloader/legacy
* File: include/boot/bootimg.h
* Commit: 4205b865141ff2e255fe1d3bd16de18e217ef06a
*
* Copyright (C) 2008 The Android Open Source Project
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#ifndef _ANDROID_IMAGE_H_
#define _ANDROID_IMAGE_H_
#define ANDR_BOOT_MAGIC "ANDROID!"
#define ANDR_BOOT_MAGIC_SIZE 8
#define ANDR_BOOT_NAME_SIZE 16
#define ANDR_BOOT_ARGS_SIZE 512
struct andr_img_hdr {
char magic[ANDR_BOOT_MAGIC_SIZE];
u32 kernel_size; /* size in bytes */
u32 kernel_addr; /* physical load addr */
u32 ramdisk_size; /* size in bytes */
u32 ramdisk_addr; /* physical load addr */
u32 second_size; /* size in bytes */
u32 second_addr; /* physical load addr */
u32 tags_addr; /* physical addr for kernel tags */
u32 page_size; /* flash page size we assume */
u32 unused[2]; /* future expansion: should be 0 */
char name[ANDR_BOOT_NAME_SIZE]; /* asciiz product name */
char cmdline[ANDR_BOOT_ARGS_SIZE];
u32 id[8]; /* timestamp / checksum / sha1 / etc */
};
/*
* +-----------------+
* | boot header | 1 page
* +-----------------+
* | kernel | n pages
* +-----------------+
* | ramdisk | m pages
* +-----------------+
* | second stage | o pages
* +-----------------+
*
* n = (kernel_size + page_size - 1) / page_size
* m = (ramdisk_size + page_size - 1) / page_size
* o = (second_size + page_size - 1) / page_size
*
* 0. all entities are page_size aligned in flash
* 1. kernel and ramdisk are required (size != 0)
* 2. second is optional (second_size == 0 -> no second)
* 3. load each element (kernel, ramdisk, second) at
* the specified physical address (kernel_addr, etc)
* 4. prepare tags at tag_addr. kernel_args[] is
* appended to the kernel commandline in the tags.
* 5. r0 = 0, r1 = MACHINE_TYPE, r2 = tags_addr
* 6. if second_size != 0: jump to second_addr
* else: jump to kernel_addr
*/
#endif

View File

@ -66,6 +66,16 @@
#define CONFIG_TWL4030_USB 1
#define CONFIG_USB_ETHER
#define CONFIG_USB_ETHER_RNDIS
#define CONFIG_USB_GADGET
#define CONFIG_USB_GADGET_VBUS_DRAW 0
#define CONFIG_USBDOWNLOAD_GADGET
#define CONFIG_G_DNL_VENDOR_NUM 0x0451
#define CONFIG_G_DNL_PRODUCT_NUM 0xd022
#define CONFIG_G_DNL_MANUFACTURER "TI"
#define CONFIG_CMD_FASTBOOT
#define CONFIG_ANDROID_BOOT_IMAGE
#define CONFIG_USB_FASTBOOT_BUF_ADDR CONFIG_SYS_LOAD_ADDR
#define CONFIG_USB_FASTBOOT_BUF_SIZE 0x07000000
/* USB EHCI */
#define CONFIG_CMD_USB

View File

@ -100,6 +100,7 @@ struct dfu_entity {
u64 offset, void *buf, long *len);
int (*flush_medium)(struct dfu_entity *dfu);
unsigned int (*poll_timeout)(struct dfu_entity *dfu);
struct list_head list;

View File

@ -413,6 +413,7 @@ enum fit_load_op {
#define IMAGE_FORMAT_INVALID 0x00
#define IMAGE_FORMAT_LEGACY 0x01 /* legacy image_header based format */
#define IMAGE_FORMAT_FIT 0x02 /* new, libfdt based format */
#define IMAGE_FORMAT_ANDROID 0x03 /* Android boot image */
int genimg_get_format(const void *img_addr);
int genimg_has_config(bootm_headers_t *images);
@ -1031,4 +1032,16 @@ static inline int fit_image_check_target_arch(const void *fdt, int node)
#endif /* CONFIG_FIT_VERBOSE */
#endif /* CONFIG_FIT */
#if defined(CONFIG_ANDROID_BOOT_IMAGE)
struct andr_img_hdr;
int android_image_check_header(const struct andr_img_hdr *hdr);
int android_image_get_kernel(const struct andr_img_hdr *hdr, int verify,
ulong *os_data, ulong *os_len);
int android_image_get_ramdisk(const struct andr_img_hdr *hdr,
ulong *rd_data, ulong *rd_len);
ulong android_image_get_end(const struct andr_img_hdr *hdr);
ulong android_image_get_kload(const struct andr_img_hdr *hdr);
#endif /* CONFIG_ANDROID_BOOT_IMAGE */
#endif /* __IMAGE_H__ */

View File

@ -9,17 +9,9 @@
#define __USB_MASS_STORAGE_H__
#define SECTOR_SIZE 0x200
#include <mmc.h>
#include <part.h>
#include <linux/usb/composite.h>
#ifndef UMS_START_SECTOR
#define UMS_START_SECTOR 0
#endif
#ifndef UMS_NUM_SECTORS
#define UMS_NUM_SECTORS 0
#endif
/* Wait at maximum 60 seconds for cable connection */
#define UMS_CABLE_READY_TIMEOUT 60
@ -31,14 +23,13 @@ struct ums {
unsigned int start_sector;
unsigned int num_sectors;
const char *name;
struct mmc *mmc;
block_dev_desc_t *block_dev;
};
extern struct ums *ums;
int fsg_init(struct ums *);
void fsg_cleanup(void);
struct ums *ums_init(unsigned int);
int fsg_main_thread(void *);
int fsg_add(struct usb_configuration *c);
#endif /* __USB_MASS_STORAGE_H__ */