/** * @brief Generic endpoint OUT handler. * * @param[in] usbp pointer to the @p USBDriver object * @param[in] ep endpoint number * * @notapi */ static void otg_epout_handler(USBDriver *usbp, usbep_t ep) { stm32_otg_t *otgp = usbp->otg; uint32_t epint = otgp->oe[ep].DOEPINT; /* Resets all EP IRQ sources.*/ otgp->oe[ep].DOEPINT = epint; if ((epint & DOEPINT_STUP) && (otgp->DOEPMSK & DOEPMSK_STUPM)) { /* Setup packets handling, setup packets are handled using a specific callback.*/ _usb_isr_invoke_setup_cb(usbp, ep); } if ((epint & DOEPINT_XFRC) && (otgp->DOEPMSK & DOEPMSK_XFRCM)) { /* Receive transfer complete.*/ USBOutEndpointState *osp = usbp->epc[ep]->out_state; if (osp->rxsize < osp->totsize) { /* In case the transaction covered only part of the total transfer then another transaction is immediately started in order to cover the remaining.*/ osp->rxsize = osp->totsize - osp->rxsize; osp->rxcnt = 0; usb_lld_prepare_receive(usbp, ep); chSysLockFromIsr(); usb_lld_start_out(usbp, ep); chSysUnlockFromIsr(); } else { /* End on OUT transfer.*/ _usb_isr_invoke_out_cb(usbp, ep); } } }
/** * @brief Generic endpoint OUT handler. * * @param[in] usbp pointer to the @p USBDriver object * @param[in] ep endpoint number * * @notapi */ static void otg_epout_handler(USBDriver *usbp, usbep_t ep) { stm32_otg_t *otgp = usbp->otg; uint32_t epint = otgp->oe[ep].DOEPINT; /* Resets all EP IRQ sources.*/ otgp->oe[ep].DOEPINT = 0xFFFFFFFF; if ((epint & DOEPINT_STUP) && (otgp->DOEPMSK & DOEPMSK_STUPM)) { /* Setup packets handling, setup packets are handled using a specific callback.*/ _usb_isr_invoke_setup_cb(usbp, ep); } if ((epint & DOEPINT_XFRC) && (otgp->DOEPMSK & DOEPMSK_XFRCM)) { /* Receive transfer complete.*/ _usb_isr_invoke_out_cb(usbp, ep); } }
static void ep_isr(USBDriver *usbp, usbep_t ep) { const USBEndpointConfig *epcp = usbp->epc[ep]; size_t n; UENUM = ep & 0xf; /* TODO: if stalling is needed/expected remove this check */ osalDbgAssert(!(UEINTX & (1 << STALLEDI)), "Endpoint stalled!"); if ((UEIENX & (1 << TXINE)) && (UEINTX & (1 << TXINI))) { /* Ready to accept more IN data to transmit to host */ /* Disable TXIN interrupt for now, will be re-enabled below if we * send more data */ UEIENX &= ~(1 << TXINE); /* Update transaction counts to reflect newly transmitted bytes */ epcp->in_state->txcnt += epcp->in_state->last_tx_size; n = epcp->in_state->txsize - epcp->in_state->txcnt; if (n > 0) { /* Transfer not completed, there are more packets to send. */ usb_fifo_write(usbp, ep, n); osalSysLockFromISR(); usb_lld_start_in(usbp, ep); osalSysUnlockFromISR(); } else { UEINTX &= ~(1 << TXINI); _usb_isr_invoke_in_cb(usbp, ep); } } if ((UEIENX & (1 << RXSTPE)) && (UEINTX & (1 << RXSTPI))) { /* Received SETUP data */ /* Reset transaction state for endpoint */ epcp->in_state->txcnt = 0; epcp->in_state->txsize = 0; epcp->in_state->last_tx_size = 0; /* Setup packets handling, setup packets are handled using a specific callback.*/ _usb_isr_invoke_setup_cb(usbp, ep); } else if (UEINTX & (1 << RXOUTI)) { /* Received OUT data from host */ if (ep == 0 && usbp->ep0state == USB_EP0_WAITING_STS) { /* SETUP/control transaction complete, invoke the callback. */ n = 0; UEINTX &= ~((1 << RXOUTI) | (1 << FIFOCON)); _usb_isr_invoke_out_cb(usbp, ep); } else { /* Check the FIFO byte count to see how many bytes were received */ n = UEBCX; } if (n > 0) { usb_fifo_read(usbp, ep, n); /* Mark OUT FIFO processed to allow more data to be received */ UEINTX &= ~((1 << RXOUTI) | (1 << FIFOCON)); /* Transaction state update */ epcp->out_state->rxcnt += n; epcp->out_state->rxsize -= n; epcp->out_state->rxpkts -= 1; if (n < epcp->out_maxsize || epcp->out_state->rxpkts == 0) { /* Transfer complete, invokes the callback.*/ _usb_isr_invoke_out_cb(usbp, ep); } } } }
/** * @brief Common ISR code, serves the EP-related interrupts. * * @param[in] usbp pointer to the @p USBDriver object * @param[in] ep endpoint number * * @notapi */ static void usb_serve_endpoints(USBDriver *usbp, uint32_t ep) { size_t n; uint32_t epr = STM32_USB->EPR[ep]; const USBEndpointConfig *epcp = usbp->epc[ep]; if (epr & EPR_CTR_TX) { /* IN endpoint, transmission.*/ USBInEndpointState *isp = epcp->in_state; EPR_CLEAR_CTR_TX(ep); isp->txcnt += isp->txlast; n = isp->txsize - isp->txcnt; if (n > 0) { /* Transfer not completed, there are more packets to send.*/ if (n > epcp->in_maxsize) n = epcp->in_maxsize; /* Writes the packet from the defined buffer.*/ isp->txbuf += isp->txlast; isp->txlast = n; usb_packet_write_from_buffer(ep, isp->txbuf, n); /* Starting IN operation.*/ EPR_SET_STAT_TX(ep, EPR_STAT_TX_VALID); } else { /* Transfer completed, invokes the callback.*/ _usb_isr_invoke_in_cb(usbp, ep); } } if (epr & EPR_CTR_RX) { /* OUT endpoint, receive.*/ EPR_CLEAR_CTR_RX(ep); if (epr & EPR_SETUP) { /* Setup packets handling, setup packets are handled using a specific callback.*/ _usb_isr_invoke_setup_cb(usbp, ep); } else { USBOutEndpointState *osp = epcp->out_state; /* Reads the packet into the defined buffer.*/ n = usb_packet_read_to_buffer(ep, osp->rxbuf); osp->rxbuf += n; /* Transaction data updated.*/ osp->rxcnt += n; osp->rxsize -= n; osp->rxpkts -= 1; /* The transaction is completed if the specified number of packets has been received or the current packet is a short packet.*/ if ((n < epcp->out_maxsize) || (osp->rxpkts == 0)) { /* Transfer complete, invokes the callback.*/ _usb_isr_invoke_out_cb(usbp, ep); } else { /* Transfer not complete, there are more packets to receive.*/ EPR_SET_STAT_RX(ep, EPR_STAT_RX_VALID); } } } }