summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Rigby <john.rigby@linaro.org>2011-11-14 22:36:21 -0700
committerJohn Rigby <john.rigby@linaro.org>2011-11-14 22:36:21 -0700
commit27d77171a1b9f0caa60bd8aa310381bacaadf054 (patch)
tree7719217514886b1cd17882e616f79bbda1bee80f
Initial commitv0.1
Signed-off-by: John Rigby <john.rigby@linaro.org>
-rw-r--r--.gitignore2
-rw-r--r--Makefile26
-rw-r--r--usb.h66
-rw-r--r--usb_linux.c370
-rw-r--r--usbboot.c228
5 files changed, 692 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..14e5d15
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+local.mk
+out
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..86ea1cd
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,26 @@
+CFLAGS = -g -O2 -Wall
+
+prog = usbboot
+
+all: $(prog)
+
+install: all
+ install -d $(DESTDIR)/usr/bin
+ install $(prog) $(DESTDIR)/usr/bin
+
+%.o: %.c
+ $(CC) $(CFLAGS) -c $< -o $@ -MD -MT $@ -MF $(@:%o=%d)
+
+objs = usbboot.o usb_linux.o
+
+
+$(prog): $(objs)
+ $(CC) $(CFLAGS) -o $@ $(objs)
+
+clean:
+ rm -rf $(prog) $(objs) $(deps)
+
+deps = $(objs:%o=%d)
+
+-include $(deps)
+
diff --git a/usb.h b/usb.h
new file mode 100644
index 0000000..cc157d5
--- /dev/null
+++ b/usb.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _USB_H_
+#define _USB_H_
+
+typedef struct usb_handle usb_handle;
+
+typedef struct usb_ifc_info usb_ifc_info;
+
+struct usb_ifc_info
+{
+ /* from device descriptor */
+ unsigned short dev_vendor;
+ unsigned short dev_product;
+
+ unsigned char dev_class;
+ unsigned char dev_subclass;
+ unsigned char dev_protocol;
+
+ unsigned char ifc_class;
+ unsigned char ifc_subclass;
+ unsigned char ifc_protocol;
+
+ unsigned char has_bulk_in;
+ unsigned char has_bulk_out;
+
+ unsigned char writable;
+
+ char serial_number[256];
+};
+
+typedef int (*ifc_match_func)(usb_ifc_info *ifc);
+
+usb_handle *usb_open(ifc_match_func callback);
+int usb_close(usb_handle *h);
+int usb_read(usb_handle *h, void *_data, int len);
+int usb_write(usb_handle *h, const void *_data, int len);
+
+
+#endif
diff --git a/usb_linux.c b/usb_linux.c
new file mode 100644
index 0000000..aba9552
--- /dev/null
+++ b/usb_linux.c
@@ -0,0 +1,370 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <pthread.h>
+#include <ctype.h>
+
+#include <linux/usbdevice_fs.h>
+#include <linux/version.h>
+#include <linux/usb/ch9.h>
+#include <asm/byteorder.h>
+
+#include "usb.h"
+
+#define MAX_RETRIES 5
+
+/*#define TRACE_USB*/
+#ifdef TRACE_USB
+#define DBG(x...) fprintf(stderr, x)
+#else
+#define DBG(x...)
+#endif
+
+struct usb_handle {
+ char fname[64];
+ int desc;
+ unsigned char ep_in;
+ unsigned char ep_out;
+};
+
+static inline int badname(const char *name)
+{
+ while (*name) {
+ if (!isdigit(*name++))
+ return 1;
+ }
+ return 0;
+}
+
+static int check(void *_desc, int len, unsigned type, int size)
+{
+ unsigned char *desc = _desc;
+
+ if (len < size)
+ return -1;
+ if (desc[0] < size)
+ return -1;
+ if (desc[0] > len)
+ return -1;
+ if (desc[1] != type)
+ return -1;
+
+ return 0;
+}
+
+static int filter_usb_device(int fd, char *ptr, int len, int writable,
+ ifc_match_func callback,
+ int *ept_in_id, int *ept_out_id, int *ifc_id)
+{
+ struct usb_device_descriptor *dev;
+ struct usb_config_descriptor *cfg;
+ struct usb_interface_descriptor *ifc;
+ struct usb_endpoint_descriptor *ept;
+ struct usb_ifc_info info;
+
+ int in, out;
+ unsigned i;
+ unsigned e;
+
+ if (check(ptr, len, USB_DT_DEVICE, USB_DT_DEVICE_SIZE))
+ return -1;
+ dev = (void *)ptr;
+ len -= dev->bLength;
+ ptr += dev->bLength;
+
+ if (check(ptr, len, USB_DT_CONFIG, USB_DT_CONFIG_SIZE))
+ return -1;
+ cfg = (void *)ptr;
+ len -= cfg->bLength;
+ ptr += cfg->bLength;
+
+ info.dev_vendor = dev->idVendor;
+ info.dev_product = dev->idProduct;
+ info.dev_class = dev->bDeviceClass;
+ info.dev_subclass = dev->bDeviceSubClass;
+ info.dev_protocol = dev->bDeviceProtocol;
+ info.writable = writable;
+
+ for (i = 0; i < cfg->bNumInterfaces; i++) {
+ if (check(ptr, len, USB_DT_INTERFACE, USB_DT_INTERFACE_SIZE))
+ return -1;
+ ifc = (void *)ptr;
+ len -= ifc->bLength;
+ ptr += ifc->bLength;
+
+ in = -1;
+ out = -1;
+ info.ifc_class = ifc->bInterfaceClass;
+ info.ifc_subclass = ifc->bInterfaceSubClass;
+ info.ifc_protocol = ifc->bInterfaceProtocol;
+
+ for (e = 0; e < ifc->bNumEndpoints; e++) {
+ if (check
+ (ptr, len, USB_DT_ENDPOINT, USB_DT_ENDPOINT_SIZE))
+ return -1;
+ ept = (void *)ptr;
+ len -= ept->bLength;
+ ptr += ept->bLength;
+
+ if ((ept->bmAttributes & 0x03) != 0x02)
+ continue;
+
+ if (ept->bEndpointAddress & 0x80) {
+ in = ept->bEndpointAddress;
+ } else {
+ out = ept->bEndpointAddress;
+ }
+ }
+
+ info.has_bulk_in = (in != -1);
+ info.has_bulk_out = (out != -1);
+
+ if (callback(&info) == 0) {
+ *ept_in_id = in;
+ *ept_out_id = out;
+ *ifc_id = ifc->bInterfaceNumber;
+ return 0;
+ }
+ }
+
+ return -1;
+}
+
+static void scanning(char *str)
+{
+#ifdef TRACE_USB
+ DBG("scanning %s\n", str);
+#else
+ fprintf(stdout, "scanning %24s\r", str);
+#endif
+}
+
+static usb_handle *find_usb_device(const char *base, ifc_match_func callback)
+{
+ usb_handle *usb = 0;
+ char busname[64], devname[64];
+ char desc[1024];
+ int n, in, out, ifc;
+
+ DIR *busdir, *devdir;
+ struct dirent *de;
+ int fd;
+ int writable;
+
+ busdir = opendir(base);
+ if (busdir == 0)
+ return 0;
+
+ while ((de = readdir(busdir)) && (usb == 0)) {
+ if (badname(de->d_name))
+ continue;
+
+ sprintf(busname, "%s/%s", base, de->d_name);
+ devdir = opendir(busname);
+ if (devdir == 0)
+ continue;
+
+ scanning(busname);
+ while ((de = readdir(devdir)) && (usb == 0)) {
+
+ if (badname(de->d_name))
+ continue;
+ sprintf(devname, "%s/%s", busname, de->d_name);
+
+ scanning(devname);
+ writable = 1;
+ if ((fd = open(devname, O_RDWR)) < 0) {
+ /*
+ * TODO: Check if we have read-only access, so we
+ * can give a helpful diagnostic like "adb devices" does.
+ */
+ writable = 0;
+ if ((fd = open(devname, O_RDONLY)) < 0) {
+ continue;
+ }
+ }
+
+ n = read(fd, desc, sizeof(desc));
+
+ if (filter_usb_device(fd, desc, n, writable, callback,
+ &in, &out, &ifc) == 0) {
+ usb = calloc(1, sizeof(usb_handle));
+ strcpy(usb->fname, devname);
+ usb->ep_in = in;
+ usb->ep_out = out;
+ usb->desc = fd;
+
+ n = ioctl(fd, USBDEVFS_CLAIMINTERFACE, &ifc);
+ if (n != 0) {
+ close(fd);
+ free(usb);
+ usb = 0;
+ continue;
+ }
+ } else {
+ close(fd);
+ }
+ }
+ closedir(devdir);
+ }
+ closedir(busdir);
+#ifndef TRACE_USB
+ if (usb)
+ fprintf(stdout, "\n");
+#endif
+
+ return usb;
+}
+
+int usb_write(usb_handle * h, const void *_data, int len)
+{
+ unsigned char *data = (unsigned char *)_data;
+ unsigned count = 0;
+ struct usbdevfs_bulktransfer bulk;
+ int n;
+
+ if (h->ep_out == 0) {
+ return -1;
+ }
+
+ if (len == 0) {
+ bulk.ep = h->ep_out;
+ bulk.len = 0;
+ bulk.data = data;
+ bulk.timeout = 0;
+
+ n = ioctl(h->desc, USBDEVFS_BULK, &bulk);
+ if (n != 0) {
+ fprintf(stderr, "ERROR: n = %d, errno = %d (%s)\n",
+ n, errno, strerror(errno));
+ return -1;
+ }
+ return 0;
+ }
+
+ while (len > 0) {
+ int xfer;
+ xfer = (len > 4096) ? 4096 : len;
+
+ bulk.ep = h->ep_out;
+ bulk.len = xfer;
+ bulk.data = data;
+ bulk.timeout = 0;
+
+ n = ioctl(h->desc, USBDEVFS_BULK, &bulk);
+ if (n != xfer) {
+ DBG("ERROR: n = %d, errno = %d (%s)\n",
+ n, errno, strerror(errno));
+ return -1;
+ }
+
+ count += xfer;
+ len -= xfer;
+ data += xfer;
+ }
+
+ return count;
+}
+
+int usb_read(usb_handle * h, void *_data, int len)
+{
+ unsigned char *data = (unsigned char *)_data;
+ unsigned count = 0;
+ struct usbdevfs_bulktransfer bulk;
+ int n, retry;
+
+ if (h->ep_in == 0) {
+ return -1;
+ }
+
+ while (len > 0) {
+ int xfer = (len > 4096) ? 4096 : len;
+
+ bulk.ep = h->ep_in;
+ bulk.len = xfer;
+ bulk.data = data;
+ bulk.timeout = 0;
+ retry = 0;
+
+ do {
+ DBG("[ usb read %d fd = %d], fname=%s\n", xfer, h->desc,
+ h->fname);
+ n = ioctl(h->desc, USBDEVFS_BULK, &bulk);
+ DBG("[ usb read %d ] = %d, fname=%s, Retry %d \n", xfer,
+ n, h->fname, retry);
+
+ if (n < 0) {
+ DBG("ERROR: n = %d, errno = %d (%s)\n", n,
+ errno, strerror(errno));
+ if (++retry > MAX_RETRIES)
+ return -1;
+ sleep(1);
+ }
+ }
+ while (n < 0);
+
+ count += n;
+ len -= n;
+ data += n;
+
+ if (n < xfer) {
+ break;
+ }
+ }
+
+ return count;
+}
+
+int usb_close(usb_handle * h)
+{
+ int fd;
+
+ fd = h->desc;
+ h->desc = -1;
+ if (fd >= 0) {
+ close(fd);
+ DBG("[ usb closed %d ]\n", fd);
+ }
+
+ return 0;
+}
+
+usb_handle *usb_open(ifc_match_func callback)
+{
+ return find_usb_device("/dev/bus/usb", callback);
+}
diff --git a/usbboot.c b/usbboot.c
new file mode 100644
index 0000000..bafcccf
--- /dev/null
+++ b/usbboot.c
@@ -0,0 +1,228 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <stdint.h>
+#include <fcntl.h>
+#include <string.h>
+
+#include "usb.h"
+
+int usb_boot(usb_handle * usb,
+ void *data1, unsigned sz1, void *data2, unsigned sz2)
+{
+ if (data1) {
+ uint32_t msg_boot = 0xF0030002;
+ uint32_t msg_getid = 0xF0030003;
+ uint32_t msg_size = sz1;
+ uint8_t id[81];
+ int i;
+
+#define OFF_CHIP 0x04
+#define OFF_ID 0x0F
+#define OFF_MPKH 0x26
+ memset(id, 0xee, 81);
+ fprintf(stderr, "reading ASIC ID\n");
+ usb_write(usb, &msg_getid, sizeof(msg_getid));
+ usb_read(usb, id, sizeof(id));
+
+ fprintf(stderr, "CHIP: %02x%02x\n", id[OFF_CHIP + 0],
+ id[OFF_CHIP + 1]);
+ fprintf(stderr, "IDEN: ");
+ for (i = 0; i < 20; i++)
+ fprintf(stderr, "%02x", id[OFF_ID + i]);
+ fprintf(stderr, "\nMPKH: ");
+ for (i = 0; i < 32; i++)
+ fprintf(stderr, "%02x", id[OFF_MPKH + i]);
+ fprintf(stderr, "\nCRC0: %02x%02x%02x%02x\n",
+ id[73], id[74], id[75], id[76]);
+ fprintf(stderr, "CRC1: %02x%02x%02x%02x\n",
+ id[77], id[78], id[79], id[80]);
+
+ fprintf(stderr, "sending u-boot-spl to target... %08x\n",
+ msg_boot);
+ sleep(1);
+ usb_write(usb, &msg_boot, sizeof(msg_boot));
+ sleep(1);
+ usb_write(usb, &msg_size, sizeof(msg_size));
+ sleep(1);
+ usb_write(usb, data1, sz1);
+ }
+
+ if (data2) {
+ char command[64];
+ char response[64];
+ long rsz;
+
+ sleep(1);
+ fprintf(stderr, "sending download command to u-boot-spl\n");
+ sprintf(command, "download:%08x", sz2);
+ usb_write(usb, command, sizeof(command));
+ fprintf(stderr, "waiting for \"DATA\" response to download: command\n");
+ usb_read(usb, response, sizeof(response));
+ if (strncmp("DATA", response, 4)) {
+ fprintf(stderr, "unexpected response\"%s\"\n", response);
+ return -1;
+ }
+ rsz = strtol(response + 4, 0, 16);
+ if (rsz != sz2) {
+ fprintf(stderr, "bad returned size\"%s\"\n", response);
+ return -1;
+ }
+ sleep(1);
+ fprintf(stderr, "transferring %d bytes of data\n", sz2);
+ usb_write(usb, data2, sz2);
+ fprintf(stderr, "write finished, waiting for \"OKAY\"\n");
+ usb_read(usb, response, sizeof(response));
+ if (strncmp("OKAY", response, 4) == 0) {
+ fprintf(stderr, "data transfer successful\n");
+ } else {
+ fprintf(stderr, "unexpected response to data xfer\"%s\"\n", response);
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+int match_omap4_bootloader(usb_ifc_info * ifc)
+{
+ if (ifc->dev_vendor != 0x0451)
+ return -1;
+ if ((ifc->dev_product != 0xd010) && (ifc->dev_product != 0xd00f))
+ return -1;
+ return 0;
+}
+
+/*
+ * same as above for now
+ */
+int match_u_boot_spl(usb_ifc_info * ifc)
+{
+ if (ifc->dev_vendor != 0x0525)
+ return -1;
+ if (ifc->dev_product != 0xFFFF)
+ return -1;
+ return 0;
+}
+
+void *load_file(const char *file, unsigned *sz)
+{
+ void *data;
+ struct stat s;
+ int fd;
+
+ fd = open(file, O_RDONLY);
+ if (fd < 0)
+ return 0;
+
+ if (fstat(fd, &s))
+ goto fail;
+
+ data = malloc(s.st_size);
+ if (!data)
+ goto fail;
+
+ if (read(fd, data, s.st_size) != s.st_size) {
+ free(data);
+ goto fail;
+ }
+
+ close(fd);
+ *sz = s.st_size;
+ return data;
+
+fail:
+ close(fd);
+ return 0;
+}
+
+extern unsigned char aboot_data[];
+extern unsigned aboot_size;
+
+int main(int argc, char **argv)
+{
+ void *data[2];
+ unsigned sz[2];
+ usb_handle *usb;
+ int i;
+ int once = 1;
+
+ if (argc < 3) {
+ fprintf(stderr, "usage: usbboot u-boot-spl.bin u-boot.bin\n");
+ return 0;
+ }
+
+ for (i = 0; i < 2; i++) {
+ data[i] = load_file(argv[i + 1], sz + i);
+ if (data[i] == 0) {
+ fprintf(stderr, "cannot load '%s'\n", argv[i + 1]);
+ return -1;
+ }
+ }
+
+ /*
+ * First talk to the omap4 mask rom boot loader
+ */
+ for (;;) {
+ usb = usb_open(match_omap4_bootloader);
+ if (usb) {
+ usb_boot(usb, data[0], sz[0], 0, 0);
+ break;
+ }
+ if (once) {
+ once = 0;
+ fprintf(stderr, "waiting for OMAP44xx device...\n");
+ }
+ usleep(2500);
+ }
+ usb_close(usb);
+
+ /*
+ * Second talk to u-boot-spl usb boot loader
+ * this is a new connection since there is no
+ * hand off between the mask rom usb code and
+ * u-boot-spl
+ */
+ once = 1;
+ for (;;) {
+ usb = usb_open(match_u_boot_spl);
+ if (usb)
+ return usb_boot(usb, 0, 0, data[1], sz[1]);
+ if (once) {
+ once = 0;
+ fprintf(stderr, "waiting for U-Boot-spl bootloader...\n");
+ }
+ usleep(2500);
+ }
+
+ return -1;
+}