1use core::{
2 fmt,
3 sync::atomic::{AtomicPtr, Ordering},
4};
5
6use crate::{LineStsFlags, WouldBlockError};
7
8#[derive(Debug)]
10pub struct MmioSerialPort {
11 data: AtomicPtr<u8>,
12 int_en: AtomicPtr<u8>,
13 fifo_ctrl: AtomicPtr<u8>,
14 line_ctrl: AtomicPtr<u8>,
15 modem_ctrl: AtomicPtr<u8>,
16 line_sts: AtomicPtr<u8>,
17}
18
19impl MmioSerialPort {
20 #[rustversion::attr(since(1.61), const)]
25 pub unsafe fn new(base: usize) -> Self {
26 Self::new_with_stride(base, 1)
27 }
28
29 #[rustversion::attr(since(1.61), const)]
35 pub unsafe fn new_with_stride(base: usize, stride: usize) -> Self {
36 let base_pointer = base as *mut u8;
37 Self {
38 data: AtomicPtr::new(base_pointer),
39 int_en: AtomicPtr::new(base_pointer.add(1 * stride)),
40 fifo_ctrl: AtomicPtr::new(base_pointer.add(2 * stride)),
41 line_ctrl: AtomicPtr::new(base_pointer.add(3 * stride)),
42 modem_ctrl: AtomicPtr::new(base_pointer.add(4 * stride)),
43 line_sts: AtomicPtr::new(base_pointer.add(5 * stride)),
44 }
45 }
46
47 pub fn init(&mut self) {
51 let self_int_en = self.int_en.load(Ordering::Relaxed);
52 let self_line_ctrl = self.line_ctrl.load(Ordering::Relaxed);
53 let self_data = self.data.load(Ordering::Relaxed);
54 let self_fifo_ctrl = self.fifo_ctrl.load(Ordering::Relaxed);
55 let self_modem_ctrl = self.modem_ctrl.load(Ordering::Relaxed);
56 unsafe {
57 self_int_en.write(0x00);
59
60 self_line_ctrl.write(0x80);
62
63 self_data.write(0x03);
65 self_int_en.write(0x00);
66
67 self_line_ctrl.write(0x03);
69
70 self_fifo_ctrl.write(0xC7);
73
74 self_modem_ctrl.write(0x0B);
77
78 self_int_en.write(0x01);
80 }
81 }
82
83 fn line_sts(&mut self) -> LineStsFlags {
84 unsafe { LineStsFlags::from_bits_truncate(*self.line_sts.load(Ordering::Relaxed)) }
85 }
86
87 pub fn send(&mut self, data: u8) {
89 match data {
90 8 | 0x7F => {
91 self.send_raw(8);
92 self.send_raw(b' ');
93 self.send_raw(8);
94 }
95 data => {
96 self.send_raw(data);
97 }
98 }
99 }
100
101 pub fn send_raw(&mut self, data: u8) {
103 retry_until_ok!(self.try_send_raw(data))
104 }
105
106 pub fn try_send_raw(&mut self, data: u8) -> Result<(), WouldBlockError> {
108 if self.line_sts().contains(LineStsFlags::OUTPUT_EMPTY) {
109 let self_data = self.data.load(Ordering::Relaxed);
110 unsafe {
111 self_data.write(data);
112 }
113 Ok(())
114 } else {
115 Err(WouldBlockError)
116 }
117 }
118
119 pub fn receive(&mut self) -> u8 {
121 retry_until_ok!(self.try_receive())
122 }
123
124 pub fn try_receive(&mut self) -> Result<u8, WouldBlockError> {
126 if self.line_sts().contains(LineStsFlags::INPUT_FULL) {
127 let self_data = self.data.load(Ordering::Relaxed);
128 let data = unsafe { self_data.read() };
129 Ok(data)
130 } else {
131 Err(WouldBlockError)
132 }
133 }
134}
135
136impl fmt::Write for MmioSerialPort {
137 fn write_str(&mut self, s: &str) -> fmt::Result {
138 for byte in s.bytes() {
139 self.send(byte);
140 }
141 Ok(())
142 }
143}