1 //! PIO的串口驱动 2 3 use core::{ 4 hint::spin_loop, 5 sync::atomic::{AtomicBool, Ordering}, 6 }; 7 8 use alloc::sync::{Arc, Weak}; 9 10 use crate::{ 11 arch::{io::PortIOArch, CurrentPortIOArch}, 12 driver::serial::{AtomicBaudRate, BaudRate, DivisorFraction, UartPort}, 13 libs::rwlock::RwLock, 14 }; 15 use system_error::SystemError; 16 17 use super::{Serial8250ISADevices, Serial8250ISADriver, Serial8250Manager, Serial8250Port}; 18 19 static mut PIO_PORTS: [Option<Serial8250PIOPort>; 8] = 20 [None, None, None, None, None, None, None, None]; 21 22 impl Serial8250Manager { 23 #[allow(static_mut_refs)] 24 pub(super) fn bind_pio_ports( 25 &self, 26 uart_driver: &Arc<Serial8250ISADriver>, 27 devs: &Arc<Serial8250ISADevices>, 28 ) { 29 for port in unsafe { &PIO_PORTS }.iter().flatten() { 30 port.set_device(Some(devs)); 31 self.uart_add_one_port(uart_driver, port).ok(); 32 } 33 } 34 } 35 36 macro_rules! init_port { 37 ($port_num:expr, $baudrate:expr) => { 38 unsafe { 39 let port = Serial8250PIOPort::new( 40 match $port_num { 41 1 => Serial8250PortBase::COM1, 42 2 => Serial8250PortBase::COM2, 43 3 => Serial8250PortBase::COM3, 44 4 => Serial8250PortBase::COM4, 45 5 => Serial8250PortBase::COM5, 46 6 => Serial8250PortBase::COM6, 47 7 => Serial8250PortBase::COM7, 48 8 => Serial8250PortBase::COM8, 49 _ => panic!("invalid port number"), 50 }, 51 BaudRate::new($baudrate), 52 ); 53 if let Ok(port) = port { 54 if port.init().is_ok() { 55 PIO_PORTS[$port_num - 1] = Some(port); 56 } 57 } 58 } 59 }; 60 } 61 62 /// 在内存管理初始化之前,初始化串口设备 63 pub(super) fn serial8250_pio_port_early_init() -> Result<(), SystemError> { 64 for i in 1..=8 { 65 init_port!(i, 115200); 66 } 67 return Ok(()); 68 } 69 70 #[derive(Debug)] 71 pub struct Serial8250PIOPort { 72 iobase: Serial8250PortBase, 73 baudrate: AtomicBaudRate, 74 initialized: AtomicBool, 75 inner: RwLock<Serial8250PIOPortInner>, 76 } 77 78 impl Serial8250PIOPort { 79 const SERIAL8250PIO_MAX_BAUD_RATE: BaudRate = BaudRate::new(115200); 80 pub fn new(iobase: Serial8250PortBase, baudrate: BaudRate) -> Result<Self, SystemError> { 81 let r = Self { 82 iobase, 83 baudrate: AtomicBaudRate::new(baudrate), 84 initialized: AtomicBool::new(false), 85 inner: RwLock::new(Serial8250PIOPortInner::new()), 86 }; 87 88 r.check_baudrate(&baudrate)?; 89 90 return Ok(r); 91 } 92 93 pub fn init(&self) -> Result<(), SystemError> { 94 let r = self 95 .initialized 96 .compare_exchange(false, true, Ordering::SeqCst, Ordering::SeqCst); 97 if r.is_err() { 98 // 已经初始化 99 return Ok(()); 100 } 101 102 let port = self.iobase as u16; 103 104 unsafe { 105 CurrentPortIOArch::out8(port + 1, 0x00); // Disable all interrupts 106 self.set_divisor(self.baudrate.load(Ordering::SeqCst)) 107 .unwrap(); // Set baud rate 108 109 CurrentPortIOArch::out8(port + 2, 0xC7); // Enable FIFO, clear them, with 14-byte threshold 110 CurrentPortIOArch::out8(port + 4, 0x08); // IRQs enabled, RTS/DSR clear (现代计算机上一般都不需要hardware flow control,因此不需要置位RTS/DSR) 111 CurrentPortIOArch::out8(port + 4, 0x1E); // Set in loopback mode, test the serial chip 112 CurrentPortIOArch::out8(port, 0xAE); // Test serial chip (send byte 0xAE and check if serial returns same byte) 113 114 // Check if serial is faulty (i.e: not same byte as sent) 115 if CurrentPortIOArch::in8(port) != 0xAE { 116 self.initialized.store(false, Ordering::SeqCst); 117 return Err(SystemError::ENODEV); 118 } 119 120 // If serial is not faulty set it in normal operation mode 121 // (not-loopback with IRQs enabled and OUT#1 and OUT#2 bits enabled) 122 CurrentPortIOArch::out8(port + 4, 0x08); 123 } 124 125 return Ok(()); 126 /* 127 Notice that the initialization code above writes to [PORT + 1] 128 twice with different values. This is once to write to the Divisor 129 register along with [PORT + 0] and once to write to the Interrupt 130 register as detailed in the previous section. 131 The second write to the Line Control register [PORT + 3] 132 clears the DLAB again as well as setting various other bits. 133 */ 134 } 135 136 const fn check_baudrate(&self, baudrate: &BaudRate) -> Result<(), SystemError> { 137 // 错误的比特率 138 if baudrate.data() > Self::SERIAL8250PIO_MAX_BAUD_RATE.data() 139 || Self::SERIAL8250PIO_MAX_BAUD_RATE.data() % baudrate.data() != 0 140 { 141 return Err(SystemError::EINVAL); 142 } 143 144 return Ok(()); 145 } 146 147 #[allow(dead_code)] 148 fn serial_received(&self) -> bool { 149 self.serial_in(5) & 1 != 0 150 } 151 152 fn is_transmit_empty(&self) -> bool { 153 self.serial_in(5) & 0x20 != 0 154 } 155 156 /// 发送字节 157 /// 158 /// ## 参数 159 /// 160 /// - `s`:待发送的字节 161 fn send_bytes(&self, s: &[u8]) { 162 while !self.is_transmit_empty() { 163 spin_loop(); 164 } 165 166 for c in s { 167 self.serial_out(0, (*c).into()); 168 } 169 } 170 171 /// 读取一个字节 172 #[allow(dead_code)] 173 fn read_one_byte(&self) -> u8 { 174 while !self.serial_received() { 175 spin_loop(); 176 } 177 return self.serial_in(0) as u8; 178 } 179 } 180 181 impl Serial8250Port for Serial8250PIOPort { 182 fn device(&self) -> Option<Arc<Serial8250ISADevices>> { 183 self.inner.read().device() 184 } 185 186 fn set_device(&self, device: Option<&Arc<Serial8250ISADevices>>) { 187 self.inner.write().set_device(device); 188 } 189 } 190 191 impl UartPort for Serial8250PIOPort { 192 fn serial_in(&self, offset: u32) -> u32 { 193 unsafe { CurrentPortIOArch::in8(self.iobase as u16 + offset as u16).into() } 194 } 195 196 fn serial_out(&self, offset: u32, value: u32) { 197 // warning: pio的串口只能写入8位,因此这里丢弃高24位 198 unsafe { CurrentPortIOArch::out8(self.iobase as u16 + offset as u16, value as u8) } 199 } 200 201 fn divisor(&self, baud: BaudRate) -> (u32, DivisorFraction) { 202 let divisor = Self::SERIAL8250PIO_MAX_BAUD_RATE.data() / baud.data(); 203 return (divisor, DivisorFraction::new(0)); 204 } 205 206 fn set_divisor(&self, baud: BaudRate) -> Result<(), SystemError> { 207 self.check_baudrate(&baud)?; 208 209 let port = self.iobase as u16; 210 unsafe { 211 CurrentPortIOArch::out8(port + 3, 0x80); // Enable DLAB (set baud rate divisor) 212 213 let divisor = self.divisor(baud).0; 214 215 CurrentPortIOArch::out8(port, (divisor & 0xff) as u8); // Set divisor (lo byte) 216 CurrentPortIOArch::out8(port + 1, ((divisor >> 8) & 0xff) as u8); // (hi byte) 217 CurrentPortIOArch::out8(port + 3, 0x03); // 8 bits, no parity, one stop bit 218 } 219 220 self.baudrate.store(baud, Ordering::SeqCst); 221 222 return Ok(()); 223 } 224 225 fn startup(&self) -> Result<(), SystemError> { 226 todo!("serial8250_pio::startup") 227 } 228 229 fn shutdown(&self) { 230 todo!("serial8250_pio::shutdown") 231 } 232 233 fn baud_rate(&self) -> Option<BaudRate> { 234 Some(self.baudrate.load(Ordering::SeqCst)) 235 } 236 237 fn handle_irq(&self) -> Result<(), SystemError> { 238 todo!("serial8250_pio::handle_irq") 239 } 240 } 241 242 #[derive(Debug)] 243 struct Serial8250PIOPortInner { 244 /// 当前端口绑定的设备 245 /// 246 /// ps: 存储weak以避免循环引用 247 device: Option<Weak<Serial8250ISADevices>>, 248 } 249 250 impl Serial8250PIOPortInner { 251 pub const fn new() -> Self { 252 Self { device: None } 253 } 254 255 #[allow(dead_code)] 256 pub fn device(&self) -> Option<Arc<Serial8250ISADevices>> { 257 if let Some(device) = self.device.as_ref() { 258 return device.upgrade(); 259 } 260 return None; 261 } 262 263 fn set_device(&mut self, device: Option<&Arc<Serial8250ISADevices>>) { 264 self.device = device.map(Arc::downgrade); 265 } 266 } 267 268 #[allow(dead_code)] 269 #[repr(u16)] 270 #[derive(Clone, Debug, Copy)] 271 pub enum Serial8250PortBase { 272 COM1 = 0x3f8, 273 COM2 = 0x2f8, 274 COM3 = 0x3e8, 275 COM4 = 0x2e8, 276 COM5 = 0x5f8, 277 COM6 = 0x4f8, 278 COM7 = 0x5e8, 279 COM8 = 0x4e8, 280 } 281 282 /// 临时函数,用于向COM1发送数据 283 pub fn send_to_serial8250_pio_com1(s: &[u8]) { 284 if let Some(port) = unsafe { PIO_PORTS[0].as_ref() } { 285 port.send_bytes(s); 286 } 287 } 288