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