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
// SPDX-License-Identifier: MPL-2.0
//! A port-mapped UART. Copied from uart_16550.
use crate::arch::x86::device::io_port::{IoPort, ReadWriteAccess, WriteOnlyAccess};
/// A serial port.
///
/// Serial ports are a legacy communications port common on IBM-PC compatible computers.
/// Ref: <https://wiki.osdev.org/Serial_Ports>
pub struct SerialPort {
pub data: IoPort<u8, ReadWriteAccess>,
pub int_en: IoPort<u8, WriteOnlyAccess>,
pub fifo_ctrl: IoPort<u8, WriteOnlyAccess>,
pub line_ctrl: IoPort<u8, WriteOnlyAccess>,
pub modem_ctrl: IoPort<u8, WriteOnlyAccess>,
pub line_status: IoPort<u8, ReadWriteAccess>,
pub modem_status: IoPort<u8, ReadWriteAccess>,
}
impl SerialPort {
/// Create a serial port.
///
/// # Safety
///
/// User must ensure the `port` is valid serial port.
pub const unsafe fn new(port: u16) -> Self {
let data = IoPort::new(port);
let int_en = IoPort::new(port + 1);
let fifo_ctrl = IoPort::new(port + 2);
let line_ctrl = IoPort::new(port + 3);
let modem_ctrl = IoPort::new(port + 4);
let line_status = IoPort::new(port + 5);
let modem_status = IoPort::new(port + 6);
Self {
data,
int_en,
fifo_ctrl,
line_ctrl,
modem_ctrl,
line_status,
modem_status,
}
}
pub fn init(&self) {
// Disable interrupts
self.int_en.write(0x00);
// Enable DLAB
self.line_ctrl.write(0x80);
// Set maximum speed to 38400 bps by configuring DLL and DLM
self.data.write(0x03);
self.int_en.write(0x00);
// Disable DLAB and set data word length to 8 bits
self.line_ctrl.write(0x03);
// Enable FIFO, clear TX/RX queues and
// set interrupt watermark at 14 bytes
self.fifo_ctrl.write(0xC7);
// Mark data terminal ready, signal request to send
// and enable auxilliary output #2 (used as interrupt line for CPU)
self.modem_ctrl.write(0x0B);
// Enable interrupts
self.int_en.write(0x01);
}
}