Skip to main content

atmos/kernel/
usb.rs

1// usb.rs - Minimal DWC2 (Synopsys OTG) USB Host Controller & USB HID Stack
2#![allow(dead_code)]
3#![allow(static_mut_refs)]
4
5use crate::kernel::net;
6use crate::kernel::reclock::RecoverableMutex;
7
8// パニック回復対応ロック(NET_LOCK と同じ理由)。
9static USB_LOCK: RecoverableMutex<()> = RecoverableMutex::new(());
10
11/// パニック回復: コア `cid` が USB_LOCK を保持していれば強制解放する。
12pub fn force_release_locks(cid: i16) {
13    unsafe {
14        USB_LOCK.force_release_if_core(cid);
15    }
16}
17
18// BCM2837 DWC2 USB Base MMIO Address
19const USB_BASE: usize = 0x3F98_0000;
20
21// Global Registers
22const GOTGCTL: *mut u32 = USB_BASE as *mut u32;
23const GOTGINT: *mut u32 = (USB_BASE + 0x004) as *mut u32;
24const GAHBCFG: *mut u32 = (USB_BASE + 0x008) as *mut u32;
25const GUSBCFG: *mut u32 = (USB_BASE + 0x00C) as *mut u32;
26const GRSTCTL: *mut u32 = (USB_BASE + 0x010) as *mut u32;
27const GINTSTS: *mut u32 = (USB_BASE + 0x014) as *mut u32;
28const GINTMSK: *mut u32 = (USB_BASE + 0x018) as *mut u32;
29// 診断用: コア ID / ハードウェア構成(PHY 種別など)
30const GSNPSID: *mut u32 = (USB_BASE + 0x040) as *mut u32;
31const GHWCFG2: *mut u32 = (USB_BASE + 0x048) as *mut u32;
32const GRXSTSR: *mut u32 = (USB_BASE + 0x01C) as *mut u32;
33const GRXFSIZ: *mut u32 = (USB_BASE + 0x024) as *mut u32;
34const GNPTXFSIZ: *mut u32 = (USB_BASE + 0x028) as *mut u32;
35const GNPTXSTS: *mut u32 = (USB_BASE + 0x02C) as *mut u32;
36const HPTXFSIZ: *mut u32 = (USB_BASE + 0x100) as *mut u32;
37
38// Host Global Registers
39const HCFG: *mut u32 = (USB_BASE + 0x400) as *mut u32;
40const HFIR: *mut u32 = (USB_BASE + 0x404) as *mut u32;
41const HFNUM: *mut u32 = (USB_BASE + 0x408) as *mut u32;
42const HAINT: *mut u32 = (USB_BASE + 0x414) as *mut u32;
43const HAINTMSK: *mut u32 = (USB_BASE + 0x418) as *mut u32;
44const HPRT0: *mut u32 = (USB_BASE + 0x440) as *mut u32;
45// Power and Clock Gating Control。0 を書いて PHY クロックのゲートを解除する(BCM2837 必須)。
46const PCGCCTL: *mut u32 = (USB_BASE + 0xE00) as *mut u32;
47
48// Host Channel Registers
49const HC_BASE: usize = USB_BASE + 0x500;
50fn hc_char(n: usize) -> *mut u32 {
51    (HC_BASE + n * 0x20) as *mut u32
52}
53// HCSPLT (Split Control, offset +0x04)。非スプリット転送では 0 にクリアする。
54// これを書かないと、ファームウェア残留の SplitEna によりチャネルがスプリット転送を試み、
55// ルート機器(ハブ配下でない)相手では永遠に完了せず HCINT=0 でスタックする。
56fn hc_splt(n: usize) -> *mut u32 {
57    (HC_BASE + n * 0x20 + 0x04) as *mut u32
58}
59fn hc_int(n: usize) -> *mut u32 {
60    (HC_BASE + n * 0x20 + 0x08) as *mut u32
61}
62fn hc_intmsk(n: usize) -> *mut u32 {
63    (HC_BASE + n * 0x20 + 0x0C) as *mut u32
64}
65fn hc_tsiz(n: usize) -> *mut u32 {
66    (HC_BASE + n * 0x20 + 0x10) as *mut u32
67}
68fn hc_dma(n: usize) -> *mut u32 {
69    (HC_BASE + n * 0x20 + 0x14) as *mut u32
70}
71
72// USB Request Setup Packet structure
73#[repr(C, packed)]
74#[derive(Copy, Clone, Debug)]
75pub struct UsbSetupPacket {
76    pub request_type: u8,
77    pub request: u8,
78    pub value: u16,
79    pub index: u16,
80    pub length: u16,
81}
82
83// RNDIS packet message header structure (44 bytes)
84#[repr(C, packed)]
85#[derive(Copy, Clone, Debug)]
86pub struct RndisPacketMsg {
87    pub message_type: u32,              // 0x00000001 (RNDIS_PACKET_MSG)
88    pub message_length: u32,            // Total message length in bytes (44 + payload)
89    pub data_offset: u32, // Offset from the start of data_offset field (8 bytes from structure start) to payload (36)
90    pub data_length: u32, // Size of payload in bytes
91    pub oob_data_offset: u32, // 0
92    pub oob_data_length: u32, // 0
93    pub num_oob_data_elements: u32, // 0
94    pub packet_information_offset: u32, // 0
95    pub packet_information_length: u32, // 0
96    pub device_vc_handle: u32, // 0
97    pub reserved: u32,    // 0
98}
99
100// DMA用バッファ(メモリのアライメントに注意)
101#[repr(C, align(64))]
102struct DmaBuffer {
103    data: [u8; 2048],
104}
105
106static mut DMA_BUF: DmaBuffer = DmaBuffer { data: [0; 2048] };
107static mut SETUP_BUF: DmaBuffer = DmaBuffer { data: [0; 2048] };
108/// Ethernet bulk IN 専用 DMA バッファ。
109/// RX は「張りっぱなし」(async) 運用のため、TX/HID と共用すると保留中の DMA 書き込みと衝突する。
110static mut RX_DMA_BUF: DmaBuffer = DmaBuffer { data: [0; 2048] };
111static mut ETH_RX_BUF: [u8; 2048] = [0; 2048];
112static mut ETH_RX_LEN: usize = 0;
113
114const MAX_HID_DEVICES: usize = 4;
115const HUB_DESCRIPTOR_TYPE: u16 = 0x2900;
116const HUB_FEATURE_PORT_RESET: u16 = 4;
117const HUB_FEATURE_PORT_POWER: u16 = 8;
118const HUB_FEATURE_C_PORT_CONNECTION: u16 = 16;
119const HUB_FEATURE_C_PORT_RESET: u16 = 20;
120
121#[derive(Copy, Clone, PartialEq, Eq, Debug)]
122pub enum UsbDeviceKind {
123    None,
124    Hub,
125    Keyboard,
126    Mouse,
127    Tablet,
128    CdcEthernet,
129}
130
131#[derive(Copy, Clone)]
132struct UsbHidDevice {
133    address: u8,
134    ep0_mps: u16,
135    hid_ep: u8,
136    hid_ep_size: u16,
137    interface_number: u8,
138    kind: UsbDeviceKind,
139    key_prev_state: [u8; 6],
140    shift_pressed: bool,
141    ctrl_pressed: bool,
142    alt_pressed: bool,
143    gui_pressed: bool,
144    /// Interrupt IN 転送の DATA toggle (0=DATA0, 2=DATA1)
145    data_toggle: u32,
146}
147
148impl UsbHidDevice {
149    const fn empty() -> Self {
150        Self {
151            address: 0,
152            ep0_mps: 8,
153            hid_ep: 0,
154            hid_ep_size: 8,
155            interface_number: 0,
156            kind: UsbDeviceKind::None,
157            key_prev_state: [0; 6],
158            shift_pressed: false,
159            ctrl_pressed: false,
160            alt_pressed: false,
161            gui_pressed: false,
162            data_toggle: 0,
163        }
164    }
165}
166
167pub struct EnumeratedDevice {
168    pub kind: UsbDeviceKind,
169    pub address: u8,
170    pub interface_number: u8,
171    pub ep0_mps: u16,
172    pub hid_ep: u8,
173    pub hid_ep_size: u16,
174    pub port_count: u8,
175    pub bulk_in_ep: u8,
176    pub bulk_out_ep: u8,
177    pub bulk_ep_size: u16,
178    pub data_interface_number: u8,
179    pub data_alt_setting: u8,
180    /// 構成記述子の bConfigurationValue(SET_CONFIGURATION で使用)
181    pub config_value: u8,
182    pub is_rndis: bool,
183    pub i_mac_address: u8,
184    pub mac_address: Option<[u8; 6]>,
185}
186
187impl EnumeratedDevice {
188    pub fn empty() -> Self {
189        Self {
190            kind: UsbDeviceKind::None,
191            address: 0,
192            interface_number: 0,
193            ep0_mps: 8,
194            hid_ep: 0,
195            hid_ep_size: 0,
196            port_count: 0,
197            bulk_in_ep: 0,
198            bulk_out_ep: 0,
199            bulk_ep_size: 64,
200            data_interface_number: 0,
201            data_alt_setting: 0,
202            config_value: 1,
203            is_rndis: false,
204            i_mac_address: 0,
205            mac_address: None,
206        }
207    }
208}
209
210// デバイスの状態追跡
211static mut DEV_SPEED: u32 = 0; // 1: High, 2: Full, 3: Low
212static mut DEV_ADDR: u8 = 0;
213static mut EP0_MPS: u16 = 8; // コントロールエンドポイント0の最大パケットサイズ
214static mut HID_EP_SIZE: u16 = 8; // HIDインタラプトエンドポイントの最大パケットサイズ
215#[repr(align(64))]
216struct Align64<T>(T);
217
218static mut HID_DEVICES: Align64<[UsbHidDevice; MAX_HID_DEVICES]> = Align64([UsbHidDevice::empty(); MAX_HID_DEVICES]);
219static mut HID_DEVICE_COUNT: Align64<usize> = Align64(0);
220static mut HUB_ADDR: u8 = 0;
221static mut HUB_EP0_MPS: u16 = 8;
222static mut ETH_BULK_OUT_TOGGLE: u32 = 0;
223static mut ETH_BULK_IN_TOGGLE: u32 = 0;
224static mut HUB_PORT_COUNT: u8 = 0;
225static mut NEXT_DEVICE_ADDR: u8 = 1;
226
227static mut CURRENT_HUB_PORT: u8 = 0;
228static mut CURRENT_HUB_PORT_SPEED: u32 = 0; // 0: FS, 1: LS, 2: HS
229static mut DEV_SPEEDS: [u8; 16] = [0; 16]; // 各デバイスアドレス (0..16) の速度を記録する (0: FS, 1: LS, 2: HS)
230// 各デバイスの親ハブ情報。実機 RPi3B+ の LAN7515 はハブが2段構成のため、
231// スプリット転送の宛先 (直近の HS ハブのアドレスとポート) をデバイスごとに記録する。
232static mut DEV_HUB_ADDRS: [u8; 16] = [0; 16]; // 0 = ルート直結 (ハブ経由でない)
233static mut DEV_HUB_PORTS: [u8; 16] = [0; 16];
234
235// 簡易ディレイ
236fn delay_ms(ms: u32) {
237    // ARM ジェネリックタイマ (cntpct_el0) を使った実時間ウェイト。
238    // 旧実装は NOP ループ (ms*50000) で CPU クロック依存だったため、実機 RPi3B+ (1.4GHz) では
239    // ウェイトが極端に短くなり、USB リセット/安定待ちが不足して列挙失敗やコントローラ停止を招いていた。
240    let start = crate::kernel::timer::get_system_time_us();
241    let target = ms as u64 * 1000;
242    while crate::kernel::timer::get_system_time_us().wrapping_sub(start) < target {
243        unsafe {
244            core::arch::asm!("nop");
245        }
246    }
247}
248
249/// 指定レジスタの mask ビットがすべてセットされるまで実時間で待つ。
250/// timeout_ms 以内に成立すれば true、タイムアウトなら false(uspi の WaitForBit 相当)。
251/// 反復回数ベースの待ちは CPU クロック依存で実機 1.4GHz では早期に尽きるため使わない。
252unsafe fn wait_bit_set(reg: *mut u32, mask: u32, timeout_ms: u32) -> bool {
253    let start = crate::kernel::timer::get_system_time_us();
254    let limit = timeout_ms as u64 * 1000;
255    loop {
256        if core::ptr::read_volatile(reg) & mask == mask {
257            return true;
258        }
259        if crate::kernel::timer::get_system_time_us().wrapping_sub(start) > limit {
260            return false;
261        }
262    }
263}
264
265/// 指定レジスタの mask ビットがすべてクリアされるまで実時間で待つ。
266unsafe fn wait_bit_clear(reg: *mut u32, mask: u32, timeout_ms: u32) -> bool {
267    let start = crate::kernel::timer::get_system_time_us();
268    let limit = timeout_ms as u64 * 1000;
269    loop {
270        if core::ptr::read_volatile(reg) & mask == 0 {
271            return true;
272        }
273        if crate::kernel::timer::get_system_time_us().wrapping_sub(start) > limit {
274            return false;
275        }
276    }
277}
278
279/// HPRT0 レジスタを安全に読み取る。
280/// HPRT0 には W1C (Write-1-to-Clear) ビットが含まれており、read-modify-write で
281/// これらのビットを不用意に書き戻すとポートが無効化される。
282/// bit1=PrtConnDet, bit2=PrtEna, bit3=PrtEnChng, bit5=PrtOvrCurrChng
283unsafe fn read_hprt0_safe() -> u32 {
284    let val = core::ptr::read_volatile(HPRT0);
285    val & !(0b0010_1110) // W1C ビット (1,2,3,5) をマスク
286}
287
288/// DWC2 USBホストコントローラの初期化とデバイス検出
289pub fn init() {
290    // 一切の変更やソフトリセットを行う前に、初期レジスタのダンプを出力する
291    unsafe {
292        let initial_gusbcfg = core::ptr::read_volatile(GUSBCFG);
293        let initial_hprt0 = core::ptr::read_volatile(HPRT0);
294        let initial_hcfg = core::ptr::read_volatile(HCFG);
295        let initial_pcgcctl = core::ptr::read_volatile(PCGCCTL);
296        crate::warn!("[USB][DIAG] Initial state: GUSBCFG=0x{:08X} HPRT0=0x{:08X} HCFG=0x{:08X} PCGCCTL=0x{:08X}",
297            initial_gusbcfg, initial_hprt0, initial_hcfg, initial_pcgcctl);
298    }
299
300    // uspi 同様、初期化の最初に USB ホストコントローラの電源を投入する。
301    match crate::kernel::mailbox::power_on_usb() {
302        Ok(()) => {}
303        Err(e) => crate::warn!("[USB] Mailbox USB power ON: FAILED ({})", e),
304    }
305    delay_ms(500);
306
307    unsafe {
308        reset_device_state();
309
310        // ================= InitCore (GUSBCFG 設定後のソフトリセットシーケンス) =================
311        // リセット前に確実に PHY クロックのゲートを解除しておく
312        core::ptr::write_volatile(PCGCCTL, 0);
313        delay_ms(10);
314
315        let mut usbcfg = core::ptr::read_volatile(GUSBCFG);
316
317        // 1. ULPI_EXT_VBUS_DRV / TERM_SEL_DL_PULSE をクリア
318        usbcfg &= !(1 << 20); // ULPI_EXT_VBUS_DRV
319        usbcfg &= !(1 << 22); // TERM_SEL_DL_PULSE
320
321        // 2. UTMI+ (ULPI_UTMI_SELクリア) & PHYIF=8bit (PHYIFクリア)
322        usbcfg &= !(1 << 4); // ULPI_UTMI_SEL -> UTMI+
323        usbcfg &= !(1 << 3); // PHYIF -> 8bit
324
325        // 3. HS PHY が UTMI+(BCM2837)なので ULPI_FSLS / ULPI_CLK_SUS_M をクリア
326        usbcfg &= !(1 << 17); // ULPI_FSLS
327        usbcfg &= !(1 << 19); // ULPI_CLK_SUS_M
328
329        // 4. ホストモード強制
330        usbcfg |= 1 << 29; // ForceHstMode
331        usbcfg &= !(1 << 30); // clear ForceDevMode
332
333        // 5. USBTrdTim / TOutCal はファーム既定(5 / 0)のまま触らない。
334        //    Circle の実機 golden 値 USBCFG=0x20001400 が TrdTim=5・TOutCal=0 であり、
335        //    それで HS チャープが成功している。TrdTim=9/TOutCal=7 は HS を阻害したため撤去。
336
337        // 6. HNP / SRP 無効化
338        usbcfg &= !(1 << 9); // HNP_CAPABLE
339        usbcfg &= !(1 << 8); // SRP_CAPABLE
340
341        core::ptr::write_volatile(GUSBCFG, usbcfg);
342        delay_ms(10);
343
344        // 7. HCFG: FSLSPClkSel = 30/60MHz (0) をリセット前に設定(リセットでステートマシンに同期させる)
345        let mut hcfg = core::ptr::read_volatile(HCFG);
346        hcfg &= !0x3; // FSLSPClkSel = 0
347        core::ptr::write_volatile(HCFG, hcfg);
348        delay_ms(10);
349
350        // コアソフトリセット: GUSBCFG で設定した PHY 幅・ホストモードをステートマシンに反映させる
351        let ahb_idle_before = wait_bit_set(GRSTCTL, 1 << 31, 100); // AHB Idle
352        core::ptr::write_volatile(GRSTCTL, 1 << 0); // CSFTRST
353        let csftrst_cleared = wait_bit_clear(GRSTCTL, 1 << 0, 100); // CSFTRST 自己クリア待ち
354        let ahb_idle_after = wait_bit_set(GRSTCTL, 1 << 31, 100);
355        crate::warn!(
356            "[USB] srst: ahb_idle={}/{} csftrst_clr={} GRSTCTL=0x{:08X}",
357            ahb_idle_before,
358            ahb_idle_after,
359            csftrst_cleared,
360            core::ptr::read_volatile(GRSTCTL)
361        );
362        delay_ms(100);
363
364        // リセット後、速やかに PHY クロックのゲートを解除する
365        core::ptr::write_volatile(PCGCCTL, 0);
366        delay_ms(10);
367
368        // リセット直後のレジスタ値を診断ログで出力
369        let post_reset_usbcfg = core::ptr::read_volatile(GUSBCFG);
370        let post_reset_hcfg = core::ptr::read_volatile(HCFG);
371        crate::warn!(
372            "[USB][DIAG] Post-reset: GUSBCFG=0x{:08X} HCFG=0x{:08X}",
373            post_reset_usbcfg,
374            post_reset_hcfg
375        );
376
377        // ソフトリセットによって初期値に戻ってしまった GUSBCFG / HCFG を再度適用する。
378        // PHY構成関連ビット(ULPI_UTMI_SEL, PHYIF, ULPI_FSLS, ULPI_CLK_SUS_M, ULPI_EXT_VBUS_DRV, TERM_SEL_DL_PULSE, HNP/SRP)には触れず、
379        // リセットでクリアされる ForceHstMode, USBTrdTim, TOutCal のみを最小限に上書き設定する。
380        let mut usbcfg = post_reset_usbcfg;
381        usbcfg |= 1 << 29; // ForceHstMode
382        usbcfg &= !(1 << 30); // clear ForceDevMode
383                              // TrdTim / TOutCal はファーム既定のまま(Circle golden = TrdTim=5/TOutCal=0)。触らない。
384        core::ptr::write_volatile(GUSBCFG, usbcfg);
385        delay_ms(10);
386
387        let mut hcfg = core::ptr::read_volatile(HCFG);
388        // すでに FSLSPClkSel が 0 でなければ設定する
389        if (hcfg & 0x3) != 0 {
390            hcfg &= !0x3; // FSLSPClkSel = 0
391            core::ptr::write_volatile(HCFG, hcfg);
392            delay_ms(10);
393        }
394
395        // ホストモードへの遷移確認 (GINTSTS.CurMod が 1 になるのを待つ)
396        let mut curmod_ok = false;
397        for _ in 0..100 {
398            let gintsts = core::ptr::read_volatile(GINTSTS);
399            if (gintsts & 1) != 0 {
400                // CurMod (Bit 0) が 1 (Host)
401                curmod_ok = true;
402                break;
403            }
404            delay_ms(5);
405        }
406        if !curmod_ok {
407            crate::warn!(
408                "[USB]   WARNING: Host Mode transition timed out (GINTSTS=0x{:08X})",
409                core::ptr::read_volatile(GINTSTS)
410            );
411        }
412
413        // GAHBCFG: DMAEnable | WAIT_AXI_WRITES、MAX_AXI_BURST(bits2:1) クリア
414        let mut ahbcfg = core::ptr::read_volatile(GAHBCFG);
415        ahbcfg |= 1 << 5; // DMAEnable
416        ahbcfg |= 1 << 4; // WAIT_AXI_WRITES
417        ahbcfg &= !(3 << 1); // MAX_AXI_BURST = 0
418                             // GlobalInt(bit0): CPU への IRQ 線アサートを制御するビット。DMA モードでは必要
419        ahbcfg |= 1 << 0; // GlobalInt enable
420        core::ptr::write_volatile(GAHBCFG, ahbcfg);
421        crate::warn!(
422            "[USB] GAHBCFG=0x{:08X} GINTMSK=0x{:08X}",
423            core::ptr::read_volatile(GAHBCFG),
424            (1u32 << 3) | (1 << 24) | (1 << 25) | (1 << 29)
425        );
426
427        // 割り込みマスク: ホストチャネル割り込みをアンマスク(uspi EnableHostInterrupts 相当)。
428        core::ptr::write_volatile(GINTSTS, 0xFFFF_FFFF); // pending クリア
429                                                         // Circle golden GINTMSK=0x23000008: SOF(3) | PrtInt(24) | HChInt(25) | DisconnInt(29)
430        core::ptr::write_volatile(GINTMSK, (1 << 3) | (1 << 24) | (1 << 25) | (1 << 29));
431
432        // ================= InitHost (uspi 忠実移植) =================
433        // PHY クロックのゲートを解除(PCGCCTL=0)
434        crate::info!("[USB]   InitHost: restart PHY clock (PCGCCTL=0)...");
435        core::ptr::write_volatile(PCGCCTL, 0);
436
437        // HCFG: FSLSPClkSel = 30/60MHz (0)。FslsOnly は立てない(Circle golden HCFG=0x0)。
438        let mut hcfg = core::ptr::read_volatile(HCFG);
439        hcfg &= !0x3; // FSLSPClkSel = 30/60MHz (UTMI PHY 用)
440        core::ptr::write_volatile(HCFG, hcfg);
441        crate::warn!(
442            "[USB] HCFG=0x{:08X} FIFO RX/NP/P=1024/1024/1024",
443            core::ptr::read_volatile(HCFG)
444        );
445
446        // FIFO サイズ: Circle 実機 golden に一致させる。
447        // RXSIZ=1024, NPTXSIZ=depth1024|start1024(=0x04000400), HPTXSIZ=depth1024|start2048(=0x04000800)。
448        core::ptr::write_volatile(GRXFSIZ, 1024);
449        core::ptr::write_volatile(GNPTXFSIZ, 1024 | (1024 << 16));
450        core::ptr::write_volatile(HPTXFSIZ, (1024 + 1024) | (1024 << 16));
451
452        // FIFO フラッシュ(全 TX → RX、実時間ベースで完了待ち)
453        core::ptr::write_volatile(GRSTCTL, (0x10 << 6) | (1 << 5)); // TxFFlsh (all)
454        let txflush = wait_bit_clear(GRSTCTL, 1 << 5, 100);
455        core::ptr::write_volatile(GRSTCTL, 1 << 4); // RxFFlsh
456        let rxflush = wait_bit_clear(GRSTCTL, 1 << 4, 100);
457        if !txflush || !rxflush {
458            crate::warn!("[USB] FIFO flush TIMEOUT: tx={} rx={}", txflush, rxflush);
459        }
460
461        // ポート電源 ON
462        let hprt = read_hprt0_safe();
463        if (hprt & (1 << 12)) == 0 {
464            core::ptr::write_volatile(HPRT0, hprt | (1 << 12)); // PrtPwr
465        }
466        delay_ms(500);
467
468        // ================= EnableRootPort =================
469        crate::warn!("[USB] Waiting for device connection...");
470        let mut t = 20;
471        loop {
472            let v = core::ptr::read_volatile(HPRT0);
473            if (v & 1) != 0 {
474                crate::warn!("[USB] Device detected! HPRT0=0x{:08X}", v);
475                break;
476            }
477            delay_ms(100);
478            t -= 1;
479            if t == 0 {
480                crate::warn!("[USB] WARNING: No USB device detected.");
481                return;
482            }
483        }
484        delay_ms(1000); // USB 2.0 spec
485
486        const RESET_RETRIES: u32 = 8;
487        let mut enabled = false;
488        let mut hprt_final = 0u32;
489        let mut last_reset_try = 0u32;
490        for reset_try in 0..RESET_RETRIES {
491            let v = read_hprt0_safe();
492            core::ptr::write_volatile(HPRT0, v | (1 << 12) | (1 << 8)); // PrtPwr | PrtRst
493            delay_ms(100);
494            let v = read_hprt0_safe();
495            core::ptr::write_volatile(HPRT0, (v | (1 << 12)) & !(1 << 8)); // PrtPwr | clear PrtRst
496            delay_ms(200);
497
498            hprt_final = core::ptr::read_volatile(HPRT0);
499            enabled = (hprt_final & (1 << 2)) != 0; // PrtEna
500            last_reset_try = reset_try;
501
502            if !enabled {
503                delay_ms(50);
504                continue;
505            }
506
507            DEV_SPEED = (hprt_final >> 17) & 0x3; // PrtSpd
508            if DEV_SPEED == 0 {
509                break;
510            } // High Speed 達成
511            delay_ms(50);
512        }
513        crate::warn!(
514            "[USB] reset×{}: HPRT0=0x{:08X} PrtSpd={} ({})",
515            last_reset_try + 1,
516            hprt_final,
517            DEV_SPEED,
518            match DEV_SPEED {
519                0 => "HS",
520                1 => "FS",
521                2 => "LS",
522                _ => "?",
523            }
524        );
525
526        if enabled {
527            DEV_SPEED = (hprt_final >> 17) & 0x3; // PrtSpd (Port Speed)
528                                                  // 実機デバッグ: DWC2 の構成とホストクロック状態をダンプする。
529            {
530                let snpsid = core::ptr::read_volatile(GSNPSID);
531                let hwcfg2 = core::ptr::read_volatile(GHWCFG2);
532                let hfir = core::ptr::read_volatile(HFIR);
533                let hfnum1 = core::ptr::read_volatile(HFNUM) & 0x3FFF;
534                delay_ms(2);
535                let hfnum2 = core::ptr::read_volatile(HFNUM) & 0x3FFF;
536                crate::warn!(
537                    "[USB][DIAG] SNPSID=0x{:08X} HWCFG2=0x{:08X} GUSBCFG=0x{:08X} HCFG=0x{:08X}",
538                    snpsid,
539                    hwcfg2,
540                    core::ptr::read_volatile(GUSBCFG),
541                    core::ptr::read_volatile(HCFG)
542                );
543                crate::warn!(
544                    "[USB][DIAG] HFIR=0x{:08X} frame:{}->{} ({})",
545                    hfir,
546                    hfnum1,
547                    hfnum2,
548                    if hfnum2 != hfnum1 {
549                        "SOF OK"
550                    } else {
551                        "SOF STUCK!"
552                    }
553                );
554            }
555
556            // コントローラ側のホスト速度設定を設定値に同期 (実機クロック消失防止のためコメントアウト)
557            // let mut hcfg = core::ptr::read_volatile(HCFG);
558            // hcfg &= !0x3; // FSLSPclkSel
559            // BCM2837 DWC2 FSLSPclkSel: 0=30/60MHz(HS), 1=48MHz(FS), 2=6MHz(LS)
560            // if DEV_SPEED == 2 {
561            //     hcfg |= 2; // 6MHz for Low Speed
562            // } else {
563            //     hcfg |= 1; // 48MHz for Full/High Speed
564            // }
565            // core::ptr::write_volatile(HCFG, hcfg);
566
567            // ポートのW1C変化ビット (PrtConnDet=1, PrtEnChng=3, PrtOvrCurrChng=5) をクリアして
568            // 保留中のポート割り込み(GINTSTS bit24 PrtInt)を落とす。PrtEna(bit2)は read_hprt0_safe で
569            // マスク済みなので触らない(書き戻すとポートが無効化されるため)。
570            // 保留ポート割り込みがチャネルのスケジューリングを阻むことがあるため、列挙前に必ず落とす。
571            {
572                let v = read_hprt0_safe();
573                core::ptr::write_volatile(HPRT0, v | (1 << 1) | (1 << 3) | (1 << 5));
574                let after = core::ptr::read_volatile(GINTSTS);
575                crate::warn!(
576                    "[USB][DIAG] W1C cleared. HPRT0=0x{:08X} GINTSTS=0x{:08X}",
577                    core::ptr::read_volatile(HPRT0),
578                    after
579                );
580            }
581
582            // 8. デバイスの列挙(Enumeration)の実行
583            enumerate_root_device();
584        } else {
585            crate::warn!(
586                "[USB]   ERROR: Port did not enable after reset (500ms timeout). HPRT0=0x{:08X}",
587                hprt_final
588            );
589        }
590    }
591}
592
593unsafe fn reset_device_state() {
594    DEV_ADDR = 0;
595    EP0_MPS = 8;
596    HID_EP_SIZE = 8;
597    HID_DEVICE_COUNT.0 = 0;
598    HUB_ADDR = 0;
599    HUB_EP0_MPS = 8;
600    HUB_PORT_COUNT = 0;
601    NEXT_DEVICE_ADDR = 1;
602    CURRENT_HUB_PORT = 0;
603    CURRENT_HUB_PORT_SPEED = 0;
604    DEV_SPEEDS = [0; 16];
605    DEV_HUB_ADDRS = [0; 16];
606    DEV_HUB_PORTS = [0; 16];
607    for idx in 0..MAX_HID_DEVICES {
608        HID_DEVICES.0[idx] = UsbHidDevice::empty();
609    }
610}
611
612/// スプリット転送の宛先 (Transaction Translator を持つ直近の HS ハブ) を解決する。
613/// USB のトポロジ規則上、非 HS (FS/LS) で動作しているハブは TT を持たないため、
614/// その配下のデバイスへのスプリット転送は、そのハブではなくさらに上流の直近の
615/// HS ハブを宛先にしなければならない。中間ハブを辿って HS ハブに到達するまで遡る。
616unsafe fn resolve_split_target(hub_addr_in: u8, port_in: u8) -> (u8, u8) {
617    let mut hub_addr = hub_addr_in;
618    let mut port = port_in;
619    // hub_addr == 0 はルートハブ (常に HS) を意味するのでそのまま返す。
620    // 暴走防止のため最大16段まで遡る。
621    for _ in 0..16 {
622        if hub_addr == 0 || DEV_SPEEDS[hub_addr as usize] == 2 {
623            break;
624        }
625        let parent_addr = DEV_HUB_ADDRS[hub_addr as usize];
626        let parent_port = DEV_HUB_PORTS[hub_addr as usize];
627        if parent_addr == 0 && parent_port == 0 {
628            // これ以上遡る情報がない (異常系)。現状の hub_addr/port をそのまま使う。
629            break;
630        }
631        hub_addr = parent_addr;
632        port = parent_port;
633    }
634    (hub_addr, port)
635}
636
637unsafe fn select_control_target(address: u8, ep0_mps: u16) {
638    DEV_ADDR = address;
639    EP0_MPS = ep0_mps;
640}
641
642unsafe fn register_hid_device(device: EnumeratedDevice) {
643    if HID_DEVICE_COUNT.0 >= MAX_HID_DEVICES {
644        crate::debug!(
645            "  WARNING: HID device table is full. Skipping address {}.",
646            device.address
647        );
648        return;
649    }
650
651    HID_DEVICES.0[HID_DEVICE_COUNT.0] = UsbHidDevice {
652        address: device.address,
653        ep0_mps: device.ep0_mps,
654        hid_ep: device.hid_ep,
655        hid_ep_size: device.hid_ep_size,
656        interface_number: device.interface_number,
657        kind: device.kind,
658        key_prev_state: [0; 6],
659        shift_pressed: false,
660        ctrl_pressed: false,
661        alt_pressed: false,
662        gui_pressed: false,
663        data_toggle: 0,
664    };
665    HID_DEVICE_COUNT.0 += 1;
666
667    // キャッシュを物理メモリへ書き出し (Core 0 -> Core 1)
668    let count_addr = &HID_DEVICE_COUNT.0 as *const usize as usize;
669    crate::kernel::mmu::clean_dcache_range(count_addr, core::mem::size_of_val(&HID_DEVICE_COUNT.0));
670    let devices_addr = HID_DEVICES.0.as_ptr() as usize;
671    crate::kernel::mmu::clean_dcache_range(devices_addr, core::mem::size_of_val(&HID_DEVICES.0));
672    core::arch::asm!("dsb sy", "isb", options(nostack));
673
674    let kind = match device.kind {
675        UsbDeviceKind::Keyboard => "keyboard",
676        UsbDeviceKind::Mouse => "mouse",
677        UsbDeviceKind::Tablet => "tablet",
678        _ => "unknown",
679    };
680    crate::warn!(
681        "[USB] Registered USB HID {} at address {} (EP {}, MPS {}).",
682        kind,
683        device.address,
684        device.hid_ep,
685        device.hid_ep_size
686    );
687}
688
689unsafe fn parse_config_descriptor(total_len: u16, device_class: u8) -> EnumeratedDevice {
690    let mut result = EnumeratedDevice::empty();
691    // bConfigurationValue (構成記述子 offset 5) を保存。
692    // QEMU usb-net は config 1=RNDIS / config 2=CDC-ECM のため、ハードコードの 1 を
693    // SET_CONFIGURATION すると RNDIS 構成が活性化され、INITIALIZE 未実施の RNDIS
694    // ゲートにより bulk IN が永久 NAK(=受信不能)になっていた。
695    if total_len >= 9 {
696        result.config_value = DMA_BUF.data[5];
697    }
698    let mut current_kind = if device_class == 0x09 {
699        UsbDeviceKind::Hub
700    } else {
701        UsbDeviceKind::None
702    };
703    let mut current_interface = 0u8;
704    let mut current_alt = 0u8;
705    // current_alt_setting moved to inner loop
706    let mut current_if_class = 0u8;
707    let mut cdc_control_if = 0u8;
708    let mut cdc_data_if = 0u8;
709    let mut cdc_bulk_in = 0u8;
710    let mut cdc_bulk_out = 0u8;
711    let mut cdc_bulk_mps = 0u16;
712    let mut cdc_data_alt_setting = 0u8;
713    let mut cdc_detected = false;
714    let mut cdc_is_rndis = false;
715    let mut i = 0usize;
716
717    if current_kind == UsbDeviceKind::Hub {
718        result.kind = UsbDeviceKind::Hub;
719    }
720
721    while i < total_len as usize {
722        let desc_len = DMA_BUF.data[i] as usize;
723        if desc_len < 2 {
724            break;
725        }
726
727        let desc_type = DMA_BUF.data[i + 1];
728        if desc_type == 0x04 {
729            current_interface = DMA_BUF.data[i + 2];
730            let current_alt_setting = DMA_BUF.data[i + 3];
731            current_alt = current_alt_setting;
732            let if_class = DMA_BUF.data[i + 5];
733            let if_subclass = DMA_BUF.data[i + 6];
734            let if_protocol = DMA_BUF.data[i + 7];
735            let is_cdc_control = (if_class == 0x02 && matches!(if_subclass, 0x00 | 0x02 | 0x06))
736                || (if_class == 0xE0 && if_subclass == 0x01 && if_protocol == 0x03);
737            current_if_class = if_class;
738
739            if is_cdc_control {
740                cdc_detected = true;
741                cdc_control_if = current_interface;
742                // RNDIS 判定: class 0xE0 (Wireless/RNDIS) に加え、
743                // class 02/subclass 02/protocol 0xFF (ACM 形式の RNDIS。QEMU usb-net が使用) も RNDIS。
744                // これを CDC-ECM と誤認すると RNDIS INITIALIZE が送られず、
745                // デバイスの rndis_state が DATA_INITIALIZED にならないため受信が永久 NAK になる。
746                cdc_is_rndis = if_class == 0xE0
747                    || (if_class == 0x02 && if_subclass == 0x02 && if_protocol == 0xFF);
748            }
749            if if_class == 0x0A {
750                cdc_data_if = current_interface;
751                cdc_data_alt_setting = current_alt_setting;
752            }
753
754            current_kind = match if_class {
755                0x09 => UsbDeviceKind::Hub,
756                0x03 if if_protocol == 1 => UsbDeviceKind::Keyboard,
757                0x03 if if_protocol == 2 => UsbDeviceKind::Mouse,
758                0x03 if if_protocol == 0 => UsbDeviceKind::Tablet, // USB Tablet often uses protocol 0 (None)
759                0x02 if matches!(if_subclass, 0x00 | 0x02 | 0x06) => UsbDeviceKind::CdcEthernet,
760                0xE0 if if_subclass == 0x01 && if_protocol == 0x03 => UsbDeviceKind::CdcEthernet,
761                _ => UsbDeviceKind::None,
762            };
763
764            if result.kind == UsbDeviceKind::None && current_kind != UsbDeviceKind::None {
765                result.kind = current_kind;
766                result.interface_number = current_interface;
767                if current_kind == UsbDeviceKind::Hub {
768                    break;
769                }
770            }
771        } else if desc_type == 0x05
772            && (current_kind == UsbDeviceKind::Keyboard
773                || current_kind == UsbDeviceKind::Mouse
774                || current_kind == UsbDeviceKind::Tablet)
775        {
776            let ep_addr = DMA_BUF.data[i + 2];
777            let ep_attr = DMA_BUF.data[i + 3];
778            let raw_ep_size = ((DMA_BUF.data[i + 5] as u16) << 8 | (DMA_BUF.data[i + 4] as u16)) & 0x07FF;
779            let ep_size = raw_ep_size.min(64); // HIDデバイスのパケットサイズは最大64バイト
780            if (ep_addr & 0x80) != 0 && (ep_attr & 0x3) == 0x3 {
781                result.kind = current_kind;
782                result.interface_number = current_interface;
783                result.hid_ep = ep_addr & 0x0F;
784                result.hid_ep_size = ep_size;
785                break;
786            }
787        } else if desc_type == 0x05 && cdc_detected && current_if_class == 0x0A {
788            let ep_addr = DMA_BUF.data[i + 2];
789            let ep_attr = DMA_BUF.data[i + 3];
790            let raw_ep_size = ((DMA_BUF.data[i + 5] as u16) << 8 | (DMA_BUF.data[i + 4] as u16)) & 0x07FF;
791            let ep_size = raw_ep_size.min(1024);
792            if (ep_attr & 0x3) == 0x2 {
793                if (ep_addr & 0x80) != 0 {
794                    cdc_bulk_in = ep_addr & 0x0F;
795                    cdc_bulk_mps = ep_size;
796                } else {
797                    cdc_bulk_out = ep_addr & 0x0F;
798                    cdc_bulk_mps = ep_size;
799                }
800                // バルクデータ EP が含まれる alt 設定を採用する。
801                // CDC-ECM のデータ IF は alt 0=EP無し / alt 1=EP有り のため、
802                // EP が見つかった alt を SET_INTERFACE 対象にしないと RX が有効化されない。
803                cdc_data_alt_setting = current_alt;
804            }
805        } else if desc_type == 0x24 && DMA_BUF.data[i + 2] == 0x0F {
806            // CDC Ethernet Networking Functional Descriptor
807            if desc_len >= 4 {
808                result.i_mac_address = DMA_BUF.data[i + 3];
809            }
810        }
811
812        i += desc_len;
813    }
814
815    if cdc_detected && cdc_bulk_in != 0 && cdc_bulk_out != 0 {
816        result.kind = UsbDeviceKind::CdcEthernet;
817        result.interface_number = cdc_control_if;
818        result.data_interface_number = cdc_data_if;
819        result.data_alt_setting = cdc_data_alt_setting;
820        result.bulk_in_ep = cdc_bulk_in;
821        result.bulk_out_ep = cdc_bulk_out;
822        result.bulk_ep_size = cdc_bulk_mps;
823        result.is_rndis = cdc_is_rndis;
824    }
825
826    result
827}
828
829unsafe fn hub_get_port_count() -> Option<u8> {
830    select_control_target(HUB_ADDR, HUB_EP0_MPS);
831    let req = UsbSetupPacket {
832        request_type: 0xA0,
833        request: 0x06,
834        value: HUB_DESCRIPTOR_TYPE,
835        index: 0,
836        length: 9,
837    };
838    let buf_phys = &DMA_BUF as *const DmaBuffer as u32;
839    if usb_control_transfer(req, buf_phys, 9, true).is_err() {
840        return None;
841    }
842    Some(DMA_BUF.data[2])
843}
844
845unsafe fn hub_set_port_feature(port: u8, feature: u16) -> bool {
846    select_control_target(HUB_ADDR, HUB_EP0_MPS);
847    let req = UsbSetupPacket {
848        request_type: 0x23,
849        request: 0x03,
850        value: feature,
851        index: port as u16,
852        length: 0,
853    };
854    usb_control_transfer(req, 0, 0, false).is_ok()
855}
856
857unsafe fn hub_clear_port_feature(port: u8, feature: u16) -> bool {
858    select_control_target(HUB_ADDR, HUB_EP0_MPS);
859    let req = UsbSetupPacket {
860        request_type: 0x23,
861        request: 0x01,
862        value: feature,
863        index: port as u16,
864        length: 0,
865    };
866    usb_control_transfer(req, 0, 0, false).is_ok()
867}
868
869unsafe fn hub_get_port_status(port: u8) -> Option<u32> {
870    select_control_target(HUB_ADDR, HUB_EP0_MPS);
871    let req = UsbSetupPacket {
872        request_type: 0xA3,
873        request: 0x00,
874        value: 0,
875        index: port as u16,
876        length: 4,
877    };
878    let buf_phys = &DMA_BUF as *const DmaBuffer as u32;
879    if usb_control_transfer(req, buf_phys, 4, true).is_err() {
880        return None;
881    }
882
883    let status = DMA_BUF.data[0] as u32
884        | ((DMA_BUF.data[1] as u32) << 8)
885        | ((DMA_BUF.data[2] as u32) << 16)
886        | ((DMA_BUF.data[3] as u32) << 24);
887    Some(status)
888}
889
890unsafe fn hub_reset_port(port: u8) -> bool {
891    let _ = hub_clear_port_feature(port, HUB_FEATURE_C_PORT_CONNECTION);
892    let _ = hub_clear_port_feature(port, HUB_FEATURE_C_PORT_RESET);
893
894    if !hub_set_port_feature(port, HUB_FEATURE_PORT_RESET) {
895        return false;
896    }
897    delay_ms(100);
898    let _ = hub_clear_port_feature(port, HUB_FEATURE_C_PORT_RESET);
899    delay_ms(50);
900
901    for _ in 0..10 {
902        if let Some(status) = hub_get_port_status(port) {
903            if (status & 0x0003) == 0x0003 {
904                return true;
905            }
906        }
907        delay_ms(20);
908    }
909
910    false
911}
912
913unsafe fn enumerate_default_address_device(
914    new_address: u8,
915    label: &str,
916) -> Option<EnumeratedDevice> {
917    crate::info!("[USB] {}: starting enumeration on default address.", label);
918
919    select_control_target(0, 64);
920    HID_EP_SIZE = 8;
921
922    let buf_phys = &DMA_BUF as *const DmaBuffer as u32;
923    let req = UsbSetupPacket {
924        request_type: 0x80,
925        request: 0x06,
926        value: 0x0100,
927        index: 0,
928        length: 8,
929    };
930    if usb_control_transfer(req, buf_phys, 8, true).is_err() {
931        crate::warn!(
932            "[USB] {}: failed to read first device descriptor bytes.",
933            label
934        );
935        return None;
936    }
937
938    let ep0_mps = DMA_BUF.data[7] as u16;
939    crate::warn!(
940        "[USB] {}: max packet size = {} (parent hub_addr={} port={} speed={})",
941        label,
942        ep0_mps,
943        unsafe { HUB_ADDR },
944        unsafe { CURRENT_HUB_PORT },
945        unsafe { CURRENT_HUB_PORT_SPEED }
946    );
947    select_control_target(0, ep0_mps);
948
949    let set_addr_req = UsbSetupPacket {
950        request_type: 0x00,
951        request: 0x05,
952        value: new_address as u16,
953        index: 0,
954        length: 0,
955    };
956    if usb_control_transfer(set_addr_req, 0, 0, false).is_err() {
957        crate::info!("[USB] {}: failed to set address {}.", label, new_address);
958        return None;
959    }
960
961    delay_ms(20);
962    unsafe {
963        DEV_SPEEDS[new_address as usize] = CURRENT_HUB_PORT_SPEED as u8;
964        // この時点の HUB_ADDR / CURRENT_HUB_PORT は列挙中の直接の親ハブを指す
965        // (ルート直結の場合はともに 0)。直接の親を記録しておく (TT解決の連鎖に使う)。
966        DEV_HUB_ADDRS[new_address as usize] = HUB_ADDR;
967        DEV_HUB_PORTS[new_address as usize] = CURRENT_HUB_PORT;
968    }
969    select_control_target(new_address, ep0_mps);
970
971    let req_full = UsbSetupPacket {
972        request_type: 0x80,
973        request: 0x06,
974        value: 0x0100,
975        index: 0,
976        length: 18,
977    };
978    if usb_control_transfer(req_full, buf_phys, 18, true).is_err() {
979        crate::info!("[USB] {}: failed to read full device descriptor.", label);
980        return None;
981    }
982
983    let vid = (DMA_BUF.data[9] as u16) << 8 | (DMA_BUF.data[8] as u16);
984    let pid = (DMA_BUF.data[11] as u16) << 8 | (DMA_BUF.data[10] as u16);
985    let class = DMA_BUF.data[4];
986    let subclass = DMA_BUF.data[5];
987    let protocol = DMA_BUF.data[6];
988    crate::info!(
989        "[USB] {}: VID=0x{:04X} PID=0x{:04X} CLASS=0x{:02X} SUB=0x{:02X} PROTO=0x{:02X}",
990        label,
991        vid,
992        pid,
993        class,
994        subclass,
995        protocol
996    );
997
998    let config_req = UsbSetupPacket {
999        request_type: 0x80,
1000        request: 0x06,
1001        value: 0x0200,
1002        index: 0,
1003        length: 9,
1004    };
1005    if usb_control_transfer(config_req, buf_phys, 9, true).is_err() {
1006        crate::info!(
1007            "[USB] {}: failed to read configuration descriptor header.",
1008            label
1009        );
1010        return None;
1011    }
1012
1013    let total_len = (DMA_BUF.data[3] as u16) << 8 | (DMA_BUF.data[2] as u16);
1014    let req_config_all = UsbSetupPacket {
1015        request_type: 0x80,
1016        request: 0x06,
1017        value: 0x0200,
1018        index: 0,
1019        length: total_len,
1020    };
1021    if usb_control_transfer(req_config_all, buf_phys, total_len as u32, true).is_err() {
1022        crate::info!(
1023            "[USB] {}: failed to read full configuration descriptor.",
1024            label
1025        );
1026        return None;
1027    }
1028
1029    let mut result = parse_config_descriptor(total_len, class);
1030
1031    // String Descriptor (MAC)
1032    let mut mac_opt: Option<[u8; 6]> = None;
1033    if result.i_mac_address != 0 {
1034        let req_str = UsbSetupPacket {
1035            request_type: 0x80,
1036            request: 0x06,
1037            value: 0x0300 | (result.i_mac_address as u16),
1038            index: 0x0409, // English
1039            length: 255,
1040        };
1041        if usb_control_transfer(req_str, buf_phys, 255, true).is_ok() {
1042            let str_len = DMA_BUF.data[0] as usize;
1043            if str_len >= 26 && DMA_BUF.data[1] == 0x03 {
1044                let mut mac = [0u8; 6];
1045                let mut valid = true;
1046                for j in 0..6 {
1047                    let hi_char = DMA_BUF.data[2 + j * 4] as char;
1048                    let lo_char = DMA_BUF.data[2 + j * 4 + 2] as char;
1049                    let hi = hi_char.to_digit(16);
1050                    let lo = lo_char.to_digit(16);
1051                    if let (Some(h), Some(l)) = (hi, lo) {
1052                        mac[j] = ((h << 4) | l) as u8;
1053                    } else {
1054                        valid = false;
1055                        break;
1056                    }
1057                }
1058                if valid {
1059                    mac_opt = Some(mac);
1060                }
1061            }
1062        }
1063    }
1064
1065    result.address = new_address;
1066    result.ep0_mps = ep0_mps;
1067    result.mac_address = mac_opt;
1068
1069    let set_config_req = UsbSetupPacket {
1070        request_type: 0x00,
1071        request: 0x09,
1072        value: result.config_value.max(1) as u16, // 記述子の bConfigurationValue を使用
1073        index: 0,
1074        length: 0,
1075    };
1076    if usb_control_transfer(set_config_req, 0, 0, false).is_err() {
1077        crate::debug!("[USB] {}: failed to activate configuration.", label);
1078        return None;
1079    }
1080    delay_ms(20);
1081
1082    match result.kind {
1083        UsbDeviceKind::Hub => {
1084            HUB_ADDR = new_address;
1085            HUB_EP0_MPS = ep0_mps;
1086            if let Some(port_count) = hub_get_port_count() {
1087                result.port_count = port_count;
1088                crate::debug!(
1089                    "[USB] {}: identified as USB hub with {} port(s).",
1090                    label,
1091                    port_count
1092                );
1093            } else {
1094                crate::debug!("[USB] {}: failed to read hub descriptor.", label);
1095                return None;
1096            }
1097        }
1098        UsbDeviceKind::Keyboard | UsbDeviceKind::Mouse | UsbDeviceKind::Tablet => {
1099            let set_protocol_req = UsbSetupPacket {
1100                request_type: 0x21,
1101                request: 0x0B,
1102                value: 0,
1103                index: result.interface_number as u16,
1104                length: 0,
1105            };
1106            let _ = usb_control_transfer(set_protocol_req, 0, 0, false);
1107            let kind_str = match result.kind {
1108                UsbDeviceKind::Keyboard => "keyboard",
1109                UsbDeviceKind::Mouse => "mouse",
1110                UsbDeviceKind::Tablet => "tablet",
1111                _ => "unknown",
1112            };
1113            crate::debug!(
1114                "[USB] {}: identified as USB HID {} on interface {} endpoint {}.",
1115                label,
1116                kind_str,
1117                result.interface_number,
1118                result.hid_ep
1119            );
1120        }
1121        UsbDeviceKind::CdcEthernet => {
1122            if result.data_alt_setting != 0 {
1123                let set_interface_req = UsbSetupPacket {
1124                    request_type: 0x01,
1125                    request: 0x0B, // SET_INTERFACE
1126                    value: result.data_alt_setting as u16,
1127                    index: result.data_interface_number as u16,
1128                    length: 0,
1129                };
1130                if usb_control_transfer(set_interface_req, 0, 0, false).is_err() {
1131                    crate::debug!("[USB] {}: failed to set CDC-ECM data alternate setting.", label);
1132                    return None;
1133                }
1134            }
1135
1136            if !result.is_rndis {
1137                let set_packet_filter_req = UsbSetupPacket {
1138                    request_type: 0x21,
1139                    request: 0x43,
1140                    value: 0x000F, // Promiscuous, AllMulticast, Directed, Broadcast
1141                    index: result.interface_number as u16,
1142                    length: 0,
1143                };
1144                if usb_control_transfer(set_packet_filter_req, 0, 0, false).is_err() {
1145                    crate::debug!("[USB] {}: CDC-ECM packet filter set failed.", label);
1146                }
1147            } else {
1148                let init_req = UsbSetupPacket {
1149                    request_type: 0x21,
1150                    request: 0x00, // SEND_ENCAPSULATED_COMMAND
1151                    value: 0,
1152                    index: result.interface_number as u16,
1153                    length: 24,
1154                };
1155                let mut init_msg = [0u32; 6];
1156                init_msg[0] = 0x00000002; // REMOTE_NDIS_INITIALIZE_MSG
1157                init_msg[1] = 24;
1158                init_msg[2] = 1;
1159                init_msg[3] = 1;
1160                init_msg[4] = 1;
1161                init_msg[5] = 1580; // MaxTransferSize
1162
1163                let init_ptr = &init_msg as *const u32 as *const u8;
1164                let buf_phys = &DMA_BUF as *const DmaBuffer as u32;
1165                unsafe {
1166                    core::ptr::copy_nonoverlapping(init_ptr, DMA_BUF.data.as_mut_ptr(), 24);
1167                }
1168
1169                let init_ok = usb_control_transfer(init_req, buf_phys, 24, false).is_ok();
1170                crate::info!("[USB] RNDIS DIAG: INITIALIZE_MSG sent ok={}", init_ok);
1171
1172                // wait and get response
1173                delay_ms(10);
1174                let get_resp_req = UsbSetupPacket {
1175                    request_type: 0xA1,
1176                    request: 0x01, // GET_ENCAPSULATED_RESPONSE
1177                    value: 0,
1178                    index: result.interface_number as u16,
1179                    length: 1024,
1180                };
1181                let resp_ok = usb_control_transfer(get_resp_req, buf_phys, 1024, true).is_ok();
1182                crate::info!("[USB] RNDIS DIAG: GET_RESPONSE ok={} head={:02x} {:02x} {:02x} {:02x} | {:02x} {:02x} {:02x} {:02x}",
1183                    resp_ok,
1184                    DMA_BUF.data[0], DMA_BUF.data[1], DMA_BUF.data[2], DMA_BUF.data[3],
1185                    DMA_BUF.data[16], DMA_BUF.data[17], DMA_BUF.data[18], DMA_BUF.data[19]);
1186
1187                let _set_req = UsbSetupPacket {
1188                    request_type: 0x21,
1189                    request: 0x00,
1190                    value: 0,
1191                    index: result.interface_number as u16,
1192                    length: 32,
1193                };
1194                let mut set_msg = [0u32; 8];
1195                set_msg[0] = 0x00000005; // REMOTE_NDIS_SET_MSG
1196                set_msg[1] = 32;
1197                set_msg[2] = 2;
1198                set_msg[3] = 0x0001010E; // OID_GEN_CURRENT_PACKET_FILTER
1199                set_msg[6] = 0; // DeviceVcHandle
1200                set_msg[7] = 0x0000000F; // Filter: Directed, Multicast, AllMulticast, Broadcast
1201
1202                let set_req = UsbSetupPacket {
1203                    request_type: 0x21,
1204                    request: 0x00, // SEND_ENCAPSULATED_COMMAND
1205                    value: 0,
1206                    index: result.interface_number as u16,
1207                    length: 32,
1208                };
1209                unsafe {
1210                    core::ptr::copy_nonoverlapping(
1211                        set_msg.as_ptr() as *const u8,
1212                        DMA_BUF.data.as_mut_ptr(),
1213                        32,
1214                    );
1215                }
1216                let set_ok = usb_control_transfer(set_req, buf_phys, 32, false).is_ok();
1217                crate::info!("[USB] RNDIS DIAG: SET_PACKET_FILTER sent ok={}", set_ok);
1218                if set_ok {
1219                    delay_ms(10);
1220                    let read_req = UsbSetupPacket {
1221                        request_type: 0xA1,
1222                        request: 0x01,
1223                        value: 0,
1224                        index: result.interface_number as u16,
1225                        length: 64,
1226                    };
1227                    let r_ok = usb_control_transfer(read_req, buf_phys, 64, true).is_ok();
1228                    crate::info!(
1229                        "RNDIS DIAG: SET_RESPONSE ok={} status={:02x}{:02x}{:02x}{:02x}",
1230                        r_ok,
1231                        DMA_BUF.data[15],
1232                        DMA_BUF.data[14],
1233                        DMA_BUF.data[13],
1234                        DMA_BUF.data[12]
1235                    );
1236                }
1237            }
1238
1239            crate::debug!(
1240                "{}: identified as USB Ethernet {} (ctrl if {}, data if {} alt {}, bulk in {}, bulk out {}, mps {}).",
1241                label,
1242                if result.is_rndis { "RNDIS" } else { "CDC-ECM" },
1243                result.interface_number,
1244                result.data_interface_number,
1245                result.data_alt_setting,
1246                result.bulk_in_ep,
1247                result.bulk_out_ep,
1248                result.bulk_ep_size
1249            );
1250            let default_mac = [0x02, 0x00, 0xA1, 0xCE, 0x00, 0x01];
1251            let mac = result.mac_address.unwrap_or(default_mac);
1252            net::register_usb_ethernet(
1253                result.address,
1254                result.bulk_in_ep,
1255                result.bulk_out_ep,
1256                result.bulk_ep_size,
1257                result.is_rndis,
1258                mac,
1259            );
1260        }
1261        UsbDeviceKind::None => {
1262            crate::debug!("[USB] {}: unsupported USB device.", label);
1263            return None;
1264        }
1265    }
1266
1267    Some(result)
1268}
1269
1270unsafe fn enumerate_hub_children(depth: u8) {
1271    // 実機 RPi3B+ の LAN7515 はハブ2段構成のため再帰列挙する。暴走防止に深さ制限。
1272    if depth >= 4 {
1273        crate::warn!("[USB] Hub nesting too deep ({}). Skipping.", depth);
1274        return;
1275    }
1276    crate::info!("[USB] Starting USB hub child enumeration (depth {})...", depth);
1277
1278    // このハブ自身の識別情報を退避 (子ハブの再帰列挙でグローバルが書き替わるため)
1279    let my_hub_addr = HUB_ADDR;
1280    let my_hub_mps = HUB_EP0_MPS;
1281    let my_port_count = HUB_PORT_COUNT;
1282
1283    for port in 1..=my_port_count {
1284        let _ = hub_set_port_feature(port, HUB_FEATURE_PORT_POWER);
1285    }
1286    crate::info!("[USB] Waiting 1000ms for USB hub ports to settle...");
1287    delay_ms(1000); // 100msから1000msに延長。vmnet-sharedの初期化遅延対策
1288
1289    for port in 1..=my_port_count {
1290        let status = match hub_get_port_status(port) {
1291            Some(status) => status,
1292            None => {
1293                crate::debug!("[USB] Hub port {}: failed to read status.", port);
1294                continue;
1295            }
1296        };
1297
1298        if (status & 0x0001) == 0 {
1299            continue;
1300        }
1301
1302        crate::warn!(
1303            "[USB]   Hub port {}: device connected. status=0x{:08X} speed={}",
1304            port,
1305            status,
1306            CURRENT_HUB_PORT_SPEED
1307        );
1308        if !hub_reset_port(port) {
1309            crate::warn!("[USB]   Hub port {}: reset failed.", port);
1310            continue;
1311        }
1312
1313        // リセット後の回復ウェイト
1314        delay_ms(100);
1315
1316        // リセット後の最新ステータスと速度を再取得して更新する
1317        let status_post = match hub_get_port_status(port) {
1318            Some(s) => s,
1319            None => {
1320                crate::warn!("[USB]   Hub port {}: failed to read status post-reset.", port);
1321                continue;
1322            }
1323        };
1324        unsafe {
1325            CURRENT_HUB_PORT_SPEED = (status_post >> 9) & 0x3;
1326        }
1327        crate::warn!(
1328            "[USB]   Hub port {}: reset success. status=0x{:08X} speed={}",
1329            port,
1330            status_post,
1331            unsafe { CURRENT_HUB_PORT_SPEED }
1332        );
1333
1334        let child_addr = NEXT_DEVICE_ADDR + 1;
1335        let label_buf = [
1336            b'H',
1337            b'u',
1338            b'b',
1339            b' ',
1340            b'P',
1341            b'o',
1342            b'r',
1343            b't',
1344            b' ',
1345            b'0' + port,
1346        ];
1347        let label = unsafe { core::str::from_utf8_unchecked(&label_buf) };
1348
1349        // 親ハブ情報の保存
1350        unsafe {
1351            CURRENT_HUB_PORT = port;
1352        }
1353
1354        // アドレスは列挙の成否にかかわらず事前に消費する。
1355        // enumerate_default_address_device が SET_ADDRESS まで進んで失敗した場合、
1356        // デバイスは child_addr に居座ったままになる。次のデバイスが同じ child_addr を
1357        // 使うとバス上でアドレス衝突が起き、CSPLIT NAK 地獄になる。
1358        NEXT_DEVICE_ADDR = child_addr;
1359
1360        if let Some(child) = enumerate_default_address_device(child_addr, label) {
1361            match child.kind {
1362                UsbDeviceKind::Keyboard | UsbDeviceKind::Mouse | UsbDeviceKind::Tablet => {
1363                    register_hid_device(child)
1364                }
1365                UsbDeviceKind::CdcEthernet => {
1366                    crate::debug!("[USB] Hub port {}: USB Ethernet configured.", port)
1367                }
1368                UsbDeviceKind::Hub => {
1369                    // ネストハブ: enumerate_default_address_device が HUB_ADDR / HUB_EP0_MPS
1370                    // を子ハブに更新済み。ポート数を設定して子ハブ配下を再帰列挙する。
1371                    crate::warn!(
1372                        "[USB]   Hub port {}: nested hub (addr {}, {} ports). Enumerating children...",
1373                        port,
1374                        child.address,
1375                        child.port_count
1376                    );
1377                    HUB_PORT_COUNT = child.port_count;
1378                    enumerate_hub_children(depth + 1);
1379                    // 自分 (親ハブ) の識別情報へ復元して残りのポートの列挙を続ける
1380                    HUB_ADDR = my_hub_addr;
1381                    HUB_EP0_MPS = my_hub_mps;
1382                    HUB_PORT_COUNT = my_port_count;
1383                }
1384                UsbDeviceKind::None => {}
1385            }
1386        } else {
1387            crate::warn!(
1388                "[USB]   Hub port {}: enumeration failed (addr {} consumed).",
1389                port,
1390                child_addr
1391            );
1392        }
1393
1394        // 親ハブ情報のクリア
1395        unsafe {
1396            CURRENT_HUB_PORT = 0;
1397            CURRENT_HUB_PORT_SPEED = 0;
1398        }
1399
1400        let _ = hub_clear_port_feature(port, HUB_FEATURE_C_PORT_CONNECTION);
1401        let _ = hub_clear_port_feature(port, HUB_FEATURE_C_PORT_RESET);
1402    }
1403
1404    crate::warn!(
1405        "[USB] Hub child enumeration completed. {} HID device(s) ready.",
1406        HID_DEVICE_COUNT.0
1407    );
1408}
1409
1410unsafe fn enumerate_root_device() {
1411    crate::info!("[USB] Starting USB Device Enumeration...");
1412
1413    if let Some(root) = enumerate_default_address_device(1, "Root Device") {
1414        NEXT_DEVICE_ADDR = 1;
1415        match root.kind {
1416            UsbDeviceKind::Hub => {
1417                HUB_PORT_COUNT = root.port_count;
1418                enumerate_hub_children(0);
1419            }
1420            UsbDeviceKind::Keyboard | UsbDeviceKind::Mouse | UsbDeviceKind::Tablet => {
1421                register_hid_device(root);
1422                crate::debug!("[USB] USB root HID enumeration completed.");
1423            }
1424            UsbDeviceKind::CdcEthernet => {
1425                crate::debug!("[USB] USB root Ethernet enumeration completed.");
1426            }
1427            UsbDeviceKind::None => {}
1428        }
1429    }
1430}
1431
1432unsafe fn handle_mouse_packet() {
1433    let btn = DMA_BUF.data[0];
1434    let dx = DMA_BUF.data[1];
1435    let dy = (-(DMA_BUF.data[2] as i8)) as u8;
1436
1437    let mut ps2_btn = 0x08;
1438    if (btn & 0x01) != 0 {
1439        ps2_btn |= 0x01;
1440    }
1441    if (btn & 0x02) != 0 {
1442        ps2_btn |= 0x02;
1443    }
1444    if (btn & 0x04) != 0 {
1445        ps2_btn |= 0x04;
1446    }
1447    if (dx as i8) < 0 {
1448        ps2_btn |= 0x10;
1449    }
1450    if (dy as i8) < 0 {
1451        ps2_btn |= 0x20;
1452    }
1453
1454    let _ = crate::kernel::interrupt::MOUSE_FIFO.lock().push(0xFE);
1455    let _ = crate::kernel::interrupt::MOUSE_FIFO
1456        .lock()
1457        .push(ps2_btn as u32);
1458    let _ = crate::kernel::interrupt::MOUSE_FIFO.lock().push(dx as u32);
1459    let _ = crate::kernel::interrupt::MOUSE_FIFO.lock().push(dy as u32);
1460}
1461
1462unsafe fn handle_tablet_packet(len: usize) {
1463    if len < 5 {
1464        return;
1465    }
1466
1467    let btn = DMA_BUF.data[0];
1468    let abs_x = (DMA_BUF.data[1] as u16) | ((DMA_BUF.data[2] as u16) << 8);
1469    let abs_y = (DMA_BUF.data[3] as u16) | ((DMA_BUF.data[4] as u16) << 8);
1470
1471    // 絶対座標イベントのシグネチャ: 0xFC
1472    // この後、btn, abs_x, abs_y, wheel を連続して送る
1473    let wheel = if len >= 6 { DMA_BUF.data[5] as i8 } else { 0 };
1474    let _ = crate::kernel::interrupt::MOUSE_FIFO.lock().push(0xFC);
1475    let _ = crate::kernel::interrupt::MOUSE_FIFO.lock().push(btn as u32);
1476    let _ = crate::kernel::interrupt::MOUSE_FIFO
1477        .lock()
1478        .push(abs_x as u32);
1479    let _ = crate::kernel::interrupt::MOUSE_FIFO
1480        .lock()
1481        .push(abs_y as u32);
1482    let _ = crate::kernel::interrupt::MOUSE_FIFO
1483        .lock()
1484        .push(wheel as u32);
1485}
1486
1487unsafe fn handle_keyboard_packet(device: &mut UsbHidDevice) {
1488    let modifier = DMA_BUF.data[0];
1489    let shift_pressed = (modifier & 0x22) != 0;
1490    let ctrl_pressed = (modifier & 0x11) != 0; // LCtrl (0x01) | RCtrl (0x10)
1491    let alt_pressed = (modifier & 0x44) != 0; // LAlt (0x04) | RAlt (0x40)
1492    let gui_pressed = (modifier & 0x88) != 0; // LGui (0x08) | RGui (0x80)
1493
1494    if shift_pressed != device.shift_pressed {
1495        device.shift_pressed = shift_pressed;
1496        let code = 0x2A;
1497        let p = if shift_pressed { code } else { code | 0x80 };
1498        let _ = crate::kernel::interrupt::KBD_FIFO.lock().push(p as u32);
1499    }
1500
1501    if ctrl_pressed != device.ctrl_pressed {
1502        device.ctrl_pressed = ctrl_pressed;
1503        let code = 0x1D; // LCtrl scan code
1504        let p = if ctrl_pressed { code } else { code | 0x80 };
1505        let _ = crate::kernel::interrupt::KBD_FIFO.lock().push(p as u32);
1506    }
1507
1508    if alt_pressed != device.alt_pressed {
1509        device.alt_pressed = alt_pressed;
1510        let code = 0x38; // LAlt scan code
1511        let p = if alt_pressed { code } else { code | 0x80 };
1512        let _ = crate::kernel::interrupt::KBD_FIFO.lock().push(p as u32);
1513    }
1514
1515    if gui_pressed != device.gui_pressed {
1516        device.gui_pressed = gui_pressed;
1517        let code = 0x5B; // LGui scan code
1518        let p = if gui_pressed { code } else { code | 0x80 };
1519        let _ = crate::kernel::interrupt::KBD_FIFO.lock().push(p as u32);
1520    }
1521
1522    for key_idx in 0..6 {
1523        let key = DMA_BUF.data[2 + key_idx];
1524        if key == 0 {
1525            continue;
1526        }
1527
1528        let mut is_new = true;
1529        for prev_idx in 0..6 {
1530            if device.key_prev_state[prev_idx] == key {
1531                is_new = false;
1532                break;
1533            }
1534        }
1535
1536        if is_new {
1537            if let Some(ps2_code) = hid_to_ps2(key) {
1538                let _ = crate::kernel::interrupt::KBD_FIFO
1539                    .lock()
1540                    .push(ps2_code as u32);
1541            }
1542        }
1543    }
1544
1545    for prev_idx in 0..6 {
1546        let prev_key = device.key_prev_state[prev_idx];
1547        if prev_key == 0 {
1548            continue;
1549        }
1550
1551        let mut is_released = true;
1552        for key_idx in 0..6 {
1553            if DMA_BUF.data[2 + key_idx] == prev_key {
1554                is_released = false;
1555                break;
1556            }
1557        }
1558
1559        if is_released {
1560            if let Some(ps2_code) = hid_to_ps2(prev_key) {
1561                let _ = crate::kernel::interrupt::KBD_FIFO
1562                    .lock()
1563                    .push((ps2_code | 0x80) as u32);
1564            }
1565        }
1566    }
1567
1568    for idx in 0..6 {
1569        device.key_prev_state[idx] = DMA_BUF.data[2 + idx];
1570    }
1571}
1572
1573/// ホストチャネルを使った1つのUSB転送(トランザクション)の発行
1574/// ch: チャネル番号, ep: エンドポイント, dev_addr: デバイスアドレス, pid: PID(0=DATA0, 2=DATA1, 3=SETUP), dir_in: 転送方向(true=IN, false=OUT), len: 転送サイズ
1575unsafe fn usb_transfer(
1576    ch: usize,
1577    ep: u8,
1578    dev_addr: u8,
1579    ep_type: u8,
1580    pid: u32,
1581    dir_in: bool,
1582    buffer_phys: u32,
1583    len: u32,
1584    mps: u16,
1585    timeout_val: u32,
1586) -> Result<u32, ()> {
1587    // キャッシュ一貫性の確保 (DMA Buffer)
1588    if !dir_in || pid == 3 {
1589        if len > 0 {
1590            crate::kernel::mmu::clean_dcache_range(buffer_phys as usize, len as usize);
1591        } else if pid == 3 {
1592            crate::kernel::mmu::clean_dcache_range(buffer_phys as usize, 8); // SETUPは常に8バイト
1593        }
1594    } else if dir_in && len > 0 {
1595        crate::kernel::mmu::invalidate_dcache_range(buffer_phys as usize, len as usize);
1596    }
1597
1598    // スプリット転送が必要か判定:
1599    // ルートがHSで、対象デバイスがハブ経由かつ HS (2) ではない場合。
1600    // 親ハブはデバイスごとに DEV_HUB_ADDRS で追跡する (ネストハブ対応)。
1601    let is_split = unsafe {
1602        DEV_SPEED == 0 && (
1603            (dev_addr == 0 && HUB_ADDR > 0 && CURRENT_HUB_PORT > 0 && CURRENT_HUB_PORT_SPEED != 2) ||
1604            (dev_addr > 0 && DEV_HUB_ADDRS[dev_addr as usize] > 0 && DEV_SPEEDS[dev_addr as usize] != 2)
1605        )
1606    };
1607
1608    if !is_split {
1609        // 0. HCSPLT をクリア(非スプリット転送)。
1610        core::ptr::write_volatile(hc_splt(ch), 0);
1611
1612        // 1. チャネル割り込みのクリア + マスク設定
1613        core::ptr::write_volatile(hc_int(ch), 0x7FF);
1614        core::ptr::write_volatile(hc_intmsk(ch), 0x7FF);
1615        core::ptr::write_volatile(HAINTMSK, 0xFFFF);
1616
1617        // 2. 転送サイズとPID、パケット数の設定
1618        let packet_count = if len == 0 {
1619            1
1620        } else {
1621            len.div_ceil(mps as u32)
1622        };
1623        let mut tsiz = len & 0x7FFFF;
1624        tsiz |= packet_count << 19;
1625        tsiz |= pid << 29; // PID (0: DATA0, 2: DATA1, 3: SETUP)
1626        core::ptr::write_volatile(hc_tsiz(ch), tsiz);
1627
1628        // 3. DMAアドレスを設定
1629        let bus_addr = buffer_phys | 0xC0000000;
1630        core::ptr::write_volatile(hc_dma(ch), bus_addr);
1631
1632        // 4. チャネル特性の設定 & 転送開始
1633        let mut hcchar = mps as u32 & 0x7FF; // MaxPacketSize (Bits 10:0)
1634        hcchar |= (ep as u32 & 0xF) << 11; // EPNum (Bits 14:11)
1635        if dir_in {
1636            hcchar |= 1 << 15; // EPDir = IN (Bit 15)
1637        }
1638        if DEV_SPEED == 2 {
1639            hcchar |= 1 << 17; // LSPDev = Low-Speed (Bit 17)
1640        }
1641        hcchar |= (ep_type as u32 & 0x3) << 18; // EPType (Bits 19:18)
1642        hcchar |= 1 << 20; // MULTI_CNT = 1
1643        hcchar |= (dev_addr as u32 & 0x7F) << 22; // DevAddr (Bits 28:22)
1644        // OddFrame (bit29): Circle reads HFNUM and sets this even for bulk.
1645        // Real BCM2837 DWC2 requires it for correct frame scheduling.
1646        if (core::ptr::read_volatile(HFNUM) & 1) != 0 {
1647            hcchar |= 1 << 29; // OddFrame
1648        }
1649        hcchar |= 1 << 31; // ChEna = Channel Enable (Bit 31)
1650
1651        core::ptr::write_volatile(hc_char(ch), hcchar);
1652
1653        // メモリバリア
1654        core::arch::asm!("dsb sy", "isb", options(nostack));
1655
1656        // 5. ポーリングで待機
1657        let start_time = crate::kernel::timer::get_system_time_us();
1658        let timeout_us = timeout_val as u64;
1659        loop {
1660            core::arch::asm!("dsb sy", options(nostack));
1661            let hctrans = core::ptr::read_volatile(hc_char(ch));
1662            if (hctrans & (1 << 31)) == 0 {
1663                core::arch::asm!("dsb sy", options(nostack));
1664                let interrupts = core::ptr::read_volatile(hc_int(ch));
1665                if interrupts == 0 {
1666                    // DWC2 on real HW (Pi 4) may clear ChEna slightly before setting HCINT.
1667                    // If no interrupt reason is posted yet, check timeout and break out if needed.
1668                    if crate::kernel::timer::get_system_time_us().wrapping_sub(start_time) > timeout_us {
1669                        crate::warn!("[USB] ch{} TIMEOUT while waiting for HCINT to populate", ch);
1670                        return Err(());
1671                    }
1672                    continue;
1673                }
1674                if (interrupts & (1 << 0)) != 0 {
1675                    // XferCompl
1676                    let actual_size = len - (core::ptr::read_volatile(hc_tsiz(ch)) & 0x7FFFF);
1677                    if dir_in && actual_size > 0 {
1678                        crate::kernel::mmu::invalidate_dcache_range(
1679                            buffer_phys as usize,
1680                            actual_size as usize,
1681                        );
1682                    }
1683                    return Ok(actual_size);
1684                }
1685                if (interrupts & (1 << 1)) != 0 {
1686                    // ChHltd
1687                    let ints2 = core::ptr::read_volatile(hc_int(ch));
1688                    if (ints2 & (1 << 0)) != 0 {
1689                        let actual_size = len - (core::ptr::read_volatile(hc_tsiz(ch)) & 0x7FFFF);
1690                        if dir_in && actual_size > 0 {
1691                            crate::kernel::mmu::invalidate_dcache_range(
1692                                buffer_phys as usize,
1693                                actual_size as usize,
1694                            );
1695                        }
1696                        return Ok(actual_size);
1697                    }
1698                    if (ints2 & (1 << 4)) == 0 {
1699                        // STALL (bit 3) は正常なプロトコル拒否応答であり、警告ログを出さず debug! にします
1700                        if (ints2 & (1 << 3)) != 0 {
1701                            crate::debug!(
1702                                "[USB]     Transfer STALL (hc_int=0x{:03X} is_split={} dir_in={} ep={} len={} dev_addr={})",
1703                                ints2,
1704                                is_split,
1705                                dir_in as u8,
1706                                ep,
1707                                len,
1708                                dev_addr
1709                            );
1710                        } else {
1711                            crate::warn!(
1712                                "[USB]     Transfer failed: Channel Halted (hc_int=0x{:03X} is_split={} dir_in={} ep={} len={} dev_addr={})",
1713                                ints2,
1714                                is_split,
1715                                dir_in as u8,
1716                                ep,
1717                                len,
1718                                dev_addr
1719                            );
1720                        }
1721                    }
1722                    return Err(());
1723                }
1724                if (interrupts & (1 << 2)) != 0 {
1725                    // AHBErr (bit2) - AHB DMA read/write error
1726                    crate::warn!("[USB] ch{} AHB Error (hcint=0x{:03X})", ch, interrupts);
1727                    return Err(());
1728                }
1729                if (interrupts & (1 << 3)) != 0 {
1730                    // STALL (bit3) - device returned STALL
1731                    crate::warn!("[USB] ch{} STALL (hcint=0x{:03X})", ch, interrupts);
1732                    return Err(());
1733                }
1734                if (interrupts & (1 << 4)) != 0 {
1735                    // NAK
1736                    return Err(());
1737                }
1738                // ChEna cleared but no recognized completion/error bits.
1739                // Log at warn for real-HW diagnostics (HCINT=0 case).
1740                crate::warn!(
1741                    "[USB] ch{} unexpected halt: hcint=0x{:03X} dir_in={} ep={} len={}",
1742                    ch, interrupts, dir_in as u8, ep, len
1743                );
1744                return Err(());
1745            }
1746
1747            if crate::kernel::timer::get_system_time_us().wrapping_sub(start_time) > timeout_us {
1748                // Request channel halt (Circle: always wait for ChHltd after ChDis)
1749                let mut char_val = core::ptr::read_volatile(hc_char(ch));
1750                char_val |= 1 << 30; // ChDis
1751                char_val |= 1 << 31; // ChEna (required to let ChDis take effect)
1752                core::ptr::write_volatile(hc_char(ch), char_val);
1753                // Wait up to 1ms for channel to actually halt before returning,
1754                // so next transfer on same channel starts clean.
1755                let halt_start = crate::kernel::timer::get_system_time_us();
1756                loop {
1757                    core::arch::asm!("dsb sy", options(nostack));
1758                    if (core::ptr::read_volatile(hc_char(ch)) & (1 << 31)) == 0 {
1759                        break;
1760                    }
1761                    if crate::kernel::timer::get_system_time_us().wrapping_sub(halt_start)
1762                        > 1_000
1763                    {
1764                        break;
1765                    }
1766                }
1767                let final_hcint = core::ptr::read_volatile(hc_int(ch));
1768                let final_hcchar = core::ptr::read_volatile(hc_char(ch));
1769                let chdis_ok = (final_hcchar & (1 << 31)) == 0;
1770                let final_gnptxsts = core::ptr::read_volatile(GNPTXSTS);
1771                let final_gintsts = core::ptr::read_volatile(GINTSTS);
1772                crate::warn!(
1773                    "[USB] ch{} TIMEOUT: hcint=0x{:03X} hcchar=0x{:08X} chdis_ok={} gnptx=0x{:08X} gintsts=0x{:08X}",
1774                    ch, final_hcint, final_hcchar, chdis_ok, final_gnptxsts, final_gintsts
1775                );
1776                return Err(());
1777            }
1778        }
1779    } else {
1780        // --- スプリット転送 ---
1781        // 宛先は必ず TT を持つ直近の HS ハブでなければならない。デバイスごとに記録した
1782        // 直接の親ハブから、非 HS ハブを飛ばして直近の HS ハブまで辿る (resolve_split_target)。
1783        let (hub_addr, port_addr) = unsafe {
1784            let (direct_hub_addr, direct_port) = if dev_addr > 0 {
1785                (
1786                    DEV_HUB_ADDRS[dev_addr as usize],
1787                    DEV_HUB_PORTS[dev_addr as usize],
1788                )
1789            } else {
1790                (HUB_ADDR, CURRENT_HUB_PORT)
1791            };
1792            resolve_split_target(direct_hub_addr, direct_port)
1793        };
1794
1795        let is_periodic = ep_type == 3;
1796        let mut sched = if is_periodic {
1797            frame_sched::FrameScheduler::new_periodic()
1798        } else {
1799            frame_sched::FrameScheduler::new_non_periodic()
1800        };
1801
1802        sched.start_split();
1803
1804        let start_time = crate::kernel::timer::get_system_time_us();
1805        // スプリット転送時はハブの下流応答待ちによる NYET リトライが多発するため、
1806        // タイムアウトを最小 1,000,000us (1秒) に引き上げるが、
1807        // Periodic (Interrupt) ポーリングでアイドル時に毎回1秒ブロックしないよう短く切る。
1808        let timeout_us = if is_periodic {
1809            (timeout_val as u64).min(5_000) // 5ms で打ち切り
1810        } else {
1811            (timeout_val as u64).max(1_000_000)
1812        };
1813
1814        loop {
1815            if crate::kernel::timer::get_system_time_us().wrapping_sub(start_time) > timeout_us {
1816                let mut char_val = core::ptr::read_volatile(hc_char(ch));
1817                char_val |= 1 << 30; // ChDis
1818                char_val |= 1 << 31; // ChEna
1819                core::ptr::write_volatile(hc_char(ch), char_val);
1820                let halt_start = crate::kernel::timer::get_system_time_us();
1821                loop {
1822                    core::arch::asm!("dsb sy", options(nostack));
1823                    if (core::ptr::read_volatile(hc_char(ch)) & (1 << 31)) == 0 {
1824                        break;
1825                    }
1826                    if crate::kernel::timer::get_system_time_us().wrapping_sub(halt_start)
1827                        > 1_000
1828                    {
1829                        break;
1830                    }
1831                }
1832                if !is_periodic {
1833                    crate::warn!(
1834                        "[USB] ch{} split TIMEOUT: hcint=0x{:03X} dir_in={} ep={} dev_addr={} hub_addr={} port={} state={:?} nak_restarts={}",
1835                        ch,
1836                        core::ptr::read_volatile(hc_int(ch)),
1837                        dir_in as u8,
1838                        ep,
1839                        dev_addr,
1840                        hub_addr,
1841                        port_addr,
1842                        sched.state,
1843                        sched.nak_restarts
1844                    );
1845                    return Err(());
1846                } else {
1847                    let hcint = core::ptr::read_volatile(hc_int(ch));
1848                    if (hcint & 0x050) == 0 { // NAK (0x010) と NYET (0x040) 以外ならバスエラー等なので警告
1849                        crate::warn!("[USB] ch{} Periodic split TIMEOUT with error: hcint=0x{:03X} state={:?}", ch, hcint, sched.state);
1850                    }
1851                    return Ok(0); // 割り込み転送のタイムアウトは「データなし(NAK)」と同義
1852                }
1853            }
1854
1855            let is_csplit = sched.complete_split();
1856
1857            // 1. HCSPLT の設定
1858            let mut splt = 1 << 31; // SPLTENA
1859            if is_csplit {
1860                splt |= 1 << 16; // COMPSPLT
1861            }
1862            splt |= 3 << 14; // XACTPOS = All
1863            splt |= ((hub_addr as u32) & 0x7F) << 7;
1864            splt |= (port_addr as u32) & 0x7F;
1865            core::ptr::write_volatile(hc_splt(ch), splt);
1866
1867            // 2. 割り込みクリア
1868            core::ptr::write_volatile(hc_int(ch), 0x7FF);
1869            core::ptr::write_volatile(hc_intmsk(ch), 0x7FF);
1870            core::ptr::write_volatile(HAINTMSK, 0xFFFF);
1871
1872            // 3. 転送サイズとDMAアドレスの設定
1873            let packet_count = if len == 0 {
1874                1
1875            } else {
1876                len.div_ceil(mps as u32)
1877            };
1878            let mut tsiz = len & 0x7FFFF;
1879            tsiz |= packet_count << 19;
1880            tsiz |= pid << 29;
1881            core::ptr::write_volatile(hc_tsiz(ch), tsiz);
1882
1883            let bus_addr = buffer_phys | 0xC0000000;
1884            core::ptr::write_volatile(hc_dma(ch), bus_addr);
1885
1886            // 4. フレーム待機 (マイクロフレーム同期)
1887            sched.wait_for_frame();
1888
1889            // 5. チャネル特性の設定と開始
1890            let mut hcchar = mps as u32 & 0x7FF;
1891            hcchar |= (ep as u32 & 0xF) << 11;
1892            if dir_in {
1893                hcchar |= 1 << 15;
1894            }
1895            // スプリット転送時は AXI バス上の通信は常にハブの速度(HS)となるため、
1896            // LSPDev (bit 17) は設定してはなりません (常に0)。
1897            hcchar |= (ep_type as u32 & 0x3) << 18;
1898            if sched.is_odd_frame() {
1899                hcchar |= 1 << 29; // OddFrame
1900            }
1901            hcchar |= 1 << 20; // MULTI_CNT = 1
1902            hcchar |= (dev_addr as u32 & 0x7F) << 22;
1903            hcchar |= 1 << 31; // ChEna
1904
1905            core::ptr::write_volatile(hc_char(ch), hcchar);
1906
1907            // メモリバリア
1908            core::arch::asm!("dsb sy", "isb", options(nostack));
1909
1910            // 6. ポーリング完了待ち (スプリット1回分)
1911            let trans_start = crate::kernel::timer::get_system_time_us();
1912            let mut interrupts = 0;
1913            loop {
1914                core::arch::asm!("dsb sy", options(nostack));
1915                let hctrans = core::ptr::read_volatile(hc_char(ch));
1916                if (hctrans & (1 << 31)) == 0 {
1917                    interrupts = core::ptr::read_volatile(hc_int(ch));
1918                    if interrupts != 0 {
1919                        break;
1920                    }
1921                }
1922                if crate::kernel::timer::get_system_time_us().wrapping_sub(trans_start) > 50000 {
1923                    break; // 50ms タイムアウト
1924                }
1925            }
1926
1927            // スケジューラに状態通知
1928            sched.transaction_complete(interrupts);
1929
1930            if sched.is_complete() {
1931                let actual_size = len - (core::ptr::read_volatile(hc_tsiz(ch)) & 0x7FFFF);
1932                if dir_in && actual_size > 0 {
1933                    crate::kernel::mmu::invalidate_dcache_range(
1934                        buffer_phys as usize,
1935                        actual_size as usize,
1936                    );
1937                }
1938                return Ok(actual_size);
1939            }
1940
1941            if sched.is_failed() {
1942                if !is_periodic {
1943                    crate::warn!(
1944                        "[USB] ch{} split transaction failed: status=0x{:03X} state={:?} ep={} dev_addr={} hub_addr={} port={} mps={} dir_in={} nak_restarts={}",
1945                        ch,
1946                        interrupts,
1947                        sched.state,
1948                        ep,
1949                        dev_addr,
1950                        hub_addr,
1951                        port_addr,
1952                        mps,
1953                        dir_in as u8,
1954                        sched.nak_restarts
1955                    );
1956                    return Err(());
1957                } else {
1958                    if (interrupts & 0x050) == 0 {
1959                        crate::warn!("[USB] ch{} Periodic split failed with error: hcint=0x{:03X} state={:?}", ch, interrupts, sched.state);
1960                    }
1961                    return Ok(0); // データなしとして扱う
1962                }
1963            }
1964
1965            // Periodic転送の場合、遅延を入れるとマイクロフレーム同期が崩れてTTにデータを破棄されるため待機しない
1966            if !is_periodic {
1967                delay_ms(1);
1968            }
1969        }
1970    }
1971}
1972
1973/// USBコントロール転送の実行 (SETUP, DATA, STATUSの3ステージ)
1974unsafe fn usb_control_transfer(
1975    request: UsbSetupPacket,
1976    data_buf_phys: u32,
1977    data_len: u32,
1978    dir_in: bool,
1979) -> Result<u32, ()> {
1980    // Packed構造体のフィールドアライメント問題を避けるため、一旦ローカル変数にコピー
1981    let req_type = request.request_type;
1982    let req_code = request.request;
1983    let req_value = request.value;
1984    let req_index = request.index;
1985    let req_length = request.length;
1986
1987    // 1. SETUPバッファの構築
1988    let setup_ptr = &request as *const UsbSetupPacket as *const u8;
1989    for i in 0..8 {
1990        SETUP_BUF.data[i] = core::ptr::read(setup_ptr.add(i));
1991    }
1992
1993    // コントロール転送は SETUP/DATA/STATUS が一体のトランザクション。DATA ステージ
1994    // だけを再試行しても、デバイス側の EP0 状態機械が SETUP 待ちに戻っている場合は
1995    // 永遠に NAK され続ける (実機のハブ配下 FS デバイスで観測)。そのため DATA 失敗時
1996    // は SETUP からやり直す (SETUP は EP0 状態を無条件にリセットする)。
1997    let mut outer = 3;
1998    let mut actual_len;
1999    'transfer: loop {
2000        // 2. SETUPステージ
2001        // ch=0, ep=0, dev_addr=DEV_ADDR, pid=3(SETUP), dir=OUT
2002        let mut retry = 3;
2003        while retry > 0 {
2004            let setup_phys = &SETUP_BUF as *const DmaBuffer as u32;
2005            if usb_transfer(0, 0, DEV_ADDR, 0, 3, false, setup_phys, 8, EP0_MPS, 200000).is_ok() {
2006                break;
2007            }
2008            retry -= 1;
2009            delay_ms(5);
2010        }
2011        if retry == 0 {
2012            crate::warn!(
2013                "[USB] SETUP stage failed: req_type=0x{:02X} req=0x{:02X} val=0x{:04X} idx=0x{:04X} len={} dev_addr={}",
2014                req_type,
2015                req_code,
2016                req_value,
2017                req_index,
2018                req_length,
2019                DEV_ADDR
2020            );
2021            return Err(());
2022        }
2023
2024        // 3. DATAステージ (データがある場合のみ)
2025        actual_len = 0;
2026        if data_len > 0 {
2027            let mut retry = 7;
2028            let mut success = false;
2029            while retry > 0 {
2030                // コントロール転送のデータステージは常に DATA1 から開始
2031                if usb_transfer(
2032                    0,
2033                    0,
2034                    DEV_ADDR,
2035                    0,
2036                    2,
2037                    dir_in,
2038                    data_buf_phys,
2039                    data_len,
2040                    EP0_MPS,
2041                    200000,
2042                )
2043                .is_ok()
2044                {
2045                    if dir_in {
2046                        actual_len = data_len;
2047                    }
2048                    success = true;
2049                    break;
2050                }
2051                retry -= 1;
2052                delay_ms(5);
2053            }
2054            if !success {
2055                outer -= 1;
2056                if outer == 0 {
2057                    crate::warn!(
2058                        "[USB] DATA stage failed: req_type=0x{:02X} req=0x{:02X} val=0x{:04X} idx=0x{:04X} len={} dev_addr={}",
2059                        req_type,
2060                        req_code,
2061                        req_value,
2062                        req_index,
2063                        req_length,
2064                        DEV_ADDR
2065                    );
2066                    return Err(());
2067                }
2068                crate::warn!(
2069                    "[USB] DATA stage failed; restarting control transfer from SETUP (remaining {})",
2070                    outer
2071                );
2072                delay_ms(10);
2073                continue 'transfer;
2074            }
2075        }
2076        break 'transfer;
2077    }
2078
2079    // 4. STATUSステージ (応答)
2080    // 送信ならIN、受信ならOUTで0バイトのステータス確認パケットを送受信
2081    // ステータスステージのPIDは常に DATA1
2082    let status_phys = &SETUP_BUF as *const DmaBuffer as u32; // 空バッファを指定
2083    let mut retry = 100; // QEMU/実機での状態遷移中NAKを考慮し5から100に大幅拡張 (最大500ms)
2084    let mut success = false;
2085    while retry > 0 {
2086        if usb_transfer(
2087            0,
2088            0,
2089            DEV_ADDR,
2090            0,
2091            2,
2092            !dir_in,
2093            status_phys,
2094            0,
2095            EP0_MPS,
2096            200000,
2097        )
2098        .is_ok()
2099        {
2100            success = true;
2101            break;
2102        }
2103        retry -= 1;
2104        delay_ms(5);
2105    }
2106    if !success {
2107        crate::warn!(
2108            "[USB] STATUS stage failed: req_type=0x{:02X} req=0x{:02X} val=0x{:04X} idx=0x{:04X} len={} dev_addr={}",
2109            req_type,
2110            req_code,
2111            req_value,
2112            req_index,
2113            req_length,
2114            DEV_ADDR
2115        );
2116        return Err(());
2117    }
2118
2119    Ok(actual_len)
2120}
2121
2122static mut POLL_DIVIDER: u32 = 0;
2123
2124/// 定期的にUSBデバイスをポーリングし、入力パケットを INPUT_FIFO に転送します
2125/// この関数は main.rs のループ内で毎フレーム実行されます
2126pub fn poll() {
2127    unsafe {
2128        let _lock = USB_LOCK.lock();
2129        HID_POLL_CALLS.fetch_add(1, core::sync::atomic::Ordering::Relaxed);
2130        // 【2026-08-05】ここにあった `poll_usb_ethernet_data_plane()` を外した。
2131        //
2132        // ## 外す前の実測(3.7MB JPEG 取得中、fetch=4244tick=42.4秒)
2133        //
2134        // ```text
2135        // hid_eth_us=18641424  ← Core 1 がここで 18.6 秒(全体の 44%)
2136        // eth_us=2724875       ← Core 2 の専用スレッドは 2.7 秒だけ
2137        // hid_us=0             ← HID 転送そのものは無視できる
2138        // ```
2139        //
2140        // Ethernet 収穫は 2 コアから同じ `USB_LOCK` の下で行われており、
2141        // **本来 HID 担当の Core 1 が受信の 87% を担っていた**。
2142        // しかも Core 1 は収穫中ずっとロックを握るので、
2143        // 専用スレッド(Core 2)の `try_lock` が 41% 失敗し、
2144        // そのたびに受信の番が 100ms 飛んでいた。
2145        //
2146        // ## 一本化を試したが**明確に悪化したので戻した**
2147        //
2148        // 「Core 1 から外し、Core 2 の間隔を `yield_now` まで詰める」を試した結果、
2149        // 3.7MB の画像が **200 秒待っても完了しなくなった**
2150        // (それまでは 42 秒。1 ブート内の取得数も 13 → 10 に減った)。
2151        //
2152        // Core 2 には画像取得ワーカー等も載るため、`net_service_thread` が
2153        // `yield_now` で譲ると受信の番が安定して回ってこない。
2154        // 一方 Core 1 の `poll()` はスリープ無しの専用ループで、
2155        // **結果的にこれが最も安定した受信ドライバになっている**。
2156        // 見た目の役割分担(HID 担当)と実際の役割が食い違っているが、
2157        // 動いている構造を崩してはいけない。
2158        //
2159        // 受信を速くするなら、担当を移すのではなく
2160        // **1 フレームあたり 1.4ms かかっている中身**を削ること。
2161        let t_eth1 = crate::kernel::timer::get_system_time_us();
2162        poll_usb_ethernet_data_plane();
2163        HID_ETH_US.fetch_add(
2164            crate::kernel::timer::get_system_time_us().wrapping_sub(t_eth1) as u32,
2165            core::sync::atomic::Ordering::Relaxed,
2166        );
2167        // 【2026-08-05 計測】ここから下の HID 転送が
2168        // `USB_LOCK` をどれだけ握り続けるかを測る。
2169        // Core 2 の受信は try_lock なので、ここが長いと 41% の取りこぼしになる。
2170        let t_hid = crate::kernel::timer::get_system_time_us();
2171
2172        // キャッシュの無効化 (Core 1 が物理メモリから最新値をロードするように強制)
2173        let count_addr = &HID_DEVICE_COUNT.0 as *const usize as usize;
2174        crate::kernel::mmu::invalidate_dcache_range(count_addr, core::mem::size_of_val(&HID_DEVICE_COUNT.0));
2175        let devices_addr = HID_DEVICES.0.as_ptr() as usize;
2176        crate::kernel::mmu::invalidate_dcache_range(devices_addr, core::mem::size_of_val(&HID_DEVICES.0));
2177        core::arch::asm!("dsb sy", "isb", options(nostack));
2178
2179        if HID_DEVICE_COUNT.0 == 0 {
2180            return; // デバイスが未初期化の場合は何もしない
2181        }
2182
2183        // チャネル1を割り当てて、インタラプト転送を実行
2184        let buf_phys = &DMA_BUF as *const DmaBuffer as u32;
2185
2186        for idx in 0..HID_DEVICE_COUNT.0 {
2187            let device = &mut HID_DEVICES.0[idx];
2188            if device.address == 0 || device.hid_ep == 0 {
2189                continue;
2190            }
2191
2192            // DATA toggle 管理: USB仕様では Interrupt IN は DATA0/DATA1 を交互に送る必要がある。
2193            // QEMUではトグルを無視しても動作するが、実機ではNAK/STALLの原因となる。
2194            let pid = device.data_toggle;
2195            let res = usb_transfer(
2196                1,
2197                device.hid_ep,
2198                device.address,
2199                3,
2200                pid,
2201                true,
2202                buf_phys,
2203                device.hid_ep_size as u32,
2204                device.hid_ep_size,
2205                200000,
2206            );
2207
2208            if let Ok(len) = res {
2209                let recv_len = len as usize;
2210                if recv_len == 0 {
2211                    // NAK(データなし): トグルは進めない
2212                    continue;
2213                }
2214                // 受信成功: トグルを反転 (DATA0=0 <-> DATA1=2)
2215                device.data_toggle = if pid == 0 { 2 } else { 0 };
2216
2217                match device.kind {
2218                    UsbDeviceKind::Mouse => handle_mouse_packet(),
2219                    UsbDeviceKind::Tablet => handle_tablet_packet(len as usize),
2220                    UsbDeviceKind::Keyboard => handle_keyboard_packet(device),
2221                    _ => {}
2222                }
2223            }
2224        }
2225        HID_POLL_US.fetch_add(
2226            crate::kernel::timer::get_system_time_us().wrapping_sub(t_hid) as u32,
2227            core::sync::atomic::Ordering::Relaxed,
2228        );
2229    }
2230}
2231
2232/// 【2026-08-05 診断】Core 1 の `poll()` が回った回数。
2233pub static HID_POLL_CALLS: core::sync::atomic::AtomicU32 =
2234    core::sync::atomic::AtomicU32::new(0);
2235/// そのうち HID 転送に費やしたマイクロ秒の累計(`USB_LOCK` を握ったまま)。
2236pub static HID_POLL_US: core::sync::atomic::AtomicU32 =
2237    core::sync::atomic::AtomicU32::new(0);
2238/// Core 1 の `poll()` が Ethernet 収穫に費やしたマイクロ秒の累計。
2239pub static HID_ETH_US: core::sync::atomic::AtomicU32 =
2240    core::sync::atomic::AtomicU32::new(0);
2241
2242// 【2026-08-05】収穫 1 回の内訳計装は目的を果たしたので撤去した(L-4)。
2243// 得られた事実(3.7MB 取得中、約 14000 フレーム):
2244//   sec_frame_us  … フレーム処理。開始時 832µs/枚 → 修正後 75〜165µs/枚
2245//   sec_arm_us    … 再アーム 約 1.2 秒
2246//   sec_inv_us    … dcache 無効化 約 0.1 秒(軽い)
2247//   rndis_extra   … 1 転送に 2 個目以降のメッセージ = **0 件**
2248// 計装自体が `get_system_time_us`(除算を含む)をフレームごとに
2249// 2 回呼ぶため、熱経路に残してはいけない(U-5)。
2250pub static mut POLL_THREAD_ACTIVE: bool = false;
2251
2252/// # 実測(2026-08-05、sugi-lab.net の 3.7MB JPEG 取得中)
2253///
2254/// ```text
2255/// fetch=4631tick  eth_calls=311  eth_ticks=282  eth_lockmiss=219
2256/// ```
2257///
2258/// - **この関数の内側で使っている時間は取得時間の 6%**(282/4631)。
2259///   受信処理そのものは重くない。
2260/// - 呼び出しが成立したのは 46 秒間で 311 回(≒150ms に 1 回)。
2261///   `net_service_thread` の `sleep(10)`(100ms)より疎い。
2262/// - 差の原因は `USB_LOCK` で、**試行 530 回中 219 回(41%)が
2263///   ロックを取れずに諦めている**(Core 1 の HID ポーリングと競合)。
2264///
2265/// つまり律速は「受信処理の重さ」でも「眠る間隔」でもなく、
2266/// **ロック競合で受信の番が回ってこないこと**。
2267///
2268/// 計算量: 1 回の呼び出しは **O(F)**(F は回収フレーム数、上限 8)。
2269pub fn poll_ethernet_data_plane_only() {
2270    // [修正] マルチコア環境でのデータ競合(USBレジスタやDMA_BUFへの複数コア同時アクセス)を防ぐため、
2271    // USBポーリングスレッドが稼働している Core 2 以外からの直接ポーリングを禁止する。
2272    // Core 2 以外は yield_now() で待機していれば、Core 2 が裏で受信パケットを処理してキューに積んでくれる。
2273    //
2274    // 【2026-07-25 補足】この関数名から`usb_poll_thread`(Core 1、HID専用)が
2275    // 呼んでいるように誤解しやすいが、実際にこの関数を毎ループ呼んでいるのは
2276    // `net_service_thread`(`main.rs`の`spawn_on_core(net_service_thread, ..., 2)`
2277    // によりCore 2固定)である。`core_id() != 2`のガードはこの`net_service_thread`
2278    // と正しく整合しており、意図通り動作している(spec/TODO.md 2026-07-24/25の
2279    // 調査で一度「バグ候補」として疑い、検証の上「問題なし」と確定済み)。
2280    if crate::kernel::scheduler::core_id() != 2 {
2281        return;
2282    }
2283    unsafe {
2284        // 【2026-07-30】DWC2 の共有レジスタ・DMA バッファ・`RX_IN_FLIGHT` 等の
2285        // `static mut` は Core 1(HID: `poll()`)と Core 2(本経路)の両方から
2286        // 触られる。`poll()` 側は `USB_LOCK` を取っていたが**こちらは取っておらず**、
2287        // 排他なしで同じレジスタを同時操作していた。
2288        // 受信が不安定になる典型なので同じロックで保護する。
2289        //
2290        // ただし**ブロックする `lock()` は使わない**。実測で、ネットワーク側が
2291        // ロックを保持し続けると Core 1 の `poll()`(HID/GUI)が待たされ、
2292        // 画面が「Loading Secure Page...」のまま更新されなくなった。
2293        // ネットワーク取得は 5/5 成功しているのに描画が止まる、という
2294        // 分かりにくい回帰になる。
2295        // 取得できなければこの回は諦める(次のポーリングで再試行される)。
2296        // 【2026-08-05】以前は 1 回 `try_lock` して駄目なら即 `return` していた。
2297        //
2298        // 呼び元(`net_service_thread`)は戻ると 100ms 眠るので、
2299        // **取りこぼし 1 回につき受信の番が 100ms 飛ぶ**。
2300        // 実測ではこれが試行の 41%(530 回中 219 回)に達していた。
2301        //
2302        // ## 粘って取りに行く案は**効果を示せなかったので入れていない**
2303        //
2304        // 「8 回まで `yield_now` しながら `try_lock` を繰り返す」を試すと、
2305        // 取りこぼしは 210 → 5 まで減った。ところが取得時間は改善せず、
2306        // 別の回では取りこぼしが 119 に戻り取得も遅くなった。
2307        //
2308        // ```text
2309        // 変更前: fetch = 3685 / 3746 / 4273 / 4296 / 4631 tick(平均 4126)
2310        // 変更後: fetch = 3598 / 4244 / 5879 tick(平均 4574)
2311        // ```
2312        //
2313        // 取りこぼしを潰しても速くならないのは、受信の 87% を
2314        // Core 1 の `poll()` が担っており、こちらの寄与が元々小さいから。
2315        // 根拠の無い複雑さは入れない。
2316        let Some(_lock) = USB_LOCK.try_lock() else {
2317            ETH_POLL_LOCK_MISS.fetch_add(1, core::sync::atomic::Ordering::Relaxed);
2318            return;
2319        };
2320        // 【2026-08-05 計測】取得の律速がこの関数の内側かどうかを決める。
2321        // 内側の実時間が取得時間に比べて小さければ、律速は「呼ばれる回数」側。
2322        // 目的: 受信律速の特定。破棄条件: 特定でき次第削除。
2323        // tick(10ms 刻み)では 1 回数 ms の処理を測れない。
2324        // 毎回 0 と数えられて合計しても出てこないため、
2325        // CNTPCT 由来のマイクロ秒(`get_system_time_us`)で測る。
2326        let t0 = crate::kernel::timer::get_system_time_us();
2327        ETH_POLL_CALLS.fetch_add(1, core::sync::atomic::Ordering::Relaxed);
2328        poll_usb_ethernet_data_plane();
2329        ETH_POLL_US.fetch_add(
2330            crate::kernel::timer::get_system_time_us().wrapping_sub(t0) as u32,
2331            core::sync::atomic::Ordering::Relaxed,
2332        );
2333    }
2334}
2335
2336/// 【2026-07-29診断】USB Ethernet が受信したフレーム総数。
2337/// 「1 回目は成功するが 2 回目以降が失敗する」件で、
2338/// フレームがそもそも届いていないのかを切り分けるために数える。
2339/// 転送中のままポーリングした回数。上限を超えたら強制再アームする。
2340static mut RX_IN_FLIGHT_POLLS: u32 = 0;
2341
2342/// 【2026-08-05 診断】`poll_ethernet_data_plane_only` が実際に働いた回数。
2343pub static ETH_POLL_CALLS: core::sync::atomic::AtomicU32 =
2344    core::sync::atomic::AtomicU32::new(0);
2345/// その内側で費やしたマイクロ秒の累計。取得時間と比べて律速の在り処を決める。
2346pub static ETH_POLL_US: core::sync::atomic::AtomicU32 =
2347    core::sync::atomic::AtomicU32::new(0);
2348/// `USB_LOCK` が取れずに諦めた回数。HID 側と競っているかを見る。
2349pub static ETH_POLL_LOCK_MISS: core::sync::atomic::AtomicU32 =
2350    core::sync::atomic::AtomicU32::new(0);
2351
2352/// 【2026-08-05 診断】USB 送信(イーサネットフレーム)の成否。
2353///
2354/// `送信再送` が 36 回の送信に対し 44〜48 回と多い。
2355/// 受信側(破棄 0.2%)・順序外バッファ・再送閾値のどれも原因でなく、
2356/// 送信キューも一度も溢れていない(`nic tx queue FULL` 0 件)。
2357/// 残るのは**USB へ実際に出せているか**。ここが最後の未計測区間。
2358/// 破棄条件: 送信ロストの原因が特定でき次第削除。
2359pub static TX_USB_OK: core::sync::atomic::AtomicU32 =
2360    core::sync::atomic::AtomicU32::new(0);
2361pub static TX_USB_FAIL: core::sync::atomic::AtomicU32 =
2362    core::sync::atomic::AtomicU32::new(0);
2363
2364pub static RX_FRAME_COUNT: core::sync::atomic::AtomicU32 =
2365    core::sync::atomic::AtomicU32::new(0);
2366
2367unsafe fn poll_usb_ethernet_data_plane() {
2368    let st = net::status();
2369    if !st.usb_eth_present
2370        || st.usb_eth_addr == 0
2371        || st.usb_eth_bulk_in == 0
2372        || st.usb_eth_bulk_out == 0
2373    {
2374        return;
2375    }
2376
2377    let mut tx_buf = [0u8; 1536];
2378    let max_chunk = 1536; // USBコントローラが自動でMPS分割するので、ソフトウェア側で細切れにせずパケット全体を渡す
2379    while let Some(chunk_len) = net::nic_take_tx_ipv4_chunk(max_chunk, &mut tx_buf) {
2380        if chunk_len == 0 {
2381            break;
2382        }
2383
2384        if st.usb_eth_is_rndis {
2385            let header_len = 44;
2386            let total_len = header_len + chunk_len;
2387            let rndis_header = RndisPacketMsg {
2388                message_type: 0x00000001, // RNDIS_PACKET_MSG
2389                message_length: total_len as u32,
2390                data_offset: 36, // Relative offset from the start of data_offset field (36 + 8 = 44 bytes offset from start)
2391                data_length: chunk_len as u32,
2392                oob_data_offset: 0,
2393                oob_data_length: 0,
2394                num_oob_data_elements: 0,
2395                packet_information_offset: 0,
2396                packet_information_length: 0,
2397                device_vc_handle: 0,
2398                reserved: 0,
2399            };
2400
2401            let header_ptr = &rndis_header as *const RndisPacketMsg as *const u8;
2402            core::ptr::copy_nonoverlapping(header_ptr, DMA_BUF.data.as_mut_ptr(), header_len);
2403            core::ptr::copy_nonoverlapping(
2404                tx_buf.as_ptr(),
2405                DMA_BUF.data.as_mut_ptr().add(header_len),
2406                chunk_len,
2407            );
2408
2409            let buf_phys = &DMA_BUF as *const DmaBuffer as u32;
2410            let pid = crate::kernel::usb_toggle::pid_from_toggle(ETH_BULK_OUT_TOGGLE);
2411            match usb_transfer(
2412                2,
2413                st.usb_eth_bulk_out,
2414                st.usb_eth_addr,
2415                2,
2416                pid,
2417                false,
2418                buf_phys,
2419                total_len as u32,
2420                st.usb_eth_mps,
2421                500_000,
2422            ) {
2423                Ok(_) => {
2424                    crate::debug!("[USB] NET: USB OUT sent {} bytes (RNDIS)", total_len);
2425                }
2426                Err(_) => {
2427                    crate::warn!("[USB] NET: USB OUT FAILED (RNDIS)!");
2428                    break;
2429                }
2430            }
2431            // 【2026-07-29】トグル計算は検証済みモジュールへ一本化
2432            // (`kernel/usb_toggle.rs`、単体試験 14 件)。
2433            // ここへ到達するのは転送成功時のみ(失敗時は上の `Err` で break)。
2434            // トグルがずれるとデバイスはパケットを重複とみなして黙って捨てるため、
2435            // インライン計算のままだと壊れても気付けない。
2436            if let Some(pc) = crate::kernel::usb_toggle::packet_count(total_len, st.usb_eth_mps as u32) {
2437                ETH_BULK_OUT_TOGGLE = crate::kernel::usb_toggle::advance_by_packets(
2438                    ETH_BULK_OUT_TOGGLE,
2439                    pc,
2440                    crate::kernel::usb_toggle::TxnResult::Acked,
2441                );
2442            }
2443        } else {
2444            DMA_BUF.data[..chunk_len].copy_from_slice(&tx_buf[..chunk_len]);
2445            let buf_phys = &DMA_BUF as *const DmaBuffer as u32;
2446            let pid = crate::kernel::usb_toggle::pid_from_toggle(ETH_BULK_OUT_TOGGLE);
2447            match usb_transfer(
2448                2,
2449                st.usb_eth_bulk_out,
2450                st.usb_eth_addr,
2451                2,
2452                pid,
2453                false,
2454                buf_phys,
2455                chunk_len as u32,
2456                st.usb_eth_mps,
2457                500_000,
2458            ) {
2459                Ok(_) => {
2460                    crate::debug!("[USB] NET: USB OUT sent {} bytes (CDC-ECM)", chunk_len);
2461                }
2462                Err(_) => {
2463                    crate::warn!("[USB] NET: USB OUT FAILED (CDC-ECM)!");
2464                    break;
2465                }
2466            }
2467            // CDC-ECM 側も同様に検証済みモジュールへ一本化(`kernel/usb_toggle.rs`)。
2468            // 到達するのは転送成功時のみ(失敗時は上の `Err` で break)。
2469            if let Some(pc) = crate::kernel::usb_toggle::packet_count(chunk_len, st.usb_eth_mps as u32) {
2470                ETH_BULK_OUT_TOGGLE = crate::kernel::usb_toggle::advance_by_packets(
2471                    ETH_BULK_OUT_TOGGLE,
2472                    pc,
2473                    crate::kernel::usb_toggle::TxnResult::Acked,
2474                );
2475            }
2476        }
2477    }
2478
2479    // --- 受信 (bulk IN): 「張りっぱなし」非同期方式 ---
2480    // QEMU DWC2 モデルは bulk NAK 時にチャネルを停止せず (ChEna 維持)、
2481    // 内部タイマ (4kHz) とデバイス wakeup で自動再試行し、データ到着時に
2482    // XferCompl|ChHltd で完了する。従来の「スピン待ち→タイムアウトで強制 ChDis」は
2483    // この保留パケットを毎回キャンセルしてしまい、受信が永久に成立しなかった。
2484    // よって IN は一度発行したら放置し、後続の poll で完了だけを収穫する。
2485    const RX_LEN: u32 = 1600;
2486    static mut RX_IN_FLIGHT: bool = false;
2487    /// 【2026-07-26診断】XferCompl 以外でチャネルが停止した回数。
2488    static mut RX_ABNORMAL_HALTS: u32 = 0;
2489
2490    // 1 ポールで最大 8 フレームまで収穫する。
2491    // デバイス(QEMU usb-net)は 1 フレームしか持てないため、収穫→即再装填を繰り返すと
2492    // 連続データ時はチャネル再装填の同期完了で次々と取り込める。
2493    // 【2026-07-30】1 回のポーリングで回収するフレーム数。
2494    // 64 へ増やし間隔も詰めたところ実機で全滅したため 8 に戻した
2495    // (`kernel/usb_rx_state.rs` の試験と `spec/l1_l2_usb.md` を参照)。
2496    //
2497    // 【2026-08-05】画像取得の律速がここだと実測で確定した。
2498    //
2499    // 3.7MB の JPEG は取得 3685 tick に対しデコード 1092 tick
2500    // (`[IMGPERF]`)。取得側が 3 倍以上重い。
2501    // ポーリング間隔 100ms × 1 回 8 フレーム × 1500 バイト
2502    //   = 120KB/s
2503    // で、実効 100KB/s とほぼ一致する。**この 2 つの値が上限そのもの**。
2504    //
2505    // 2026-07-30 の全滅は間隔(100→20ms)と回収数(8→64)を
2506    // **同時に**変えた結果で、どちらが原因かは分かっていない。
2507    // 当時の注記自身が「片方ずつ変えて測ること」と書いている。
2508    //
2509    // 回収数だけを 8 → 32 にして測った結果(間隔は 100ms のまま):
2510    //
2511    // ```
2512    // 8:  fetch=3685tick  13/13 成功
2513    // 32: fetch=8329tick  13/13 成功   ← 2.3 倍**遅い**
2514    // ```
2515    //
2516    // 成功率は落ちないが確実に遅くなる。
2517    // QEMU の usb-net はデバイス側が 1 フレームしか持てないため、
2518    // 予算を増やしても待つ回数が増えるだけで、
2519    // その間 `USB_LOCK` を握り続けて他を止めているとみられる。
2520    // **8 のままが正しい。**
2521    let mut harvest_budget = 8u32;
2522    loop {
2523        if RX_IN_FLIGHT {
2524            let hcchar_v = core::ptr::read_volatile(hc_char(3));
2525            let ints = core::ptr::read_volatile(hc_int(3));
2526            // 【2026-07-29】判断は純粋モジュールへ委譲(`kernel/usb_rx_state.rs`、
2527            // 単体試験 10 件)。以前はここで CHENA が立っている限り無条件に
2528            // `return` しており、CHENA が落ちない状態に陥ると**受信が永久に停止**
2529            // していた(実測: 1 回目の 14 フレーム以降まったく増えない)。
2530            // DNS タイムアウト・TCP 接続タイムアウト・受信打ち切りは
2531            // すべてこの単一症状の現れだった。
2532            let action = crate::kernel::usb_rx_state::decide(
2533                true,
2534                hcchar_v,
2535                ints,
2536                RX_IN_FLIGHT_POLLS,
2537            );
2538            if action == crate::kernel::usb_rx_state::RxAction::WaitInFlight {
2539                RX_IN_FLIGHT_POLLS = RX_IN_FLIGHT_POLLS.saturating_add(1);
2540                return;
2541            }
2542            // NAK は「今はデータが無い」という正常応答。異常扱いも待機もせず、
2543            // 割り込みをクリアして即座に再アームへ進む(下の再アーム処理へ落とす)。
2544            if action == crate::kernel::usb_rx_state::RxAction::Rearm {
2545                // 【2026-08-05】ここで `hc_int` をクリアしていたが、
2546                // この後どの経路を通っても必ず下の再アーム処理へ落ち、
2547                // そこで**同じクリアをもう一度**行っている。
2548                // NAK は「今はデータが無い」という正常応答なので
2549                // この経路は頻繁に通り、MMIO 書き込みが 1 回まるごと無駄だった。
2550                RX_IN_FLIGHT_POLLS = 0;
2551                RX_IN_FLIGHT = false;
2552            }
2553            if RX_IN_FLIGHT_POLLS >= crate::kernel::usb_rx_state::MAX_IN_FLIGHT_POLLS {
2554                crate::warn!(
2555                    "[USB][RX] channel stuck enabled for {} polls; forcing re-arm (HCCHAR=0x{:08x} HCINT=0x{:08x})",
2556                    RX_IN_FLIGHT_POLLS,
2557                    hcchar_v,
2558                    ints
2559                );
2560            }
2561            RX_IN_FLIGHT_POLLS = 0;
2562            RX_IN_FLIGHT = false;
2563            if (ints & (1 << 0)) != 0 {
2564                // XferCompl
2565                // 【2026-08-05】ここは `hc_tsiz(3)` を 2 回読んでいた
2566                // (残バイト数と、下の Data Toggle 引き継ぎ用 PID)。
2567                // MMIO は QEMU では 1 回ごとにトラップするため、
2568                // 収穫したフレームの数だけ無駄な往復が発生していた
2569                // (実測でフレームは 1 ブートあたり 13000 以上)。
2570                // 同じレジスタなので 1 回読んで使い回す。
2571                let tsiz = core::ptr::read_volatile(hc_tsiz(3));
2572                let remaining = tsiz & 0x7FFFF;
2573                let recv_len = (RX_LEN - remaining) as usize;
2574
2575                // ハードウェアが管理する Data Toggle を読み出して次回の IN トークンへ
2576                // 引き継ぐ。
2577                //
2578                // 【2026-07-26 重大バグ修正】この更新は以前 `if recv_len > 0` の
2579                // **内側**にあった。USB のバルク転送では、デバイスが転送の区切りとして
2580                // **ゼロ長パケット(ZLP)** を返すことがあり、その場合 XferCompl は立つが
2581                // `recv_len == 0` になる。すると Data Toggle が更新されないまま次の IN
2582                // トークンを**古い PID** で発行してしまう。デバイス側は既にトグルを
2583                // 進めているため PID が不一致となり、以後こちらの IN はすべて噛み合わず
2584                // **受信が恒久的に停止する**。
2585                // これは本セッションで繰り返し観測した「送信は成功するのに、ある回数を
2586                // 境に SYN-ACK も DNS 応答も一切届かなくなる(接続の通し番号 ordinal が
2587                // 進むほど失敗する)」という症状を説明しうる。
2588                // 完了した転送では長さに関わらず必ずトグルを引き継ぐ。
2589                let next_pid = (tsiz >> 29) & 3;
2590                // PID → トグルの変換も検証済みモジュールへ(`usb_toggle.rs`)。
2591                ETH_BULK_IN_TOGGLE = crate::kernel::usb_toggle::toggle_from_pid(next_pid);
2592
2593                if recv_len > 0 {
2594                    crate::kernel::mmu::invalidate_dcache_range(
2595                        (&RX_DMA_BUF as *const DmaBuffer) as usize,
2596                        recv_len,
2597                    );
2598
2599                    if st.usb_eth_is_rndis {
2600                        if recv_len >= 44 {
2601                            let msg = core::ptr::read_unaligned(
2602                                RX_DMA_BUF.data.as_ptr() as *const RndisPacketMsg
2603                            );
2604                            // 【2026-07-29】範囲計算は検証済みモジュールへ一本化
2605                            // (`kernel/usb_rndis.rs`、単体試験 12 件)。
2606                            // DataOffset は offset 8 からの相対値で、`+8` を忘れる誤りや
2607                            // 加算オーバーフロー、短すぎるフレームの素通しを型で防ぐ。
2608                            let range = crate::kernel::usb_rndis::rndis_frame_range(
2609                                recv_len,
2610                                msg.message_type,
2611                                msg.data_offset,
2612                                msg.data_length,
2613                            );
2614                            if let Ok((abs_offset, frame_end)) = range {
2615                                // 【2026-08-05 計測済み】1 転送に 2 個目以降の RNDIS
2616                                // メッセージが入っていた回数を数えたところ **0 件**だった
2617                                // (13968 フレーム中)。QEMU の usb-net はバッチ送信しない。
2618                                // → 先頭 1 個しか見ていなくても**取りこぼしは無い**。
2619                                // → `RX_LEN` を増やして 1 転送に複数詰める案も効果が無い。
2620                                let data_len = frame_end - abs_offset;
2621                                if true {
2622                                    let eth_frame =
2623                                        &RX_DMA_BUF.data[abs_offset..abs_offset + data_len];
2624                                    if eth_frame.len() >= 14 {
2625                                        crate::debug!(
2626                                            "[USB] NET: USB IN received {} bytes (RNDIS)",
2627                                            eth_frame.len()
2628                                        );
2629                                        RX_FRAME_COUNT.fetch_add(1, core::sync::atomic::Ordering::Relaxed);
2630                                        let _ = net::ingest_nic_ethernet_frame(eth_frame);
2631                                    }
2632                                }
2633                            }
2634                        }
2635                    } else if recv_len >= 14 {
2636                        crate::debug!("[USB] NET: USB IN received {} bytes (CDC-ECM)", recv_len);
2637                        // 【2026-07-29診断】連続取得で 2 回目以降が失敗する件。
2638                        // そもそもフレームが届いているのかを数える。
2639                        RX_FRAME_COUNT.fetch_add(1, core::sync::atomic::Ordering::Relaxed);
2640                        let _ = net::ingest_nic_ethernet_frame(&RX_DMA_BUF.data[..recv_len]);
2641                    }
2642                }
2643            }
2644            // XferCompl 以外(STALL / XactErr / DataToggleErr 等)で停止した場合。
2645            //
2646            // 【2026-07-26診断】現状はここで何もせず、**同じ Data Toggle のまま**
2647            // 次の IN を再発行している。もし停止要因が Data Toggle Error(DTERR,
2648            // bit10) や Transaction Error(XactErr, bit7) であれば、同じ条件で再試行
2649            // し続けることになり **受信が恒久的に停止する**。本セッションで繰り返し
2650            // 観測している「送信は成功し続けるのに、ある時点から SYN-ACK も DNS 応答も
2651            // 一切届かなくなる」症状と整合する。まず実際にどのビットで停止して
2652            // いるのかを計測する(憶測で回復処理を入れる前に事実を取る)。
2653            // NAK は正常応答なので異常カウンタを回さない(実測で 21504 回
2654            // 誤記録していた)。判定は `usb_rx_state::decide` に一本化済み。
2655            else if action != crate::kernel::usb_rx_state::RxAction::Rearm {
2656                RX_ABNORMAL_HALTS = RX_ABNORMAL_HALTS.saturating_add(1);
2657                if RX_ABNORMAL_HALTS <= 8 || RX_ABNORMAL_HALTS.is_multiple_of(64) {
2658                    crate::warn!(
2659                        "[USB][DIAG] RX halted without XferCompl: HCINT=0x{:08x} (STALL={} XactErr={} DTERR={} BblErr={} FrmOvrun={}) count={}",
2660                        ints,
2661                        (ints >> 3) & 1,
2662                        (ints >> 7) & 1,
2663                        (ints >> 10) & 1,
2664                        (ints >> 8) & 1,
2665                        (ints >> 9) & 1,
2666                        RX_ABNORMAL_HALTS
2667                    );
2668                }
2669            }
2670        }
2671
2672        if !RX_IN_FLIGHT {
2673            // 新しい IN 転送をノンブロッキングで発行(完了は待たない)
2674            let buf_phys = &RX_DMA_BUF as *const DmaBuffer as u32;
2675            crate::kernel::mmu::invalidate_dcache_range(buf_phys as usize, RX_LEN as usize);
2676            let pid = crate::kernel::usb_toggle::pid_from_toggle(ETH_BULK_IN_TOGGLE);
2677            core::ptr::write_volatile(hc_int(3), 0x7FF); // 割り込みクリア
2678            let mps = st.usb_eth_mps as u32;
2679            let packet_count = RX_LEN.div_ceil(mps);
2680            let mut tsiz = RX_LEN & 0x7FFFF;
2681            tsiz |= packet_count << 19;
2682            tsiz |= pid << 29;
2683            core::ptr::write_volatile(hc_tsiz(3), tsiz);
2684            core::ptr::write_volatile(hc_dma(3), buf_phys);
2685            let mut hcchar_v = mps & 0x7FF;
2686            hcchar_v |= ((st.usb_eth_bulk_in as u32) & 0xF) << 11;
2687            hcchar_v |= 1 << 15; // EPDir = IN
2688            hcchar_v |= 2 << 18; // EPType = Bulk
2689            hcchar_v |= 3 << 20; // MC/EC
2690            hcchar_v |= ((st.usb_eth_addr as u32) & 0x7F) << 22;
2691            hcchar_v |= 1 << 31; // ChEna
2692            core::ptr::write_volatile(hc_char(3), hcchar_v);
2693            RX_IN_FLIGHT = true;
2694        }
2695
2696        harvest_budget -= 1;
2697        if harvest_budget == 0 {
2698            break;
2699        }
2700    } // loop
2701}
2702
2703/// USB HID スキャンコードから PS/2 Set 1 スキャンコードへのマッピング
2704fn hid_to_ps2(hid_code: u8) -> Option<u8> {
2705    let ps2 = match hid_code {
2706        0x1E => 0x02, // 1
2707        0x1F => 0x03, // 2
2708        0x20 => 0x04, // 3
2709        0x21 => 0x05, // 4
2710        0x22 => 0x06, // 5
2711        0x23 => 0x07, // 6
2712        0x24 => 0x08, // 7
2713        0x25 => 0x09, // 8
2714        0x26 => 0x0A, // 9
2715        0x27 => 0x0B, // 0
2716        0x2D => 0x0C, // -
2717        0x2E => 0x0D, // = / ^
2718        0x2A => 0x0E, // Backspace
2719        0x2B => 0x0F, // Tab
2720        0x04 => 0x1E, // A
2721        0x05 => 0x30, // B
2722        0x06 => 0x2E, // C
2723        0x07 => 0x20, // D
2724        0x08 => 0x12, // E
2725        0x09 => 0x21, // F
2726        0x0A => 0x22, // G
2727        0x0B => 0x23, // H
2728        0x0C => 0x17, // I
2729        0x0D => 0x24, // J
2730        0x0E => 0x25, // K
2731        0x0F => 0x26, // L
2732        0x10 => 0x32, // M
2733        0x11 => 0x31, // N
2734        0x12 => 0x18, // O
2735        0x13 => 0x19, // P
2736        0x14 => 0x10, // Q
2737        0x15 => 0x13, // R
2738        0x16 => 0x1F, // S
2739        0x17 => 0x14, // T
2740        0x18 => 0x16, // U
2741        0x19 => 0x2F, // V
2742        0x1A => 0x11, // W
2743        0x1B => 0x2D, // X
2744        0x1C => 0x15, // Y
2745        0x1D => 0x2C, // Z
2746        0x2F => 0x1A, // [ / @
2747        0x30 => 0x1B, // ] / [
2748        0x2C => 0x39, // Space
2749        0x28 => 0x1C, // Enter
2750        0x33 => 0x27, // ; / +
2751        0x34 => 0x28, // ' / :
2752        0x35 => 0x29, // ` / Hankaku-Zenkaku
2753        0x31 => 0x2B, // \ / ]
2754        0x36 => 0x33, // ,
2755        0x37 => 0x34, // .
2756        0x38 => 0x35, // /
2757        0x64 => 0x73, // Non-US \ / |
2758        0x87 => 0x73, // JIS Ro
2759        0x88 => 0x70, // JIS Katakana/Hiragana
2760        0x89 => 0x7D, // JIS Yen
2761        0x8A => 0x79, // JIS Henkan
2762        0x8B => 0x7B, // JIS Muhenkan
2763        0x90 => 0x79, // Mac Kana (Lang1) -> Map to Henkan (0x79)
2764        0x91 => 0x7B, // Mac Eisu (Lang2) -> Map to Muhenkan (0x7B)
2765        0x52 => 0x48, // Up Arrow
2766        0x51 => 0x50, // Down Arrow
2767        0x50 => 0x4B, // Left Arrow
2768        0x4F => 0x4D, // Right Arrow
2769        0x4C => 0x53, // Delete Forward
2770        0x4A => 0x47, // Home
2771        0x4D => 0x4F, // End
2772        0x4B => 0x49, // Page Up
2773        0x4E => 0x51, // Page Down
2774        0x29 => 0x01, // Esc
2775        0x3A => 0x3B, // F1
2776        0x3B => 0x3C, // F2
2777        0x3C => 0x3D, // F3
2778        0x3D => 0x3E, // F4
2779        0x3E => 0x3F, // F5
2780        0x3F => 0x40, // F6
2781        0x40 => 0x41, // F7
2782        0x41 => 0x42, // F8
2783        0x42 => 0x43, // F9
2784        0x43 => 0x44, // F10
2785        0x44 => 0x57, // F11
2786        0x45 => 0x58, // F12
2787        _ => return None,
2788    };
2789    Some(ps2)
2790}
2791
2792// =====================================================================================
2793// DWC2 スプリットトランザクション用フレームスケジューラ
2794// =====================================================================================
2795//
2796// HS ホスト(DWC2)が HS ハブ(RPi3B+ 内蔵 LAN9514)の背後にぶら下がる FS/LS デバイス
2797// (実機のキーボード/マウス)と通信するには、Start-Split / Complete-Split の2段階
2798// トランザクションを正しい (マイクロ)フレームに配置し、NYET/NAK 時に決められた
2799// ポリシーで再試行する必要がある。その時間規律を司るのがフレームスケジューラ。
2800//
2801// アルゴリズムは uspi (rsta2/uspi, GPLv3) の dwhciframesched{nsplit,nper,per}.c を
2802// 「参照」し、USB 2.0 spec §11.18 のスプリットスケジューリング規則に基づいて
2803// 自前 Rust で機能等価に再実装したもの(逐語移植・コードコピーではない)。
2804//
2805// 設計: 非ブロッキングのフレーム駆動ステートマシン。状態遷移ロジック(バグの出やすい
2806// 部分)は純粋関数なので frame_sched::selftest() で QEMU/ホスト検証できる。
2807// wait_for_frame だけが実 HFNUM レジスタを参照する(実機タイミング依存)。
2808pub mod frame_sched {
2809    // チャネル割り込みステータスビット(HCINT と共通)
2810    const INT_XFER_COMPLETE: u32 = 1 << 0;
2811    const INT_NAK: u32 = 1 << 4;
2812    const INT_ACK: u32 = 1 << 5;
2813    const INT_NYET: u32 = 1 << 6;
2814    const INT_XACT_ERR: u32 = 1 << 7;
2815
2816    /// CSPLIT NAK による SSPLIT やり直しの上限。complete_split() がサイクル毎に
2817    /// tries をリセットするため、これがないと外側のタイムアウト (1秒) まで
2818    /// リトライし続けてしまう。上限到達で失敗を返し、上位層 (コントロール転送の
2819    /// SETUP からのやり直し) に回復を委ねる。
2820    const MAX_NAK_RESTARTS: u32 = 64;
2821
2822    const UFRAME_US: u64 = 125; // 1 マイクロフレーム = 125us
2823    const MAX_FRAME_NUMBER: u32 = 0x3FFF;
2824    const NPER_FRAME_UNSET: u32 = MAX_FRAME_NUMBER + 1; // NoSplit 用センチネル
2825    const PER_FRAME_UNSET: u32 = 8; // Periodic 用センチネル(マイクロフレーム 0..7 の範囲外)
2826
2827    /// HFNUM レジスタからフレーム番号フィールド (下位16bit) を読む。
2828    #[inline]
2829    fn frame_number() -> u32 {
2830        unsafe { core::ptr::read_volatile(super::HFNUM) & 0xFFFF }
2831    }
2832
2833    /// 実時間マイクロ秒ウェイト(cntpct_el0 ベース、割り込み非依存)。
2834    fn udelay(us: u64) {
2835        let start = crate::kernel::timer::get_system_time_us();
2836        while crate::kernel::timer::get_system_time_us().wrapping_sub(start) < us {
2837            unsafe { core::arch::asm!("nop") };
2838        }
2839    }
2840
2841    #[derive(Clone, Copy, PartialEq, Eq, Debug)]
2842    pub enum State {
2843        StartSplit,
2844        StartSplitComplete,
2845        CompleteSplit,
2846        CompleteRetry,
2847        CompleteSplitComplete,
2848        CompleteSplitFailed,
2849        Unknown,
2850    }
2851
2852    #[derive(Clone, Copy, PartialEq, Eq)]
2853    enum Kind {
2854        /// 非スプリット(HS デバイス直結。SSPLIT/CSPLIT を使わない)
2855        NoSplit { is_periodic: bool },
2856        /// スプリット・非ピリオディック(FS/LS の control/bulk)
2857        NonPeriodic,
2858        /// スプリット・ピリオディック(FS/LS の interrupt/iso)
2859        Periodic,
2860    }
2861
2862    /// 1 トランザクション分のフレームスケジューラ状態。
2863    pub struct FrameScheduler {
2864        kind: Kind,
2865        pub state: State,
2866        tries: i32,
2867        next_frame: u32,
2868        /// CSPLIT が NAK を受けて SSPLIT からやり直した回数(診断用)。
2869        pub nak_restarts: u32,
2870        /// XactErr (バス転送エラー) の残りリトライ回数。tries と違い NAK 再開で
2871        /// リセットされない、サイクル全体を通した予算。
2872        xacterr_budget: i32,
2873    }
2874
2875    impl FrameScheduler {
2876        pub fn new_no_split(is_periodic: bool) -> Self {
2877            Self {
2878                kind: Kind::NoSplit { is_periodic },
2879                state: State::Unknown,
2880                tries: 0,
2881                next_frame: NPER_FRAME_UNSET,
2882                nak_restarts: 0,
2883                xacterr_budget: 3,
2884            }
2885        }
2886        pub fn new_non_periodic() -> Self {
2887            Self {
2888                kind: Kind::NonPeriodic,
2889                state: State::Unknown,
2890                tries: 0,
2891                next_frame: NPER_FRAME_UNSET,
2892                nak_restarts: 0,
2893                xacterr_budget: 3,
2894            }
2895        }
2896        pub fn new_periodic() -> Self {
2897            Self {
2898                kind: Kind::Periodic,
2899                state: State::Unknown,
2900                tries: 0,
2901                next_frame: PER_FRAME_UNSET,
2902                nak_restarts: 0,
2903                xacterr_budget: 3,
2904            }
2905        }
2906
2907        /// この転送がスプリットを使うか(NoSplit なら false)。
2908        pub fn is_split(&self) -> bool {
2909            !matches!(self.kind, Kind::NoSplit { .. })
2910        }
2911        /// スプリットサイクルが成功完了したか。
2912        pub fn is_complete(&self) -> bool {
2913            self.state == State::CompleteSplitComplete
2914        }
2915        /// スプリットサイクルが失敗終了したか。
2916        pub fn is_failed(&self) -> bool {
2917            self.state == State::CompleteSplitFailed
2918        }
2919
2920        /// 新しい Start-Split サイクルを開始する。
2921        pub fn start_split(&mut self) {
2922            match self.kind {
2923                Kind::NoSplit { .. } => {} // 非スプリットでは呼ばれない(呼ばれても無害)
2924                Kind::NonPeriodic => {
2925                    self.state = State::StartSplit;
2926                }
2927                Kind::Periodic => {
2928                    self.state = State::StartSplit;
2929                    self.next_frame = PER_FRAME_UNSET;
2930                }
2931            }
2932        }
2933
2934        /// Complete-Split を今発行すべきか返す。false なら CSPLIT は出さない(完了/失敗 or 待機)。
2935        pub fn complete_split(&mut self) -> bool {
2936            match self.kind {
2937                Kind::NoSplit { .. } => false,
2938                Kind::NonPeriodic => match self.state {
2939                    State::StartSplitComplete => {
2940                        // USB 2.0 spec §11.18.2.2:
2941                        // SSPLIT ACK 後、最初の CSPLIT を発行するまでに FS デバイスが
2942                        // ダウンストリームバスでトランザクションを完了するのを待つ。
2943                        // FS: ~1bit time × 8bit × max_packet + ターンアラウンド。
2944                        // 安全マージンを含め 3 マイクロフレーム (375μs) 待機する。
2945                        // この wait がないと TT が「まだ完了していない」として NAK を返す。
2946                        udelay(3 * UFRAME_US);
2947                        self.state = State::CompleteSplit;
2948                        self.tries = 3;
2949                        true
2950                    }
2951                    State::CompleteSplit | State::CompleteRetry => {
2952                        udelay(5 * UFRAME_US);
2953                        true
2954                    }
2955                    _ => false, // CompleteSplitComplete / Failed / その他
2956                },
2957                Kind::Periodic => match self.state {
2958                    State::StartSplitComplete => {
2959                        self.state = State::CompleteSplit;
2960                        self.tries = if self.next_frame != 5 { 3 } else { 2 };
2961                        self.next_frame = (self.next_frame + 2) & 7;
2962                        true
2963                    }
2964                    State::CompleteRetry => {
2965                        self.next_frame = (self.next_frame + 1) & 7;
2966                        true
2967                    }
2968                    _ => false,
2969                },
2970            }
2971        }
2972
2973        /// 直前トランザクションのチャネル割り込みステータスを与えて状態を進める。
2974        pub fn transaction_complete(&mut self, status: u32) {
2975            match self.kind {
2976                Kind::NoSplit { .. } => {}
2977                Kind::NonPeriodic => match self.state {
2978                    State::StartSplit => self.state = State::StartSplitComplete,
2979                    State::CompleteSplit | State::CompleteRetry => {
2980                        if status & INT_XFER_COMPLETE != 0 {
2981                            self.state = State::CompleteSplitComplete;
2982                        } else if status & (INT_NYET | INT_ACK) != 0 {
2983                            if status & INT_NYET != 0 {
2984                                self.state = State::CompleteRetry;
2985                            } else {
2986                                if self.tries == 0 {
2987                                    self.state = State::CompleteSplitFailed;
2988                                } else {
2989                                    self.tries -= 1;
2990                                    self.state = State::CompleteRetry;
2991                                }
2992                            }
2993                        } else if status & INT_NAK != 0 {
2994                            // USB 2.0 spec §11.18: Complete-Split が NAK を受けたら、
2995                            // それは「ハブが完了トランザクションを保持していない」ことを意味する。
2996                            // CSPLIT を単純に再送するのではなく、Start-Split からサイクル全体を
2997                            // やり直さなければならない。(Linux dwc2 ドライバも同様に
2998                            // complete_split フラグをクリアして SSPLIT からリトライする)
2999                            if self.tries == 0 || self.nak_restarts >= MAX_NAK_RESTARTS {
3000                                udelay(5 * UFRAME_US);
3001                                self.state = State::CompleteSplitFailed;
3002                            } else {
3003                                self.tries -= 1;
3004                                self.state = State::StartSplit;
3005                                self.nak_restarts += 1;
3006                            }
3007                        } else {
3008                            // XactErr 等のバス転送エラー。実機の TT 経由通信では単発の
3009                            // バスエラーが起こり得るため、Linux dwc2 ドライバ同様に
3010                            // 数回は SSPLIT からやり直す。予算 (xacterr_budget) を
3011                            // 使い切ったら諦める。
3012                            if self.xacterr_budget <= 0 {
3013                                self.state = State::CompleteSplitFailed;
3014                            } else {
3015                                self.xacterr_budget -= 1;
3016                                self.state = State::StartSplit;
3017                                self.nak_restarts += 1;
3018                            }
3019                        }
3020                    }
3021                    _ => {}
3022                },
3023                Kind::Periodic => match self.state {
3024                    State::StartSplit => self.state = State::StartSplitComplete,
3025                    State::CompleteSplit | State::CompleteRetry => {
3026                        if status & INT_XFER_COMPLETE != 0 {
3027                            self.state = State::CompleteSplitComplete;
3028                        } else if status & (INT_NYET | INT_ACK) != 0 {
3029                            if status & INT_NYET != 0 {
3030                                self.state = State::CompleteRetry;
3031                            } else {
3032                                if self.tries == 0 {
3033                                    self.state = State::CompleteSplitFailed;
3034                                    udelay(8 * UFRAME_US);
3035                                } else {
3036                                    self.tries -= 1;
3037                                    self.state = State::CompleteRetry;
3038                                }
3039                            }
3040                        } else if status & INT_NAK != 0 {
3041                            udelay(5 * UFRAME_US);
3042                            self.state = State::CompleteSplitFailed;
3043                        } else {
3044                            self.state = State::CompleteSplitFailed;
3045                        }
3046                    }
3047                    _ => {}
3048                },
3049            }
3050        }
3051
3052        /// Start-Split を発行する正しいフレームまで待つ(実 HFNUM 参照)。
3053        pub fn wait_for_frame(&mut self) {
3054            match self.kind {
3055                Kind::NoSplit { is_periodic } => {
3056                    self.next_frame = (frame_number() + 1) & MAX_FRAME_NUMBER;
3057                    if !is_periodic {
3058                        while (frame_number() & MAX_FRAME_NUMBER) != self.next_frame {
3059                            unsafe {
3060                                core::arch::asm!("dsb sy", "isb", options(nostack));
3061                            }
3062                        }
3063                    }
3064                }
3065                Kind::NonPeriodic => {} // 任意フレームで SSPLIT 可
3066                Kind::Periodic => {
3067                    if self.next_frame == PER_FRAME_UNSET {
3068                        self.next_frame = (frame_number() + 1) & 7;
3069                        if self.next_frame == 6 {
3070                            self.next_frame += 1; // 6 は避ける(→7)
3071                        }
3072                    }
3073                    while (frame_number() & 7) != self.next_frame {
3074                        unsafe {
3075                            core::arch::asm!("dsb sy", "isb", options(nostack));
3076                        }
3077                    }
3078                }
3079            }
3080        }
3081
3082        /// HCCHAR の Odd-Frame ビットに設定すべき値。
3083        pub fn is_odd_frame(&self) -> bool {
3084            match self.kind {
3085                Kind::NoSplit { .. } | Kind::Periodic => self.next_frame & 1 != 0,
3086                Kind::NonPeriodic => false,
3087            }
3088        }
3089    }
3090
3091    /// 状態遷移ロジックのセルフテスト(実機タイミング非依存の純粋部分のみ)。
3092    /// main.rs のブート時セルフテスト群から呼ばれ "USBSCHED_SELFTEST: PASS x/y" を出す。
3093    pub fn selftest() -> (usize, usize) {
3094        let mut pass = 0usize;
3095        let mut total = 0usize;
3096        macro_rules! check {
3097            ($cond:expr) => {{
3098                total += 1;
3099                if $cond {
3100                    pass += 1;
3101                }
3102            }};
3103        }
3104
3105        // --- NonPeriodic: 正常系 (SSPLIT ACK → CSPLIT → XFER_COMPLETE) ---
3106        {
3107            let mut s = FrameScheduler::new_non_periodic();
3108            check!(s.is_split());
3109            s.start_split();
3110            s.transaction_complete(INT_ACK); // SSPLIT が ACK
3111            check!(s.complete_split()); // → CSPLIT を発行
3112            s.transaction_complete(INT_XFER_COMPLETE); // CSPLIT 完了
3113            check!(s.is_complete());
3114            check!(!s.complete_split()); // もう CSPLIT は出さない
3115            check!(!s.is_failed());
3116        }
3117
3118        // --- NonPeriodic: NYET では tries を消費せずリトライを継続すること ---
3119        {
3120            let mut s = FrameScheduler::new_non_periodic();
3121            s.start_split();
3122            s.transaction_complete(INT_ACK);
3123            check!(s.complete_split()); // tries=3, CompleteSplit
3124            // NYET を 10 回与えてもリトライが継続し、失敗しない
3125            for _ in 0..10 {
3126                s.transaction_complete(INT_NYET);
3127                check!(s.complete_split());
3128                check!(!s.is_failed());
3129                check!(!s.is_complete());
3130            }
3131        }
3132
3133        // --- NonPeriodic: CSPLIT が NAK を受けたら SSPLIT からやり直すこと ---
3134        {
3135            let mut s = FrameScheduler::new_non_periodic();
3136            s.start_split();
3137            s.transaction_complete(INT_ACK); // SSPLIT ACK → StartSplitComplete
3138            check!(s.complete_split()); // → CompleteSplit (tries=3), CSPLIT 発行
3139            s.transaction_complete(INT_NAK); // CSPLIT が NAK → SSPLIT からやり直し
3140            check!(!s.is_failed());
3141            check!(!s.complete_split()); // state=StartSplit なので CSPLIT は出さない (SSPLIT を送る)
3142            s.transaction_complete(INT_ACK); // 2回目の SSPLIT が ACK
3143            check!(s.complete_split()); // → 再度 CSPLIT
3144            s.transaction_complete(INT_XFER_COMPLETE);
3145            check!(s.is_complete());
3146        }
3147
3148        // --- NonPeriodic: NAK やり直しは有限回 (MAX_NAK_RESTARTS) で打ち切られること ---
3149        {
3150            let mut s = FrameScheduler::new_non_periodic();
3151            s.start_split();
3152            let mut iters = 0u32;
3153            loop {
3154                s.transaction_complete(INT_ACK); // SSPLIT ACK
3155                if !s.complete_split() {
3156                    break; // 失敗確定なら CSPLIT を出さない
3157                }
3158                s.transaction_complete(INT_NAK); // CSPLIT が NAK
3159                if s.is_failed() {
3160                    break;
3161                }
3162                iters += 1;
3163                if iters > 1000 {
3164                    break; // 無限ループ防止 (テスト自体の失敗を意味する)
3165                }
3166            }
3167            check!(s.is_failed());
3168            check!((10..=MAX_NAK_RESTARTS + 1).contains(&iters));
3169        }
3170
3171        // --- NonPeriodic: XactErr は予算内なら SSPLIT からやり直し、成功できること ---
3172        {
3173            let mut s = FrameScheduler::new_non_periodic();
3174            s.start_split();
3175            s.transaction_complete(INT_ACK);
3176            check!(s.complete_split()); // → CompleteSplit, CSPLIT 発行
3177            s.transaction_complete(INT_XACT_ERR); // バスエラー → SSPLIT からやり直し
3178            check!(!s.is_failed());
3179            check!(!s.complete_split()); // state=StartSplit → SSPLIT を送る
3180            s.transaction_complete(INT_ACK);
3181            check!(s.complete_split());
3182            s.transaction_complete(INT_XFER_COMPLETE);
3183            check!(s.is_complete());
3184        }
3185
3186        // --- NonPeriodic: XactErr が予算(3回)を使い切ったら失敗すること ---
3187        {
3188            let mut s = FrameScheduler::new_non_periodic();
3189            s.start_split();
3190            s.transaction_complete(INT_ACK);
3191            for _ in 0..4 {
3192                check!(!s.is_failed());
3193                check!(s.complete_split());
3194                s.transaction_complete(INT_XACT_ERR);
3195                s.transaction_complete(INT_ACK); // 次サイクルの SSPLIT ACK (StartSplit→StartSplitComplete)
3196            }
3197            check!(s.is_failed());
3198        }
3199
3200        // --- Periodic: 正常系 ---
3201        {
3202            let mut s = FrameScheduler::new_periodic();
3203            check!(s.is_split());
3204            s.start_split();
3205            s.transaction_complete(INT_ACK); // SSPLIT ACK
3206            check!(s.complete_split()); // → CSPLIT
3207            s.transaction_complete(INT_XFER_COMPLETE);
3208            check!(s.is_complete());
3209        }
3210
3211        // --- Periodic: NAK は即失敗 ---
3212        {
3213            let mut s = FrameScheduler::new_periodic();
3214            s.start_split();
3215            s.transaction_complete(INT_ACK);
3216            check!(s.complete_split());
3217            s.transaction_complete(INT_NAK); // NAK → 即失敗
3218            check!(s.is_failed());
3219        }
3220
3221        // --- NoSplit: スプリットを使わない ---
3222        {
3223            let s = FrameScheduler::new_no_split(false);
3224            check!(!s.is_split());
3225        }
3226
3227        (pass, total)
3228    }
3229}