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