macaque/drivers/serial/
uart.rs

1//! UART driver for the 16550 chip.
2//! Note this currently does not support reading into a buffer.
3//!
4//! # Usage Example:
5//! ```
6//! lazy_static::lazy_static! {
7//!     pub static ref SERIAL: uart::SerialPort = uart::SerialPort::new(0x1000_0000);
8//! }
9//!
10//! #[macro_export]
11//! macro_rules! print {
12//!     	($($args:tt)+) => ({
13//! 			use core::fmt::Write;
14//! 			let _ = write!(crate::io::serial::SERIAL.lock(), $($args)+);
15//! 	});
16//! }
17//! #[macro_export]
18//! macro_rules! println
19//! {
20//! 	() => ({
21//! 		print!("\r\n")
22//! 	});
23//! 	($fmt:expr) => ({
24//! 		crate::print!(concat!($fmt, "\r\n"))
25//! 	});
26//! 	($fmt:expr, $($args:tt)+) => ({
27//! 		crate::print!(concat!($fmt, "\r\n"), $($args)+)
28//! 	});
29//! }
30//! ```
31
32
33#![allow(dead_code)]
34
35use crate::{cpu::port::Port, sync::spinlock::SpinLock};
36
37pub struct SerialPort {
38    regs: SpinLock<SerialInner>,
39}
40
41pub struct SerialInner {
42    data: Port,
43    irq_enable: Port,
44    irq_id: Port,
45    line_ctrl: Port,
46    modem_ctrl: Port,
47    line_status: Port,
48    modem_status: Port,
49    scratch: Port,
50
51    baud_rate_divisor: u16,
52}
53
54impl SerialInner {
55    pub fn new(base: u32) -> Self {
56        let regs = Self {
57            data: Port::new(base),
58            irq_enable: Port::new(base + 1),
59            irq_id: Port::new(base + 2),
60            line_ctrl: Port::new(base + 3),
61            modem_ctrl: Port::new(base + 4),
62            line_status: Port::new(base + 5),
63            modem_status: Port::new(base + 6),
64            scratch: Port::new(base + 7),
65            baud_rate_divisor: 3,
66        };
67
68        #[cfg(debug_assertions)]
69        // validate reads and writes via scratch register
70        // we set this to 0 before hand just to avert any weird race
71        // conditions with this check
72        unsafe {
73            let before = regs.scratch.readb();
74            regs.scratch.writeb(127);
75            let after = regs.scratch.readb();
76            assert_ne!(before, after);
77            regs.scratch.writeb(0);
78        }
79
80        regs
81    }
82
83    const DLAB_BIT: u8 = 0b1000_0000;
84
85    fn without_irqs<T>(&mut self, f: impl FnOnce(&mut Self) -> T) -> T {
86        unsafe {
87            self.irq_enable.writeb(0x00);
88        }
89        let res = f(self);
90        unsafe {
91            self.irq_enable.writeb(0x01);
92        }
93        res
94    }
95
96    fn set_baud_rate_divisor(&mut self, divisor: u16) -> u16 {
97        let prev = self.baud_rate_divisor;
98        if divisor == 0 {
99            panic!("DLAB BIT NOT SET")
100        }
101
102        let lcr_state = unsafe { self.line_ctrl.readb() };
103        if lcr_state & Self::DLAB_BIT != 0 {
104            // TODO Error here
105            panic!("DLAB BIT NOT SET")
106        }
107
108        unsafe {
109            // set the Divisor Latch Access Bit. now, the data port and irq enable
110            // port can be used to set the least and most significant bytes of the
111            // divisor, respectively.
112            self.line_ctrl.writeb(lcr_state | Self::DLAB_BIT);
113
114            // least significant byte
115            self.data.writeb((divisor & 0x00FF) as u8);
116            // most significant byte
117            self.irq_enable.writeb((divisor >> 8) as u8);
118
119            self.line_ctrl.writeb(lcr_state);
120        }
121
122        self.baud_rate_divisor = divisor;
123
124        prev
125    }
126
127    #[inline]
128    pub fn write_char(&self, b: u8) {
129        while !self.write_rdy() {
130            core::hint::spin_loop()
131        }
132        unsafe {
133            self.data.writeb(b);
134        }
135    }
136
137    #[inline]
138    fn write_rdy(&self) -> bool {
139        unsafe { self.line_status.readb() & 0x20 != 0 }
140    }
141
142    #[inline]
143    fn read_rdy(&self) -> bool {
144        unsafe { self.line_status.readb() & 0x1 == 1 }
145    }
146
147    #[inline]
148    fn print(&self, s: &str) {
149        for b in s.bytes() {
150            self.write_char(b)
151        }
152    }
153}
154impl core::fmt::Write for SerialInner {
155    fn write_str(&mut self, s: &str) -> core::fmt::Result {
156        Ok(self.print(s))
157    }
158}
159
160impl SerialPort {
161    pub fn new(base_addr: u32) -> Self {
162        let mut regs = SerialInner::new(base_addr);
163
164        // Disable all interrupts
165        regs.without_irqs(|registers| unsafe {
166            // Set divisor to 38400 baud
167            registers.set_baud_rate_divisor(3);
168
169            // 8 bits, no parity, one stop bit
170            registers.line_ctrl.writeb(0x03);
171
172            // Enable FIFO with 14-byte threshold
173            registers.irq_id.writeb(0xC7);
174
175            // RTS/DSR set
176            registers.modem_ctrl.writeb(0x0B);
177        });
178
179        Self {
180            regs: SpinLock::new(regs),
181        }
182    }
183
184    pub fn lock(&self) -> crate::sync::spinlock::Guard<SerialInner> {
185        self.regs.lock()
186    }
187
188    pub fn read_char(&self) -> char {
189        while !self.regs.lock().read_rdy() {
190            core::hint::spin_loop()
191        }
192        unsafe { self.regs.lock().data.readb() as char }
193    }
194
195    pub fn read_char_non_blocking(&self) -> Option<char> {
196        let r = self.regs.lock();
197        if r.read_rdy() {
198            unsafe { Some(r.data.readb() as char) }
199        } else {
200            None
201        }
202    }
203}