macaque/drivers/serial/
uart.rs1#![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 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 panic!("DLAB BIT NOT SET")
106 }
107
108 unsafe {
109 self.line_ctrl.writeb(lcr_state | Self::DLAB_BIT);
113
114 self.data.writeb((divisor & 0x00FF) as u8);
116 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 regs.without_irqs(|registers| unsafe {
166 registers.set_baud_rate_divisor(3);
168
169 registers.line_ctrl.writeb(0x03);
171
172 registers.irq_id.writeb(0xC7);
174
175 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}