serial
This commit is contained in:
parent
96c2ea2298
commit
932d98af20
9
kernel/Cargo.lock
generated
9
kernel/Cargo.lock
generated
|
|
@ -2,6 +2,15 @@
|
|||
# It is not intended for manual editing.
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.13.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b588b76d00fde79687d7646a9b5bdf3cc0f655e0bbd080335a95d7e96f3587da"
|
||||
|
||||
[[package]]
|
||||
name = "kernel"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
]
|
||||
|
|
|
|||
|
|
@ -14,3 +14,4 @@ test = false
|
|||
bench = false
|
||||
|
||||
[dependencies]
|
||||
bitflags = "2.13.1"
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
#![feature(const_trait_impl, const_default)]
|
||||
|
||||
pub mod limine;
|
||||
pub mod serial;
|
||||
pub mod sync;
|
||||
pub mod x86_64;
|
||||
|
||||
|
|
|
|||
|
|
@ -3,11 +3,13 @@
|
|||
|
||||
#[panic_handler]
|
||||
fn panic(_info: &core::panic::PanicInfo) -> ! {
|
||||
kernel::serial_println!("[PANIC] {}", _info);
|
||||
kernel::x86_64::halt_loop()
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
fn _start() -> ! {
|
||||
kernel::serial_println!("Hello, world!");
|
||||
assert!(limine_requests::LIMINE_BASE_REVISION.is_supported());
|
||||
|
||||
let fb = limine_requests::FRAMEBUFFER_REQUEST
|
||||
|
|
|
|||
808
kernel/src/serial.rs
Normal file
808
kernel/src/serial.rs
Normal file
|
|
@ -0,0 +1,808 @@
|
|||
pub mod uart_16550 {
|
||||
#![cfg(target_arch = "x86_64")]
|
||||
use crate::x86_64::PortU16;
|
||||
|
||||
use core::mem::MaybeUninit;
|
||||
|
||||
pub struct Uart16550 {
|
||||
pub base_port: PortU16,
|
||||
pub baud_rate: BaudRate,
|
||||
pub parity: Parity,
|
||||
pub stop_bits: StopBits,
|
||||
pub data_bits: DataBits,
|
||||
pub fifo_trigger_level: Option<FifoTriggerLevel>,
|
||||
pub interrupt_enable: InterruptEnable,
|
||||
}
|
||||
|
||||
impl Uart16550 {
|
||||
/// Transmitter/Receiver Holding Register offset
|
||||
pub const DATA: u16 = 0x0;
|
||||
/// Interrupt Enable Register offset
|
||||
pub const IER: u16 = 0x1;
|
||||
/// Interrupt Status Register offset
|
||||
pub const ISR: u16 = 0x2;
|
||||
/// FIFO Control Register offset
|
||||
pub const FCR: u16 = 0x2;
|
||||
/// Line Control Register offset
|
||||
pub const LCR: u16 = 0x3;
|
||||
/// Modem Control Register offset
|
||||
pub const MCR: u16 = 0x4;
|
||||
/// Line Status Register offset
|
||||
pub const LSR: u16 = 0x5;
|
||||
/// Modem Status Register offset
|
||||
pub const MSR: u16 = 0x6;
|
||||
/// Scratch Pad Register offset
|
||||
pub const SPR: u16 = 0x7;
|
||||
|
||||
/// Divisor Latch Low offset
|
||||
pub const DLL: u16 = 0x0;
|
||||
/// Divisor Latch High offset
|
||||
pub const DLM: u16 = 0x1;
|
||||
|
||||
/// # Safety
|
||||
/// This function creates a new instance of Uart16550 with the given base port.
|
||||
pub unsafe fn with_port(base_port: u16) -> Self {
|
||||
Self {
|
||||
base_port: PortU16(base_port),
|
||||
baud_rate: BaudRate::default(),
|
||||
parity: Parity::default(),
|
||||
stop_bits: StopBits::default(),
|
||||
data_bits: DataBits::default(),
|
||||
fifo_trigger_level: Some(FifoTriggerLevel::default()),
|
||||
interrupt_enable: InterruptEnable::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn init(&mut self) {
|
||||
unsafe {
|
||||
self.base_port.offset(Self::IER).write(0);
|
||||
self.base_port.offset(Self::LCR).write(0);
|
||||
}
|
||||
|
||||
self.set_baud_rate(self.baud_rate);
|
||||
|
||||
let lcr = LineControl::new(false, false, self.parity, self.stop_bits, self.data_bits);
|
||||
unsafe {
|
||||
self.write_lcr(lcr);
|
||||
|
||||
let mut fcr = FifoControl::empty();
|
||||
if let Some(level) = self.fifo_trigger_level {
|
||||
fcr.set_fifo_enable(true);
|
||||
fcr.set_fifo_trigger_level(level);
|
||||
}
|
||||
fcr.set_clear_receive_fifo();
|
||||
fcr.set_clear_transmit_fifo();
|
||||
|
||||
self.write_fcr(fcr);
|
||||
|
||||
let mut mcr = ModemControl::empty();
|
||||
mcr.set_data_terminal_ready(true);
|
||||
mcr.set_request_to_send(true);
|
||||
mcr.set_auxiliary_output_2(true);
|
||||
self.write_mcr(mcr);
|
||||
|
||||
self.write_ier(self.interrupt_enable);
|
||||
|
||||
loop {
|
||||
let lsr = self.read_lsr();
|
||||
if lsr.transmitter_holding_register_empty() {
|
||||
break;
|
||||
}
|
||||
|
||||
core::hint::spin_loop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn ready_to_receive(&self) -> bool {
|
||||
let lsr = self.read_lsr();
|
||||
lsr.data_ready()
|
||||
}
|
||||
|
||||
pub fn ready_to_send(&self) -> bool {
|
||||
let lsr = self.read_lsr();
|
||||
let msr = self.read_msr();
|
||||
let mcr = self.read_mcr();
|
||||
|
||||
if !lsr.transmitter_holding_register_empty() {
|
||||
return false;
|
||||
}
|
||||
|
||||
if !mcr.loopback_mode() && !msr.clear_to_send() {
|
||||
return false;
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
pub fn try_receive_byte(&self) -> Option<u8> {
|
||||
if self.ready_to_receive() {
|
||||
let data_port = self.base_port.offset(Self::DATA);
|
||||
let value = unsafe { data_port.read() } as u8;
|
||||
Some(value)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn try_send_bytes(&self, bytes: &[u8]) -> Option<usize> {
|
||||
if bytes.is_empty() {
|
||||
return Some(0);
|
||||
}
|
||||
|
||||
if !self.ready_to_send() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let bytes = match self.fifo_trigger_level {
|
||||
None => &bytes[..1],
|
||||
Some(level) => {
|
||||
let end = core::cmp::min(bytes.len(), level.count());
|
||||
&bytes[..end]
|
||||
}
|
||||
};
|
||||
|
||||
for &b in bytes {
|
||||
unsafe {
|
||||
self.base_port.offset(Self::DATA).write(b as u16);
|
||||
}
|
||||
}
|
||||
|
||||
Some(bytes.len())
|
||||
}
|
||||
|
||||
pub fn try_send_byte(&self, byte: u8) -> Option<()> {
|
||||
if self.ready_to_send() {
|
||||
let data_port = self.base_port.offset(Self::DATA);
|
||||
unsafe { data_port.write(byte as u16) };
|
||||
Some(())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn try_receive_bytes<'a>(
|
||||
&self,
|
||||
buffer: &'a mut [MaybeUninit<u8>],
|
||||
) -> (&'a mut [u8], &'a mut [MaybeUninit<u8>]) {
|
||||
let len = buffer
|
||||
.iter_mut()
|
||||
.map_while(|b: &mut MaybeUninit<u8>| {
|
||||
self.try_receive_byte().map(|val| b.write(val))
|
||||
})
|
||||
.count();
|
||||
|
||||
// SAFETY: We have just initialized the first `len` elements of the
|
||||
// buffer, so it is safe to transmute them to `&mut [u8]`.
|
||||
unsafe {
|
||||
let (init, uninit) = buffer.split_at_mut(len);
|
||||
let init = core::mem::transmute::<&mut [MaybeUninit<u8>], &mut [u8]>(init);
|
||||
(init, uninit)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn receive_bytes_exact<'a>(&self, buffer: &'a mut [MaybeUninit<u8>]) -> &'a mut [u8] {
|
||||
let (ptr, len) = (buffer.as_mut_ptr(), buffer.len());
|
||||
let mut rest = buffer;
|
||||
|
||||
loop {
|
||||
rest = self.try_receive_bytes(rest).1;
|
||||
if rest.is_empty() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
unsafe {
|
||||
// SAFETY: We have just initialized the entire buffer, so it is safe to transmute it to `&mut [u8]`.
|
||||
core::slice::from_raw_parts_mut(ptr as *mut u8, len)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn send_bytes_exact(&self, bytes: &[u8]) {
|
||||
let mut rest = bytes;
|
||||
|
||||
loop {
|
||||
let sent = self.try_send_bytes(rest).unwrap_or(0);
|
||||
rest = &rest[sent..];
|
||||
if rest.is_empty() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn read_lcr(&self) -> LineControl {
|
||||
let lcr_port = self.base_port.offset(3);
|
||||
let value = unsafe { lcr_port.read() } as u8;
|
||||
LineControl(value)
|
||||
}
|
||||
|
||||
/// # Safety
|
||||
/// This function writes to the Line Control Register (LCR) of the UART.
|
||||
pub unsafe fn write_lcr(&self, lcr: LineControl) {
|
||||
let lcr_port = self.base_port.offset(Self::LCR);
|
||||
unsafe { lcr_port.write(lcr.0 as u16) };
|
||||
}
|
||||
|
||||
pub fn read_msr(&self) -> ModemStatus {
|
||||
let msr_port = self.base_port.offset(Self::MSR);
|
||||
let value = unsafe { msr_port.read() } as u8;
|
||||
ModemStatus(value)
|
||||
}
|
||||
|
||||
pub fn read_lsr(&self) -> LineStatus {
|
||||
let lsr_port = self.base_port.offset(Self::LSR);
|
||||
let value = unsafe { lsr_port.read() } as u8;
|
||||
LineStatus(value)
|
||||
}
|
||||
|
||||
pub fn read_ier(&self) -> InterruptEnable {
|
||||
let ier_port = self.base_port.offset(Self::IER);
|
||||
let value = unsafe { ier_port.read() } as u8;
|
||||
InterruptEnable(value)
|
||||
}
|
||||
|
||||
/// # Safety
|
||||
/// This function writes to the Interrupt Enable Register (IER) of the UART.
|
||||
pub unsafe fn write_ier(&self, ier: InterruptEnable) {
|
||||
let ier_port = self.base_port.offset(Self::IER);
|
||||
unsafe { ier_port.write(ier.0 as u16) };
|
||||
}
|
||||
|
||||
pub fn read_isr(&self) -> InterruptStatus {
|
||||
let isr_port = self.base_port.offset(Self::ISR);
|
||||
let value = unsafe { isr_port.read() } as u8;
|
||||
InterruptStatus(value)
|
||||
}
|
||||
|
||||
pub fn read_fcr(&self) -> FifoControl {
|
||||
let fcr_port = self.base_port.offset(Self::FCR);
|
||||
let value = unsafe { fcr_port.read() } as u8;
|
||||
FifoControl(value)
|
||||
}
|
||||
|
||||
pub fn read_mcr(&self) -> ModemControl {
|
||||
let mcr_port = self.base_port.offset(Self::MCR);
|
||||
let value = unsafe { mcr_port.read() } as u8;
|
||||
ModemControl(value)
|
||||
}
|
||||
|
||||
/// # Safety
|
||||
/// This function writes to the Modem Control Register (MCR) of the UART.
|
||||
pub unsafe fn write_mcr(&self, mcr: ModemControl) {
|
||||
let mcr_port = self.base_port.offset(Self::MCR);
|
||||
unsafe { mcr_port.write(mcr.0 as u16) };
|
||||
}
|
||||
|
||||
/// # Safety
|
||||
/// This function writes to the FIFO Control Register (FCR) of the UART.
|
||||
pub unsafe fn write_fcr(&self, fcr: FifoControl) {
|
||||
let fcr_port = self.base_port.offset(Self::FCR);
|
||||
unsafe { fcr_port.write(fcr.0 as u16) };
|
||||
}
|
||||
|
||||
pub fn set_baud_rate(&self, baud_rate: BaudRate) {
|
||||
let divisor = baud_rate.divisor();
|
||||
let mut lcr = self.read_lcr();
|
||||
lcr.set_dlab(true);
|
||||
let [low_byte, high_byte] = divisor.to_le_bytes();
|
||||
|
||||
unsafe {
|
||||
self.write_lcr(lcr);
|
||||
self.base_port.offset(Self::DLL).write(low_byte as u16);
|
||||
self.base_port.offset(Self::DLM).write(high_byte as u16);
|
||||
lcr.set_dlab(false);
|
||||
self.write_lcr(lcr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const BASE_RATE: u32 = 115200;
|
||||
|
||||
#[derive(Debug, Clone, Copy, Default)]
|
||||
pub enum BaudRate {
|
||||
Baud115200,
|
||||
Baud57600,
|
||||
Baud38400,
|
||||
Baud19200,
|
||||
#[default]
|
||||
Baud9600,
|
||||
}
|
||||
|
||||
impl BaudRate {
|
||||
pub fn divisor(&self) -> u16 {
|
||||
let rate = match self {
|
||||
BaudRate::Baud115200 => 115200,
|
||||
BaudRate::Baud57600 => 57600,
|
||||
BaudRate::Baud38400 => 38400,
|
||||
BaudRate::Baud19200 => 19200,
|
||||
BaudRate::Baud9600 => 9600,
|
||||
};
|
||||
|
||||
assert!(BASE_RATE.is_multiple_of(rate), "Invalid baud rate");
|
||||
(BASE_RATE / rate) as u16
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
#[repr(transparent)]
|
||||
pub struct LineControl(pub u8);
|
||||
|
||||
#[derive(Debug, Clone, Copy, Default)]
|
||||
#[repr(u8)]
|
||||
pub enum DataBits {
|
||||
Five = 0b00,
|
||||
Six = 0b01,
|
||||
Seven = 0b10,
|
||||
#[default]
|
||||
Eight = 0b11,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Default)]
|
||||
#[repr(u8)]
|
||||
pub enum StopBits {
|
||||
#[default]
|
||||
One = 0b0,
|
||||
Two = 0b1,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Default)]
|
||||
#[repr(u8)]
|
||||
pub enum Parity {
|
||||
#[default]
|
||||
None = 0b00,
|
||||
Odd = 0b01,
|
||||
Even = 0b11,
|
||||
Mark = 0b101,
|
||||
Space = 0b111,
|
||||
}
|
||||
|
||||
impl LineControl {
|
||||
pub const fn empty() -> Self {
|
||||
Self(0)
|
||||
}
|
||||
|
||||
pub fn dlab(&self) -> bool {
|
||||
(self.0 & (1 << 7)) != 0
|
||||
}
|
||||
pub fn set_dlab(&mut self, dlab: bool) {
|
||||
if dlab {
|
||||
self.0 |= 1 << 7;
|
||||
} else {
|
||||
self.0 &= !(1 << 7);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_break_signal(&mut self, break_signal: bool) {
|
||||
if break_signal {
|
||||
self.0 |= 1 << 6;
|
||||
} else {
|
||||
self.0 &= !(1 << 6);
|
||||
}
|
||||
}
|
||||
pub fn break_signal(&self) -> bool {
|
||||
(self.0 & (1 << 6)) != 0
|
||||
}
|
||||
|
||||
pub fn set_parity(&mut self, parity: Parity) {
|
||||
self.0 &= !(0b111 << 3);
|
||||
self.0 |= (parity as u8) << 3;
|
||||
}
|
||||
pub fn parity(&self) -> Parity {
|
||||
match (self.0 >> 3) & 0b111 {
|
||||
0b000 => Parity::None,
|
||||
0b001 => Parity::Odd,
|
||||
0b011 => Parity::Even,
|
||||
0b101 => Parity::Mark,
|
||||
0b111 => Parity::Space,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_stop_bits(&mut self, stop_bits: StopBits) {
|
||||
self.0 &= !(1 << 2);
|
||||
self.0 |= (stop_bits as u8) << 2;
|
||||
}
|
||||
pub fn stop_bits(&self) -> StopBits {
|
||||
match (self.0 >> 2) & 0b1 {
|
||||
0b0 => StopBits::One,
|
||||
0b1 => StopBits::Two,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
pub fn set_data_bits(&mut self, data_bits: DataBits) {
|
||||
self.0 &= !(0b11);
|
||||
self.0 |= data_bits as u8;
|
||||
}
|
||||
pub fn data_bits(&self) -> DataBits {
|
||||
match self.0 & 0b11 {
|
||||
0b00 => DataBits::Five,
|
||||
0b01 => DataBits::Six,
|
||||
0b10 => DataBits::Seven,
|
||||
0b11 => DataBits::Eight,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
pub const fn new(
|
||||
dlab: bool,
|
||||
break_signal: bool,
|
||||
parity: Parity,
|
||||
stop_bits: StopBits,
|
||||
data_bits: DataBits,
|
||||
) -> Self {
|
||||
let mut value = 0u8;
|
||||
if dlab {
|
||||
value |= 1 << 7;
|
||||
}
|
||||
if break_signal {
|
||||
value |= 1 << 6;
|
||||
}
|
||||
value |= (parity as u8) << 3;
|
||||
value |= (stop_bits as u8) << 2;
|
||||
value |= data_bits as u8;
|
||||
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
#[repr(transparent)]
|
||||
pub struct InterruptEnable(pub u8);
|
||||
|
||||
impl Default for InterruptEnable {
|
||||
fn default() -> Self {
|
||||
let mut empty = Self(0);
|
||||
empty.set_received_data_available(true);
|
||||
empty
|
||||
}
|
||||
}
|
||||
|
||||
impl InterruptEnable {
|
||||
pub const fn empty() -> Self {
|
||||
Self(0)
|
||||
}
|
||||
|
||||
pub fn set_received_data_available(&mut self, enable: bool) {
|
||||
if enable {
|
||||
self.0 |= 1 << 0;
|
||||
} else {
|
||||
self.0 &= !(1 << 0);
|
||||
}
|
||||
}
|
||||
pub fn received_data_available(&self) -> bool {
|
||||
(self.0 & (1 << 0)) != 0
|
||||
}
|
||||
|
||||
pub fn set_transmitter_holding_register_empty(&mut self, enable: bool) {
|
||||
if enable {
|
||||
self.0 |= 1 << 1;
|
||||
} else {
|
||||
self.0 &= !(1 << 1);
|
||||
}
|
||||
}
|
||||
pub fn transmitter_holding_register_empty(&self) -> bool {
|
||||
(self.0 & (1 << 1)) != 0
|
||||
}
|
||||
|
||||
pub fn set_receiver_line_status(&mut self, enable: bool) {
|
||||
if enable {
|
||||
self.0 |= 1 << 2;
|
||||
} else {
|
||||
self.0 &= !(1 << 2);
|
||||
}
|
||||
}
|
||||
pub fn receiver_line_status(&self) -> bool {
|
||||
(self.0 & (1 << 2)) != 0
|
||||
}
|
||||
|
||||
pub fn set_modem_status(&mut self, enable: bool) {
|
||||
if enable {
|
||||
self.0 |= 1 << 3;
|
||||
} else {
|
||||
self.0 &= !(1 << 3);
|
||||
}
|
||||
}
|
||||
pub fn modem_status(&self) -> bool {
|
||||
(self.0 & (1 << 3)) != 0
|
||||
}
|
||||
}
|
||||
|
||||
pub struct FifoControl(pub u8);
|
||||
|
||||
impl FifoControl {
|
||||
pub const fn empty() -> Self {
|
||||
Self(0)
|
||||
}
|
||||
|
||||
pub fn set_fifo_enable(&mut self, enable: bool) {
|
||||
if enable {
|
||||
self.0 |= 1 << 0;
|
||||
} else {
|
||||
self.0 &= !(1 << 0);
|
||||
}
|
||||
}
|
||||
pub fn fifo_enable(&self) -> bool {
|
||||
(self.0 & (1 << 0)) != 0
|
||||
}
|
||||
|
||||
pub fn set_fifo_trigger_level(&mut self, level: FifoTriggerLevel) {
|
||||
self.0 &= !(0b11 << 6);
|
||||
self.0 |= (level as u8) << 6;
|
||||
}
|
||||
pub fn fifo_trigger_level(&self) -> FifoTriggerLevel {
|
||||
match (self.0 >> 6) & 0b11 {
|
||||
0b00 => FifoTriggerLevel::Level1Byte,
|
||||
0b01 => FifoTriggerLevel::Level4Bytes,
|
||||
0b10 => FifoTriggerLevel::Level8Bytes,
|
||||
0b11 => FifoTriggerLevel::Level14Bytes,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_clear_receive_fifo(&mut self) {
|
||||
self.0 |= 1 << 1;
|
||||
}
|
||||
pub fn set_clear_transmit_fifo(&mut self) {
|
||||
self.0 |= 1 << 2;
|
||||
}
|
||||
pub fn set_dma_mode(&mut self, enable: bool) {
|
||||
if enable {
|
||||
self.0 |= 1 << 3;
|
||||
} else {
|
||||
self.0 &= !(1 << 3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(u8)]
|
||||
pub enum InterruptState {
|
||||
ModemStatus = 0,
|
||||
TransmitterHoldingRegisterEmpty = 1,
|
||||
ReceivedDataAvailable = 2,
|
||||
ReceiverLineStatus = 3,
|
||||
}
|
||||
|
||||
#[repr(u8)]
|
||||
pub enum FIFOBufferState {
|
||||
Disabled = 0,
|
||||
Unusable = 1,
|
||||
Enabled = 2,
|
||||
}
|
||||
|
||||
pub struct InterruptStatus(pub u8);
|
||||
|
||||
impl InterruptStatus {
|
||||
pub fn interrupt_pending(&self) -> bool {
|
||||
(self.0 & (1 << 0)) == 0
|
||||
}
|
||||
pub fn timeout_interrupt_pending(&self) -> bool {
|
||||
(self.0 & (1 << 4)) != 0
|
||||
}
|
||||
pub fn interrupt_state(&self) -> InterruptState {
|
||||
match (self.0 >> 1) & 0b111 {
|
||||
0b000 => InterruptState::ModemStatus,
|
||||
0b001 => InterruptState::TransmitterHoldingRegisterEmpty,
|
||||
0b010 => InterruptState::ReceivedDataAvailable,
|
||||
0b011 => InterruptState::ReceiverLineStatus,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
pub fn fifo_buffer_state(&self) -> FIFOBufferState {
|
||||
match (self.0 >> 6) & 0b11 {
|
||||
0b00 => FIFOBufferState::Disabled,
|
||||
0b01 => FIFOBufferState::Unusable,
|
||||
0b10 => FIFOBufferState::Enabled,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ModemControl(pub u8);
|
||||
|
||||
impl ModemControl {
|
||||
pub const fn empty() -> Self {
|
||||
Self(0)
|
||||
}
|
||||
|
||||
pub fn set_data_terminal_ready(&mut self, enable: bool) {
|
||||
if enable {
|
||||
self.0 |= 1 << 0;
|
||||
} else {
|
||||
self.0 &= !(1 << 0);
|
||||
}
|
||||
}
|
||||
pub fn set_request_to_send(&mut self, enable: bool) {
|
||||
if enable {
|
||||
self.0 |= 1 << 1;
|
||||
} else {
|
||||
self.0 &= !(1 << 1);
|
||||
}
|
||||
}
|
||||
pub fn set_auxiliary_output_1(&mut self, enable: bool) {
|
||||
if enable {
|
||||
self.0 |= 1 << 2;
|
||||
} else {
|
||||
self.0 &= !(1 << 2);
|
||||
}
|
||||
}
|
||||
pub fn set_auxiliary_output_2(&mut self, enable: bool) {
|
||||
if enable {
|
||||
self.0 |= 1 << 3;
|
||||
} else {
|
||||
self.0 &= !(1 << 3);
|
||||
}
|
||||
}
|
||||
pub fn set_loopback_mode(&mut self, enable: bool) {
|
||||
if enable {
|
||||
self.0 |= 1 << 4;
|
||||
} else {
|
||||
self.0 &= !(1 << 4);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn loopback_mode(&self) -> bool {
|
||||
(self.0 & (1 << 4)) != 0
|
||||
}
|
||||
}
|
||||
|
||||
pub struct LineStatus(pub u8);
|
||||
|
||||
impl LineStatus {
|
||||
pub fn data_ready(&self) -> bool {
|
||||
(self.0 & (1 << 0)) != 0
|
||||
}
|
||||
pub fn overrun_error(&self) -> bool {
|
||||
(self.0 & (1 << 1)) != 0
|
||||
}
|
||||
pub fn parity_error(&self) -> bool {
|
||||
(self.0 & (1 << 2)) != 0
|
||||
}
|
||||
pub fn framing_error(&self) -> bool {
|
||||
(self.0 & (1 << 3)) != 0
|
||||
}
|
||||
pub fn break_interrupt(&self) -> bool {
|
||||
(self.0 & (1 << 4)) != 0
|
||||
}
|
||||
pub fn transmitter_holding_register_empty(&self) -> bool {
|
||||
(self.0 & (1 << 5)) != 0
|
||||
}
|
||||
pub fn transmitter_empty(&self) -> bool {
|
||||
(self.0 & (1 << 6)) != 0
|
||||
}
|
||||
pub fn impending_error(&self) -> bool {
|
||||
(self.0 & (1 << 7)) != 0
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ModemStatus(pub u8);
|
||||
|
||||
impl ModemStatus {
|
||||
pub fn delta_clear_to_send(&self) -> bool {
|
||||
(self.0 & (1 << 0)) != 0
|
||||
}
|
||||
pub fn delta_data_set_ready(&self) -> bool {
|
||||
(self.0 & (1 << 1)) != 0
|
||||
}
|
||||
pub fn trailing_edge_ring_indicator(&self) -> bool {
|
||||
(self.0 & (1 << 2)) != 0
|
||||
}
|
||||
pub fn delta_data_carrier_detect(&self) -> bool {
|
||||
(self.0 & (1 << 3)) != 0
|
||||
}
|
||||
pub fn clear_to_send(&self) -> bool {
|
||||
(self.0 & (1 << 4)) != 0
|
||||
}
|
||||
pub fn data_set_ready(&self) -> bool {
|
||||
(self.0 & (1 << 5)) != 0
|
||||
}
|
||||
pub fn ring_indicator(&self) -> bool {
|
||||
(self.0 & (1 << 6)) != 0
|
||||
}
|
||||
pub fn data_carrier_detect(&self) -> bool {
|
||||
(self.0 & (1 << 7)) != 0
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Default)]
|
||||
#[repr(u8)]
|
||||
pub enum FifoTriggerLevel {
|
||||
Level1Byte = 0b00,
|
||||
Level4Bytes = 0b01,
|
||||
Level8Bytes = 0b10,
|
||||
#[default]
|
||||
Level14Bytes = 0b11,
|
||||
}
|
||||
impl FifoTriggerLevel {
|
||||
pub fn count(&self) -> usize {
|
||||
match self {
|
||||
FifoTriggerLevel::Level1Byte => 1,
|
||||
FifoTriggerLevel::Level4Bytes => 4,
|
||||
FifoTriggerLevel::Level8Bytes => 8,
|
||||
FifoTriggerLevel::Level14Bytes => 14,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Uart16550Writer {
|
||||
uart: Uart16550,
|
||||
}
|
||||
|
||||
impl Uart16550Writer {
|
||||
pub fn from_port(base_port: u16) -> Self {
|
||||
let mut uart = unsafe { Uart16550::with_port(base_port) };
|
||||
uart.init();
|
||||
Self { uart }
|
||||
}
|
||||
}
|
||||
|
||||
impl core::fmt::Write for Uart16550Writer {
|
||||
fn write_str(&mut self, s: &str) -> core::fmt::Result {
|
||||
let bytes = s.as_bytes();
|
||||
|
||||
const SPECIAL_BYTES: &[u8] = &[b'\n', 8, 0x7f];
|
||||
bytes
|
||||
.split_inclusive(|b| SPECIAL_BYTES.contains(b))
|
||||
.for_each(|chunk| {
|
||||
if let Some((special, rest)) = chunk.split_last() {
|
||||
self.uart.send_bytes_exact(rest);
|
||||
match special {
|
||||
b'\n' => {
|
||||
self.uart.send_bytes_exact(b"\r\n");
|
||||
}
|
||||
8 | 0x7f => {
|
||||
self.uart.send_bytes_exact(&[8, b' ', 8]);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub static SERIAL1: crate::sync::LazyLock<crate::sync::SpinMutex<Uart16550Writer>> =
|
||||
crate::sync::LazyLock::new(|| {
|
||||
crate::sync::SpinMutex::new(Uart16550Writer::from_port(0x3f8))
|
||||
});
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub fn _print(args: core::fmt::Arguments) {
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
{
|
||||
use core::fmt::Write;
|
||||
struct Writer<'a>(&'a crate::sync::SpinMutex<uart_16550::Uart16550Writer>);
|
||||
|
||||
impl core::fmt::Write for Writer<'_> {
|
||||
fn write_str(&mut self, s: &str) -> core::fmt::Result {
|
||||
let mut writer = self.0.lock();
|
||||
writer.write_str(s)
|
||||
}
|
||||
}
|
||||
|
||||
Writer(&uart_16550::SERIAL1).write_fmt(args).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! serial_print {
|
||||
($($arg:tt)*) => {
|
||||
$crate::serial::_print(format_args!($($arg)*));
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! serial_println {
|
||||
() => {
|
||||
$crate::serial_print!("\n");
|
||||
};
|
||||
($fmt:expr) => {
|
||||
$crate::serial_print!(concat!($fmt, "\n"));
|
||||
};
|
||||
($fmt:expr, $($arg:tt)*) => {
|
||||
$crate::serial_print!(
|
||||
concat!($fmt, "\n"), $($arg)*
|
||||
);
|
||||
};
|
||||
}
|
||||
Loading…
Reference in a new issue