summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorKeith Packard <keithp@keithp.com>2013-03-24 15:04:57 -0700
committerKeith Packard <keithp@keithp.com>2013-03-31 12:24:38 -0700
commit8b2f211758dfa97230a730b8c4b31e0e711c19c9 (patch)
treeaa3f38b7be42f6bfe250f8e83292cf0175489eac /src
parentde199601a177fc2d45ad9bd7357111111844d40a (diff)
altos/stm: Always check for idle IN buffer before sending
Unlike the AVR and CC1111 USB drivers, the STM usb driver queues IN bytes in a local buffer instead of in the driver; this means that the driver is queuing bytes while the previous IN packet is queued for the host, which allows for overlapping execution. It also means that when the local buffer is full, we must check to see if the host has picked up the previous IN packet before trying to queue another IN packet for transmission. This is done by always waiting for the IN buffer to be ready before sending data. Signed-off-by: Keith Packard <keithp@keithp.com>
Diffstat (limited to 'src')
-rw-r--r--src/stm/ao_usb_stm.c19
1 files changed, 11 insertions, 8 deletions
diff --git a/src/stm/ao_usb_stm.c b/src/stm/ao_usb_stm.c
index 44f49dfa..e29abc87 100644
--- a/src/stm/ao_usb_stm.c
+++ b/src/stm/ao_usb_stm.c
@@ -823,15 +823,20 @@ ao_usb_ep0(void)
/* Queue the current IN buffer for transmission */
static void
-ao_usb_in_send(void)
+_ao_usb_in_send(void)
{
_tx_dbg0("in_send start");
debug ("send %d\n", ao_usb_tx_count);
+ while (ao_usb_in_pending)
+ ao_sleep(&ao_usb_in_pending);
ao_usb_in_pending = 1;
+ if (ao_usb_tx_count != AO_USB_IN_SIZE)
+ ao_usb_in_flushed = 1;
ao_usb_write(ao_usb_tx_buffer, ao_usb_in_tx_buffer, 0, ao_usb_tx_count);
ao_usb_bdt[AO_USB_IN_EPR].single.count_tx = ao_usb_tx_count;
- ao_usb_set_stat_tx(AO_USB_IN_EPR, STM_USB_EPR_STAT_TX_VALID);
ao_usb_tx_count = 0;
+ _ao_usb_set_stat_tx(AO_USB_IN_EPR, STM_USB_EPR_STAT_TX_VALID);
+ _tx_dbg0("in_send end");
}
/* Wait for a free IN buffer. Interrupts are blocked */
@@ -865,12 +870,10 @@ ao_usb_flush(void)
* want to send an empty packet
*/
ao_arch_block_interrupts();
- if (!ao_usb_in_flushed) {
- ao_usb_in_flushed = 1;
- /* Wait for an IN buffer to be ready */
- while (ao_usb_in_pending)
- ao_sleep(&ao_usb_in_pending);
- ao_usb_in_send();
+ while (!ao_usb_in_flushed) {
+ _tx_dbg0("flush top");
+ _ao_usb_in_send();
+ _tx_dbg0("flush end");
}
ao_arch_release_interrupts();
}