git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@8533 35acf78f-673a-0410-8e92-d51de3d6d3f4
This commit is contained in:
parent
ec59801695
commit
be48aa8f69
|
@ -282,6 +282,124 @@ static void usb_packet_write_from_queue(stm32_usb_descriptor_t *udp,
|
||||||
osalSysRestoreStatusX(sts);
|
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. */
|
/* Driver interrupt handlers. */
|
||||||
/*===========================================================================*/
|
/*===========================================================================*/
|
||||||
|
@ -294,9 +412,18 @@ static void usb_packet_write_from_queue(stm32_usb_descriptor_t *udp,
|
||||||
* @isr
|
* @isr
|
||||||
*/
|
*/
|
||||||
OSAL_IRQ_HANDLER(STM32_USB1_HP_HANDLER) {
|
OSAL_IRQ_HANDLER(STM32_USB1_HP_HANDLER) {
|
||||||
|
uint32_t istr;
|
||||||
|
USBDriver *usbp = &USBD1;
|
||||||
|
|
||||||
OSAL_IRQ_PROLOGUE();
|
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();
|
OSAL_IRQ_EPILOGUE();
|
||||||
}
|
}
|
||||||
#endif /* STM32_USB1_LP_NUMBER != STM32_USB1_HP_NUMBER */
|
#endif /* STM32_USB1_LP_NUMBER != STM32_USB1_HP_NUMBER */
|
||||||
|
@ -358,114 +485,7 @@ OSAL_IRQ_HANDLER(STM32_USB1_LP_HANDLER) {
|
||||||
|
|
||||||
/* Endpoint events handling.*/
|
/* Endpoint events handling.*/
|
||||||
while (istr & ISTR_CTR) {
|
while (istr & ISTR_CTR) {
|
||||||
size_t n;
|
usb_serve_endpoints(usbp, istr & ISTR_EP_ID_MASK);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
istr = STM32_USB->ISTR;
|
istr = STM32_USB->ISTR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue