libxr
Embedded C++ framework for bare-metal, RTOS and Linux
Loading...
Searching...
No Matches
esp_usb_dev.cpp
1#include "esp_usb_dev.hpp"
2
3#if SOC_USB_OTG_SUPPORTED && defined(CONFIG_IDF_TARGET_ESP32S3) && \
4 CONFIG_IDF_TARGET_ESP32S3
5
6#include <cstring>
7#include <new>
8
9#include "esp32s3/rom/usb/cdc_acm.h"
10#include "esp32s3/rom/usb/usb_dc.h"
11#include "esp32s3/rom/usb/usb_device.h"
12#include "esp_attr.h"
13#include "esp_err.h"
14#include "esp_private/usb_phy.h"
15#include "esp_usb.hpp"
16#include "esp_usb_ep.hpp"
17#include "soc/interrupts.h"
18
19namespace LibXR
20{
21
22// 构造时先建立 endpoint 对象映射,再交给上层 USB core 统一驱动 / Build the
23// endpoint-object map first, then hand it to the shared USB core.
25 const std::initializer_list<EPConfig> ep_cfgs,
26 USB::DeviceDescriptor::PacketSize0 packet_size, uint16_t vid, uint16_t pid,
27 uint16_t bcd,
28 const std::initializer_list<const USB::DescriptorStrings::LanguagePack*> lang_list,
29 const std::initializer_list<const std::initializer_list<USB::ConfigDescriptorItem*>>
30 configs,
31 ConstRawData uid)
32 : USB::EndpointPool(ep_cfgs.size() * 2U),
33 USB::DeviceCore(*this, USB::USBSpec::USB_2_1, USB::Speed::FULL, packet_size, vid,
34 pid, bcd, lang_list, configs, uid)
35{
36 ASSERT(ep_cfgs.size() > 0U && ep_cfgs.size() <= ENDPOINT_COUNT);
37
38 auto cfg_it = ep_cfgs.begin();
39
40 auto* ep0_out = new ESP32USBEndpoint(*this, USB::Endpoint::EPNumber::EP0,
41 USB::Endpoint::Direction::OUT, cfg_it->buffer);
42 auto* ep0_in = new ESP32USBEndpoint(*this, USB::Endpoint::EPNumber::EP0,
43 USB::Endpoint::Direction::IN, cfg_it->buffer);
44
45 SetEndpoint0(ep0_in, ep0_out);
46 endpoint_map_.in[0] = ep0_in;
47 endpoint_map_.out[0] = ep0_out;
48
49 auto ep_num = USB::Endpoint::EPNumber::EP1;
50 for (++cfg_it; cfg_it != ep_cfgs.end();
51 ++cfg_it, ep_num = USB::Endpoint::NextEPNumber(ep_num))
52 {
53 DEV_ASSERT(USB::Endpoint::EPNumberToInt8(ep_num) < ENDPOINT_COUNT);
54
55 if (cfg_it->direction_hint == EPConfig::DirectionHint::BothDirections)
56 {
57 auto* ep_out = new ESP32USBEndpoint(*this, ep_num, USB::Endpoint::Direction::OUT,
58 cfg_it->buffer);
59 auto* ep_in = new ESP32USBEndpoint(*this, ep_num, USB::Endpoint::Direction::IN,
60 cfg_it->buffer);
61 endpoint_map_.out[USB::Endpoint::EPNumberToInt8(ep_num)] = ep_out;
62 endpoint_map_.in[USB::Endpoint::EPNumberToInt8(ep_num)] = ep_in;
63 Put(ep_out);
64 Put(ep_in);
65 }
66 else
67 {
68 const auto direction = (cfg_it->direction_hint == EPConfig::DirectionHint::InOnly)
69 ? USB::Endpoint::Direction::IN
70 : USB::Endpoint::Direction::OUT;
71 auto* ep = new ESP32USBEndpoint(*this, ep_num, direction, cfg_it->buffer);
72 if (direction == USB::Endpoint::Direction::IN)
73 {
74 endpoint_map_.in[USB::Endpoint::EPNumberToInt8(ep_num)] = ep;
75 }
76 else
77 {
78 endpoint_map_.out[USB::Endpoint::EPNumberToInt8(ep_num)] = ep;
79 }
80 Put(ep);
81 }
82 }
83}
84
85void ESP32USBDevice::Init(bool in_isr)
86{
87 // 每次重新 Init 前先重置 FIFO 账本,避免复用旧的分配状态 / Reset FIFO bookkeeping
88 // before each re-init so stale allocation state is not reused.
89 ResetFifoState();
90 USB::DeviceCore::Init(in_isr);
91}
92
93void ESP32USBDevice::Deinit(bool in_isr) { USB::DeviceCore::Deinit(in_isr); }
94
95// 地址只在 SETUP status 之前写入硬件,保持 control-transfer 时序正确 / Write the device
96// address only at the setup-before-status point to preserve control-transfer timing.
97ErrorCode ESP32USBDevice::SetAddress(uint8_t address, USB::DeviceCore::Context context)
98{
99 if (context == USB::DeviceCore::Context::SETUP_BEFORE_STATUS)
100 {
101 auto* dev = reinterpret_cast<usb_dwc_dev_t*>(ESPUSBDetail::DWC2_FS_REG_BASE);
102 dev->dcfg_reg.devaddr = address;
103 }
104 return ErrorCode::OK;
105}
106
107void ESP32USBDevice::Start(bool)
108{
109 // Start 是幂等的;PHY/IRQ/ROM 清理只做一次,core 寄存器则按当前状态重建 / Start is
110 // idempotent: PHY/IRQ/ROM cleanup are one-time, while core registers are rebuilt for
111 // the current state.
112 if (runtime_.started)
113 {
114 return;
115 }
116
117 EnsureRomUsbCleaned();
118 [[maybe_unused]] const auto ensure_phy_ready_result = EnsurePhyReady();
119 REQUIRE(ensure_phy_ready_result);
120 [[maybe_unused]] const auto ensure_interrupt_ready_result = EnsureInterruptReady();
121 REQUIRE(ensure_interrupt_ready_result);
122
123 InitializeCore();
124 if (IsInited())
125 {
126 USB::DeviceCore::Deinit(false);
127 USB::DeviceCore::Init(false);
128 }
129
130 auto* dev = reinterpret_cast<usb_dwc_dev_t*>(ESPUSBDetail::DWC2_FS_REG_BASE);
131 dev->dctl_reg.sftdiscon = 0;
132 dev->gahbcfg_reg.glbllntrmsk = 1;
133 if (runtime_.intr_handle != nullptr)
134 {
135 esp_intr_enable(runtime_.intr_handle);
136 }
137 runtime_.started = true;
138}
139
140void ESP32USBDevice::Stop(bool)
141{
142 // Stop 只关中断和软断开,不回收一次性 runtime 资源 / Stop only masks interrupts and
143 // soft-disconnects; it does not release one-time runtime resources.
144 auto* dev = reinterpret_cast<usb_dwc_dev_t*>(ESPUSBDetail::DWC2_FS_REG_BASE);
145 dev->gahbcfg_reg.glbllntrmsk = 0;
146 dev->gintmsk_reg.val = 0;
147 if (runtime_.intr_handle != nullptr)
148 {
149 esp_intr_disable(runtime_.intr_handle);
150 }
151 dev->dctl_reg.sftdiscon = 1;
152 runtime_.started = false;
153}
154
155void IRAM_ATTR ESP32USBDevice::IsrEntry(void* arg)
156{
157 auto* self = static_cast<ESP32USBDevice*>(arg);
158 if (self != nullptr)
159 {
160 self->HandleInterrupt();
161 }
162}
163
164bool ESP32USBDevice::EnsurePhyReady()
165{
166 // 内部 PHY 生命周期按整个设备实例保留,不做反复创建销毁 / Keep the internal PHY for the
167 // lifetime of the device instance instead of repeatedly recreating it.
168 if (runtime_.phy_ready)
169 {
170 return true;
171 }
172
173 usb_phy_config_t phy_conf = {
174 .controller = USB_PHY_CTRL_OTG,
175 .target = USB_PHY_TARGET_INT,
176 .otg_mode = USB_OTG_MODE_DEVICE,
177 .otg_speed = USB_PHY_SPEED_UNDEFINED,
178 .ext_io_conf = nullptr,
179 .otg_io_conf = nullptr,
180 };
181
182 usb_phy_handle_t handle = nullptr;
183 if (usb_new_phy(&phy_conf, &handle) != ESP_OK)
184 {
185 return false;
186 }
187
188 runtime_.phy_handle = handle;
189 runtime_.phy_ready = true;
190 return true;
191}
192
193bool ESP32USBDevice::EnsureInterruptReady()
194{
195 // 中断句柄按实例生命周期保留,只在第一次 Start 前注册一次 / Keep the interrupt handle
196 // for the instance lifetime and register it only once before the first start.
197 if (runtime_.irq_ready)
198 {
199 return true;
200 }
201
202 if (esp_intr_alloc(ETS_USB_INTR_SOURCE, ESP_INTR_FLAG_IRAM | ESP_INTR_FLAG_INTRDISABLED,
203 IsrEntry, this, &runtime_.intr_handle) != ESP_OK)
204 {
205 runtime_.intr_handle = nullptr;
206 return false;
207 }
208
209 runtime_.irq_ready = true;
210 return true;
211}
212
213void ESP32USBDevice::EnsureRomUsbCleaned()
214{
215 // 先清掉 ROM 默认 USB/CDC ACM 状态,再接管 DWC2 device core / Tear down the
216 // ROM-provided default USB/CDC ACM state before taking over the DWC2 device core.
217 if (runtime_.rom_usb_cleaned)
218 {
219 return;
220 }
221
222 usb_dev_deinit();
223 usb_dw_ctrl_deinit();
224 uart_acm_dev = nullptr;
225 runtime_.rom_usb_cleaned = true;
226}
227
228void ESP32USBDevice::InitializeCore()
229{
230 // 这里直接重建 DWC2 device-mode 寄存器基线:先停总中断,复位 core,再重建 FIFO/中断
231 // mask / Rebuild the DWC2 device-mode register baseline directly: stop global
232 // interrupts, reset the core, then rebuild FIFO and interrupt masks.
233 auto* dev = reinterpret_cast<usb_dwc_dev_t*>(ESPUSBDetail::DWC2_FS_REG_BASE);
234
235 dev->gahbcfg_reg.glbllntrmsk = 0;
236
237 while (!dev->grstctl_reg.ahbidle)
238 {
239 }
240
241 dev->gusbcfg_reg.forcehstmode = 0;
242 dev->gusbcfg_reg.forcedevmode = 1;
243 dev->gusbcfg_reg.physel = 1;
244 dev->gusbcfg_reg.usbtrdtim = 5;
245 dev->gusbcfg_reg.toutcal = 7;
246 dev->gusbcfg_reg.srpcap = 0;
247 dev->gusbcfg_reg.hnpcap = 0;
248
249 dev->grstctl_reg.csftrst = 1;
250 while (dev->grstctl_reg.csftrst)
251 {
252 }
253 while (!dev->grstctl_reg.ahbidle)
254 {
255 }
256
257 dev->pcgcctl_reg.stoppclk = 0;
258 dev->pcgcctl_reg.gatehclk = 0;
259 dev->pcgcctl_reg.pwrclmp = 0;
260 dev->pcgcctl_reg.rstpdwnmodule = 0;
261 dev->gotgctl_reg.avalidoven = 0;
262 dev->gotgctl_reg.bvalidoven = 1;
263 dev->gotgctl_reg.bvalidovval = 1;
264
265 ClearTxFifoRegisters();
266
267 FlushFifos();
268 ResetDeviceState();
269
270 dev->gintsts_reg.val = 0xFFFFFFFFU;
271 dev->gotgint_reg.val = 0xFFFFFFFFU;
272 dev->gintmsk_reg.val = 0U;
273 dev->gahbcfg_reg.hbstlen = ESPUSBDetail::DMA_BURST_INCR4;
274 dev->gahbcfg_reg.dmaen = DmaEnabled() ? 1U : 0U;
275 dev->gahbcfg_reg.nptxfemplvl = 1;
276 dev->gahbcfg_reg.ptxfemplvl = 1;
277 dev->dcfg_reg.descdma = 0;
278 dev->dcfg_reg.nzstsouthshk = 1;
279 dev->gintmsk_reg.usbrstmsk = 1;
280 dev->gintmsk_reg.enumdonemsk = 1;
281 dev->gintmsk_reg.usbsuspmsk = 1;
282 dev->gintmsk_reg.wkupintmsk = 1;
283 dev->gintmsk_reg.rxflvlmsk = DmaEnabled() ? 0U : 1U;
284 dev->gintmsk_reg.oepintmsk = 1;
285 dev->gintmsk_reg.iepintmsk = 1;
286 dev->gintmsk_reg.otgintmsk = 1;
287}
288
289void ESP32USBDevice::ClearTxFifoRegisters()
290{
291 // 所有 TX FIFO 尺寸寄存器先清零,再按 endpoint 配置重新分配 / Clear all TX-FIFO size
292 // registers first, then reallocate them per endpoint configuration.
293 auto* dev = reinterpret_cast<usb_dwc_dev_t*>(ESPUSBDetail::DWC2_FS_REG_BASE);
294 dev->gnptxfsiz_reg.val = 0U;
295 const size_t tx_fifo_reg_count =
296 sizeof(dev->dieptxf_regs) / sizeof(dev->dieptxf_regs[0]);
297 for (size_t i = 0U; i < tx_fifo_reg_count; ++i)
298 {
299 dev->dieptxf_regs[i].val = 0U;
300 }
301}
302
303void ESP32USBDevice::FlushFifos()
304{
305 // 复位后先冲刷所有 FIFO,避免旧 payload / setup 残留 / Flush all FIFOs after reset so
306 // no stale payload or setup bytes survive.
307 auto* dev = reinterpret_cast<usb_dwc_dev_t*>(ESPUSBDetail::DWC2_FS_REG_BASE);
308 dev->grstctl_reg.txfnum = ESPUSBDetail::FLUSH_ALL_TX_FIFO;
309 dev->grstctl_reg.txfflsh = 1;
310 while (dev->grstctl_reg.txfflsh)
311 {
312 }
313 dev->grstctl_reg.rxfflsh = 1;
314 while (dev->grstctl_reg.rxfflsh)
315 {
316 }
317}
318
319void ESP32USBDevice::ResetFifoState()
320{
321 // FIFO 账本完全由当前硬件深度和 DMA 模式重新推导,不依赖旧运行态 / Recompute the FIFO
322 // bookkeeping solely from the current hardware depth and DMA mode, without relying on
323 // stale runtime state.
324 fifo_state_.depth_words = ESPUSBDetail::GetHardwareFifoDepthWords();
325 fifo_state_.rx_words =
326 ESPUSBDetail::CalcConfiguredRxFifoWords(64U, ENDPOINT_COUNT, DmaEnabled());
327 fifo_state_.tx_next_words = fifo_state_.rx_words;
328 std::memset(fifo_state_.tx_words, 0, sizeof(fifo_state_.tx_words));
329 std::memset(fifo_state_.tx_bound, 0, sizeof(fifo_state_.tx_bound));
330 fifo_state_.allocated_in = 0U;
331}
332
333void ESP32USBDevice::ResetDeviceState()
334{
335 // 总线复位后先清 device 级寄存器,再由 endpoint 层各自重建具体硬件配置 / After bus
336 // reset, clear the device-level register state first; each endpoint later rebuilds its
337 // own concrete hardware configuration.
338 ResetFifoState();
339 // Init() 在 Start() 打开内核时钟之前也会重置账本,此时读到的深度为 0;
340 // 这里内核已经上电。
341 // Init() also resets the bookkeeping before Start() clocks the core, when the depth
342 // reads as 0; here the core is powered.
343 DEV_ASSERT(fifo_state_.depth_words > 0U);
344 ResetControlState();
345
346 auto* dev = reinterpret_cast<usb_dwc_dev_t*>(ESPUSBDetail::DWC2_FS_REG_BASE);
347 dev->grxfsiz_reg.rxfdep = fifo_state_.rx_words;
348 ClearTxFifoRegisters();
349}
350
351void ESP32USBDevice::ResetEndpointHardwareState()
352{
353 // endpoint 对象本身保留,但它们的硬件绑定状态必须全部失效 / Keep the endpoint objects,
354 // but invalidate all of their hardware-bound state.
355 for (uint8_t i = 0; i < ENDPOINT_COUNT; ++i)
356 {
357 if (endpoint_map_.in[i] != nullptr)
358 {
359 static_cast<ESP32USBEndpoint*>(endpoint_map_.in[i])->ResetHardwareState();
360 }
361 if (endpoint_map_.out[i] != nullptr)
362 {
363 static_cast<ESP32USBEndpoint*>(endpoint_map_.out[i])->ResetHardwareState();
364 }
365 }
366}
367
368void ESP32USBDevice::ReloadSetupPacketCount()
369{
370 // EP0 setup 接收窗口在 reset/setup-done 之后都要重新装填 / Reload the EP0 setup receive
371 // window after reset and after each setup-done transition.
372 auto* dev = reinterpret_cast<usb_dwc_dev_t*>(ESPUSBDetail::DWC2_FS_REG_BASE);
373 dev->doeptsiz0_reg.val = 0U;
374 if (DmaEnabled())
375 {
376 dev->doeptsiz0_reg.xfersize = 3U * SETUP_PACKET_BYTES;
377 dev->doeptsiz0_reg.pktcnt = 1U;
378 dev->doeptsiz0_reg.supcnt = 3U;
379 const auto cache_sync_dma_buffer_result =
380 ESPUSBDetail::CacheSyncDmaBuffer(setup_packet_, SETUP_DMA_BUFFER_BYTES, false);
381 REQUIRE(cache_sync_dma_buffer_result);
382 dev->doepdma0_reg.dmaaddr =
383 static_cast<uint32_t>(reinterpret_cast<uintptr_t>(setup_packet_));
384 dev->doepctl0_reg.cnak = 1;
385 dev->doepctl0_reg.epena = 1;
386 if (endpoint_map_.out[0] != nullptr)
387 {
388 static_cast<ESP32USBEndpoint*>(endpoint_map_.out[0])->ep0_out_phase_ =
389 ESP32USBEndpoint::Ep0OutPhase::SETUP;
390 }
391 }
392 else
393 {
394 dev->doeptsiz0_reg.pktcnt = 1U;
395 dev->doeptsiz0_reg.xfersize = 3U * SETUP_PACKET_BYTES;
396 dev->doeptsiz0_reg.supcnt = 3U;
397 }
398}
399
400void ESP32USBDevice::ResetControlState() { control_ = {}; }
401
402// 只跟踪 setup 请求的 data-stage 方向,供 EP0 OUT/STATUS 判定复用 / Track only the
403// setup-request data-stage direction for later EP0 OUT/STATUS decisions.
404void ESP32USBDevice::UpdateSetupState(const uint8_t* setup)
405{
406 control_.setup_direction_out = (setup != nullptr) && ((setup[0] & 0x80U) == 0U);
407}
408
409void IRAM_ATTR ESP32USBDevice::HandleInterrupt()
410{
411 // 统一从 gintsts & gintmsk 取当前批次待处理中断,并在有限 guard 内排空 / Pull one
412 // interrupt batch from gintsts & gintmsk and drain it under a bounded guard.
413 auto* dev = reinterpret_cast<usb_dwc_dev_t*>(ESPUSBDetail::DWC2_FS_REG_BASE);
414 for (uint32_t guard = 0; guard < INTERRUPT_DISPATCH_GUARD; ++guard)
415 {
416 usb_dwc_gintsts_reg_t pending = {};
417 pending.val = dev->gintsts_reg.val & dev->gintmsk_reg.val;
418
419 if (pending.val == 0U)
420 {
421 break;
422 }
423
424 if (pending.usbrst)
425 {
426 dev->gintsts_reg.usbrst = 1;
427 HandleBusReset(true);
428 }
429
430 if (pending.enumdone)
431 {
432 dev->gintsts_reg.enumdone = 1;
433 const uint32_t enum_speed = dev->dsts_reg.enumspd;
434 if (enum_speed != ESPUSBDetail::ENUM_SPEED_FULL_30_TO_60_MHZ &&
435 enum_speed != ESPUSBDetail::ENUM_SPEED_FULL_48_MHZ)
436 {
437 REQUIRE_FROM_CALLBACK(false, true);
438 }
439 }
440
441 if (pending.usbsusp)
442 {
443 dev->gintsts_reg.usbsusp = 1;
444 }
445
446 if (pending.wkupint)
447 {
448 dev->gintsts_reg.wkupint = 1;
449 }
450
451 if (!DmaEnabled() && pending.rxflvl)
452 {
453 dev->gintmsk_reg.rxflvlmsk = 0;
454 while (dev->gintsts_reg.rxflvl)
455 {
456 HandleRxFifoLevel();
457 }
458 dev->gintmsk_reg.rxflvlmsk = 1;
459 }
460
461 if (pending.oepint)
462 {
463 HandleEndpointInterrupt(true, false);
464 }
465
466 if (pending.iepint)
467 {
468 HandleEndpointInterrupt(true, true);
469 }
470
471 if (pending.otgint)
472 {
473 const uint32_t otg_status = dev->gotgint_reg.val;
474 dev->gotgint_reg.val = otg_status;
475 }
476 }
477}
478
479void ESP32USBDevice::HandleBusReset(bool in_isr)
480{
481 // 总线复位路径先停所有 endpoint,再清 mask/FIFO/状态,最后把 setup 接收窗口重新挂回去 /
482 // The bus-reset path stops all endpoints first, then clears masks/FIFOs/state, and
483 // finally rearms the setup receive window.
484 auto* dev = reinterpret_cast<usb_dwc_dev_t*>(ESPUSBDetail::DWC2_FS_REG_BASE);
485
486 for (uint8_t i = 0; i < ENDPOINT_COUNT; ++i)
487 {
488 if (i == 0U)
489 {
490 ESPUSBDetail::DisableOutEndpointAndWait(dev->doepctl0_reg);
491 }
492 else
493 {
494 ESPUSBDetail::DisableOutEndpointAndWait(dev->out_eps[i - 1U].doepctl_reg);
495 }
496 }
497
498 for (uint8_t i = 0; i < ENDPOINT_COUNT; ++i)
499 {
500 if (i == 0U)
501 {
502 if (dev->diepctl0_reg.epena)
503 {
504 dev->diepctl0_reg.snak = 1;
505 dev->diepctl0_reg.epdis = 1;
506 }
507 }
508 else if (dev->in_eps[i - 1U].diepctl_reg.epena)
509 {
510 dev->in_eps[i - 1U].diepctl_reg.snak = 1;
511 dev->in_eps[i - 1U].diepctl_reg.epdis = 1;
512 }
513 }
514
515 dev->daintmsk_reg.val = 0U;
516 dev->doepmsk_reg.val = 0U;
517 dev->diepmsk_reg.val = 0U;
518 dev->diepempmsk_reg.val = 0U;
519 dev->doepmsk_reg.setupmsk = 1;
520 dev->doepmsk_reg.xfercomplmsk = 1;
521 dev->doepmsk_reg.epdisbldmsk = 1;
522 dev->doepmsk_reg.ahberrmsk = 1;
523 dev->doepmsk_reg.outtknepdismsk = 1;
524 dev->doepmsk_reg.stsphsercvdmsk = 1;
525 dev->doepmsk_reg.outpkterrmsk = 1;
526 dev->doepmsk_reg.bnaoutintrmsk = 1;
527 dev->doepmsk_reg.bbleerrmsk = 1;
528 dev->doepmsk_reg.nakmsk = 1;
529 dev->doepmsk_reg.nyetmsk = 1;
530 dev->diepmsk_reg.xfercomplmsk = 1;
531 dev->diepmsk_reg.timeoutmsk = 1;
532
533 FlushFifos();
534 ResetDeviceState();
535 ResetEndpointHardwareState();
536
537 dev->dcfg_reg.devaddr = 0U;
538
539 if (IsInited())
540 {
541 Deinit(in_isr);
542 Init(in_isr);
543 }
544
545 ReloadSetupPacketCount();
546}
547
548void ESP32USBDevice::HandleEndpointInterrupt(bool in_isr, bool in_dir)
549{
550 // daint 里只保留当前方向且已使能的 endpoint 位,然后逐个转发给 endpoint 对象 / Keep
551 // only enabled endpoint bits for the current direction from daint, then forward them
552 // one by one to the endpoint objects.
553 auto* dev = reinterpret_cast<usb_dwc_dev_t*>(ESPUSBDetail::DWC2_FS_REG_BASE);
554 const uint32_t daint = dev->daint_reg.val & dev->daintmsk_reg.val;
555 const uint32_t bits = in_dir ? (daint & 0xFFFFU) : ((daint >> 16U) & 0xFFFFU);
556
557 for (uint8_t ep_num = 0; ep_num < ENDPOINT_COUNT; ++ep_num)
558 {
559 if ((bits & (1UL << ep_num)) == 0U)
560 {
561 continue;
562 }
563
564 USB::Endpoint* ep = in_dir ? endpoint_map_.in[ep_num] : endpoint_map_.out[ep_num];
565 if (ep == nullptr)
566 {
567 continue;
568 }
569
570 auto* esp_ep = static_cast<ESP32USBEndpoint*>(ep);
571 if (in_dir)
572 {
573 esp_ep->HandleInInterrupt(in_isr);
574 }
575 else
576 {
577 esp_ep->HandleOutInterrupt(in_isr);
578 }
579 }
580}
581
582void ESP32USBDevice::HandleRxFifoLevel()
583{
584 // 非 DMA 模式下直接消费 grxstsp;DMA 模式下只把状态转发给 OUT endpoint / In non-DMA
585 // mode, consume grxstsp directly; in DMA mode, only forward the status to the OUT
586 // endpoint.
587 auto* dev = reinterpret_cast<usb_dwc_dev_t*>(ESPUSBDetail::DWC2_FS_REG_BASE);
588 usb_dwc_grxstsp_reg_t status = {};
589 status.val = dev->grxstsp_reg.val;
590 const uint8_t ep_num = static_cast<uint8_t>(status.chnum);
591
592 if (DmaEnabled())
593 {
594 if ((ep_num < ENDPOINT_COUNT) && (endpoint_map_.out[ep_num] != nullptr))
595 {
596 static_cast<ESP32USBEndpoint*>(endpoint_map_.out[ep_num])
597 ->ObserveDmaRxStatus(status.pktsts, status.bcnt);
598 }
599 return;
600 }
601
602 switch (status.pktsts)
603 {
604 case ESPUSBDetail::RX_STATUS_GLOBAL_OUT_NAK:
605 break;
606
607 case ESPUSBDetail::RX_STATUS_SETUP_DATA:
608 ESPUSBDetail::ReadFifoPacket(ESPUSBDetail::GetEndpointFifo(dev, 0), setup_packet_,
609 sizeof(setup_packet_));
610 UpdateSetupState(setup_packet_);
611 break;
612
613 case ESPUSBDetail::RX_STATUS_SETUP_DONE:
614 ReloadSetupPacketCount();
615 break;
616
617 case ESPUSBDetail::RX_STATUS_DATA:
618 {
619 USB::Endpoint* ep = (ep_num < ENDPOINT_COUNT) ? endpoint_map_.out[ep_num] : nullptr;
620 if (ep != nullptr)
621 {
622 static_cast<ESP32USBEndpoint*>(ep)->HandleRxData(status.bcnt);
623 }
624 else
625 {
626 uint8_t sink[64] = {};
627 ESPUSBDetail::ReadFifoPacket(ESPUSBDetail::GetEndpointFifo(dev, 0), sink,
628 status.bcnt);
629 }
630 break;
631 }
632
633 case ESPUSBDetail::RX_STATUS_TRANSFER_COMPLETE:
634 default:
635 break;
636 }
637}
638
639bool ESP32USBDevice::AllocateTxFifo(uint8_t ep_num, uint16_t packet_size, bool is_bulk,
640 uint16_t& fifo_words)
641{
642 // TX FIFO 分配保持“前缀连续”布局;若中间某级无法满足,就整体拒绝,避免留下稀疏映射 /
643 // Keep TX-FIFO allocation prefix-contiguous; if any intermediate level cannot be
644 // satisfied, reject the whole request to avoid sparse mappings.
645 auto* dev = reinterpret_cast<usb_dwc_dev_t*>(ESPUSBDetail::DWC2_FS_REG_BASE);
646 const uint8_t max_in_ep_num =
647 static_cast<uint8_t>(sizeof(dev->dieptxf_regs) / sizeof(dev->dieptxf_regs[0]));
648
649 (void)is_bulk;
650
651 if (ep_num > max_in_ep_num)
652 {
653 return false;
654 }
655
656 const uint16_t words = ESPUSBDetail::CalcTxFifoWords(packet_size, DmaEnabled());
657 if (!fifo_state_.tx_bound[ep_num] && (fifo_state_.allocated_in >= IN_ENDPOINT_LIMIT))
658 {
659 return false;
660 }
661
662 for (uint8_t index = 0U; index <= ep_num; ++index)
663 {
664 const uint16_t requested_words =
665 (index == ep_num) ? words : ESPUSBDetail::ESP32_SX_FS_MIN_TX_FIFO_WORDS;
666 if (fifo_state_.tx_words[index] != 0U)
667 {
668 if (fifo_state_.tx_words[index] < requested_words)
669 {
670 return false;
671 }
672 continue;
673 }
674
675 const uint16_t next_words =
676 static_cast<uint16_t>(fifo_state_.tx_next_words + requested_words);
677 if (next_words > fifo_state_.depth_words)
678 {
679 return false;
680 }
681
682 const uint32_t tx_fifo_reg =
683 ESPUSBDetail::PackTxFifoSizeReg(fifo_state_.tx_next_words, requested_words);
684 if (index == 0U)
685 {
686 dev->gnptxfsiz_reg.val = tx_fifo_reg;
687 }
688 else
689 {
690 dev->dieptxf_regs[index - 1U].val = tx_fifo_reg;
691 }
692
693 fifo_state_.tx_words[index] = requested_words;
694 fifo_state_.tx_next_words = next_words;
695 }
696
697 if (!fifo_state_.tx_bound[ep_num])
698 {
699 fifo_state_.tx_bound[ep_num] = true;
700 fifo_state_.allocated_in++;
701 }
702 fifo_words = words;
703 return true;
704}
705
706bool ESP32USBDevice::EnsureRxFifo(uint16_t packet_size)
707{
708 // RX FIFO 只允许单调扩张,不做在线收缩,避免影响已经配置的 OUT endpoint / RX FIFO is
709 // allowed to grow monotonically only; it is not shrunk online, so already configured
710 // OUT endpoints are not disturbed.
711 auto* dev = reinterpret_cast<usb_dwc_dev_t*>(ESPUSBDetail::DWC2_FS_REG_BASE);
712 const uint16_t needed =
713 ESPUSBDetail::CalcConfiguredRxFifoWords(packet_size, ENDPOINT_COUNT, DmaEnabled());
714 if (needed <= fifo_state_.rx_words)
715 {
716 return true;
717 }
718
719 if (fifo_state_.tx_next_words != fifo_state_.rx_words)
720 {
721 return false;
722 }
723
724 if (needed > fifo_state_.depth_words)
725 {
726 return false;
727 }
728
729 fifo_state_.rx_words = needed;
730 fifo_state_.tx_next_words = needed;
731 dev->grxfsiz_reg.rxfdep = fifo_state_.rx_words;
732 return true;
733}
734
735} // namespace LibXR
736
737#endif
ESP32USBDevice(const std::initializer_list< EPConfig > ep_cfgs, USB::DeviceDescriptor::PacketSize0 packet_size, uint16_t vid, uint16_t pid, uint16_t bcd, const std::initializer_list< const USB::DescriptorStrings::LanguagePack * > lang_list, const std::initializer_list< const std::initializer_list< USB::ConfigDescriptorItem * > > configs, ConstRawData uid={nullptr, 0})
构造 ESP32-S3 USB device core / Construct the ESP32-S3 USB device core
PacketSize0
控制端点0最大包长度枚举 Packet size for endpoint 0 (bMaxPacketSize0)
Definition desc_dev.hpp:74
LibXR 命名空间 / LibXR namespace.
Definition ch32_can.hpp:14
ErrorCode
定义错误码枚举 / Defines an enumeration for error codes
@ FULL
已满 / Full