ostd/console/
uart_ns16650a.rs1use core::fmt;
11
12use bitflags::bitflags;
13
14#[repr(u8)]
16#[derive(Clone, Copy, Debug)]
17pub enum Ns16550aRegister {
18 DataOrDivisorLo,
20 IntEnOrDivisorHi,
22 FifoCtrl,
24 LineCtrl,
26 ModemCtrl,
28 LineStat,
30 ModemStat,
32}
33
34pub trait Ns16550aAccess {
36 fn read(&self, reg: Ns16550aRegister) -> u8;
38
39 fn write(&mut self, reg: Ns16550aRegister, val: u8);
41}
42
43#[derive(Debug)]
45pub struct Ns16550aUart<A: Ns16550aAccess> {
46 access: A,
47}
48
49bitflags! {
50 struct LineStat: u8 {
51 const DR = 1 << 0;
53 const THRE = 1 << 5;
55 }
56}
57
58impl<A: Ns16550aAccess> Ns16550aUart<A> {
59 pub const fn new(access: A) -> Self {
61 Self { access }
62 }
63
64 pub fn init(&mut self) {
69 const DLAB: u8 = 0x80;
71
72 self.access.write(Ns16550aRegister::LineCtrl, DLAB);
74 self.access.write(Ns16550aRegister::DataOrDivisorLo, 0x01);
75 self.access.write(Ns16550aRegister::IntEnOrDivisorHi, 0x00);
76
77 self.access.write(Ns16550aRegister::LineCtrl, 0x03);
79 self.access.write(Ns16550aRegister::FifoCtrl, 0x00);
81 self.access.write(Ns16550aRegister::ModemCtrl, 0x0B);
83 self.access.write(Ns16550aRegister::IntEnOrDivisorHi, 0x01);
85 }
86
87 pub fn send(&mut self, data: u8) {
91 while !self.line_stat().contains(LineStat::THRE) {
92 core::hint::spin_loop();
93 }
94
95 self.access.write(Ns16550aRegister::DataOrDivisorLo, data);
96 }
97
98 pub fn recv(&mut self) -> Option<u8> {
102 if !self.line_stat().contains(LineStat::DR) {
103 return None;
104 }
105
106 Some(self.access.read(Ns16550aRegister::DataOrDivisorLo))
107 }
108
109 fn line_stat(&self) -> LineStat {
110 LineStat::from_bits_truncate(self.access.read(Ns16550aRegister::LineStat))
111 }
112}
113
114impl<A: Ns16550aAccess> fmt::Write for Ns16550aUart<A> {
115 fn write_str(&mut self, s: &str) -> fmt::Result {
116 for c in s.as_bytes() {
117 if *c == b'\n' {
118 self.send(b'\r');
119 }
120 self.send(*c);
121 }
122 Ok(())
123 }
124}