1use core::ptr;
2use core::sync::atomic::Ordering;
3
4use crate::memlayout::UART0;
5use crate::printf::PRINTF;
6use crate::proc::Cpus;
7use crate::spinlock::Mutex;
8
9const fn offset(base_address: usize, reg: usize) -> *mut u8 {
10 unsafe { (base_address as *mut u8).add(reg) }
11}
12
13const RHR: usize = 0;
14const THR: usize = 0;
15const IER: usize = 1;
16const IER_RX_ENABLE: u8 = 1 << 0;
17const IER_TX_ENABLE: u8 = 1 << 0;
18const FCR: usize = 2;
19const FCR_FIFO_ENABLE: u8 = 1 << 0;
20const FCR_FIFO_CLEAR: u8 = 3 << 1;
21const _ISR: usize = 2;
22const LCR: usize = 3;
23const LCR_EIGHT_BITS: u8 = 3 << 0;
24const LCR_BAUD_LATCH: u8 = 1 << 7;
25const LSR: usize = 5;
26const _LSR_RX_READY: u8 = 1 << 0;
27const LSR_TX_IDLE: u8 = 1 << 5;
28
29pub static UART: Mutex<Uart> = Mutex::new(Uart::new(UART0), "uart");
30
31const UART_TX_BUF_SIZE: usize = 32;
32
33pub struct Uart {
34 base_address: usize,
35 tx_buf: [u8; UART_TX_BUF_SIZE],
36 tx_w: usize,
37 tx_r: usize,
38}
39
40impl Uart {
41 pub const fn new(base_address: usize) -> Self {
42 Self {
43 base_address,
44 tx_buf: [0; UART_TX_BUF_SIZE],
45 tx_w: 0,
46 tx_r: 0,
47 }
48 }
49
50 fn read(&self, reg: usize) -> u8 {
51 unsafe { ptr::read_volatile(offset(self.base_address, reg)) }
52 }
53
54 fn write(&mut self, reg: usize, value: u8) {
55 unsafe { ptr::write_volatile(offset(self.base_address, reg), value) }
56 }
57
58 pub fn init(&mut self) {
59 self.write(IER, 0x00);
61
62 self.write(LCR, LCR_BAUD_LATCH);
64
65 self.write(0, 0x03);
67
68 self.write(1, 0x00);
70
71 self.write(LCR, LCR_EIGHT_BITS);
73
74 self.write(FCR, FCR_FIFO_ENABLE | FCR_FIFO_CLEAR);
76
77 self.write(IER, IER_TX_ENABLE | IER_RX_ENABLE);
79 }
80
81 fn start(&mut self) {
82 loop {
83 if self.tx_w == self.tx_r {
84 return;
85 }
86
87 if (self.read(LSR) & LSR_TX_IDLE) == 0 {
88 return;
89 }
90
91 let c = self.tx_buf[self.tx_r % UART_TX_BUF_SIZE];
92 self.tx_r += 1;
93
94 self.write(THR, c);
97 }
98 }
99}
100
101impl Mutex<Uart> {
102 pub fn putc(&self, c: u8) {
103 let mut guard = self.lock();
104
105 if PRINTF.is_panicked().load(Ordering::Relaxed) {
106 loop {}
107 }
108
109 while guard.tx_w == guard.tx_r + UART_TX_BUF_SIZE {
110 }
112
113 let index = guard.tx_w % UART_TX_BUF_SIZE;
114 *guard.tx_buf.get_mut(index).unwrap() = c;
115 guard.tx_w += 1;
116
117 guard.start();
118 }
119
120 pub fn getc(&self) -> Option<u8> {
121 let uart = unsafe { self.get_mut_unchecked() };
123 if uart.read(LSR) & 0x01 != 0 {
124 Some(uart.read(RHR))
125 } else {
126 None
127 }
128 }
129
130 pub fn handle_interrupt(&self) {
131 while let Some(c) = self.getc() {
132 }
134
135 self.lock().start();
136 }
137}
138
139pub fn putc_sync(c: u8) {
140 let _intr_lock = Cpus::lock_mycpu();
141
142 let uart = unsafe { UART.get_mut_unchecked() };
144
145 if PRINTF.is_panicked().load(Ordering::Relaxed) {
146 loop {}
147 }
148
149 while (uart.read(LSR) & LSR_TX_IDLE) == 0 {}
150
151 uart.write(THR, c);
152}
153
154pub unsafe fn init() {
155 UART.get_mut_unchecked().init()
156}