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
1 changed files with 29 additions and 23 deletions
|
@ -283,12 +283,21 @@ static struct nrf_usbd_ctx usbd_ctx = {
|
||||||
.ready = false,
|
.ready = false,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
static inline struct nrf_usbd_ctx *get_usbd_ctx(void)
|
static inline struct nrf_usbd_ctx *get_usbd_ctx(void)
|
||||||
{
|
{
|
||||||
return &usbd_ctx;
|
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)
|
static inline nrfx_usbd_ep_t ep_addr_to_nrfx(uint8_t ep)
|
||||||
{
|
{
|
||||||
return (nrfx_usbd_ep_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();
|
nrfx_usbd_enable();
|
||||||
(void) hf_clock_enable(true, false);
|
(void) hf_clock_enable(true, false);
|
||||||
|
|
||||||
if (ctx->status_cb) {
|
/* No callback here.
|
||||||
ctx->status_cb(USB_DC_CONNECTED, NULL);
|
* Stack will be notified when the peripheral is ready.
|
||||||
}
|
*/
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case USBD_POWERED:
|
case USBD_POWERED:
|
||||||
LOG_DBG("USB Powered");
|
|
||||||
usbd_enable_endpoints(ctx);
|
usbd_enable_endpoints(ctx);
|
||||||
nrfx_usbd_start(true);
|
nrfx_usbd_start(true);
|
||||||
ctx->ready = true;
|
ctx->ready = true;
|
||||||
|
|
||||||
|
LOG_DBG("USB Powered");
|
||||||
|
|
||||||
if (ctx->status_cb) {
|
if (ctx->status_cb) {
|
||||||
ctx->status_cb(USB_DC_CONNECTED, NULL);
|
ctx->status_cb(USB_DC_CONNECTED, NULL);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case USBD_DETACHED:
|
case USBD_DETACHED:
|
||||||
LOG_DBG("USB Removed");
|
|
||||||
ctx->ready = false;
|
ctx->ready = false;
|
||||||
nrfx_usbd_disable();
|
nrfx_usbd_disable();
|
||||||
(void) hf_clock_enable(false, false);
|
(void) hf_clock_enable(false, false);
|
||||||
|
|
||||||
|
LOG_DBG("USB Removed");
|
||||||
|
|
||||||
if (ctx->status_cb) {
|
if (ctx->status_cb) {
|
||||||
ctx->status_cb(USB_DC_DISCONNECTED, NULL);
|
ctx->status_cb(USB_DC_DISCONNECTED, NULL);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case USBD_SUSPENDED:
|
case USBD_SUSPENDED:
|
||||||
LOG_DBG("USB Suspend state");
|
if (dev_ready()) {
|
||||||
nrfx_usbd_suspend();
|
nrfx_usbd_suspend();
|
||||||
|
LOG_DBG("USB Suspend state");
|
||||||
|
|
||||||
if (ctx->status_cb) {
|
if (ctx->status_cb) {
|
||||||
ctx->status_cb(USB_DC_SUSPEND, NULL);
|
ctx->status_cb(USB_DC_SUSPEND, NULL);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case USBD_RESUMED:
|
case USBD_RESUMED:
|
||||||
LOG_DBG("USB resume");
|
if (ctx->status_cb && dev_ready()) {
|
||||||
|
LOG_DBG("USB resume");
|
||||||
if (ctx->status_cb) {
|
|
||||||
ctx->status_cb(USB_DC_RESUME, NULL);
|
ctx->status_cb(USB_DC_RESUME, NULL);
|
||||||
}
|
}
|
||||||
break;
|
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)
|
static void usbd_event_transfer_ctrl(nrfx_usbd_evt_t const *const p_event)
|
||||||
{
|
{
|
||||||
struct nrf_usbd_ep_ctx *ep_ctx =
|
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);
|
ctx = CONTAINER_OF(item, struct nrf_usbd_ctx, usb_work);
|
||||||
|
|
||||||
while ((ev = usbd_evt_get()) != NULL) {
|
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) {
|
switch (ev->evt_type) {
|
||||||
case USBD_EVT_EP:
|
case USBD_EVT_EP:
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue