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