summaryrefslogtreecommitdiffstats
path: root/kernel/src/serial.rs
blob: 73cb24747d1f7f6634f279bfa2953e3e5202c5dc (plain) (blame)
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;
}
Go back to lisible.xyz