|  | @@ -11,10 +11,16 @@
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  #include "hw_dwc_otg.h"
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -static struct {
 | 
	
		
			
				|  |  | -    int rx_count;
 | 
	
		
			
				|  |  | -    uint32_t rx_data[USB_FS_MPS / 4];
 | 
	
		
			
				|  |  | -    bool_t rx_ready, tx_ready;
 | 
	
		
			
				|  |  | +#define RX_NR 8
 | 
	
		
			
				|  |  | +#define RX_MASK(x) ((x) & (RX_NR-1))
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static struct ep {
 | 
	
		
			
				|  |  | +    struct {
 | 
	
		
			
				|  |  | +        uint32_t data[USB_FS_MPS / 4];
 | 
	
		
			
				|  |  | +        uint32_t count;
 | 
	
		
			
				|  |  | +    } rx[RX_NR];
 | 
	
		
			
				|  |  | +    uint16_t rxc, rxp;
 | 
	
		
			
				|  |  | +    bool_t rx_active, tx_ready;
 | 
	
		
			
				|  |  |  } eps[conf_nr_ep];
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  static void core_reset(void)
 | 
	
	
		
			
				|  | @@ -49,17 +55,20 @@ static bool_t is_high_speed(void)
 | 
	
		
			
				|  |  |      return ((otgd->dsts >> 1) & 3) == 0;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -static void prepare_rx(uint8_t ep)
 | 
	
		
			
				|  |  | +static void prepare_rx(uint8_t epnr)
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  | -    OTG_DOEP doep = &otg_doep[ep];
 | 
	
		
			
				|  |  | -    uint16_t len = (ep == 0) ? 64 : (doep->ctl & 0x7ff);
 | 
	
		
			
				|  |  | +    OTG_DOEP doep = &otg_doep[epnr];
 | 
	
		
			
				|  |  | +    uint16_t mps = (epnr == 0) ? 64 : (doep->ctl & 0x7ff);
 | 
	
		
			
				|  |  |      uint32_t tsiz = doep->tsiz & 0xe0000000;
 | 
	
		
			
				|  |  | +    int pktcnt = (epnr == 0) ? 1 : RX_NR;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    tsiz |= OTG_DOEPTSZ_PKTCNT(1);
 | 
	
		
			
				|  |  | -    tsiz |= OTG_DOEPTSZ_XFERSIZ(len);
 | 
	
		
			
				|  |  | +    tsiz |= OTG_DOEPTSZ_PKTCNT(pktcnt);
 | 
	
		
			
				|  |  | +    tsiz |= OTG_DOEPTSZ_XFERSIZ(mps * pktcnt);
 | 
	
		
			
				|  |  |      doep->tsiz = tsiz;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      doep->ctl |= OTG_DOEPCTL_CNAK | OTG_DOEPCTL_EPENA;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    eps[epnr].rx_active = TRUE;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  static void read_packet(void *p, int len)
 | 
	
	
		
			
				|  | @@ -70,12 +79,12 @@ static void read_packet(void *p, int len)
 | 
	
		
			
				|  |  |          *_p++ = otg_dfifo[0].x[0];
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -static void write_packet(const void *p, uint8_t ep, int len)
 | 
	
		
			
				|  |  | +static void write_packet(const void *p, uint8_t epnr, int len)
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  |      const uint32_t *_p = p;
 | 
	
		
			
				|  |  |      unsigned int n = (len + 3) / 4;
 | 
	
		
			
				|  |  |      while (n--)
 | 
	
		
			
				|  |  | -        otg_dfifo[ep].x[0] = *_p++;
 | 
	
		
			
				|  |  | +        otg_dfifo[epnr].x[0] = *_p++;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  static void fifos_init(void)
 | 
	
	
		
			
				|  | @@ -225,75 +234,77 @@ void hw_usb_deinit(void)
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -int ep_rx_ready(uint8_t ep)
 | 
	
		
			
				|  |  | +int ep_rx_ready(uint8_t epnr)
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  | -    return eps[ep].rx_ready ? eps[ep].rx_count : -1;
 | 
	
		
			
				|  |  | +    struct ep *ep = &eps[epnr];
 | 
	
		
			
				|  |  | +    return (ep->rxc != ep->rxp) ? ep->rx[RX_MASK(ep->rxc)].count : -1;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -bool_t ep_tx_ready(uint8_t ep)
 | 
	
		
			
				|  |  | +bool_t ep_tx_ready(uint8_t epnr)
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  | -    return eps[ep].tx_ready;
 | 
	
		
			
				|  |  | +    return eps[epnr].tx_ready;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -void usb_read(uint8_t ep, void *buf, uint32_t len)
 | 
	
		
			
				|  |  | +void usb_read(uint8_t epnr, void *buf, uint32_t len)
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  | -    memcpy(buf, eps[ep].rx_data, len);
 | 
	
		
			
				|  |  | -    eps[ep].rx_ready = FALSE;
 | 
	
		
			
				|  |  | -    prepare_rx(ep);
 | 
	
		
			
				|  |  | +    struct ep *ep = &eps[epnr];
 | 
	
		
			
				|  |  | +    memcpy(buf, ep->rx[RX_MASK(ep->rxc++)].data, len);
 | 
	
		
			
				|  |  | +    if (!ep->rx_active && (ep->rxc == ep->rxp))
 | 
	
		
			
				|  |  | +        prepare_rx(epnr);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -void usb_write(uint8_t ep, const void *buf, uint32_t len)
 | 
	
		
			
				|  |  | +void usb_write(uint8_t epnr, const void *buf, uint32_t len)
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  | -    OTG_DIEP diep = &otg_diep[ep];
 | 
	
		
			
				|  |  | +    OTG_DIEP diep = &otg_diep[epnr];
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      diep->tsiz = OTG_DIEPTSIZ_PKTCNT(1) | len;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  //    if (len != 0)
 | 
	
		
			
				|  |  | -//        otgd->diepempmsk |= 1u << ep;
 | 
	
		
			
				|  |  | +//        otgd->diepempmsk |= 1u << epnr;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      diep->ctl |= OTG_DIEPCTL_CNAK | OTG_DIEPCTL_EPENA;
 | 
	
		
			
				|  |  | -    write_packet(buf, ep, len);
 | 
	
		
			
				|  |  | -    eps[ep].tx_ready = FALSE;
 | 
	
		
			
				|  |  | +    write_packet(buf, epnr, len);
 | 
	
		
			
				|  |  | +    eps[epnr].tx_ready = FALSE;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -void usb_stall(uint8_t ep)
 | 
	
		
			
				|  |  | +void usb_stall(uint8_t epnr)
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  | -    otg_diep[ep].ctl |= OTG_DIEPCTL_STALL;
 | 
	
		
			
				|  |  | -    otg_doep[ep].ctl |= OTG_DOEPCTL_STALL;
 | 
	
		
			
				|  |  | +    otg_diep[epnr].ctl |= OTG_DIEPCTL_STALL;
 | 
	
		
			
				|  |  | +    otg_doep[epnr].ctl |= OTG_DOEPCTL_STALL;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -void usb_configure_ep(uint8_t ep, uint8_t type, uint32_t size)
 | 
	
		
			
				|  |  | +void usb_configure_ep(uint8_t epnr, uint8_t type, uint32_t size)
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  | -    bool_t in = !!(ep & 0x80);
 | 
	
		
			
				|  |  | -    ep &= 0x7f;
 | 
	
		
			
				|  |  | +    bool_t in = !!(epnr & 0x80);
 | 
	
		
			
				|  |  | +    epnr &= 0x7f;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      if (type == EPT_DBLBUF)
 | 
	
		
			
				|  |  |          type = EPT_BULK;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    if (in || (ep == 0)) {
 | 
	
		
			
				|  |  | -        otgd->daintmsk |= 1u << ep;
 | 
	
		
			
				|  |  | -        if (!(otg_diep[ep].ctl & OTG_DIEPCTL_USBAEP)) {
 | 
	
		
			
				|  |  | -            otg_diep[ep].ctl |= 
 | 
	
		
			
				|  |  | +    if (in || (epnr == 0)) {
 | 
	
		
			
				|  |  | +        otgd->daintmsk |= 1u << epnr;
 | 
	
		
			
				|  |  | +        if (!(otg_diep[epnr].ctl & OTG_DIEPCTL_USBAEP)) {
 | 
	
		
			
				|  |  | +            otg_diep[epnr].ctl |= 
 | 
	
		
			
				|  |  |                  OTG_DIEPCTL_MPSIZ(size) |
 | 
	
		
			
				|  |  |                  OTG_DIEPCTL_EPTYP(type) |
 | 
	
		
			
				|  |  | -                OTG_DIEPCTL_TXFNUM(ep) |
 | 
	
		
			
				|  |  | +                OTG_DIEPCTL_TXFNUM(epnr) |
 | 
	
		
			
				|  |  |                  OTG_DIEPCTL_SD0PID |
 | 
	
		
			
				|  |  |                  OTG_DIEPCTL_USBAEP;
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  | -        eps[ep].tx_ready = TRUE;
 | 
	
		
			
				|  |  | +        eps[epnr].tx_ready = TRUE;
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      if (!in) {
 | 
	
		
			
				|  |  | -        otgd->daintmsk |= 1u << (ep + 16);
 | 
	
		
			
				|  |  | -        if (!(otg_doep[ep].ctl & OTG_DOEPCTL_USBAEP)) {
 | 
	
		
			
				|  |  | -            otg_doep[ep].ctl |= 
 | 
	
		
			
				|  |  | +        otgd->daintmsk |= 1u << (epnr + 16);
 | 
	
		
			
				|  |  | +        if (!(otg_doep[epnr].ctl & OTG_DOEPCTL_USBAEP)) {
 | 
	
		
			
				|  |  | +            otg_doep[epnr].ctl |= 
 | 
	
		
			
				|  |  |                  OTG_DOEPCTL_MPSIZ(size) |
 | 
	
		
			
				|  |  |                  OTG_DOEPCTL_EPTYP(type) |
 | 
	
		
			
				|  |  |                  OTG_DIEPCTL_SD0PID |
 | 
	
		
			
				|  |  |                  OTG_DOEPCTL_USBAEP;
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  | -        eps[ep].rx_ready = FALSE;
 | 
	
		
			
				|  |  | -        prepare_rx(ep);
 | 
	
		
			
				|  |  | +        eps[epnr].rxc = eps[epnr].rxp = 0;
 | 
	
		
			
				|  |  | +        prepare_rx(epnr);
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -351,51 +362,63 @@ static void handle_rx_transfer(void)
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  |      uint32_t grxsts = otg->grxstsp;
 | 
	
		
			
				|  |  |      unsigned int bcnt = OTG_RXSTS_BCNT(grxsts);
 | 
	
		
			
				|  |  | -    unsigned int ep = OTG_RXSTS_CHNUM(grxsts);
 | 
	
		
			
				|  |  | +    unsigned int epnr = OTG_RXSTS_CHNUM(grxsts);
 | 
	
		
			
				|  |  | +    unsigned int rxp;
 | 
	
		
			
				|  |  | +    struct ep *ep = &eps[epnr];
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |      switch (OTG_RXSTS_PKTSTS(grxsts)) {
 | 
	
		
			
				|  |  |      case STS_SETUP_UPDT:
 | 
	
		
			
				|  |  |          bcnt = 8;
 | 
	
		
			
				|  |  |      case STS_DATA_UPDT:
 | 
	
		
			
				|  |  | -        read_packet(eps[ep].rx_data, bcnt);
 | 
	
		
			
				|  |  | -        eps[ep].rx_count = bcnt;
 | 
	
		
			
				|  |  | +        ASSERT(ep->rx_active);
 | 
	
		
			
				|  |  | +        ASSERT((uint16_t)(ep->rxp - ep->rxc) < RX_NR);
 | 
	
		
			
				|  |  | +        rxp = RX_MASK(ep->rxp++);
 | 
	
		
			
				|  |  | +        read_packet(ep->rx[rxp].data, bcnt);
 | 
	
		
			
				|  |  | +        ep->rx[rxp].count = bcnt;
 | 
	
		
			
				|  |  |          break;
 | 
	
		
			
				|  |  |      default:
 | 
	
		
			
				|  |  |          break;
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -static void handle_oepint(uint8_t ep)
 | 
	
		
			
				|  |  | +static void handle_oepint(uint8_t epnr)
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  | -    uint32_t oepint = otg_doep[ep].intsts & otgd->doepmsk;
 | 
	
		
			
				|  |  | +    uint32_t oepint = otg_doep[epnr].intsts & otgd->doepmsk;
 | 
	
		
			
				|  |  | +    struct ep *ep = &eps[epnr];
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    otg_doep[ep].intsts = oepint;
 | 
	
		
			
				|  |  | +    otg_doep[epnr].intsts = oepint;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      if (oepint & OTG_DOEPMSK_XFRCM) {
 | 
	
		
			
				|  |  | -        eps[ep].rx_ready = TRUE;
 | 
	
		
			
				|  |  | -        if (ep == 0)
 | 
	
		
			
				|  |  | +        ASSERT(ep->rx_active);
 | 
	
		
			
				|  |  | +        ep->rx_active = FALSE;
 | 
	
		
			
				|  |  | +        if (epnr == 0)
 | 
	
		
			
				|  |  |              handle_rx_ep0(FALSE);
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      if (oepint & OTG_DOEPMSK_STUPM) {
 | 
	
		
			
				|  |  | -        eps[ep].rx_ready = TRUE;
 | 
	
		
			
				|  |  | -        if (ep == 0)
 | 
	
		
			
				|  |  | +        ASSERT(ep->rx_active);
 | 
	
		
			
				|  |  | +        ep->rx_active = FALSE;
 | 
	
		
			
				|  |  | +        if (epnr == 0)
 | 
	
		
			
				|  |  |              handle_rx_ep0(TRUE);
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    if (!ep->rx_active && (ep->rxc == ep->rxp))
 | 
	
		
			
				|  |  | +        prepare_rx(epnr);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -static void handle_iepint(uint8_t ep)
 | 
	
		
			
				|  |  | +static void handle_iepint(uint8_t epnr)
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  | -    uint32_t iepint = otg_diep[ep].intsts, iepmsk;
 | 
	
		
			
				|  |  | +    uint32_t iepint = otg_diep[epnr].intsts, iepmsk;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    iepmsk = otgd->diepmsk | (((otgd->diepempmsk >> ep) & 1) << 7);
 | 
	
		
			
				|  |  | -    iepint = otg_diep[ep].intsts & iepmsk;
 | 
	
		
			
				|  |  | +    iepmsk = otgd->diepmsk | (((otgd->diepempmsk >> epnr) & 1) << 7);
 | 
	
		
			
				|  |  | +    iepint = otg_diep[epnr].intsts & iepmsk;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    otg_diep[ep].intsts = iepint;
 | 
	
		
			
				|  |  | +    otg_diep[epnr].intsts = iepint;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      if (iepint & OTG_DIEPINT_XFRC) {
 | 
	
		
			
				|  |  | -        otgd->diepempmsk &= ~(1 << ep);
 | 
	
		
			
				|  |  | -        eps[ep].tx_ready = TRUE;
 | 
	
		
			
				|  |  | -        if (ep == 0)
 | 
	
		
			
				|  |  | +        otgd->diepempmsk &= ~(1 << epnr);
 | 
	
		
			
				|  |  | +        eps[epnr].tx_ready = TRUE;
 | 
	
		
			
				|  |  | +        if (epnr == 0)
 | 
	
		
			
				|  |  |              handle_tx_ep0();
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -410,19 +433,19 @@ void usb_process(void)
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      if (gintsts & OTG_GINT_OEPINT) {
 | 
	
		
			
				|  |  |          uint16_t mask = (otgd->daint & otgd->daintmsk) >> 16;
 | 
	
		
			
				|  |  | -        int ep;
 | 
	
		
			
				|  |  | -        for (ep = 0; mask != 0; mask >>= 1, ep++) {
 | 
	
		
			
				|  |  | +        int epnr;
 | 
	
		
			
				|  |  | +        for (epnr = 0; mask != 0; mask >>= 1, epnr++) {
 | 
	
		
			
				|  |  |              if (mask & 1)
 | 
	
		
			
				|  |  | -                handle_oepint(ep);
 | 
	
		
			
				|  |  | +                handle_oepint(epnr);
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      if (gintsts & OTG_GINT_IEPINT) {
 | 
	
		
			
				|  |  |          uint16_t mask = otgd->daint & otgd->daintmsk;
 | 
	
		
			
				|  |  | -        int ep;
 | 
	
		
			
				|  |  | -        for (ep = 0; mask != 0; mask >>= 1, ep++) {
 | 
	
		
			
				|  |  | +        int epnr;
 | 
	
		
			
				|  |  | +        for (epnr = 0; mask != 0; mask >>= 1, epnr++) {
 | 
	
		
			
				|  |  |              if (mask & 1)
 | 
	
		
			
				|  |  | -                handle_iepint(ep);
 | 
	
		
			
				|  |  | +                handle_iepint(epnr);
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 |