xref: /DragonOS/kernel/src/driver/serial/serial8250/serial8250_pio.rs (revision 52dc4c3ee87b31fee4f567f776fd8ad58fbfd9a5)
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