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
34impl Ns16550aRegister {
35 pub const MAX: Self = Self::ModemStat;
37}
38
39pub trait Ns16550aAccess {
41 fn read(&self, reg: Ns16550aRegister) -> u8;
43
44 fn write(&mut self, reg: Ns16550aRegister, val: u8);
46}
47
48#[derive(Debug)]
50pub struct Ns16550aUart<A: Ns16550aAccess> {
51 access: A,
52}
53
54bitflags! {
55 struct LineStat: u8 {
56 const DR = 1 << 0;
58 const THRE = 1 << 5;
60 }
61}
62
63impl<A: Ns16550aAccess> Ns16550aUart<A> {
64 pub const fn new(access: A) -> Self {
66 Self { access }
67 }
68
69 pub fn init(&mut self) {
74 const DLAB: u8 = 0x80;
76
77 self.access.write(Ns16550aRegister::LineCtrl, DLAB);
79 self.access.write(Ns16550aRegister::DataOrDivisorLo, 0x01);
80 self.access.write(Ns16550aRegister::IntEnOrDivisorHi, 0x00);
81
82 self.access.write(Ns16550aRegister::LineCtrl, 0x03);
84 self.access.write(Ns16550aRegister::FifoCtrl, 0x00);
86 self.access.write(Ns16550aRegister::ModemCtrl, 0x0B);
88 self.access.write(Ns16550aRegister::IntEnOrDivisorHi, 0x01);
90 }
91
92 pub fn send(&mut self, data: u8) {
96 while !self.line_stat().contains(LineStat::THRE) {
97 core::hint::spin_loop();
98 }
99
100 self.access.write(Ns16550aRegister::DataOrDivisorLo, data);
101 }
102
103 pub fn recv(&mut self) -> Option<u8> {
107 if !self.line_stat().contains(LineStat::DR) {
108 return None;
109 }
110
111 Some(self.access.read(Ns16550aRegister::DataOrDivisorLo))
112 }
113
114 fn line_stat(&self) -> LineStat {
115 LineStat::from_bits_truncate(self.access.read(Ns16550aRegister::LineStat))
116 }
117}
118
119impl<A: Ns16550aAccess> fmt::Write for Ns16550aUart<A> {
120 fn write_str(&mut self, s: &str) -> fmt::Result {
121 for c in s.as_bytes() {
122 if *c == b'\n' {
123 self.send(b'\r');
124 }
125 self.send(*c);
126 }
127 Ok(())
128 }
129}