1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
use crate::environment;
use crate::x86::io::*;
use core::hint::spin_loop;
const UART_TX: u16 = 0;
const UART_IER: u16 = 1;
const UART_DLL: u16 = 0;
const UART_DLM: u16 = 1;
const UART_FCR: u16 = 2;
const UART_FCR_ENABLE_FIFO: u8 = 0x01;
const UART_FCR_CLEAR_RECEIVER_FIFO: u8 = 0x02;
const UART_FCR_CLEAR_TRANSMITTER_FIFO: u8 = 0x04;
const UART_LCR: u16 = 3;
const UART_LCR_WORD_LENGTH_8BITS: u8 = 0x03;
const UART_LCR_DIVISOR_LATCH_ACCESS: u8 = 0x80;
const UART_LSR: u16 = 5;
const UART_LSR_EMPTY_TRANSMITTER_HOLDING_REGISTER: u8 = 0x20;
pub struct SerialPort {
pub port_address: u16,
}
impl SerialPort {
pub const fn new(port_address: u16) -> Self {
Self { port_address }
}
fn read_from_register(&self, register: u16) -> u8 {
unsafe { inb(self.port_address + register) }
}
fn is_transmitting(&self) -> bool {
if environment::is_uhyve() {
return false;
}
self.read_from_register(UART_LSR) & UART_LSR_EMPTY_TRANSMITTER_HOLDING_REGISTER == 0
}
fn write_to_register(&self, register: u16, byte: u8) {
while self.is_transmitting() {
spin_loop();
}
unsafe {
outb(self.port_address + register, byte);
}
}
pub fn write_byte(&self, byte: u8) {
if self.port_address == 0 {
return;
}
if byte == b'\n' {
self.write_to_register(UART_TX, b'\r');
}
self.write_to_register(UART_TX, byte);
}
pub fn init(&self, baudrate: u32) {
if !environment::is_uhyve() && self.port_address != 0 {
self.write_to_register(UART_IER, 0);
self.write_to_register(UART_LCR, UART_LCR_WORD_LENGTH_8BITS);
let divisor = (115_200 / baudrate) as u16;
let lcr = self.read_from_register(UART_LCR);
self.write_to_register(UART_LCR, lcr | UART_LCR_DIVISOR_LATCH_ACCESS);
self.write_to_register(UART_DLL, divisor as u8);
self.write_to_register(UART_DLM, (divisor >> 8) as u8);
self.write_to_register(UART_LCR, lcr);
self.write_to_register(
UART_FCR,
UART_FCR_ENABLE_FIFO
| UART_FCR_CLEAR_RECEIVER_FIFO
| UART_FCR_CLEAR_TRANSMITTER_FIFO,
);
}
}
}