axhal/platform/x86_pc/
uart16550.rs1use kspin::SpinNoIrq;
4use x86_64::instructions::port::{Port, PortReadOnly, PortWriteOnly};
5
6const UART_CLOCK_FACTOR: usize = 16;
7const OSC_FREQ: usize = 1_843_200;
8
9static COM1: SpinNoIrq<Uart16550> = SpinNoIrq::new(Uart16550::new(0x3f8));
10
11bitflags::bitflags! {
12 struct LineStsFlags: u8 {
14 const INPUT_FULL = 1;
15 const OUTPUT_EMPTY = 1 << 5;
17 }
19}
20
21struct Uart16550 {
22 data: Port<u8>,
23 int_en: PortWriteOnly<u8>,
24 fifo_ctrl: PortWriteOnly<u8>,
25 line_ctrl: PortWriteOnly<u8>,
26 modem_ctrl: PortWriteOnly<u8>,
27 line_sts: PortReadOnly<u8>,
28}
29
30impl Uart16550 {
31 const fn new(port: u16) -> Self {
32 Self {
33 data: Port::new(port),
34 int_en: PortWriteOnly::new(port + 1),
35 fifo_ctrl: PortWriteOnly::new(port + 2),
36 line_ctrl: PortWriteOnly::new(port + 3),
37 modem_ctrl: PortWriteOnly::new(port + 4),
38 line_sts: PortReadOnly::new(port + 5),
39 }
40 }
41
42 fn init(&mut self, baud_rate: usize) {
43 unsafe {
44 self.int_en.write(0x00);
46
47 self.line_ctrl.write(0x80);
49
50 let divisor = OSC_FREQ / (baud_rate * UART_CLOCK_FACTOR);
52 self.data.write((divisor & 0xff) as u8);
53 self.int_en.write((divisor >> 8) as u8);
54
55 self.line_ctrl.write(0x03);
57
58 self.fifo_ctrl.write(0xC7);
61
62 self.modem_ctrl.write(0x0B);
65 }
66 }
67
68 fn line_sts(&mut self) -> LineStsFlags {
69 unsafe { LineStsFlags::from_bits_truncate(self.line_sts.read()) }
70 }
71
72 fn putchar(&mut self, c: u8) {
73 while !self.line_sts().contains(LineStsFlags::OUTPUT_EMPTY) {}
74 unsafe { self.data.write(c) };
75 }
76
77 fn getchar(&mut self) -> Option<u8> {
78 if self.line_sts().contains(LineStsFlags::INPUT_FULL) {
79 unsafe { Some(self.data.read()) }
80 } else {
81 None
82 }
83 }
84}
85
86fn putchar(c: u8) {
88 let mut uart = COM1.lock();
89 match c {
90 b'\n' => {
91 uart.putchar(b'\r');
92 uart.putchar(b'\n');
93 }
94 c => uart.putchar(c),
95 }
96}
97
98fn getchar() -> Option<u8> {
100 COM1.lock().getchar()
101}
102
103pub fn write_bytes(bytes: &[u8]) {
105 for c in bytes {
106 putchar(*c);
107 }
108}
109
110pub fn read_bytes(bytes: &mut [u8]) -> usize {
113 let mut read_len = 0;
114 while read_len < bytes.len() {
115 if let Some(c) = getchar() {
116 bytes[read_len] = c;
117 } else {
118 break;
119 }
120 read_len += 1;
121 }
122 read_len
123}
124
125pub(super) fn init() {
126 COM1.lock().init(115200);
127}