1 //! PIO的串口驱动 2 3 use core::{ 4 hint::spin_loop, 5 sync::atomic::{AtomicBool, Ordering}, 6 }; 7 8 use alloc::{ 9 string::ToString, 10 sync::{Arc, Weak}, 11 }; 12 13 use crate::{ 14 arch::{driver::apic::ioapic::IoApic, io::PortIOArch, CurrentPortIOArch}, 15 driver::{ 16 base::device::{ 17 device_number::{DeviceNumber, Major}, 18 DeviceId, 19 }, 20 serial::{AtomicBaudRate, BaudRate, DivisorFraction, UartPort}, 21 tty::{ 22 kthread::send_to_tty_refresh_thread, 23 termios::WindowSize, 24 tty_core::{TtyCore, TtyCoreData}, 25 tty_driver::{TtyDriver, TtyDriverManager, TtyOperation}, 26 virtual_terminal::{vc_manager, VirtConsole}, 27 }, 28 }, 29 exception::{ 30 irqdata::IrqHandlerData, 31 irqdesc::{IrqHandleFlags, IrqHandler, IrqReturn}, 32 manage::irq_manager, 33 IrqNumber, 34 }, 35 libs::rwlock::RwLock, 36 }; 37 use system_error::SystemError; 38 39 use super::{Serial8250ISADevices, Serial8250ISADriver, Serial8250Manager, Serial8250Port}; 40 41 static mut PIO_PORTS: [Option<Serial8250PIOPort>; 8] = 42 [None, None, None, None, None, None, None, None]; 43 44 const SERIAL_8250_PIO_IRQ: IrqNumber = IrqNumber::new(IoApic::VECTOR_BASE as u32 + 4); 45 46 impl Serial8250Manager { 47 #[allow(static_mut_refs)] 48 pub(super) fn bind_pio_ports( 49 &self, 50 uart_driver: &Arc<Serial8250ISADriver>, 51 devs: &Arc<Serial8250ISADevices>, 52 ) { 53 for port in unsafe { &PIO_PORTS }.iter().flatten() { 54 port.set_device(Some(devs)); 55 self.uart_add_one_port(uart_driver, port).ok(); 56 } 57 } 58 } 59 60 macro_rules! init_port { 61 ($port_num:expr) => { 62 unsafe { 63 let port = Serial8250PIOPort::new( 64 match $port_num { 65 1 => Serial8250PortBase::COM1, 66 2 => Serial8250PortBase::COM2, 67 3 => Serial8250PortBase::COM3, 68 4 => Serial8250PortBase::COM4, 69 5 => Serial8250PortBase::COM5, 70 6 => Serial8250PortBase::COM6, 71 7 => Serial8250PortBase::COM7, 72 8 => Serial8250PortBase::COM8, 73 _ => panic!("invalid port number"), 74 }, 75 crate::driver::serial::SERIAL_BAUDRATE, 76 ); 77 if let Ok(port) = port { 78 if port.init().is_ok() { 79 PIO_PORTS[$port_num - 1] = Some(port); 80 true 81 } else { 82 false 83 } 84 } else { 85 false 86 } 87 } 88 }; 89 } 90 91 /// 在内存管理初始化之前,初始化串口设备 92 pub(super) fn serial8250_pio_port_early_init() -> Result<(), SystemError> { 93 for i in 1..=8 { 94 init_port!(i); 95 } 96 97 return Ok(()); 98 } 99 100 #[derive(Debug)] 101 pub struct Serial8250PIOPort { 102 iobase: Serial8250PortBase, 103 baudrate: AtomicBaudRate, 104 initialized: AtomicBool, 105 inner: RwLock<Serial8250PIOPortInner>, 106 } 107 108 impl Serial8250PIOPort { 109 const SERIAL8250PIO_MAX_BAUD_RATE: BaudRate = BaudRate::new(115200); 110 pub fn new(iobase: Serial8250PortBase, baudrate: BaudRate) -> Result<Self, SystemError> { 111 let r = Self { 112 iobase, 113 baudrate: AtomicBaudRate::new(baudrate), 114 initialized: AtomicBool::new(false), 115 inner: RwLock::new(Serial8250PIOPortInner::new()), 116 }; 117 118 r.check_baudrate(&baudrate)?; 119 120 return Ok(r); 121 } 122 123 pub fn init(&self) -> Result<(), SystemError> { 124 let r = self 125 .initialized 126 .compare_exchange(false, true, Ordering::SeqCst, Ordering::SeqCst); 127 if r.is_err() { 128 // 已经初始化 129 return Ok(()); 130 } 131 132 let port = self.iobase as u16; 133 unsafe { 134 CurrentPortIOArch::out8(port + 1, 0x00); // Disable all interrupts 135 self.set_divisor(self.baudrate.load(Ordering::SeqCst)) 136 .unwrap(); // Set baud rate 137 138 CurrentPortIOArch::out8(port + 2, 0xC7); // Enable FIFO, clear them, with 14-byte threshold 139 CurrentPortIOArch::out8(port + 4, 0x08); // IRQs enabled, RTS/DSR clear (现代计算机上一般都不需要hardware flow control,因此不需要置位RTS/DSR) 140 CurrentPortIOArch::out8(port + 4, 0x1E); // Set in loopback mode, test the serial chip 141 CurrentPortIOArch::out8(port, 0xAE); // Test serial chip (send byte 0xAE and check if serial returns same byte) 142 143 // Check if serial is faulty (i.e: not same byte as sent) 144 if CurrentPortIOArch::in8(port) != 0xAE { 145 self.initialized.store(false, Ordering::SeqCst); 146 return Err(SystemError::ENODEV); 147 } 148 149 // If serial is not faulty set it in normal operation mode 150 // (not-loopback with IRQs enabled and OUT#1 and OUT#2 bits enabled) 151 CurrentPortIOArch::out8(port + 4, 0x0b); 152 153 CurrentPortIOArch::out8(port + 1, 0x01); // Enable interrupts 154 } 155 156 return Ok(()); 157 /* 158 Notice that the initialization code above writes to [PORT + 1] 159 twice with different values. This is once to write to the Divisor 160 register along with [PORT + 0] and once to write to the Interrupt 161 register as detailed in the previous section. 162 The second write to the Line Control register [PORT + 3] 163 clears the DLAB again as well as setting various other bits. 164 */ 165 } 166 167 const fn check_baudrate(&self, baudrate: &BaudRate) -> Result<(), SystemError> { 168 // 错误的比特率 169 if baudrate.data() > Self::SERIAL8250PIO_MAX_BAUD_RATE.data() 170 || Self::SERIAL8250PIO_MAX_BAUD_RATE.data() % baudrate.data() != 0 171 { 172 return Err(SystemError::EINVAL); 173 } 174 175 return Ok(()); 176 } 177 178 #[allow(dead_code)] 179 fn serial_received(&self) -> bool { 180 self.serial_in(5) & 1 != 0 181 } 182 183 fn is_transmit_empty(&self) -> bool { 184 self.serial_in(5) & 0x20 != 0 185 } 186 187 /// 发送字节 188 /// 189 /// ## 参数 190 /// 191 /// - `s`:待发送的字节 192 fn send_bytes(&self, s: &[u8]) { 193 while !self.is_transmit_empty() { 194 spin_loop(); 195 } 196 197 for c in s { 198 self.serial_out(0, (*c).into()); 199 } 200 } 201 202 /// 读取一个字节,如果没有数据则返回None 203 fn read_one_byte(&self) -> Option<u8> { 204 if !self.serial_received() { 205 return None; 206 } 207 return Some(self.serial_in(0) as u8); 208 } 209 } 210 211 impl Serial8250Port for Serial8250PIOPort { 212 fn device(&self) -> Option<Arc<Serial8250ISADevices>> { 213 self.inner.read().device() 214 } 215 216 fn set_device(&self, device: Option<&Arc<Serial8250ISADevices>>) { 217 self.inner.write().set_device(device); 218 } 219 } 220 221 impl UartPort for Serial8250PIOPort { 222 fn serial_in(&self, offset: u32) -> u32 { 223 unsafe { CurrentPortIOArch::in8(self.iobase as u16 + offset as u16).into() } 224 } 225 226 fn serial_out(&self, offset: u32, value: u32) { 227 // warning: pio的串口只能写入8位,因此这里丢弃高24位 228 unsafe { CurrentPortIOArch::out8(self.iobase as u16 + offset as u16, value as u8) } 229 } 230 231 fn divisor(&self, baud: BaudRate) -> (u32, DivisorFraction) { 232 let divisor = Self::SERIAL8250PIO_MAX_BAUD_RATE.data() / baud.data(); 233 return (divisor, DivisorFraction::new(0)); 234 } 235 236 fn set_divisor(&self, baud: BaudRate) -> Result<(), SystemError> { 237 self.check_baudrate(&baud)?; 238 239 let port = self.iobase as u16; 240 unsafe { 241 CurrentPortIOArch::out8(port + 3, 0x80); // Enable DLAB (set baud rate divisor) 242 243 let divisor = self.divisor(baud).0; 244 245 CurrentPortIOArch::out8(port, (divisor & 0xff) as u8); // Set divisor (lo byte) 246 CurrentPortIOArch::out8(port + 1, ((divisor >> 8) & 0xff) as u8); // (hi byte) 247 CurrentPortIOArch::out8(port + 3, 0x03); // 8 bits, no parity, one stop bit 248 } 249 250 self.baudrate.store(baud, Ordering::SeqCst); 251 252 return Ok(()); 253 } 254 255 fn startup(&self) -> Result<(), SystemError> { 256 todo!("serial8250_pio::startup") 257 } 258 259 fn shutdown(&self) { 260 todo!("serial8250_pio::shutdown") 261 } 262 263 fn baud_rate(&self) -> Option<BaudRate> { 264 Some(self.baudrate.load(Ordering::SeqCst)) 265 } 266 267 fn handle_irq(&self) -> Result<(), SystemError> { 268 if let Some(c) = self.read_one_byte() { 269 send_to_tty_refresh_thread(&[c]); 270 } 271 Ok(()) 272 } 273 274 fn iobase(&self) -> Option<usize> { 275 Some(self.iobase as usize) 276 } 277 } 278 279 #[derive(Debug)] 280 struct Serial8250PIOPortInner { 281 /// 当前端口绑定的设备 282 /// 283 /// ps: 存储weak以避免循环引用 284 device: Option<Weak<Serial8250ISADevices>>, 285 } 286 287 impl Serial8250PIOPortInner { 288 pub const fn new() -> Self { 289 Self { device: None } 290 } 291 292 #[allow(dead_code)] 293 pub fn device(&self) -> Option<Arc<Serial8250ISADevices>> { 294 if let Some(device) = self.device.as_ref() { 295 return device.upgrade(); 296 } 297 return None; 298 } 299 300 fn set_device(&mut self, device: Option<&Arc<Serial8250ISADevices>>) { 301 self.device = device.map(Arc::downgrade); 302 } 303 } 304 305 #[allow(dead_code)] 306 #[repr(u16)] 307 #[derive(Clone, Debug, Copy)] 308 pub enum Serial8250PortBase { 309 COM1 = 0x3f8, 310 COM2 = 0x2f8, 311 COM3 = 0x3e8, 312 COM4 = 0x2e8, 313 COM5 = 0x5f8, 314 COM6 = 0x4f8, 315 COM7 = 0x5e8, 316 COM8 = 0x4e8, 317 } 318 319 /// 临时函数,用于向COM1发送数据 320 pub fn send_to_default_serial8250_pio_port(s: &[u8]) { 321 if let Some(port) = unsafe { PIO_PORTS[0].as_ref() } { 322 port.send_bytes(s); 323 } 324 } 325 326 #[derive(Debug)] 327 pub(super) struct Serial8250PIOTtyDriverInner; 328 329 impl Serial8250PIOTtyDriverInner { 330 pub fn new() -> Self { 331 Self 332 } 333 334 fn do_install( 335 &self, 336 driver: Arc<TtyDriver>, 337 tty: Arc<TtyCore>, 338 vc: Arc<VirtConsole>, 339 ) -> Result<(), SystemError> { 340 driver.standard_install(tty.clone())?; 341 vc.port().setup_internal_tty(Arc::downgrade(&tty)); 342 tty.set_port(vc.port()); 343 vc.devfs_setup()?; 344 345 Ok(()) 346 } 347 } 348 349 impl TtyOperation for Serial8250PIOTtyDriverInner { 350 fn open(&self, _tty: &TtyCoreData) -> Result<(), SystemError> { 351 Ok(()) 352 } 353 354 fn write(&self, tty: &TtyCoreData, buf: &[u8], nr: usize) -> Result<usize, SystemError> { 355 let index = tty.index(); 356 if tty.index() >= unsafe { PIO_PORTS.len() } { 357 return Err(SystemError::ENODEV); 358 } 359 let pio_port = unsafe { PIO_PORTS[index].as_ref() }.ok_or(SystemError::ENODEV)?; 360 pio_port.send_bytes(&buf[..nr]); 361 362 Ok(nr) 363 } 364 365 fn flush_chars(&self, _tty: &TtyCoreData) {} 366 367 fn put_char(&self, tty: &TtyCoreData, ch: u8) -> Result<(), SystemError> { 368 self.write(tty, &[ch], 1).map(|_| ()) 369 } 370 371 fn ioctl(&self, _tty: Arc<TtyCore>, _cmd: u32, _arg: usize) -> Result<(), SystemError> { 372 Err(SystemError::ENOIOCTLCMD) 373 } 374 375 fn close(&self, _tty: Arc<TtyCore>) -> Result<(), SystemError> { 376 Ok(()) 377 } 378 379 fn resize(&self, tty: Arc<TtyCore>, winsize: WindowSize) -> Result<(), SystemError> { 380 *tty.core().window_size_write() = winsize; 381 Ok(()) 382 } 383 384 fn install(&self, driver: Arc<TtyDriver>, tty: Arc<TtyCore>) -> Result<(), SystemError> { 385 if tty.core().index() >= unsafe { PIO_PORTS.len() } { 386 return Err(SystemError::ENODEV); 387 } 388 let vc = VirtConsole::new(None); 389 let vc_index = vc_manager().alloc(vc.clone()).ok_or(SystemError::EBUSY)?; 390 self.do_install(driver, tty, vc.clone()).inspect_err(|_| { 391 vc_manager().free(vc_index); 392 })?; 393 394 Ok(()) 395 } 396 } 397 398 pub(super) fn serial_8250_pio_register_tty_devices() -> Result<(), SystemError> { 399 let (_, driver) = TtyDriverManager::lookup_tty_driver(DeviceNumber::new( 400 Major::TTY_MAJOR, 401 Serial8250Manager::TTY_SERIAL_MINOR_START, 402 )) 403 .ok_or(SystemError::ENODEV)?; 404 405 for (i, port) in unsafe { PIO_PORTS.iter() }.enumerate() { 406 if let Some(port) = port { 407 let core = driver.init_tty_device(Some(i)).inspect_err(|_| { 408 log::error!( 409 "failed to init tty device for serial 8250 pio port {}, port iobase: {:?}", 410 i, 411 port.iobase 412 ); 413 })?; 414 core.resize( core.clone(), WindowSize::DEFAULT) 415 .inspect_err(|_| { 416 log::error!( 417 "failed to resize tty device for serial 8250 pio port {}, port iobase: {:?}", 418 i, 419 port.iobase 420 ); 421 })?; 422 } 423 } 424 425 irq_manager() 426 .request_irq( 427 SERIAL_8250_PIO_IRQ, 428 "serial8250_pio".to_string(), 429 &Serial8250IrqHandler, 430 IrqHandleFlags::IRQF_SHARED | IrqHandleFlags::IRQF_TRIGGER_RISING, 431 Some(DeviceId::new(Some("serial8250_pio"), None).unwrap()), 432 ) 433 .inspect_err(|e| { 434 log::error!("failed to request irq for serial 8250 pio: {:?}", e); 435 })?; 436 437 Ok(()) 438 } 439 440 #[derive(Debug)] 441 struct Serial8250IrqHandler; 442 443 impl IrqHandler for Serial8250IrqHandler { 444 fn handle( 445 &self, 446 _irq: IrqNumber, 447 _static_data: Option<&dyn IrqHandlerData>, 448 _dynamic_data: Option<Arc<dyn IrqHandlerData>>, 449 ) -> Result<IrqReturn, SystemError> { 450 for port in unsafe { PIO_PORTS.iter() }.flatten() { 451 port.handle_irq()?; 452 } 453 454 Ok(IrqReturn::Handled) 455 } 456 } 457