strat9_kernel/hardware/usb/
ehci.rs1#![allow(dead_code)]
11
12use crate::{
13 hardware::pci_client::{self as pci, Bar, ProbeCriteria},
14 memory::{allocate_dma_frame, 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 let mmio_base = phys_to_virt(bar) as usize;
110 let cap_regs = mmio_base as *const EhciCapRegisters;
111 let caplength = (*cap_regs).caplength;
112 let op_regs = (mmio_base + caplength as usize) as *mut EhciOpRegisters;
113 let port_regs = (mmio_base + caplength as usize + 0x44) as *mut EhciPortRegisters;
114
115 let max_ports = ((*cap_regs).hcsparams1 as usize) & 0xF;
116
117 let mut controller = Self {
118 mmio_base,
119 cap_regs,
120 op_regs,
121 port_regs,
122 max_ports,
123 ports: Vec::new(),
124 periodic_list: core::ptr::null_mut(),
125 periodic_list_phys: 0,
126 async_list: core::ptr::null_mut(),
127 async_list_phys: 0,
128 };
129
130 controller.init()?;
131 Ok(Arc::new(controller))
132 }
133
134 fn init(&mut self) -> Result<(), &'static str> {
136 unsafe {
137 let op = &mut *self.op_regs;
138
139 op.usbcmd &= !USBCMD_RUN_STOP;
141 while op.usbsts & USBSTS_HCH == 0 {
142 core::hint::spin_loop();
143 }
144
145 op.usbcmd |= USBCMD_HCRST;
147 while op.usbcmd & USBCMD_HCRST != 0 {
148 core::hint::spin_loop();
149 }
150
151 for i in 0..self.max_ports {
153 let portsc = self.read_portsc(i);
154 self.ports.push(EhciPort {
155 port_num: i,
156 enabled: (portsc & PORTSC_PE) != 0,
157 connected: (portsc & PORTSC_CCS) != 0,
158 speed: ((portsc >> PORTSC_SPEED_SHIFT) & 0x03) as u8,
159 });
160 }
161
162 self.init_schedules()?;
164
165 op.usbintr = USBSTS_INT | USBSTS_ERR | USBSTS_PCD;
167
168 op.usbcmd |= USBCMD_RUN_STOP | USBCMD_PSE | USBCMD_ASE | USBCMD_INTE;
170 op.config_flag = 1;
171 }
172 Ok(())
173 }
174
175 unsafe fn init_schedules(&mut self) -> Result<(), &'static str> {
177 let periodic_frame = allocate_dma_frame().ok_or("Failed to allocate periodic list")?;
179 self.periodic_list_phys = periodic_frame.start_address.as_u64();
180 self.periodic_list = phys_to_virt(self.periodic_list_phys) as *mut u32;
181 core::ptr::write_bytes(self.periodic_list as *mut u8, 0, 4096);
182
183 let async_frame = allocate_dma_frame().ok_or("Failed to allocate async list")?;
185 self.async_list_phys = async_frame.start_address.as_u64();
186 self.async_list = phys_to_virt(self.async_list_phys) as *mut u32;
187 core::ptr::write_bytes(self.async_list as *mut u8, 0, 4096);
188
189 *self.async_list = (self.async_list_phys as u32) & 0xFFFFFFE0;
191
192 let op = &mut *self.op_regs;
193 op.periodic_list_base = self.periodic_list_phys as u32;
194 op.async_list_base = self.async_list_phys as u32;
195
196 Ok(())
197 }
198
199 unsafe fn read_portsc(&self, port: usize) -> u32 {
201 let portsc_ptr = core::ptr::addr_of!((*self.port_regs).portsc[port]) as *const u32;
202 portsc_ptr.read_volatile()
203 }
204
205 unsafe fn write_portsc(&self, port: usize, val: u32) {
207 let portsc_ptr = core::ptr::addr_of!((*self.port_regs).portsc[port]) as *mut u32;
208 portsc_ptr.write_volatile(val);
209 }
210
211 pub fn port_count(&self) -> usize {
213 self.max_ports
214 }
215
216 pub fn is_port_connected(&self, port: usize) -> bool {
218 if port >= self.ports.len() {
219 return false;
220 }
221 self.ports[port].connected
222 }
223
224 pub fn get_port_speed(&self, port: usize) -> u8 {
226 if port >= self.ports.len() {
227 return 0;
228 }
229 self.ports[port].speed
230 }
231}
232
233static EHCI_CONTROLLERS: Mutex<Vec<Arc<EhciController>>> = Mutex::new(Vec::new());
234static EHCI_INITIALIZED: AtomicBool = AtomicBool::new(false);
235
236pub fn init() {
238 log::info!("[EHCI] Scanning for EHCI controllers...");
239
240 let candidates = pci::probe_all(ProbeCriteria {
241 vendor_id: None,
242 device_id: None,
243 class_code: Some(0x0C),
244 subclass: Some(0x03),
245 prog_if: Some(0x20),
246 });
247
248 for pci_dev in candidates.into_iter() {
249 log::info!(
250 "EHCI: Found controller at {:?} (VEN:{:04x} DEV:{:04x})",
251 pci_dev.address,
252 pci_dev.vendor_id,
253 pci_dev.device_id
254 );
255
256 pci_dev.enable_bus_master();
257
258 match unsafe { EhciController::new(pci_dev) } {
259 Ok(controller) => {
260 log::info!("[EHCI] Initialized with {} ports", controller.port_count());
261 EHCI_CONTROLLERS.lock().push(controller);
262 }
263 Err(e) => {
264 log::warn!("EHCI: Failed to initialize controller: {}", e);
265 }
266 }
267 }
268
269 EHCI_INITIALIZED.store(true, Ordering::SeqCst);
270 log::info!(
271 "[EHCI] Found {} controller(s)",
272 EHCI_CONTROLLERS.lock().len()
273 );
274}
275
276pub fn get_controller(index: usize) -> Option<Arc<EhciController>> {
278 EHCI_CONTROLLERS.lock().get(index).cloned()
279}
280
281pub fn is_available() -> bool {
283 EHCI_INITIALIZED.load(Ordering::Relaxed)
284}