📄 uboot-dfu.patch
字号:
Index: u-boot/drivers/usb/usbdcore_ep0.c===================================================================--- u-boot.orig/drivers/usb/usbdcore_ep0.c+++ u-boot/drivers/usb/usbdcore_ep0.c@@ -51,10 +51,15 @@ */ #include <common.h>+DECLARE_GLOBAL_DATA_PTR; #if defined(CONFIG_USB_DEVICE) #include "usbdcore.h" +#ifdef CONFIG_USBD_DFU+#include <usb_dfu.h>+#endif+ #if 0 #define dbg_ep0(lvl,fmt,args...) serial_printf("[%s] %s:%d: "fmt"\n",__FILE__,__FUNCTION__,__LINE__,##args) #else@@ -273,7 +278,24 @@ case USB_DESCRIPTOR_TYPE_ENDPOINT: serial_printf("USB_DESCRIPTOR_TYPE_ENDPOINT - error not implemented\n"); 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 */ { serial_printf("USB_DESCRIPTOR_TYPE_HID - error not implemented\n"); return -1; /* unsupported at this time */@@ -301,6 +323,7 @@ max); #endif }+#endif /* CONFIG_USBD_DFU */ break; case USB_DESCRIPTOR_TYPE_REPORT: {@@ -403,6 +426,24 @@ le16_to_cpu (request->wLength), USBD_DEVICE_REQUESTS (request->bRequest)); +#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) */ if ((request->bmRequestType & USB_REQ_TYPE_MASK) != 0) { if(device->device_state <= STATE_CONFIGURED){@@ -590,7 +631,8 @@ device->interface = le16_to_cpu (request->wIndex); device->alternate = le16_to_cpu (request->wValue); /*dbg_ep0(2, "set interface: %d alternate: %d", device->interface, device->alternate); */- serial_printf ("DEVICE_SET_INTERFACE.. event?\n");+ usbd_device_event_irq(device, DEVICE_SET_INTERFACE,+ (request->wIndex << 16 | request->wValue)); return 0; case USB_REQ_GET_STATUS:Index: u-boot/drivers/usb/usbdfu.c===================================================================--- /dev/null+++ u-boot/drivers/usb/usbdfu.c@@ -0,0 +1,1050 @@+/*+ * (C) 2007 by OpenMoko, Inc.+ * Author: Harald Welte <laforge@openmoko.org>+ *+ * based on existing SAM7DFU code from OpenPCD:+ * (C) Copyright 2006 by Harald Welte <hwelte@hmw-consulting.de>+ *+ * See file CREDITS for list of people who contributed to this+ * project.+ *+ * 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+ *+ * TODO:+ * - make NAND support reasonably self-contained and put in apropriate+ * ifdefs+ * - add some means of synchronization, i.e. block commandline access+ * while DFU transfer is in progress, and return to commandline once+ * we're finished+ * - add VERIFY support after writing to flash+ * - sanely free() resources allocated during first uppload/download+ * request when aborting+ * - sanely free resources when another alternate interface is selected+ *+ * Maybe:+ * - add something like uImage or some other header that provides CRC+ * checking?+ * - make 'dnstate' attached to 'struct usb_device_instance'+ */++#include <config.h>+#if defined(CONFIG_USBD_DFU)++#include <common.h>+DECLARE_GLOBAL_DATA_PTR;++#include <malloc.h>+#include <linux/types.h>+#include <linux/list.h>+#include <asm/errno.h>+#include <usbdcore.h>+#include <usb_dfu.h>+#include <usb_dfu_descriptors.h>+#include <usb_dfu_trailer.h>++#include <nand.h>+#include <jffs2/load_kernel.h>+int mtdparts_init(void);+extern struct list_head devices;++#include "usbdcore_s3c2410.h"+#include "../serial/usbtty.h" /* for STR_* defs */++#define RET_NOTHING 0+#define RET_ZLP 1+#define RET_STALL 2++volatile enum dfu_state *system_dfu_state; /* for 3rd parties */+++struct dnload_state {+ nand_info_t *nand;+ struct part_info *part;+ unsigned int part_net_size; /* net sizee (excl. bad blocks) of part */++ nand_erase_options_t erase_opts;+ nand_write_options_t write_opts;+ nand_read_options_t read_opts;++ unsigned char *ptr; /* pointer to next empty byte in buffer */+ unsigned int off; /* offset of current erase page in flash chip */+ unsigned char *buf; /* pointer to allocated erase page buffer */++ /* unless doing an atomic transfer, we use the static buffer below.+ * This saves us from having to clean up dynamic allications in the+ * various error paths of the code. Also, it will always work, no+ * matter what the memory situation is. */+ unsigned char _buf[0x20000]; /* FIXME: depends flash page size */+};++static struct dnload_state _dnstate;++static int dfu_trailer_matching(const struct uboot_dfu_trailer *trailer)+{+ if (trailer->magic != UBOOT_DFU_TRAILER_MAGIC ||+ trailer->version != UBOOT_DFU_TRAILER_V1 ||+ trailer->vendor != CONFIG_USBD_VENDORID ||+ (trailer->product != CONFIG_USBD_PRODUCTID_CDCACM &&+ trailer->product != CONFIG_USBD_PRODUCTID_GSERIAL))+ return 0;+#ifdef CONFIG_REVISION_TAG+ if (trailer->revision != get_board_rev())+ return 0;+#endif++ return 1;+}++static struct part_info *get_partition_nand(int idx)+{+ struct mtd_device *dev;+ struct part_info *part;+ struct list_head *pentry;+ int i;++ if (mtdparts_init())+ return NULL;+ if (list_empty(&devices))+ return NULL;++ dev = list_entry(devices.next, struct mtd_device, link);+ i = 0;+ list_for_each(pentry, &dev->parts) {+ if (i == idx) {+ part = list_entry(pentry, struct part_info, link);+ return part;+ }+ i++;+ }++ return NULL;+}++#define LOAD_ADDR ((unsigned char *)0x32000000)++static int initialize_ds_nand(struct usb_device_instance *dev, struct dnload_state *ds)+{+ ds->part = get_partition_nand(dev->alternate - 1);+ if (!ds->part) {+ printf("DFU: unable to find partition %u\b", dev->alternate-1);+ dev->dfu_state = DFU_STATE_dfuERROR;+ dev->dfu_status = DFU_STATUS_errADDRESS;+ return RET_STALL;+ }+ ds->nand = &nand_info[ds->part->dev->id->num];+ ds->off = ds->part->offset;+ ds->part_net_size = nand_net_part_size(ds->part);++ if (ds->nand->erasesize > sizeof(ds->_buf)) {+ printf("*** Warning - NAND ERASESIZE bigger than static buffer\n");+ ds->buf = malloc(ds->nand->erasesize);+ if (!ds->buf) {+ printf("DFU: can't allocate %u bytes\n", ds->nand->erasesize);+ dev->dfu_state = DFU_STATE_dfuERROR;+ dev->dfu_status = DFU_STATUS_errADDRESS;+ return RET_STALL;+ }+ } else+ ds->buf = ds->_buf;++ ds->ptr = ds->buf;++ memset(&ds->read_opts, 0, sizeof(ds->read_opts));++ memset(&ds->erase_opts, 0, sizeof(ds->erase_opts));+ ds->erase_opts.quiet = 1;+ /* FIXME: do this more dynamic */+ if (!strcmp(ds->part->name, "rootfs"))+ ds->erase_opts.jffs2 = 1;++ memset(&ds->write_opts, 0, sizeof(ds->write_opts));+ ds->write_opts.pad = 1;+ ds->write_opts.blockalign = 1;+ ds->write_opts.quiet = 1;++ debug("initialize_ds_nand(dev=%p, ds=%p): ", dev, ds);+ debug("nand=%p, ptr=%p, buf=%p, off=0x%x\n", ds->nand, ds->ptr, ds->buf, ds->off);++ return RET_NOTHING;+}++static int erase_flash_verify_nand(struct urb *urb, struct dnload_state *ds,+ unsigned long erasesize, unsigned long size)+{+ struct usb_device_instance *dev = urb->device;+ int rc;++ debug("erase_flash_verify_nand(urb=%p, ds=%p, erase=0x%x size=0x%x)\n",+ urb, ds, erasesize, size);++ if (erasesize == ds->nand->erasesize) {+ /* we're only writing a single block and need to+ * do bad block skipping / offset adjustments our own */+ while (ds->nand->block_isbad(ds->nand, ds->off)) {+ debug("SKIP_ONE_BLOCK(0x%08x)!!\n", ds->off);+ ds->off += ds->nand->erasesize;+ }+ }++ /* we have finished one eraseblock, flash it */+ ds->erase_opts.offset = ds->off;+ ds->erase_opts.length = erasesize;+ debug("Erasing 0x%x bytes @ offset 0x%x (jffs=%u)\n",+ ds->erase_opts.length, ds->erase_opts.offset,+ ds->erase_opts.jffs2);+ rc = nand_erase_opts(ds->nand, &ds->erase_opts);+ if (rc) {+ debug("Error erasing\n");+ dev->dfu_state = DFU_STATE_dfuERROR;+ dev->dfu_status = DFU_STATUS_errERASE;+ return RET_STALL;+ }++ ds->write_opts.buffer = ds->buf;+ ds->write_opts.length = size;+ ds->write_opts.offset = ds->off;+ debug("Writing 0x%x bytes @ offset 0x%x\n", size, ds->off);+ rc = nand_write_opts(ds->nand, &ds->write_opts);+ if (rc) {+ debug("Error writing\n");+ dev->dfu_state = DFU_STATE_dfuERROR;+ dev->dfu_status = DFU_STATUS_errWRITE;+ return RET_STALL;+ }++ ds->off += size;+ ds->ptr = ds->buf;++ /* FIXME: implement verify! */+ return RET_NOTHING;+}++static int erase_tail_clean_nand(struct urb *urb, struct dnload_state *ds)+{+ struct usb_device_instance *dev = urb->device;+ int rc;++ ds->erase_opts.offset = ds->off;+ ds->erase_opts.length = ds->part->size - (ds->off - ds->part->offset);+ debug("Erasing tail of 0x%x bytes @ offset 0x%x (jffs=%u)\n",+ ds->erase_opts.length, ds->erase_opts.offset,+ ds->erase_opts.jffs2);+ rc = nand_erase_opts(ds->nand, &ds->erase_opts);+ if (rc) {+ printf("Error erasing tail\n");+ dev->dfu_state = DFU_STATE_dfuERROR;+ dev->dfu_status = DFU_STATUS_errERASE;+ return RET_STALL;+ }++ ds->off += ds->erase_opts.length; /* for consistency */++ return RET_NOTHING;+}++/* Read the next erase blcok from NAND into buffer */+static int read_next_nand(struct urb *urb, struct dnload_state *ds)+{+ struct usb_device_instance *dev = urb->device;+ int rc;++ ds->read_opts.buffer = ds->buf;+ ds->read_opts.length = ds->nand->erasesize;+ ds->read_opts.offset = ds->off;+ ds->read_opts.quiet = 1;++ debug("Reading 0x%x@0x%x to 0x%08p\n", ds->nand->erasesize,+ ds->off, ds->buf);+ rc = nand_read_opts(ds->nand, &ds->read_opts);+ if (rc) {+ debug("Error reading\n");+ dev->dfu_state = DFU_STATE_dfuERROR;+ dev->dfu_status = DFU_STATUS_errWRITE;+ return RET_STALL;+ }+ ds->off += ds->nand->erasesize;+ ds->ptr = ds->buf;++ return RET_NOTHING;+}+++static int handle_dnload(struct urb *urb, u_int16_t val, u_int16_t len, int first)+{+ struct usb_device_instance *dev = urb->device;+ struct dnload_state *ds = &_dnstate;+ unsigned int actual_len = len;+ unsigned int remain_len;+ unsigned long size;+ int rc;++ debug("download(len=%u, first=%u) ", len, first);++ if (len > CONFIG_USBD_DFU_XFER_SIZE) {+ /* Too big. Not that we'd really care, but it's a+ * DFU protocol violation */+ debug("length exceeds flash page size ");+ dev->dfu_state = DFU_STATE_dfuERROR;+ dev->dfu_status = DFU_STATUS_errADDRESS;+ return RET_STALL;+ }++ if (first) {+ /* Make sure that we have a valid mtd partition table */+ char *mtdp = getenv("mtdparts");+ if (!mtdp)+ run_command("dynpart", 0);+ }++ if (len == 0) {+ debug("zero-size write -> MANIFEST_SYNC ");+ dev->dfu_state = DFU_STATE_dfuMANIFEST_SYNC;++ /* cleanup */+ switch (dev->alternate) {+ char buf[12];+ case 0:+ sprintf(buf, "%lx", ds->ptr - ds->buf);+ setenv("filesize", buf);+ ds->ptr = ds->buf;+ break;+ case 1:+ if (ds->ptr >+ ds->buf + sizeof(struct uboot_dfu_trailer)) {+ struct uboot_dfu_trailer trailer;+ dfu_trailer_mirror(&trailer, ds->ptr);+ if (!dfu_trailer_matching(&trailer)) {+ printf("DFU TRAILER NOT OK\n");+ dev->dfu_state = DFU_STATE_dfuERROR;+ dev->dfu_status = DFU_STATUS_errTARGET;+ return RET_STALL;+ }++ rc = erase_flash_verify_nand(urb, ds,+ ds->part->size,+ ds->part_net_size);+ /* re-write dynenv marker in OOB */+ run_command("dynenv set u-boot_env", 0);+ }+ ds->nand = NULL;+ free(ds->buf);+ ds->ptr = ds->buf = ds->_buf;+ break;+ default:+ rc = 0;+ if (ds->ptr > ds->buf)+ rc = erase_flash_verify_nand(urb, ds,+ ds->nand->erasesize,+ ds->nand->erasesize);+ /* rootfs partition */+ if (!rc && !strcmp(ds->part->name, "rootfs"))+ rc = erase_tail_clean_nand(urb, ds);++ ds->nand = NULL;+ break;+ }++ return RET_ZLP;+ }++ if (urb->actual_length != len) {+ debug("urb->actual_length(%u) != len(%u) ?!? ",+ urb->actual_length, len);+ dev->dfu_state = DFU_STATE_dfuERROR;+ dev->dfu_status = DFU_STATUS_errADDRESS;+ return RET_STALL;+ }++ if (first && ds->buf && ds->buf != ds->_buf && ds->buf != LOAD_ADDR) {+ free(ds->buf);+ ds->buf = ds->_buf;+ }++ switch (dev->alternate) {+ case 0:+ if (first) {+ printf("Starting DFU DOWNLOAD to RAM (0x%08p)\n",+ LOAD_ADDR);+ ds->buf = LOAD_ADDR;+ ds->ptr = ds->buf;+ }++ memcpy(ds->ptr, urb->buffer, len);+ ds->ptr += len;+ break;+ case 1:+ if (first) {+ rc = initialize_ds_nand(dev, ds);+ if (rc)+ return rc;+ ds->buf = malloc(ds->part_net_size);+ if (!ds->buf) {+ printf("No memory for atomic buffer!!\n");+ dev->dfu_state = DFU_STATE_dfuERROR;+ dev->dfu_status = DFU_STATUS_errUNKNOWN;+ return RET_STALL;+ }+ ds->ptr = ds->buf;+ printf("Starting Atomic DFU DOWNLOAD to partition '%s'\n",+ ds->part->name);+ }++ remain_len = (ds->buf + ds->part_net_size) - ds->ptr;+ if (remain_len < len) {+ len = remain_len;+ printf("End of write exceeds partition end\n");+ dev->dfu_state = DFU_STATE_dfuERROR;+ dev->dfu_status = DFU_STATUS_errADDRESS;+ return RET_STALL;+ }+ memcpy(ds->ptr, urb->buffer, len);+ ds->ptr += len;+ break;+ default:+ if (first) {+ rc = initialize_ds_nand(dev, ds);+ if (rc)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -