usb: dfu: Signal completion of DFU

Generally when DFU is in progress, the system is not expected to
be doing anything else in addition. Hence, a completion signal
would help the system to know that DFU is over and it can proceed
towards next tasks.

Signed-off-by: Rajavardhan Gundi <rajavardhan.gundi@intel.com>
This commit is contained in:
Rajavardhan Gundi 2019-02-20 12:33:30 +05:30 committed by Anas Nashif
commit fa49e3e4c7
3 changed files with 68 additions and 0 deletions

View file

@ -119,4 +119,6 @@ enum dfu_state {
dfuERROR, dfuERROR,
}; };
void wait_for_usb_dfu(void);
#endif /* ZEPHYR_INCLUDE_USB_CLASS_USB_DFU_H_ */ #endif /* ZEPHYR_INCLUDE_USB_CLASS_USB_DFU_H_ */

View file

@ -126,10 +126,18 @@ source "subsys/usb/class/hid/Kconfig"
config USB_DFU_CLASS config USB_DFU_CLASS
bool "USB DFU Class Driver" bool "USB DFU Class Driver"
select MPU_ALLOW_FLASH_WRITE select MPU_ALLOW_FLASH_WRITE
select POLL
depends on IMG_MANAGER depends on IMG_MANAGER
help help
USB DFU class driver USB DFU class driver
config USB_DFU_WAIT_DELAY_MS
int
depends on USB_DFU_CLASS
default 12000
help
A thread can wait for a prescribed time (in ms) for DFU to begin
config USB_DFU_MAX_XFER_SIZE config USB_DFU_MAX_XFER_SIZE
int int
depends on USB_DFU_CLASS depends on USB_DFU_CLASS

View file

@ -68,6 +68,15 @@ LOG_MODULE_REGISTER(usb_dfu);
#define FIRMWARE_IMAGE_0_LABEL "image-1" #define FIRMWARE_IMAGE_0_LABEL "image-1"
#define FIRMWARE_IMAGE_1_LABEL "image-0" #define FIRMWARE_IMAGE_1_LABEL "image-0"
/* MCUBoot waits for CONFIG_USB_DFU_WAIT_DELAY_MS time in total to let DFU to
* be commenced. It intermittently checks every INTERMITTENT_CHECK_DELAY
* milliseconds to see if DFU has started.
*/
#define INTERMITTENT_CHECK_DELAY 50
static struct k_poll_event dfu_event;
static struct k_poll_signal dfu_signal;
static struct k_work dfu_work; static struct k_work dfu_work;
struct dfu_worker_data_t { struct dfu_worker_data_t {
@ -433,6 +442,8 @@ static int dfu_class_handle_req(struct usb_setup_packet *pSetup,
case dfuIDLE: case dfuIDLE:
LOG_DBG("DFU_DNLOAD start"); LOG_DBG("DFU_DNLOAD start");
dfu_reset_counters(); dfu_reset_counters();
k_poll_signal_reset(&dfu_signal);
if (dfu_data.flash_area_id != if (dfu_data.flash_area_id !=
DT_FLASH_AREA_IMAGE_1_ID) { DT_FLASH_AREA_IMAGE_1_ID) {
dfu_data.status = errWRITE; dfu_data.status = errWRITE;
@ -453,6 +464,7 @@ static int dfu_class_handle_req(struct usb_setup_packet *pSetup,
dfu_data_worker.worker_len = pSetup->wLength; dfu_data_worker.worker_len = pSetup->wLength;
if (dfu_data_worker.worker_len == 0) { if (dfu_data_worker.worker_len == 0) {
dfu_data.state = dfuMANIFEST_SYNC; dfu_data.state = dfuMANIFEST_SYNC;
k_poll_signal_raise(&dfu_signal, 0);
} }
memcpy(dfu_data_worker.buf, *data, pSetup->wLength); memcpy(dfu_data_worker.buf, *data, pSetup->wLength);
@ -741,6 +753,7 @@ static int usb_dfu_init(struct device *dev)
ARG_UNUSED(dev); ARG_UNUSED(dev);
k_work_init(&dfu_work, dfu_work_handler); k_work_init(&dfu_work, dfu_work_handler);
k_poll_signal_init(&dfu_signal);
#ifndef CONFIG_USB_COMPOSITE_DEVICE #ifndef CONFIG_USB_COMPOSITE_DEVICE
dfu_config.usb_device_description = usb_get_device_descriptor(); dfu_config.usb_device_description = usb_get_device_descriptor();
@ -772,4 +785,49 @@ static int usb_dfu_init(struct device *dev)
return 0; return 0;
} }
/**
* @brief Function to check if DFU is started.
*
* @return true if DNBUSY/DNLOAD_IDLE, false otherwise.
*/
static bool is_dfu_started(void)
{
if ((dfu_data.state == dfuDNBUSY) ||
(dfu_data.state == dfuDNLOAD_IDLE)) {
return true;
}
return false;
}
/**
* @brief Function to check and wait while the USB DFU is in progress.
*
* @return N/A
*/
void wait_for_usb_dfu(void)
{
/* Wait for a prescribed duration of time. If DFU hasn't started within
* that time, stop waiting and proceed further.
*/
for (int time = 0;
time < (CONFIG_USB_DFU_WAIT_DELAY_MS/INTERMITTENT_CHECK_DELAY);
time++) {
if (is_dfu_started()) {
k_poll_event_init(&dfu_event, K_POLL_TYPE_SIGNAL,
K_POLL_MODE_NOTIFY_ONLY, &dfu_signal);
/* Wait till DFU is complete */
if (k_poll(&dfu_event, 1, K_FOREVER) != 0) {
LOG_DBG("USB DFU Error");
}
LOG_INF("USB DFU Completed");
break;
}
k_sleep(INTERMITTENT_CHECK_DELAY);
}
}
SYS_INIT(usb_dfu_init, APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEVICE); SYS_INIT(usb_dfu_init, APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEVICE);