usb: dfu: introduce dfuMANIFEST state
authorHeiko Schocher <hs@denx.de>
Tue, 18 Mar 2014 07:09:56 +0000 (08:09 +0100)
committerMarek Vasut <marex@denx.de>
Sun, 23 Mar 2014 01:20:09 +0000 (02:20 +0100)
on nand flash using ubi, after the download of the new image into
the flash, the "rest" of the nand sectors get erased while flushing
the medium. With current u-boot version dfu-util may show:

Starting download: [##################################################] finished!
state(7) = dfuMANIFEST, status(0) = No error condition is present
unable to read DFU status

as get_status is not answered while erasing sectors, if erasing
needs some time.

So do the following changes to prevent this:

- introduce dfuManifest state
  According to dfu specification
  ( http://www.usb.org/developers/devclass_docs/usbdfu10.pdf ) section 7:
  "the device enters the dfuMANIFEST-SYNC state and awaits the solicitation
   of the status report by the host. Upon receipt of the anticipated
   DFU_GETSTATUS, the device enters the dfuMANIFEST state, where it
   completes its reprogramming operations."

- when stepping into dfuManifest state, sending a PollTimeout
  DFU_MANIFEST_POLL_TIMEOUT in ms, to the host, so the host
  (dfu-util) waits the PollTimeout before sending a get_status again.

Signed-off-by: Heiko Schocher <hs@denx.de>
Cc: Lukasz Majewski <l.majewski@samsung.com>
Cc: Kyungmin Park <kyungmin.park@samsung.com>
Cc: Marek Vasut <marex@denx.de>
Cc: Pantelis Antoniou <panto@antoniou-consulting.com>
README
drivers/dfu/dfu.c
drivers/usb/gadget/f_dfu.c
include/dfu.h

diff --git a/README b/README
index 216f0c70aa9403534127dcd256627fa55e12f08e..7cb7c4f6267f10eec034d0b68c29f28242b9cd7a 100644 (file)
--- a/README
+++ b/README
@@ -1525,6 +1525,16 @@ The following options need to be configured:
                this to the maximum filesize (in bytes) for the buffer.
                Default is 4 MiB if undefined.
 
+               DFU_DEFAULT_POLL_TIMEOUT
+               Poll timeout [ms], is the timeout a device can send to the
+               host. The host must wait for this timeout before sending
+               a subsequent DFU_GET_STATUS request to the device.
+
+               DFU_MANIFEST_POLL_TIMEOUT
+               Poll timeout [ms], which the device sends to the host when
+               entering dfuMANIFEST state. Host waits this timeout, before
+               sending again an USB request to the device.
+
 - Journaling Flash filesystem support:
                CONFIG_JFFS2_NAND, CONFIG_JFFS2_NAND_OFF, CONFIG_JFFS2_NAND_SIZE,
                CONFIG_JFFS2_NAND_DEV
index 1aced26c4e8824995ac29b540fcacf290b07b9d8..f94c412aa982a65b1a528464bed1832b17defa59 100644 (file)
@@ -218,10 +218,6 @@ int dfu_write(struct dfu_entity *dfu, void *buf, int size, int blk_seq_num)
                        ret = tret;
        }
 
-       /* end? */
-       if (size == 0)
-               ret = dfu_flush(dfu, buf, size, blk_seq_num);
-
        return ret = 0 ? size : ret;
 }
 
index a045864d730686448c4740eccd56585a80291f54..de75ff13390c44bdc961136ad02ad83452c580a0 100644 (file)
@@ -164,9 +164,14 @@ static void dnload_request_complete(struct usb_ep *ep, struct usb_request *req)
 
        dfu_write(dfu_get_entity(f_dfu->altsetting), req->buf,
                  req->length, f_dfu->blk_seq_num);
+}
 
-       if (req->length == 0)
-               puts("DOWNLOAD ... OK\nCtrl+C to exit ...\n");
+static void dnload_request_flush(struct usb_ep *ep, struct usb_request *req)
+{
+       struct f_dfu *f_dfu = req->context;
+
+       dfu_flush(dfu_get_entity(f_dfu->altsetting), req->buf,
+                 req->length, f_dfu->blk_seq_num);
 }
 
 static void handle_getstatus(struct usb_request *req)
@@ -174,19 +179,22 @@ static void handle_getstatus(struct usb_request *req)
        struct dfu_status *dstat = (struct dfu_status *)req->buf;
        struct f_dfu *f_dfu = req->context;
 
