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