diff --git a/lib/usbd/backend/dwc_otg_private.h b/lib/usbd/backend/dwc_otg_private.h index e1a1f247..8aabbad3 100644 --- a/lib/usbd/backend/dwc_otg_private.h +++ b/lib/usbd/backend/dwc_otg_private.h @@ -83,11 +83,19 @@ struct dwc_otg_private_data { /* FIXME: used for all endpoint setup_data. */ struct usb_setup_data setup_data; + + /* Premature terminated OUT URBs are probably have followed by + * COMP_OUT cause IRQ RXC - that should be ommited, + * else next URB will terminate by this loosed RXC */ + uint32_t ep_prematured; }; #define USBD_DEVICE_EXTRA \ struct dwc_otg_private_data private_data; + + +#include "../usbd_private.h" void dwc_otg_init(usbd_device *dev); void dwc_otg_set_address(usbd_device *dev, uint8_t addr); @@ -112,6 +120,23 @@ typedef struct usbd_urb usbd_urb; void dwc_otg_urb_submit(usbd_device *dev, usbd_urb *urb); void dwc_otg_urb_cancel(usbd_device *dev, usbd_urb *urb); +static inline +bool is_ep_prematured(usbd_device *dev, uint8_t ep_addr) +{ + return (dev->private_data.ep_prematured & ep_free_mask(ep_addr)); +} + +static inline +void mark_ep_as_prematured(usbd_device *dev, uint8_t ep_addr, bool yes) +{ + uint32_t mask = ep_free_mask(ep_addr); + if (yes) { + dev->private_data.ep_prematured |= mask; + } else { + dev->private_data.ep_prematured &= ~mask; + } +} + END_DECLS #endif diff --git a/lib/usbd/backend/usbd_dwc_otg.c b/lib/usbd/backend/usbd_dwc_otg.c index ebb42f89..1970ee68 100644 --- a/lib/usbd/backend/usbd_dwc_otg.c +++ b/lib/usbd/backend/usbd_dwc_otg.c @@ -207,6 +207,7 @@ void dwc_otg_ep_prepare_start(usbd_device *dev) dev->private_data.fifo_rx_usage_overall = 16; /* by EP0 and constant */ dev->private_data.fifo_rx_usage_packet = fifo_word + 1; /* EP0 */ + dev->private_data.ep_prematured = 0; disable_all_non_ep0(dev); @@ -684,6 +685,7 @@ static void premature_urb_complete(usbd_device *dev, usbd_urb *urb, REBASE(DWC_OTG_DOEPxINT, ep_num) = 0xFFFF ^ DWC_OTG_DOEPINT_STUP; REBASE(DWC_OTG_DAINTMSK) &= ~DWC_OTG_DAINTMSK_OEPM(ep_num); } + mark_ep_as_prematured(dev, transfer->ep_addr, true); usbd_urb_complete(dev, urb, status); } @@ -919,6 +921,15 @@ static void process_out_endpoint_interrupt(usbd_device *dev, uint8_t ep_num) LOGF_LN("Transfer Complete: endpoint 0x%"PRIx8, ep_addr); usbd_urb *urb = usbd_find_active_urb(dev, ep_addr); + if (is_ep_prematured(dev, ep_addr)) { + if (urb != NULL){ + //* ommit this RXC and restart current URB + REBASE(DWC_OTG_DOEPxCTL, ep_num) |= DWC_OTG_DOEP0CTL_EPENA + | DWC_OTG_DOEP0CTL_CNAK; + } + mark_ep_as_prematured(dev, ep_addr, false); + } + else if (!ep_num && urb != NULL && dev->private_data.ep0tsiz_pktcnt) { /* We are still expecting data! */