From c0030810dda8d9cca9cd041f246180ff03dc6624 Mon Sep 17 00:00:00 2001 From: hathach Date: Tue, 10 Sep 2024 16:15:51 +0700 Subject: [PATCH] update edpt_stream to support non-buffered (no fifo) mode --- src/common/tusb_private.h | 14 +++--- src/tusb.c | 102 ++++++++++++++++++++++++-------------- 2 files changed, 72 insertions(+), 44 deletions(-) diff --git a/src/common/tusb_private.h b/src/common/tusb_private.h index 5a1eb683b..ef0d5315e 100644 --- a/src/common/tusb_private.h +++ b/src/common/tusb_private.h @@ -129,11 +129,9 @@ uint32_t tu_edpt_stream_write_xfer(tu_edpt_stream_t* s); // Start an zero-length packet if needed bool tu_edpt_stream_write_zlp_if_needed(tu_edpt_stream_t* s, uint32_t last_xferred_bytes); -// Get the number of bytes available for writing -TU_ATTR_ALWAYS_INLINE static inline -uint32_t tu_edpt_stream_write_available(tu_edpt_stream_t* s) { - return (uint32_t) tu_fifo_remaining(&s->ff); -} +// Get the number of bytes available for writing to FIFO +// Note: if no fifo, return endpoint size if not busy, 0 otherwise +uint32_t tu_edpt_stream_write_available(tu_edpt_stream_t* s); //--------------------------------------------------------------------+ // Stream Read @@ -148,13 +146,15 @@ uint32_t tu_edpt_stream_read_xfer(tu_edpt_stream_t* s); // Must be called in the transfer complete callback TU_ATTR_ALWAYS_INLINE static inline void tu_edpt_stream_read_xfer_complete(tu_edpt_stream_t* s, uint32_t xferred_bytes) { - tu_fifo_write_n(&s->ff, s->ep_buf, (uint16_t) xferred_bytes); + if (tu_fifo_depth(&s->ff)) { + tu_fifo_write_n(&s->ff, s->ep_buf, (uint16_t) xferred_bytes); + } } // Same as tu_edpt_stream_read_xfer_complete but skip the first n bytes TU_ATTR_ALWAYS_INLINE static inline void tu_edpt_stream_read_xfer_complete_offset(tu_edpt_stream_t* s, uint32_t xferred_bytes, uint32_t skip_offset) { - if (skip_offset < xferred_bytes) { + if (tu_fifo_depth(&s->ff) && (skip_offset < xferred_bytes)) { tu_fifo_write_n(&s->ff, s->ep_buf + skip_offset, (uint16_t) (xferred_bytes - skip_offset)); } } diff --git a/src/tusb.c b/src/tusb.c index 7b840e3a2..44fd2dc14 100644 --- a/src/tusb.c +++ b/src/tusb.c @@ -239,8 +239,7 @@ bool tu_edpt_stream_deinit(tu_edpt_stream_t* s) { return true; } -TU_ATTR_ALWAYS_INLINE static inline -bool stream_claim(tu_edpt_stream_t* s) { +TU_ATTR_ALWAYS_INLINE static inline bool stream_claim(tu_edpt_stream_t* s) { if (s->is_host) { #if CFG_TUH_ENABLED return usbh_edpt_claim(s->daddr, s->ep_addr); @@ -253,8 +252,7 @@ bool stream_claim(tu_edpt_stream_t* s) { return false; } -TU_ATTR_ALWAYS_INLINE static inline -bool stream_xfer(tu_edpt_stream_t* s, uint16_t count) { +TU_ATTR_ALWAYS_INLINE static inline bool stream_xfer(tu_edpt_stream_t* s, uint16_t count) { if (s->is_host) { #if CFG_TUH_ENABLED return usbh_edpt_xfer(s->daddr, s->ep_addr, count ? s->ep_buf : NULL, count); @@ -267,8 +265,7 @@ bool stream_xfer(tu_edpt_stream_t* s, uint16_t count) { return false; } -TU_ATTR_ALWAYS_INLINE static inline -bool stream_release(tu_edpt_stream_t* s) { +TU_ATTR_ALWAYS_INLINE static inline bool stream_release(tu_edpt_stream_t* s) { if (s->is_host) { #if CFG_TUH_ENABLED return usbh_edpt_release(s->daddr, s->ep_addr); @@ -296,7 +293,6 @@ uint32_t tu_edpt_stream_write_xfer(tu_edpt_stream_t* s) { // skip if no data TU_VERIFY(tu_fifo_count(&s->ff), 0); - // Claim the endpoint TU_VERIFY(stream_claim(s), 0); // Pull data from FIFO -> EP buf @@ -315,46 +311,78 @@ uint32_t tu_edpt_stream_write_xfer(tu_edpt_stream_t* s) { uint32_t tu_edpt_stream_write(tu_edpt_stream_t* s, void const* buffer, uint32_t bufsize) { TU_VERIFY(bufsize); // TODO support ZLP - const uint16_t ret = tu_fifo_write_n(&s->ff, buffer, (uint16_t) bufsize); - // flush if fifo has more than packet size or - // in rare case: fifo depth is configured too small (which never reach packet size) - if ((tu_fifo_count(&s->ff) >= s->ep_packetsize) || (tu_fifo_depth(&s->ff) < s->ep_packetsize)) { - tu_edpt_stream_write_xfer(s); + if (0 == tu_fifo_depth(&s->ff)) { + // no fifo for buffered + TU_VERIFY(stream_claim(s), 0); + const uint32_t xact_len = tu_min32(bufsize, s->ep_bufsize); + memcpy(s->ep_buf, buffer, xact_len); + TU_ASSERT(stream_xfer(s, xact_len), 0); + return xact_len; + } else { + const uint16_t ret = tu_fifo_write_n(&s->ff, buffer, (uint16_t) bufsize); + + // flush if fifo has more than packet size or + // in rare case: fifo depth is configured too small (which never reach packet size) + if ((tu_fifo_count(&s->ff) >= s->ep_packetsize) || (tu_fifo_depth(&s->ff) < s->ep_packetsize)) { + tu_edpt_stream_write_xfer(s); + } + return ret; } +} - return ret; +uint32_t tu_edpt_stream_write_available(tu_edpt_stream_t* s) { + if (tu_fifo_depth(&s->ff)) { + return (uint32_t) tu_fifo_remaining(&s->ff); + } else { + bool is_busy = true; + if (s->is_host) { + #if CFG_TUH_ENABLED + is_busy = usbh_edpt_busy(s->daddr, s->ep_addr); + #endif + } else { + #if CFG_TUD_ENABLED + is_busy = usbd_edpt_busy(s->rhport, s->ep_addr); + #endif + } + return is_busy ? 0 : s->ep_bufsize; + } } //--------------------------------------------------------------------+ // Stream Read //--------------------------------------------------------------------+ uint32_t tu_edpt_stream_read_xfer(tu_edpt_stream_t* s) { - uint16_t available = tu_fifo_remaining(&s->ff); - - // Prepare for incoming data but only allow what we can store in the ring buffer. - // TODO Actually we can still carry out the transfer, keeping count of received bytes - // and slowly move it to the FIFO when read(). - // This pre-check reduces endpoint claiming - TU_VERIFY(available >= s->ep_packetsize); - - // claim endpoint - TU_VERIFY(stream_claim(s), 0); - - // get available again since fifo can be changed before endpoint is claimed - available = tu_fifo_remaining(&s->ff); - - if (available >= s->ep_packetsize) { - // multiple of packet size limit by ep bufsize - uint16_t count = (uint16_t) (available & ~(s->ep_packetsize - 1)); - count = tu_min16(count, s->ep_bufsize); - - TU_ASSERT(stream_xfer(s, count), 0); - return count; + if (0 == tu_fifo_depth(&s->ff)) { + // no fifo for buffered + TU_VERIFY(stream_claim(s), 0); + TU_ASSERT(stream_xfer(s, s->ep_bufsize), 0); + return s->ep_bufsize; } else { - // Release endpoint since we don't make any transfer - stream_release(s); - return 0; + uint16_t available = tu_fifo_remaining(&s->ff); + + // Prepare for incoming data but only allow what we can store in the ring buffer. + // TODO Actually we can still carry out the transfer, keeping count of received bytes + // and slowly move it to the FIFO when read(). + // This pre-check reduces endpoint claiming + TU_VERIFY(available >= s->ep_packetsize); + + TU_VERIFY(stream_claim(s), 0); + + // get available again since fifo can be changed before endpoint is claimed + available = tu_fifo_remaining(&s->ff); + + if (available >= s->ep_packetsize) { + // multiple of packet size limit by ep bufsize + uint16_t count = (uint16_t) (available & ~(s->ep_packetsize - 1)); + count = tu_min16(count, s->ep_bufsize); + TU_ASSERT(stream_xfer(s, count), 0); + return count; + } else { + // Release endpoint since we don't make any transfer + stream_release(s); + return 0; + } } }