u-boot: Fix DFU upload in u-boot
[u-boot-openmoko/mini2440.git] / drivers / usb / usbdfu.c
blob855d12ef6da4443917d1a2eedca044ea58b28afc
1 /*
2 * (C) 2007 by OpenMoko, Inc.
3 * Author: Harald Welte <laforge@openmoko.org>
5 * based on existing SAM7DFU code from OpenPCD:
6 * (C) Copyright 2006 by Harald Welte <hwelte@hmw-consulting.de>
8 * See file CREDITS for list of people who contributed to this
9 * project.
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License as
13 * published by the Free Software Foundation; either version 2 of
14 * the License, or (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
24 * MA 02111-1307 USA
26 * TODO:
27 * - make NAND support reasonably self-contained and put in apropriate
28 * ifdefs
29 * - add some means of synchronization, i.e. block commandline access
30 * while DFU transfer is in progress, and return to commandline once
31 * we're finished
32 * - add VERIFY support after writing to flash
33 * - sanely free() resources allocated during first uppload/download
34 * request when aborting
35 * - sanely free resources when another alternate interface is selected
37 * Maybe:
38 * - add something like uImage or some other header that provides CRC
39 * checking?
40 * - make 'dnstate' attached to 'struct usb_device_instance'
43 #include <config.h>
44 #if defined(CONFIG_USBD_DFU)
46 #include <common.h>
47 DECLARE_GLOBAL_DATA_PTR;
49 #include <malloc.h>
50 #include <linux/types.h>
51 #include <linux/list.h>
52 #include <asm/errno.h>
53 #include <usbdcore.h>
54 #include <usb_dfu.h>
55 #include <usb_dfu_descriptors.h>
56 #include <usb_dfu_trailer.h>
58 #include <nand.h>
59 #include <jffs2/load_kernel.h>
60 int mtdparts_init(void);
61 extern struct list_head devices;
63 #include "usbdcore_s3c2410.h"
64 #include "../serial/usbtty.h" /* for STR_* defs */
66 #define RET_NOTHING 0
67 #define RET_ZLP 1
68 #define RET_STALL 2
70 volatile enum dfu_state *system_dfu_state; /* for 3rd parties */
73 struct dnload_state {
74 nand_info_t *nand;
75 struct part_info *part;
76 unsigned int part_net_size; /* net sizee (excl. bad blocks) of part */
78 nand_erase_options_t erase_opts;
79 nand_write_options_t write_opts;
80 nand_read_options_t read_opts;
82 unsigned char *ptr; /* pointer to next empty byte in buffer */
83 unsigned int off; /* offset of current erase page in flash chip */
84 unsigned char *buf; /* pointer to allocated erase page buffer */
86 /* unless doing an atomic transfer, we use the static buffer below.
87 * This saves us from having to clean up dynamic allications in the
88 * various error paths of the code. Also, it will always work, no
89 * matter what the memory situation is. */
90 unsigned char _buf[0x20000]; /* FIXME: depends flash page size */
93 static struct dnload_state _dnstate;
95 static int dfu_trailer_matching(const struct uboot_dfu_trailer *trailer)
97 if (trailer->magic != UBOOT_DFU_TRAILER_MAGIC ||
98 trailer->version != UBOOT_DFU_TRAILER_V1 ||
99 trailer->vendor != CONFIG_USBD_VENDORID ||
100 (trailer->product != CONFIG_USBD_PRODUCTID_CDCACM &&
101 trailer->product != CONFIG_USBD_PRODUCTID_GSERIAL))
102 return 0;
103 #ifdef CONFIG_REVISION_TAG
104 if (trailer->revision != CONFIG_USB_DFU_REVISION)
105 return 0;
106 #endif
108 return 1;
111 static struct part_info *get_partition_nand(int idx)
113 struct mtd_device *dev;
114 struct part_info *part;
115 struct list_head *dentry;
116 struct list_head *pentry;
117 int i;
119 if (mtdparts_init())
120 return NULL;
122 list_for_each(dentry, &devices) {
123 dev = list_entry(dentry, struct mtd_device, link);
124 if (dev->id->type == MTD_DEV_TYPE_NAND) {
125 i = 0;
126 list_for_each(pentry, &dev->parts) {
127 if (i == idx) {
128 part = list_entry(pentry,
129 struct part_info, link);
130 return part;
132 i++;
134 return NULL;
139 #define LOAD_ADDR ((unsigned char *)0x32000000)
141 static int initialize_ds_nand(struct usb_device_instance *dev, struct dnload_state *ds)
143 ds->part = get_partition_nand(dev->alternate - 1);
144 if (!ds->part) {
145 printf("DFU: unable to find partition %u\b", dev->alternate-1);
146 dev->dfu_state = DFU_STATE_dfuERROR;
147 dev->dfu_status = DFU_STATUS_errADDRESS;
148 return RET_STALL;
150 ds->nand = &nand_info[ds->part->dev->id->num];
151 ds->off = ds->part->offset;
152 ds->part_net_size = nand_net_part_size(ds->part);
154 if (ds->nand->erasesize > sizeof(ds->_buf)) {
155 printf("*** Warning - NAND ERASESIZE bigger than static buffer\n");
156 ds->buf = malloc(ds->nand->erasesize);
157 if (!ds->buf) {
158 printf("DFU: can't allocate %u bytes\n", ds->nand->erasesize);
159 dev->dfu_state = DFU_STATE_dfuERROR;
160 dev->dfu_status = DFU_STATUS_errADDRESS;
161 return RET_STALL;
163 } else
164 ds->buf = ds->_buf;
166 ds->ptr = ds->buf;
168 memset(&ds->read_opts, 0, sizeof(ds->read_opts));
170 memset(&ds->erase_opts, 0, sizeof(ds->erase_opts));
171 ds->erase_opts.quiet = 1;
172 /* FIXME: do this more dynamic */
173 if (!strcmp(ds->part->name, "rootfs"))
174 ds->erase_opts.jffs2 = 1;
176 memset(&ds->write_opts, 0, sizeof(ds->write_opts));
177 ds->write_opts.pad = 1;
178 ds->write_opts.blockalign = 1;
179 ds->write_opts.quiet = 1;
181 debug("initialize_ds_nand(dev=%p, ds=%p): ", dev, ds);
182 debug("nand=%p, ptr=%p, buf=%p, off=0x%x\n", ds->nand, ds->ptr, ds->buf, ds->off);
184 return RET_NOTHING;
187 static int erase_flash_verify_nand(struct urb *urb, struct dnload_state *ds,
188 unsigned long erasesize, unsigned long size)
190 struct usb_device_instance *dev = urb->device;
191 int rc;
193 debug("erase_flash_verify_nand(urb=%p, ds=%p, erase=0x%x size=0x%x)\n",
194 urb, ds, erasesize, size);
196 if (erasesize == ds->nand->erasesize) {
197 /* we're only writing a single block and need to
198 * do bad block skipping / offset adjustments our own */
199 while (ds->nand->block_isbad(ds->nand, ds->off)) {
200 debug("SKIP_ONE_BLOCK(0x%08x)!!\n", ds->off);
201 ds->off += ds->nand->erasesize;
205 /* we have finished one eraseblock, flash it */
206 ds->erase_opts.offset = ds->off;
207 ds->erase_opts.length = erasesize;
208 debug("Erasing 0x%x bytes @ offset 0x%x (jffs=%u)\n",
209 ds->erase_opts.length, ds->erase_opts.offset,
210 ds->erase_opts.jffs2);
211 rc = nand_erase_opts(ds->nand, &ds->erase_opts);
212 if (rc) {
213 debug("Error erasing\n");
214 dev->dfu_state = DFU_STATE_dfuERROR;
215 dev->dfu_status = DFU_STATUS_errERASE;
216 return RET_STALL;
219 ds->write_opts.buffer = ds->buf;
220 ds->write_opts.length = size;
221 ds->write_opts.offset = ds->off;
222 debug("Writing 0x%x bytes @ offset 0x%x\n", size, ds->off);
223 rc = nand_write_opts(ds->nand, &ds->write_opts);
224 if (rc) {
225 debug("Error writing\n");
226 dev->dfu_state = DFU_STATE_dfuERROR;
227 dev->dfu_status = DFU_STATUS_errWRITE;
228 return RET_STALL;
231 ds->off += size;
232 ds->ptr = ds->buf;
234 /* FIXME: implement verify! */
235 return RET_NOTHING;
238 static int erase_tail_clean_nand(struct urb *urb, struct dnload_state *ds)
240 struct usb_device_instance *dev = urb->device;
241 int rc;
243 ds->erase_opts.offset = ds->off;
244 ds->erase_opts.length = ds->part->size - (ds->off - ds->part->offset);
245 debug("Erasing tail of 0x%x bytes @ offset 0x%x (jffs=%u)\n",
246 ds->erase_opts.length, ds->erase_opts.offset,
247 ds->erase_opts.jffs2);
248 rc = nand_erase_opts(ds->nand, &ds->erase_opts);
249 if (rc) {
250 printf("Error erasing tail\n");
251 dev->dfu_state = DFU_STATE_dfuERROR;
252 dev->dfu_status = DFU_STATUS_errERASE;
253 return RET_STALL;
256 ds->off += ds->erase_opts.length; /* for consistency */
258 return RET_NOTHING;
261 /* Read the next erase blcok from NAND into buffer */
262 static int read_next_nand(struct urb *urb, struct dnload_state *ds, int len)
264 struct usb_device_instance *dev = urb->device;
265 int rc;
267 ds->read_opts.buffer = ds->buf;
268 ds->read_opts.length = len;
269 ds->read_opts.offset = ds->off;
270 ds->read_opts.quiet = 1;
272 debug("Reading 0x%x@0x%x to 0x%08p\n", len, ds->off, ds->buf);
273 rc = nand_read_opts(ds->nand, &ds->read_opts);
274 if (rc) {
275 debug("Error reading\n");
276 dev->dfu_state = DFU_STATE_dfuERROR;
277 dev->dfu_status = DFU_STATUS_errWRITE;
278 return RET_STALL;
280 ds->off += len;
281 ds->ptr = ds->buf;
283 return RET_NOTHING;
287 static int handle_dnload(struct urb *urb, u_int16_t val, u_int16_t len, int first)
289 struct usb_device_instance *dev = urb->device;
290 struct dnload_state *ds = &_dnstate;
291 unsigned int actual_len = len;
292 unsigned int remain_len;
293 unsigned long size;
294 int rc;
296 debug("download(len=%u, first=%u) ", len, first);
298 if (len > CONFIG_USBD_DFU_XFER_SIZE) {
299 /* Too big. Not that we'd really care, but it's a
300 * DFU protocol violation */
301 debug("length exceeds flash page size ");
302 dev->dfu_state = DFU_STATE_dfuERROR;
303 dev->dfu_status = DFU_STATUS_errADDRESS;
304 return RET_STALL;
307 if (first) {
308 /* Make sure that we have a valid mtd partition table */
309 char *mtdp = getenv("mtdparts");
310 if (!mtdp)
311 run_command("dynpart", 0);
314 if (len == 0) {
315 debug("zero-size write -> MANIFEST_SYNC ");
316 dev->dfu_state = DFU_STATE_dfuMANIFEST_SYNC;
318 /* cleanup */
319 switch (dev->alternate) {
320 char buf[12];
321 case 0:
322 sprintf(buf, "%lx", ds->ptr - ds->buf);
323 setenv("filesize", buf);
324 ds->ptr = ds->buf;
325 break;
326 case 1:
327 if (ds->ptr >
328 ds->buf + sizeof(struct uboot_dfu_trailer)) {
329 struct uboot_dfu_trailer trailer;
330 dfu_trailer_mirror(&trailer, ds->ptr);
331 if (!dfu_trailer_matching(&trailer)) {
332 printf("DFU TRAILER NOT OK\n");
333 dev->dfu_state = DFU_STATE_dfuERROR;
334 dev->dfu_status = DFU_STATUS_errTARGET;
335 return RET_STALL;
338 rc = erase_flash_verify_nand(urb, ds,
339 ds->part->size,
340 ds->part_net_size);
341 /* re-write dynenv marker in OOB */
342 run_command("dynenv set u-boot_env", 0);
344 ds->nand = NULL;
345 free(ds->buf);
346 ds->ptr = ds->buf = ds->_buf;
347 break;
348 default:
349 rc = 0;
350 if (ds->ptr > ds->buf)
351 rc = erase_flash_verify_nand(urb, ds,
352 ds->nand->erasesize,
353 ds->nand->erasesize);
354 /* rootfs partition */
355 if (!rc && !strcmp(ds->part->name, "rootfs"))
356 rc = erase_tail_clean_nand(urb, ds);
358 ds->nand = NULL;
359 break;
362 return RET_ZLP;
365 if (urb->actual_length != len) {
366 debug("urb->actual_length(%u) != len(%u) ?!? ",
367 urb->actual_length, len);
368 dev->dfu_state = DFU_STATE_dfuERROR;
369 dev->dfu_status = DFU_STATUS_errADDRESS;
370 return RET_STALL;
373 if (first && ds->buf && ds->buf != ds->_buf && ds->buf != LOAD_ADDR) {
374 free(ds->buf);
375 ds->buf = ds->_buf;
378 switch (dev->alternate) {
379 case 0:
380 if (first) {
381 printf("Starting DFU DOWNLOAD to RAM (0x%08p)\n",
382 LOAD_ADDR);
383 ds->buf = LOAD_ADDR;
384 ds->ptr = ds->buf;
387 memcpy(ds->ptr, urb->buffer, len);
388 ds->ptr += len;
389 break;
390 case 1:
391 if (first) {
392 rc = initialize_ds_nand(dev, ds);
393 if (rc)
394 return rc;
395 ds->buf = malloc(ds->part_net_size);
396 if (!ds->buf) {
397 printf("No memory for atomic buffer!!\n");
398 dev->dfu_state = DFU_STATE_dfuERROR;
399 dev->dfu_status = DFU_STATUS_errUNKNOWN;
400 return RET_STALL;
402 ds->ptr = ds->buf;
403 printf("Starting Atomic DFU DOWNLOAD to partition '%s'\n",
404 ds->part->name);
407 remain_len = (ds->buf + ds->part_net_size) - ds->ptr;
408 if (remain_len < len) {
409 len = remain_len;
410 printf("End of write exceeds partition end\n");
411 dev->dfu_state = DFU_STATE_dfuERROR;
412 dev->dfu_status = DFU_STATUS_errADDRESS;
413 return RET_STALL;
415 memcpy(ds->ptr, urb->buffer, len);
416 ds->ptr += len;
417 break;
418 default:
419 if (first) {
420 rc = initialize_ds_nand(dev, ds);
421 if (rc)
422 return rc;
423 printf("Starting DFU DOWNLOAD to partition '%s'\n",
424 ds->part->name);
427 size = ds->nand->erasesize;
428 remain_len = ds->buf + size - ds->ptr;
429 if (remain_len < len)
430 actual_len = remain_len;
432 memcpy(ds->ptr, urb->buffer, actual_len);
433 ds->ptr += actual_len;
435 /* check partition end */
436 if (ds->off + (ds->ptr - ds->buf) > ds->part->offset + ds->part->size) {
437 printf("End of write exceeds partition end\n");
438 dev->dfu_state = DFU_STATE_dfuERROR;
439 dev->dfu_status = DFU_STATUS_errADDRESS;
440 return RET_STALL;
443 if (ds->ptr >= ds->buf + size) {
444 rc = erase_flash_verify_nand(urb, ds,
445 ds->nand->erasesize,
446 ds->nand->erasesize);
447 if (rc)
448 return rc;
449 /* copy remainder of data into buffer */
450 memcpy(ds->ptr, urb->buffer + actual_len, len - actual_len);
451 ds->ptr += (len - actual_len);
453 break;
456 return RET_ZLP;
459 static int handle_upload(struct urb *urb, u_int16_t val, u_int16_t len, int first)
461 struct usb_device_instance *dev = urb->device;
462 struct dnload_state *ds = &_dnstate;
463 unsigned int remain;
464 int rc;
466 debug("upload(val=0x%02x, len=%u, first=%u) ", val, len, first);
468 if (len > CONFIG_USBD_DFU_XFER_SIZE) {
469 /* Too big */
470 dev->dfu_state = DFU_STATE_dfuERROR;
471 dev->dfu_status = DFU_STATUS_errADDRESS;
472 //udc_ep0_send_stall();
473 debug("Error: Transfer size > CONFIG_USBD_DFU_XFER_SIZE ");
474 return -EINVAL;
477 switch (dev->alternate) {
478 case 0:
479 if (first) {
480 printf("Starting DFU Upload of RAM (0x%08p)\n",
481 LOAD_ADDR);
482 ds->ptr = ds->buf;
485 /* FIXME: end at some more dynamic point */
486 if (ds->ptr + len > LOAD_ADDR + 0x200000)
487 len = (LOAD_ADDR + 0x200000) - ds->ptr;
489 urb->buffer = ds->ptr;
490 urb->actual_length = len;
491 ds->ptr += len;
492 break;
493 default:
494 if (first) {
495 rc = initialize_ds_nand(dev, ds);
496 if (rc)
497 return -EINVAL;
498 printf("Starting DFU Upload of partition '%s'\n",
499 ds->part->name);
502 if (len > ds->nand->erasesize) {
503 printf("We don't support transfers bigger than %u\n",
504 ds->nand->erasesize);
505 len = ds->nand->erasesize;
508 /* limit length to whatever number of bytes is left in
509 * this partition */
510 remain = (ds->part->offset + ds->part->size) - ds->off;
511 if (len > remain)
512 len = remain;
514 rc = read_next_nand(urb, ds, len);
515 if (rc)
516 return -EINVAL;
518 debug("uploading %u bytes ", len);
519 urb->buffer = ds->buf;
520 urb->actual_length = len;
521 break;
524 debug("returning len=%u\n", len);
525 return len;
528 static void handle_getstatus(struct urb *urb, int max)
530 struct usb_device_instance *dev = urb->device;
531 struct dfu_status *dstat = (struct dfu_status *) urb->buffer;
533 debug("getstatus ");
535 if (!urb->buffer || urb->buffer_length < sizeof(*dstat)) {
536 debug("invalid urb! ");
537 return;
540 switch (dev->dfu_state) {
541 case DFU_STATE_dfuDNLOAD_SYNC:
542 case DFU_STATE_dfuDNBUSY:
543 #if 0
544 if (fsr & AT91C_MC_PROGE) {
545 debug("errPROG ");
546 dev->dfu_status = DFU_STATUS_errPROG;
547 dev->dfu_state = DFU_STATE_dfuERROR;
548 } else if (fsr & AT91C_MC_LOCKE) {
549 debug("errWRITE ");
550 dev->dfu_status = DFU_STATUS_errWRITE;
551 dev->dfu_state = DFU_STATE_dfuERROR;
552 } else if (fsr & AT91C_MC_FRDY) {
553 #endif
554 debug("DNLOAD_IDLE ");
555 dev->dfu_state = DFU_STATE_dfuDNLOAD_IDLE;
556 #if 0
557 } else {
558 debug("DNBUSY ");
559 dev->dfu_state = DFU_STATE_dfuDNBUSY;
561 #endif
562 break;
563 case DFU_STATE_dfuMANIFEST_SYNC:
564 break;
565 default:
566 //return;
567 break;
570 /* send status response */
571 dstat->bStatus = dev->dfu_status;
572 dstat->bState = dev->dfu_state;
573 dstat->iString = 0;
574 /* FIXME: set dstat->bwPollTimeout */
575 urb->actual_length = MIN(sizeof(*dstat), max);
577 /* we don't need to explicitly send data here, will
578 * be done by the original caller! */
581 static void handle_getstate(struct urb *urb, int max)
583 debug("getstate ");
585 if (!urb->buffer || urb->buffer_length < sizeof(u_int8_t)) {
586 debug("invalid urb! ");
587 return;
590 urb->buffer[0] = urb->device->dfu_state & 0xff;
591 urb->actual_length = sizeof(u_int8_t);
594 #ifndef CONFIG_USBD_PRODUCTID_DFU
595 #define CONFIG_USBD_PRODUCTID_DFU CONFIG_USBD_PRODUCTID_CDCACM
596 #endif
598 static const struct usb_device_descriptor dfu_dev_descriptor = {
599 .bLength = USB_DT_DEVICE_SIZE,
600 .bDescriptorType = USB_DT_DEVICE,
601 .bcdUSB = 0x0100,
602 .bDeviceClass = 0x00,
603 .bDeviceSubClass = 0x00,
604 .bDeviceProtocol = 0x00,
605 .bMaxPacketSize0 = EP0_MAX_PACKET_SIZE,
606 .idVendor = CONFIG_USBD_VENDORID,
607 .idProduct = CONFIG_USBD_PRODUCTID_DFU,
608 .bcdDevice = 0x0000,
609 .iManufacturer = DFU_STR_MANUFACTURER,
610 .iProduct = DFU_STR_PRODUCT,
611 .iSerialNumber = DFU_STR_SERIAL,
612 .bNumConfigurations = 0x01,
615 static struct _dfu_desc dfu_cfg_descriptor = {
616 .ucfg = {
617 .bLength = USB_DT_CONFIG_SIZE,
618 .bDescriptorType = USB_DT_CONFIG,
619 .wTotalLength = USB_DT_CONFIG_SIZE +
620 DFU_NUM_ALTERNATES * USB_DT_INTERFACE_SIZE +
621 USB_DT_DFU_SIZE,
622 .bNumInterfaces = 1,
623 .bConfigurationValue = 1,
624 .iConfiguration = DFU_STR_CONFIG,
625 .bmAttributes = BMATTRIBUTE_RESERVED,
626 .bMaxPower = 50,
628 .func_dfu = DFU_FUNC_DESC,
631 int dfu_ep0_handler(struct urb *urb)
633 int rc, ret = RET_NOTHING;
634 u_int8_t req = urb->device_request.bRequest;
635 u_int16_t val = urb->device_request.wValue;
636 u_int16_t len = urb->device_request.wLength;
637 struct usb_device_instance *dev = urb->device;
639 debug("dfu_ep0(req=0x%x, val=0x%x, len=%u) old_state = %u ",
640 req, val, len, dev->dfu_state);
642 switch (dev->dfu_state) {
643 case DFU_STATE_appIDLE:
644 switch (req) {
645 case USB_REQ_DFU_GETSTATUS:
646 handle_getstatus(urb, len);
647 break;
648 case USB_REQ_DFU_GETSTATE:
649 handle_getstate(urb, len);
650 break;
651 case USB_REQ_DFU_DETACH:
652 dev->dfu_state = DFU_STATE_appDETACH;
653 ret = RET_ZLP;
654 goto out;
655 break;
656 default:
657 ret = RET_STALL;
659 break;
660 case DFU_STATE_appDETACH:
661 switch (req) {
662 case USB_REQ_DFU_GETSTATUS:
663 handle_getstatus(urb, len);
664 break;
665 case USB_REQ_DFU_GETSTATE:
666 handle_getstate(urb, len);
667 break;
668 default:
669 dev->dfu_state = DFU_STATE_appIDLE;
670 ret = RET_STALL;
671 goto out;
672 break;
674 /* FIXME: implement timer to return to appIDLE */
675 break;
676 case DFU_STATE_dfuIDLE:
677 switch (req) {
678 case USB_REQ_DFU_DNLOAD:
679 if (len == 0) {
680 dev->dfu_state = DFU_STATE_dfuERROR;
681 ret = RET_STALL;
682 goto out;
684 dev->dfu_state = DFU_STATE_dfuDNLOAD_SYNC;
685 ret = handle_dnload(urb, val, len, 1);
686 break;
687 case USB_REQ_DFU_UPLOAD:
688 dev->dfu_state = DFU_STATE_dfuUPLOAD_IDLE;
689 handle_upload(urb, val, len, 1);
690 break;
691 case USB_REQ_DFU_ABORT:
692 /* no zlp? */
693 ret = RET_ZLP;
694 break;
695 case USB_REQ_DFU_GETSTATUS:
696 handle_getstatus(urb, len);
697 break;
698 case USB_REQ_DFU_GETSTATE:
699 handle_getstate(urb, len);
700 break;
701 case USB_REQ_DFU_DETACH:
702 /* Proprietary extension: 'detach' from idle mode and
703 * get back to runtime mode in case of USB Reset. As
704 * much as I dislike this, we just can't use every USB
705 * bus reset to switch back to runtime mode, since at
706 * least the Linux USB stack likes to send a number of resets
707 * in a row :( */
708 dev->dfu_state = DFU_STATE_dfuMANIFEST_WAIT_RST;
709 break;
710 default:
711 dev->dfu_state = DFU_STATE_dfuERROR;
712 ret = RET_STALL;
713 goto out;
714 break;
716 break;
717 case DFU_STATE_dfuDNLOAD_SYNC:
718 switch (req) {
719 case USB_REQ_DFU_GETSTATUS:
720 handle_getstatus(urb, len);
721 /* FIXME: state transition depending on block completeness */
722 break;
723 case USB_REQ_DFU_GETSTATE:
724 handle_getstate(urb, len);
725 break;
726 default:
727 dev->dfu_state = DFU_STATE_dfuERROR;
728 ret = RET_STALL;
729 goto out;
731 break;
732 case DFU_STATE_dfuDNBUSY:
733 switch (req) {
734 case USB_REQ_DFU_GETSTATUS:
735 /* FIXME: only accept getstatus if bwPollTimeout
736 * has elapsed */
737 handle_getstatus(urb, len);
738 break;
739 default:
740 dev->dfu_state = DFU_STATE_dfuERROR;
741 ret = RET_STALL;
742 goto out;
744 break;
745 case DFU_STATE_dfuDNLOAD_IDLE:
746 switch (req) {
747 case USB_REQ_DFU_DNLOAD:
748 dev->dfu_state = DFU_STATE_dfuDNLOAD_SYNC;
749 ret = handle_dnload(urb, val, len, 0);
750 break;
751 case USB_REQ_DFU_ABORT:
752 dev->dfu_state = DFU_STATE_dfuIDLE;
753 ret = RET_ZLP;
754 break;
755 case USB_REQ_DFU_GETSTATUS:
756 handle_getstatus(urb, len);
757 break;
758 case USB_REQ_DFU_GETSTATE:
759 handle_getstate(urb, len);
760 break;
761 default:
762 dev->dfu_state = DFU_STATE_dfuERROR;
763 ret = RET_STALL;
764 break;
766 break;
767 case DFU_STATE_dfuMANIFEST_SYNC:
768 switch (req) {
769 case USB_REQ_DFU_GETSTATUS:
770 /* We're MainfestationTolerant */
771 dev->dfu_state = DFU_STATE_dfuIDLE;
772 handle_getstatus(urb, len);
773 break;
774 case USB_REQ_DFU_GETSTATE:
775 handle_getstate(urb, len);
776 break;
777 default:
778 dev->dfu_state = DFU_STATE_dfuERROR;
779 ret = RET_STALL;
780 break;
782 break;
783 case DFU_STATE_dfuMANIFEST:
784 /* we should never go here */
785 dev->dfu_state = DFU_STATE_dfuERROR;
786 ret = RET_STALL;
787 break;
788 case DFU_STATE_dfuMANIFEST_WAIT_RST:
789 /* we should never go here */
790 break;
791 case DFU_STATE_dfuUPLOAD_IDLE:
792 switch (req) {
793 case USB_REQ_DFU_UPLOAD:
794 /* state transition if less data then requested */
795 rc = handle_upload(urb, val, len, 0);
796 if (rc >= 0 && rc < len)
797 dev->dfu_state = DFU_STATE_dfuIDLE;
798 break;
799 case USB_REQ_DFU_ABORT:
800 dev->dfu_state = DFU_STATE_dfuIDLE;
801 /* no zlp? */
802 ret = RET_ZLP;
803 break;
804 case USB_REQ_DFU_GETSTATUS:
805 handle_getstatus(urb, len);
806 break;
807 case USB_REQ_DFU_GETSTATE:
808 handle_getstate(urb, len);
809 break;
810 default:
811 dev->dfu_state = DFU_STATE_dfuERROR;
812 ret = RET_STALL;
813 break;
815 break;
816 case DFU_STATE_dfuERROR:
817 switch (req) {
818 case USB_REQ_DFU_GETSTATUS:
819 handle_getstatus(urb, len);
820 break;
821 case USB_REQ_DFU_GETSTATE:
822 handle_getstate(urb, len);
823 break;
824 case USB_REQ_DFU_CLRSTATUS:
825 dev->dfu_state = DFU_STATE_dfuIDLE;
826 dev->dfu_status = DFU_STATUS_OK;
827 /* no zlp? */
828 ret = RET_ZLP;
829 break;
830 default:
831 dev->dfu_state = DFU_STATE_dfuERROR;
832 ret = RET_STALL;
833 break;
835 break;
836 default:
837 return DFU_EP0_UNHANDLED;
838 break;
841 out:
842 debug("new_state = %u, ret = %u\n", dev->dfu_state, ret);
844 switch (ret) {
845 case RET_ZLP:
846 //udc_ep0_send_zlp();
847 urb->actual_length = 0;
848 return DFU_EP0_ZLP;
849 break;
850 case RET_STALL:
851 //udc_ep0_send_stall();
852 return DFU_EP0_STALL;
853 break;
854 case RET_NOTHING:
855 break;
858 return DFU_EP0_DATA;
861 void str2wide (char *str, u16 * wide);
862 static struct usb_string_descriptor *create_usbstring(char *string)
864 struct usb_string_descriptor *strdesc;
865 int size = sizeof(*strdesc) + strlen(string)*2;
867 if (size > 255)
868 return NULL;
870 strdesc = malloc(size);
871 if (!strdesc)
872 return NULL;
874 strdesc->bLength = size;
875 strdesc->bDescriptorType = USB_DT_STRING;
876 str2wide(string, strdesc->wData);
878 return strdesc;
882 static void dfu_init_strings(struct usb_device_instance *dev)
884 int i;
885 struct usb_string_descriptor *strdesc;
887 strdesc = create_usbstring(CONFIG_DFU_CFG_STR);
888 usb_strings[DFU_STR_CONFIG] = strdesc;
890 for (i = 0; i < DFU_NUM_ALTERNATES; i++) {
891 if (i == 0) {
892 strdesc = create_usbstring(CONFIG_DFU_ALT0_STR);
893 } else {
894 struct part_info *part = get_partition_nand(i-1);
896 if (part)
897 strdesc = create_usbstring(part->name);
898 else
899 strdesc =
900 create_usbstring("undefined partition");
902 if (!strdesc)
903 continue;
904 usb_strings[STR_COUNT+i+1] = strdesc;
909 #ifdef CONFIG_NAND_DYNPART
911 void dfu_update_strings(void)
913 int i;
915 if (!system_dfu_state) {
916 printf("NASTY SURPRISE: system_dfu_state not set\n");
917 return;
920 for (i = 1; i != DFU_NUM_ALTERNATES; i++) {
921 struct part_info *part = get_partition_nand(i-1);
922 struct usb_string_descriptor *strdesc, **slot;
924 if (part)
925 strdesc = create_usbstring(part->name);
926 else
927 strdesc = create_usbstring("undefined partition");
928 if (!strdesc)
929 continue;
930 slot = usb_strings+STR_COUNT+i+1;
931 if (*slot)
932 free(*slot);
933 *slot = strdesc;
937 #endif /* CONFIG_NAND_DYNPART */
940 int dfu_init_instance(struct usb_device_instance *dev)
942 int i;
944 for (i = 0; i != DFU_NUM_ALTERNATES; i++) {
945 struct usb_interface_descriptor *uif =
946 dfu_cfg_descriptor.uif+i;
948 uif->bLength = USB_DT_INTERFACE_SIZE;
949 uif->bDescriptorType = USB_DT_INTERFACE;
950 uif->bAlternateSetting = i;
951 uif->bInterfaceClass = 0xfe;
952 uif->bInterfaceSubClass = 1;
953 uif->bInterfaceProtocol = 2;
954 uif->iInterface = DFU_STR_ALT(i);
957 dev->dfu_dev_desc = &dfu_dev_descriptor;
958 dev->dfu_cfg_desc = &dfu_cfg_descriptor;
959 dev->dfu_state = DFU_STATE_appIDLE;
960 dev->dfu_status = DFU_STATUS_OK;
962 if (system_dfu_state)
963 printf("SURPRISE: system_dfu_state is already set\n");
964 system_dfu_state = &dev->dfu_state;
966 dfu_init_strings(dev);
968 return 0;
971 static int stdout_switched;
973 /* event handler for usb device state events */
974 void dfu_event(struct usb_device_instance *device,
975 usb_device_event_t event, int data)
977 char *out;
979 switch (event) {
980 case DEVICE_RESET:
981 switch (device->dfu_state) {
982 case DFU_STATE_appDETACH:
983 device->dfu_state = DFU_STATE_dfuIDLE;
984 out = getenv("stdout");
985 if (out && !strcmp(out, "usbtty")) {
986 setenv("stdout", "vga");
987 setenv("stderr", "vga");
988 stdout_switched = 1;
990 printf("DFU: Switching to DFU Mode\n");
991 break;
992 case DFU_STATE_dfuMANIFEST_WAIT_RST:
993 device->dfu_state = DFU_STATE_appIDLE;
994 printf("DFU: Switching back to Runtime mode\n");
995 if (stdout_switched) {
996 setenv("stdout", "usbtty");
997 setenv("stderr", "usbtty");
998 stdout_switched = 0;
1000 break;
1001 default:
1002 break;
1004 break;
1005 case DEVICE_CONFIGURED:
1006 case DEVICE_DE_CONFIGURED:
1007 debug("SET_CONFIGURATION(%u) ", device->configuration);
1008 /* fallthrough */
1009 case DEVICE_SET_INTERFACE:
1010 debug("SET_INTERFACE(%u,%u) old_state = %u ",
1011 device->interface, device->alternate,
1012 device->dfu_state);
1013 switch (device->dfu_state) {
1014 case DFU_STATE_appIDLE:
1015 case DFU_STATE_appDETACH:
1016 case DFU_STATE_dfuIDLE:
1017 case DFU_STATE_dfuMANIFEST_WAIT_RST:
1018 /* do nothing, we're fine */
1019 break;
1020 case DFU_STATE_dfuDNLOAD_SYNC:
1021 case DFU_STATE_dfuDNBUSY:
1022 case DFU_STATE_dfuDNLOAD_IDLE:
1023 case DFU_STATE_dfuMANIFEST:
1024 device->dfu_state = DFU_STATE_dfuERROR;
1025 device->dfu_status = DFU_STATUS_errNOTDONE;
1026 /* FIXME: free malloc()ed buffer! */
1027 break;
1028 case DFU_STATE_dfuMANIFEST_SYNC:
1029 case DFU_STATE_dfuUPLOAD_IDLE:
1030 case DFU_STATE_dfuERROR:
1031 device->dfu_state = DFU_STATE_dfuERROR;
1032 device->dfu_status = DFU_STATUS_errUNKNOWN;
1033 break;
1035 debug("new_state = %u\n", device->dfu_state);
1036 break;
1037 default:
1038 break;
1041 #endif /* CONFIG_USBD_DFU */