r1097 - trunk/src/target/u-boot/patches
laforge at sita.openmoko.org
laforge at sita.openmoko.org
Sat Feb 24 14:03:42 CET 2007
Author: laforge
Date: 2007-02-24 14:03:41 +0100 (Sat, 24 Feb 2007)
New Revision: 1097
Modified:
trunk/src/target/u-boot/patches/uboot-dfu.patch
Log:
* bring DFU code to a state where it reliably supports UPLOAd from all partitions and download into RAM
Modified: trunk/src/target/u-boot/patches/uboot-dfu.patch
===================================================================
--- trunk/src/target/u-boot/patches/uboot-dfu.patch 2007-02-24 13:02:27 UTC (rev 1096)
+++ trunk/src/target/u-boot/patches/uboot-dfu.patch 2007-02-24 13:03:41 UTC (rev 1097)
@@ -1,14 +1,87 @@
Index: u-boot/drivers/usbdcore_ep0.c
===================================================================
---- u-boot.orig/drivers/usbdcore_ep0.c 2007-02-15 18:07:52.000000000 +0100
-+++ u-boot/drivers/usbdcore_ep0.c 2007-02-15 20:50:05.000000000 +0100
-@@ -388,6 +388,11 @@
+--- u-boot.orig/drivers/usbdcore_ep0.c 2007-02-24 03:59:30.000000000 +0100
++++ u-boot/drivers/usbdcore_ep0.c 2007-02-24 04:03:05.000000000 +0100
+@@ -42,11 +42,16 @@
+ */
+
+ #include <common.h>
++DECLARE_GLOBAL_DATA_PTR;
+
+ #if defined(CONFIG_USB_DEVICE)
+ #include "usbdcore.h"
+
+-#if 0
++#ifdef CONFIG_USBD_DFU
++#include <usb_dfu.h>
++#endif
++
++#if 1
+ #define dbg_ep0(lvl,fmt,args...) serial_printf("[%s] %s:%d: "fmt"\n",__FILE__,__FUNCTION__,__LINE__,##args)
+ #else
+ #define dbg_ep0(lvl,fmt,args...)
+@@ -213,7 +218,7 @@
+ urb->buffer = device_descriptor;
+ urb->actual_length = MIN(sizeof(*device_descriptor), max);
+ }
+- /*dbg_ep0(3, "copied device configuration, actual_length: %x", urb->actual_length); */
++ dbg_ep0(3, "using device configuration, actual_length: %x", urb->actual_length);
+ break;
+
+ case USB_DESCRIPTOR_TYPE_CONFIGURATION:
+@@ -267,7 +272,24 @@
+ return -1;
+ case USB_DESCRIPTOR_TYPE_ENDPOINT:
+ return -1;
++ /* This really means "Class Specific Descriptor #1 == USB_DT_DFU */
+ case USB_DESCRIPTOR_TYPE_HID:
++#ifdef CONFIG_USBD_DFU
++ {
++ int bNumInterface =
++ le16_to_cpu(urb->device_request.wIndex);
++
++ /* In runtime mode, we only respond to the DFU INTERFACE,
++ * whereas in DFU mode, we respond for all intrfaces */
++ if (device->dfu_state != DFU_STATE_appIDLE &&
++ device->dfu_state != DFU_STATE_appDETACH ||
++ bNumInterface == CONFIG_USBD_DFU_INTERFACE) {
++ urb->buffer = &device->dfu_cfg_desc->func_dfu;
++ urb->actual_length = sizeof(struct usb_dfu_func_descriptor);
++ } else
++ return -1;
++ }
++#else /* CONFIG_USBD_DFU */
+ {
+ return -1; /* unsupported at this time */
+ #if 0
+@@ -294,6 +316,7 @@
+ max);
+ #endif
+ }
++#endif /* CONFIG_USBD_DFU */
+ break;
+ case USB_DESCRIPTOR_TYPE_REPORT:
+ {
+@@ -388,6 +411,24 @@
le16_to_cpu (request->wLength),
USBD_DEVICE_REQUESTS (request->bRequest));
-+#ifdef CONFIG_USB_DFU
-+ if ((request->bmRequestType & 0x3f) == USB_TYPE_DFU)
-+ return dfu_ep0_handler(urb);
++#ifdef CONFIG_USBD_DFU
++ if ((request->bmRequestType & 0x3f) == USB_TYPE_DFU &&
++ (device->dfu_state != DFU_STATE_appIDLE ||
++ le16_to_cpu(request->wIndex) == CONFIG_USBD_DFU_INTERFACE)) {
++ int rc = dfu_ep0_handler(urb);
++ switch (rc) {
++ case DFU_EP0_NONE:
++ case DFU_EP0_UNHANDLED:
++ break;
++ case DFU_EP0_ZLP:
++ case DFU_EP0_DATA:
++ return 0;
++ case DFU_EP0_STALL:
++ return -1;
++ }
++ }
+#endif /* CONFIG_USB_DFU */
+
/* handle USB Standard Request (c.f. USB Spec table 9-2) */
@@ -17,14 +90,13 @@
Index: u-boot/drivers/usbdfu.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
-+++ u-boot/drivers/usbdfu.c 2007-02-16 18:59:54.000000000 +0100
-@@ -0,0 +1,352 @@
++++ u-boot/drivers/usbdfu.c 2007-02-24 04:03:05.000000000 +0100
+@@ -0,0 +1,553 @@
+/*
+ * (C) 2007 by OpenMoko, Inc.
+ * Author: Harald Welte <laforge at openmoko.org>
+ *
+ * based on existing SAM7DFU code from OpenPCD:
-+ *
+ * (C) Copyright 2006 by Harald Welte <hwelte at hmw-consulting.de>
+ *
+ * See file CREDITS for list of people who contributed to this
@@ -45,141 +117,326 @@
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
-+static u_int32_t dfu_state = DFU_STATE_appIDLE;
+
-+static int handle_dnload(u_int16_t val, u_int16_t len)
++#include <config.h>
++#if defined(CONFIG_USBD_DFU)
++
++//#define DEBUG
++
++#include <common.h>
++DECLARE_GLOBAL_DATA_PTR;
++
++#include <linux/types.h>
++#include <asm/errno.h>
++#include <usbdcore.h>
++#include <usb_dfu.h>
++#include <usb_dfu_descriptors.h>
++
++#include "usbdcore_s3c2410.h"
++
++#define RET_NOTHING 0
++#define RET_ZLP 1
++#define RET_STALL 2
++
++#define LOAD_ADDR 0x32000000
++
++static char *ptr;
++
++static int handle_dnload(struct urb *urb, u_int16_t val, u_int16_t len, int first)
+{
-+ volatile u_int32_t *p = (volatile u_int32_t *)ptr;
-+ u_int8_t *pagebuf = (u_int8_t *) pagebuf32;
++ struct usb_device_instance *dev = urb->device;
++ debug("download ");
++
+ int i;
+
-+ DEBUGE("download ");
-+
-+ if (len > AT91C_IFLASH_PAGE_SIZE) {
++ if (len > CONFIG_USBD_DFU_XFER_SIZE) {
+ /* Too big. Not that we'd really care, but it's a
+ * DFU protocol violation */
-+ DEBUGP("length exceeds flash page size ");
-+ dfu_state = DFU_STATE_dfuERROR;
-+ dfu_status = DFU_STATUS_errADDRESS;
++ debug("length exceeds flash page size ");
++ dev->dfu_state = DFU_STATE_dfuERROR;
++ dev->dfu_status = DFU_STATUS_errADDRESS;
+ return RET_STALL;
+ }
++#if 0
+ if (len & 0x3) {
+ /* reject non-four-byte-aligned writes */
-+ DEBUGP("not four-byte-aligned length ");
-+ dfu_state = DFU_STATE_dfuERROR;
-+ dfu_status = DFU_STATUS_errADDRESS;
++ debug("not four-byte-aligned length ");
++ dev->dfu_state = DFU_STATE_dfuERROR;
++ dev->dfu_status = DFU_STATUS_errADDRESS;
+ return RET_STALL;
+ }
++#endif
+ if (len == 0) {
-+ DEBUGP("zero-size write -> MANIFEST_SYNC ");
-+ flash_page(p);
-+ dfu_state = DFU_STATE_dfuMANIFEST_SYNC;
++ debug("zero-size write -> MANIFEST_SYNC ");
++ //flash_page(p);
++ dev->dfu_state = DFU_STATE_dfuMANIFEST_SYNC;
+ return RET_ZLP;
+ }
-+ if (ptr + len > (u_int8_t *) AT91C_IFLASH + AT91C_IFLASH_SIZE) {
-+ DEBUGP("end of write exceeds flash end ");
-+ dfu_state = DFU_STATE_dfuERROR;
-+ dfu_status = DFU_STATUS_errADDRESS;
++ if (ptr + len > LOAD_ADDR + 0x200000) {
++ debug("end of write exceeds flash end ");
++ dev->dfu_state = DFU_STATE_dfuERROR;
++ dev->dfu_status = DFU_STATUS_errADDRESS;
+ return RET_STALL;
+ }
+
-+ DEBUGP("try_to_recv=%u ", len);
-+ udp_ep0_recv_data(pagebuf, len);
++ if (urb->actual_length != len) {
++ debug("urb->actual_length(%u) != len(%u) ?!?\n",
++ urb->actual_length, len);
++ return RET_STALL;
++ }
+
-+ DEBUGR(hexdump(pagebuf, len));
++ /* actually write the data somewhere */
++ switch (dev->alternate) {
++ case 0:
++ if (first)
++ ptr = LOAD_ADDR;
++ memcpy(ptr, urb->buffer, len);
++ ptr += len;
++ break;
++ default:
++ debug("[yet] unsupported altsetting %u\n", dev->alternate);
++ break;
++ }
+
-+ /* FXIME: actually write the data somewhere */
-+
+ return RET_ZLP;
+}
+
-+#define AT91C_IFLASH_END ((u_int8_t *)AT91C_IFLASH + AT91C_IFLASH_SIZE)
-+static dfufunc int handle_upload(u_int16_t val, u_int16_t len)
++static int handle_upload(struct urb *urb, u_int16_t val, u_int16_t len, int first)
+{
-+ DEBUGE("upload ");
-+ if (len > AT91C_IFLASH_PAGE_SIZE) {
++ struct usb_device_instance *dev = urb->device;
++ debug("upload(val=0x%02x, len=%u, first=%u) ", val, len, first);
++
++ if (len > CONFIG_USBD_DFU_XFER_SIZE) {
+ /* Too big */
-+ dfu_state = DFU_STATE_dfuERROR;
-+ dfu_status = DFU_STATUS_errADDRESS;
-+ udp_ep0_send_stall();
++ dev->dfu_state = DFU_STATE_dfuERROR;
++ dev->dfu_status = DFU_STATUS_errADDRESS;
++ //udc_ep0_send_stall();
++ debug("Error: Transfer size > CONFIG_USBD_DFU_XFER_SIZE\n");
+ return -EINVAL;
+ }
+
-+ if (ptr + len > AT91C_IFLASH_END)
-+ len = AT91C_IFLASH_END - (u_int8_t *)ptr;
++ if (first) {
++ ptr = LOAD_ADDR;
++ /* the first of many upload requests */
++ switch (dev->alternate) {
++ case 0:
++ /* upload RAM contents ?!? */
++ break;
++ case 1:
++ /* u-boot */
++ run_command("nand read.e 0x32000000 u-boot", 0);
++ break;
++ case 2:
++ run_command("nand read.e 0x32000000 u-boot_env", 0);
++ break;
++ case 3:
++ run_command("nand read.e 0x32000000 splash", 0);
++ break;
++ case 4:
++ run_command("nand read.e 0x32000000 kernel", 0);
++ break;
++ default:
++ return -EINVAL;
++ }
++ }
+
-+ udp_ep0_send_data((char *)ptr, len);
++
++ if (ptr + len > LOAD_ADDR + 0x200000)
++ len = (char *)(LOAD_ADDR + 0x200000) - ptr;
++
++ urb->buffer = ptr;
++ urb->actual_length = len;
+ ptr+= len;
+
++ printf("returning len=%u\n", len);
+ return len;
+}
+
-+static void handle_getstatus(void)
++static void handle_getstatus(struct urb *urb, int max)
+{
-+ struct dfu_status dstat;
-+ u_int32_t fsr = AT91F_MC_EFC_GetStatus(AT91C_BASE_MC);
++ struct usb_device_instance *dev = urb->device;
++ struct dfu_status *dstat = urb->buffer;
++ u_int32_t fsr = 0;//AT91F_MC_EFC_GetStatus(AT91C_BASE_MC);
+
-+ DEBUGE("getstatus(fsr=0x%08x) ", fsr);
++ debug("getstatus(fsr=0x%08x) ", fsr);
+
-+ switch (dfu_state) {
++ if (!urb->buffer || urb->buffer_length < sizeof(*dstat)) {
++ debug("invalid urb! ");
++ return;
++ }
++
++ switch (dev->dfu_state) {
+ case DFU_STATE_dfuDNLOAD_SYNC:
+ case DFU_STATE_dfuDNBUSY:
++#if 0
+ if (fsr & AT91C_MC_PROGE) {
-+ DEBUGE("errPROG ");
-+ dfu_status = DFU_STATUS_errPROG;
-+ dfu_state = DFU_STATE_dfuERROR;
++ debug("errPROG ");
++ dev->dfu_status = DFU_STATUS_errPROG;
++ dev->dfu_state = DFU_STATE_dfuERROR;
+ } else if (fsr & AT91C_MC_LOCKE) {
-+ DEBUGE("errWRITE ");
-+ dfu_status = DFU_STATUS_errWRITE;
-+ dfu_state = DFU_STATE_dfuERROR;
++ debug("errWRITE ");
++ dev->dfu_status = DFU_STATUS_errWRITE;
++ dev->dfu_state = DFU_STATE_dfuERROR;
+ } else if (fsr & AT91C_MC_FRDY) {
-+ DEBUGE("DNLOAD_IDLE ");
-+ dfu_state = DFU_STATE_dfuDNLOAD_IDLE;
++#endif
++ debug("DNLOAD_IDLE ");
++ dev->dfu_state = DFU_STATE_dfuDNLOAD_IDLE;
++#if 0
+ } else {
-+ DEBUGE("DNBUSY ");
-+ dfu_state = DFU_STATE_dfuDNBUSY;
++ debug("DNBUSY ");
++ dev->dfu_state = DFU_STATE_dfuDNBUSY;
+ }
++#endif
+ break;
+ case DFU_STATE_dfuMANIFEST_SYNC:
-+ dfu_state = DFU_STATE_dfuMANIFEST;
++ dev->dfu_state = DFU_STATE_dfuMANIFEST;
+ break;
++ default:
++ //return;
++ break;
+ }
+
+ /* send status response */
-+ dstat.bStatus = dfu_status;
-+ dstat.bState = dfu_state;
-+ dstat.iString = 0;
-+ /* FIXME: set dstat.bwPollTimeout */
++ dstat->bStatus = dev->dfu_status;
++ dstat->bState = dev->dfu_state;
++ dstat->iString = 0;
++ /* FIXME: set dstat->bwPollTimeout */
++ urb->actual_length = MIN(sizeof(*dstat), max);
+
-+ udp_ep0_send_data((char *)&dstat, sizeof(dstat));
++ /* we don't need to explicitly send data here, will
++ * be done by the original caller! */
+}
+
-+static void handle_getstate(void)
++static void handle_getstate(struct urb *urb, int max)
+{
-+ u_int8_t u8 = dfu_state;
-+ DEBUGE("getstate ");
++ debug("getstate ");
+
-+ udp_ep0_send_data((char *)&u8, sizeof(u8));
++ if (!urb->buffer || urb->buffer_length < sizeof(u_int8_t)) {
++ debug("invalid urb! ");
++ return;
++ }
++
++ urb->buffer[0] = urb->device->dfu_state & 0xff;
++ urb->actual_length = sizeof(u_int8_t);
+}
+
++#ifndef CONFIG_USBD_PRODUCTID_DFU
++#define CONFIG_USBD_PRODUCTID_DFU CONFIG_USBD_PRODUCTID_CDCACM
++#endif
+
++static const struct usb_device_descriptor dfu_dev_descriptor = {
++ .bLength = USB_DT_DEVICE_SIZE,
++ .bDescriptorType = USB_DT_DEVICE,
++ .bcdUSB = 0x0100,
++ .bDeviceClass = 0x00,
++ .bDeviceSubClass = 0x00,
++ .bDeviceProtocol = 0x00,
++ .bMaxPacketSize0 = EP0_MAX_PACKET_SIZE,
++ .idVendor = CONFIG_USBD_VENDORID,
++ .idProduct = CONFIG_USBD_PRODUCTID_DFU,
++ .bcdDevice = 0x0000,
++ .iManufacturer = 1,
++ .iProduct = 2,
++ .iSerialNumber = 0x00,
++ .bNumConfigurations = 0x01,
++};
++
++static const struct _dfu_desc dfu_cfg_descriptor = {
++ .ucfg = {
++ .bLength = USB_DT_CONFIG_SIZE,
++ .bDescriptorType = USB_DT_CONFIG,
++ .wTotalLength = USB_DT_CONFIG_SIZE +
++ 5*USB_DT_INTERFACE_SIZE +
++ USB_DT_DFU_SIZE,
++ .bNumInterfaces = 5,
++ .bConfigurationValue = 1,
++#ifdef CONFIG_USBD_STRING
++ .iConfiguration = 3,
++#else
++ .iConfiguration = 0,
++#endif
++ .bmAttributes = BMATTRIBUTE_RESERVED,
++ .bMaxPower = 50,
++ },
++ .uif[0] = {
++ .bLength = USB_DT_INTERFACE_SIZE,
++ .bDescriptorType = USB_DT_INTERFACE,
++ .bInterfaceNumber = 0x00,
++ .bAlternateSetting = 0x00,
++ .bNumEndpoints = 0x00,
++ .bInterfaceClass = 0xfe,
++ .bInterfaceSubClass = 0x01,
++ .bInterfaceProtocol = 0x02,
++ .iInterface = 0,
++ },
++ .uif[1] = {
++ .bLength = USB_DT_INTERFACE_SIZE,
++ .bDescriptorType = USB_DT_INTERFACE,
++ .bInterfaceNumber = 0x00,
++ .bAlternateSetting = 0x01,
++ .bNumEndpoints = 0x00,
++ .bInterfaceClass = 0xfe,
++ .bInterfaceSubClass = 0x01,
++ .bInterfaceProtocol = 0x02,
++ .iInterface = 0,
++ },
++ .uif[2] = {
++ .bLength = USB_DT_INTERFACE_SIZE,
++ .bDescriptorType = USB_DT_INTERFACE,
++ .bInterfaceNumber = 0x00,
++ .bAlternateSetting = 0x02,
++ .bNumEndpoints = 0x00,
++ .bInterfaceClass = 0xfe,
++ .bInterfaceSubClass = 0x01,
++ .bInterfaceProtocol = 0x02,
++ .iInterface = 0,
++ },
++ .uif[3] = {
++ .bLength = USB_DT_INTERFACE_SIZE,
++ .bDescriptorType = USB_DT_INTERFACE,
++ .bInterfaceNumber = 0x00,
++ .bAlternateSetting = 0x03,
++ .bNumEndpoints = 0x00,
++ .bInterfaceClass = 0xfe,
++ .bInterfaceSubClass = 0x01,
++ .bInterfaceProtocol = 0x02,
++ .iInterface = 0,
++ },
++ .uif[4] = {
++ .bLength = USB_DT_INTERFACE_SIZE,
++ .bDescriptorType = USB_DT_INTERFACE,
++ .bInterfaceNumber = 0x00,
++ .bAlternateSetting = 0x04,
++ .bNumEndpoints = 0x00,
++ .bInterfaceClass = 0xfe,
++ .bInterfaceSubClass = 0x01,
++ .bInterfaceProtocol = 0x02,
++ .iInterface = 0,
++ },
++ .func_dfu = DFU_FUNC_DESC,
++};
++
+int dfu_ep0_handler(struct urb *urb)
+{
+ int rc, ret = RET_NOTHING;
++ u_int8_t req = urb->device_request.bRequest;
++ u_int16_t val = urb->device_request.wValue;
++ u_int16_t len = urb->device_request.wLength;
++ struct usb_device_instance *dev = urb->device;
+
-+ DEBUGE("old_state = %u ", dfu_state);
++ debug("old_state = %u ", dev->dfu_state);
+
-+ switch (dfu_state) {
++ switch (dev->dfu_state) {
+ case DFU_STATE_appIDLE:
+ switch (req) {
+ case USB_REQ_DFU_GETSTATUS:
-+ handle_getstatus();
++ handle_getstatus(urb, len);
+ break;
+ case USB_REQ_DFU_GETSTATE:
-+ handle_getstate();
++ handle_getstate(urb, len);
+ break;
+ case USB_REQ_DFU_DETACH:
-+ dfu_state = DFU_STATE_appDETACH;
++ dev->dfu_state = DFU_STATE_appDETACH;
+ ret = RET_ZLP;
+ goto out;
+ break;
@@ -190,13 +447,13 @@
+ case DFU_STATE_appDETACH:
+ switch (req) {
+ case USB_REQ_DFU_GETSTATUS:
-+ handle_getstatus();
++ handle_getstatus(urb, len);
+ break;
+ case USB_REQ_DFU_GETSTATE:
-+ handle_getstate();
++ handle_getstate(urb, len);
+ break;
+ default:
-+ dfu_state = DFU_STATE_appIDLE;
++ dev->dfu_state = DFU_STATE_appIDLE;
+ ret = RET_STALL;
+ goto out;
+ break;
@@ -207,31 +464,31 @@
+ switch (req) {
+ case USB_REQ_DFU_DNLOAD:
+ if (len == 0) {
-+ dfu_state = DFU_STATE_dfuERROR;
++ dev->dfu_state = DFU_STATE_dfuERROR;
+ ret = RET_STALL;
+ goto out;
+ }
-+ dfu_state = DFU_STATE_dfuDNLOAD_SYNC;
-+ ptr = (u_int8_t *) AT91C_IFLASH + SAM7DFU_SIZE;
-+ ret = handle_dnload(val, len);
++ dev->dfu_state = DFU_STATE_dfuDNLOAD_SYNC;
++ //ptr = (u_int8_t *) AT91C_IFLASH + SAM7DFU_SIZE;
++ ret = handle_dnload(urb, val, len, 1);
+ break;
+ case USB_REQ_DFU_UPLOAD:
-+ ptr = (u_int8_t *) AT91C_IFLASH + SAM7DFU_SIZE;
-+ dfu_state = DFU_STATE_dfuUPLOAD_IDLE;
-+ handle_upload(val, len);
++ //ptr = (u_int8_t *) AT91C_IFLASH + SAM7DFU_SIZE;
++ dev->dfu_state = DFU_STATE_dfuUPLOAD_IDLE;
++ handle_upload(urb, val, len, 1);
+ break;
+ case USB_REQ_DFU_ABORT:
+ /* no zlp? */
+ ret = RET_ZLP;
+ break;
+ case USB_REQ_DFU_GETSTATUS:
-+ handle_getstatus();
++ handle_getstatus(urb, len);
+ break;
+ case USB_REQ_DFU_GETSTATE:
-+ handle_getstate();
++ handle_getstate(urb, len);
+ break;
+ default:
-+ dfu_state = DFU_STATE_dfuERROR;
++ dev->dfu_state = DFU_STATE_dfuERROR;
+ ret = RET_STALL;
+ goto out;
+ break;
@@ -240,14 +497,14 @@
+ case DFU_STATE_dfuDNLOAD_SYNC:
+ switch (req) {
+ case USB_REQ_DFU_GETSTATUS:
-+ handle_getstatus();
++ handle_getstatus(urb, len);
+ /* FIXME: state transition depending on block completeness */
+ break;
+ case USB_REQ_DFU_GETSTATE:
-+ handle_getstate();
++ handle_getstate(urb, len);
+ break;
+ default:
-+ dfu_state = DFU_STATE_dfuERROR;
++ dev->dfu_state = DFU_STATE_dfuERROR;
+ ret = RET_STALL;
+ goto out;
+ }
@@ -257,10 +514,10 @@
+ case USB_REQ_DFU_GETSTATUS:
+ /* FIXME: only accept getstatus if bwPollTimeout
+ * has elapsed */
-+ handle_getstatus();
++ handle_getstatus(urb, len);
+ break;
+ default:
-+ dfu_state = DFU_STATE_dfuERROR;
++ dev->dfu_state = DFU_STATE_dfuERROR;
+ ret = RET_STALL;
+ goto out;
+ }
@@ -268,21 +525,21 @@
+ case DFU_STATE_dfuDNLOAD_IDLE:
+ switch (req) {
+ case USB_REQ_DFU_DNLOAD:
-+ dfu_state = DFU_STATE_dfuDNLOAD_SYNC;
-+ ret = handle_dnload(val, len);
++ dev->dfu_state = DFU_STATE_dfuDNLOAD_SYNC;
++ ret = handle_dnload(urb, val, len, 0);
+ break;
+ case USB_REQ_DFU_ABORT:
-+ dfu_state = DFU_STATE_dfuIDLE;
++ dev->dfu_state = DFU_STATE_dfuIDLE;
+ ret = RET_ZLP;
+ break;
+ case USB_REQ_DFU_GETSTATUS:
-+ handle_getstatus();
++ handle_getstatus(urb, len);
+ break;
+ case USB_REQ_DFU_GETSTATE:
-+ handle_getstate();
++ handle_getstate(urb, len);
+ break;
+ default:
-+ dfu_state = DFU_STATE_dfuERROR;
++ dev->dfu_state = DFU_STATE_dfuERROR;
+ ret = RET_STALL;
+ break;
+ }
@@ -290,19 +547,19 @@
+ case DFU_STATE_dfuMANIFEST_SYNC:
+ switch (req) {
+ case USB_REQ_DFU_GETSTATUS:
-+ handle_getstatus();
++ handle_getstatus(urb, len);
+ break;
+ case USB_REQ_DFU_GETSTATE:
-+ handle_getstate();
++ handle_getstate(urb, len);
+ break;
+ default:
-+ dfu_state = DFU_STATE_dfuERROR;
++ dev->dfu_state = DFU_STATE_dfuERROR;
+ ret = RET_STALL;
+ break;
+ }
+ break;
+ case DFU_STATE_dfuMANIFEST:
-+ dfu_state = DFU_STATE_dfuERROR;
++ dev->dfu_state = DFU_STATE_dfuERROR;
+ ret = RET_STALL;
+ break;
+ case DFU_STATE_dfuMANIFEST_WAIT_RST:
@@ -312,23 +569,23 @@
+ switch (req) {
+ case USB_REQ_DFU_UPLOAD:
+ /* state transition if less data then requested */
-+ rc = handle_upload(val, len);
++ rc = handle_upload(urb, val, len, 0);
+ if (rc >= 0 && rc < len)
-+ dfu_state = DFU_STATE_dfuIDLE;
++ dev->dfu_state = DFU_STATE_dfuIDLE;
+ break;
+ case USB_REQ_DFU_ABORT:
-+ dfu_state = DFU_STATE_dfuIDLE;
++ dev->dfu_state = DFU_STATE_dfuIDLE;
+ /* no zlp? */
+ ret = RET_ZLP;
+ break;
+ case USB_REQ_DFU_GETSTATUS:
-+ handle_getstatus();
++ handle_getstatus(urb, len);
+ break;
+ case USB_REQ_DFU_GETSTATE:
-+ handle_getstate();
++ handle_getstate(urb, len);
+ break;
+ default:
-+ dfu_state = DFU_STATE_dfuERROR;
++ dev->dfu_state = DFU_STATE_dfuERROR;
+ ret = RET_STALL;
+ break;
+ }
@@ -336,38 +593,434 @@
+ case DFU_STATE_dfuERROR:
+ switch (req) {
+ case USB_REQ_DFU_GETSTATUS:
-+ handle_getstatus();
++ handle_getstatus(urb, len);
+ break;
+ case USB_REQ_DFU_GETSTATE:
-+ handle_getstate();
++ handle_getstate(dev, len);
+ break;
+ case USB_REQ_DFU_CLRSTATUS:
-+ dfu_state = DFU_STATE_dfuIDLE;
-+ dfu_status = DFU_STATUS_OK;
++ dev->dfu_state = DFU_STATE_dfuIDLE;
++ dev->dfu_status = DFU_STATUS_OK;
+ /* no zlp? */
+ ret = RET_ZLP;
+ break;
+ default:
-+ dfu_state = DFU_STATE_dfuERROR;
++ dev->dfu_state = DFU_STATE_dfuERROR;
+ ret = RET_STALL;
+ break;
+ }
+ break;
++ default:
++ return DFU_EP0_UNHANDLED;
++ break;
+ }
+
+out:
-+ DEBUGE("new_state = %u\r\n", dfu_state);
++ debug("new_state = %u, ret = %u\n", dev->dfu_state, ret);
+
+ switch (ret) {
-+ case RET_NOTHING:
-+ break;
+ case RET_ZLP:
-+ udp_ep0_send_zlp();
++ //udc_ep0_send_zlp();
++ urb->actual_length = 0;
++ return DFU_EP0_ZLP;
+ break;
+ case RET_STALL:
-+ udp_ep0_send_stall();
++ //udc_ep0_send_stall();
++ return DFU_EP0_STALL;
+ break;
++ case RET_NOTHING:
++ break;
+ }
++
++ return DFU_EP0_DATA;
++}
++
++int dfu_init_instance(struct usb_device_instance *dev)
++{
++ dev->dfu_dev_desc = &dfu_dev_descriptor;
++ dev->dfu_cfg_desc = &dfu_cfg_descriptor;
++ dev->dfu_state = DFU_STATE_appIDLE;
++ dev->dfu_status = DFU_STATUS_OK;
++
+ return 0;
++}
++#endif /* CONFIG_USBD_DFU */
+Index: u-boot/drivers/Makefile
+===================================================================
+--- u-boot.orig/drivers/Makefile 2007-02-24 03:59:30.000000000 +0100
++++ u-boot/drivers/Makefile 2007-02-24 04:03:05.000000000 +0100
+@@ -46,7 +46,7 @@
+ sl811_usb.o sm501.o smc91111.o smiLynxEM.o \
+ status_led.o sym53c8xx.o ahci.o \
+ ti_pci1410a.o tigon3.o tsec.o \
+- usbdcore.o usbdcore_ep0.o usbdcore_omap1510.o usbdcore_s3c2410.o usbtty.o \
++ usbdcore.o usbdfu.o usbdcore_ep0.o usbdcore_omap1510.o usbdcore_s3c2410.o usbtty.o \
+ videomodes.o w83c553f.o \
+ ks8695eth.o \
+ pxa_pcmcia.o mpc8xx_pcmcia.o tqm8xx_pcmcia.o \
+Index: u-boot/drivers/usbdcore.c
+===================================================================
+--- u-boot.orig/drivers/usbdcore.c 2007-02-24 03:58:21.000000000 +0100
++++ u-boot/drivers/usbdcore.c 2007-02-24 04:03:05.000000000 +0100
+@@ -31,6 +31,7 @@
+
+ #include <malloc.h>
+ #include "usbdcore.h"
++#include <usb_dfu.h>
+
+ #define MAX_INTERFACES 2
+
+@@ -212,6 +213,10 @@
+ */
+ struct usb_device_descriptor *usbd_device_device_descriptor (struct usb_device_instance *device, int port)
+ {
++#ifdef CONFIG_USBD_DFU
++ if (device->dfu_state != DFU_STATE_appIDLE)
++ return device->dfu_dev_desc;
++#endif
+ return (device->device_descriptor);
+ }
+
+@@ -232,6 +237,10 @@
+ if (!(configuration_instance = usbd_device_configuration_instance (device, port, configuration))) {
+ return NULL;
+ }
++#ifdef CONFIG_USBD_DFU
++ if (device->dfu_state != DFU_STATE_appIDLE)
++ return (&device->dfu_cfg_desc->ucfg);
++#endif
+ return (configuration_instance->configuration_descriptor);
+ }
+
+@@ -253,6 +262,13 @@
+ if (!(interface_instance = usbd_device_interface_instance (device, port, configuration, interface))) {
+ return NULL;
+ }
++#ifdef CONFIG_USBD_DFU
++ if (device->dfu_state != DFU_STATE_appIDLE) {
++ if (alternate < 0 || alternate >= DFU_NUM_ALTERNATES)
++ return NULL;
++ return &device->dfu_cfg_desc->uif[alternate];
++ }
++#endif
+ if ((alternate < 0) || (alternate >= interface_instance->alternates)) {
+ return NULL;
+ }
+@@ -623,6 +639,12 @@
+ case DEVICE_RESET:
+ device->device_state = STATE_DEFAULT;
+ device->address = 0;
++#ifdef CONFIG_USBD_DFU
++ if (device->dfu_state == DFU_STATE_appDETACH) {
++ debug("DFU SWITCH\n");
++ device->dfu_state = DFU_STATE_dfuIDLE;
++ }
++#endif
+ break;
+
+ case DEVICE_ADDRESS_ASSIGNED:
+Index: u-boot/drivers/usbtty.c
+===================================================================
+--- u-boot.orig/drivers/usbtty.c 2007-02-24 03:59:29.000000000 +0100
++++ u-boot/drivers/usbtty.c 2007-02-24 04:03:05.000000000 +0100
+@@ -31,6 +31,8 @@
+ #include "usbtty.h"
+ #include "usb_cdc_acm.h"
+ #include "usbdescriptors.h"
++#include <usb_dfu_descriptors.h>
++#include <usb_dfu.h>
+ #include <config.h> /* If defined, override Linux identifiers with
+ * vendor specific ones */
+
+@@ -169,6 +171,10 @@
+ struct usb_interface_descriptor data_class_interface;
+ struct usb_endpoint_descriptor
+ data_endpoints[NUM_ENDPOINTS-1] __attribute__((packed));
++#ifdef CONFIG_USBD_DFU
++ struct usb_interface_descriptor uif_dfu;
++ struct usb_dfu_func_descriptor func_dfu;
++#endif
+ } __attribute__((packed));
+
+ static struct acm_config_desc acm_configuration_descriptors[NUM_CONFIGS] = {
+@@ -179,7 +185,11 @@
+ .bDescriptorType = USB_DT_CONFIG,
+ .wTotalLength =
+ cpu_to_le16(sizeof(struct acm_config_desc)),
++#ifdef CONFIG_USBD_DFU
++ .bNumInterfaces = NUM_ACM_INTERFACES +1,
++#else
+ .bNumInterfaces = NUM_ACM_INTERFACES,
++#endif
+ .bConfigurationValue = 1,
+ .iConfiguration = STR_CONFIG,
+ .bmAttributes =
+@@ -278,6 +288,11 @@
+ .bInterval = 0xFF,
+ },
+ },
++#ifdef CONFIG_USBD_DFU
++ /* Interface 3 */
++ .uif_dfu = DFU_RT_IF_DESC,
++ .func_dfu = DFU_FUNC_DESC,
++#endif
+ },
+ };
+
+@@ -652,6 +667,9 @@
+ device_instance->bus = bus_instance;
+ device_instance->configurations = NUM_CONFIGS;
+ device_instance->configuration_instance_array = config_instance;
++#ifdef CONFIG_USBD_DFU
++ dfu_init_instance(device_instance);
++#endif
+
+ /* initialize bus instance */
+ memset (bus_instance, 0, sizeof (struct usb_bus_instance));
+Index: u-boot/include/configs/neo1973.h
+===================================================================
+--- u-boot.orig/include/configs/neo1973.h 2007-02-24 04:03:04.000000000 +0100
++++ u-boot/include/configs/neo1973.h 2007-02-24 04:03:05.000000000 +0100
+@@ -182,6 +182,10 @@
+ #define CONFIG_USBD_MANUFACTURER "OpenMoko, Inc"
+ #define CONFIG_USBD_PRODUCT_NAME "Neo1973 Bootloader " U_BOOT_VERSION
+ #define CONFIG_EXTRA_ENV_SETTINGS "usbtty=cdc_acm\0"
++#define CONFIG_USBD_DFU 1
++#define CONFIG_USBD_DFU_XFER_SIZE 0x4000
++#define CONFIG_USBD_DFU_INTERFACE 2
+
+
+ /*-----------------------------------------------------------------------
+ * Physical Memory Map
+Index: u-boot/include/usb_dfu.h
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ u-boot/include/usb_dfu.h 2007-02-24 04:03:05.000000000 +0100
+@@ -0,0 +1,91 @@
++#ifndef _DFU_H
++#define _DFU_H
++
++/* USB Device Firmware Update Implementation for u-boot
++ * (C) 2007 by OpenMoko, Inc.
++ * Author: Harald Welte <laforge at openmoko.org>
++ *
++ * based on: USB Device Firmware Update Implementation for OpenPCD
++ * (C) 2006 by Harald Welte <hwelte at hmw-consulting.de>
++ *
++ * This ought to be compliant to the USB DFU Spec 1.0 as available from
++ * http://www.usb.org/developers/devclass_docs/usbdfu10.pdf
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ */
++
++#include <asm/types.h>
++#include <usbdescriptors.h>
++#include <usb_dfu_descriptors.h>
++#include <config.h>
++
++/* USB DFU functional descriptor */
++#define DFU_FUNC_DESC { \
++ .bLength = USB_DT_DFU_SIZE, \
++ .bDescriptorType = USB_DT_DFU, \
++ .bmAttributes = USB_DFU_CAN_UPLOAD | USB_DFU_CAN_DOWNLOAD, \
++ .wDetachTimeOut = 0xff00, \
++ .wTransferSize = CONFIG_USBD_DFU_XFER_SIZE, \
++ .bcdDFUVersion = 0x0100, \
+}
++
++/* USB Interface descriptor in Runtime mode */
++#ifdef CONFIG_USB_STRING
++#define DFU_RT_IF_DESC { \
++ .bLength = USB_DT_INTERFACE_SIZE, \
++ .bDescriptorType = USB_DT_INTERFACE, \
++ .bInterfaceNumber = CONFIG_USBD_DFU_INTERFACE, \
++ .bAlternateSetting = 0x00, \
++ .bNumEndpoints = 0x00, \
++ .bInterfaceClass = 0xfe, \
++ .bInterfaceSubClass = 0x01, \
++ .bInterfaceProtocol = 0x01, \
++ .iInterface = 1, \
++}
++#else
++#define DFU_RT_IF_DESC { \
++ .bLength = USB_DT_INTERFACE_SIZE, \
++ .bDescriptorType = USB_DT_INTERFACE, \
++ .bInterfaceNumber = CONFIG_USBD_DFU_INTERFACE, \
++ .bAlternateSetting = 0x00, \
++ .bNumEndpoints = 0x00, \
++ .bInterfaceClass = 0xfe, \
++ .bInterfaceSubClass = 0x01, \
++ .bInterfaceProtocol = 0x01, \
++ .iInterface = 0, \
++}
++#endif
++
++#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
++
++#define DFU_NUM_ALTERNATES 5
++
++struct _dfu_desc {
++ struct usb_configuration_descriptor ucfg;
++ struct usb_interface_descriptor uif[DFU_NUM_ALTERNATES];
++ struct usb_dfu_func_descriptor func_dfu;
++};
++
++int dfu_init_instance(struct usb_device_instance *dev);
++
++#define DFU_EP0_NONE 0
++#define DFU_EP0_UNHANDLED 1
++#define DFU_EP0_STALL 2
++#define DFU_EP0_ZLP 3
++#define DFU_EP0_DATA 4
++
++int dfu_ep0_handler(struct urb *urb);
++
++#endif /* _DFU_H */
+Index: u-boot/include/usb_dfu_descriptors.h
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ u-boot/include/usb_dfu_descriptors.h 2007-02-24 04:03:05.000000000 +0100
+@@ -0,0 +1,94 @@
++#ifndef _USB_DFU_H
++#define _USB_DFU_H
++/* USB Device Firmware Update Implementation for OpenPCD
++ * (C) 2006 by Harald Welte <hwelte at hmw-consulting.de>
++ *
++ * Protocol definitions for USB DFU
++ *
++ * This ought to be compliant to the USB DFU Spec 1.0 as available from
++ * http://www.usb.org/developers/devclass_docs/usbdfu10.pdf
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ */
++
++#include <linux/types.h>
++
++#define USB_DT_DFU 0x21
++
++struct usb_dfu_func_descriptor {
++ u_int8_t bLength;
++ u_int8_t bDescriptorType;
++ u_int8_t bmAttributes;
++#define USB_DFU_CAN_DOWNLOAD (1 << 0)
++#define USB_DFU_CAN_UPLOAD (1 << 1)
++#define USB_DFU_MANIFEST_TOL (1 << 2)
++#define USB_DFU_WILL_DETACH (1 << 3)
++ u_int16_t wDetachTimeOut;
++ u_int16_t wTransferSize;
++ u_int16_t bcdDFUVersion;
++} __attribute__ ((packed));
++
++#define USB_DT_DFU_SIZE 9
++
++#define USB_TYPE_DFU (USB_TYPE_CLASS|USB_RECIP_INTERFACE)
++
++/* DFU class-specific requests (Section 3, DFU Rev 1.1) */
++#define USB_REQ_DFU_DETACH 0x00
++#define USB_REQ_DFU_DNLOAD 0x01
++#define USB_REQ_DFU_UPLOAD 0x02
++#define USB_REQ_DFU_GETSTATUS 0x03
++#define USB_REQ_DFU_CLRSTATUS 0x04
++#define USB_REQ_DFU_GETSTATE 0x05
++#define USB_REQ_DFU_ABORT 0x06
++
++struct dfu_status {
++ u_int8_t bStatus;
++ u_int8_t bwPollTimeout[3];
++ u_int8_t bState;
++ u_int8_t iString;
++} __attribute__((packed));
++
++#define DFU_STATUS_OK 0x00
++#define DFU_STATUS_errTARGET 0x01
++#define DFU_STATUS_errFILE 0x02
++#define DFU_STATUS_errWRITE 0x03
++#define DFU_STATUS_errERASE 0x04
++#define DFU_STATUS_errCHECK_ERASED 0x05
++#define DFU_STATUS_errPROG 0x06
++#define DFU_STATUS_errVERIFY 0x07
++#define DFU_STATUS_errADDRESS 0x08
++#define DFU_STATUS_errNOTDONE 0x09
++#define DFU_STATUS_errFIRMWARE 0x0a
++#define DFU_STATUS_errVENDOR 0x0b
++#define DFU_STATUS_errUSBR 0x0c
++#define DFU_STATUS_errPOR 0x0d
++#define DFU_STATUS_errUNKNOWN 0x0e
++#define DFU_STATUS_errSTALLEDPKT 0x0f
++
++enum dfu_state {
++ DFU_STATE_appIDLE = 0,
++ DFU_STATE_appDETACH = 1,
++ DFU_STATE_dfuIDLE = 2,
++ DFU_STATE_dfuDNLOAD_SYNC = 3,
++ DFU_STATE_dfuDNBUSY = 4,
++ DFU_STATE_dfuDNLOAD_IDLE = 5,
++ DFU_STATE_dfuMANIFEST_SYNC = 6,
++ DFU_STATE_dfuMANIFEST = 7,
++ DFU_STATE_dfuMANIFEST_WAIT_RST = 8,
++ DFU_STATE_dfuUPLOAD_IDLE = 9,
++ DFU_STATE_dfuERROR = 10,
++};
++
++#endif /* _USB_DFU_H */
+Index: u-boot/include/usbdcore.h
+===================================================================
+--- u-boot.orig/include/usbdcore.h 2007-02-24 03:59:29.000000000 +0100
++++ u-boot/include/usbdcore.h 2007-02-24 04:03:05.000000000 +0100
+@@ -33,6 +33,7 @@
+
+ #include <common.h>
+ #include "usbdescriptors.h"
++#include <usb_dfu_descriptors.h>
+
+
+ #define MAX_URBS_QUEUED 5
+@@ -475,7 +476,11 @@
+ * function driver to inform it that data has arrived.
+ */
+
++#ifdef CONFIG_USBD_DFU
++#define URB_BUF_SIZE (128+CONFIG_USBD_DFU_XFER_SIZE)
++#else
+ #define URB_BUF_SIZE 128 /* in linux we'd malloc this, but in u-boot we prefer static data */
++#endif
+ struct urb {
+
+ struct usb_endpoint_instance *endpoint;
+@@ -603,6 +608,12 @@
+ unsigned long usbd_rxtx_timestamp;
+ unsigned long usbd_last_rxtx_timestamp;
+
++#ifdef CONFIG_USBD_DFU
++ struct usb_device_descriptor *dfu_dev_desc;
++ struct _dfu_desc *dfu_cfg_desc;
++ enum dfu_state dfu_state;
++ u_int8_t dfu_status;
++#endif
+ };
+
+ /* Bus Interface configuration structure
More information about the commitlog
mailing list