From be48aa8f69331b6ec5b8594cf72a9563a75ab646 Mon Sep 17 00:00:00 2001 From: Giovanni Di Sirio Date: Fri, 27 Nov 2015 09:01:57 +0000 Subject: git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@8533 35acf78f-673a-0410-8e92-d51de3d6d3f4 --- os/hal/ports/STM32/LLD/USBv1/usb_lld.c | 236 ++++++++++++++++++--------------- 1 file changed, 128 insertions(+), 108 deletions(-) (limited to 'os/hal/ports/STM32/LLD/USBv1') diff --git a/os/hal/ports/STM32/LLD/USBv1/usb_lld.c b/os/hal/ports/STM32/LLD/USBv1/usb_lld.c index 69054f6fc..45450b0bb 100644 --- a/os/hal/ports/STM32/LLD/USBv1/usb_lld.c +++ b/os/hal/ports/STM32/LLD/USBv1/usb_lld.c @@ -282,6 +282,124 @@ static void usb_packet_write_from_queue(stm32_usb_descriptor_t *udp, osalSysRestoreStatusX(sts); } +/** + * @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) { + size_t transmitted; + /* IN endpoint, transmission.*/ + EPR_CLEAR_CTR_TX(ep); + + /* Double buffering is always enabled for isochronous endpoints, and + although we overlap the two buffers for simplicity, we still need + to read from the right counter. The DTOG_TX bit indicates the buffer + that is currently in use by the USB peripheral, that is, the buffer + from which the next packet will be sent, so we need to read the + transmitted bytes from the counter of the OTHER buffer, which is + where we stored the last transmitted packet.*/ + transmitted = (size_t)USB_GET_DESCRIPTOR(ep)->TXCOUNT0; + if (EPR_EP_TYPE_IS_ISO(epr) && !(epr & EPR_DTOG_TX)) + transmitted = (size_t)USB_GET_DESCRIPTOR(ep)->TXCOUNT1; + + epcp->in_state->txcnt += transmitted; + n = epcp->in_state->txsize - epcp->in_state->txcnt; + if (n > 0) { + /* Transfer not completed, there are more packets to send.*/ + if (n > epcp->in_maxsize) + n = epcp->in_maxsize; + + /* Double buffering is always enabled for isochronous endpoints, and + although we overlap the two buffers for simplicity, we still need + to write to the right counter. The DTOG_TX bit indicates the buffer + that is currently in use by the USB peripheral, that is, the buffer + from which the next packet will be sent, so we need to write the + counter of that buffer.*/ + USB_GET_DESCRIPTOR(ep)->TXCOUNT0 = (stm32_usb_pma_t)n; + if (EPR_EP_TYPE_IS_ISO(epr) && (epr & EPR_DTOG_TX)) + USB_GET_DESCRIPTOR(ep)->TXCOUNT1 = (stm32_usb_pma_t)n; + + if (epcp->in_state->txqueued) + usb_packet_write_from_queue(USB_GET_DESCRIPTOR(ep), + epcp->in_state->mode.queue.txqueue, + n); + else { + epcp->in_state->mode.linear.txbuf += transmitted; + usb_packet_write_from_buffer(USB_GET_DESCRIPTOR(ep), + epcp->in_state->mode.linear.txbuf, + n); + } + osalSysLockFromISR(); + usb_lld_start_in(usbp, ep); + osalSysUnlockFromISR(); + } + else { + /* Transfer completed, invokes the callback.*/ + _usb_isr_invoke_in_cb(usbp, ep); + } + } + if (epr & EPR_CTR_RX) { + EPR_CLEAR_CTR_RX(ep); + /* OUT endpoint, receive.*/ + if (epr & EPR_SETUP) { + /* Setup packets handling, setup packets are handled using a + specific callback.*/ + _usb_isr_invoke_setup_cb(usbp, ep); + } + else { + stm32_usb_descriptor_t *udp = USB_GET_DESCRIPTOR(ep); + + /* Double buffering is always enabled for isochronous endpoints, and + although we overlap the two buffers for simplicity, we still need + to read from the right counter. The DTOG_RX bit indicates the buffer + that is currently in use by the USB peripheral, that is, the buffer + in which the next received packet will be stored, so we need to + read the counter of the OTHER buffer, which is where the last + received packet was stored.*/ + n = (size_t)udp->RXCOUNT0 & RXCOUNT_COUNT_MASK; + if (EPR_EP_TYPE_IS_ISO(epr) && !(epr & EPR_DTOG_RX)) + n = (size_t)udp->RXCOUNT1 & RXCOUNT_COUNT_MASK; + + /* Reads the packet into the defined buffer.*/ + if (epcp->out_state->rxqueued) + usb_packet_read_to_queue(udp, + epcp->out_state->mode.queue.rxqueue, + n); + else { + usb_packet_read_to_buffer(udp, + epcp->out_state->mode.linear.rxbuf, + n); + epcp->out_state->mode.linear.rxbuf += n; + } + + /* Transaction data updated.*/ + epcp->out_state->rxcnt += n; + epcp->out_state->rxsize -= n; + epcp->out_state->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) || (epcp->out_state->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); + } + } + } +} + /*===========================================================================*/ /* Driver interrupt handlers. */ /*===========================================================================*/ @@ -294,9 +412,18 @@ static void usb_packet_write_from_queue(stm32_usb_descriptor_t *udp, * @isr */ OSAL_IRQ_HANDLER(STM32_USB1_HP_HANDLER) { + uint32_t istr; + USBDriver *usbp = &USBD1; OSAL_IRQ_PROLOGUE(); + /* Endpoint events handling.*/ + istr = STM32_USB->ISTR; + while (istr & ISTR_CTR) { + usb_serve_endpoints(usbp, istr & ISTR_EP_ID_MASK); + istr = STM32_USB->ISTR; + } + OSAL_IRQ_EPILOGUE(); } #endif /* STM32_USB1_LP_NUMBER != STM32_USB1_HP_NUMBER */ @@ -358,114 +485,7 @@ OSAL_IRQ_HANDLER(STM32_USB1_LP_HANDLER) { /* Endpoint events handling.*/ while (istr & ISTR_CTR) { - size_t n; - uint32_t ep; - uint32_t epr = STM32_USB->EPR[ep = istr & ISTR_EP_ID_MASK]; - const USBEndpointConfig *epcp = usbp->epc[ep]; - - if (epr & EPR_CTR_TX) { - size_t transmitted; - /* IN endpoint, transmission.*/ - EPR_CLEAR_CTR_TX(ep); - - /* Double buffering is always enabled for isochronous endpoints, and - although we overlap the two buffers for simplicity, we still need - to read from the right counter. The DTOG_TX bit indicates the buffer - that is currently in use by the USB peripheral, that is, the buffer - from which the next packet will be sent, so we need to read the - transmitted bytes from the counter of the OTHER buffer, which is - where we stored the last transmitted packet.*/ - transmitted = (size_t)USB_GET_DESCRIPTOR(ep)->TXCOUNT0; - if (EPR_EP_TYPE_IS_ISO(epr) && !(epr & EPR_DTOG_TX)) - transmitted = (size_t)USB_GET_DESCRIPTOR(ep)->TXCOUNT1; - - epcp->in_state->txcnt += transmitted; - n = epcp->in_state->txsize - epcp->in_state->txcnt; - if (n > 0) { - /* Transfer not completed, there are more packets to send.*/ - if (n > epcp->in_maxsize) - n = epcp->in_maxsize; - - /* Double buffering is always enabled for isochronous endpoints, and - although we overlap the two buffers for simplicity, we still need - to write to the right counter. The DTOG_TX bit indicates the buffer - that is currently in use by the USB peripheral, that is, the buffer - from which the next packet will be sent, so we need to write the - counter of that buffer.*/ - USB_GET_DESCRIPTOR(ep)->TXCOUNT0 = (stm32_usb_pma_t)n; - if (EPR_EP_TYPE_IS_ISO(epr) && (epr & EPR_DTOG_TX)) - USB_GET_DESCRIPTOR(ep)->TXCOUNT1 = (stm32_usb_pma_t)n; - - if (epcp->in_state->txqueued) - usb_packet_write_from_queue(USB_GET_DESCRIPTOR(ep), - epcp->in_state->mode.queue.txqueue, - n); - else { - epcp->in_state->mode.linear.txbuf += transmitted; - usb_packet_write_from_buffer(USB_GET_DESCRIPTOR(ep), - epcp->in_state->mode.linear.txbuf, - n); - } - osalSysLockFromISR(); - usb_lld_start_in(usbp, ep); - osalSysUnlockFromISR(); - } - else { - /* Transfer completed, invokes the callback.*/ - _usb_isr_invoke_in_cb(usbp, ep); - } - } - if (epr & EPR_CTR_RX) { - EPR_CLEAR_CTR_RX(ep); - /* OUT endpoint, receive.*/ - if (epr & EPR_SETUP) { - /* Setup packets handling, setup packets are handled using a - specific callback.*/ - _usb_isr_invoke_setup_cb(usbp, ep); - } - else { - stm32_usb_descriptor_t *udp = USB_GET_DESCRIPTOR(ep); - - /* Double buffering is always enabled for isochronous endpoints, and - although we overlap the two buffers for simplicity, we still need - to read from the right counter. The DTOG_RX bit indicates the buffer - that is currently in use by the USB peripheral, that is, the buffer - in which the next received packet will be stored, so we need to - read the counter of the OTHER buffer, which is where the last - received packet was stored.*/ - n = (size_t)udp->RXCOUNT0 & RXCOUNT_COUNT_MASK; - if (EPR_EP_TYPE_IS_ISO(epr) && !(epr & EPR_DTOG_RX)) - n = (size_t)udp->RXCOUNT1 & RXCOUNT_COUNT_MASK; - - /* Reads the packet into the defined buffer.*/ - if (epcp->out_state->rxqueued) - usb_packet_read_to_queue(udp, - epcp->out_state->mode.queue.rxqueue, - n); - else { - usb_packet_read_to_buffer(udp, - epcp->out_state->mode.linear.rxbuf, - n); - epcp->out_state->mode.linear.rxbuf += n; - } - - /* Transaction data updated.*/ - epcp->out_state->rxcnt += n; - epcp->out_state->rxsize -= n; - epcp->out_state->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) || (epcp->out_state->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); - } - } - } + usb_serve_endpoints(usbp, istr & ISTR_EP_ID_MASK); istr = STM32_USB->ISTR; } -- cgit v1.2.3