diff options
-rw-r--r-- | chip/g/usb-stream.c | 47 | ||||
-rw-r--r-- | chip/g/usb-stream.h | 14 |
2 files changed, 36 insertions, 25 deletions
diff --git a/chip/g/usb-stream.c b/chip/g/usb-stream.c index 8241eaf43c..7ab28c37a6 100644 --- a/chip/g/usb-stream.c +++ b/chip/g/usb-stream.c @@ -120,7 +120,7 @@ static inline int tx_fifo_is_ready(struct usb_stream_config const *config) uint32_t status; struct g_usb_desc *in_desc = config->in_desc; - if (!(in_desc->flags & DOEPDMA_LAST)) + if (!(in_desc->flags & DIEPDMA_LAST)) ++in_desc; status = in_desc->flags & DIEPDMA_BS_MASK; @@ -133,12 +133,6 @@ void tx_stream_handler(struct usb_stream_config const *config) size_t count; struct queue const *tx_q = config->consumer.queue; - if (!*config->is_reset) - return; - - if (!tx_fifo_is_ready(config)) - return; - /* handle the completion of the previous transfer, if there was any. */ count = *(config->tx_handled); if (count > 0) { @@ -194,21 +188,30 @@ void tx_stream_handler(struct usb_stream_config const *config) * descriptor as well if it is needed. */ usb_enable_tx(config, len); + } else { + /* USB TX transfer is not active. */ + *config->tx_in_progress = 0; } } /* Tx/IN interrupt handler */ void usb_stream_tx(struct usb_stream_config const *config) { - /* Wake up the Tx FIFO handler */ - hook_call_deferred(config->deferred_tx, 0); - - /* clear the Tx/IN interrupts */ + /* Clear the Tx/IN interrupts */ GR_USB_DIEPINT(config->endpoint) = 0xffffffff; + + /* Call the Tx FIFO handler */ + tx_stream_handler(config); } void usb_stream_reset(struct usb_stream_config const *config) { + /* + * Mark USB TX transfer is in progress, because it shall be so at + * the end of this function to flush any queued data. + */ + *config->tx_in_progress = 1; + config->out_desc->flags = DOEPDMA_RXBYTES(config->rx_size) | DOEPDMA_LAST | DOEPDMA_BS_HOST_RDY | DOEPDMA_IOC; @@ -235,10 +238,8 @@ void usb_stream_reset(struct usb_stream_config const *config) GR_USB_DAINTMSK |= DAINT_INEP(config->endpoint) | DAINT_OUTEP(config->endpoint); - *config->is_reset = 1; - /* Flush any queued data */ - hook_call_deferred(config->deferred_tx, 0); + tx_stream_handler(config); hook_call_deferred(config->deferred_rx, 0); } @@ -250,12 +251,28 @@ static void usb_read(struct producer const *producer, size_t count) hook_call_deferred(config->deferred_rx, 0); } +/* + * NOTE: usb_written() should be called by IRQ handlers, so that + * it can be non-preemptive. + */ static void usb_written(struct consumer const *consumer, size_t count) { struct usb_stream_config const *config = DOWNCAST(consumer, struct usb_stream_config, consumer); - hook_call_deferred(config->deferred_tx, 0); + /* USB TX transfer is active. No need to activate it. */ + if (*config->tx_in_progress) + return; + + /* + * if USB Endpoint has not been initialized nor in ready status, + * then return. + */ + if (!tx_fifo_is_ready(config)) + return; + + *config->tx_in_progress = 1; + tx_stream_handler(config); } struct producer_ops const usb_stream_producer_ops = { diff --git a/chip/g/usb-stream.h b/chip/g/usb-stream.h index 020f6995c5..a0c580acea 100644 --- a/chip/g/usb-stream.h +++ b/chip/g/usb-stream.h @@ -29,12 +29,12 @@ struct usb_stream_config { */ int endpoint; - int *is_reset; + /* USB TX transfer is in progress */ + uint8_t *tx_in_progress; /* * Deferred function to call to handle USB and Queue request. */ - const struct deferred_data *deferred_tx; const struct deferred_data *deferred_rx; int tx_size; @@ -114,19 +114,16 @@ extern struct producer_ops const usb_stream_producer_ops; static struct g_usb_desc CONCAT2(NAME, _out_desc_); \ static struct g_usb_desc CONCAT2(NAME, _in_desc_)[MAX_IN_DESC]; \ static uint8_t CONCAT2(NAME, _buf_rx_)[RX_SIZE]; \ - static int CONCAT2(NAME, _is_reset_); \ - static void CONCAT2(NAME, _deferred_tx_)(void); \ - DECLARE_DEFERRED(CONCAT2(NAME, _deferred_tx_)); \ + static uint8_t CONCAT2(NAME, _tx_in_progress_); \ static void CONCAT2(NAME, _deferred_rx_)(void); \ DECLARE_DEFERRED(CONCAT2(NAME, _deferred_rx_)); \ static int CONCAT2(NAME, _rx_handled); \ static size_t CONCAT2(NAME, _tx_handled); \ struct usb_stream_config const NAME = { \ .endpoint = ENDPOINT, \ - .is_reset = &CONCAT2(NAME, _is_reset_), \ + .tx_in_progress = &CONCAT2(NAME, _tx_in_progress_), \ .in_desc = &CONCAT2(NAME, _in_desc_)[0], \ .out_desc = &CONCAT2(NAME, _out_desc_), \ - .deferred_tx = &CONCAT2(NAME, _deferred_tx__data), \ .deferred_rx = &CONCAT2(NAME, _deferred_rx__data), \ .tx_size = TX_SIZE, \ .rx_size = RX_SIZE, \ @@ -172,8 +169,6 @@ extern struct producer_ops const usb_stream_producer_ops; .wMaxPacketSize = RX_SIZE, \ .bInterval = 0, \ }; \ - static void CONCAT2(NAME, _deferred_tx_)(void) \ - { tx_stream_handler(&NAME); } \ static void CONCAT2(NAME, _deferred_rx_)(void) \ { rx_stream_handler(&NAME); } \ static void CONCAT2(NAME, _ep_tx)(void) \ @@ -218,7 +213,6 @@ extern struct producer_ops const usb_stream_producer_ops; * Handle USB and Queue request in a deferred callback. */ void rx_stream_handler(struct usb_stream_config const *config); -void tx_stream_handler(struct usb_stream_config const *config); /* * These functions are used by the trampoline functions defined above to |