strat9_kernel/hardware/usb/
uhci.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;
19use x86_64::instructions::port::Port;
20
21const UHCI_USBCMD: u16 = 0x00;
22const UHCI_USBSTS: u16 = 0x02;
23const UHCI_USBINTR: u16 = 0x04;
24const UHCI_FRNUM: u16 = 0x06;
25const UHCI_FRBASEADDR: u16 = 0x08;
26const UHCI_SOFMOD: u16 = 0x0C;
27const UHCI_PORTSC: u16 = 0x10;
28
29const USBCMD_RUN_STOP: u16 = 1 << 0;
30const USBCMD_HCRESET: u16 = 1 << 1;
31const USBCMD_EGSM: u16 = 1 << 3;
32const USBCMD_FGSM: u16 = 1 << 4;
33const USBCMD_CONFIGURE: u16 = 1 << 6;
34const USBCMD_MAX_PACKET: u16 = 1 << 7;
35
36const USBSTS_USBINT: u16 = 1 << 0;
37const USBSTS_USBERR: u16 = 1 << 1;
38const USBSTS_RD: u16 = 1 << 2;
39const USBSTS_HSE: u16 = 1 << 3;
40const USBSTS_HCPE: u16 = 1 << 4;
41const USBSTS_HCH: u16 = 1 << 5;
42
43const PORTSC_CCS: u16 = 1 << 0;
44const PORTSC_CSC: u16 = 1 << 1;
45const PORTSC_PE: u16 = 1 << 2;
46const PORTSC_PEC: u16 = 1 << 3;
47const PORTSC_LSDA: u16 = 1 << 8;
48const PORTSC_PR: u16 = 1 << 9;
49
50const TD_TOKEN_ACTIVE: u32 = 1 << 23;
51const TD_TOKEN_IOC: u32 = 1 << 24;
52const TD_TOKEN_LS: u32 = 1 << 26;
53const TD_TOKEN_ERRCNT_SHIFT: u32 = 27;
54
55const TD_LINK_PTR_MASK: u32 = 0xFFFFFFF0;
56const TD_LINK_VF: u32 = 1 << 0;
57const TD_LINK_QH: u32 = 1 << 1;
58
59#[repr(C)]
60struct UhciTD {
61 link_ptr: u32,
62 ctrl_status: u32,
63 token: u32,
64 buffer: u32,
65}
66
67#[repr(C)]
68struct UhciQH {
69 head_link: u32,
70 element_link: u32,
71}
72
73pub struct UhciPort {
74 port_num: usize,
75 enabled: bool,
76 connected: bool,
77 low_speed: bool,
78}
79
80pub struct UhciController {
81 io_base: u16,
82 usbcmd: Port<u16>,
83 usbsts: Port<u16>,
84 usbintr: Port<u16>,
85 frnum: Port<u16>,
86 frbaseaddr: Port<u32>,
87 sofmod: Port<u16>,
88 max_ports: usize,
89 ports: Vec<UhciPort>,
90 frame_list: *mut u32,
91 frame_list_phys: u64,
92}
93
94unsafe impl Send for UhciController {}
95unsafe impl Sync for UhciController {}
96
97impl UhciController {
98 pub unsafe fn new(pci_dev: pci::PciDevice) -> Result<Arc<Self>, &'static str> {
100 let io_base = match pci_dev.read_bar(4) {
101 Some(Bar::Io { port }) => port as u16,
102 _ => return Err("Invalid BAR4"),
103 };
104
105 let mut controller = Self {
106 io_base,
107 usbcmd: Port::new(io_base + UHCI_USBCMD),
108 usbsts: Port::new(io_base + UHCI_USBSTS),
109 usbintr: Port::new(io_base + UHCI_USBINTR),
110 frnum: Port::new(io_base + UHCI_FRNUM),
111 frbaseaddr: Port::new(io_base + UHCI_FRBASEADDR),
112 sofmod: Port::new(io_base + UHCI_SOFMOD),
113 max_ports: 2, ports: Vec::new(),
115 frame_list: core::ptr::null_mut(),
116 frame_list_phys: 0,
117 };
118
119 controller.init()?;
120 Ok(Arc::new(controller))
121 }
122
123 fn init(&mut self) -> Result<(), &'static str> {
125 unsafe {
126 let mut cmd = self.usbcmd.read();
127 cmd &= !USBCMD_RUN_STOP;
128 self.usbcmd.write(cmd);
129 let mut timeout = 10000;
130 while self.usbsts.read() & USBSTS_HCH == 0 {
131 core::hint::spin_loop();
132 timeout -= 1;
133 if timeout == 0 {
134 return Err("UHCI: controller did not halt");
135 }
136 }
137
138 cmd = self.usbcmd.read();
139 cmd |= USBCMD_HCRESET;
140 self.usbcmd.write(cmd);
141 let mut reset_ok = false;
142 for _ in 0..10000 {
143 if self.usbcmd.read() & USBCMD_HCRESET == 0 {
144 reset_ok = true;
145 break;
146 }
147 core::hint::spin_loop();
148 }
149 if !reset_ok {
150 return Err("UHCI: controller reset timed out");
151 }
152
153 for i in 0..self.max_ports {
155 let portsc = self.read_portsc(i);
156 self.ports.push(UhciPort {
157 port_num: i,
158 enabled: (portsc & PORTSC_PE) != 0,
159 connected: (portsc & PORTSC_CCS) != 0,
160 low_speed: (portsc & PORTSC_LSDA) != 0,
161 });
162 }
163
164 self.init_frame_list()?;
166
167 self.usbintr
169 .write(USBSTS_USBINT | USBSTS_USBERR | USBSTS_RD);
170
171 cmd = self.usbcmd.read();
173 cmd |= USBCMD_RUN_STOP | USBCMD_CONFIGURE | USBCMD_MAX_PACKET;
174 self.usbcmd.write(cmd);
175 }
176 Ok(())
177 }
178
179 unsafe fn init_frame_list(&mut self) -> Result<(), &'static str> {
181 let frame = allocate_dma_frame().ok_or("Failed to allocate frame list")?;
183 self.frame_list_phys = frame.start_address.as_u64();
184 self.frame_list = phys_to_virt(self.frame_list_phys) as *mut u32;
185 core::ptr::write_bytes(self.frame_list as *mut u8, 0, 4096);
186
187 for i in 0..1024 {
189 *self.frame_list.add(i) = 0x0001; }
191
192 self.frbaseaddr
193 .write((self.frame_list_phys & 0xFFFFF000) as u32);
194
195 Ok(())
196 }
197
198 unsafe fn read_portsc(&self, port: usize) -> u16 {
200 let mut port_reg = Port::new(self.io_base + UHCI_PORTSC + (port as u16) * 2);
201 port_reg.read()
202 }
203
204 unsafe fn write_portsc(&self, port: usize, val: u16) {
206 let mut port_reg = Port::new(self.io_base + UHCI_PORTSC + (port as u16) * 2);
207 port_reg.write(val);
208 }
209
210 pub fn port_count(&self) -> usize {
212 self.max_ports
213 }
214
215 pub fn is_port_connected(&self, port: usize) -> bool {
217 if port >= self.ports.len() {
218 return false;
219 }
220 self.ports[port].connected
221 }
222
223 pub fn is_low_speed(&self, port: usize) -> bool {
225 if port >= self.ports.len() {
226 return false;
227 }
228 self.ports[port].low_speed
229 }
230}
231
232static UHCI_CONTROLLERS: Mutex<Vec<Arc<UhciController>>> = Mutex::new(Vec::new());
233static UHCI_INITIALIZED: AtomicBool = AtomicBool::new(false);
234
235pub fn init() {
237 log::info!("[UHCI] Scanning for UHCI controllers...");
238
239 let candidates = pci::probe_all(ProbeCriteria {
240 vendor_id: None,
241 device_id: None,
242 class_code: Some(0x0C),
243 subclass: Some(0x03),
244 prog_if: Some(0x00),
245 });
246
247 for pci_dev in candidates.into_iter() {
248 log::info!(
249 "UHCI: Found controller at {:?} (VEN:{:04x} DEV:{:04x})",
250 pci_dev.address,
251 pci_dev.vendor_id,
252 pci_dev.device_id
253 );
254
255 pci_dev.enable_bus_master();
256
257 match unsafe { UhciController::new(pci_dev) } {
258 Ok(controller) => {
259 log::info!("[UHCI] Initialized with {} ports", controller.port_count());
260 UHCI_CONTROLLERS.lock().push(controller);
261 }
262 Err(e) => {
263 log::warn!("UHCI: Failed to initialize controller: {}", e);
264 }
265 }
266 }
267
268 UHCI_INITIALIZED.store(true, Ordering::SeqCst);
269 log::info!(
270 "[UHCI] Found {} controller(s)",
271 UHCI_CONTROLLERS.lock().len()
272 );
273}
274
275pub fn get_controller(index: usize) -> Option<Arc<UhciController>> {
277 UHCI_CONTROLLERS.lock().get(index).cloned()
278}
279
280pub fn is_available() -> bool {
282 UHCI_INITIALIZED.load(Ordering::Relaxed)
283}