stm32: Simplify usbotg packet reading and writing

Signed-off-by: Kevin O'Connor <kevin@koconnor.net>
This commit is contained in:
Kevin O'Connor 2019-08-16 08:40:03 -04:00
parent 4ec6db7a87
commit 8aca7764c3
1 changed files with 54 additions and 57 deletions

View File

@ -57,40 +57,35 @@ fifo_configure(void)
fpos += ep_size; fpos += ep_size;
} }
// Inspect the next packet on the rx queue // Write a packet to a tx fifo
static uint32_t static int_fast8_t
peek_rx_queue(uint32_t ep) fifo_write_packet(uint32_t ep, const uint8_t *src, uint32_t len)
{ {
for (;;) { void *fifo = EPFIFO(ep);
USB_OTG_OUTEndpointTypeDef *epo = EPOUT(ep); USB_OTG_INEndpointTypeDef *epi = EPIN(ep);
uint32_t ctl = epo->DOEPCTL; epi->DIEPTSIZ = len | (1 << USB_OTG_DIEPTSIZ_PKTCNT_Pos);
if (!(ctl & USB_OTG_DOEPCTL_EPENA) || ctl & USB_OTG_DOEPCTL_NAKSTS) { epi->DIEPCTL |= USB_OTG_DIEPCTL_EPENA | USB_OTG_DIEPCTL_CNAK;
// Reenable packet reception if it got disabled by controller int32_t count = len;
epo->DOEPTSIZ = 64 | (1 << USB_OTG_DOEPTSIZ_PKTCNT_Pos); while (count >= 4) {
epo->DOEPCTL = ctl | USB_OTG_DOEPCTL_EPENA | USB_OTG_DOEPCTL_CNAK; uint32_t data;
memcpy(&data, src, 4);
writel(fifo, data);
count -= 4;
src += 4;
} }
uint32_t sts = OTG->GINTSTS; if (count) {
if (!(sts & USB_OTG_GINTSTS_RXFLVL)) uint32_t data = 0;
// No packet ready memcpy(&data, src, count);
return 0; writel(fifo, data);
uint32_t grx = OTG->GRXSTSR;
uint32_t pktsts = ((grx & USB_OTG_GRXSTSP_PKTSTS_Msk)
>> USB_OTG_GRXSTSP_PKTSTS_Pos);
if (pktsts != 1 && pktsts != 3 && pktsts != 4) {
// A packet is ready
if ((grx & USB_OTG_GRXSTSP_EPNUM_Msk) != ep)
return 0;
return grx;
}
// Discard informational entries from queue
grx = OTG->GRXSTSP;
} }
return len;
} }
// Read a packet from the rx queue // Read a packet from the rx queue
static int_fast8_t static int_fast8_t
fifo_read_packet(uint8_t *dest, uint_fast8_t max_len) fifo_read_packet(uint8_t *dest, uint_fast8_t max_len)
{ {
// Transfer data
void *fifo = EPFIFO(0); void *fifo = EPFIFO(0);
uint32_t grx = OTG->GRXSTSP; uint32_t grx = OTG->GRXSTSP;
uint32_t bcnt = (grx & USB_OTG_GRXSTSP_BCNT) >> USB_OTG_GRXSTSP_BCNT_Pos; uint32_t bcnt = (grx & USB_OTG_GRXSTSP_BCNT) >> USB_OTG_GRXSTSP_BCNT_Pos;
@ -108,24 +103,37 @@ fifo_read_packet(uint8_t *dest, uint_fast8_t max_len)
uint32_t extra = DIV_ROUND_UP(bcnt, 4) - DIV_ROUND_UP(xfer, 4); uint32_t extra = DIV_ROUND_UP(bcnt, 4) - DIV_ROUND_UP(xfer, 4);
while (extra--) while (extra--)
readl(fifo); readl(fifo);
// Reenable packet reception if it got disabled by controller
USB_OTG_OUTEndpointTypeDef *epo = EPOUT(grx & USB_OTG_GRXSTSP_EPNUM_Msk);
uint32_t ctl = epo->DOEPCTL;
if (!(ctl & USB_OTG_DOEPCTL_EPENA) || ctl & USB_OTG_DOEPCTL_NAKSTS) {
epo->DOEPTSIZ = 64 | (1 << USB_OTG_DOEPTSIZ_PKTCNT_Pos);
epo->DOEPCTL = ctl | USB_OTG_DOEPCTL_EPENA | USB_OTG_DOEPCTL_CNAK;
}
return xfer; return xfer;
} }
// Write a packet to a tx fifo // Inspect the next packet on the rx queue
static void static uint32_t
fifo_write_packet(void *fifo, const uint8_t *src, uint32_t count) peek_rx_queue(uint32_t ep)
{ {
while (count >= 4) { for (;;) {
uint32_t data; uint32_t sts = OTG->GINTSTS;
memcpy(&data, src, 4); if (!(sts & USB_OTG_GINTSTS_RXFLVL))
writel(fifo, data); // No packet ready
count -= 4; return 0;
src += 4; uint32_t grx = OTG->GRXSTSR;
uint32_t pktsts = ((grx & USB_OTG_GRXSTSP_PKTSTS_Msk)
>> USB_OTG_GRXSTSP_PKTSTS_Pos);
if (pktsts != 1 && pktsts != 3 && pktsts != 4) {
// A packet is ready
if ((grx & USB_OTG_GRXSTSP_EPNUM_Msk) != ep)
return 0;
return grx;
} }
if (count) { // Discard informational entries from queue
uint32_t data = 0; fifo_read_packet(NULL, 0);
memcpy(&data, src, count);
writel(fifo, data);
} }
} }
@ -149,20 +157,16 @@ usb_read_bulk_out(void *data, uint_fast8_t max_len)
int_fast8_t int_fast8_t
usb_send_bulk_in(void *data, uint_fast8_t len) usb_send_bulk_in(void *data, uint_fast8_t len)
{ {
USB_OTG_INEndpointTypeDef *epi = EPIN(USB_CDC_EP_BULK_IN); uint32_t ctl = EPIN(USB_CDC_EP_BULK_IN)->DIEPCTL;
uint32_t len_d4 = DIV_ROUND_UP(len, 4);
uint32_t ctl = epi->DIEPCTL;
if (!(ctl & USB_OTG_DIEPCTL_USBAEP)) if (!(ctl & USB_OTG_DIEPCTL_USBAEP))
// Controller not enabled
return -2; return -2;
if (ctl & USB_OTG_DIEPCTL_EPENA || len_d4 > epi->DTXFSTS) { if (ctl & USB_OTG_DIEPCTL_EPENA) {
// Wait for space to transmit // Wait for space to transmit
OTGD->DIEPEMPMSK |= (1 << USB_CDC_EP_BULK_IN); OTGD->DIEPEMPMSK |= (1 << USB_CDC_EP_BULK_IN);
return -1; return -1;
} }
epi->DIEPTSIZ = len | (1 << USB_OTG_DIEPTSIZ_PKTCNT_Pos); return fifo_write_packet(USB_CDC_EP_BULK_IN, data, len);
epi->DIEPCTL |= USB_OTG_DIEPCTL_EPENA | USB_OTG_DIEPCTL_CNAK;
fifo_write_packet(EPFIFO(USB_CDC_EP_BULK_IN), data, len);
return len;
} }
int_fast8_t int_fast8_t
@ -221,20 +225,13 @@ usb_send_ep0(const void *data, uint_fast8_t len)
// Transfer interrupted // Transfer interrupted
return -2; return -2;
} }
USB_OTG_INEndpointTypeDef *epi = EPIN(0); if (EPIN(0)->DIEPCTL & USB_OTG_DIEPCTL_EPENA) {
uint32_t len_d4 = DIV_ROUND_UP(len, 4);
uint32_t ctl = epi->DIEPCTL;
if (ctl & USB_OTG_DIEPCTL_EPENA || len_d4 > epi->DTXFSTS) {
// Wait for space to transmit // Wait for space to transmit
OTGD->DIEPEMPMSK |= (1 << 0); OTGD->DIEPEMPMSK |= (1 << 0);
OTG->GINTMSK |= USB_OTG_GINTMSK_RXFLVLM; OTG->GINTMSK |= USB_OTG_GINTMSK_RXFLVLM;
return -1; return -1;
} }
epi->DIEPTSIZ = len | (1 << USB_OTG_DIEPTSIZ_PKTCNT_Pos); return fifo_write_packet(0, data, len);
epi->DIEPCTL = ((ctl & ~USB_OTG_DIEPCTL_STALL) | USB_OTG_DIEPCTL_EPENA
| USB_OTG_DIEPCTL_CNAK);
fifo_write_packet(EPFIFO(0), data, len);
return len;
} }
void void