1#![allow(dead_code)]
11
12use crate::{
13 hardware::pci_client::{self as pci, Bar, ProbeCriteria},
14 memory::{allocate_zeroed_frame, paging, phys_to_virt},
15};
16use alloc::{sync::Arc, vec::Vec};
17use core::sync::atomic::{AtomicBool, Ordering};
18use spin::Mutex;
19
20const EHCI_MMIO_SIZE: usize = 0x1000;
21
22const USBCMD_RUN_STOP: u32 = 1 << 0;
23const USBCMD_HCRST: u32 = 1 << 1;
24const USBCMD_INTE: u32 = 1 << 2;
25const USBCMD_PSE: u32 = 1 << 4;
26const USBCMD_ASE: u32 = 1 << 5;
27
28const USBSTS_INT: u32 = 1 << 0;
29const USBSTS_ERR: u32 = 1 << 1;
30const USBSTS_PCD: u32 = 1 << 2;
31const USBSTS_HCH: u32 = 1 << 12;
32
33const PORTSC_CCS: u32 = 1 << 0;
34const PORTSC_CSC: u32 = 1 << 1;
35const PORTSC_PE: u32 = 1 << 2;
36const PORTSC_PEC: u32 = 1 << 3;
37const PORTSC_OCA: u32 = 1 << 4;
38const PORTSC_OCC: u32 = 1 << 5;
39const PORTSC_FPR: u32 = 1 << 6;
40const PORTSC_SUSP: u32 = 1 << 7;
41const PORTSC_PR: u32 = 1 << 8;
42const PORTSC_PP: u32 = 1 << 12;
43const PORTSC_SPEED_SHIFT: u32 = 26;
44const PORTSC_SPEED_MASK: u32 = 0x03 << PORTSC_SPEED_SHIFT;
45
46const SPEED_FULL: u32 = 0;
47const SPEED_LOW: u32 = 1;
48const SPEED_HIGH: u32 = 2;
49
50#[repr(C)]
51struct EhciCapRegisters {
52 caplength: u8,
53 _reserved: u8,
54 hciversion: u16,
55 hcsparams1: u32,
56 hcsparams2: u32,
57 hccparams: u32,
58}
59
60#[repr(C)]
61struct EhciOpRegisters {
62 usbcmd: u32,
63 usbsts: u32,
64 usbintr: u32,
65 frindex: u32,
66 ctrl_ds_seg: u32,
67 periodic_list_base: u32,
68 async_list_base: u32,
69 _reserved: [u32; 9],
70 config_flag: u32,
71}
72
73#[repr(C)]
74struct EhciPortRegisters {
75 portsc: [u32; 16],
76}
77
78pub struct EhciPort {
79 port_num: usize,
80 enabled: bool,
81 connected: bool,
82 speed: u8,
83}
84
85pub struct EhciController {
86 mmio_base: usize,
87 cap_regs: *const EhciCapRegisters,
88 op_regs: *mut EhciOpRegisters,
89 port_regs: *mut EhciPortRegisters,
90 max_ports: usize,
91 ports: Vec<EhciPort>,
92 periodic_list: *mut u32,
93 periodic_list_phys: u64,
94 async_list: *mut u32,
95 async_list_phys: u64,
96}
97
98unsafe impl Send for EhciController {}
99unsafe impl Sync for EhciController {}
100
101impl EhciController {
102 pub unsafe fn new(pci_dev: pci::PciDevice) -> Result<Arc<Self>, &'static str> {
104 let bar = match pci_dev.read_bar(0) {
105 Some(Bar::Memory32 { addr, .. }) => addr as u64,
106 _ => return Err("Invalid BAR"),
107 };
108
109 paging::ensure_identity_map_range(bar, EHCI_MMIO_SIZE as u64);
110
111 let mmio_base = phys_to_virt(bar) as usize;
112 let cap_regs = mmio_base as *const EhciCapRegisters;
113 let caplength = (*cap_regs).caplength;
114 let op_regs = (mmio_base + caplength as usize) as *mut EhciOpRegisters;
115 let port_regs = (mmio_base + caplength as usize + 0x44) as *mut EhciPortRegisters;
116
117 let max_ports = ((*cap_regs).hcsparams1 as usize) & 0xF;
118
119 let mut controller = Self {
120 mmio_base,
121 cap_regs,
122 op_regs,
123 port_regs,
124 max_ports,
125 ports: Vec::new(),
126 periodic_list: core::ptr::null_mut(),
127 periodic_list_phys: 0,
128 async_list: core::ptr::null_mut(),
129 async_list_phys: 0,
130 };
131
132 controller.init()?;
133 Ok(Arc::new(controller))
134 }
135
136 fn init(&mut self) -> Result<(), &'static str> {
138 unsafe {
139 let cmd = core::ptr::addr_of_mut!((*self.op_regs).usbcmd);
140 let sts = core::ptr::addr_of!((*self.op_regs).usbsts);
141 let intr = core::ptr::addr_of_mut!((*self.op_regs).usbintr);
142 let cfg = core::ptr::addr_of_mut!((*self.op_regs).config_flag);
143
144 cmd.write_volatile(cmd.read_volatile() & !USBCMD_RUN_STOP);
146 for _ in 0..100_000u32 {
147 if sts.read_volatile() & USBSTS_HCH != 0 {
148 break;
149 }
150 core::hint::spin_loop();
151 }
152 if sts.read_volatile() & USBSTS_HCH == 0 {
153 return Err("EHCI: halt timeout");
154 }
155
156 cmd.write_volatile(cmd.read_volatile() | USBCMD_HCRST);
158 for _ in 0..100_000u32 {
159 if cmd.read_volatile() & USBCMD_HCRST == 0 {
160 break;
161 }
162 core::hint::spin_loop();
163 }
164 if cmd.read_volatile() & USBCMD_HCRST != 0 {
165 return Err("EHCI: reset timeout");
166 }
167
168 for i in 0..self.max_ports {
170 let portsc = self.read_portsc(i);
171 self.ports.push(EhciPort {
172 port_num: i,
173 enabled: (portsc & PORTSC_PE) != 0,
174 connected: (portsc & PORTSC_CCS) != 0,
175 speed: ((portsc >> PORTSC_SPEED_SHIFT) & 0x03) as u8,
176 });
177 }
178
179 self.init_schedules()?;
181
182 intr.write_volatile(USBSTS_INT | USBSTS_ERR | USBSTS_PCD);
184
185 cmd.write_volatile(
187 cmd.read_volatile() | USBCMD_RUN_STOP | USBCMD_PSE | USBCMD_ASE | USBCMD_INTE,
188 );
189 cfg.write_volatile(1);
190 }
191 Ok(())
192 }
193
194 unsafe fn init_schedules(&mut self) -> Result<(), &'static str> {
196 let periodic_frame = allocate_zeroed_frame().ok_or("Failed to allocate periodic list")?;
198 self.periodic_list_phys = periodic_frame.start_address.as_u64();
199 self.periodic_list = phys_to_virt(self.periodic_list_phys) as *mut u32;
200 core::ptr::write_bytes(self.periodic_list as *mut u8, 0, 4096);
201
202 let async_frame = allocate_zeroed_frame().ok_or("Failed to allocate async list")?;
204 self.async_list_phys = async_frame.start_address.as_u64();
205 self.async_list = phys_to_virt(self.async_list_phys) as *mut u32;
206 core::ptr::write_bytes(self.async_list as *mut u8, 0, 4096);
207
208 core::ptr::write_volatile(self.async_list, (self.async_list_phys as u32) & 0xFFFFFFE0);
210
211 let plb = core::ptr::addr_of_mut!((*self.op_regs).periodic_list_base);
212 let alb = core::ptr::addr_of_mut!((*self.op_regs).async_list_base);
213 plb.write_volatile(self.periodic_list_phys as u32);
214 alb.write_volatile(self.async_list_phys as u32);
215
216 Ok(())
217 }
218
219 unsafe fn read_portsc(&self, port: usize) -> u32 {
221 let portsc_ptr = core::ptr::addr_of!((*self.port_regs).portsc[port]) as *const u32;
222 portsc_ptr.read_volatile()
223 }
224
225 unsafe fn write_portsc(&self, port: usize, val: u32) {
227 let portsc_ptr = core::ptr::addr_of!((*self.port_regs).portsc[port]) as *mut u32;
228 portsc_ptr.write_volatile(val);
229 }
230
231 pub fn port_count(&self) -> usize {
233 self.max_ports
234 }
235
236 pub fn is_port_connected(&self, port: usize) -> bool {
238 if port >= self.ports.len() {
239 return false;
240 }
241 self.ports[port].connected
242 }
243
244 pub fn get_port_speed(&self, port: usize) -> u8 {
246 if port >= self.ports.len() {
247 return 0;
248 }
249 self.ports[port].speed
250 }
251
252 unsafe fn reset_port(&self, port: usize) -> bool {
254 let mut portsc = self.read_portsc(port);
255 if portsc & PORTSC_CCS == 0 {
256 return false;
257 }
258
259 portsc = self.read_portsc(port);
261 self.write_portsc(port, portsc | PORTSC_PR);
262 for _ in 0..10_000u32 {
263 core::hint::spin_loop();
264 }
265 portsc = self.read_portsc(port);
266 self.write_portsc(port, portsc & !PORTSC_PR);
267 for _ in 0..10_000u32 {
268 core::hint::spin_loop();
269 }
270
271 for _ in 0..100_000u32 {
273 portsc = self.read_portsc(port);
274 if portsc & PORTSC_PE != 0 {
275 return true;
276 }
277 if portsc & PORTSC_CCS == 0 {
278 return false;
279 }
280 core::hint::spin_loop();
281 }
282 false
283 }
284
285 unsafe fn ctrl_transfer(
290 &self,
291 _port: usize,
292 setup_data: &[u8; 8],
293 data_buf: Option<&mut [u8]>,
294 data_len: usize,
295 device_addr: u8,
296 max_packet: u32,
297 ) -> Result<usize, &'static str> {
298 let qh_frame = allocate_zeroed_frame().ok_or("EHCI: QH alloc failed")?;
299 let qh_phys = qh_frame.start_address.as_u64();
300 let qh_virt = phys_to_virt(qh_phys) as *mut u32;
301
302 let td_frame = allocate_zeroed_frame().ok_or("EHCI: TD alloc failed")?;
303 let td_phys = td_frame.start_address.as_u64();
304 let td_virt = phys_to_virt(td_phys) as *mut u32;
305
306 let setup_frame = allocate_zeroed_frame().ok_or("EHCI: setup buf alloc failed")?;
307 let setup_buf_phys = setup_frame.start_address.as_u64();
308 let setup_buf_virt = phys_to_virt(setup_buf_phys) as *mut u8;
309 core::ptr::copy_nonoverlapping(setup_data.as_ptr(), setup_buf_virt, 8);
310
311 let dir_in = (setup_data[0] & 0x80) != 0;
312 let has_data = data_buf.is_some();
313
314 qh_virt.add(0).write_volatile(0x0000_0002); qh_virt.add(1).write_volatile(
323 (device_addr as u32 & 0x7F) | ((max_packet & 0x7FF) << 16), );
326 qh_virt.add(2).write_volatile(0); qh_virt.add(3).write_volatile(td_phys as u32); qh_virt.add(4).write_volatile(td_phys as u32); let setup_token = (1u32 << 31) | (0u32 << 30) | ((8u32 & 0x7FFF) << 16) | (0u32 << 25) | (3u32 << 26) | (0x2Du32); td_virt.add(0).write_volatile(0x0000_0002); td_virt.add(1).write_volatile(0x0000_0002); td_virt.add(2).write_volatile(setup_token);
358 td_virt.add(3).write_volatile(setup_buf_phys as u32);
359
360 if has_data && data_len > 0 {
361 let data_frame = allocate_zeroed_frame().ok_or("EHCI: data buf alloc failed")?;
362 let data_buf_phys = data_frame.start_address.as_u64();
363 let data_buf_virt = phys_to_virt(data_buf_phys) as *mut u8;
364
365 if !dir_in {
366 if let Some(ref buf) = data_buf {
367 core::ptr::copy_nonoverlapping(buf.as_ptr(), data_buf_virt, data_len);
368 }
369 }
370
371 let data_pid: u32 = if dir_in { 0x69 } else { 0xE1 };
373 let data_token = (1u32 << 31) | (1u32 << 30) | (((data_len as u32) & 0x7FFF) << 16) | (0u32 << 25) | (3u32 << 26) | data_pid; let data_td_virt = (td_virt as *mut u8).add(0x20) as *mut u32;
380 data_td_virt.add(0).write_volatile(0x0000_0002);
381 data_td_virt.add(1).write_volatile(0x0000_0002);
382 data_td_virt.add(2).write_volatile(data_token);
383 data_td_virt.add(3).write_volatile(data_buf_phys as u32);
384
385 let status_token = (1u32 << 31) | (0u32 << 30) | (0u32 << 16) | (1u32 << 25) | (3u32 << 26) | (0u32); let status_td_virt = (td_virt as *mut u8).add(0x40) as *mut u32;
393 status_td_virt.add(0).write_volatile(0x0000_0002);
394 status_td_virt.add(1).write_volatile(0x0000_0002);
395 status_td_virt.add(2).write_volatile(status_token);
396 status_td_virt.add(3).write_volatile(0);
397
398 td_virt.add(0).write_volatile((td_phys + 0x20) as u32);
400 data_td_virt.add(0).write_volatile((td_phys + 0x40) as u32);
401 } else {
402 let status_token = (1u32 << 31)
404 | (1u32 << 30) | (0u32 << 16)
406 | (1u32 << 25) | (3u32 << 26)
408 | (0x69u32); let status_td_virt = (td_virt as *mut u8).add(0x20) as *mut u32;
410 status_td_virt.add(0).write_volatile(0x0000_0002);
411 status_td_virt.add(1).write_volatile(0x0000_0002);
412 status_td_virt.add(2).write_volatile(status_token);
413 status_td_virt.add(3).write_volatile(0);
414
415 td_virt.add(0).write_volatile((td_phys + 0x20) as u32);
416 }
417
418 let async_head = self.async_list;
420 let old_head = core::ptr::read_volatile(async_head);
421 qh_virt.add(0).write_volatile(old_head & 0xFFFFFFE0 | 0x02);
422 core::sync::atomic::fence(core::sync::atomic::Ordering::SeqCst);
423 core::ptr::write_volatile(async_head, (qh_phys as u32 & 0xFFFFFFE0) | 0x02);
424
425 let cmd = core::ptr::addr_of!((*self.op_regs).usbcmd);
427 core::ptr::write_volatile(cmd as *mut u32, cmd.read_volatile() | USBCMD_ASE);
428 for _ in 0..10_000u32 {
429 core::hint::spin_loop();
430 }
431
432 let status_td_virt = if has_data && data_len > 0 {
434 (td_virt as *mut u8).add(0x40) as *mut u32
435 } else {
436 (td_virt as *mut u8).add(0x20) as *mut u32
437 };
438
439 let mut transferred = 0;
440 for _ in 0..1_000_000u32 {
441 let token = core::ptr::read_volatile(status_td_virt.add(2));
442 if token & (1u32 << 31) == 0 {
443 if dir_in && has_data && data_len > 0 {
444 if let Some(buf) = data_buf {
445 let data_td = (td_virt as *mut u8).add(0x20) as *const u32;
446 let buf_phys = core::ptr::read_volatile(data_td.add(3));
447 let src = phys_to_virt(buf_phys as u64) as *const u8;
448 core::ptr::copy_nonoverlapping(src, buf.as_mut_ptr(), data_len);
449 transferred = data_len;
450 }
451 }
452 break;
453 }
454 core::hint::spin_loop();
455 }
456
457 core::ptr::write_volatile(cmd as *mut u32, cmd.read_volatile() & !USBCMD_ASE);
459 for _ in 0..10_000u32 {
460 core::hint::spin_loop();
461 }
462 core::ptr::write_volatile(async_head, old_head);
463
464 Ok(transferred)
465 }
466
467 fn enumerate_all_ports(&self) {
469 let mut usb_address: u8 = 1;
470
471 for port in 0..self.max_ports {
472 let portsc = unsafe { self.read_portsc(port) };
473 if portsc & PORTSC_CCS == 0 {
474 continue;
475 }
476
477 log::info!("[EHCI] Port {} connected, resetting...", port);
478
479 if !unsafe { self.reset_port(port) } {
480 log::warn!("[EHCI] Port {} reset failed", port);
481 continue;
482 }
483
484 let speed = unsafe { ((self.read_portsc(port) >> PORTSC_SPEED_SHIFT) & 0x03) as u8 };
485 let max_packet: u32 = if speed as u32 == SPEED_HIGH { 64 } else { 8 };
486 log::info!(
487 "[EHCI] Port {} speed={} max_pkt={}",
488 port,
489 speed,
490 max_packet
491 );
492
493 let addr = usb_address;
495 let set_addr = [0x00u8, 0x05, addr, 0x00, 0x00, 0x00, 0x00, 0x00];
496 if unsafe { self.ctrl_transfer(port, &set_addr, None, 0, 0, max_packet) }.is_err() {
497 log::warn!("[EHCI] Port {} set address failed", port);
498 continue;
499 }
500
501 let get_desc_8 = [0x80u8, 0x06, 0x00, 0x01, 0x00, 0x00, 8, 0x00];
503 let mut desc8 = [0u8; 8];
504 if unsafe {
505 self.ctrl_transfer(port, &get_desc_8, Some(&mut desc8), 8, addr, max_packet)
506 }
507 .is_err()
508 {
509 log::warn!("[EHCI] Port {} get desc (8) failed", addr);
510 usb_address += 1;
511 continue;
512 }
513
514 let vid = u16::from_le_bytes([desc8[2], desc8[3]]);
515 let pid = u16::from_le_bytes([desc8[4], desc8[5]]);
516 let max_pkt0 = desc8[7] as u32;
517 log::info!(
518 "[EHCI] Port {} device VID={:04x} PID={:04x} max_pkt0={}",
519 port,
520 vid,
521 pid,
522 max_pkt0
523 );
524
525 let mut desc18 = [0u8; 18];
527 let get_desc_18 = [0x80u8, 0x06, 0x00, 0x01, 0x00, 0x00, 18, 0x00];
528 let _ = unsafe {
529 self.ctrl_transfer(port, &get_desc_18, Some(&mut desc18), 18, addr, max_pkt0)
530 };
531
532 let dev_class = desc18[4];
533 log::info!("[EHCI] Port {} class={:02x}", port, dev_class);
534
535 let set_config = [0x00u8, 0x09, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00];
537 let _ = unsafe { self.ctrl_transfer(port, &set_config, None, 0, addr, max_pkt0) };
538
539 crate::hardware::usb::hid::enumerate_device(port, addr, &desc18);
541
542 usb_address += 1;
543 }
544 }
545}
546
547static EHCI_CONTROLLERS: Mutex<Vec<Arc<EhciController>>> = Mutex::new(Vec::new());
548static EHCI_INITIALIZED: AtomicBool = AtomicBool::new(false);
549
550pub fn init() {
552 log::info!("[EHCI] Scanning for EHCI controllers...");
553
554 let candidates = pci::probe_all(ProbeCriteria {
555 vendor_id: None,
556 device_id: None,
557 class_code: Some(0x0C),
558 subclass: Some(0x03),
559 prog_if: Some(0x20),
560 });
561
562 for pci_dev in candidates.into_iter() {
563 log::info!(
564 "EHCI: Found controller at {:?} (VEN:{:04x} DEV:{:04x})",
565 pci_dev.address,
566 pci_dev.vendor_id,
567 pci_dev.device_id
568 );
569
570 pci_dev.enable_bus_master();
571
572 match unsafe { EhciController::new(pci_dev) } {
573 Ok(controller) => {
574 log::info!("[EHCI] Initialized with {} ports", controller.port_count());
575 controller.enumerate_all_ports();
576 EHCI_CONTROLLERS.lock().push(controller);
577 }
578 Err(e) => {
579 log::warn!("EHCI: Failed to initialize controller: {}", e);
580 }
581 }
582 }
583
584 EHCI_INITIALIZED.store(true, Ordering::SeqCst);
585 log::info!(
586 "[EHCI] Found {} controller(s)",
587 EHCI_CONTROLLERS.lock().len()
588 );
589}
590
591pub fn get_controller(index: usize) -> Option<Arc<EhciController>> {
593 EHCI_CONTROLLERS.lock().get(index).cloned()
594}
595
596pub fn is_available() -> bool {
598 EHCI_INITIALIZED.load(Ordering::Relaxed)
599}