1#include "esp_usb_ep.hpp"
3#if SOC_USB_OTG_SUPPORTED && defined(CONFIG_IDF_TARGET_ESP32S3) && \
4 CONFIG_IDF_TARGET_ESP32S3
9#include "esp_heap_caps.h"
11#include "esp_usb_dev.hpp"
16ESP32USBEndpoint::ESP32USBEndpoint(ESP32USBDevice& device, EPNumber number,
17 Direction direction, RawData buffer)
18 : USB::Endpoint(number, direction, buffer), device_(device)
22void ESP32USBEndpoint::Configure(
const Config& cfg)
24 ASSERT(cfg.direction == Direction::IN || cfg.direction == Direction::OUT);
26 auto& ep_cfg = GetConfig();
28 ep_cfg.max_packet_size = ESPUSBDetail::ClampPacketSize(cfg.type, cfg.max_packet_size);
29 if (ep_cfg.max_packet_size == 0U)
31 ep_cfg.max_packet_size = (cfg.type == Type::ISOCHRONOUS) ? 1023U : 64U;
34 auto buffer = GetBuffer();
35 if (buffer.size_ < ep_cfg.max_packet_size)
37 ep_cfg.max_packet_size =
static_cast<uint16_t
>(buffer.size_);
40 ASSERT(ep_cfg.max_packet_size > 0U);
42 if (device_.DmaEnabled() && (buffer.size_ > 0U) && !EnsureDmaShadow(buffer.size_))
44 SetState(State::ERROR);
48 if (cfg.direction == Direction::IN)
50 const bool is_bulk = (cfg.type == Type::BULK);
51 if (!fifo_allocated_ &&
52 !device_.AllocateTxFifo(EPNumberToInt8(GetNumber()), ep_cfg.max_packet_size,
53 is_bulk, fifo_words_))
55 SetState(State::ERROR);
58 fifo_allocated_ =
true;
62 if (!device_.EnsureRxFifo(ep_cfg.max_packet_size))
64 SetState(State::ERROR);
69 ActivateHardwareEndpoint();
71 SetState(State::IDLE);
74void ESP32USBEndpoint::Close()
76 auto* dev =
reinterpret_cast<usb_dwc_dev_t*
>(ESPUSBDetail::DWC2_FS_REG_BASE);
77 const uint8_t ep_num = EPNumberToInt8(GetNumber());
79 if (GetDirection() == Direction::IN)
83 if (dev->diepctl0_reg.epena)
85 ESPUSBDetail::DisableInEndpointAndWait(dev);
90 dev->diepempmsk_reg.val &= ~(1UL << ep_num);
91 if (dev->in_eps[ep_num - 1U].diepctl_reg.epena)
93 ESPUSBDetail::DisableInEndpointAndWait(dev, ep_num);
96 dev->daintmsk_reg.val &= ~(1UL << ep_num);
102 ESPUSBDetail::DisableOutEndpointAndWait(dev->doepctl0_reg);
106 ESPUSBDetail::DisableOutEndpointAndWait(dev->out_eps[ep_num - 1U].doepctl_reg);
108 dev->daintmsk_reg.val &= ~(1UL << (16U + ep_num));
111 ResetTransferState();
112 SetState(State::DISABLED);
117 const bool is_in = (GetDirection() == Direction::IN);
118 if ((GetState() == State::BUSY) && is_in)
120 return ErrorCode::BUSY;
123 auto* dev =
reinterpret_cast<usb_dwc_dev_t*
>(ESPUSBDetail::DWC2_FS_REG_BASE);
124 const uint8_t ep_num = EPNumberToInt8(GetNumber());
130 dev->diepctl0_reg.stall = 1;
134 dev->in_eps[ep_num - 1U].diepctl_reg.stall = 1;
141 dev->doepctl0_reg.stall = 1;
145 dev->out_eps[ep_num - 1U].doepctl_reg.stall = 1;
149 SetState(State::STALLED);
150 return ErrorCode::OK;
155 auto* dev =
reinterpret_cast<usb_dwc_dev_t*
>(ESPUSBDetail::DWC2_FS_REG_BASE);
156 const uint8_t ep_num = EPNumberToInt8(GetNumber());
158 if (GetDirection() == Direction::IN)
162 dev->diepctl0_reg.stall = 0;
166 auto& reg = dev->in_eps[ep_num - 1U].diepctl_reg;
175 dev->doepctl0_reg.stall = 0;
179 auto& reg = dev->out_eps[ep_num - 1U].doepctl_reg;
185 SetState(State::IDLE);
186 return ErrorCode::OK;
189ErrorCode ESP32USBEndpoint::Transfer(
size_t size)
191 if (GetState() == State::BUSY)
193 return ErrorCode::BUSY;
196 auto buffer = GetBuffer();
197 if (buffer.size_ < size)
199 return ErrorCode::NO_BUFF;
202 transfer_buffer_ =
static_cast<uint8_t*
>(buffer.addr_);
203 transfer_request_size_ = size;
204 transfer_actual_size_ = 0U;
205 transfer_queued_size_ = 0U;
207 const uint8_t ep_num = EPNumberToInt8(GetNumber());
208 if ((ep_num == 0U) && (GetDirection() == Direction::OUT))
210 ep0_out_phase_ = (size == 0U) ? Ep0OutPhase::STATUS : Ep0OutPhase::DATA;
213 if (UseDoubleBuffer() && GetDirection() == Direction::IN && size > 0U)
218 if (!PrepareTransferBuffer(size))
220 ResetTransferState();
221 return ErrorCode::NO_MEM;
224 SetState(State::BUSY);
225 ProgramTransfer(size);
226 return ErrorCode::OK;
229size_t ESP32USBEndpoint::MaxTransferSize()
const
231 if (GetNumber() == EPNumber::EP0)
233 return MaxPacketSize();
235 return GetBuffer().size_;
238void ESP32USBEndpoint::ResetHardwareState()
240 fifo_allocated_ =
false;
242 ResetTransferState();
243 SetState(State::DISABLED);
246void ESP32USBEndpoint::HandleInInterrupt(
bool in_isr)
248 const uint8_t ep_num = EPNumberToInt8(GetNumber());
249 usb_dwc_diepint_reg_t intr = {};
250 auto* dev =
reinterpret_cast<usb_dwc_dev_t*
>(ESPUSBDetail::DWC2_FS_REG_BASE);
254 intr.val = dev->diepint0_reg.val;
255 dev->diepint0_reg.val = intr.val;
259 intr.val = dev->in_eps[ep_num - 1U].diepint_reg.val;
260 dev->in_eps[ep_num - 1U].diepint_reg.val = intr.val;
263 if (!device_.DmaEnabled() && intr.txfemp)
266 if (transfer_queued_size_ >= transfer_request_size_)
268 dev->diepempmsk_reg.val &= ~(1UL << ep_num);
274 const bool rearm_ep0_setup = (ep_num == 0U) && device_.DmaEnabled() &&
275 (transfer_request_size_ == 0U) &&
276 device_.LastSetupDirectionOut();
277 dev->diepempmsk_reg.val &= ~(1UL << ep_num);
278 const size_t actual =
279 device_.DmaEnabled() ? GetCompletedTransferSize() : transfer_request_size_;
280 OnTransferCompleteCallback(in_isr, actual);
283 device_.ReloadSetupPacketCount();
285 if (GetState() != State::BUSY)
287 ResetTransferState();
292void ESP32USBEndpoint::FinishPendingEp0InStatus(
bool in_isr)
294 if (!device_.DmaEnabled() || (device_.endpoint_map_.in[0] ==
nullptr))
299 auto* ep0_in =
static_cast<ESP32USBEndpoint*
>(device_.endpoint_map_.in[0]);
300 if ((ep0_in->GetState() != State::BUSY) || (ep0_in->transfer_request_size_ != 0U))
305 ep0_in->OnTransferCompleteCallback(in_isr, 0U);
306 if (ep0_in->GetState() != State::BUSY)
308 ep0_in->ResetTransferState();
312void ESP32USBEndpoint::HandleOutInterrupt(
bool in_isr)
314 const uint8_t ep_num = EPNumberToInt8(GetNumber());
315 usb_dwc_doepint_reg_t intr = {};
316 auto* dev =
reinterpret_cast<usb_dwc_dev_t*
>(ESPUSBDetail::DWC2_FS_REG_BASE);
320 intr.val = dev->doepint0_reg.val;
321 dev->doepint0_reg.val = intr.val;
325 intr.val = dev->out_eps[ep_num - 1U].doepint_reg.val;
326 dev->out_eps[ep_num - 1U].doepint_reg.val = intr.val;
329 const bool ep0_setup_related =
330 (ep_num == 0U) && (intr.setup || intr.stuppktrcvd || intr.back2backsetup);
331 const bool has_active_ep0_transfer =
332 (ep_num == 0U) && (GetState() == State::BUSY) &&
333 ((transfer_buffer_ !=
nullptr) || (transfer_request_size_ > 0U));
335 if (intr.xfercompl &&
336 ((ep_num != 0U) || ((ep0_out_phase_ != Ep0OutPhase::SETUP) && !ep0_setup_related &&
337 has_active_ep0_transfer)))
339 const size_t actual =
340 device_.DmaEnabled() ? GetCompletedTransferSize() : transfer_actual_size_;
341 ASSERT(FinishOutTransfer(actual));
344 FinishPendingEp0InStatus(in_isr);
346 OnTransferCompleteCallback(in_isr, actual);
347 if ((ep_num == 0U) && device_.DmaEnabled() && (transfer_request_size_ == 0U))
349 device_.ReloadSetupPacketCount();
351 if (GetState() != State::BUSY)
353 ResetTransferState();
359 if (device_.DmaEnabled())
361 ASSERT(ESPUSBDetail::CacheSyncDmaBuffer(
362 device_.setup_packet_, ESP32USBDevice::SETUP_DMA_BUFFER_BYTES,
false));
364 device_.UpdateSetupState(device_.setup_packet_);
365 const auto* setup =
reinterpret_cast<const USB::SetupPacket*
>(device_.setup_packet_);
366 const bool expect_out_data_stage =
367 ((setup->bmRequestType & 0x80U) == 0U) && (setup->wLength > 0U);
369 FinishPendingEp0InStatus(in_isr);
370 ep0_out_phase_ = Ep0OutPhase::SETUP;
371 ResetTransferState();
372 SetState(State::IDLE);
374 if (device_.endpoint_map_.in[0] !=
nullptr)
376 auto* ep0_in =
static_cast<ESP32USBEndpoint*
>(device_.endpoint_map_.in[0]);
377 if (ep0_in->GetState() == State::BUSY)
379 ep0_in->ResetTransferState();
380 ep0_in->SetState(State::IDLE);
384 if (device_.DmaEnabled() && !expect_out_data_stage)
386 device_.ReloadSetupPacketCount();
388 device_.OnSetupPacket(in_isr, setup);
392void ESP32USBEndpoint::HandleRxData(
size_t size)
394 uint8_t*
const dst = (transfer_buffer_ !=
nullptr)
395 ? (transfer_buffer_ + transfer_actual_size_)
397 const size_t remain = (transfer_request_size_ > transfer_actual_size_)
398 ? (transfer_request_size_ - transfer_actual_size_)
400 const size_t copy_size = std::min(size, remain);
401 const size_t drop_size = size - copy_size;
405 ESPUSBDetail::ReadFifoPacket(
406 ESPUSBDetail::GetEndpointFifo(
407 reinterpret_cast<usb_dwc_dev_t*
>(ESPUSBDetail::DWC2_FS_REG_BASE), 0),
409 transfer_actual_size_ += copy_size;
417 uint8_t sink[64] = {};
418 size_t remain_drop = drop_size;
419 auto* fifo = ESPUSBDetail::GetEndpointFifo(
420 reinterpret_cast<usb_dwc_dev_t*
>(ESPUSBDetail::DWC2_FS_REG_BASE), 0);
421 while (remain_drop > 0U)
423 const size_t chunk = std::min(remain_drop,
sizeof(sink));
424 ESPUSBDetail::ReadFifoPacket(fifo, sink, chunk);
425 remain_drop -= chunk;
429void ESP32USBEndpoint::ObserveDmaRxStatus(uint8_t pktsts,
size_t size)
431 if (!device_.DmaEnabled() || (GetDirection() != Direction::OUT))
436 if (pktsts != ESPUSBDetail::RX_STATUS_DATA)
441 dma_rx_status_seen_ =
true;
442 dma_rx_status_bytes_ = std::min(transfer_request_size_, dma_rx_status_bytes_ + size);
445void ESP32USBEndpoint::ResetTransferState()
447 transfer_buffer_ =
nullptr;
448 transfer_hw_buffer_ =
nullptr;
449 transfer_request_size_ = 0U;
450 transfer_actual_size_ = 0U;
451 transfer_queued_size_ = 0U;
452 transfer_uses_shadow_ =
false;
453 transfer_direct_sync_size_ = 0U;
454 dma_rx_status_bytes_ = 0U;
455 dma_rx_status_seen_ =
false;
458bool ESP32USBEndpoint::EnsureDmaShadow(
size_t size)
460 const size_t need = ESPUSBDetail::AlignUp(size, ESPUSBDetail::USB_DMA_ALIGNMENT);
466 if ((dma_shadow_buffer_ !=
nullptr) && (dma_shadow_size_ >= need))
471 void* new_buffer = heap_caps_aligned_alloc(ESPUSBDetail::USB_DMA_ALIGNMENT, need,
472 ESPUSBDetail::DMA_MEMORY_CAPS);
473 if (new_buffer ==
nullptr)
478 if (dma_shadow_buffer_ !=
nullptr)
480 heap_caps_free(dma_shadow_buffer_);
483 dma_shadow_buffer_ =
static_cast<uint8_t*
>(new_buffer);
484 dma_shadow_size_ = need;
488bool ESP32USBEndpoint::PrepareTransferBuffer(
size_t size)
490 transfer_hw_buffer_ = transfer_buffer_;
491 transfer_uses_shadow_ =
false;
492 transfer_direct_sync_size_ = 0U;
494 if (!device_.DmaEnabled() || (size == 0U))
499 if (GetDirection() == Direction::IN)
501 if (ESPUSBDetail::CanUseDirectInDmaBuffer(transfer_buffer_, size))
503 return ESPUSBDetail::CacheSyncDmaBuffer(transfer_hw_buffer_, size,
true,
true);
508 auto buffer = GetBuffer();
509 if (ESPUSBDetail::CanUseDirectOutDmaBuffer(buffer.addr_, buffer.size_))
511 transfer_direct_sync_size_ = buffer.size_;
516 if (!EnsureDmaShadow(size))
521 transfer_hw_buffer_ = dma_shadow_buffer_;
522 transfer_uses_shadow_ =
true;
524 if (GetDirection() == Direction::IN)
526 ASSERT(transfer_buffer_ !=
nullptr);
527 std::memcpy(transfer_hw_buffer_, transfer_buffer_, size);
528 return ESPUSBDetail::CacheSyncDmaBuffer(
529 transfer_hw_buffer_, ESPUSBDetail::AlignUp(size, ESPUSBDetail::USB_DMA_ALIGNMENT),
533 return ESPUSBDetail::CacheSyncDmaBuffer(
534 transfer_hw_buffer_, ESPUSBDetail::AlignUp(size, ESPUSBDetail::USB_DMA_ALIGNMENT),
538bool ESP32USBEndpoint::FinishOutTransfer(
size_t actual_size)
540 transfer_actual_size_ = actual_size;
542 if (!device_.DmaEnabled() || (actual_size == 0U))
547 ASSERT(transfer_hw_buffer_ !=
nullptr);
549 if (!transfer_uses_shadow_)
551 if (transfer_direct_sync_size_ == 0U)
555 return ESPUSBDetail::CacheSyncDmaBuffer(transfer_hw_buffer_,
556 transfer_direct_sync_size_,
false);
559 ASSERT(transfer_buffer_ !=
nullptr);
561 if (!ESPUSBDetail::CacheSyncDmaBuffer(
563 ESPUSBDetail::AlignUp(actual_size, ESPUSBDetail::USB_DMA_ALIGNMENT),
false))
568 std::memcpy(transfer_buffer_, transfer_hw_buffer_, actual_size);
572size_t ESP32USBEndpoint::GetRemainingTransferSize()
const
574 auto* dev =
reinterpret_cast<usb_dwc_dev_t*
>(ESPUSBDetail::DWC2_FS_REG_BASE);
575 const uint8_t ep_num = EPNumberToInt8(GetNumber());
577 if (GetDirection() == Direction::IN)
581 return dev->dieptsiz0_reg.xfersize;
583 return dev->in_eps[ep_num - 1U].dieptsiz_reg.xfersize;
588 return dev->doeptsiz0_reg.xfersize;
590 return dev->out_eps[ep_num - 1U].doeptsiz_reg.xfersize;
593size_t ESP32USBEndpoint::GetCompletedTransferSize()
const
595 if ((GetDirection() == Direction::OUT) && device_.DmaEnabled() && dma_rx_status_seen_)
597 return dma_rx_status_bytes_;
600 const size_t remaining = GetRemainingTransferSize();
601 return (remaining >= transfer_request_size_) ? 0U
602 : (transfer_request_size_ - remaining);
605void ESP32USBEndpoint::ActivateHardwareEndpoint()
607 auto* dev =
reinterpret_cast<usb_dwc_dev_t*
>(ESPUSBDetail::DWC2_FS_REG_BASE);
608 const uint8_t ep_num = EPNumberToInt8(GetNumber());
609 auto& cfg = GetConfig();
611 if (GetDirection() == Direction::IN)
615 usb_dwc_diepctl0_reg_t ctl = {};
616 ctl.mps = ESPUSBDetail::EncodeEp0Mps(cfg.max_packet_size);
618 ctl.eptype =
static_cast<uint32_t
>(cfg.type);
620 dev->diepctl0_reg.val = ctl.val;
624 usb_dwc_diepctl_reg_t ctl = {};
625 ctl.mps = cfg.max_packet_size;
627 ctl.eptype =
static_cast<uint32_t
>(cfg.type);
630 dev->in_eps[ep_num - 1U].diepctl_reg.val = ctl.val;
632 dev->daintmsk_reg.val |= (1UL << ep_num);
638 usb_dwc_doepctl0_reg_t ctl = {};
639 ctl.mps = ESPUSBDetail::EncodeEp0Mps(cfg.max_packet_size);
641 ctl.eptype =
static_cast<uint32_t
>(cfg.type);
642 dev->doepctl0_reg.val = ctl.val;
646 usb_dwc_doepctl_reg_t ctl = {};
647 ctl.mps = cfg.max_packet_size;
649 ctl.eptype =
static_cast<uint32_t
>(cfg.type);
651 dev->out_eps[ep_num - 1U].doepctl_reg.val = ctl.val;
653 dev->daintmsk_reg.val |= (1UL << (16U + ep_num));
657void ESP32USBEndpoint::ProgramTransfer(
size_t size)
659 auto* dev =
reinterpret_cast<usb_dwc_dev_t*
>(ESPUSBDetail::DWC2_FS_REG_BASE);
660 const uint8_t ep_num = EPNumberToInt8(GetNumber());
661 const uint16_t pkt_count = ESPUSBDetail::PacketCount(size, MaxPacketSize());
663 if (GetDirection() == Direction::IN)
667 dev->dieptsiz0_reg.xfersize =
static_cast<uint32_t
>(size);
668 dev->dieptsiz0_reg.pktcnt = pkt_count;
669 if (device_.DmaEnabled() && (size > 0U))
671 dev->diepdma0_reg.dmaaddr =
672 static_cast<uint32_t
>(
reinterpret_cast<uintptr_t
>(transfer_hw_buffer_));
674 ESPUSBDetail::StartEndpointTransfer(dev->diepctl0_reg);
678 auto& tsiz = dev->in_eps[ep_num - 1U].dieptsiz_reg;
679 tsiz.xfersize =
static_cast<uint32_t
>(size);
680 tsiz.pktcnt = pkt_count;
682 if (device_.DmaEnabled() && (size > 0U))
684 dev->in_eps[ep_num - 1U].diepdma_reg.dmaddr =
685 static_cast<uint32_t
>(
reinterpret_cast<uintptr_t
>(transfer_hw_buffer_));
687 ESPUSBDetail::StartEndpointTransfer(dev->in_eps[ep_num - 1U].diepctl_reg);
690 if (!device_.DmaEnabled() && (size > 0U))
693 if ((ep_num != 0U) && (transfer_queued_size_ < transfer_request_size_))
695 dev->diepempmsk_reg.val |= (1UL << ep_num);
703 dev->doeptsiz0_reg.val = 0U;
704 dev->doeptsiz0_reg.xfersize =
705 static_cast<uint32_t
>((size == 0U) ? MaxPacketSize() : size);
706 dev->doeptsiz0_reg.pktcnt = pkt_count;
707 if (device_.DmaEnabled() && (size > 0U))
709 dev->doepdma0_reg.dmaaddr =
710 static_cast<uint32_t>(reinterpret_cast<uintptr_t>(transfer_hw_buffer_));
712 ESPUSBDetail::StartEndpointTransfer(dev->doepctl0_reg);
716 auto& tsiz = dev->out_eps[ep_num - 1U].doeptsiz_reg;
717 tsiz.xfersize =
static_cast<uint32_t
>(size);
718 tsiz.pktcnt = pkt_count;
720 if (device_.DmaEnabled() && (size > 0U))
722 dev->out_eps[ep_num - 1U].doepdma_reg.dmaaddr =
723 static_cast<uint32_t
>(
reinterpret_cast<uintptr_t
>(transfer_hw_buffer_));
725 ESPUSBDetail::StartEndpointTransfer(dev->out_eps[ep_num - 1U].doepctl_reg);
730void ESP32USBEndpoint::WriteMoreTxData()
732 if (transfer_buffer_ ==
nullptr || transfer_queued_size_ >= transfer_request_size_)
737 auto* dev =
reinterpret_cast<usb_dwc_dev_t*
>(ESPUSBDetail::DWC2_FS_REG_BASE);
738 const uint8_t ep_num = EPNumberToInt8(GetNumber());
739 const volatile uint32_t* fifo = ESPUSBDetail::GetEndpointFifo(dev, ep_num);
741 while (transfer_queued_size_ < transfer_request_size_)
743 uint16_t fifo_words = 0U;
746 fifo_words = dev->dtxfsts0_reg.ineptxfspcavail;
750 fifo_words = dev->in_eps[ep_num - 1U].dtxfsts_reg.ineptxfspcavail;
753 const size_t remaining = transfer_request_size_ - transfer_queued_size_;
754 const size_t packet_size = std::min(remaining,
static_cast<size_t>(MaxPacketSize()));
755 if (packet_size >
static_cast<size_t>(fifo_words) * 4U)
760 ESPUSBDetail::WriteFifoPacket(
const_cast<volatile uint32_t*
>(fifo),
761 transfer_buffer_ + transfer_queued_size_, packet_size);
762 transfer_queued_size_ += packet_size;