-
Notifications
You must be signed in to change notification settings - Fork 3
/
serial.rs
90 lines (74 loc) · 2.51 KB
/
serial.rs
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
use io;
const COM1_BASE: u16 = 0x3f8;
const LINE_ENABLE_DLAB: u8 = 0x80;
fn fifo_command_port(base: u16) -> u16 {
base + 2
}
fn line_command_port(base: u16) -> u16 {
base + 3
}
fn modem_command_port(base: u16) -> u16 {
base + 4
}
fn line_status_port(base: u16) -> u16 {
base + 5
}
pub struct Port {
base: u16,
}
impl Port {
pub fn new() -> Port {
let port = Port { base: COM1_BASE };
port.configure_baud_rate(1);
port.configure_line();
port.configure_fifo_command_port();
port.configure_modem_command_port();
port
}
/// Sets the speed of the data being sent. Default speed is 115200 bits/s.
/// Divisor will be used to set the speed to (115200 / divisor) bits/s.
fn configure_baud_rate(&self, divisor: u16) {
let high: u8 = ((divisor >> 8) & 0x00ff) as u8;
let low: u8 = (divisor & 0x00ff) as u8;
io::outb(line_command_port(self.base), LINE_ENABLE_DLAB);
io::outb(self.base, high);
io::outb(self.base, low);
}
/// Configures the line of the given serial port. Data length of 8 bits, no
/// parity bits, one stop bit, DLAB disabled, and break control disabled.
fn configure_line(&self) {
// bit: | 7 | 6 | 5 4 3 | 2 | 1 0 |
// content: | d | b | prty | s | dln |
// value: | 0 | 0 | 0 0 0 | 0 | 1 1 |
io::outb(line_command_port(self.base), 0x03);
}
/// Configures the fifo command port to buffer 14 bytes.
fn configure_fifo_command_port(&self) {
// bit: | 7 6 | 5 | 4 | 3 | 2 | 1 | 0 |
// content: | lvl | bs | r | dma | clt | clr | e |
// value: | 1 1 | 0 | 0 | 0 | 1 | 1 | 1 |
io::outb(fifo_command_port(self.base), 0xc7);
}
fn configure_modem_command_port(&self) {
// bit: | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
// content: | r | r | af | lb | ao2 | ao1 | rts | dtr |
// value: | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 |
io::outb(modem_command_port(self.base), 0x03);
}
fn transmitting_fifo_empty(&self) -> bool {
let status = io::inb(line_status_port(self.base));
(status & 0x20) == 0x20
}
/// Write a string to the serial port
pub fn write(&self, text: &str) {
for b in text.bytes() {
loop {
match self.transmitting_fifo_empty() {
true => break,
false => {}
}
}
io::outb(self.base, b)
}
}
}