/** * @brief Starts a transmit transaction on an IN endpoint. * @note This function is meant to be called from ISR context outside * critical zones because there is a potentially slow operation * inside. * * @param[in] usbp pointer to the @p USBDriver object * @param[in] ep endpoint number * @param[in] buf buffer where to fetch the data to be transmitted * @param[in] n transaction size * * @iclass */ void usbStartTransmitI(USBDriver *usbp, usbep_t ep, const uint8_t *buf, size_t n) { USBInEndpointState *isp; osalDbgCheckClassI(); osalDbgCheck((usbp != NULL) && (ep <= (usbep_t)USB_MAX_ENDPOINTS)); osalDbgAssert(!usbGetTransmitStatusI(usbp, ep), "already transmitting"); /* Marking the endpoint as active.*/ usbp->transmitting |= (uint16_t)((unsigned)1U << (unsigned)ep); /* Setting up the transfer.*/ /*lint -save -e661 [18.1] pclint is confused by the check on ep.*/ isp = usbp->epc[ep]->in_state; /*lint -restore*/ isp->txbuf = buf; isp->txsize = n; isp->txcnt = 0; #if USB_USE_WAIT == TRUE isp->thread = NULL; #endif /* Starting transfer.*/ usb_lld_start_in(usbp, ep); }
/** * @brief Starts a transmit transaction on an IN endpoint. * @post The endpoint callback is invoked when the transfer has been * completed. * * @param[in] usbp pointer to the @p USBDriver object * @param[in] ep endpoint number * * @return The operation status. * @retval false Operation started successfully. * @retval true Endpoint busy, operation not started. * * @iclass */ bool usbStartTransmitI(USBDriver *usbp, usbep_t ep) { osalDbgCheckClassI(); osalDbgCheck(usbp != NULL); if (usbGetTransmitStatusI(usbp, ep)) return true; usbp->transmitting |= (1 << ep); usb_lld_start_in(usbp, ep); return false; }
/** * @brief Starts a transmit transaction on an IN endpoint. * @post The endpoint callback is invoked when the transfer has been * completed. * * @param[in] usbp pointer to the @p USBDriver object * @param[in] ep endpoint number * * @return The operation status. * @retval FALSE Operation started successfully. * @retval TRUE Endpoint busy, operation not started. * * @iclass */ bool_t usbStartTransmitI(USBDriver *usbp, usbep_t ep) { chDbgCheckClassI(); chDbgCheck(usbp != NULL, "usbStartTransmitI"); if (usbGetTransmitStatusI(usbp, ep)) return TRUE; usbp->transmitting |= (1 << ep); usb_lld_start_in(usbp, ep); return FALSE; }
/** * @brief Starts a transmit transaction on an IN endpoint. * @post The endpoint callback is invoked when the transfer has been * completed. * * @param[in] usbp pointer to the @p USBDriver object * @param[in] ep endpoint number * * @return The operation status. * @retval false Operation started successfully. * @retval true Endpoint busy, operation not started. * * @iclass */ bool usbStartTransmitI(USBDriver *usbp, usbep_t ep) { osalDbgCheckClassI(); osalDbgCheck(usbp != NULL); if (usbGetTransmitStatusI(usbp, ep)) { return true; } usbp->transmitting |= (uint16_t)((unsigned)1U << (unsigned)ep); usb_lld_start_in(usbp, ep); return false; }
/** * @brief Generic endpoint IN handler. * * @param[in] usbp pointer to the @p USBDriver object * @param[in] ep endpoint number * * @notapi */ static void otg_epin_handler(USBDriver *usbp, usbep_t ep) { stm32_otg_t *otgp = usbp->otg; uint32_t epint = otgp->ie[ep].DIEPINT; otgp->ie[ep].DIEPINT = epint; if (epint & DIEPINT_TOC) { /* Timeouts not handled yet, not sure how to handle.*/ } if ((epint & DIEPINT_XFRC) && (otgp->DIEPMSK & DIEPMSK_XFRCM)) { /* Transmit transfer complete.*/ USBInEndpointState *isp = usbp->epc[ep]->in_state; if (isp->txsize < isp->totsize) { /* In case the transaction covered only part of the total transfer then another transaction is immediately started in order to cover the remaining.*/ isp->txsize = isp->totsize - isp->txsize; isp->txcnt = 0; usb_lld_prepare_transmit(usbp, ep); chSysLockFromIsr(); usb_lld_start_in(usbp, ep); chSysUnlockFromIsr(); } else { /* End on IN transfer.*/ _usb_isr_invoke_in_cb(usbp, ep); } } if ((epint & DIEPINT_TXFE) && (otgp->DIEPEMPMSK & DIEPEMPMSK_INEPTXFEM(ep))) { /* The thread is made ready, it will be scheduled on ISR exit.*/ chSysLockFromIsr(); usbp->txpending |= (1 << ep); otgp->DIEPEMPMSK &= ~(1 << ep); usb_lld_wakeup_pump(usbp); chSysUnlockFromIsr(); } }
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); } } } }