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_event dfu_event;
static struct k_poll_signal dfu_signal; 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; 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 (dfu_data.state == appDETACH) {
if (IS_ENABLED(CONFIG_USB_DFU_WILL_DETACH)) { if (IS_ENABLED(CONFIG_USB_DFU_WILL_DETACH)) {
if (usb_dc_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 */ /* Begin detach timeout timer */
timeout = MIN(setup->wValue, CONFIG_USB_DFU_DETACH_TIMEOUT); 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; break;
default: default:
LOG_DBG("Unsupported bmRequestType 0x%02x bRequest 0x%02x", 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); LOG_DBG("USB device reset detected, state %d", dfu_data.state);
if (!IS_ENABLED(CONFIG_USB_DFU_WILL_DETACH)) { if (!IS_ENABLED(CONFIG_USB_DFU_WILL_DETACH)) {
/* Stop the appDETACH timeout timer */ /* Stop the appDETACH timeout timer */
k_timer_stop(&dfu_timer); k_work_cancel_delayable(&dfu_timer_work);
if (dfu_data.state == appDETACH) { if (dfu_data.state == appDETACH) {
dfu_enter_idle(); 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_work_init(&dfu_work, dfu_work_handler);
k_poll_signal_init(&dfu_signal); 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 #ifdef CONFIG_USB_DFU_REBOOT
k_work_init_delayable(&reboot_work, reboot_work_handler); k_work_init_delayable(&reboot_work, reboot_work_handler);