usb: dfu: Schedule timer handler from USB workqueue

Use k_work_delayable instead of k_timer in order to execute timeout in
USB workqueue context instead of ISR context. This fixes Will-Detach on
targets where usb_dc_detach() uses functions not allowed in ISR context,
e.g. nrfx usb_dc_detach() acquires mutex.

Fixes: c27d48c89a ("usb: dfu: Support DFU with WinUSB on Windows")

Signed-off-by: Tomasz Moń <tomasz.mon@nordicsemi.no>
This commit is contained in:
Tomasz Moń 2023-01-02 10:34:32 +01:00 committed by Carles Cufí
commit 73e3fcabc0

View file

@ -91,7 +91,7 @@ LOG_MODULE_REGISTER(usb_dfu, CONFIG_USB_DEVICE_LOG_LEVEL);
static struct k_poll_event dfu_event;
static struct k_poll_signal dfu_signal;
static struct k_timer dfu_timer;
static struct k_work_delayable dfu_timer_work;
static struct k_work dfu_work;
@ -417,8 +417,10 @@ static void dfu_enter_idle(void)
}
}
static void dfu_timer_expired(struct k_timer *timer)
static void dfu_timer_work_handler(struct k_work *item)
{
ARG_UNUSED(item);
if (dfu_data.state == appDETACH) {
if (IS_ENABLED(CONFIG_USB_DFU_WILL_DETACH)) {
if (usb_dc_detach()) {
@ -693,7 +695,7 @@ static int dfu_class_handle_to_device(struct usb_setup_packet *setup,
/* Begin detach timeout timer */
timeout = MIN(setup->wValue, CONFIG_USB_DFU_DETACH_TIMEOUT);
}
k_timer_start(&dfu_timer, K_MSEC(timeout), K_FOREVER);
k_work_reschedule_for_queue(&USB_WORK_Q, &dfu_timer_work, K_MSEC(timeout));
break;
default:
LOG_DBG("Unsupported bmRequestType 0x%02x bRequest 0x%02x",
@ -747,7 +749,7 @@ static void dfu_status_cb(struct usb_cfg_data *cfg,
LOG_DBG("USB device reset detected, state %d", dfu_data.state);
if (!IS_ENABLED(CONFIG_USB_DFU_WILL_DETACH)) {
/* Stop the appDETACH timeout timer */
k_timer_stop(&dfu_timer);
k_work_cancel_delayable(&dfu_timer_work);
if (dfu_data.state == appDETACH) {
dfu_enter_idle();
}
@ -904,7 +906,7 @@ static int usb_dfu_init(const struct device *dev)
k_work_init(&dfu_work, dfu_work_handler);
k_poll_signal_init(&dfu_signal);
k_timer_init(&dfu_timer, dfu_timer_expired, NULL);
k_work_init_delayable(&dfu_timer_work, dfu_timer_work_handler);
#ifdef CONFIG_USB_DFU_REBOOT
k_work_init_delayable(&reboot_work, reboot_work_handler);