stm32f4: Refactor IN and OUT endpoint interrupt handling into their own functions.

This commit is contained in:
William D. Jones 2019-02-27 11:01:08 -05:00
parent f43161353c
commit c95ad426c6
1 changed files with 60 additions and 54 deletions

View File

@ -553,6 +553,64 @@ static void read_rx_fifo(USB_OTG_OUTEndpointTypeDef * out_ep) {
}
}
static void handle_epout_ints(USB_OTG_DeviceTypeDef * dev, USB_OTG_OUTEndpointTypeDef * out_ep) {
// DAINT for a given EP clears when DOEPINTx is cleared.
// OEPINT will be cleared when DAINT's out bits are cleared.
for(int n = 0; n < 4; n++) {
xfer_ctl_t * xfer = XFER_CTL_BASE(n, TUSB_DIR_OUT);
if(dev->DAINT & (1 << (USB_OTG_DAINT_OEPINT_Pos + n))) {
// SETUP packet Setup Phase done.
if(out_ep[n].DOEPINT & USB_OTG_DOEPINT_STUP) {
out_ep[n].DOEPINT = USB_OTG_DOEPINT_STUP;
dcd_event_setup_received(0, (uint8_t*) &_setup_packet[0], true);
_setup_offs = 0;
}
// OUT XFER complete (single packet).
if(out_ep[n].DOEPINT & USB_OTG_DOEPINT_XFRC) {
out_ep[n].DOEPINT = USB_OTG_DOEPINT_XFRC;
// TODO: Because of endpoint 0's constrained size, we handle XFRC
// on a packet-basis. The core can internally handle multiple OUT
// packets; it would be more efficient to only trigger XFRC on a
// completed transfer for non-0 endpoints.
if(xfer->short_packet) {
xfer->short_packet = false;
dcd_event_xfer_complete(0, n, xfer->queued_len, XFER_RESULT_SUCCESS, true);
} else {
// Schedule another packet to be received.
out_ep[n].DOEPTSIZ = (1 << USB_OTG_DOEPTSIZ_PKTCNT_Pos) | \
((xfer->max_size & USB_OTG_DOEPTSIZ_XFRSIZ_Msk) << USB_OTG_DOEPTSIZ_XFRSIZ_Pos);
out_ep[n].DOEPCTL |= USB_OTG_DOEPCTL_EPENA | USB_OTG_DOEPCTL_CNAK;
}
}
}
}
}
static void handle_epin_ints(USB_OTG_DeviceTypeDef * dev, USB_OTG_INEndpointTypeDef * in_ep) {
// DAINT for a given EP clears when DIEPINTx is cleared.
// IEPINT will be cleared when DAINT's out bits are cleared.
for(uint8_t n = 0; n < 4; n++) {
xfer_ctl_t * xfer = XFER_CTL_BASE(n, TUSB_DIR_IN);
if(dev->DAINT & (1 << (USB_OTG_DAINT_IEPINT_Pos + n))) {
// IN XFER complete (entire xfer).
if(in_ep[n].DIEPINT & USB_OTG_DIEPINT_XFRC) {
in_ep[n].DIEPINT = USB_OTG_DIEPINT_XFRC;
dev->DIEPEMPMSK &= ~(1 << n); // Turn off TXFE b/c xfer inactive.
dcd_event_xfer_complete(0, n | TUSB_DIR_IN_MASK, xfer->total_len, XFER_RESULT_SUCCESS, true);
}
// XFER FIFO empty
if(in_ep[n].DIEPINT & USB_OTG_DIEPINT_TXFE) {
in_ep[n].DIEPINT = USB_OTG_DIEPINT_TXFE;
transmit_packet(xfer, &in_ep[n], n);
}
}
}
}
void OTG_FS_IRQHandler(void) {
USB_OTG_DeviceTypeDef * dev = DEVICE_BASE;
USB_OTG_OUTEndpointTypeDef * out_ep = OUT_EP_BASE;
@ -586,64 +644,12 @@ void OTG_FS_IRQHandler(void) {
// OUT endpoint interrupt handling.
if(int_status & USB_OTG_GINTSTS_OEPINT) {
// DAINT for a given EP clears when DOEPINTx is cleared.
// OEPINT will be cleared when DAINT's out bits are cleared.
for(int n = 0; n < 4; n++) {
xfer_ctl_t * xfer = XFER_CTL_BASE(n, TUSB_DIR_OUT);
if(dev->DAINT & (1 << (USB_OTG_DAINT_OEPINT_Pos + n))) {
// SETUP packet Setup Phase done.
if(out_ep[n].DOEPINT & USB_OTG_DOEPINT_STUP) {
out_ep[n].DOEPINT = USB_OTG_DOEPINT_STUP;
dcd_event_setup_received(0, (uint8_t*) &_setup_packet[0], true);
_setup_offs = 0;
}
// OUT XFER complete (single packet).
if(out_ep[n].DOEPINT & USB_OTG_DOEPINT_XFRC) {
out_ep[n].DOEPINT = USB_OTG_DOEPINT_XFRC;
// TODO: Because of endpoint 0's constrained size, we handle XFRC
// on a packet-basis. The core can internally handle multiple OUT
// packets; it would be more efficient to only trigger XFRC on a
// completed transfer for non-0 endpoints.
if(xfer->short_packet) {
xfer->short_packet = false;
dcd_event_xfer_complete(0, n, xfer->queued_len, XFER_RESULT_SUCCESS, true);
} else {
// Schedule another packet to be received.
out_ep[n].DOEPTSIZ = (1 << USB_OTG_DOEPTSIZ_PKTCNT_Pos) | \
((xfer->max_size & USB_OTG_DOEPTSIZ_XFRSIZ_Msk) << USB_OTG_DOEPTSIZ_XFRSIZ_Pos);
out_ep[n].DOEPCTL |= USB_OTG_DOEPCTL_EPENA | USB_OTG_DOEPCTL_CNAK;
}
}
}
}
handle_epout_ints(dev, out_ep);
}
// IN endpoint interrupt handling.
if(int_status & USB_OTG_GINTSTS_IEPINT) {
// DAINT for a given EP clears when DIEPINTx is cleared.
// IEPINT will be cleared when DAINT's out bits are cleared.
for(uint8_t n = 0; n < 4; n++) {
xfer_ctl_t * xfer = XFER_CTL_BASE(n, TUSB_DIR_IN);
if(dev->DAINT & (1 << (USB_OTG_DAINT_IEPINT_Pos + n))) {
// IN XFER complete (entire xfer).
if(in_ep[n].DIEPINT & USB_OTG_DIEPINT_XFRC) {
in_ep[n].DIEPINT = USB_OTG_DIEPINT_XFRC;
dev->DIEPEMPMSK &= ~(1 << n); // Turn off TXFE b/c xfer inactive.
dcd_event_xfer_complete(0, n | TUSB_DIR_IN_MASK, xfer->total_len, XFER_RESULT_SUCCESS, true);
}
// XFER FIFO empty
if(in_ep[n].DIEPINT & USB_OTG_DIEPINT_TXFE) {
in_ep[n].DIEPINT = USB_OTG_DIEPINT_TXFE;
transmit_packet(xfer, &in_ep[n], n);
}
}
}
handle_epin_ints(dev, in_ep);
}
}