+       dfu_set_poll_timeout(dstat, 0);
+
        switch (f_dfu->dfu_state) {
        case DFU_STATE_dfuDNLOAD_SYNC:
        case DFU_STATE_dfuDNBUSY:
                f_dfu->dfu_state = DFU_STATE_dfuDNLOAD_IDLE;
                break;
        case DFU_STATE_dfuMANIFEST_SYNC:
+               f_dfu->dfu_state = DFU_STATE_dfuMANIFEST;
                break;
+       case DFU_STATE_dfuMANIFEST:
+               dfu_set_poll_timeout(dstat, DFU_MANIFEST_POLL_TIMEOUT);
        default:
                break;
        }
 
-       dfu_set_poll_timeout(dstat, 0);
-
        if (f_dfu->poll_timeout)
                if (!(f_dfu->blk_seq_num %
                      (dfu_get_buf_size() / DFU_USB_BUFSIZ)))
@@ -446,10 +454,11 @@ static int state_dfu_manifest_sync(struct f_dfu *f_dfu,
        switch (ctrl->bRequest) {
        case USB_REQ_DFU_GETSTATUS:
                /* We're MainfestationTolerant */
-               f_dfu->dfu_state = DFU_STATE_dfuIDLE;
+               f_dfu->dfu_state = DFU_STATE_dfuMANIFEST;
                handle_getstatus(req);
                f_dfu->blk_seq_num = 0;
                value = RET_STAT_LEN;
+               req->complete = dnload_request_flush;
                break;
        case USB_REQ_DFU_GETSTATE:
                handle_getstate(req);
@@ -463,6 +472,33 @@ static int state_dfu_manifest_sync(struct f_dfu *f_dfu,
        return value;
 }
 
+static int state_dfu_manifest(struct f_dfu *f_dfu,
+                             const struct usb_ctrlrequest *ctrl,
+                             struct usb_gadget *gadget,
+                             struct usb_request *req)
+{
+       int value = 0;
+
+       switch (ctrl->bRequest) {
+       case USB_REQ_DFU_GETSTATUS:
+               /* We're MainfestationTolerant */
+               f_dfu->dfu_state = DFU_STATE_dfuIDLE;
+               handle_getstatus(req);
+               f_dfu->blk_seq_num = 0;
+               value = RET_STAT_LEN;
+               puts("DOWNLOAD ... OK\nCtrl+C to exit ...\n");
+               break;
+       case USB_REQ_DFU_GETSTATE:
+               handle_getstate(req);
+               break;
+       default:
+               f_dfu->dfu_state = DFU_STATE_dfuERROR;
+               value = RET_STALL;
+               break;
+       }
+       return value;
+}
+
 static int state_dfu_upload_idle(struct f_dfu *f_dfu,
                                 const struct usb_ctrlrequest *ctrl,
                                 struct usb_gadget *gadget,
@@ -539,7 +575,7 @@ static dfu_state_fn dfu_state[] = {
        state_dfu_dnbusy,        /* DFU_STATE_dfuDNBUSY */
        state_dfu_dnload_idle,   /* DFU_STATE_dfuDNLOAD_IDLE */
        state_dfu_manifest_sync, /* DFU_STATE_dfuMANIFEST_SYNC */
-       NULL,                    /* DFU_STATE_dfuMANIFEST */
+       state_dfu_manifest,      /* DFU_STATE_dfuMANIFEST */
        NULL,                    /* DFU_STATE_dfuMANIFEST_WAIT_RST */
        state_dfu_upload_idle,   /* DFU_STATE_dfuUPLOAD_IDLE */
        state_dfu_error          /* DFU_STATE_dfuERROR */
index 272a245764a5319b76c1bd24a0b97a8cecfa58bc..6c71ecbe3555377fd83eefc2f0fdd3a7a173646b 100644 (file)
@@ -80,6 +80,9 @@ static inline unsigned int get_mmc_blk_size(int dev)
 #ifndef DFU_DEFAULT_POLL_TIMEOUT
 #define DFU_DEFAULT_POLL_TIMEOUT 0
 #endif
+#ifndef DFU_MANIFEST_POLL_TIMEOUT
+#define DFU_MANIFEST_POLL_TIMEOUT      DFU_DEFAULT_POLL_TIMEOUT
+#endif
 
 struct dfu_entity {
        char                    name[DFU_NAME_SIZE];