1pub macro wait_for {
2 ($cond:expr) => {
3 while !$cond {
4 core::hint::spin_loop()
5 }
6 }
7}
8
9bitflags!{
10 struct LineStatusFlags: u8 {
12 const INPUT_FULL = 1;
13 const OUTPUT_EMPTY = 1 << 5;
15 }
17}
18
19bitflags!{
20 struct InterruptEnableFlags: u8 {
21 const RECEIVED = 1;
22 const SENT = 1 << 1;
23 const ERRORED = 1 << 2;
24 const STATUS_CHANGE = 1 << 3;
25 }
27}
28
29#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
33#[derive(Debug)]
34pub struct SerialPort(u16);
35
36impl SerialPort {
37 fn base_port(&self) -> u16 {
41 self.0
42 }
43
44 fn interrupt_enable(&self) -> u16 {
48 return self.base_port() + 1;
49 }
50
51 fn fifo_control(&self) -> u16 {
55 return self.base_port() + 2;
56 }
57
58 fn line_control(&self) -> u16 {
62 return self.base_port() + 3;
63 }
64
65 fn modem_control(&self) -> u16 {
69 return self.base_port() + 4;
70 }
71
72 fn line_status_port(&self) -> u16 {
76 return self.base_port() + 5;
77 }
78
79 fn line_status(&self) -> LineStatusFlags {
80 return unsafe {
81 LineStatusFlags::from_bits_truncate(x86::io::inb(self.line_status_port()))
82 };
83 }
84
85 pub const unsafe fn new(base: u16) -> Self {
91 return SerialPort(base);
92 }
93
94 pub fn init(&mut self) {
98 unsafe {
99 x86::io::outb(self.interrupt_enable(), 0x00);
101
102 x86::io::outb(self.line_control(), 0x80);
104
105 x86::io::outb(self.base_port(), 0x03);
107 x86::io::outb(self.interrupt_enable(), 0x00);
108
109 x86::io::outb(self.line_control(), 0x03);
111
112 x86::io::outb(self.fifo_control(), 0xc7);
115
116 x86::io::outb(self.modem_control(), 0x0b);
119
120 x86::io::outb(self.interrupt_enable(), 0x01);
122 }
123 }
124
125 pub fn send(&mut self, data: u8) {
127 unsafe {
128 match data {
129 8 | 0x7F => {
130 wait_for!(self.line_status().contains(LineStatusFlags::OUTPUT_EMPTY));
131 x86::io::outb(self.base_port(), 8);
132 wait_for!(self.line_status().contains(LineStatusFlags::OUTPUT_EMPTY));
133 x86::io::outb(self.base_port(), b' ');
134 wait_for!(self.line_status().contains(LineStatusFlags::OUTPUT_EMPTY));
135 x86::io::outb(self.base_port(), 8);
136 }
137 _ => {
138 wait_for!(self.line_status().contains(LineStatusFlags::OUTPUT_EMPTY));
139 x86::io::outb(self.base_port(), data);
140 }
141 }
142 }
143 }
144
145 pub fn send_raw(&mut self, data: u8) {
147 unsafe {
148 wait_for!(self.line_status().contains(LineStatusFlags::OUTPUT_EMPTY));
149 x86::io::outb(self.base_port(), data);
150 }
151 }
152
153 pub fn receive(&mut self) -> u8 {
155 unsafe {
156 wait_for!(self.line_status().contains(LineStatusFlags::INPUT_FULL));
157 x86::io::inb(self.base_port())
158 }
159 }
160}
161
162impl fmt::Write for SerialPort {
163 fn write_str(&mut self, s: &str) -> fmt::Result {
164 for byte in s.bytes() {
165 self.send(byte);
166 }
167 Ok(())
168 }
169}
170
171#[derive(Debug)]
174pub struct MmioPort {
175 data: AtomicPtr<u8>,
176 interrupt_enable: AtomicPtr<u8>,
177 fifo_control: AtomicPtr<u8>,
178 line_control: AtomicPtr<u8>,
179 modem_control: AtomicPtr<u8>,
180 line_status: AtomicPtr<u8>,
181}
182
183impl MmioPort {
184 #[rustversion::attr(since(1.61), const)]
189 pub unsafe fn new(base: usize) -> Self {
190 let base_pointer = base as *mut u8;
191 return MmioPort{
192 data: AtomicPtr::new(base_pointer),
193 interrupt_enable: AtomicPtr::new(base_pointer.add(1)),
194 fifo_control: AtomicPtr::new(base_pointer.add(2)),
195 line_control: AtomicPtr::new(base_pointer.add(3)),
196 modem_control: AtomicPtr::new(base_pointer.add(4)),
197 line_status: AtomicPtr::new(base_pointer.add(5)),
198 };
199 }
200
201 pub fn init(&mut self) {
205 let self_interrupt_enable = self.interrupt_enable.load(Ordering::Relaxed);
206 let self_line_control = self.line_control.load(Ordering::Relaxed);
207 let self_data = self.data.load(Ordering::Relaxed);
208 let self_fifo_control = self.fifo_control.load(Ordering::Relaxed);
209 let self_modem_control = self.modem_control.load(Ordering::Relaxed);
210
211 unsafe {
212 self_interrupt_enable.write(0x00);
214
215 self_line_control.write(0x80);
217
218 self_data.write(0x03);
220 self_interrupt_enable.write(0x00);
221
222 self_line_control.write(0x03);
224
225 self_fifo_control.write(0xC7);
228
229 self_modem_control.write(0x0B);
232
233 self_interrupt_enable.write(0x01);
235 }
236 }
237
238 fn line_status(&mut self) -> LineStatusFlags {
239 unsafe { LineStatusFlags::from_bits_truncate(*self.line_status.load(Ordering::Relaxed)) }
240 }
241
242 pub fn send(&mut self, data: u8) {
244 let self_data = self.data.load(Ordering::Relaxed);
245
246 unsafe {
247 match data {
248 8 | 0x7F => {
249 wait_for!(self.line_status().contains(LineStatusFlags::OUTPUT_EMPTY));
250 self_data.write(8);
251 wait_for!(self.line_status().contains(LineStatusFlags::OUTPUT_EMPTY));
252 self_data.write(b' ');
253 wait_for!(self.line_status().contains(LineStatusFlags::OUTPUT_EMPTY));
254 self_data.write(8)
255 }
256 _ => {
257 wait_for!(self.line_status().contains(LineStatusFlags::OUTPUT_EMPTY));
258 self_data.write(data);
259 }
260 }
261 }
262 }
263
264 pub fn receive(&mut self) -> u8 {
266 let self_data = self.data.load(Ordering::Relaxed);
267
268 unsafe {
269 wait_for!(self.line_status().contains(LineStatusFlags::INPUT_FULL));
270 self_data.read()
271 }
272 }
273}
274
275impl fmt::Write for MmioPort {
276 fn write_str(&mut self, s: &str) -> fmt::Result {
277 for byte in s.bytes() {
278 self.send(byte);
279 }
280
281 Ok(())
282 }
283}
284
285use {
288 bitflags::bitflags,
289 core::{
290 fmt,
291 sync::atomic::{
292 AtomicPtr, Ordering,
293 },
294 },
295};