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
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,
27 * - make NAND support reasonably self-contained and put in apropriate
29 * - add some means of synchronization, i.e. block commandline access
30 * while DFU transfer is in progress, and return to commandline once
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
38 * - add something like uImage or some other header that provides CRC
40 * - make 'dnstate' attached to 'struct usb_device_instance'
44 #if defined(CONFIG_USBD_DFU)
47 DECLARE_GLOBAL_DATA_PTR
;
50 #include <linux/types.h>
51 #include <linux/list.h>
52 #include <asm/errno.h>
55 #include <usb_dfu_descriptors.h>
56 #include <usb_dfu_trailer.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 */
70 volatile enum dfu_state
*system_dfu_state
; /* for 3rd parties */
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
))
103 #ifdef CONFIG_REVISION_TAG
104 if (trailer
->revision
!= CONFIG_USB_DFU_REVISION
)
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
;
122 list_for_each(dentry
, &devices
) {
123 dev
= list_entry(dentry
, struct mtd_device
, link
);
124 if (dev
->id
->type
== MTD_DEV_TYPE_NAND
) {
126 list_for_each(pentry
, &dev
->parts
) {
128 part
= list_entry(pentry
,
129 struct part_info
, link
);
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);
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
;
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
);
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
;
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
);
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
;
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
);
213 debug("Error erasing\n");
214 dev
->dfu_state
= DFU_STATE_dfuERROR
;
215 dev
->dfu_status
= DFU_STATUS_errERASE
;
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
);
225 debug("Error writing\n");
226 dev
->dfu_state
= DFU_STATE_dfuERROR
;
227 dev
->dfu_status
= DFU_STATUS_errWRITE
;
234 /* FIXME: implement verify! */
238 static int erase_tail_clean_nand(struct urb
*urb
, struct dnload_state
*ds
)
240 struct usb_device_instance
*dev
= urb
->device
;
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
);
250 printf("Error erasing tail\n");
251 dev
->dfu_state
= DFU_STATE_dfuERROR
;
252 dev
->dfu_status
= DFU_STATUS_errERASE
;
256 ds
->off
+= ds
->erase_opts
.length
; /* for consistency */
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
;
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
);
275 debug("Error reading\n");
276 dev
->dfu_state
= DFU_STATE_dfuERROR
;
277 dev
->dfu_status
= DFU_STATUS_errWRITE
;
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
;
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
;
308 /* Make sure that we have a valid mtd partition table */
309 char *mtdp
= getenv("mtdparts");
311 run_command("dynpart", 0);
315 debug("zero-size write -> MANIFEST_SYNC ");
316 dev
->dfu_state
= DFU_STATE_dfuMANIFEST_SYNC
;
319 switch (dev
->alternate
) {
322 sprintf(buf
, "%lx", ds
->ptr
- ds
->buf
);
323 setenv("filesize", buf
);
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
;
338 rc
= erase_flash_verify_nand(urb
, ds
,
341 /* re-write dynenv marker in OOB */
342 run_command("dynenv set u-boot_env", 0);
346 ds
->ptr
= ds
->buf
= ds
->_buf
;
350 if (ds
->ptr
> ds
->buf
)
351 rc
= erase_flash_verify_nand(urb
, ds
,
353 ds
->nand
->erasesize
);
354 /* rootfs partition */
355 if (!rc
&& !strcmp(ds
->part
->name
, "rootfs"))
356 rc
= erase_tail_clean_nand(urb
, ds
);
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
;
373 if (first
&& ds
->buf
&& ds
->buf
!= ds
->_buf
&& ds
->buf
!= LOAD_ADDR
) {
378 switch (dev
->alternate
) {
381 printf("Starting DFU DOWNLOAD to RAM (0x%08p)\n",
387 memcpy(ds
->ptr
, urb
->buffer
, len
);
392 rc
= initialize_ds_nand(dev
, ds
);
395 ds
->buf
= malloc(ds
->part_net_size
);
397 printf("No memory for atomic buffer!!\n");
398 dev
->dfu_state
= DFU_STATE_dfuERROR
;
399 dev
->dfu_status
= DFU_STATUS_errUNKNOWN
;
403 printf("Starting Atomic DFU DOWNLOAD to partition '%s'\n",
407 remain_len
= (ds
->buf
+ ds
->part_net_size
) - ds
->ptr
;
408 if (remain_len
< len
) {
410 printf("End of write exceeds partition end\n");
411 dev
->dfu_state
= DFU_STATE_dfuERROR
;
412 dev
->dfu_status
= DFU_STATUS_errADDRESS
;
415 memcpy(ds
->ptr
, urb
->buffer
, len
);
420 rc
= initialize_ds_nand(dev
, ds
);
423 printf("Starting DFU DOWNLOAD to partition '%s'\n",
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
;
443 if (ds
->ptr
>= ds
->buf
+ size
) {
444 rc
= erase_flash_verify_nand(urb
, ds
,
446 ds
->nand
->erasesize
);
449 /* copy remainder of data into buffer */
450 memcpy(ds
->ptr
, urb
->buffer
+ actual_len
, len
- actual_len
);
451 ds
->ptr
+= (len
- actual_len
);
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
;
466 debug("upload(val=0x%02x, len=%u, first=%u) ", val
, len
, first
);
468 if (len
> CONFIG_USBD_DFU_XFER_SIZE
) {
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 ");
477 switch (dev
->alternate
) {
480 printf("Starting DFU Upload of RAM (0x%08p)\n",
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
;
495 rc
= initialize_ds_nand(dev
, ds
);
498 printf("Starting DFU Upload of partition '%s'\n",
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
510 remain
= (ds
->part
->offset
+ ds
->part
->size
) - ds
->off
;
514 rc
= read_next_nand(urb
, ds
, len
);
518 debug("uploading %u bytes ", len
);
519 urb
->buffer
= ds
->buf
;
520 urb
->actual_length
= len
;
524 debug("returning len=%u\n", 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
;
535 if (!urb
->buffer
|| urb
->buffer_length
< sizeof(*dstat
)) {
536 debug("invalid urb! ");
540 switch (dev
->dfu_state
) {
541 case DFU_STATE_dfuDNLOAD_SYNC
:
542 case DFU_STATE_dfuDNBUSY
:
544 if (fsr
& AT91C_MC_PROGE
) {
546 dev
->dfu_status
= DFU_STATUS_errPROG
;
547 dev
->dfu_state
= DFU_STATE_dfuERROR
;
548 } else if (fsr
& AT91C_MC_LOCKE
) {
550 dev
->dfu_status
= DFU_STATUS_errWRITE
;
551 dev
->dfu_state
= DFU_STATE_dfuERROR
;
552 } else if (fsr
& AT91C_MC_FRDY
) {
554 debug("DNLOAD_IDLE ");
555 dev
->dfu_state
= DFU_STATE_dfuDNLOAD_IDLE
;
559 dev
->dfu_state
= DFU_STATE_dfuDNBUSY
;
563 case DFU_STATE_dfuMANIFEST_SYNC
:
570 /* send status response */
571 dstat
->bStatus
= dev
->dfu_status
;
572 dstat
->bState
= dev
->dfu_state
;
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
)
585 if (!urb
->buffer
|| urb
->buffer_length
< sizeof(u_int8_t
)) {
586 debug("invalid urb! ");
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
598 static const struct usb_device_descriptor dfu_dev_descriptor
= {
599 .bLength
= USB_DT_DEVICE_SIZE
,
600 .bDescriptorType
= USB_DT_DEVICE
,
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
,
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
= {
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
+
623 .bConfigurationValue
= 1,
624 .iConfiguration
= DFU_STR_CONFIG
,
625 .bmAttributes
= BMATTRIBUTE_RESERVED
,
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
:
645 case USB_REQ_DFU_GETSTATUS
:
646 handle_getstatus(urb
, len
);
648 case USB_REQ_DFU_GETSTATE
:
649 handle_getstate(urb
, len
);
651 case USB_REQ_DFU_DETACH
:
652 dev
->dfu_state
= DFU_STATE_appDETACH
;
660 case DFU_STATE_appDETACH
:
662 case USB_REQ_DFU_GETSTATUS
:
663 handle_getstatus(urb
, len
);
665 case USB_REQ_DFU_GETSTATE
:
666 handle_getstate(urb
, len
);
669 dev
->dfu_state
= DFU_STATE_appIDLE
;
674 /* FIXME: implement timer to return to appIDLE */
676 case DFU_STATE_dfuIDLE
:
678 case USB_REQ_DFU_DNLOAD
:
680 dev
->dfu_state
= DFU_STATE_dfuERROR
;
684 dev
->dfu_state
= DFU_STATE_dfuDNLOAD_SYNC
;
685 ret
= handle_dnload(urb
, val
, len
, 1);
687 case USB_REQ_DFU_UPLOAD
:
688 dev
->dfu_state
= DFU_STATE_dfuUPLOAD_IDLE
;
689 handle_upload(urb
, val
, len
, 1);
691 case USB_REQ_DFU_ABORT
:
695 case USB_REQ_DFU_GETSTATUS
:
696 handle_getstatus(urb
, len
);
698 case USB_REQ_DFU_GETSTATE
:
699 handle_getstate(urb
, len
);
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
708 dev
->dfu_state
= DFU_STATE_dfuMANIFEST_WAIT_RST
;
711 dev
->dfu_state
= DFU_STATE_dfuERROR
;
717 case DFU_STATE_dfuDNLOAD_SYNC
:
719 case USB_REQ_DFU_GETSTATUS
:
720 handle_getstatus(urb
, len
);
721 /* FIXME: state transition depending on block completeness */
723 case USB_REQ_DFU_GETSTATE
:
724 handle_getstate(urb
, len
);
727 dev
->dfu_state
= DFU_STATE_dfuERROR
;
732 case DFU_STATE_dfuDNBUSY
:
734 case USB_REQ_DFU_GETSTATUS
:
735 /* FIXME: only accept getstatus if bwPollTimeout
737 handle_getstatus(urb
, len
);
740 dev
->dfu_state
= DFU_STATE_dfuERROR
;
745 case DFU_STATE_dfuDNLOAD_IDLE
:
747 case USB_REQ_DFU_DNLOAD
:
748 dev
->dfu_state
= DFU_STATE_dfuDNLOAD_SYNC
;
749 ret
= handle_dnload(urb
, val
, len
, 0);
751 case USB_REQ_DFU_ABORT
:
752 dev
->dfu_state
= DFU_STATE_dfuIDLE
;
755 case USB_REQ_DFU_GETSTATUS
:
756 handle_getstatus(urb
, len
);
758 case USB_REQ_DFU_GETSTATE
:
759 handle_getstate(urb
, len
);
762 dev
->dfu_state
= DFU_STATE_dfuERROR
;
767 case DFU_STATE_dfuMANIFEST_SYNC
:
769 case USB_REQ_DFU_GETSTATUS
:
770 /* We're MainfestationTolerant */
771 dev
->dfu_state
= DFU_STATE_dfuIDLE
;
772 handle_getstatus(urb
, len
);
774 case USB_REQ_DFU_GETSTATE
:
775 handle_getstate(urb
, len
);
778 dev
->dfu_state
= DFU_STATE_dfuERROR
;
783 case DFU_STATE_dfuMANIFEST
:
784 /* we should never go here */
785 dev
->dfu_state
= DFU_STATE_dfuERROR
;
788 case DFU_STATE_dfuMANIFEST_WAIT_RST
:
789 /* we should never go here */
791 case DFU_STATE_dfuUPLOAD_IDLE
:
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
;
799 case USB_REQ_DFU_ABORT
:
800 dev
->dfu_state
= DFU_STATE_dfuIDLE
;
804 case USB_REQ_DFU_GETSTATUS
:
805 handle_getstatus(urb
, len
);
807 case USB_REQ_DFU_GETSTATE
:
808 handle_getstate(urb
, len
);
811 dev
->dfu_state
= DFU_STATE_dfuERROR
;
816 case DFU_STATE_dfuERROR
:
818 case USB_REQ_DFU_GETSTATUS
:
819 handle_getstatus(urb
, len
);
821 case USB_REQ_DFU_GETSTATE
:
822 handle_getstate(urb
, len
);
824 case USB_REQ_DFU_CLRSTATUS
:
825 dev
->dfu_state
= DFU_STATE_dfuIDLE
;
826 dev
->dfu_status
= DFU_STATUS_OK
;
831 dev
->dfu_state
= DFU_STATE_dfuERROR
;
837 return DFU_EP0_UNHANDLED
;
842 debug("new_state = %u, ret = %u\n", dev
->dfu_state
, ret
);
846 //udc_ep0_send_zlp();
847 urb
->actual_length
= 0;
851 //udc_ep0_send_stall();
852 return DFU_EP0_STALL
;
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;
870 strdesc
= malloc(size
);
874 strdesc
->bLength
= size
;
875 strdesc
->bDescriptorType
= USB_DT_STRING
;
876 str2wide(string
, strdesc
->wData
);
882 static void dfu_init_strings(struct usb_device_instance
*dev
)
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
++) {
892 strdesc
= create_usbstring(CONFIG_DFU_ALT0_STR
);
894 struct part_info
*part
= get_partition_nand(i
-1);
897 strdesc
= create_usbstring(part
->name
);
900 create_usbstring("undefined partition");
904 usb_strings
[STR_COUNT
+i
+1] = strdesc
;
909 #ifdef CONFIG_NAND_DYNPART
911 void dfu_update_strings(void)
915 if (!system_dfu_state
) {
916 printf("NASTY SURPRISE: system_dfu_state not set\n");
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
;
925 strdesc
= create_usbstring(part
->name
);
927 strdesc
= create_usbstring("undefined partition");
930 slot
= usb_strings
+STR_COUNT
+i
+1;
937 #endif /* CONFIG_NAND_DYNPART */
940 int dfu_init_instance(struct usb_device_instance
*dev
)
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
);
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
)
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");
990 printf("DFU: Switching to DFU Mode\n");
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");
1005 case DEVICE_CONFIGURED
:
1006 case DEVICE_DE_CONFIGURED
:
1007 debug("SET_CONFIGURATION(%u) ", device
->configuration
);
1009 case DEVICE_SET_INTERFACE
:
1010 debug("SET_INTERFACE(%u,%u) old_state = %u ",
1011 device
->interface
, device
->alternate
,
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 */
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! */
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
;
1035 debug("new_state = %u\n", device
->dfu_state
);
1041 #endif /* CONFIG_USBD_DFU */