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