summaryrefslogtreecommitdiffstats
path: root/meta/packages/uboot/u-boot-mkimage-openmoko-native/uboot-dfu.patch
diff options
context:
space:
mode:
Diffstat (limited to 'meta/packages/uboot/u-boot-mkimage-openmoko-native/uboot-dfu.patch')
-rw-r--r--meta/packages/uboot/u-boot-mkimage-openmoko-native/uboot-dfu.patch2081
1 files changed, 2081 insertions, 0 deletions
diff --git a/meta/packages/uboot/u-boot-mkimage-openmoko-native/uboot-dfu.patch b/meta/packages/uboot/u-boot-mkimage-openmoko-native/uboot-dfu.patch
new file mode 100644
index 0000000000..1122f4894f
--- /dev/null
+++ b/meta/packages/uboot/u-boot-mkimage-openmoko-native/uboot-dfu.patch
@@ -0,0 +1,2081 @@
1Index: u-boot/drivers/usbdcore_ep0.c
2===================================================================
3--- u-boot.orig/drivers/usbdcore_ep0.c
4+++ u-boot/drivers/usbdcore_ep0.c
5@@ -42,10 +42,15 @@
6 */
7
8 #include <common.h>
9+DECLARE_GLOBAL_DATA_PTR;
10
11 #if defined(CONFIG_USB_DEVICE)
12 #include "usbdcore.h"
13
14+#ifdef CONFIG_USBD_DFU
15+#include <usb_dfu.h>
16+#endif
17+
18 #if 0
19 #define dbg_ep0(lvl,fmt,args...) serial_printf("[%s] %s:%d: "fmt"\n",__FILE__,__FUNCTION__,__LINE__,##args)
20 #else
21@@ -213,7 +218,7 @@
22 urb->buffer = device_descriptor;
23 urb->actual_length = MIN(sizeof(*device_descriptor), max);
24 }
25- /*dbg_ep0(3, "copied device configuration, actual_length: %x", urb->actual_length); */
26+ dbg_ep0(3, "using device configuration, actual_length: %x", urb->actual_length);
27 break;
28
29 case USB_DESCRIPTOR_TYPE_CONFIGURATION:
30@@ -267,7 +272,24 @@
31 return -1;
32 case USB_DESCRIPTOR_TYPE_ENDPOINT:
33 return -1;
34+ /* This really means "Class Specific Descriptor #1 == USB_DT_DFU */
35 case USB_DESCRIPTOR_TYPE_HID:
36+#ifdef CONFIG_USBD_DFU
37+ {
38+ int bNumInterface =
39+ le16_to_cpu(urb->device_request.wIndex);
40+
41+ /* In runtime mode, we only respond to the DFU INTERFACE,
42+ * whereas in DFU mode, we respond for all intrfaces */
43+ if (device->dfu_state != DFU_STATE_appIDLE &&
44+ device->dfu_state != DFU_STATE_appDETACH ||
45+ bNumInterface == CONFIG_USBD_DFU_INTERFACE) {
46+ urb->buffer = &device->dfu_cfg_desc->func_dfu;
47+ urb->actual_length = sizeof(struct usb_dfu_func_descriptor);
48+ } else
49+ return -1;
50+ }
51+#else /* CONFIG_USBD_DFU */
52 {
53 return -1; /* unsupported at this time */
54 #if 0
55@@ -294,6 +316,7 @@
56 max);
57 #endif
58 }
59+#endif /* CONFIG_USBD_DFU */
60 break;
61 case USB_DESCRIPTOR_TYPE_REPORT:
62 {
63@@ -388,6 +411,24 @@
64 le16_to_cpu (request->wLength),
65 USBD_DEVICE_REQUESTS (request->bRequest));
66
67+#ifdef CONFIG_USBD_DFU
68+ if ((request->bmRequestType & 0x3f) == USB_TYPE_DFU &&
69+ (device->dfu_state != DFU_STATE_appIDLE ||
70+ le16_to_cpu(request->wIndex) == CONFIG_USBD_DFU_INTERFACE)) {
71+ int rc = dfu_ep0_handler(urb);
72+ switch (rc) {
73+ case DFU_EP0_NONE:
74+ case DFU_EP0_UNHANDLED:
75+ break;
76+ case DFU_EP0_ZLP:
77+ case DFU_EP0_DATA:
78+ return 0;
79+ case DFU_EP0_STALL:
80+ return -1;
81+ }
82+ }
83+#endif /* CONFIG_USB_DFU */
84+
85 /* handle USB Standard Request (c.f. USB Spec table 9-2) */
86 if ((request->bmRequestType & USB_REQ_TYPE_MASK) != 0) {
87 if (device->device_state <= STATE_CONFIGURED)
88@@ -570,7 +611,8 @@
89 device->interface = le16_to_cpu (request->wIndex);
90 device->alternate = le16_to_cpu (request->wValue);
91 /*dbg_ep0(2, "set interface: %d alternate: %d", device->interface, device->alternate); */
92- serial_printf ("DEVICE_SET_INTERFACE.. event?\n");
93+ usbd_device_event_irq(device, DEVICE_SET_INTERFACE,
94+ (request->wIndex << 16 | request->wValue));
95 return 0;
96
97 case USB_REQ_GET_STATUS:
98Index: u-boot/drivers/usbdfu.c
99===================================================================
100--- /dev/null
101+++ u-boot/drivers/usbdfu.c
102@@ -0,0 +1,1069 @@
103+/*
104+ * (C) 2007 by OpenMoko, Inc.
105+ * Author: Harald Welte <laforge@openmoko.org>
106+ *
107+ * based on existing SAM7DFU code from OpenPCD:
108+ * (C) Copyright 2006 by Harald Welte <hwelte@hmw-consulting.de>
109+ *
110+ * See file CREDITS for list of people who contributed to this
111+ * project.
112+ *
113+ * This program is free software; you can redistribute it and/or
114+ * modify it under the terms of the GNU General Public License as
115+ * published by the Free Software Foundation; either version 2 of
116+ * the License, or (at your option) any later version.
117+ *
118+ * This program is distributed in the hope that it will be useful,
119+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
120+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
121+ * GNU General Public License for more details.
122+ *
123+ * You should have received a copy of the GNU General Public License
124+ * along with this program; if not, write to the Free Software
125+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
126+ * MA 02111-1307 USA
127+ *
128+ * TODO:
129+ * - make NAND support reasonably self-contained and put in apropriate
130+ * ifdefs
131+ * - add some means of synchronization, i.e. block commandline access
132+ * while DFU transfer is in progress, and return to commandline once
133+ * we're finished
134+ * - add VERIFY support after writing to flash
135+ * - sanely free() resources allocated during first uppload/download
136+ * request when aborting
137+ * - sanely free resources when another alternate interface is selected
138+ *
139+ * Maybe:
140+ * - add something like uImage or some other header that provides CRC
141+ * checking?
142+ * - make 'dnstate' attached to 'struct usb_device_instance'
143+ */
144+
145+#include <config.h>
146+#if defined(CONFIG_USBD_DFU)
147+
148+#include <common.h>
149+DECLARE_GLOBAL_DATA_PTR;
150+
151+#include <malloc.h>
152+#include <linux/types.h>
153+#include <linux/list.h>
154+#include <asm/errno.h>
155+#include <usbdcore.h>
156+#include <usb_dfu.h>
157+#include <usb_dfu_descriptors.h>
158+#include <usb_dfu_trailer.h>
159+
160+#include <nand.h>
161+#include <jffs2/load_kernel.h>
162+int mtdparts_init(void);
163+extern struct list_head devices;
164+
165+#include "usbdcore_s3c2410.h"
166+#include "usbtty.h" /* for STR_* defs */
167+
168+#define RET_NOTHING 0
169+#define RET_ZLP 1
170+#define RET_STALL 2
171+
172+volatile enum dfu_state *system_dfu_state; /* for 3rd parties */
173+
174+
175+struct dnload_state {
176+ nand_info_t *nand;
177+ struct part_info *part;
178+ unsigned int part_net_size; /* net sizee (excl. bad blocks) of part */
179+
180+ nand_erase_options_t erase_opts;
181+ nand_write_options_t write_opts;
182+ nand_read_options_t read_opts;
183+
184+ unsigned char *ptr; /* pointer to next empty byte in buffer */
185+ unsigned int off; /* offset of current erase page in flash chip */
186+ unsigned char *buf; /* pointer to allocated erase page buffer */
187+
188+ /* unless doing an atomic transfer, we use the static buffer below.
189+ * This saves us from having to clean up dynamic allications in the
190+ * various error paths of the code. Also, it will always work, no
191+ * matter what the memory situation is. */
192+ unsigned char _buf[0x20000]; /* FIXME: depends flash page size */
193+};
194+
195+static struct dnload_state _dnstate;
196+
197+static int dfu_trailer_matching(const struct uboot_dfu_trailer *trailer)
198+{
199+ if (trailer->magic != UBOOT_DFU_TRAILER_MAGIC ||
200+ trailer->version != UBOOT_DFU_TRAILER_V1 ||
201+ trailer->vendor != CONFIG_USBD_VENDORID ||
202+ (trailer->product != CONFIG_USBD_PRODUCTID_CDCACM &&
203+ trailer->product != CONFIG_USBD_PRODUCTID_GSERIAL))
204+ return 0;
205+#ifdef CONFIG_REVISION_TAG
206+ if (trailer->revision != get_board_rev())
207+ return 0;
208+#endif
209+
210+ return 1;
211+}
212+
213+static struct part_info *get_partition_nand(int idx)
214+{
215+ struct mtd_device *dev;
216+ struct part_info *part;
217+ struct list_head *pentry;
218+ int i;
219+
220+ if (mtdparts_init())
221+ return NULL;
222+ if (list_empty(&devices))
223+ return NULL;
224+
225+ dev = list_entry(devices.next, struct mtd_device, link);
226+ i = 0;
227+ list_for_each(pentry, &dev->parts) {
228+ if (i == idx) {
229+ part = list_entry(pentry, struct part_info, link);
230+ return part;
231+ }
232+ i++;
233+ }
234+
235+ return NULL;
236+}
237+
238+#define LOAD_ADDR ((unsigned char *)0x32000000)
239+
240+static int initialize_ds_nand(struct usb_device_instance *dev, struct dnload_state *ds)
241+{
242+ ds->part = get_partition_nand(dev->alternate - 1);
243+ if (!ds->part) {
244+ printf("DFU: unable to find partition %u\b", dev->alternate-1);
245+ dev->dfu_state = DFU_STATE_dfuERROR;
246+ dev->dfu_status = DFU_STATUS_errADDRESS;
247+ return RET_STALL;
248+ }
249+ ds->nand = &nand_info[ds->part->dev->id->num];
250+ ds->off = ds->part->offset;
251+ ds->part_net_size = nand_net_part_size(ds->part);
252+
253+ if (ds->nand->erasesize > sizeof(ds->_buf)) {
254+ printf("*** Warning - NAND ERASESIZE bigger than static buffer\n");
255+ ds->buf = malloc(ds->nand->erasesize);
256+ if (!ds->buf) {
257+ printf("DFU: can't allocate %u bytes\n", ds->nand->erasesize);
258+ dev->dfu_state = DFU_STATE_dfuERROR;
259+ dev->dfu_status = DFU_STATUS_errADDRESS;
260+ return RET_STALL;
261+ }
262+ } else
263+ ds->buf = ds->_buf;
264+
265+ ds->ptr = ds->buf;
266+
267+ memset(&ds->read_opts, 0, sizeof(ds->read_opts));
268+
269+ memset(&ds->erase_opts, 0, sizeof(ds->erase_opts));
270+ ds->erase_opts.quiet = 1;
271+ /* FIXME: do this more dynamic */
272+ if (!strcmp(ds->part->name, "rootfs"))
273+ ds->erase_opts.jffs2 = 1;
274+
275+ memset(&ds->write_opts, 0, sizeof(ds->write_opts));
276+ ds->write_opts.pad = 1;
277+ ds->write_opts.blockalign = 1;
278+ ds->write_opts.quiet = 1;
279+
280+ debug("initialize_ds_nand(dev=%p, ds=%p): ", dev, ds);
281+ debug("nand=%p, ptr=%p, buf=%p, off=0x%x\n", ds->nand, ds->ptr, ds->buf, ds->off);
282+
283+ return RET_NOTHING;
284+}
285+
286+static int erase_flash_verify_nand(struct urb *urb, struct dnload_state *ds,
287+ unsigned long erasesize, unsigned long size)
288+{
289+ struct usb_device_instance *dev = urb->device;
290+ int rc;
291+
292+ debug("erase_flash_verify_nand(urb=%p, ds=%p, erase=0x%x size=0x%x)\n",
293+ urb, ds, erasesize, size);
294+
295+ if (erasesize == ds->nand->erasesize) {
296+ /* we're only writing a single block and need to
297+ * do bad block skipping / offset adjustments our own */
298+ while (ds->nand->block_isbad(ds->nand, ds->off)) {
299+ debug("SKIP_ONE_BLOCK(0x%08x)!!\n", ds->off);
300+ ds->off += ds->nand->erasesize;
301+ }
302+ }
303+
304+ /* we have finished one eraseblock, flash it */
305+ ds->erase_opts.offset = ds->off;
306+ ds->erase_opts.length = erasesize;
307+ debug("Erasing 0x%x bytes @ offset 0x%x (jffs=%u)\n",
308+ ds->erase_opts.length, ds->erase_opts.offset,
309+ ds->erase_opts.jffs2);
310+ rc = nand_erase_opts(ds->nand, &ds->erase_opts);
311+ if (rc) {
312+ debug("Error erasing\n");
313+ dev->dfu_state = DFU_STATE_dfuERROR;
314+ dev->dfu_status = DFU_STATUS_errERASE;
315+ return RET_STALL;
316+ }
317+
318+ ds->write_opts.buffer = ds->buf;
319+ ds->write_opts.length = size;
320+ ds->write_opts.offset = ds->off;
321+ debug("Writing 0x%x bytes @ offset 0x%x\n", size, ds->off);
322+ rc = nand_write_opts(ds->nand, &ds->write_opts);
323+ if (rc) {
324+ debug("Error writing\n");
325+ dev->dfu_state = DFU_STATE_dfuERROR;
326+ dev->dfu_status = DFU_STATUS_errWRITE;
327+ return RET_STALL;
328+ }
329+
330+ ds->off += size;
331+ ds->ptr = ds->buf;
332+
333+ /* FIXME: implement verify! */
334+ return RET_NOTHING;
335+}
336+
337+static int erase_tail_clean_nand(struct urb *urb, struct dnload_state *ds)
338+{
339+ struct usb_device_instance *dev = urb->device;
340+ int rc;
341+
342+ ds->erase_opts.offset = ds->off;
343+ ds->erase_opts.length = ds->part->size-ds->off;
344+ debug("Erasing 0x%x bytes @ offset 0x%x (jffs=%u)\n",
345+ ds->erase_opts.length, ds->erase_opts.offset,
346+ ds->erase_opts.jffs2);
347+ rc = nand_erase_opts(ds->nand, &ds->erase_opts);
348+ if (rc) {
349+ debug("Error erasing\n");
350+ dev->dfu_state = DFU_STATE_dfuERROR;
351+ dev->dfu_status = DFU_STATUS_errERASE;
352+ return RET_STALL;
353+ }
354+
355+ ds->off += ds->part->size; /* for consistency */
356+
357+ return RET_NOTHING;
358+}
359+
360+/* Read the next erase blcok from NAND into buffer */
361+static int read_next_nand(struct urb *urb, struct dnload_state *ds)
362+{
363+ struct usb_device_instance *dev = urb->device;
364+ int rc;
365+
366+ ds->read_opts.buffer = ds->buf;
367+ ds->read_opts.length = ds->nand->erasesize;
368+ ds->read_opts.offset = ds->off;
369+ ds->read_opts.quiet = 1;
370+
371+ debug("Reading 0x%x@0x%x to 0x%08p\n", ds->nand->erasesize,
372+ ds->off, ds->buf);
373+ rc = nand_read_opts(ds->nand, &ds->read_opts);
374+ if (rc) {
375+ debug("Error reading\n");
376+ dev->dfu_state = DFU_STATE_dfuERROR;
377+ dev->dfu_status = DFU_STATUS_errWRITE;
378+ return RET_STALL;
379+ }
380+ ds->off += ds->nand->erasesize;
381+ ds->ptr = ds->buf;
382+
383+ return RET_NOTHING;
384+}
385+
386+
387+static int handle_dnload(struct urb *urb, u_int16_t val, u_int16_t len, int first)
388+{
389+ struct usb_device_instance *dev = urb->device;
390+ struct dnload_state *ds = &_dnstate;
391+ unsigned int actual_len = len;
392+ unsigned int remain_len;
393+ unsigned long size;
394+ int rc;
395+
396+ debug("download(len=%u, first=%u) ", len, first);
397+
398+ if (len > CONFIG_USBD_DFU_XFER_SIZE) {
399+ /* Too big. Not that we'd really care, but it's a
400+ * DFU protocol violation */
401+ debug("length exceeds flash page size ");
402+ dev->dfu_state = DFU_STATE_dfuERROR;
403+ dev->dfu_status = DFU_STATUS_errADDRESS;
404+ return RET_STALL;
405+ }
406+
407+ if (first) {
408+ /* Make sure that we have a valid mtd partition table */
409+ char *mtdp = getenv("mtdparts");
410+ if (!mtdp)
411+ run_command("dynpart", 0);
412+ }
413+
414+ if (len == 0) {
415+ debug("zero-size write -> MANIFEST_SYNC ");
416+ dev->dfu_state = DFU_STATE_dfuMANIFEST_SYNC;
417+
418+ /* cleanup */
419+ switch (dev->alternate) {
420+ char buf[12];
421+ case 0:
422+ sprintf(buf, "%lx", ds->ptr - ds->buf);
423+ setenv("filesize", buf);
424+ ds->ptr = ds->buf;
425+ break;
426+ case 1:
427+ if (ds->ptr >
428+ ds->buf + sizeof(struct uboot_dfu_trailer)) {
429+ struct uboot_dfu_trailer trailer;
430+ dfu_trailer_mirror(&trailer, ds->ptr);
431+ if (!dfu_trailer_matching(&trailer)) {
432+ printf("DFU TRAILER NOT OK\n");
433+ dev->dfu_state = DFU_STATE_dfuERROR;
434+ dev->dfu_status = DFU_STATUS_errTARGET;
435+ return RET_STALL;
436+ }
437+
438+ rc = erase_flash_verify_nand(urb, ds,
439+ ds->part->size,
440+ ds->part_net_size);
441+ /* re-write dynenv marker in OOB */
442+ run_command("dynenv set u-boot_env", 0);
443+ }
444+ ds->nand = NULL;
445+ free(ds->buf);
446+ ds->ptr = ds->buf = ds->_buf;
447+ break;
448+ default:
449+ rc = 0;
450+ if (ds->ptr > ds->buf)
451+ rc = erase_flash_verify_nand(urb, ds,
452+ ds->nand->erasesize,
453+ ds->nand->erasesize);
454+ /* rootfs partition */
455+ if (!rc && dev->alternate == 5)
456+ rc = erase_tail_clean_nand(urb, ds);
457+
458+ ds->nand = NULL;
459+ break;
460+ }
461+
462+ return RET_ZLP;
463+ }
464+
465+ if (urb->actual_length != len) {
466+ debug("urb->actual_length(%u) != len(%u) ?!? ",
467+ urb->actual_length, len);
468+ dev->dfu_state = DFU_STATE_dfuERROR;
469+ dev->dfu_status = DFU_STATUS_errADDRESS;
470+ return RET_STALL;
471+ }
472+
473+ if (first && ds->buf && ds->buf != ds->_buf && ds->buf != LOAD_ADDR) {
474+ free(ds->buf);
475+ ds->buf = ds->_buf;
476+ }
477+
478+ switch (dev->alternate) {
479+ case 0:
480+ if (first) {
481+ printf("Starting DFU DOWNLOAD to RAM (0x%08p)\n",
482+ LOAD_ADDR);
483+ ds->buf = LOAD_ADDR;
484+ ds->ptr = ds->buf;
485+ }
486+
487+ memcpy(ds->ptr, urb->buffer, len);
488+ ds->ptr += len;
489+ break;
490+ case 1:
491+ if (first) {
492+ rc = initialize_ds_nand(dev, ds);
493+ if (rc)
494+ return rc;
495+ ds->buf = malloc(ds->part_net_size);
496+ if (!ds->buf) {
497+ printf("No memory for atomic buffer!!\n");
498+ dev->dfu_state = DFU_STATE_dfuERROR;
499+ dev->dfu_status = DFU_STATUS_errUNKNOWN;
500+ return RET_STALL;
501+ }
502+ ds->ptr = ds->buf;
503+ printf("Starting Atomic DFU DOWNLOAD to partition '%s'\n",
504+ ds->part->name);
505+ }
506+
507+ remain_len = (ds->buf + ds->part_net_size) - ds->ptr;
508+ if (remain_len < len) {
509+ len = remain_len;
510+ printf("End of write exceeds partition end\n");
511+ dev->dfu_state = DFU_STATE_dfuERROR;
512+ dev->dfu_status = DFU_STATUS_errADDRESS;
513+ return RET_STALL;
514+ }
515+ memcpy(ds->ptr, urb->buffer, len);
516+ ds->ptr += len;
517+ break;
518+ default:
519+ if (first) {
520+ rc = initialize_ds_nand(dev, ds);
521+ if (rc)
522+ return rc;
523+ printf("Starting DFU DOWNLOAD to partition '%s'\n",
524+ ds->part->name);
525+ }
526+
527+ size = ds->nand->erasesize;
528+ remain_len = ds->buf + size - ds->ptr;
529+ if (remain_len < len)
530+ actual_len = remain_len;
531+
532+ memcpy(ds->ptr, urb->buffer, actual_len);
533+ ds->ptr += actual_len;
534+
535+ /* check partition end */
536+ if (ds->off + (ds->ptr - ds->buf) > ds->part->offset + ds->part->size) {
537+ printf("End of write exceeds partition end\n");
538+ dev->dfu_state = DFU_STATE_dfuERROR;
539+ dev->dfu_status = DFU_STATUS_errADDRESS;
540+ return RET_STALL;
541+ }
542+
543+ if (ds->ptr >= ds->buf + size) {
544+ rc = erase_flash_verify_nand(urb, ds,
545+ ds->nand->erasesize,
546+ ds->nand->erasesize);
547+ if (rc)
548+ return rc;
549+ /* copy remainder of data into buffer */
550+ memcpy(ds->ptr, urb->buffer + actual_len, len - actual_len);
551+ ds->ptr += (len - actual_len);
552+ }
553+ break;
554+ }
555+
556+ return RET_ZLP;
557+}
558+
559+static int handle_upload(struct urb *urb, u_int16_t val, u_int16_t len, int first)
560+{
561+ struct usb_device_instance *dev = urb->device;
562+ struct dnload_state *ds = &_dnstate;
563+ unsigned int remain;
564+ int rc;
565+
566+ debug("upload(val=0x%02x, len=%u, first=%u) ", val, len, first);
567+
568+ if (len > CONFIG_USBD_DFU_XFER_SIZE) {
569+ /* Too big */
570+ dev->dfu_state = DFU_STATE_dfuERROR;
571+ dev->dfu_status = DFU_STATUS_errADDRESS;
572+ //udc_ep0_send_stall();
573+ debug("Error: Transfer size > CONFIG_USBD_DFU_XFER_SIZE ");
574+ return -EINVAL;
575+ }
576+
577+ switch (dev->alternate) {
578+ case 0:
579+ if (first) {
580+ printf("Starting DFU Upload of RAM (0x%08p)\n",
581+ LOAD_ADDR);
582+ ds->ptr = ds->buf;
583+ }
584+
585+ /* FIXME: end at some more dynamic point */
586+ if (ds->ptr + len > LOAD_ADDR + 0x200000)
587+ len = (LOAD_ADDR + 0x200000) - ds->ptr;
588+
589+ urb->buffer = ds->ptr;
590+ urb->actual_length = len;
591+ ds->ptr += len;
592+ break;
593+ default:
594+ if (first) {
595+ rc = initialize_ds_nand(dev, ds);
596+ if (rc)
597+ return -EINVAL;
598+ printf("Starting DFU Upload of partition '%s'\n",
599+ ds->part->name);
600+ rc = read_next_nand(urb, ds);
601+ if (rc)
602+ return -EINVAL;
603+ }
604+
605+ if (len > ds->nand->erasesize) {
606+ printf("We don't support transfers bigger than %u\n",
607+ ds->nand->erasesize);
608+ len = ds->nand->erasesize;
609+ }
610+
611+ remain = ds->nand->erasesize - (ds->ptr - ds->buf);
612+ if (len < remain)
613+ remain = len;
614+
615+ debug("copying %u bytes ", remain);
616+ urb->buffer = ds->ptr;
617+ ds->ptr += remain;
618+ urb->actual_length = remain;
619+
620+ if (ds->ptr >= ds->buf + ds->nand->erasesize &&
621+ ds->off < ds->part->offset + ds->part->size) {
622+ rc = read_next_nand(urb, ds);
623+ if (rc)
624+ return -EINVAL;
625+ if (len > remain) {
626+ debug("copying another %u bytes ", len - remain);
627+ memcpy(urb->buffer + remain, ds->ptr, len - remain);
628+ ds->ptr += (len - remain);
629+ urb->actual_length += (len - remain);
630+ }
631+ }
632+ break;
633+ }
634+
635+ debug("returning len=%u\n", len);
636+ return len;
637+}
638+
639+static void handle_getstatus(struct urb *urb, int max)
640+{
641+ struct usb_device_instance *dev = urb->device;
642+ struct dfu_status *dstat = (struct dfu_status *) urb->buffer;
643+
644+ debug("getstatus ");
645+
646+ if (!urb->buffer || urb->buffer_length < sizeof(*dstat)) {
647+ debug("invalid urb! ");
648+ return;
649+ }
650+
651+ switch (dev->dfu_state) {
652+ case DFU_STATE_dfuDNLOAD_SYNC:
653+ case DFU_STATE_dfuDNBUSY:
654+#if 0
655+ if (fsr & AT91C_MC_PROGE) {
656+ debug("errPROG ");
657+ dev->dfu_status = DFU_STATUS_errPROG;
658+ dev->dfu_state = DFU_STATE_dfuERROR;
659+ } else if (fsr & AT91C_MC_LOCKE) {
660+ debug("errWRITE ");
661+ dev->dfu_status = DFU_STATUS_errWRITE;
662+ dev->dfu_state = DFU_STATE_dfuERROR;
663+ } else if (fsr & AT91C_MC_FRDY) {
664+#endif
665+ debug("DNLOAD_IDLE ");
666+ dev->dfu_state = DFU_STATE_dfuDNLOAD_IDLE;
667+#if 0
668+ } else {
669+ debug("DNBUSY ");
670+ dev->dfu_state = DFU_STATE_dfuDNBUSY;
671+ }
672+#endif
673+ break;
674+ case DFU_STATE_dfuMANIFEST_SYNC:
675+ break;
676+ default:
677+ //return;
678+ break;
679+ }
680+
681+ /* send status response */
682+ dstat->bStatus = dev->dfu_status;
683+ dstat->bState = dev->dfu_state;
684+ dstat->iString = 0;
685+ /* FIXME: set dstat->bwPollTimeout */
686+ urb->actual_length = MIN(sizeof(*dstat), max);
687+
688+ /* we don't need to explicitly send data here, will
689+ * be done by the original caller! */
690+}
691+
692+static void handle_getstate(struct urb *urb, int max)
693+{
694+ debug("getstate ");
695+
696+ if (!urb->buffer || urb->buffer_length < sizeof(u_int8_t)) {
697+ debug("invalid urb! ");
698+ return;
699+ }
700+
701+ urb->buffer[0] = urb->device->dfu_state & 0xff;
702+ urb->actual_length = sizeof(u_int8_t);
703+}
704+
705+#ifndef CONFIG_USBD_PRODUCTID_DFU
706+#define CONFIG_USBD_PRODUCTID_DFU CONFIG_USBD_PRODUCTID_CDCACM
707+#endif
708+
709+static const struct usb_device_descriptor dfu_dev_descriptor = {
710+ .bLength = USB_DT_DEVICE_SIZE,
711+ .bDescriptorType = USB_DT_DEVICE,
712+ .bcdUSB = 0x0100,
713+ .bDeviceClass = 0x00,
714+ .bDeviceSubClass = 0x00,
715+ .bDeviceProtocol = 0x00,
716+ .bMaxPacketSize0 = EP0_MAX_PACKET_SIZE,
717+ .idVendor = CONFIG_USBD_VENDORID,
718+ .idProduct = CONFIG_USBD_PRODUCTID_DFU,
719+ .bcdDevice = 0x0000,
720+ .iManufacturer = DFU_STR_MANUFACTURER,
721+ .iProduct = DFU_STR_PRODUCT,
722+ .iSerialNumber = DFU_STR_SERIAL,
723+ .bNumConfigurations = 0x01,
724+};
725+
726+static const struct _dfu_desc dfu_cfg_descriptor = {
727+ .ucfg = {
728+ .bLength = USB_DT_CONFIG_SIZE,
729+ .bDescriptorType = USB_DT_CONFIG,
730+ .wTotalLength = USB_DT_CONFIG_SIZE +
731+ DFU_NUM_ALTERNATES * USB_DT_INTERFACE_SIZE +
732+ USB_DT_DFU_SIZE,
733+ .bNumInterfaces = 5,
734+ .bConfigurationValue = 1,
735+ .iConfiguration = DFU_STR_CONFIG,
736+ .bmAttributes = BMATTRIBUTE_RESERVED,
737+ .bMaxPower = 50,
738+ },
739+ .uif[0] = {
740+ .bLength = USB_DT_INTERFACE_SIZE,
741+ .bDescriptorType = USB_DT_INTERFACE,
742+ .bInterfaceNumber = 0x00,
743+ .bAlternateSetting = 0x00,
744+ .bNumEndpoints = 0x00,
745+ .bInterfaceClass = 0xfe,
746+ .bInterfaceSubClass = 0x01,
747+ .bInterfaceProtocol = 0x02,
748+ .iInterface = DFU_STR_ALT0,
749+ },
750+ .uif[1] = {
751+ .bLength = USB_DT_INTERFACE_SIZE,
752+ .bDescriptorType = USB_DT_INTERFACE,
753+ .bInterfaceNumber = 0x00,
754+ .bAlternateSetting = 0x01,
755+ .bNumEndpoints = 0x00,
756+ .bInterfaceClass = 0xfe,
757+ .bInterfaceSubClass = 0x01,
758+ .bInterfaceProtocol = 0x02,
759+ .iInterface = DFU_STR_ALT1,
760+ },
761+ .uif[2] = {
762+ .bLength = USB_DT_INTERFACE_SIZE,
763+ .bDescriptorType = USB_DT_INTERFACE,
764+ .bInterfaceNumber = 0x00,
765+ .bAlternateSetting = 0x02,
766+ .bNumEndpoints = 0x00,
767+ .bInterfaceClass = 0xfe,
768+ .bInterfaceSubClass = 0x01,
769+ .bInterfaceProtocol = 0x02,
770+ .iInterface = DFU_STR_ALT2,
771+ },
772+ .uif[3] = {
773+ .bLength = USB_DT_INTERFACE_SIZE,
774+ .bDescriptorType = USB_DT_INTERFACE,
775+ .bInterfaceNumber = 0x00,
776+ .bAlternateSetting = 0x03,
777+ .bNumEndpoints = 0x00,
778+ .bInterfaceClass = 0xfe,
779+ .bInterfaceSubClass = 0x01,
780+ .bInterfaceProtocol = 0x02,
781+ .iInterface = DFU_STR_ALT3,
782+ },
783+ .uif[4] = {
784+ .bLength = USB_DT_INTERFACE_SIZE,
785+ .bDescriptorType = USB_DT_INTERFACE,
786+ .bInterfaceNumber = 0x00,
787+ .bAlternateSetting = 0x04,
788+ .bNumEndpoints = 0x00,
789+ .bInterfaceClass = 0xfe,
790+ .bInterfaceSubClass = 0x01,
791+ .bInterfaceProtocol = 0x02,
792+ .iInterface = DFU_STR_ALT4,
793+ },
794+ .uif[5] = {
795+ .bLength = USB_DT_INTERFACE_SIZE,
796+ .bDescriptorType = USB_DT_INTERFACE,
797+ .bInterfaceNumber = 0x00,
798+ .bAlternateSetting = 0x05,
799+ .bNumEndpoints = 0x00,
800+ .bInterfaceClass = 0xfe,
801+ .bInterfaceSubClass = 0x01,
802+ .bInterfaceProtocol = 0x02,
803+ .iInterface = DFU_STR_ALT5,
804+ },
805+ .func_dfu = DFU_FUNC_DESC,
806+};
807+
808+int dfu_ep0_handler(struct urb *urb)
809+{
810+ int rc, ret = RET_NOTHING;
811+ u_int8_t req = urb->device_request.bRequest;
812+ u_int16_t val = urb->device_request.wValue;
813+ u_int16_t len = urb->device_request.wLength;
814+ struct usb_device_instance *dev = urb->device;
815+
816+ debug("dfu_ep0(req=0x%x, val=0x%x, len=%u) old_state = %u ",
817+ req, val, len, dev->dfu_state);
818+
819+ switch (dev->dfu_state) {
820+ case DFU_STATE_appIDLE:
821+ switch (req) {
822+ case USB_REQ_DFU_GETSTATUS:
823+ handle_getstatus(urb, len);
824+ break;
825+ case USB_REQ_DFU_GETSTATE:
826+ handle_getstate(urb, len);
827+ break;
828+ case USB_REQ_DFU_DETACH:
829+ dev->dfu_state = DFU_STATE_appDETACH;
830+ ret = RET_ZLP;
831+ goto out;
832+ break;
833+ default:
834+ ret = RET_STALL;
835+ }
836+ break;
837+ case DFU_STATE_appDETACH:
838+ switch (req) {
839+ case USB_REQ_DFU_GETSTATUS:
840+ handle_getstatus(urb, len);
841+ break;
842+ case USB_REQ_DFU_GETSTATE:
843+ handle_getstate(urb, len);
844+ break;
845+ default:
846+ dev->dfu_state = DFU_STATE_appIDLE;
847+ ret = RET_STALL;
848+ goto out;
849+ break;
850+ }
851+ /* FIXME: implement timer to return to appIDLE */
852+ break;
853+ case DFU_STATE_dfuIDLE:
854+ switch (req) {
855+ case USB_REQ_DFU_DNLOAD:
856+ if (len == 0) {
857+ dev->dfu_state = DFU_STATE_dfuERROR;
858+ ret = RET_STALL;
859+ goto out;
860+ }
861+ dev->dfu_state = DFU_STATE_dfuDNLOAD_SYNC;
862+ ret = handle_dnload(urb, val, len, 1);
863+ break;
864+ case USB_REQ_DFU_UPLOAD:
865+ dev->dfu_state = DFU_STATE_dfuUPLOAD_IDLE;
866+ handle_upload(urb, val, len, 1);
867+ break;
868+ case USB_REQ_DFU_ABORT:
869+ /* no zlp? */
870+ ret = RET_ZLP;
871+ break;
872+ case USB_REQ_DFU_GETSTATUS:
873+ handle_getstatus(urb, len);
874+ break;
875+ case USB_REQ_DFU_GETSTATE:
876+ handle_getstate(urb, len);
877+ break;
878+ case USB_REQ_DFU_DETACH:
879+ /* Proprietary extension: 'detach' from idle mode and
880+ * get back to runtime mode in case of USB Reset. As
881+ * much as I dislike this, we just can't use every USB
882+ * bus reset to switch back to runtime mode, since at
883+ * least the Linux USB stack likes to send a number of resets
884+ * in a row :( */
885+ dev->dfu_state = DFU_STATE_dfuMANIFEST_WAIT_RST;
886+ break;
887+ default:
888+ dev->dfu_state = DFU_STATE_dfuERROR;
889+ ret = RET_STALL;
890+ goto out;
891+ break;
892+ }
893+ break;
894+ case DFU_STATE_dfuDNLOAD_SYNC:
895+ switch (req) {
896+ case USB_REQ_DFU_GETSTATUS:
897+ handle_getstatus(urb, len);
898+ /* FIXME: state transition depending on block completeness */
899+ break;
900+ case USB_REQ_DFU_GETSTATE:
901+ handle_getstate(urb, len);
902+ break;
903+ default:
904+ dev->dfu_state = DFU_STATE_dfuERROR;
905+ ret = RET_STALL;
906+ goto out;
907+ }
908+ break;
909+ case DFU_STATE_dfuDNBUSY:
910+ switch (req) {
911+ case USB_REQ_DFU_GETSTATUS:
912+ /* FIXME: only accept getstatus if bwPollTimeout
913+ * has elapsed */
914+ handle_getstatus(urb, len);
915+ break;
916+ default:
917+ dev->dfu_state = DFU_STATE_dfuERROR;
918+ ret = RET_STALL;
919+ goto out;
920+ }
921+ break;
922+ case DFU_STATE_dfuDNLOAD_IDLE:
923+ switch (req) {
924+ case USB_REQ_DFU_DNLOAD:
925+ dev->dfu_state = DFU_STATE_dfuDNLOAD_SYNC;
926+ ret = handle_dnload(urb, val, len, 0);
927+ break;
928+ case USB_REQ_DFU_ABORT:
929+ dev->dfu_state = DFU_STATE_dfuIDLE;
930+ ret = RET_ZLP;
931+ break;
932+ case USB_REQ_DFU_GETSTATUS:
933+ handle_getstatus(urb, len);
934+ break;
935+ case USB_REQ_DFU_GETSTATE:
936+ handle_getstate(urb, len);
937+ break;
938+ default:
939+ dev->dfu_state = DFU_STATE_dfuERROR;
940+ ret = RET_STALL;
941+ break;
942+ }
943+ break;
944+ case DFU_STATE_dfuMANIFEST_SYNC:
945+ switch (req) {
946+ case USB_REQ_DFU_GETSTATUS:
947+ /* We're MainfestationTolerant */
948+ dev->dfu_state = DFU_STATE_dfuIDLE;
949+ handle_getstatus(urb, len);
950+ break;
951+ case USB_REQ_DFU_GETSTATE:
952+ handle_getstate(urb, len);
953+ break;
954+ default:
955+ dev->dfu_state = DFU_STATE_dfuERROR;
956+ ret = RET_STALL;
957+ break;
958+ }
959+ break;
960+ case DFU_STATE_dfuMANIFEST:
961+ /* we should never go here */
962+ dev->dfu_state = DFU_STATE_dfuERROR;
963+ ret = RET_STALL;
964+ break;
965+ case DFU_STATE_dfuMANIFEST_WAIT_RST:
966+ /* we should never go here */
967+ break;
968+ case DFU_STATE_dfuUPLOAD_IDLE:
969+ switch (req) {
970+ case USB_REQ_DFU_UPLOAD:
971+ /* state transition if less data then requested */
972+ rc = handle_upload(urb, val, len, 0);
973+ if (rc >= 0 && rc < len)
974+ dev->dfu_state = DFU_STATE_dfuIDLE;
975+ break;
976+ case USB_REQ_DFU_ABORT:
977+ dev->dfu_state = DFU_STATE_dfuIDLE;
978+ /* no zlp? */
979+ ret = RET_ZLP;
980+ break;
981+ case USB_REQ_DFU_GETSTATUS:
982+ handle_getstatus(urb, len);
983+ break;
984+ case USB_REQ_DFU_GETSTATE:
985+ handle_getstate(urb, len);
986+ break;
987+ default:
988+ dev->dfu_state = DFU_STATE_dfuERROR;
989+ ret = RET_STALL;
990+ break;
991+ }
992+ break;
993+ case DFU_STATE_dfuERROR:
994+ switch (req) {
995+ case USB_REQ_DFU_GETSTATUS:
996+ handle_getstatus(urb, len);
997+ break;
998+ case USB_REQ_DFU_GETSTATE:
999+ handle_getstate(urb, len);
1000+ break;
1001+ case USB_REQ_DFU_CLRSTATUS:
1002+ dev->dfu_state = DFU_STATE_dfuIDLE;
1003+ dev->dfu_status = DFU_STATUS_OK;
1004+ /* no zlp? */
1005+ ret = RET_ZLP;
1006+ break;
1007+ default:
1008+ dev->dfu_state = DFU_STATE_dfuERROR;
1009+ ret = RET_STALL;
1010+ break;
1011+ }
1012+ break;
1013+ default:
1014+ return DFU_EP0_UNHANDLED;
1015+ break;
1016+ }
1017+
1018+out:
1019+ debug("new_state = %u, ret = %u\n", dev->dfu_state, ret);
1020+
1021+ switch (ret) {
1022+ case RET_ZLP:
1023+ //udc_ep0_send_zlp();
1024+ urb->actual_length = 0;
1025+ return DFU_EP0_ZLP;
1026+ break;
1027+ case RET_STALL:
1028+ //udc_ep0_send_stall();
1029+ return DFU_EP0_STALL;
1030+ break;
1031+ case RET_NOTHING:
1032+ break;
1033+ }
1034+
1035+ return DFU_EP0_DATA;
1036+}
1037+
1038+void str2wide (char *str, u16 * wide);
1039+static struct usb_string_descriptor *create_usbstring(char *string)
1040+{
1041+ struct usb_string_descriptor *strdesc;
1042+ int size = sizeof(*strdesc) + strlen(string)*2;
1043+
1044+ if (size > 255)
1045+ return NULL;
1046+
1047+ strdesc = malloc(size);
1048+ if (!strdesc)
1049+ return NULL;
1050+
1051+ strdesc->bLength = size;
1052+ strdesc->bDescriptorType = USB_DT_STRING;
1053+ str2wide(string, strdesc->wData);
1054+
1055+ return strdesc;
1056+}
1057+
1058+
1059+static void dfu_init_strings(struct usb_device_instance *dev)
1060+{
1061+ int i;
1062+ struct usb_string_descriptor *strdesc;
1063+
1064+ strdesc = create_usbstring(CONFIG_DFU_CFG_STR);
1065+ usb_strings[DFU_STR_CONFIG] = strdesc;
1066+
1067+ for (i = 0; i < DFU_NUM_ALTERNATES; i++) {
1068+ if (i == 0) {
1069+ strdesc = create_usbstring(CONFIG_DFU_ALT0_STR);
1070+ } else {
1071+ struct part_info *part = get_partition_nand(i-1);
1072+
1073+ if (part)
1074+ strdesc = create_usbstring(part->name);
1075+ else
1076+ strdesc =
1077+ create_usbstring("undefined partition");
1078+ }
1079+ if (!strdesc)
1080+ continue;
1081+ usb_strings[STR_COUNT+i+1] = strdesc;
1082+ }
1083+}
1084+
1085+int dfu_init_instance(struct usb_device_instance *dev)
1086+{
1087+ dev->dfu_dev_desc = &dfu_dev_descriptor;
1088+ dev->dfu_cfg_desc = &dfu_cfg_descriptor;
1089+ dev->dfu_state = DFU_STATE_appIDLE;
1090+ dev->dfu_status = DFU_STATUS_OK;
1091+
1092+ if (system_dfu_state)
1093+ printf("SURPRISE: system_dfu_state is already set\n");
1094+ system_dfu_state = &dev->dfu_state;
1095+
1096+ dfu_init_strings(dev);
1097+
1098+ return 0;
1099+}
1100+
1101+static int stdout_switched;
1102+
1103+/* event handler for usb device state events */
1104+void dfu_event(struct usb_device_instance *device,
1105+ usb_device_event_t event, int data)
1106+{
1107+ char *out;
1108+
1109+ switch (event) {
1110+ case DEVICE_RESET:
1111+ switch (device->dfu_state) {
1112+ case DFU_STATE_appDETACH:
1113+ device->dfu_state = DFU_STATE_dfuIDLE;
1114+ out = getenv("stdout");
1115+ if (out && !strcmp(out, "usbtty")) {
1116+ setenv("stdout", "vga");
1117+ setenv("stderr", "vga");
1118+ stdout_switched = 1;
1119+ }
1120+ printf("DFU: Switching to DFU Mode\n");
1121+ break;
1122+ case DFU_STATE_dfuMANIFEST_WAIT_RST:
1123+ device->dfu_state = DFU_STATE_appIDLE;
1124+ printf("DFU: Switching back to Runtime mode\n");
1125+ if (stdout_switched) {
1126+ setenv("stdout", "usbtty");
1127+ setenv("stderr", "usbtty");
1128+ stdout_switched = 0;
1129+ }
1130+ break;
1131+ default:
1132+ break;
1133+ }
1134+ break;
1135+ case DEVICE_CONFIGURED:
1136+ case DEVICE_DE_CONFIGURED:
1137+ debug("SET_CONFIGURATION(%u) ", device->configuration);
1138+ /* fallthrough */
1139+ case DEVICE_SET_INTERFACE:
1140+ debug("SET_INTERFACE(%u,%u) old_state = %u ",
1141+ device->interface, device->alternate,
1142+ device->dfu_state);
1143+ switch (device->dfu_state) {
1144+ case DFU_STATE_appIDLE:
1145+ case DFU_STATE_appDETACH:
1146+ case DFU_STATE_dfuIDLE:
1147+ case DFU_STATE_dfuMANIFEST_WAIT_RST:
1148+ /* do nothing, we're fine */
1149+ break;
1150+ case DFU_STATE_dfuDNLOAD_SYNC:
1151+ case DFU_STATE_dfuDNBUSY:
1152+ case DFU_STATE_dfuDNLOAD_IDLE:
1153+ case DFU_STATE_dfuMANIFEST:
1154+ device->dfu_state = DFU_STATE_dfuERROR;
1155+ device->dfu_status = DFU_STATUS_errNOTDONE;
1156+ /* FIXME: free malloc()ed buffer! */
1157+ break;
1158+ case DFU_STATE_dfuMANIFEST_SYNC:
1159+ case DFU_STATE_dfuUPLOAD_IDLE:
1160+ case DFU_STATE_dfuERROR:
1161+ device->dfu_state = DFU_STATE_dfuERROR;
1162+ device->dfu_status = DFU_STATUS_errUNKNOWN;
1163+ break;
1164+ }
1165+ debug("new_state = %u\n", device->dfu_state);
1166+ break;
1167+ default:
1168+ break;
1169+ }
1170+}
1171+#endif /* CONFIG_USBD_DFU */
1172Index: u-boot/drivers/Makefile
1173===================================================================
1174--- u-boot.orig/drivers/Makefile
1175+++ u-boot/drivers/Makefile
1176@@ -47,7 +47,7 @@
1177 status_led.o sym53c8xx.o systemace.o ahci.o \
1178 ti_pci1410a.o tigon3.o tsec.o \
1179 tsi108_eth.o tsi108_i2c.o tsi108_pci.o \
1180- usbdcore.o usbdcore_ep0.o usbdcore_omap1510.o usbdcore_s3c2410.o usbtty.o \
1181+ usbdcore.o usbdfu.o usbdcore_ep0.o usbdcore_omap1510.o usbdcore_s3c2410.o usbtty.o \
1182 videomodes.o w83c553f.o \
1183 ks8695eth.o \
1184 pcf50606.o \
1185Index: u-boot/drivers/usbdcore.c
1186===================================================================
1187--- u-boot.orig/drivers/usbdcore.c
1188+++ u-boot/drivers/usbdcore.c
1189@@ -31,6 +31,7 @@
1190
1191 #include <malloc.h>
1192 #include "usbdcore.h"
1193+#include <usb_dfu.h>
1194
1195 #define MAX_INTERFACES 2
1196
1197@@ -212,6 +213,10 @@
1198 */
1199 struct usb_device_descriptor *usbd_device_device_descriptor (struct usb_device_instance *device, int port)
1200 {
1201+#ifdef CONFIG_USBD_DFU
1202+ if (device->dfu_state != DFU_STATE_appIDLE)
1203+ return device->dfu_dev_desc;
1204+#endif
1205 return (device->device_descriptor);
1206 }
1207
1208@@ -232,6 +237,10 @@
1209 if (!(configuration_instance = usbd_device_configuration_instance (device, port, configuration))) {
1210 return NULL;
1211 }
1212+#ifdef CONFIG_USBD_DFU
1213+ if (device->dfu_state != DFU_STATE_appIDLE)
1214+ return (&device->dfu_cfg_desc->ucfg);
1215+#endif
1216 return (configuration_instance->configuration_descriptor);
1217 }
1218
1219@@ -253,6 +262,13 @@
1220 if (!(interface_instance = usbd_device_interface_instance (device, port, configuration, interface))) {
1221 return NULL;
1222 }
1223+#ifdef CONFIG_USBD_DFU
1224+ if (device->dfu_state != DFU_STATE_appIDLE) {
1225+ if (alternate < 0 || alternate >= DFU_NUM_ALTERNATES)
1226+ return NULL;
1227+ return &device->dfu_cfg_desc->uif[alternate];
1228+ }
1229+#endif
1230 if ((alternate < 0) || (alternate >= interface_instance->alternates)) {
1231 return NULL;
1232 }
1233@@ -681,4 +697,7 @@
1234 /* usbdbg("calling device->event"); */
1235 device->event(device, event, data);
1236 }
1237+#ifdef CONFIG_USBD_DFU
1238+ dfu_event(device, event, data);
1239+#endif
1240 }
1241Index: u-boot/drivers/usbtty.c
1242===================================================================
1243--- u-boot.orig/drivers/usbtty.c
1244+++ u-boot/drivers/usbtty.c
1245@@ -31,6 +31,8 @@
1246 #include "usbtty.h"
1247 #include "usb_cdc_acm.h"
1248 #include "usbdescriptors.h"
1249+#include <usb_dfu_descriptors.h>
1250+#include <usb_dfu.h>
1251 #include <config.h> /* If defined, override Linux identifiers with
1252 * vendor specific ones */
1253
1254@@ -118,7 +120,7 @@
1255 static unsigned short rx_endpoint = 0;
1256 static unsigned short tx_endpoint = 0;
1257 static unsigned short interface_count = 0;
1258-static struct usb_string_descriptor *usbtty_string_table[STR_COUNT];
1259+static struct usb_string_descriptor *usbtty_string_table[NUM_STRINGS];
1260
1261 /* USB Descriptor Strings */
1262 static u8 wstrLang[4] = {4,USB_DT_STRING,0x9,0x4};
1263@@ -169,6 +171,10 @@
1264 struct usb_interface_descriptor data_class_interface;
1265 struct usb_endpoint_descriptor
1266 data_endpoints[NUM_ENDPOINTS-1] __attribute__((packed));
1267+#ifdef CONFIG_USBD_DFU
1268+ struct usb_interface_descriptor uif_dfu;
1269+ struct usb_dfu_func_descriptor func_dfu;
1270+#endif
1271 } __attribute__((packed));
1272
1273 static struct acm_config_desc acm_configuration_descriptors[NUM_CONFIGS] = {
1274@@ -179,7 +185,11 @@
1275 .bDescriptorType = USB_DT_CONFIG,
1276 .wTotalLength =
1277 cpu_to_le16(sizeof(struct acm_config_desc)),
1278+#ifdef CONFIG_USBD_DFU
1279+ .bNumInterfaces = NUM_ACM_INTERFACES +1,
1280+#else
1281 .bNumInterfaces = NUM_ACM_INTERFACES,
1282+#endif
1283 .bConfigurationValue = 1,
1284 .iConfiguration = STR_CONFIG,
1285 .bmAttributes =
1286@@ -278,6 +288,11 @@
1287 .bInterval = 0xFF,
1288 },
1289 },
1290+#ifdef CONFIG_USBD_DFU
1291+ /* Interface 3 */
1292+ .uif_dfu = DFU_RT_IF_DESC,
1293+ .func_dfu = DFU_FUNC_DESC,
1294+#endif
1295 },
1296 };
1297
1298@@ -390,7 +405,7 @@
1299 void usbtty_poll (void);
1300
1301 /* utility function for converting char* to wide string used by USB */
1302-static void str2wide (char *str, u16 * wide)
1303+void str2wide (char *str, u16 * wide)
1304 {
1305 int i;
1306 for (i = 0; i < strlen (str) && str[i]; i++){
1307@@ -652,6 +667,9 @@
1308 device_instance->bus = bus_instance;
1309 device_instance->configurations = NUM_CONFIGS;
1310 device_instance->configuration_instance_array = config_instance;
1311+#ifdef CONFIG_USBD_DFU
1312+ dfu_init_instance(device_instance);
1313+#endif
1314
1315 /* initialize bus instance */
1316 memset (bus_instance, 0, sizeof (struct usb_bus_instance));
1317Index: u-boot/include/configs/neo1973_gta01.h
1318===================================================================
1319--- u-boot.orig/include/configs/neo1973_gta01.h
1320+++ u-boot/include/configs/neo1973_gta01.h
1321@@ -167,7 +167,7 @@
1322 */
1323 #define CONFIG_STACKSIZE (128*1024) /* regular stack */
1324 #ifdef CONFIG_USE_IRQ
1325-#define CONFIG_STACKSIZE_IRQ (4*1024) /* IRQ stack */
1326+#define CONFIG_STACKSIZE_IRQ (8*1024) /* IRQ stack */
1327 #define CONFIG_STACKSIZE_FIQ (4*1024) /* FIQ stack */
1328 #endif
1329
1330@@ -184,6 +184,10 @@
1331 #define CONFIG_USBD_MANUFACTURER "OpenMoko, Inc"
1332 #define CONFIG_USBD_PRODUCT_NAME "Neo1973 Bootloader " U_BOOT_VERSION
1333 #define CONFIG_EXTRA_ENV_SETTINGS "usbtty=cdc_acm\0"
1334+#define CONFIG_USBD_DFU 1
1335+#define CONFIG_USBD_DFU_XFER_SIZE 4096 /* 0x4000 */
1336+#define CONFIG_USBD_DFU_INTERFACE 2
1337+
1338
1339 /*-----------------------------------------------------------------------
1340 * Physical Memory Map
1341Index: u-boot/include/usb_dfu.h
1342===================================================================
1343--- /dev/null
1344+++ u-boot/include/usb_dfu.h
1345@@ -0,0 +1,99 @@
1346+#ifndef _DFU_H
1347+#define _DFU_H
1348+
1349+/* USB Device Firmware Update Implementation for u-boot
1350+ * (C) 2007 by OpenMoko, Inc.
1351+ * Author: Harald Welte <laforge@openmoko.org>
1352+ *
1353+ * based on: USB Device Firmware Update Implementation for OpenPCD
1354+ * (C) 2006 by Harald Welte <hwelte@hmw-consulting.de>
1355+ *
1356+ * This ought to be compliant to the USB DFU Spec 1.0 as available from
1357+ * http://www.usb.org/developers/devclass_docs/usbdfu10.pdf
1358+ *
1359+ * This program is free software; you can redistribute it and/or modify
1360+ * it under the terms of the GNU General Public License as published by
1361+ * the Free Software Foundation; either version 2 of the License, or
1362+ * (at your option) any later version.
1363+ *
1364+ * This program is distributed in the hope that it will be useful,
1365+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1366+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1367+ * GNU General Public License for more details.
1368+ *
1369+ * You should have received a copy of the GNU General Public License
1370+ * along with this program; if not, write to the Free Software
1371+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
1372+ */
1373+
1374+#include <asm/types.h>
1375+#include <usbdescriptors.h>
1376+#include <usb_dfu_descriptors.h>
1377+#include <config.h>
1378+
1379+/* USB DFU functional descriptor */
1380+#define DFU_FUNC_DESC { \
1381+ .bLength = USB_DT_DFU_SIZE, \
1382+ .bDescriptorType = USB_DT_DFU, \
1383+ .bmAttributes = USB_DFU_CAN_UPLOAD | USB_DFU_CAN_DOWNLOAD | USB_DFU_MANIFEST_TOL, \
1384+ .wDetachTimeOut = 0xff00, \
1385+ .wTransferSize = CONFIG_USBD_DFU_XFER_SIZE, \
1386+ .bcdDFUVersion = 0x0100, \
1387+}
1388+
1389+/* USB Interface descriptor in Runtime mode */
1390+#define DFU_RT_IF_DESC { \
1391+ .bLength = USB_DT_INTERFACE_SIZE, \
1392+ .bDescriptorType = USB_DT_INTERFACE, \
1393+ .bInterfaceNumber = CONFIG_USBD_DFU_INTERFACE, \
1394+ .bAlternateSetting = 0x00, \
1395+ .bNumEndpoints = 0x00, \
1396+ .bInterfaceClass = 0xfe, \
1397+ .bInterfaceSubClass = 0x01, \
1398+ .bInterfaceProtocol = 0x01, \
1399+ .iInterface = DFU_STR_CONFIG, \
1400+}
1401+
1402+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
1403+
1404+#define DFU_NUM_ALTERNATES 6
1405+
1406+#define DFU_STR_MANUFACTURER STR_MANUFACTURER
1407+#define DFU_STR_PRODUCT STR_PRODUCT
1408+#define DFU_STR_SERIAL STR_SERIAL
1409+#define DFU_STR_CONFIG (STR_COUNT)
1410+#define DFU_STR_ALT0 (STR_COUNT+1)
1411+#define DFU_STR_ALT1 (STR_COUNT+2)
1412+#define DFU_STR_ALT2 (STR_COUNT+3)
1413+#define DFU_STR_ALT3 (STR_COUNT+4)
1414+#define DFU_STR_ALT4 (STR_COUNT+5)
1415+#define DFU_STR_ALT5 (STR_COUNT+6)
1416+#define DFU_STR_COUNT (STR_COUNT+7)
1417+
1418+#define DFU_NUM_STRINGS (STR_COUNT+8)
1419+
1420+#define CONFIG_DFU_CFG_STR "USB Device Firmware Upgrade"
1421+#define CONFIG_DFU_ALT0_STR "RAM 0x32000000"
1422+
1423+struct _dfu_desc {
1424+ struct usb_configuration_descriptor ucfg;
1425+ struct usb_interface_descriptor uif[DFU_NUM_ALTERNATES];
1426+ struct usb_dfu_func_descriptor func_dfu;
1427+};
1428+
1429+int dfu_init_instance(struct usb_device_instance *dev);
1430+
1431+#define DFU_EP0_NONE 0
1432+#define DFU_EP0_UNHANDLED 1
1433+#define DFU_EP0_STALL 2
1434+#define DFU_EP0_ZLP 3
1435+#define DFU_EP0_DATA 4
1436+
1437+extern volatile enum dfu_state *system_dfu_state; /* for 3rd parties */
1438+
1439+int dfu_ep0_handler(struct urb *urb);
1440+
1441+void dfu_event(struct usb_device_instance *device,
1442+ usb_device_event_t event, int data);
1443+
1444+#endif /* _DFU_H */
1445Index: u-boot/include/usb_dfu_descriptors.h
1446===================================================================
1447--- /dev/null
1448+++ u-boot/include/usb_dfu_descriptors.h
1449@@ -0,0 +1,94 @@
1450+#ifndef _USB_DFU_H
1451+#define _USB_DFU_H
1452+/* USB Device Firmware Update Implementation for OpenPCD
1453+ * (C) 2006 by Harald Welte <hwelte@hmw-consulting.de>
1454+ *
1455+ * Protocol definitions for USB DFU
1456+ *
1457+ * This ought to be compliant to the USB DFU Spec 1.0 as available from
1458+ * http://www.usb.org/developers/devclass_docs/usbdfu10.pdf
1459+ *
1460+ * This program is free software; you can redistribute it and/or modify
1461+ * it under the terms of the GNU General Public License as published by
1462+ * the Free Software Foundation; either version 2 of the License, or
1463+ * (at your option) any later version.
1464+ *
1465+ * This program is distributed in the hope that it will be useful,
1466+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1467+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1468+ * GNU General Public License for more details.
1469+ *
1470+ * You should have received a copy of the GNU General Public License
1471+ * along with this program; if not, write to the Free Software
1472+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
1473+ */
1474+
1475+#include <linux/types.h>
1476+
1477+#define USB_DT_DFU 0x21
1478+
1479+struct usb_dfu_func_descriptor {
1480+ u_int8_t bLength;
1481+ u_int8_t bDescriptorType;
1482+ u_int8_t bmAttributes;
1483+#define USB_DFU_CAN_DOWNLOAD (1 << 0)
1484+#define USB_DFU_CAN_UPLOAD (1 << 1)
1485+#define USB_DFU_MANIFEST_TOL (1 << 2)
1486+#define USB_DFU_WILL_DETACH (1 << 3)
1487+ u_int16_t wDetachTimeOut;
1488+ u_int16_t wTransferSize;
1489+ u_int16_t bcdDFUVersion;
1490+} __attribute__ ((packed));
1491+
1492+#define USB_DT_DFU_SIZE 9
1493+
1494+#define USB_TYPE_DFU (USB_TYPE_CLASS|USB_RECIP_INTERFACE)
1495+
1496+/* DFU class-specific requests (Section 3, DFU Rev 1.1) */
1497+#define USB_REQ_DFU_DETACH 0x00
1498+#define USB_REQ_DFU_DNLOAD 0x01
1499+#define USB_REQ_DFU_UPLOAD 0x02
1500+#define USB_REQ_DFU_GETSTATUS 0x03
1501+#define USB_REQ_DFU_CLRSTATUS 0x04
1502+#define USB_REQ_DFU_GETSTATE 0x05
1503+#define USB_REQ_DFU_ABORT 0x06
1504+
1505+struct dfu_status {
1506+ u_int8_t bStatus;
1507+ u_int8_t bwPollTimeout[3];
1508+ u_int8_t bState;
1509+ u_int8_t iString;
1510+} __attribute__((packed));
1511+
1512+#define DFU_STATUS_OK 0x00
1513+#define DFU_STATUS_errTARGET 0x01
1514+#define DFU_STATUS_errFILE 0x02
1515+#define DFU_STATUS_errWRITE 0x03
1516+#define DFU_STATUS_errERASE 0x04
1517+#define DFU_STATUS_errCHECK_ERASED 0x05
1518+#define DFU_STATUS_errPROG 0x06
1519+#define DFU_STATUS_errVERIFY 0x07
1520+#define DFU_STATUS_errADDRESS 0x08
1521+#define DFU_STATUS_errNOTDONE 0x09
1522+#define DFU_STATUS_errFIRMWARE 0x0a
1523+#define DFU_STATUS_errVENDOR 0x0b
1524+#define DFU_STATUS_errUSBR 0x0c
1525+#define DFU_STATUS_errPOR 0x0d
1526+#define DFU_STATUS_errUNKNOWN 0x0e
1527+#define DFU_STATUS_errSTALLEDPKT 0x0f
1528+
1529+enum dfu_state {
1530+ DFU_STATE_appIDLE = 0,
1531+ DFU_STATE_appDETACH = 1,
1532+ DFU_STATE_dfuIDLE = 2,
1533+ DFU_STATE_dfuDNLOAD_SYNC = 3,
1534+ DFU_STATE_dfuDNBUSY = 4,
1535+ DFU_STATE_dfuDNLOAD_IDLE = 5,
1536+ DFU_STATE_dfuMANIFEST_SYNC = 6,
1537+ DFU_STATE_dfuMANIFEST = 7,
1538+ DFU_STATE_dfuMANIFEST_WAIT_RST = 8,
1539+ DFU_STATE_dfuUPLOAD_IDLE = 9,
1540+ DFU_STATE_dfuERROR = 10,
1541+};
1542+
1543+#endif /* _USB_DFU_H */
1544Index: u-boot/include/usbdcore.h
1545===================================================================
1546--- u-boot.orig/include/usbdcore.h
1547+++ u-boot/include/usbdcore.h
1548@@ -33,6 +33,7 @@
1549
1550 #include <common.h>
1551 #include "usbdescriptors.h"
1552+#include <usb_dfu_descriptors.h>
1553
1554
1555 #define MAX_URBS_QUEUED 5
1556@@ -475,7 +476,11 @@
1557 * function driver to inform it that data has arrived.
1558 */
1559
1560+#ifdef CONFIG_USBD_DFU
1561+#define URB_BUF_SIZE (128+CONFIG_USBD_DFU_XFER_SIZE)
1562+#else
1563 #define URB_BUF_SIZE 128 /* in linux we'd malloc this, but in u-boot we prefer static data */
1564+#endif
1565 struct urb {
1566
1567 struct usb_endpoint_instance *endpoint;
1568@@ -603,6 +608,12 @@
1569 unsigned long usbd_rxtx_timestamp;
1570 unsigned long usbd_last_rxtx_timestamp;
1571
1572+#ifdef CONFIG_USBD_DFU
1573+ const struct usb_device_descriptor *dfu_dev_desc;
1574+ const struct _dfu_desc *dfu_cfg_desc;
1575+ enum dfu_state dfu_state;
1576+ u_int8_t dfu_status;
1577+#endif
1578 };
1579
1580 /* Bus Interface configuration structure
1581@@ -632,6 +643,8 @@
1582 extern char *usbd_device_requests[];
1583 extern char *usbd_device_descriptors[];
1584
1585+extern struct usb_string_descriptor **usb_strings;
1586+
1587 void urb_link_init (urb_link * ul);
1588 void urb_detach (struct urb *urb);
1589 urb_link *first_urb_link (urb_link * hd);
1590Index: u-boot/drivers/usbtty.h
1591===================================================================
1592--- u-boot.orig/drivers/usbtty.h
1593+++ u-boot/drivers/usbtty.h
1594@@ -71,4 +71,10 @@
1595 #define STR_CTRL_INTERFACE 0x06
1596 #define STR_COUNT 0x07
1597
1598+#ifdef CONFIG_USBD_DFU
1599+#define NUM_STRINGS DFU_STR_COUNT
1600+#else
1601+#define NUM_STRINGS STR_COUNT
1602+#endif
1603+
1604 #endif
1605Index: u-boot/include/configs/qt2410.h
1606===================================================================
1607--- u-boot.orig/include/configs/qt2410.h
1608+++ u-boot/include/configs/qt2410.h
1609@@ -199,7 +199,8 @@
1610 #define CONFIG_USBD_PRODUCT_NAME "QT2410 Bootloader " U_BOOT_VERSION
1611 #define CONFIG_EXTRA_ENV_SETTINGS "usbtty=cdc_acm\0"
1612 #define CONFIG_USBD_DFU 1
1613-#define CONFIG_USBD_DFU_XFER_SIZE 0x4000
1614+#define CONFIG_USBD_DFU_XFER_SIZE 4096
1615+#define CONFIG_USBD_DFU_INTERFACE 2
1616
1617 /*-----------------------------------------------------------------------
1618 * Physical Memory Map
1619Index: u-boot/tools/Makefile
1620===================================================================
1621--- u-boot.orig/tools/Makefile
1622+++ u-boot/tools/Makefile
1623@@ -21,10 +21,10 @@
1624 # MA 02111-1307 USA
1625 #
1626
1627-BIN_FILES = img2srec$(SFX) mkimage$(SFX) envcrc$(SFX) gen_eth_addr$(SFX) bmp_logo$(SFX)
1628+BIN_FILES = img2srec$(SFX) mkimage$(SFX) envcrc$(SFX) gen_eth_addr$(SFX) bmp_logo$(SFX) mkudfu$(SFX)
1629
1630 OBJ_LINKS = environment.o crc32.o
1631-OBJ_FILES = img2srec.o mkimage.o envcrc.o gen_eth_addr.o bmp_logo.o
1632+OBJ_FILES = img2srec.o mkimage.o envcrc.o gen_eth_addr.o bmp_logo.o mkudfu.o
1633
1634 ifeq ($(ARCH),mips)
1635 BIN_FILES += inca-swap-bytes$(SFX)
1636@@ -137,6 +137,10 @@
1637 $(CC) $(CFLAGS) $(HOST_LDFLAGS) -o $@ $^
1638 $(STRIP) $@
1639
1640+$(obj)mkudfu$(SFX): $(obj)mkudfu.o
1641+ $(CC) $(CFLAGS) $(HOST_LDFLAGS) -o $@ $^
1642+ $(STRIP) $@
1643+
1644 $(obj)ncb$(SFX): $(obj)ncb.o
1645 $(CC) $(CFLAGS) $(HOST_LDFLAGS) -o $@ $^
1646 $(STRIP) $@
1647Index: u-boot/tools/mkudfu.c
1648===================================================================
1649--- /dev/null
1650+++ u-boot/tools/mkudfu.c
1651@@ -0,0 +1,314 @@
1652+/*
1653+ * USB DFU file trailer tool
1654+ * (C) Copyright by OpenMoko, Inc.
1655+ * Author: Harald Welte <laforge@openmoko.org>
1656+ *
1657+ * based on mkimage.c, copyright information as follows:
1658+ *
1659+ * (C) Copyright 2000-2004
1660+ * DENX Software Engineering
1661+ * Wolfgang Denk, wd@denx.de
1662+ * All rights reserved.
1663+ *
1664+ * This program is free software; you can redistribute it and/or
1665+ * modify it under the terms of the GNU General Public License as
1666+ * published by the Free Software Foundation; either version 2 of
1667+ * the License, or (at your option) any later version.
1668+ *
1669+ * This program is distributed in the hope that it will be useful,
1670+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1671+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1672+ * GNU General Public License for more details.
1673+ *
1674+ * You should have received a copy of the GNU General Public License
1675+ * along with this program; if not, write to the Free Software
1676+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
1677+ * MA 02111-1307 USA
1678+ */
1679+
1680+#include <errno.h>
1681+#include <fcntl.h>
1682+#include <stdio.h>
1683+#include <stdlib.h>
1684+#include <string.h>
1685+#ifndef __WIN32__
1686+#include <netinet/in.h> /* for host / network byte order conversions */
1687+#endif
1688+#include <sys/mman.h>
1689+#include <sys/stat.h>
1690+#include <time.h>
1691+#include <unistd.h>
1692+
1693+#if defined(__BEOS__) || defined(__NetBSD__) || defined(__APPLE__)
1694+#include <inttypes.h>
1695+#endif
1696+
1697+#ifdef __WIN32__
1698+typedef unsigned int __u32;
1699+
1700+#define SWAP_LONG(x) \
1701+ ((__u32)( \
1702+ (((__u32)(x) & (__u32)0x000000ffUL) << 24) | \
1703+ (((__u32)(x) & (__u32)0x0000ff00UL) << 8) | \
1704+ (((__u32)(x) & (__u32)0x00ff0000UL) >> 8) | \
1705+ (((__u32)(x) & (__u32)0xff000000UL) >> 24) ))
1706+typedef unsigned char uint8_t;
1707+typedef unsigned short uint16_t;
1708+typedef unsigned int uint32_t;
1709+
1710+#define ntohl(a) SWAP_LONG(a)
1711+#define htonl(a) SWAP_LONG(a)
1712+#endif /* __WIN32__ */
1713+
1714+#ifndef O_BINARY /* should be define'd on __WIN32__ */
1715+#define O_BINARY 0
1716+#endif
1717+
1718+#include <usb_dfu_trailer.h>
1719+
1720+extern int errno;
1721+
1722+#ifndef MAP_FAILED
1723+#define MAP_FAILED (-1)
1724+#endif
1725+
1726+static char *cmdname;
1727+
1728+static char *datafile;
1729+static char *imagefile;
1730+
1731+
1732+static void usage()
1733+{
1734+ fprintf (stderr, "%s - create / display u-boot DFU trailer\n", cmdname);
1735+ fprintf (stderr, "Usage: %s -l image\n"
1736+ " -l ==> list image header information\n"
1737+ " %s -v VID -p PID -r REV -d data_file image\n",
1738+ cmdname, cmdname);
1739+ fprintf (stderr, " -v ==> set vendor ID to 'VID'\n"
1740+ " -p ==> set product ID system to 'PID'\n"
1741+ " -r ==> set hardware revision to 'REV'\n"
1742+ " -d ==> use 'data_file' as input file\n"
1743+ );
1744+ exit (EXIT_FAILURE);
1745+}
1746+
1747+static void print_trailer(struct uboot_dfu_trailer *trailer)
1748+{
1749+ printf("===> DFU Trailer information:\n");
1750+ printf("Trailer Vers.: %d\n", trailer->version);
1751+ printf("Trailer Length: %d\n", trailer->length);
1752+ printf("VendorID: 0x%04x\n", trailer->vendor);
1753+ printf("ProductID: 0x%04x\n", trailer->product);
1754+ printf("HW Revision: 0x%04x\n", trailer->revision);
1755+}
1756+
1757+static void copy_file (int ifd, const char *datafile, int pad)
1758+{
1759+ int dfd;
1760+ struct stat sbuf;
1761+ unsigned char *ptr;
1762+ int tail;
1763+ int zero = 0;
1764+ int offset = 0;
1765+ int size;
1766+
1767+ if ((dfd = open(datafile, O_RDONLY|O_BINARY)) < 0) {
1768+ fprintf (stderr, "%s: Can't open %s: %s\n",
1769+ cmdname, datafile, strerror(errno));
1770+ exit (EXIT_FAILURE);
1771+ }
1772+
1773+ if (fstat(dfd, &sbuf) < 0) {
1774+ fprintf (stderr, "%s: Can't stat %s: %s\n",
1775+ cmdname, datafile, strerror(errno));
1776+ exit (EXIT_FAILURE);
1777+ }
1778+
1779+ ptr = (unsigned char *)mmap(0, sbuf.st_size,
1780+ PROT_READ, MAP_SHARED, dfd, 0);
1781+ if (ptr == (unsigned char *)MAP_FAILED) {
1782+ fprintf (stderr, "%s: Can't read %s: %s\n",
1783+ cmdname, datafile, strerror(errno));
1784+ exit (EXIT_FAILURE);
1785+ }
1786+
1787+ size = sbuf.st_size - offset;
1788+ if (write(ifd, ptr + offset, size) != size) {
1789+ fprintf (stderr, "%s: Write error on %s: %s\n",
1790+ cmdname, imagefile, strerror(errno));
1791+ exit (EXIT_FAILURE);
1792+ }
1793+
1794+ if (pad && ((tail = size % 4) != 0)) {
1795+
1796+ if (write(ifd, (char *)&zero, 4-tail) != 4-tail) {
1797+ fprintf (stderr, "%s: Write error on %s: %s\n",
1798+ cmdname, imagefile, strerror(errno));
1799+ exit (EXIT_FAILURE);
1800+ }
1801+ }
1802+
1803+ (void) munmap((void *)ptr, sbuf.st_size);
1804+ (void) close (dfd);
1805+}
1806+
1807+
1808+int main(int argc, char **argv)
1809+{
1810+ int ifd;
1811+ int lflag = 0;
1812+ struct stat sbuf;
1813+ u_int16_t opt_vendor, opt_product, opt_revision;
1814+ struct uboot_dfu_trailer _hdr, _mirror, *hdr = &_hdr;
1815+
1816+ opt_vendor = opt_product = opt_revision = 0;
1817+
1818+ cmdname = *argv;
1819+
1820+ while (--argc > 0 && **++argv == '-') {
1821+ while (*++*argv) {
1822+ switch (**argv) {
1823+ case 'l':
1824+ lflag = 1;
1825+ break;
1826+ case 'v':
1827+ if (--argc <= 0)
1828+ usage ();
1829+ opt_vendor = strtoul(*++argv, NULL, 16);
1830+ goto NXTARG;
1831+ case 'p':
1832+ if (--argc <= 0)
1833+ usage ();
1834+ opt_product = strtoul(*++argv, NULL, 16);
1835+ goto NXTARG;
1836+ case 'r':
1837+ if (--argc <= 0)
1838+ usage ();
1839+ opt_revision = strtoul(*++argv, NULL, 16);
1840+ goto NXTARG;
1841+ case 'd':
1842+ if (--argc <= 0)
1843+ usage ();
1844+ datafile = *++argv;
1845+ goto NXTARG;
1846+ case 'h':
1847+ usage();
1848+ break;
1849+ default:
1850+ usage();
1851+ }
1852+ }
1853+NXTARG: ;
1854+ }
1855+
1856+ if (argc != 1)
1857+ usage();
1858+
1859+ imagefile = *argv;
1860+
1861+ if (lflag)
1862+ ifd = open(imagefile, O_RDONLY|O_BINARY);
1863+ else
1864+ ifd = open(imagefile, O_RDWR|O_CREAT|O_TRUNC|O_BINARY, 0666);
1865+
1866+ if (ifd < 0) {
1867+ fprintf (stderr, "%s: Can't open %s: %s\n",
1868+ cmdname, imagefile, strerror(errno));
1869+ exit (EXIT_FAILURE);
1870+ }
1871+
1872+ if (lflag) {
1873+ unsigned char *ptr;
1874+ /* list header information of existing image */
1875+ if (fstat(ifd, &sbuf) < 0) {
1876+ fprintf (stderr, "%s: Can't stat %s: %s\n",
1877+ cmdname, imagefile, strerror(errno));
1878+ exit (EXIT_FAILURE);
1879+ }
1880+
1881+ if ((unsigned)sbuf.st_size < sizeof(struct uboot_dfu_trailer)) {
1882+ fprintf (stderr,
1883+ "%s: Bad size: \"%s\" is no valid image\n",
1884+ cmdname, imagefile);
1885+ exit (EXIT_FAILURE);
1886+ }
1887+
1888+ ptr = (unsigned char *)mmap(0, sbuf.st_size,
1889+ PROT_READ, MAP_SHARED, ifd, 0);
1890+ if ((caddr_t)ptr == (caddr_t)-1) {
1891+ fprintf (stderr, "%s: Can't read %s: %s\n",
1892+ cmdname, imagefile, strerror(errno));
1893+ exit (EXIT_FAILURE);
1894+ }
1895+
1896+ dfu_trailer_mirror(hdr, ptr+sbuf.st_size);
1897+
1898+ if (hdr->magic != UBOOT_DFU_TRAILER_MAGIC) {
1899+ fprintf (stderr,
1900+ "%s: Bad Magic Number: \"%s\" is no valid image\n",
1901+ cmdname, imagefile);
1902+ exit (EXIT_FAILURE);
1903+ }
1904+
1905+ /* for multi-file images we need the data part, too */
1906+ print_trailer(hdr);
1907+
1908+ (void) munmap((void *)ptr, sbuf.st_size);
1909+ (void) close (ifd);
1910+
1911+ exit (EXIT_SUCCESS);
1912+ }
1913+
1914+ /* if we're not listing: */
1915+
1916+ copy_file (ifd, datafile, 0);
1917+
1918+ memset (hdr, 0, sizeof(struct uboot_dfu_trailer));
1919+
1920+ /* Build new header */
1921+ hdr->version = UBOOT_DFU_TRAILER_V1;
1922+ hdr->magic = UBOOT_DFU_TRAILER_MAGIC;
1923+ hdr->length = sizeof(struct uboot_dfu_trailer);
1924+ hdr->vendor = opt_vendor;
1925+ hdr->product = opt_product;
1926+ hdr->revision = opt_revision;
1927+
1928+ print_trailer(hdr);
1929+ dfu_trailer_mirror(&_mirror, (unsigned char *)hdr+sizeof(*hdr));
1930+
1931+ if (write(ifd, &_mirror, sizeof(struct uboot_dfu_trailer))
1932+ != sizeof(struct uboot_dfu_trailer)) {
1933+ fprintf (stderr, "%s: Write error on %s: %s\n",
1934+ cmdname, imagefile, strerror(errno));
1935+ exit (EXIT_FAILURE);
1936+ }
1937+
1938+ /* We're a bit of paranoid */
1939+#if defined(_POSIX_SYNCHRONIZED_IO) && !defined(__sun__) && !defined(__FreeBSD__)
1940+ (void) fdatasync (ifd);
1941+#else
1942+ (void) fsync (ifd);
1943+#endif
1944+
1945+ if (fstat(ifd, &sbuf) < 0) {
1946+ fprintf (stderr, "%s: Can't stat %s: %s\n",
1947+ cmdname, imagefile, strerror(errno));
1948+ exit (EXIT_FAILURE);
1949+ }
1950+
1951+ /* We're a bit of paranoid */
1952+#if defined(_POSIX_SYNCHRONIZED_IO) && !defined(__sun__) && !defined(__FreeBSD__)
1953+ (void) fdatasync (ifd);
1954+#else
1955+ (void) fsync (ifd);
1956+#endif
1957+
1958+ if (close(ifd)) {
1959+ fprintf (stderr, "%s: Write error on %s: %s\n",
1960+ cmdname, imagefile, strerror(errno));
1961+ exit (EXIT_FAILURE);
1962+ }
1963+
1964+ exit (EXIT_SUCCESS);
1965+}
1966Index: u-boot/include/usb_dfu_trailer.h
1967===================================================================
1968--- /dev/null
1969+++ u-boot/include/usb_dfu_trailer.h
1970@@ -0,0 +1,31 @@
1971+#ifndef _USB_DFU_TRAILER_H
1972+#define _USB_DFU_TRAILER_H
1973+
1974+/* trailer handling for DFU files */
1975+
1976+#define UBOOT_DFU_TRAILER_V1 1
1977+#define UBOOT_DFU_TRAILER_MAGIC 0x19731978
1978+struct uboot_dfu_trailer {
1979+ u_int32_t magic;
1980+ u_int16_t version;
1981+ u_int16_t length;
1982+ u_int16_t vendor;
1983+ u_int16_t product;
1984+ u_int32_t revision;
1985+} __attribute__((packed));
1986+
1987+/* we mirror the trailer because we want it to be longer in later versions
1988+ * while keeping backwards compatibility */
1989+static inline void dfu_trailer_mirror(struct uboot_dfu_trailer *trailer,
1990+ unsigned char *eof)
1991+{
1992+ int i;
1993+ int len = sizeof(struct uboot_dfu_trailer);
1994+ unsigned char *src = eof - len;
1995+ unsigned char *dst = (unsigned char *) trailer;
1996+
1997+ for (i = 0; i < len; i++)
1998+ dst[len-1-i] = src[i];
1999+}
2000+
2001+#endif /* _USB_DFU_TRAILER_H */
2002Index: u-boot/Makefile
2003===================================================================
2004--- u-boot.orig/Makefile
2005+++ u-boot/Makefile
2006@@ -261,6 +261,12 @@
2007 $(obj)u-boot.bin: $(obj)u-boot
2008 $(OBJCOPY) ${OBJCFLAGS} -O binary $< $@
2009
2010+$(obj)u-boot.udfu: $(obj)u-boot.bin
2011+ ./tools/mkudfu -v $(CONFIG_USB_DFU_VENDOR) \
2012+ -p $(CONFIG_USB_DFU_PRODUCT) \
2013+ -r $(CONFIG_USB_DFU_REVISION) \
2014+ -d $< $@
2015+
2016 $(obj)u-boot.img: $(obj)u-boot.bin
2017 ./tools/mkimage -A $(ARCH) -T firmware -C none \
2018 -a $(TEXT_BASE) -e 0 \
2019Index: u-boot/board/neo1973/gta01/split_by_variant.sh
2020===================================================================
2021--- u-boot.orig/board/neo1973/gta01/split_by_variant.sh
2022+++ u-boot/board/neo1973/gta01/split_by_variant.sh
2023@@ -15,37 +15,44 @@
2024 echo "$0:: No parameters - using GTA01Bv3 config"
2025 echo "#define CONFIG_ARCH_GTA01B_v3" > $CFGINC
2026 echo "GTA01_BIG_RAM=y" > $CFGTMP
2027+ echo "CONFIG_USB_DFU_REVISION=0x0230" > $CFGTMP
2028 else
2029 case "$1" in
2030 gta01v4_config)
2031 echo "#define CONFIG_ARCH_GTA01_v4" > $CFGINC
2032 echo "GTA01_BIG_RAM=n" > $CFGTMP
2033+ echo "CONFIG_USB_DFU_REVISION=0x0140" > $CFGTMP
2034 ;;
2035
2036 gta01v3_config)
2037 echo "#define CONFIG_ARCH_GTA01_v3" > $CFGINC
2038 echo "GTA01_BIG_RAM=n" > $CFGTMP
2039+ echo "CONFIG_USB_DFU_REVISION=0x0130" > $CFGTMP
2040 ;;
2041
2042 gta01bv2_config)
2043 echo "#define CONFIG_ARCH_GTA01B_v2" > $CFGINC
2044 echo "GTA01_BIG_RAM=y" > $CFGTMP
2045+ echo "CONFIG_USB_DFU_REVISION=0x0220" > $CFGTMP
2046 ;;
2047
2048 gta01bv3_config)
2049 echo "#define CONFIG_ARCH_GTA01B_v3" > $CFGINC
2050 echo "GTA01_BIG_RAM=y" > $CFGTMP
2051+ echo "CONFIG_USB_DFU_REVISION=0x0230" > $CFGTMP
2052 ;;
2053
2054 gta01bv4_config)
2055 echo "#define CONFIG_ARCH_GTA01B_v4" > $CFGINC
2056 echo "GTA01_BIG_RAM=y" > $CFGTMP
2057+ echo "CONFIG_USB_DFU_REVISION=0x0240" > $CFGTMP
2058 ;;
2059
2060 *)
2061 echo "$0:: Unrecognised config - using GTA01Bv4 config"
2062 echo "#define CONFIG_ARCH_GTA01B_v4" > $CFGINC
2063 echo "GTA01_BIG_RAM=y" > $CFGTMP
2064+ echo "CONFIG_USB_DFU_REVISION=0x0240" > $CFGTMP
2065 ;;
2066
2067 esac
2068Index: u-boot/board/neo1973/gta01/config.mk
2069===================================================================
2070--- u-boot.orig/board/neo1973/gta01/config.mk
2071+++ u-boot/board/neo1973/gta01/config.mk
2072@@ -24,6 +24,9 @@
2073 #
2074 # download area is 3200'0000 or 3300'0000
2075
2076+CONFIG_USB_DFU_VENDOR=0x1457
2077+CONFIG_USB_DFU_PRODUCT=0x5119
2078+
2079 sinclude $(OBJTREE)/board/$(BOARDDIR)/config.tmp
2080
2081 ifeq ($(GTA01_BIG_RAM),y)