Skip to main content

strat9_kernel/hardware/usb/
xhci.rs

1// USB xHCI Host Controller Driver
2// Reference: xHCI spec 1.2
3//
4// Features:
5// - xHCI controller initialization with full device enumeration
6// - Port reset, Enable Slot, Address Device, Configure Endpoint
7// - Per-device transfer rings and DCBAA contexts
8// - Control transfers via per-device EP0 transfer rings
9// - Interrupt transfer support for HID polling
10// - HID device support (keyboard/mouse)
11
12#![allow(dead_code)]
13
14use crate::{
15    hardware::pci_client::{self as pci, Bar, ProbeCriteria},
16    memory::{allocate_zeroed_frame, paging, phys_to_virt},
17};
18use alloc::{sync::Arc, vec::Vec};
19use core::{
20    ptr::{read_volatile, write_volatile},
21    sync::atomic::{AtomicBool, AtomicU8, AtomicUsize, Ordering},
22};
23use spin::Mutex;
24
25const XHCI_MMIO_SIZE: usize = 0x10000;
26const XHCI_PORT_REG_BASE: usize = 0x400;
27const XHCI_PORT_REG_STRIDE: usize = 0x10;
28const XHCI_RING_TRBS: usize = 64;
29const MAX_ENDPOINTS: usize = 31;
30
31const USBCMD_RUN_STOP: u32 = 1 << 0;
32const USBCMD_HCRST: u32 = 1 << 1;
33const USBCMD_INTE: u32 = 1 << 2;
34
35const USBSTS_HCH: u32 = 1 << 0;
36const USBSTS_CNR: u32 = 1 << 11;
37
38const PORTSC_CCS: u32 = 1 << 0;
39const PORTSC_PED: u32 = 1 << 1;
40const PORTSC_PR: u32 = 1 << 4;
41const PORTSC_PP: u32 = 1 << 9;
42const PORTSC_SPEED_SHIFT: u32 = 10;
43const PORTSC_W1C_MASK: u32 = 0xFE0000;
44
45const TRB_TYPE_NORMAL: u32 = 1;
46const TRB_TYPE_SETUP_STAGE: u32 = 2;
47const TRB_TYPE_DATA_STAGE: u32 = 3;
48const TRB_TYPE_STATUS_STAGE: u32 = 4;
49const TRB_TYPE_ENABLE_SLOT: u32 = 9;
50const TRB_TYPE_ADDRESS_DEVICE: u32 = 11;
51const TRB_TYPE_CONFIGURE_ENDPOINT: u32 = 12;
52const TRB_TYPE_TRANSFER_EVENT: u32 = 32;
53const TRB_TYPE_LINK: u32 = 6;
54
55const TRB_CYCLE: u32 = 1 << 0;
56const TRB_IOC: u32 = 1 << 5;
57const TRB_DIR_IN: u32 = 1 << 16;
58const TRB_DIR_OUT: u32 = 0;
59const TRB_TC: u32 = 1 << 1;
60
61const TRB_TYPE_SHIFT: u32 = 10;
62const TRB_IDT: u32 = 1 << 6;
63const TRB_TD_SIZE_SHIFT: u32 = 17;
64const TRB_TD_SIZE_MASK: u32 = 0x1F;
65
66const EP_TYPE_CONTROL: u32 = 4;
67const EP_TYPE_INTR_IN: u32 = 7;
68
69const fn trb_get_type(d3: u32) -> u32 {
70    (d3 >> TRB_TYPE_SHIFT) & 0xFF
71}
72
73#[repr(C)]
74struct CapRegisters {
75    caplength: u8,
76    _reserved: u8,
77    _hciversion: u16,
78    hcsparams1: u32,
79    _hcsparams2: u32,
80    _hcsparams3: u32,
81    _hccparams1: u32,
82    dboff: u32,
83    rtsoff: u32,
84    _hccparams2: u32,
85}
86
87#[repr(C)]
88struct OpRegisters {
89    usbcmd: u32,
90    usbsts: u32,
91    _pagesize: u32,
92    _reserved0: [u32; 2],
93    _dnctrl: u32,
94    crcr: u64,
95    _reserved1: [u32; 4],
96    dcbaap: u64,
97    config: u32,
98}
99
100#[repr(C)]
101struct RuntimeRegisters {
102    _mfindex: u32,
103    _reserved: [u32; 7],
104    ir: [InterrupterRegisters; 1],
105}
106
107#[repr(C)]
108struct InterrupterRegisters {
109    iman: u32,
110    _imod: u32,
111    erstsz: u32,
112    _reserved: u32,
113    erstba: u64,
114    erdp: u64,
115}
116
117#[repr(C)]
118#[derive(Clone, Copy)]
119struct Trb {
120    d0: u32,
121    d1: u32,
122    d2: u32,
123    d3: u32,
124}
125
126impl Trb {
127    fn link(addr: u64, toggle_cycle: bool) -> Self {
128        Self {
129            d0: (addr & 0xFFFFFFFF) as u32,
130            d1: ((addr >> 32) & 0xFFFFFFFF) as u32,
131            d2: 0,
132            d3: ((TRB_TYPE_LINK << TRB_TYPE_SHIFT) as u32)
133                | TRB_CYCLE
134                | (if toggle_cycle { TRB_TC } else { 0 }),
135        }
136    }
137
138    fn normal(addr: u64, len: u32, cycle: bool, ioc: bool) -> Self {
139        let mut d3 = (TRB_TYPE_NORMAL << TRB_TYPE_SHIFT) as u32 | if cycle { TRB_CYCLE } else { 0 };
140        if ioc {
141            d3 |= TRB_IOC;
142        }
143        Self {
144            d0: (addr & 0xFFFFFFFF) as u32,
145            d1: ((addr >> 32) & 0xFFFFFFFF) as u32,
146            d2: len,
147            d3,
148        }
149    }
150
151    fn setup_stage(addr: u64, cycle: bool) -> Self {
152        let mut d3 =
153            (TRB_TYPE_SETUP_STAGE << TRB_TYPE_SHIFT) as u32 | if cycle { TRB_CYCLE } else { 0 };
154        d3 |= TRB_IDT;
155        Self {
156            d0: (addr & 0xFFFFFFFF) as u32,
157            d1: ((addr >> 32) & 0xFFFFFFFF) as u32,
158            d2: 8,
159            d3,
160        }
161    }
162
163    fn data_stage(addr: u64, len: u32, dir_in: bool, cycle: bool, ioc: bool) -> Self {
164        let mut d3 =
165            (TRB_TYPE_DATA_STAGE << TRB_TYPE_SHIFT) as u32 | if cycle { TRB_CYCLE } else { 0 };
166        if dir_in {
167            d3 |= TRB_DIR_IN;
168        }
169        if ioc {
170            d3 |= TRB_IOC;
171        }
172        let td_size = ((len + TRB_TD_SIZE_MASK) / (TRB_TD_SIZE_MASK + 1)) & TRB_TD_SIZE_MASK;
173        let d2 = (td_size << TRB_TD_SIZE_SHIFT) | len;
174        Self {
175            d0: (addr & 0xFFFFFFFF) as u32,
176            d1: ((addr >> 32) & 0xFFFFFFFF) as u32,
177            d2,
178            d3,
179        }
180    }
181
182    fn status_stage(cycle: bool, dir_in: bool) -> Self {
183        let mut d3 =
184            (TRB_TYPE_STATUS_STAGE << TRB_TYPE_SHIFT) as u32 | if cycle { TRB_CYCLE } else { 0 };
185        if dir_in {
186            d3 |= TRB_DIR_IN;
187        }
188        d3 |= TRB_IOC;
189        Self {
190            d0: 0,
191            d1: 0,
192            d2: 0,
193            d3,
194        }
195    }
196}
197
198#[repr(C, packed)]
199struct SlotContext {
200    d0: u32,
201    d1: u32,
202    d2: u32,
203    d3: u32,
204    d4: u32,
205    d5: u32,
206    d6: u32,
207    d7: u32,
208}
209
210#[repr(C, packed)]
211struct EndpointContext {
212    d0: u32,
213    d1: u32,
214    d2: u32,
215    d3: u32,
216    d4: u32,
217    d5: u32,
218    d6: u32,
219    d7: u32,
220}
221
222#[repr(C, packed)]
223struct InputControlContext {
224    d0: u32,
225    d1: u32,
226    d2: [u32; 30],
227}
228
229#[repr(C, packed)]
230struct InputContext {
231    ctrl: InputControlContext,
232    slot: SlotContext,
233    eps: [EndpointContext; 31],
234}
235
236struct XhciPort {
237    port_num: usize,
238    enabled: bool,
239    connected: bool,
240    speed: u8,
241}
242
243struct DeviceSlot {
244    slot_id: u8,
245    usb_address: u8,
246    input_ctx: *mut InputContext,
247    input_ctx_phys: u64,
248    ep_transfer_rings: [*mut Trb; MAX_ENDPOINTS],
249    ep_transfer_ring_phys: [u64; MAX_ENDPOINTS],
250    ep_dequeue: [usize; MAX_ENDPOINTS],
251    ep_cycle: [bool; MAX_ENDPOINTS],
252    configured: bool,
253    ep_buf: [*mut u8; MAX_ENDPOINTS],
254    ep_buf_phys: [u64; MAX_ENDPOINTS],
255    ep_buf_len: [usize; MAX_ENDPOINTS],
256    ep_active: [bool; MAX_ENDPOINTS],
257}
258
259unsafe impl Send for DeviceSlot {}
260unsafe impl Sync for DeviceSlot {}
261
262impl DeviceSlot {
263    fn new(slot_id: u8) -> Self {
264        Self {
265            slot_id,
266            usb_address: 0,
267            input_ctx: core::ptr::null_mut(),
268            input_ctx_phys: 0,
269            ep_transfer_rings: [core::ptr::null_mut(); MAX_ENDPOINTS],
270            ep_transfer_ring_phys: [0; MAX_ENDPOINTS],
271            ep_dequeue: [0; MAX_ENDPOINTS],
272            ep_cycle: [true; MAX_ENDPOINTS],
273            configured: false,
274            ep_buf: [core::ptr::null_mut(); MAX_ENDPOINTS],
275            ep_buf_phys: [0; MAX_ENDPOINTS],
276            ep_buf_len: [0; MAX_ENDPOINTS],
277            ep_active: [false; MAX_ENDPOINTS],
278        }
279    }
280}
281
282pub struct XhciController {
283    mmio_base: usize,
284    cap_regs: *const CapRegisters,
285    op_regs: *mut OpRegisters,
286    rt_regs: *mut RuntimeRegisters,
287    db_regs: *mut u32,
288    caplength: u8,
289    max_ports: usize,
290    ports: Vec<XhciPort>,
291    device_ctx: *mut u8,
292    device_ctx_phys: u64,
293    cmd_ring: *mut Trb,
294    cmd_ring_phys: u64,
295    cmd_ring_deq: usize,
296    cmd_ring_cycle: bool,
297    event_ring: *mut Trb,
298    event_ring_phys: u64,
299    event_ring_deq: AtomicUsize,
300    event_ring_cycle: AtomicBool,
301    slot_id: AtomicU8,
302    ctrl_transfer_buf: *mut u8,
303    ctrl_transfer_buf_phys: u64,
304    device_slots: Vec<Option<DeviceSlot>>,
305}
306
307unsafe impl Send for XhciController {}
308unsafe impl Sync for XhciController {}
309
310impl XhciController {
311    pub unsafe fn new(pci_dev: pci::PciDevice) -> Result<Self, &'static str> {
312        let bar = match pci_dev.read_bar(0) {
313            Some(Bar::Memory64 { addr, .. }) => addr,
314            Some(Bar::Memory32 { addr, .. }) => addr as u64,
315            _ => {
316                unsafe {
317                    // 'z' + 'B' = BAR invalid
318                    core::arch::asm!("out 0xe9, al", in("al") b'z', options(nomem, nostack));
319                    core::arch::asm!("out 0xe9, al", in("al") b'B', options(nomem, nostack));
320                    core::arch::asm!("out 0xe9, al", in("al") b'\n', options(nomem, nostack));
321                }
322                return Err("Invalid BAR");
323            }
324        };
325        unsafe {
326            core::arch::asm!("out 0xe9, al", in("al") b'z', options(nomem, nostack));
327            core::arch::asm!("out 0xe9, al", in("al") b'b', options(nomem, nostack));
328            let hex = b"0123456789abcdef";
329            let a = bar;
330            for sh in [28usize, 24, 20, 16, 12, 8, 4, 0] {
331                let nib = hex[((a >> sh) & 0xF) as usize];
332                core::arch::asm!("out 0xe9, al", in("al") nib, options(nomem, nostack));
333            }
334            // Dump the PCI location + raw BAR0 value: bdf raw
335            let bdf = pci_dev.address;
336            core::arch::asm!("out 0xe9, al", in("al") b'@', options(nomem, nostack));
337            let raw = pci_dev.read_bar_raw(0).unwrap_or(0xFFFF_FFFF);
338            for sh in [28usize, 24, 20, 16, 12, 8, 4, 0] {
339                let nib = hex[((raw >> sh) & 0xF) as usize];
340                core::arch::asm!("out 0xe9, al", in("al") nib, options(nomem, nostack));
341            }
342            let _ = bdf;
343            core::arch::asm!("out 0xe9, al", in("al") b'\n', options(nomem, nostack));
344        }
345        paging::ensure_identity_map_range(bar, XHCI_MMIO_SIZE as u64);
346
347        let mmio_base = phys_to_virt(bar) as usize;
348        let cap_regs = mmio_base as *const CapRegisters;
349        let caplength = (*cap_regs).caplength;
350        let op_regs = (mmio_base + caplength as usize) as *mut OpRegisters;
351
352        let dboff = (*cap_regs).dboff;
353        let db_regs = (mmio_base + dboff as usize) as *mut u32;
354
355        let rtsoff = (*cap_regs).rtsoff;
356        let rt_regs = (mmio_base + rtsoff as usize) as *mut RuntimeRegisters;
357
358        let max_ports = (((*cap_regs).hcsparams1 >> 24) & 0xFF) as usize;
359
360        let mut controller = Self {
361            mmio_base,
362            cap_regs,
363            op_regs,
364            rt_regs,
365            db_regs,
366            caplength,
367            max_ports,
368            ports: Vec::new(),
369            device_ctx: core::ptr::null_mut(),
370            device_ctx_phys: 0,
371            cmd_ring: core::ptr::null_mut(),
372            cmd_ring_phys: 0,
373            cmd_ring_deq: 0,
374            cmd_ring_cycle: true,
375            event_ring: core::ptr::null_mut(),
376            event_ring_phys: 0,
377            event_ring_deq: AtomicUsize::new(0),
378            event_ring_cycle: AtomicBool::new(true),
379            slot_id: AtomicU8::new(0),
380            ctrl_transfer_buf: core::ptr::null_mut(),
381            ctrl_transfer_buf_phys: 0,
382            device_slots: Vec::new(),
383        };
384
385        controller.init()?;
386        Ok(controller)
387    }
388
389    fn init(&mut self) -> Result<(), &'static str> {
390        unsafe {
391            for _ in 0..100_000 {
392                if self.read_usbsts() & USBSTS_CNR == 0 {
393                    break;
394                }
395                core::hint::spin_loop();
396            }
397            if self.read_usbsts() & USBSTS_CNR != 0 {
398                return Err("xHCI: controller not ready (CNR)");
399            }
400
401            let mut usbcmd = self.read_usbcmd();
402            usbcmd &= !USBCMD_RUN_STOP;
403            self.write_usbcmd(usbcmd);
404            for _ in 0..100_000 {
405                if self.read_usbsts() & USBSTS_HCH != 0 {
406                    break;
407                }
408                core::hint::spin_loop();
409            }
410            if self.read_usbsts() & USBSTS_HCH == 0 {
411                return Err("xHCI: controller did not halt");
412            }
413
414            self.write_usbcmd(self.read_usbcmd() | USBCMD_HCRST);
415            for _ in 0..100_000 {
416                if self.read_usbcmd() & USBCMD_HCRST == 0 {
417                    break;
418                }
419                core::hint::spin_loop();
420            }
421            if self.read_usbcmd() & USBCMD_HCRST != 0 {
422                return Err("xHCI: controller reset timed out");
423            }
424            let mut cnr_timeout = 1_000_000u32;
425            while self.read_usbsts() & USBSTS_CNR != 0 {
426                if cnr_timeout == 0 {
427                    return Err("xHCI: CNR did not clear after reset");
428                }
429                cnr_timeout -= 1;
430                core::hint::spin_loop();
431            }
432
433            for i in 0..self.max_ports {
434                let portsc = self.read_portsc(i);
435                self.ports.push(XhciPort {
436                    port_num: i,
437                    enabled: (portsc & PORTSC_PED) != 0,
438                    connected: (portsc & PORTSC_CCS) != 0,
439                    speed: ((portsc >> PORTSC_SPEED_SHIFT) & 0xF) as u8,
440                });
441            }
442
443            self.init_rings()?;
444            self.init_interrupter()?;
445            self.init_ctrl_transfer_buf()?;
446
447            let max_slots = self.max_device_slots();
448            self.write_config(max_slots);
449            self.write_usbcmd(self.read_usbcmd() | USBCMD_RUN_STOP | USBCMD_INTE);
450
451            self.enumerate_all_ports();
452        }
453        Ok(())
454    }
455
456    unsafe fn init_rings(&mut self) -> Result<(), &'static str> {
457        let cmd_frame = allocate_zeroed_frame().ok_or("Failed to allocate cmd ring")?;
458        self.cmd_ring_phys = cmd_frame.start_address.as_u64();
459        self.cmd_ring = phys_to_virt(self.cmd_ring_phys) as *mut Trb;
460        core::ptr::write_bytes(self.cmd_ring as *mut u8, 0, 4096);
461        core::ptr::write(
462            self.cmd_ring.add(XHCI_RING_TRBS - 1),
463            Trb::link(self.cmd_ring_phys, true),
464        );
465        self.write_crcr(self.cmd_ring_phys | 1);
466
467        let event_frame = allocate_zeroed_frame().ok_or("Failed to allocate event ring")?;
468        self.event_ring_phys = event_frame.start_address.as_u64();
469        self.event_ring = phys_to_virt(self.event_ring_phys) as *mut Trb;
470        core::ptr::write_bytes(self.event_ring as *mut u8, 0, 4096);
471
472        let dev_frame = allocate_zeroed_frame().ok_or("Failed to allocate DCBAA")?;
473        self.device_ctx_phys = dev_frame.start_address.as_u64();
474        self.device_ctx = phys_to_virt(self.device_ctx_phys) as *mut u8;
475        core::ptr::write_bytes(self.device_ctx, 0, 4096);
476        self.write_dcbaap(self.device_ctx_phys);
477
478        Ok(())
479    }
480
481    unsafe fn init_interrupter(&mut self) -> Result<(), &'static str> {
482        let erst_frame = allocate_zeroed_frame().ok_or("Failed to allocate ERST")?;
483        let erst_phys = erst_frame.start_address.as_u64();
484        let erst_virt = phys_to_virt(erst_phys) as *mut u64;
485        core::ptr::write_bytes(erst_virt as *mut u8, 0, 4096);
486
487        let erst_entry = erst_virt as *mut u8;
488        let addr_bytes = self.event_ring_phys.to_le_bytes();
489        core::ptr::copy_nonoverlapping(addr_bytes.as_ptr(), erst_entry, 8);
490        let seg_size: u32 = XHCI_RING_TRBS as u32;
491        let size_bytes = seg_size.to_le_bytes();
492        core::ptr::copy_nonoverlapping(size_bytes.as_ptr(), erst_entry.add(8), 4);
493
494        let ir = &mut (*self.rt_regs).ir[0];
495        write_volatile(core::ptr::addr_of_mut!(ir.erstsz), 1);
496        core::sync::atomic::fence(core::sync::atomic::Ordering::SeqCst);
497        write_volatile(core::ptr::addr_of_mut!(ir.erstba), erst_phys);
498        write_volatile(core::ptr::addr_of_mut!(ir.erdp), self.event_ring_phys);
499        write_volatile(core::ptr::addr_of_mut!(ir.iman), 3);
500
501        Ok(())
502    }
503
504    unsafe fn init_ctrl_transfer_buf(&mut self) -> Result<(), &'static str> {
505        let buf_frame = allocate_zeroed_frame().ok_or("Failed to allocate ctrl buf")?;
506        self.ctrl_transfer_buf_phys = buf_frame.start_address.as_u64();
507        self.ctrl_transfer_buf = phys_to_virt(self.ctrl_transfer_buf_phys) as *mut u8;
508        core::ptr::write_bytes(self.ctrl_transfer_buf, 0, 4096);
509        Ok(())
510    }
511
512    unsafe fn read_portsc(&self, port: usize) -> u32 {
513        let port_offset = XHCI_PORT_REG_BASE + (port * XHCI_PORT_REG_STRIDE);
514        let portsc_ptr = (self.op_regs as *const u8).add(port_offset) as *const u32;
515        portsc_ptr.read_volatile()
516    }
517
518    unsafe fn write_portsc(&self, port: usize, val: u32) {
519        let port_offset = XHCI_PORT_REG_BASE + (port * XHCI_PORT_REG_STRIDE);
520        let portsc_ptr = (self.op_regs as *const u8).add(port_offset) as *mut u32;
521        portsc_ptr.write_volatile(val);
522    }
523
524    unsafe fn read_usbcmd(&self) -> u32 {
525        read_volatile(core::ptr::addr_of!((*self.op_regs).usbcmd))
526    }
527
528    unsafe fn write_usbcmd(&self, value: u32) {
529        write_volatile(core::ptr::addr_of_mut!((*self.op_regs).usbcmd), value);
530    }
531
532    unsafe fn read_usbsts(&self) -> u32 {
533        read_volatile(core::ptr::addr_of!((*self.op_regs).usbsts))
534    }
535
536    unsafe fn write_crcr(&self, value: u64) {
537        write_volatile(core::ptr::addr_of_mut!((*self.op_regs).crcr), value);
538    }
539
540    unsafe fn write_dcbaap(&self, value: u64) {
541        write_volatile(core::ptr::addr_of_mut!((*self.op_regs).dcbaap), value);
542    }
543
544    unsafe fn write_config(&self, value: u32) {
545        write_volatile(core::ptr::addr_of_mut!((*self.op_regs).config), value);
546    }
547
548    fn max_device_slots(&self) -> u32 {
549        unsafe { read_volatile(core::ptr::addr_of!((*self.cap_regs).hcsparams1)) & 0xFF }
550    }
551
552    fn max_ports_from_hw(&self) -> u32 {
553        unsafe { (read_volatile(core::ptr::addr_of!((*self.cap_regs).hcsparams1)) >> 24) & 0xFF }
554    }
555
556    unsafe fn cmd_ring_enqueue(&mut self, trb: Trb) {
557        let idx = self.cmd_ring_deq;
558        let mut trb = trb;
559        if self.cmd_ring_cycle {
560            trb.d3 |= TRB_CYCLE;
561        } else {
562            trb.d3 &= !TRB_CYCLE;
563        }
564        core::ptr::write_volatile(self.cmd_ring.add(idx), trb);
565        self.cmd_ring_deq = idx + 1;
566
567        if self.cmd_ring_deq >= 63 {
568            let link = Trb::link(self.cmd_ring_phys, true);
569            let mut link_trb = link;
570            if self.cmd_ring_cycle {
571                link_trb.d3 |= TRB_CYCLE;
572            } else {
573                link_trb.d3 &= !TRB_CYCLE;
574            }
575            core::ptr::write_volatile(self.cmd_ring.add(63), link_trb);
576            self.cmd_ring_deq = 0;
577            self.cmd_ring_cycle = !self.cmd_ring_cycle;
578        }
579
580        core::sync::atomic::fence(core::sync::atomic::Ordering::SeqCst);
581        core::ptr::write_volatile(self.db_regs.add(0), 0);
582    }
583
584    unsafe fn wait_for_event(&mut self) -> Result<Trb, &'static str> {
585        for _ in 0..1000000 {
586            let idx = self.event_ring_deq.load(Ordering::Acquire);
587            let trb = core::ptr::read_volatile(self.event_ring.add(idx));
588
589            let expected_c = if self.event_ring_cycle.load(Ordering::Acquire) {
590                TRB_CYCLE
591            } else {
592                0
593            };
594            if (trb.d3 & TRB_CYCLE) == expected_c {
595                let new_deq = (idx + 1) % 64;
596                self.event_ring_deq.store(new_deq, Ordering::Release);
597                if new_deq == 0 {
598                    self.event_ring_cycle.store(
599                        !self.event_ring_cycle.load(Ordering::Acquire),
600                        Ordering::Release,
601                    );
602                }
603                let ir = &mut (*self.rt_regs).ir[0];
604                ir.erdp = (self.event_ring_phys + (new_deq as u64) * 16) | (1 << 3);
605                return Ok(trb);
606            }
607            core::hint::spin_loop();
608        }
609        Err("Event timeout")
610    }
611
612    unsafe fn ring_doorbell(&self, slot_id: u8, endpoint: u8) {
613        let db_index = (slot_id as usize) * 32 + (endpoint as usize);
614        core::ptr::write_volatile(self.db_regs.add(db_index), 0);
615    }
616
617    unsafe fn alloc_input_context(&mut self, slot_id: u8) -> Result<(), &'static str> {
618        let frame = allocate_zeroed_frame().ok_or("Failed to allocate input context")?;
619        let phys = frame.start_address.as_u64();
620        let virt = phys_to_virt(phys) as *mut InputContext;
621
622        let idx = slot_id as usize;
623        if idx >= self.device_slots.len() {
624            self.device_slots.resize_with(idx + 1, || None);
625        }
626        let dev = self.device_slots[idx].as_mut().unwrap();
627        dev.input_ctx = virt;
628        dev.input_ctx_phys = phys;
629
630        let dcbaa = self.device_ctx as *mut u64;
631        dcbaa.add(idx as usize).write_volatile(phys);
632
633        Ok(())
634    }
635
636    unsafe fn alloc_transfer_ring(
637        &mut self,
638        slot_id: u8,
639        endpoint: u8,
640    ) -> Result<(), &'static str> {
641        let frame = allocate_zeroed_frame().ok_or("Failed to allocate transfer ring")?;
642        let phys = frame.start_address.as_u64();
643        let virt = phys_to_virt(phys) as *mut Trb;
644
645        core::ptr::write_bytes(virt as *mut u8, 0, 4096);
646        core::ptr::write(virt.add(XHCI_RING_TRBS - 1), Trb::link(phys, true));
647
648        let idx = slot_id as usize;
649        if idx < self.device_slots.len() {
650            if let Some(ref mut dev) = self.device_slots[idx] {
651                let ep = endpoint as usize;
652                if ep < MAX_ENDPOINTS {
653                    dev.ep_transfer_rings[ep] = virt;
654                    dev.ep_transfer_ring_phys[ep] = phys;
655                    dev.ep_dequeue[ep] = 0;
656                    dev.ep_cycle[ep] = true;
657                }
658            }
659        }
660        Ok(())
661    }
662
663    unsafe fn write_endpoint_context(
664        &self,
665        slot_id: u8,
666        endpoint: u8,
667        tr_phys: u64,
668        max_packet: u32,
669        ep_type: u32,
670        interval: u32,
671    ) {
672        let dcbaa = self.device_ctx as *mut u64;
673        let ctx_addr = dcbaa.add(slot_id as usize).read_volatile() as *mut u8;
674        if ctx_addr.is_null() {
675            return;
676        }
677
678        let ep_offset = 32 * ((endpoint - 1) as usize) + 32;
679        let ep_ctx = ctx_addr.add(ep_offset) as *mut EndpointContext;
680
681        let d0 = (ep_type & 0x7) << 3 | 0;
682        let d1 = (max_packet & 0x7FF) | (0 << 16);
683        let d2 = (tr_phys & 0xFFFFFFFF) as u32;
684        let d3 = ((tr_phys >> 32) & 0xFFFFFFFF) as u32;
685        let d4 = interval & 0xFF;
686
687        (*ep_ctx).d0 = d0;
688        (*ep_ctx).d1 = d1;
689        (*ep_ctx).d2 = d2;
690        (*ep_ctx).d3 = d3;
691        (*ep_ctx).d4 = d4;
692        (*ep_ctx).d5 = 0;
693        (*ep_ctx).d6 = 0;
694        (*ep_ctx).d7 = 0;
695    }
696
697    unsafe fn reset_port(&self, port: usize) -> bool {
698        let mut portsc = self.read_portsc(port);
699        if portsc & PORTSC_CCS == 0 {
700            return false;
701        }
702
703        portsc = self.read_portsc(port);
704        self.write_portsc(port, portsc | PORTSC_PR);
705
706        for _ in 0..500_000 {
707            portsc = self.read_portsc(port);
708            if portsc & PORTSC_PR == 0 {
709                break;
710            }
711            core::hint::spin_loop();
712        }
713
714        for _ in 0..500_000 {
715            portsc = self.read_portsc(port);
716            if portsc & PORTSC_PED != 0 {
717                return true;
718            }
719            if portsc & PORTSC_CCS == 0 {
720                return false;
721            }
722            core::hint::spin_loop();
723        }
724
725        self.read_portsc(port) & PORTSC_PED != 0
726    }
727
728    fn enable_slot(&mut self) -> Result<u8, &'static str> {
729        unsafe {
730            self.cmd_ring_enqueue(Trb {
731                d0: 0,
732                d1: 0,
733                d2: 0,
734                d3: (TRB_TYPE_ENABLE_SLOT << TRB_TYPE_SHIFT) as u32,
735            });
736
737            let event = self.wait_for_event()?;
738            let completion_code = (event.d2 >> 24) & 0xFF;
739            if completion_code != 1 {
740                log::warn!("[xHCI] Enable Slot failed: completion={}", completion_code);
741                return Err("Enable slot failed");
742            }
743            let slot_id = ((event.d3 >> 24) & 0xFF) as u8;
744            if slot_id == 0 {
745                return Err("No slot available");
746            }
747            self.slot_id.store(slot_id, Ordering::SeqCst);
748
749            let idx = slot_id as usize;
750            if idx >= self.device_slots.len() {
751                self.device_slots.resize_with(idx + 1, || None);
752            }
753            self.device_slots[idx] = Some(DeviceSlot::new(slot_id));
754
755            self.alloc_input_context(slot_id)?;
756            self.alloc_transfer_ring(slot_id, 1)?;
757
758            let slot_ctx = &mut (*self.device_slots[idx].as_ref().unwrap().input_ctx).slot;
759            slot_ctx.d0 = (1 << 27) | (slot_id as u32);
760            slot_ctx.d1 = 0;
761            slot_ctx.d2 = 0;
762
763            self.write_endpoint_context(
764                slot_id,
765                1,
766                self.device_slots[idx]
767                    .as_ref()
768                    .unwrap()
769                    .ep_transfer_ring_phys[1],
770                8,
771                EP_TYPE_CONTROL,
772                0,
773            );
774
775            log::info!("[xHCI] Enable Slot: slot_id={}", slot_id);
776            Ok(slot_id)
777        }
778    }
779
780    fn set_address(&mut self, slot_id: u8, address: u8) -> Result<(), &'static str> {
781        unsafe {
782            let idx = slot_id as usize;
783            if idx >= self.device_slots.len() || self.device_slots[idx].is_none() {
784                return Err("Invalid slot for Address Device");
785            }
786
787            let input_ctx_phys = self.device_slots[idx].as_ref().unwrap().input_ctx_phys;
788
789            let slot_ctx = &mut (*self.device_slots[idx].as_ref().unwrap().input_ctx).slot;
790            slot_ctx.d0 = (1 << 27) | (address as u32);
791            slot_ctx.d1 = 0;
792            slot_ctx.d2 = 0;
793
794            self.cmd_ring_enqueue(Trb {
795                d0: (input_ctx_phys & 0xFFFFFFFF) as u32,
796                d1: ((input_ctx_phys >> 32) & 0xFFFFFFFF) as u32,
797                d2: (slot_id as u32) << 24,
798                d3: (TRB_TYPE_ADDRESS_DEVICE << TRB_TYPE_SHIFT) as u32,
799            });
800
801            let event = self.wait_for_event()?;
802            let completion = (event.d2 >> 24) & 0xFF;
803            if completion != 1 {
804                unsafe {
805                    core::arch::asm!("out 0xe9, al", in("al") b'z', options(nomem, nostack));
806                    core::arch::asm!("out 0xe9, al", in("al") b'3', options(nomem, nostack));
807                    core::arch::asm!("out 0xe9, al", in("al") (b'0' + (completion & 0xF) as u8), options(nomem, nostack));
808                    core::arch::asm!("out 0xe9, al", in("al") b'\n', options(nomem, nostack));
809                }
810                log::warn!(
811                    "[xHCI] Address Device failed: slot={} completion={}",
812                    slot_id,
813                    completion
814                );
815                return Err("Set address failed");
816            }
817
818            self.device_slots[idx].as_mut().unwrap().usb_address = address;
819            log::info!("[xHCI] Address Device: slot={} addr={}", slot_id, address);
820        }
821        Ok(())
822    }
823
824    pub fn setup_endpoint(
825        &mut self,
826        slot_id: u8,
827        endpoint: u8,
828        max_packet: u32,
829        ep_type: u32,
830        interval: u32,
831        _max_burst: u32,
832    ) -> Result<(), &'static str> {
833        unsafe {
834            let idx = slot_id as usize;
835            if idx >= self.device_slots.len() || self.device_slots[idx].is_none() {
836                return Err("Invalid slot for Setup Endpoint");
837            }
838
839            self.alloc_transfer_ring(slot_id, endpoint)?;
840
841            self.write_endpoint_context(
842                slot_id,
843                endpoint,
844                self.device_slots[idx]
845                    .as_ref()
846                    .unwrap()
847                    .ep_transfer_ring_phys[endpoint as usize],
848                max_packet,
849                ep_type,
850                interval,
851            );
852
853            let input_ctx_phys = self.device_slots[idx].as_ref().unwrap().input_ctx_phys;
854
855            self.cmd_ring_enqueue(Trb {
856                d0: (input_ctx_phys & 0xFFFFFFFF) as u32,
857                d1: ((input_ctx_phys >> 32) & 0xFFFFFFFF) as u32,
858                d2: (slot_id as u32) << 24,
859                d3: (TRB_TYPE_CONFIGURE_ENDPOINT << TRB_TYPE_SHIFT) as u32,
860            });
861
862            let event = self.wait_for_event()?;
863            let completion = (event.d2 >> 24) & 0xFF;
864            if completion != 1 {
865                log::warn!(
866                    "[xHCI] Configure Endpoint failed: slot={} ep={} completion={}",
867                    slot_id,
868                    endpoint,
869                    completion
870                );
871                return Err("Configure endpoint failed");
872            }
873
874            log::info!(
875                "[xHCI] Endpoint configured: slot={} ep={} type={}",
876                slot_id,
877                endpoint,
878                ep_type
879            );
880        }
881        Ok(())
882    }
883
884    fn enumerate_all_ports(&mut self) {
885        unsafe {
886            core::arch::asm!("out 0xe9, al", in("al") b'x', options(nomem, nostack));
887            core::arch::asm!("out 0xe9, al", in("al") b"0123456789abcdef"[((self.max_ports >> 4) & 0xF) as usize], options(nomem, nostack));
888            core::arch::asm!("out 0xe9, al", in("al") b"0123456789abcdef"[(self.max_ports & 0xF) as usize], options(nomem, nostack));
889            core::arch::asm!("out 0xe9, al", in("al") b'\n', options(nomem, nostack));
890        }
891        let mut usb_address: u8 = 1;
892
893        for port in 0..self.max_ports {
894            let portsc = unsafe { self.read_portsc(port) };
895            let connected = (portsc & PORTSC_CCS) != 0;
896            if !connected {
897                continue;
898            }
899            unsafe {
900                core::arch::asm!("out 0xe9, al", in("al") b'e', options(nomem, nostack));
901                core::arch::asm!("out 0xe9, al", in("al") (b'0' + port as u8), options(nomem, nostack));
902                let psc = portsc;
903                for sh in [28usize, 24, 20, 16, 12, 8, 4, 0] {
904                    let nib = b"0123456789abcdef"[((psc >> sh) & 0xF) as usize];
905                    core::arch::asm!("out 0xe9, al", in("al") nib, options(nomem, nostack));
906                }
907                core::arch::asm!("out 0xe9, al", in("al") b'\n', options(nomem, nostack));
908            }
909
910            // NOTE: log::info! (formatted) hung the enumeration path in some
911            // builds (known format_args vtable issue) : keep it OUT of the
912            // hot enumeration loop; E9 marks carry the trace instead.
913
914            if !unsafe { self.reset_port(port) } {
915                unsafe {
916                    core::arch::asm!("out 0xe9, al", in("al") b'z', options(nomem, nostack));
917                    core::arch::asm!("out 0xe9, al", in("al") b'4', options(nomem, nostack));
918                    let portsc = self.read_portsc(port);
919                    core::arch::asm!("out 0xe9, al", in("al") b"0123456789abcdef"[((portsc >> 28) & 0xF) as usize], options(nomem, nostack));
920                    core::arch::asm!("out 0xe9, al", in("al") b"0123456789abcdef"[((portsc >> 24) & 0xF) as usize], options(nomem, nostack));
921                    core::arch::asm!("out 0xe9, al", in("al") b"0123456789abcdef"[((portsc >> 4) & 0xF) as usize], options(nomem, nostack));
922                    core::arch::asm!("out 0xe9, al", in("al") b"0123456789abcdef"[(portsc & 0xF) as usize], options(nomem, nostack));
923                    core::arch::asm!("out 0xe9, al", in("al") b'\n', options(nomem, nostack));
924                }
925                log::warn!("[xHCI] Port {} reset failed", port);
926                continue;
927            }
928            unsafe {
929                core::arch::asm!("out 0xe9, al", in("al") b'z', options(nomem, nostack));
930                core::arch::asm!("out 0xe9, al", in("al") b'R', options(nomem, nostack));
931                core::arch::asm!("out 0xe9, al", in("al") b'\n', options(nomem, nostack));
932            }
933            unsafe {
934                core::arch::asm!("out 0xe9, al", in("al") b'R', options(nomem, nostack));
935            }
936
937            let speed = unsafe { ((self.read_portsc(port) >> PORTSC_SPEED_SHIFT) & 0xF) as u8 };
938            log::info!("[xHCI] Port {} speed={}", port, speed);
939
940            match self.enable_slot() {
941                Ok(slot_id) => {
942                    unsafe {
943                        core::arch::asm!("out 0xe9, al", in("al") b'S', options(nomem, nostack));
944                    }
945                    if self.set_address(slot_id, usb_address).is_err() {
946                        log::warn!("[xHCI] Port {} address failed", port);
947                        continue;
948                    }
949                    usb_address += 1;
950                    unsafe {
951                        core::arch::asm!("out 0xe9, al", in("al") b'A', options(nomem, nostack));
952                    }
953
954                    let mut dev_desc = [0u8; 18];
955                    if self.get_device_descriptor(slot_id, &mut dev_desc).is_ok() {
956                        // TEMP DEBUG: dump the 18-byte descriptor as hex + a leading 'G'.
957                        unsafe {
958                            core::arch::asm!("out 0xe9, al", in("al") b'G', options(nomem, nostack));
959                            let mut k = 0;
960                            while k < 18 {
961                                let b = dev_desc[k];
962                                let hi = b"0123456789abcdef"[(b >> 4) as usize];
963                                let lo = b"0123456789abcdef"[(b & 0xF) as usize];
964                                core::arch::asm!("out 0xe9, al", in("al") hi, options(nomem, nostack));
965                                core::arch::asm!("out 0xe9, al", in("al") lo, options(nomem, nostack));
966                                k += 1;
967                            }
968                            core::arch::asm!("out 0xe9, al", in("al") b'\n', options(nomem, nostack));
969                        }
970                        let vid = u16::from_le_bytes([dev_desc[2], dev_desc[3]]);
971                        let pid = u16::from_le_bytes([dev_desc[4], dev_desc[5]]);
972                        let dev_class = dev_desc[4];
973                        let max_packet0 = u16::from_le_bytes([dev_desc[7], dev_desc[8]]);
974                        log::info!(
975                            "[xHCI] Device: VID={:04x} PID={:04x} class={:02x} max_pkt0={}",
976                            vid,
977                            pid,
978                            dev_class,
979                            max_packet0
980                        );
981
982                        if max_packet0 == 64
983                            || max_packet0 == 32
984                            || max_packet0 == 16
985                            || max_packet0 == 8
986                        {
987                            let idx = slot_id as usize;
988                            if idx < self.device_slots.len() {
989                                if let Some(ref mut dev) = self.device_slots[idx] {
990                                    dev.configured = true;
991                                }
992                            }
993                            // Update EP0's MaxPacketSize0 to the real value
994                            // SAFETY: slot_id is valid, endpoint context array is mapped
995                            unsafe {
996                                self.write_endpoint_context(
997                                    slot_id,
998                                    1,
999                                    self.device_slots[idx]
1000                                        .as_ref()
1001                                        .unwrap()
1002                                        .ep_transfer_ring_phys[1],
1003                                    max_packet0 as u32,
1004                                    EP_TYPE_CONTROL,
1005                                    0,
1006                                );
1007                            }
1008                        }
1009
1010                        crate::hardware::usb::hid::enumerate_device(port, slot_id, &dev_desc);
1011                    } else {
1012                        log::warn!("[xHCI] Port {} get device descriptor failed", port);
1013                    }
1014                }
1015                Err(e) => {
1016                    log::warn!("[xHCI] Port {} enable slot failed: {}", port, e);
1017                }
1018            }
1019        }
1020    }
1021
1022    pub fn alloc_interrupt_buffer(
1023        &mut self,
1024        slot_id: u8,
1025        endpoint: u8,
1026        len: usize,
1027    ) -> Result<(*mut u8, u64), &'static str> {
1028        let frame = allocate_zeroed_frame().ok_or("Failed to allocate interrupt buffer")?;
1029        let phys = frame.start_address.as_u64();
1030        let virt = phys_to_virt(phys) as *mut u8;
1031
1032        let idx = slot_id as usize;
1033        if idx < self.device_slots.len() {
1034            if let Some(ref mut dev) = self.device_slots[idx] {
1035                let ep = endpoint as usize;
1036                if ep < MAX_ENDPOINTS {
1037                    dev.ep_buf[ep] = virt;
1038                    dev.ep_buf_phys[ep] = phys;
1039                    dev.ep_buf_len[ep] = len;
1040                }
1041            }
1042        }
1043        Ok((virt, phys))
1044    }
1045
1046    pub fn submit_interrupt_transfer(
1047        &mut self,
1048        slot_id: u8,
1049        endpoint: u8,
1050    ) -> Result<(), &'static str> {
1051        let idx = slot_id as usize;
1052        if idx >= self.device_slots.len() || self.device_slots[idx].is_none() {
1053            return Err("Invalid slot for interrupt transfer");
1054        }
1055
1056        let ep = endpoint as usize;
1057        if ep >= MAX_ENDPOINTS {
1058            return Err("Invalid endpoint");
1059        }
1060
1061        let dev = self.device_slots[idx].as_ref().unwrap();
1062        let tr_ring = dev.ep_transfer_rings[ep];
1063        let _tr_phys = dev.ep_transfer_ring_phys[ep];
1064        let buf_phys = dev.ep_buf_phys[ep];
1065        let buf_len = dev.ep_buf_len[ep];
1066        if tr_ring.is_null() || buf_phys == 0 {
1067            return Err("No transfer ring or buffer for endpoint");
1068        }
1069
1070        let deq = dev.ep_dequeue[ep];
1071        let cycle = dev.ep_cycle[ep];
1072
1073        let trb = Trb::normal(buf_phys, buf_len as u32, cycle, true);
1074        unsafe {
1075            core::ptr::write_volatile(tr_ring.add(deq), trb);
1076            core::sync::atomic::fence(core::sync::atomic::Ordering::SeqCst);
1077            self.ring_doorbell(slot_id, endpoint);
1078        }
1079
1080        self.device_slots[idx].as_mut().unwrap().ep_active[ep] = true;
1081
1082        Ok(())
1083    }
1084
1085    pub fn port_count(&self) -> usize {
1086        self.max_ports
1087    }
1088
1089    pub fn is_port_connected(&self, port: usize) -> bool {
1090        if port >= self.ports.len() {
1091            return false;
1092        }
1093        self.ports[port].connected
1094    }
1095
1096    pub fn get_device_descriptor(
1097        &mut self,
1098        slot_id: u8,
1099        buf: &mut [u8; 18],
1100    ) -> Result<usize, &'static str> {
1101        let setup = [0x80, 0x06, 0x00, 0x01, 0x00, 0x00, 18, 0x00];
1102        unsafe { self.ctrl_transfer(slot_id, &setup, Some(buf), 18) }
1103    }
1104
1105    pub fn get_configuration_descriptor(
1106        &mut self,
1107        slot_id: u8,
1108        config_idx: u8,
1109        buf: &mut [u8],
1110        len: usize,
1111    ) -> Result<usize, &'static str> {
1112        let setup = [
1113            0x80,
1114            0x06,
1115            config_idx,
1116            0x02,
1117            0x00,
1118            0x00,
1119            (len & 0xFF) as u8,
1120            ((len >> 8) & 0xFF) as u8,
1121        ];
1122        unsafe { self.ctrl_transfer(slot_id, &setup, Some(buf), len) }
1123    }
1124
1125    pub fn set_configuration(&mut self, slot_id: u8, config_value: u8) -> Result<(), &'static str> {
1126        let setup = [0x00, 0x09, config_value, 0x00, 0x00, 0x00, 0x00, 0x00];
1127        unsafe {
1128            self.ctrl_transfer(slot_id, &setup, None, 0)?;
1129        }
1130        Ok(())
1131    }
1132
1133    pub fn set_protocol(
1134        &mut self,
1135        slot_id: u8,
1136        interface: u8,
1137        protocol: u8,
1138    ) -> Result<(), &'static str> {
1139        let setup = [0x21, 0x0B, protocol, interface, 0x00, 0x00, 0x00, 0x00];
1140        unsafe {
1141            self.ctrl_transfer(slot_id, &setup, None, 0)?;
1142        }
1143        Ok(())
1144    }
1145
1146    pub fn get_port_speed(&self, port: usize) -> u8 {
1147        if port >= self.ports.len() {
1148            return 0;
1149        }
1150        self.ports[port].speed
1151    }
1152
1153    unsafe fn ctrl_transfer(
1154        &mut self,
1155        slot_id: u8,
1156        setup_data: &[u8; 8],
1157        data_buf: Option<&mut [u8]>,
1158        data_len: usize,
1159    ) -> Result<usize, &'static str> {
1160        unsafe {
1161            // TEMP DEBUG: distinct marker (was 'V', collided with boot_alloc).
1162            core::arch::asm!("out 0xe9, al", in("al") b'U', options(nomem, nostack));
1163        }
1164        let idx = slot_id as usize;
1165        if idx >= self.device_slots.len() || self.device_slots[idx].is_none() {
1166            unsafe {
1167                core::arch::asm!("out 0xe9, al", in("al") b'1', options(nomem, nostack));
1168                core::arch::asm!("out 0xe9, al", in("al") b'\n', options(nomem, nostack));
1169            }
1170            return Err("Invalid slot for control transfer");
1171        }
1172
1173        let dev = self.device_slots[idx].as_ref().unwrap();
1174        let tr_ring = dev.ep_transfer_rings[1];
1175        let tr_phys = dev.ep_transfer_ring_phys[1];
1176        if tr_ring.is_null() {
1177            unsafe {
1178                core::arch::asm!("out 0xe9, al", in("al") b'2', options(nomem, nostack));
1179                core::arch::asm!("out 0xe9, al", in("al") b'\n', options(nomem, nostack));
1180            }
1181            return Err("No transfer ring for EP0");
1182        }
1183
1184        let mut deq;
1185        // The controller toggles its expected cycle bit every time it wraps
1186        // through the LINK TRB. Reusing TRB slots 0..2 with the same cycle
1187        // bit as the previous transfer makes the controller ignore them
1188        // (cycle mismatch -> "Event timeout"). Toggle the saved cycle bit
1189        // instead of resetting it to `true` every time.
1190        let cycle = !dev.ep_cycle[1];
1191        let deq_start = dev.ep_dequeue[1] as usize;
1192
1193        // Zero exactly the TRBs this transfer will use, starting from the
1194        // controller's current dequeue position, and refresh the LINK TRB
1195        // with the toggled cycle so the controller wraps correctly.
1196        for i in 0..3 {
1197            core::ptr::write_volatile(
1198                tr_ring.add((deq_start + i) % XHCI_RING_TRBS),
1199                Trb {
1200                    d0: 0,
1201                    d1: 0,
1202                    d2: 0,
1203                    d3: 0,
1204                },
1205            );
1206        }
1207        core::ptr::write_volatile(tr_ring.add(XHCI_RING_TRBS - 1), Trb::link(tr_phys, cycle));
1208        deq = deq_start;
1209
1210        let setup_phys = self.ctrl_transfer_buf_phys;
1211        let setup_virt = self.ctrl_transfer_buf;
1212        core::ptr::copy_nonoverlapping(setup_data.as_ptr(), setup_virt, 8);
1213
1214        let setup_trb = Trb::setup_stage(setup_phys, cycle);
1215        core::ptr::write_volatile(tr_ring.add(deq), setup_trb);
1216        deq += 1;
1217
1218        let has_data = data_buf.is_some();
1219        let dir_in = if has_data {
1220            (setup_data[0] & 0x80) != 0
1221        } else {
1222            false
1223        };
1224
1225        if let Some(buf) = &data_buf {
1226            let data_phys = self.ctrl_transfer_buf_phys + 8;
1227            let data_virt = self.ctrl_transfer_buf.add(8);
1228
1229            if dir_in && data_len > 0 {
1230                core::ptr::write_bytes(data_virt, 0, data_len);
1231            } else if !dir_in && data_len > 0 {
1232                core::ptr::copy_nonoverlapping(buf.as_ptr(), data_virt, data_len);
1233            }
1234
1235            let data_trb = Trb::data_stage(data_phys, data_len as u32, dir_in, cycle, false);
1236            core::ptr::write_volatile(tr_ring.add(deq), data_trb);
1237            deq += 1;
1238
1239            let status_trb = Trb::status_stage(cycle, !dir_in);
1240            core::ptr::write_volatile(tr_ring.add(deq), status_trb);
1241            deq += 1;
1242        } else {
1243            let status_trb = Trb::status_stage(cycle, true);
1244            core::ptr::write_volatile(tr_ring.add(deq), status_trb);
1245            deq += 1;
1246        }
1247
1248        core::sync::atomic::fence(core::sync::atomic::Ordering::SeqCst);
1249        self.ring_doorbell(slot_id, 1);
1250        unsafe {
1251            core::arch::asm!("out 0xe9, al", in("al") b'C', options(nomem, nostack));
1252        }
1253
1254        let mut transferred = 0;
1255        let mut seen_status = false;
1256        for _ in 0..16 {
1257            let event = match self.wait_for_event() {
1258                Ok(e) => e,
1259                Err(e) => {
1260                    unsafe {
1261                        core::arch::asm!("out 0xe9, al", in("al") b'X', options(nomem, nostack));
1262                        core::arch::asm!("out 0xe9, al", in("al") e.as_bytes()[0], options(nomem, nostack));
1263                        core::arch::asm!("out 0xe9, al", in("al") b'\n', options(nomem, nostack));
1264                    }
1265                    return Err(e);
1266                }
1267            };
1268            let event_slot = ((event.d3 >> 24) & 0xFF) as u8;
1269            let event_ep = ((event.d2 >> 16) & 0x1F) as u8;
1270
1271            // Skip events not for our control endpoint
1272            if event_slot != slot_id || event_ep != 1 {
1273                continue;
1274            }
1275
1276            let trb_type = trb_get_type(event.d3);
1277            let completion = (event.d2 >> 24) & 0xFF;
1278
1279            if completion != 1 {
1280                unsafe {
1281                    core::arch::asm!("out 0xe9, al", in("al") b'E', options(nomem, nostack));
1282                    core::arch::asm!("out 0xe9, al", in("al") (b'0' + (completion & 0xF) as u8), options(nomem, nostack));
1283                    core::arch::asm!("out 0xe9, al", in("al") b'\n', options(nomem, nostack));
1284                }
1285                log::warn!(
1286                    "[xHCI] ctrl_transfer event error: type={} completion={}",
1287                    trb_type,
1288                    completion
1289                );
1290                return Err("Control transfer event error");
1291            }
1292
1293            if trb_type == TRB_TYPE_STATUS_STAGE {
1294                if has_data && data_len > 0 && dir_in {
1295                    let data_virt = self.ctrl_transfer_buf.add(8);
1296                    if let Some(buf) = data_buf {
1297                        core::ptr::copy_nonoverlapping(data_virt, buf.as_mut_ptr(), data_len);
1298                    }
1299                    transferred = data_len;
1300                }
1301                seen_status = true;
1302                break;
1303            }
1304        }
1305        if !seen_status {
1306            return Err("Control transfer: status event not received");
1307        }
1308
1309        self.device_slots[idx].as_mut().unwrap().ep_dequeue[1] = deq;
1310        self.device_slots[idx].as_mut().unwrap().ep_cycle[1] = cycle;
1311
1312        Ok(transferred)
1313    }
1314}
1315
1316static XHCI_CONTROLLERS: Mutex<Vec<Arc<Mutex<XhciController>>>> = Mutex::new(Vec::new());
1317static XHCI_INITIALIZED: AtomicBool = AtomicBool::new(false);
1318pub static XHCI_IRQ_LINE: AtomicU8 = AtomicU8::new(0);
1319
1320pub fn init() {
1321    log::info!("[xHCI] Scanning for xHCI controllers...");
1322
1323    let candidates = pci::probe_all(ProbeCriteria {
1324        vendor_id: None,
1325        device_id: None,
1326        class_code: Some(0x0C),
1327        subclass: Some(0x03),
1328        prog_if: Some(0x30),
1329    });
1330
1331    for pci_dev in candidates.into_iter() {
1332        log::info!(
1333            "xHCI: Found controller at {:?} (VEN:{:04x} DEV:{:04x})",
1334            pci_dev.address,
1335            pci_dev.vendor_id,
1336            pci_dev.device_id
1337        );
1338
1339        pci_dev.enable_memory_space();
1340        pci_dev.enable_bus_master();
1341
1342        // Try MSI/MSI-X first; fall back to INTx line.
1343        let (irq, vector) = crate::arch::x86_64::msi::probe_and_enable(&pci_dev, true);
1344
1345        match unsafe { XhciController::new(pci_dev) } {
1346            Ok(controller) => {
1347                log::info!("[xHCI] Initialized with {} ports", controller.port_count());
1348                XHCI_IRQ_LINE.store(vector, Ordering::Relaxed);
1349                XHCI_CONTROLLERS
1350                    .lock()
1351                    .push(Arc::new(Mutex::new(controller)));
1352                crate::arch::x86_64::idt::register_xhci_irq_vector(vector);
1353            }
1354            Err(e) => {
1355                log::warn!("xHCI: Failed to initialize controller: {}", e);
1356            }
1357        }
1358    }
1359
1360    XHCI_INITIALIZED.store(true, Ordering::SeqCst);
1361    log::info!(
1362        "[xHCI] Found {} controller(s)",
1363        XHCI_CONTROLLERS.lock().len()
1364    );
1365}
1366
1367pub fn get_controller(index: usize) -> Option<Arc<Mutex<XhciController>>> {
1368    XHCI_CONTROLLERS.lock().get(index).cloned()
1369}
1370
1371pub fn is_available() -> bool {
1372    XHCI_INITIALIZED.load(Ordering::Relaxed) && !XHCI_CONTROLLERS.lock().is_empty()
1373}
1374
1375pub fn handle_interrupt() {
1376    unsafe {
1377        core::arch::asm!("out 0xe9, al", in("al") b'i', options(nomem, nostack));
1378    }
1379    if let Some(controller_arc) = get_controller(0) {
1380        let mut controller = controller_arc.lock();
1381        unsafe {
1382            let ir = &mut (*controller.rt_regs).ir[0];
1383            if (ir.iman & 1) != 0 {
1384                let mut processed = 0;
1385                while processed < 16 {
1386                    let idx = controller.event_ring_deq.load(Ordering::Acquire);
1387                    let trb = core::ptr::read_volatile(controller.event_ring.add(idx));
1388
1389                    let expected_c = if controller.event_ring_cycle.load(Ordering::Acquire) {
1390                        TRB_CYCLE
1391                    } else {
1392                        0
1393                    };
1394                    if (trb.d3 & TRB_CYCLE) != expected_c {
1395                        break;
1396                    }
1397
1398                    let trb_type = trb_get_type(trb.d3);
1399                    match trb_type {
1400                        TRB_TYPE_TRANSFER_EVENT => {
1401                            let slot_id = ((trb.d3 >> 24) & 0xFF) as u8;
1402                            let ep_id = ((trb.d2 >> 16) & 0x1F) as u8;
1403                            let completion = (trb.d2 >> 24) & 0xFF;
1404                            let transferred = (trb.d2 & 0xFFFF) as usize;
1405
1406                            if completion == 1 && ep_id >= 1 && (ep_id as usize) < MAX_ENDPOINTS {
1407                                let idx = slot_id as usize;
1408                                if idx < controller.device_slots.len() {
1409                                    if let Some(ref mut dev) = controller.device_slots[idx] {
1410                                        let ep = ep_id as usize;
1411                                        let buf = dev.ep_buf[ep];
1412                                        let buf_len = dev.ep_buf_len[ep];
1413                                        let actual_len = if transferred < buf_len {
1414                                            transferred
1415                                        } else {
1416                                            buf_len
1417                                        };
1418
1419                                        if !buf.is_null() && actual_len > 0 {
1420                                            // SAFETY: buf/actual_len describe the
1421                                            // transfer buffer filled by the ring.
1422                                            unsafe {
1423                                                crate::hardware::usb::hid::receive_interrupt_report(
1424                                                    slot_id, ep_id, buf, actual_len,
1425                                                );
1426                                            }
1427                                        }
1428
1429                                        dev.ep_dequeue[ep] =
1430                                            (dev.ep_dequeue[ep] + 1) % (XHCI_RING_TRBS - 1);
1431                                        if dev.ep_dequeue[ep] == 0 {
1432                                            dev.ep_cycle[ep] = !dev.ep_cycle[ep];
1433                                        }
1434                                        dev.ep_active[ep] = false;
1435                                    }
1436                                }
1437                            } else if completion != 1 && completion != 13 {
1438                                let idx = slot_id as usize;
1439                                if idx < controller.device_slots.len() {
1440                                    if let Some(ref mut dev) = controller.device_slots[idx] {
1441                                        let ep = ep_id as usize;
1442                                        if ep < MAX_ENDPOINTS {
1443                                            dev.ep_dequeue[ep] =
1444                                                (dev.ep_dequeue[ep] + 1) % (XHCI_RING_TRBS - 1);
1445                                            if dev.ep_dequeue[ep] == 0 {
1446                                                dev.ep_cycle[ep] = !dev.ep_cycle[ep];
1447                                            }
1448                                            dev.ep_active[ep] = false;
1449                                        }
1450                                    }
1451                                }
1452                            }
1453                        }
1454                        _ => {}
1455                    }
1456
1457                    let new_deq = (idx + 1) % 64;
1458                    controller.event_ring_deq.store(new_deq, Ordering::Release);
1459                    if new_deq == 0 {
1460                        controller.event_ring_cycle.store(
1461                            !controller.event_ring_cycle.load(Ordering::Acquire),
1462                            Ordering::Release,
1463                        );
1464                    }
1465
1466                    let new_erdp = controller.event_ring_phys + (new_deq as u64) * 16;
1467                    ir.erdp = new_erdp | (1 << 3);
1468
1469                    processed += 1;
1470                }
1471            }
1472
1473            let db_regs = controller.db_regs;
1474            for slot_idx in 0..controller.device_slots.len() {
1475                if let Some(ref mut dev) = controller.device_slots[slot_idx] {
1476                    for ep in 1..MAX_ENDPOINTS {
1477                        if dev.ep_active[ep]
1478                            || dev.ep_buf[ep].is_null()
1479                            || dev.ep_transfer_rings[ep].is_null()
1480                        {
1481                            continue;
1482                        }
1483                        let deq = dev.ep_dequeue[ep];
1484                        let cycle = dev.ep_cycle[ep];
1485                        let buf_phys = dev.ep_buf_phys[ep];
1486                        let buf_len = dev.ep_buf_len[ep];
1487                        let tr_ring = dev.ep_transfer_rings[ep];
1488                        let slot = dev.slot_id;
1489
1490                        let trb = Trb::normal(buf_phys, buf_len as u32, cycle, true);
1491                        core::ptr::write_volatile(tr_ring.add(deq), trb);
1492
1493                        core::sync::atomic::fence(core::sync::atomic::Ordering::SeqCst);
1494                        let db_index = (slot as usize) * 32 + ep;
1495                        core::ptr::write_volatile(db_regs.add(db_index), 0);
1496                        dev.ep_active[ep] = true;
1497                    }
1498                }
1499            }
1500        }
1501    }
1502}