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