usb: dfu: f_dfu: Provide infrastructure to adjust DFU's Poll Timeout value
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>
diff --git a/drivers/usb/gadget/f_dfu.c b/drivers/usb/gadget/f_dfu.c
index 37d04a1..b4b4aa4 100644
--- a/drivers/usb/gadget/f_dfu.c
+++ b/drivers/usb/gadget/f_dfu.c
@@ -40,6 +40,7 @@
/* 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 *,
@@ -128,6 +129,33 @@
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)
@@ -157,11 +185,15 @@
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;
}
@@ -725,6 +757,7 @@
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)