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