usb: dfu: f_dfu: Provide infrastructure to adjust DFU's Poll Timeout value
authorLukasz Majewski <l.majewski@samsung.com>
Mon, 9 Dec 2013 15:20:14 +0000 (16:20 +0100)
committerChanho Park <chanho61.park@samsung.com>
Fri, 24 Jul 2015 07:29:52 +0000 (16:29 +0900)
It is necessary to deter the host from sending subsequent DFU_GETSTATUS
request in the case of e.g. writing the buffer to medium.

Here the timeout is increased when we fill up the whole buffer. This delay
allows eMMC memory to perform its internal operations.
Otherwise we end up with HOST's error regarding GET_STATUS receive timeout.

Signed-off-by: Lukasz Majewski <l.majewski@samsung.com>
drivers/usb/gadget/f_dfu.c
drivers/usb/gadget/f_dfu.h
include/dfu.h

index e869703c56c86d22710e359a6fca5d62298b00a0..096606300f7c168b57090334d5a8700fb2fb8079 100644 (file)
@@ -52,6 +52,7 @@ struct f_dfu {
 
        /* Send/received block number is handy for data integrity check */
        int                             blk_seq_num;
+       unsigned int                    poll_timeout;
 };
 
 typedef int (*dfu_state_fn) (struct f_dfu *,
@@ -140,6 +141,33 @@ static struct usb_gadget_strings *dfu_strings[] = {
        NULL,
 };
 
+static void dfu_set_poll_timeout(struct dfu_status *dstat, unsigned int ms)
+{
+       /*
+        * The bwPollTimeout DFU_GETSTATUS request payload provides information
+        * about minimum time, in milliseconds, that the host should wait before
+        * sending a subsequent DFU_GETSTATUS request
+        *
+        * This permits the device to vary the delay depending on its need to
+        * erase or program the memory
+        *
+        */
+
+       unsigned char *p = (unsigned char *)&ms;
+
+       if (!ms || (ms & ~DFU_POLL_TIMEOUT_MASK)) {
+               dstat->bwPollTimeout[0] = 0;
+               dstat->bwPollTimeout[1] = 0;
+               dstat->bwPollTimeout[2] = 0;
+
+               return;
+       }
+
+       dstat->bwPollTimeout[0] = *p++;
+       dstat->bwPollTimeout[1] = *p++;
+       dstat->bwPollTimeout[2] = *p;
+}
+
 /*-------------------------------------------------------------------------*/
 
 static void dnload_request_complete(struct usb_ep *ep, struct usb_request *req)
@@ -169,11 +197,15 @@ static void handle_getstatus(struct usb_request *req)
                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)))
+                       dfu_set_poll_timeout(dstat, f_dfu->poll_timeout);
+
        /* send status response */
        dstat->bStatus = f_dfu->dfu_status;
-       dstat->bwPollTimeout[0] = 0;
-       dstat->bwPollTimeout[1] = 0;
-       dstat->bwPollTimeout[2] = 0;
        dstat->bState = f_dfu->dfu_state;
        dstat->iString = 0;
 }
@@ -737,6 +769,7 @@ static int dfu_bind_config(struct usb_configuration *c)
        f_dfu->usb_function.disable = dfu_disable;
        f_dfu->usb_function.strings = dfu_generic_strings,
        f_dfu->usb_function.setup = dfu_handle,
+       f_dfu->poll_timeout = DFU_DEFAULT_POLL_TIMEOUT;
 
        status = usb_add_function(c, &f_dfu->usb_function);
        if (status)
index bc457f4deac6db28cbcbe03cf3ff1f9189d21579..7a1548f33f5320cd9c142cd6a139701f72bc6235 100644 (file)
@@ -94,4 +94,6 @@ struct dfu_function_descriptor {
        __le16                          wTransferSize;
        __le16                          bcdDFUVersion;
 } __packed;
+
+#define DFU_POLL_TIMEOUT_MASK           (0xFFFFFFUL)
 #endif /* __F_DFU_H_ */
index dc28828f22cdfd5f3ad9e5ce73bc2ee07cfad428..3fe72ee8dcad364040d40718c668972a2b49b24d 100644 (file)
@@ -89,6 +89,9 @@ static inline unsigned int get_mmc_blk_size(int dev)
 #ifndef CONFIG_SYS_DFU_MAX_FILE_SIZE
 #define CONFIG_SYS_DFU_MAX_FILE_SIZE CONFIG_SYS_DFU_DATA_BUF_SIZE
 #endif
+#ifndef DFU_DEFAULT_POLL_TIMEOUT
+#define DFU_DEFAULT_POLL_TIMEOUT 0
+#endif
 
 struct dfu_entity {
        char                    name[DFU_NAME_SIZE];