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
|
use crate::arch::x86::io::{in8, out8};
use crate::serial::SerialError::SerialPortInitializationFailed;
const COM1_PORT: u16 = 0x3F8;
const OFFSET_DATA_REGISTER: u8 = 0;
const OFFSET_INTERRUPT_ENABLE_REGISTER: u8 = 1;
const OFFSET_INTERRUPT_IDENTIFICATION_AND_FIFO_CONTROL_REGISTER: u8 = 2;
const OFFSET_LINE_CONTROL_REGISTER: u8 = 3;
const OFFSET_MODEM_CONTROL_REGISTER: u8 = 4;
const OFFSET_LINE_STATUS_REGISTER: u8 = 5;
#[derive(Debug)]
pub enum SerialError {
SerialPortInitializationFailed,
}
pub fn initialize_serial_port() -> Result<(), SerialError> {
// Safety:
// These instructions read and write data on valid COM ports
unsafe {
out8(COM1_PORT + OFFSET_INTERRUPT_ENABLE_REGISTER as u16, 0x00);
out8(COM1_PORT + OFFSET_LINE_CONTROL_REGISTER as u16, 0x80);
out8(COM1_PORT + OFFSET_DATA_REGISTER as u16, 0x03);
out8(COM1_PORT + OFFSET_INTERRUPT_ENABLE_REGISTER as u16, 0x00);
out8(COM1_PORT + OFFSET_LINE_CONTROL_REGISTER as u16, 0x03);
out8(
COM1_PORT + OFFSET_INTERRUPT_IDENTIFICATION_AND_FIFO_CONTROL_REGISTER as u16,
0xC7,
);
out8(COM1_PORT + OFFSET_MODEM_CONTROL_REGISTER as u16, 0x0B);
// Testing the serial chip
out8(COM1_PORT + OFFSET_MODEM_CONTROL_REGISTER as u16, 0x1E); // Enable loopback mode
out8(COM1_PORT + OFFSET_DATA_REGISTER as u16, 0xAE);
if in8(COM1_PORT + OFFSET_DATA_REGISTER as u16) != 0xAE {
return Err(SerialPortInitializationFailed);
}
out8(COM1_PORT + OFFSET_MODEM_CONTROL_REGISTER as u16, 0x0F); // Enable normal mode
}
Ok(())
}
pub fn write(byte: u8) {
while !is_ready_to_send_data() {}
// Safety: the value is sent on a valid port address, which is the COM port
// data register address
unsafe {
out8(COM1_PORT, byte);
}
}
pub fn write_bytes(bytes: &[u8]) {
for &byte in bytes {
write(byte);
}
}
fn is_ready_to_send_data() -> bool {
const THRE_BIT: u8 = 0x20;
// Safety: the value is sent on a valid port address, which is the COM port
// line status register address
return unsafe { in8(COM1_PORT + OFFSET_LINE_STATUS_REGISTER as u16) } & THRE_BIT != 0;
}
|