1#![allow(dead_code)]
8
9#[cfg(feature = "alloc")]
10extern crate alloc;
11
12use core::sync::atomic::{AtomicBool, Ordering};
13
14use spin::Mutex;
15
16use crate::error::KernelError;
17
18const MAX_PORTS: usize = 16;
24
25const EVENT_RING_CAPACITY: usize = 16;
27
28const PORTSC_CSC: u32 = 1 << 17;
31const PORTSC_CCS: u32 = 1 << 0;
33const PORTSC_PED: u32 = 1 << 1;
35const PORTSC_PR: u32 = 1 << 4;
37const PORTSC_PLS_MASK: u32 = 0xF << 5;
39const PORTSC_SPEED_MASK: u32 = 0xF << 10;
41const PORTSC_SPEED_SHIFT: u32 = 10;
43const PORTSC_PP: u32 = 1 << 9;
45const PORTSC_PEC: u32 = 1 << 18;
47const PORTSC_WRC: u32 = 1 << 19;
49const PORTSC_OCC: u32 = 1 << 20;
51const PORTSC_PRC: u32 = 1 << 21;
53const PORTSC_PLC: u32 = 1 << 22;
55const PORTSC_CEC: u32 = 1 << 23;
57
58const PORTSC_CHANGE_BITS: u32 =
60 PORTSC_CSC | PORTSC_PEC | PORTSC_WRC | PORTSC_OCC | PORTSC_PRC | PORTSC_PLC | PORTSC_CEC;
61
62const USB_CLASS_HID: u8 = 0x03;
64const USB_CLASS_MASS_STORAGE: u8 = 0x08;
65const USB_CLASS_HUB: u8 = 0x09;
66const USB_CLASS_AUDIO: u8 = 0x01;
67const USB_CLASS_VIDEO: u8 = 0x0E;
68const USB_CLASS_PRINTER: u8 = 0x07;
69const USB_CLASS_CDC: u8 = 0x02;
70
71#[derive(Debug, Clone, Copy, PartialEq, Eq)]
77pub enum UsbDeviceSpeed {
78 Low,
80 Full,
82 High,
84 Super,
86}
87
88impl UsbDeviceSpeed {
89 pub(crate) fn from_portsc(speed_field: u32) -> Self {
91 match speed_field {
92 1 => UsbDeviceSpeed::Full,
93 2 => UsbDeviceSpeed::Low,
94 3 => UsbDeviceSpeed::High,
95 4 => UsbDeviceSpeed::Super,
96 _ => UsbDeviceSpeed::Full, }
98 }
99
100 pub fn name(&self) -> &'static str {
102 match self {
103 UsbDeviceSpeed::Low => "Low Speed (1.5 Mbps)",
104 UsbDeviceSpeed::Full => "Full Speed (12 Mbps)",
105 UsbDeviceSpeed::High => "High Speed (480 Mbps)",
106 UsbDeviceSpeed::Super => "SuperSpeed (5 Gbps)",
107 }
108 }
109}
110
111#[derive(Debug, Clone)]
113pub enum UsbHotplugEvent {
114 DeviceAttached {
116 port: u8,
118 speed: UsbDeviceSpeed,
120 vendor_id: u16,
122 product_id: u16,
124 device_class: u8,
126 },
127 DeviceDetached {
129 port: u8,
131 },
132}
133
134#[derive(Debug, Clone, Copy)]
136pub struct UsbPortStatus {
137 pub connected: bool,
139 pub enabled: bool,
141 pub speed: UsbDeviceSpeed,
143 pub connect_changed: bool,
145 pub enable_changed: bool,
147 pub vendor_id: u16,
149 pub product_id: u16,
151 pub device_class: u8,
153}
154
155impl Default for UsbPortStatus {
156 fn default() -> Self {
157 Self {
158 connected: false,
159 enabled: false,
160 speed: UsbDeviceSpeed::Full,
161 connect_changed: false,
162 enable_changed: false,
163 vendor_id: 0,
164 product_id: 0,
165 device_class: 0,
166 }
167 }
168}
169
170pub type HotplugCallback = fn(UsbHotplugEvent);
172
173struct EventRingBuffer {
175 events: [Option<UsbHotplugEvent>; EVENT_RING_CAPACITY],
176 head: usize,
177 tail: usize,
178 count: usize,
179}
180
181impl EventRingBuffer {
182 const fn new() -> Self {
183 const NONE: Option<UsbHotplugEvent> = None;
185 Self {
186 events: [NONE; EVENT_RING_CAPACITY],
187 head: 0,
188 tail: 0,
189 count: 0,
190 }
191 }
192
193 fn push(&mut self, event: UsbHotplugEvent) -> bool {
194 if self.count >= EVENT_RING_CAPACITY {
195 return false; }
197 self.events[self.tail] = Some(event);
198 self.tail = (self.tail + 1) % EVENT_RING_CAPACITY;
199 self.count += 1;
200 true
201 }
202
203 fn pop(&mut self) -> Option<UsbHotplugEvent> {
204 if self.count == 0 {
205 return None;
206 }
207 let event = self.events[self.head].take();
208 self.head = (self.head + 1) % EVENT_RING_CAPACITY;
209 self.count -= 1;
210 event
211 }
212
213 fn is_empty(&self) -> bool {
214 self.count == 0
215 }
216
217 fn len(&self) -> usize {
218 self.count
219 }
220
221 fn clear(&mut self) {
222 self.head = 0;
223 self.tail = 0;
224 self.count = 0;
225 for slot in self.events.iter_mut() {
226 *slot = None;
227 }
228 }
229}
230
231pub struct UsbHotplugManager {
236 ports: [UsbPortStatus; MAX_PORTS],
238 num_ports: u8,
240 event_ring: EventRingBuffer,
242 callbacks: [Option<HotplugCallback>; 4],
244 num_callbacks: usize,
246 portsc_base: usize,
248 initialized: bool,
250 total_attach_events: u32,
252 total_detach_events: u32,
254}
255
256impl Default for UsbHotplugManager {
257 fn default() -> Self {
258 Self::new()
259 }
260}
261
262impl UsbHotplugManager {
263 pub const fn new() -> Self {
265 const DEFAULT_PORT: UsbPortStatus = UsbPortStatus {
266 connected: false,
267 enabled: false,
268 speed: UsbDeviceSpeed::Full,
269 connect_changed: false,
270 enable_changed: false,
271 vendor_id: 0,
272 product_id: 0,
273 device_class: 0,
274 };
275 const NONE_CB: Option<HotplugCallback> = None;
276 Self {
277 ports: [DEFAULT_PORT; MAX_PORTS],
278 num_ports: 0,
279 event_ring: EventRingBuffer::new(),
280 callbacks: [NONE_CB; 4],
281 num_callbacks: 0,
282 portsc_base: 0,
283 initialized: false,
284 total_attach_events: 0,
285 total_detach_events: 0,
286 }
287 }
288
289 pub fn init(&mut self, portsc_base: usize, num_ports: u8) {
291 let capped = if num_ports as usize > MAX_PORTS {
292 MAX_PORTS as u8
293 } else {
294 num_ports
295 };
296 self.portsc_base = portsc_base;
297 self.num_ports = capped;
298 self.initialized = true;
299 self.event_ring.clear();
300 self.total_attach_events = 0;
301 self.total_detach_events = 0;
302
303 for port in self.ports.iter_mut() {
305 *port = UsbPortStatus::default();
306 }
307 }
308
309 pub fn poll(&mut self) {
314 if !self.initialized || self.portsc_base == 0 {
315 return;
316 }
317
318 for port_idx in 0..self.num_ports as usize {
319 let portsc = self.read_portsc(port_idx);
320
321 if portsc & PORTSC_CSC != 0 {
323 let connected = portsc & PORTSC_CCS != 0;
324 let was_connected = self.ports[port_idx].connected;
325
326 if connected && !was_connected {
327 let speed_field = (portsc & PORTSC_SPEED_MASK) >> PORTSC_SPEED_SHIFT;
329 let speed = UsbDeviceSpeed::from_portsc(speed_field);
330 let enabled = portsc & PORTSC_PED != 0;
331
332 let (vendor_id, product_id, device_class) =
334 self.read_device_descriptor(port_idx);
335
336 self.ports[port_idx] = UsbPortStatus {
337 connected: true,
338 enabled,
339 speed,
340 connect_changed: true,
341 enable_changed: false,
342 vendor_id,
343 product_id,
344 device_class,
345 };
346
347 let event = UsbHotplugEvent::DeviceAttached {
348 port: port_idx as u8,
349 speed,
350 vendor_id,
351 product_id,
352 device_class,
353 };
354
355 self.event_ring.push(event.clone());
356 self.total_attach_events = self.total_attach_events.saturating_add(1);
357 self.notify_callbacks(event);
358 } else if !connected && was_connected {
359 self.ports[port_idx] = UsbPortStatus {
361 connected: false,
362 enabled: false,
363 speed: UsbDeviceSpeed::Full,
364 connect_changed: true,
365 enable_changed: false,
366 vendor_id: 0,
367 product_id: 0,
368 device_class: 0,
369 };
370
371 let event = UsbHotplugEvent::DeviceDetached {
372 port: port_idx as u8,
373 };
374
375 self.event_ring.push(event.clone());
376 self.total_detach_events = self.total_detach_events.saturating_add(1);
377 self.notify_callbacks(event);
378 }
379
380 self.clear_portsc_csc(port_idx, portsc);
382 }
383
384 if portsc & PORTSC_PEC != 0 {
386 let enabled = portsc & PORTSC_PED != 0;
387 self.ports[port_idx].enabled = enabled;
388 self.ports[port_idx].enable_changed = true;
389
390 self.clear_portsc_change(port_idx, portsc, PORTSC_PEC);
392 }
393 }
394 }
395
396 fn read_portsc(&self, port_idx: usize) -> u32 {
398 if self.portsc_base == 0 {
399 return 0;
400 }
401 let addr = self.portsc_base + 0x400 + port_idx * 0x10;
403
404 #[cfg(all(target_arch = "x86_64", target_os = "none"))]
407 unsafe {
408 core::ptr::read_volatile(addr as *const u32)
409 }
410 #[cfg(not(all(target_arch = "x86_64", target_os = "none")))]
411 {
412 let _ = addr;
413 0
414 }
415 }
416
417 fn clear_portsc_csc(&self, port_idx: usize, current: u32) {
419 self.clear_portsc_change(port_idx, current, PORTSC_CSC);
420 }
421
422 fn clear_portsc_change(&self, port_idx: usize, current: u32, change_bit: u32) {
427 if self.portsc_base == 0 {
428 return;
429 }
430 let addr = self.portsc_base + 0x400 + port_idx * 0x10;
431
432 let write_val = (current & !PORTSC_CHANGE_BITS) | change_bit;
434
435 #[cfg(all(target_arch = "x86_64", target_os = "none"))]
437 unsafe {
438 core::ptr::write_volatile(addr as *mut u32, write_val);
439 }
440 #[cfg(not(all(target_arch = "x86_64", target_os = "none")))]
441 {
442 let _ = (addr, write_val);
443 }
444 }
445
446 fn read_device_descriptor(&self, _port_idx: usize) -> (u16, u16, u8) {
451 (0, 0, 0)
456 }
457
458 pub fn get_event(&mut self) -> Option<UsbHotplugEvent> {
460 self.event_ring.pop()
461 }
462
463 pub fn has_events(&self) -> bool {
465 !self.event_ring.is_empty()
466 }
467
468 pub fn pending_event_count(&self) -> usize {
470 self.event_ring.len()
471 }
472
473 pub fn register_callback(&mut self, callback: HotplugCallback) -> Result<(), KernelError> {
475 if self.num_callbacks >= self.callbacks.len() {
476 return Err(KernelError::ResourceExhausted {
477 resource: "hotplug callbacks",
478 });
479 }
480 self.callbacks[self.num_callbacks] = Some(callback);
481 self.num_callbacks += 1;
482 Ok(())
483 }
484
485 fn notify_callbacks(&self, event: UsbHotplugEvent) {
487 for cb in self.callbacks.iter().flatten() {
488 cb(event.clone());
489 }
490 }
491
492 pub fn port_status(&self, port: u8) -> Option<&UsbPortStatus> {
494 if port < self.num_ports {
495 Some(&self.ports[port as usize])
496 } else {
497 None
498 }
499 }
500
501 pub fn num_ports(&self) -> u8 {
503 self.num_ports
504 }
505
506 pub fn total_attach_events(&self) -> u32 {
508 self.total_attach_events
509 }
510
511 pub fn total_detach_events(&self) -> u32 {
513 self.total_detach_events
514 }
515
516 pub fn is_initialized(&self) -> bool {
518 self.initialized
519 }
520}
521
522static HOTPLUG_MANAGER: Mutex<UsbHotplugManager> = Mutex::new(UsbHotplugManager::new());
527
528static HOTPLUG_INITIALIZED: AtomicBool = AtomicBool::new(false);
530
531pub fn usb_hotplug_init(portsc_base: usize, num_ports: u8) {
536 let mut manager = HOTPLUG_MANAGER.lock();
537 manager.init(portsc_base, num_ports);
538 HOTPLUG_INITIALIZED.store(true, Ordering::Release);
539 crate::println!(
540 "[USB-HOTPLUG] Initialized, monitoring {} ports (PORTSC base: {:#x})",
541 num_ports,
542 portsc_base
543 );
544}
545
546pub fn usb_hotplug_poll() {
551 if !HOTPLUG_INITIALIZED.load(Ordering::Acquire) {
552 return;
553 }
554 HOTPLUG_MANAGER.lock().poll();
555}
556
557pub fn usb_hotplug_get_event() -> Option<UsbHotplugEvent> {
559 if !HOTPLUG_INITIALIZED.load(Ordering::Acquire) {
560 return None;
561 }
562 HOTPLUG_MANAGER.lock().get_event()
563}
564
565pub fn usb_hotplug_register_callback(callback: HotplugCallback) -> Result<(), KernelError> {
567 HOTPLUG_MANAGER.lock().register_callback(callback)
568}
569
570pub fn usb_hotplug_has_events() -> bool {
572 if !HOTPLUG_INITIALIZED.load(Ordering::Acquire) {
573 return false;
574 }
575 HOTPLUG_MANAGER.lock().has_events()
576}
577
578pub fn usb_hotplug_port_status(port: u8) -> Option<UsbPortStatus> {
580 if !HOTPLUG_INITIALIZED.load(Ordering::Acquire) {
581 return None;
582 }
583 HOTPLUG_MANAGER.lock().port_status(port).copied()
584}
585
586pub fn usb_hotplug_num_ports() -> u8 {
588 if !HOTPLUG_INITIALIZED.load(Ordering::Acquire) {
589 return 0;
590 }
591 HOTPLUG_MANAGER.lock().num_ports()
592}
593
594#[cfg(test)]
599mod tests {
600 use super::*;
601
602 #[test]
603 fn test_usb_device_speed_from_portsc() {
604 assert_eq!(UsbDeviceSpeed::from_portsc(1), UsbDeviceSpeed::Full);
605 assert_eq!(UsbDeviceSpeed::from_portsc(2), UsbDeviceSpeed::Low);
606 assert_eq!(UsbDeviceSpeed::from_portsc(3), UsbDeviceSpeed::High);
607 assert_eq!(UsbDeviceSpeed::from_portsc(4), UsbDeviceSpeed::Super);
608 assert_eq!(UsbDeviceSpeed::from_portsc(0), UsbDeviceSpeed::Full);
609 }
610
611 #[test]
612 fn test_usb_device_speed_name() {
613 assert!(UsbDeviceSpeed::Low.name().contains("1.5"));
614 assert!(UsbDeviceSpeed::Full.name().contains("12"));
615 assert!(UsbDeviceSpeed::High.name().contains("480"));
616 assert!(UsbDeviceSpeed::Super.name().contains("5"));
617 }
618
619 #[test]
620 fn test_event_ring_buffer_empty() {
621 let ring = EventRingBuffer::new();
622 assert!(ring.is_empty());
623 assert_eq!(ring.len(), 0);
624 }
625
626 #[test]
627 fn test_event_ring_buffer_push_pop() {
628 let mut ring = EventRingBuffer::new();
629 let event = UsbHotplugEvent::DeviceDetached { port: 0 };
630 assert!(ring.push(event));
631 assert!(!ring.is_empty());
632 assert_eq!(ring.len(), 1);
633
634 let popped = ring.pop();
635 assert!(popped.is_some());
636 assert!(ring.is_empty());
637 }
638
639 #[test]
640 fn test_event_ring_buffer_overflow() {
641 let mut ring = EventRingBuffer::new();
642 for i in 0..EVENT_RING_CAPACITY {
643 let event = UsbHotplugEvent::DeviceDetached { port: i as u8 };
644 assert!(ring.push(event));
645 }
646 assert_eq!(ring.len(), EVENT_RING_CAPACITY);
647
648 let event = UsbHotplugEvent::DeviceDetached { port: 99 };
650 assert!(!ring.push(event));
651 }
652
653 #[test]
654 fn test_event_ring_buffer_wrap() {
655 let mut ring = EventRingBuffer::new();
656
657 for i in 0..8 {
659 ring.push(UsbHotplugEvent::DeviceDetached { port: i });
660 }
661 for _ in 0..4 {
662 ring.pop();
663 }
664 assert_eq!(ring.len(), 4);
665
666 for i in 0..8 {
668 ring.push(UsbHotplugEvent::DeviceDetached { port: 10 + i });
669 }
670 assert_eq!(ring.len(), 12);
671 }
672
673 #[test]
674 fn test_event_ring_buffer_clear() {
675 let mut ring = EventRingBuffer::new();
676 for i in 0..5 {
677 ring.push(UsbHotplugEvent::DeviceDetached { port: i });
678 }
679 ring.clear();
680 assert!(ring.is_empty());
681 assert_eq!(ring.len(), 0);
682 }
683
684 #[test]
685 fn test_hotplug_manager_new() {
686 let manager = UsbHotplugManager::new();
687 assert!(!manager.is_initialized());
688 assert_eq!(manager.num_ports(), 0);
689 }
690
691 #[test]
692 fn test_hotplug_manager_init() {
693 let mut manager = UsbHotplugManager::new();
694 manager.init(0x1000, 4);
695 assert!(manager.is_initialized());
696 assert_eq!(manager.num_ports(), 4);
697 }
698
699 #[test]
700 fn test_hotplug_manager_port_capping() {
701 let mut manager = UsbHotplugManager::new();
702 manager.init(0x1000, 255); assert_eq!(manager.num_ports(), MAX_PORTS as u8);
704 }
705
706 #[test]
707 fn test_hotplug_manager_port_status() {
708 let mut manager = UsbHotplugManager::new();
709 manager.init(0x1000, 4);
710
711 assert!(manager.port_status(0).is_some());
712 assert!(manager.port_status(3).is_some());
713 assert!(manager.port_status(4).is_none());
714
715 let status = manager.port_status(0).unwrap();
716 assert!(!status.connected);
717 assert!(!status.enabled);
718 }
719
720 #[test]
721 fn test_hotplug_manager_event_counters() {
722 let manager = UsbHotplugManager::new();
723 assert_eq!(manager.total_attach_events(), 0);
724 assert_eq!(manager.total_detach_events(), 0);
725 }
726
727 #[test]
728 fn test_hotplug_manager_no_events_when_uninit() {
729 let mut manager = UsbHotplugManager::new();
730 assert!(!manager.has_events());
731 assert!(manager.get_event().is_none());
732 }
733
734 #[test]
735 fn test_port_status_default() {
736 let status = UsbPortStatus::default();
737 assert!(!status.connected);
738 assert!(!status.enabled);
739 assert_eq!(status.vendor_id, 0);
740 assert_eq!(status.product_id, 0);
741 assert_eq!(status.device_class, 0);
742 }
743
744 #[test]
745 fn test_portsc_constants() {
746 assert_eq!(PORTSC_CCS, 0x0000_0001);
748 assert_eq!(PORTSC_PED, 0x0000_0002);
749 assert_eq!(PORTSC_CSC, 0x0002_0000);
750 assert_eq!(PORTSC_PEC, 0x0004_0000);
751 }
752
753 #[test]
754 fn test_register_callback_limit() {
755 let mut manager = UsbHotplugManager::new();
756 fn dummy(_: UsbHotplugEvent) {}
757
758 for _ in 0..4 {
759 assert!(manager.register_callback(dummy).is_ok());
760 }
761 assert!(manager.register_callback(dummy).is_err());
763 }
764}