drivers: usb: nordic: Fix for events when cable is detached
When user disconnects the USB cable, peripheral should be immediately disabled, howewer a delay may occur when driver events are processed from a workqueue or higher-priority thread/ISR is active. This may lead to a fake resume/reset event (peripheral-specific behavior). This fix drops such events when cable is detached. Fixes #13822 Signed-off-by: Paweł Zadrożniak <pawel.zadrozniak@nordicsemi.no>
This commit is contained in:
parent
bcf3d8e16b
commit
79dc1feeb3
|
@ -283,12 +283,21 @@ static struct nrf_usbd_ctx usbd_ctx = {
|
|||
.ready = false,
|
||||
};
|
||||
|
||||
|
||||
static inline struct nrf_usbd_ctx *get_usbd_ctx(void)
|
||||
{
|
||||
return &usbd_ctx;
|
||||
}
|
||||
|
||||
static inline bool dev_attached(void)
|
||||
{
|
||||
return get_usbd_ctx()->attached;
|
||||
}
|
||||
|
||||
static inline bool dev_ready(void)
|
||||
{
|
||||
return get_usbd_ctx()->ready;
|
||||
}
|
||||
|
||||
static inline nrfx_usbd_ep_t ep_addr_to_nrfx(uint8_t ep)
|
||||
{
|
||||
return (nrfx_usbd_ep_t)ep;
|
||||
|
@ -750,45 +759,48 @@ static inline void usbd_work_process_pwr_events(struct usbd_pwr_event *pwr_evt)
|
|||
nrfx_usbd_enable();
|
||||
(void) hf_clock_enable(true, false);
|
||||
|
||||
if (ctx->status_cb) {
|
||||
ctx->status_cb(USB_DC_CONNECTED, NULL);
|
||||
}
|
||||
/* No callback here.
|
||||
* Stack will be notified when the peripheral is ready.
|
||||
*/
|
||||
break;
|
||||
|
||||
case USBD_POWERED:
|
||||
LOG_DBG("USB Powered");
|
||||
usbd_enable_endpoints(ctx);
|
||||
nrfx_usbd_start(true);
|
||||
ctx->ready = true;
|
||||
|
||||
LOG_DBG("USB Powered");
|
||||
|
||||
if (ctx->status_cb) {
|
||||
ctx->status_cb(USB_DC_CONNECTED, NULL);
|
||||
}
|
||||
break;
|
||||
|
||||
case USBD_DETACHED:
|
||||
LOG_DBG("USB Removed");
|
||||
ctx->ready = false;
|
||||
nrfx_usbd_disable();
|
||||
(void) hf_clock_enable(false, false);
|
||||
|
||||
LOG_DBG("USB Removed");
|
||||
|
||||
if (ctx->status_cb) {
|
||||
ctx->status_cb(USB_DC_DISCONNECTED, NULL);
|
||||
}
|
||||
break;
|
||||
|
||||
case USBD_SUSPENDED:
|
||||
LOG_DBG("USB Suspend state");
|
||||
nrfx_usbd_suspend();
|
||||
if (dev_ready()) {
|
||||
nrfx_usbd_suspend();
|
||||
LOG_DBG("USB Suspend state");
|
||||
|
||||
if (ctx->status_cb) {
|
||||
ctx->status_cb(USB_DC_SUSPEND, NULL);
|
||||
if (ctx->status_cb) {
|
||||
ctx->status_cb(USB_DC_SUSPEND, NULL);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case USBD_RESUMED:
|
||||
LOG_DBG("USB resume");
|
||||
|
||||
if (ctx->status_cb) {
|
||||
if (ctx->status_cb && dev_ready()) {
|
||||
LOG_DBG("USB resume");
|
||||
ctx->status_cb(USB_DC_RESUME, NULL);
|
||||
}
|
||||
break;
|
||||
|
@ -909,16 +921,6 @@ static inline void usbd_work_process_ep_events(struct usbd_ep_event *ep_evt)
|
|||
}
|
||||
}
|
||||
|
||||
static inline bool dev_attached(void)
|
||||
{
|
||||
return get_usbd_ctx()->attached;
|
||||
}
|
||||
|
||||
static inline bool dev_ready(void)
|
||||
{
|
||||
return get_usbd_ctx()->ready;
|
||||
}
|
||||
|
||||
static void usbd_event_transfer_ctrl(nrfx_usbd_evt_t const *const p_event)
|
||||
{
|
||||
struct nrf_usbd_ep_ctx *ep_ctx =
|
||||
|
@ -1235,6 +1237,10 @@ static void usbd_work_handler(struct k_work *item)
|
|||
ctx = CONTAINER_OF(item, struct nrf_usbd_ctx, usb_work);
|
||||
|
||||
while ((ev = usbd_evt_get()) != NULL) {
|
||||
if (!dev_ready() && ev->evt_type != USBD_EVT_POWER) {
|
||||
/* Drop non-power events when cable is detached. */
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (ev->evt_type) {
|
||||
case USBD_EVT_EP:
|
||||
|
|
Loading…
Reference in a new issue