diff --git a/.gitignore b/.gitignore index c41cc9e..cc48954 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ -/target \ No newline at end of file +/target +.idea \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index 56ea37d..c7ee68a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8,6 +8,12 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" +[[package]] +name = "bitflags" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" + [[package]] name = "embedded-hal" version = "0.2.7" @@ -37,7 +43,7 @@ checksum = "546c37ac5d9e56f55e73b677106873d9d9f5190605e41a856503623648488cae" name = "uart8250" version = "0.6.0" dependencies = [ - "bitflags", + "bitflags 2.4.0", "embedded-hal", "nb 1.0.0", "volatile-register", @@ -47,7 +53,7 @@ dependencies = [ name = "uart_xilinx" version = "0.1.0" dependencies = [ - "bitflags", + "bitflags 1.2.1", "volatile-register", ] diff --git a/uart8250/Cargo.toml b/uart8250/Cargo.toml index e139a20..63c425e 100644 --- a/uart8250/Cargo.toml +++ b/uart8250/Cargo.toml @@ -14,7 +14,7 @@ readme = "README.md" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -bitflags = "1" +bitflags = "2" embedded-hal = { version = "0.2.7", optional = true } nb = { version = "1.0.0", optional = true } volatile-register = "0.2" diff --git a/uart8250/README.md b/uart8250/README.md index 43c7cd7..bbac070 100644 --- a/uart8250/README.md +++ b/uart8250/README.md @@ -13,7 +13,7 @@ Besides, this crate currently is not following [Rust API Guidelines](https://rus ## Usage ```rust -let uart = MmioUart8250::new(0x1000_0000); +let uart = MmioUart8250::::new(0x1000_0000); uart.init(11_059_200, 115200); if let Some(c) = uart.read_byte() { //... @@ -23,7 +23,7 @@ if let Some(c) = uart.read_byte() { If you turn on feature `fmt` ```rust -let uart = MmioUart8250::new(0x1000_0000); +let uart = MmioUart8250::::new(0x1000_0000); uart.init(11_059_200, 115200); pub fn print_uart(args: fmt::Arguments) { diff --git a/uart8250/src/lib.rs b/uart8250/src/lib.rs index a142387..4466631 100644 --- a/uart8250/src/lib.rs +++ b/uart8250/src/lib.rs @@ -11,4 +11,37 @@ This crate provides a struct with many methods to operate an 8250 UART. mod registers; mod uart; -pub use uart::{ChipFifoInfo, InterruptType, MmioUart8250, Parity, TransmitError}; +use core::ops::{Deref, DerefMut}; +pub use uart::{ChipFifoInfo, InterruptType, Parity, TransmitError}; +use crate::registers::{Register}; + +pub struct MmioUart8250(uart::MmioUart8250<'static, R>); + + +unsafe impl Send for MmioUart8250 {} +unsafe impl Sync for MmioUart8250 {} + + +impl MmioUart8250 { + pub fn new(base_addr: usize) -> Self { + let uart_raw = unsafe { uart::MmioUart8250::::new(base_addr) }; + MmioUart8250(uart_raw) + } + pub fn set_base_address(&mut self, base_address: usize) { + unsafe { self.0.set_base_address(base_address); } + } +} + +impl Deref for MmioUart8250 { + type Target = uart::MmioUart8250<'static, u32>; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl DerefMut for MmioUart8250 { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} \ No newline at end of file diff --git a/uart8250/src/registers.rs b/uart8250/src/registers.rs index 85b5c39..6679156 100644 --- a/uart8250/src/registers.rs +++ b/uart8250/src/registers.rs @@ -22,21 +22,83 @@ use volatile_register::{RO, RW}; /// | +5 | x | Read | LSR | Line Status Register | /// | +6 | x | Read | MSR | Modem Status Register | /// | +7 | x | Read/Write | SR | Scratch Register | -#[repr(C, packed)] -pub struct Registers { - pub thr_rbr_dll: RW, - pub ier_dlh: RW, - pub iir_fcr: RW, - pub lcr: RW, - pub mcr: RW, - pub lsr: RO, - pub msr: RO, - pub scratch: RW, +#[repr(C)] +pub struct Registers { + pub thr_rbr_dll: RwReg, + pub ier_dlh: RwReg, + pub iir_fcr: RwReg, + pub lcr: RwReg, + pub mcr: RwReg, + pub lsr: RoReg, + pub msr: RoReg, + pub scratch: RwReg, } -impl Registers { +#[repr(C)] +pub struct RoReg(RO); + +impl RoReg { + /// Reads the value of the register + #[inline(always)] + pub fn read(&self) -> u8 { + self.0.read().val() + } +} + +#[repr(C)] +pub struct RwReg(RW); + +impl RwReg { + /// Performs a read-modify-write operation + /// + /// NOTE: `unsafe` because writes to a register are side effectful + #[inline(always)] + pub unsafe fn modify(&self, f: F) + where + F: FnOnce(u8) -> u8, + { + self.0.write(f(self.read()).into()); + } + + /// Reads the value of the register + #[inline(always)] + pub fn read(&self) -> u8 { + self.0.read().val() + } + + /// Writes a `value` into the register + /// + /// NOTE: `unsafe` because writes to a register are side effectful + #[inline(always)] + pub unsafe fn write(&self, value: u8) { + self.0.write(value.into()) + } +} + +impl Registers { /// Constructs a new instance of the UART registers starting at the given base address. pub unsafe fn from_base_address(base_address: usize) -> &'static mut Self { - &mut *(base_address as *mut crate::registers::Registers) + &mut *(base_address as *mut Registers) + } +} + +pub trait Register: From { + /// 取出寄存器中的有效位。 + fn val(self) -> u8; +} + +/// 寄存器的 8 位模式。 +impl Register for u8 { + #[inline] + fn val(self) -> u8 { + self + } +} + +/// 寄存器的 32 位模式。 +impl Register for u32 { + #[inline] + fn val(self) -> u8 { + self as _ } } diff --git a/uart8250/src/uart.rs b/uart8250/src/uart.rs index d13b345..ebe8a8a 100644 --- a/uart8250/src/uart.rs +++ b/uart8250/src/uart.rs @@ -3,7 +3,7 @@ use bitflags::bitflags; use core::convert::Infallible; use core::fmt::{self, Display, Formatter}; -use crate::registers::Registers; +use crate::registers::{Register, Registers}; bitflags! { /// Interrupt Enable Register (bitflags) @@ -112,11 +112,11 @@ impl Display for TransmitError { /// # MMIO version of an 8250 UART. /// /// **Note** This is only tested on the NS16550 compatible UART used in QEMU 5.0 virt machine of RISC-V. -pub struct MmioUart8250<'a> { - reg: &'a mut Registers, +pub struct MmioUart8250<'a, R: Register + Copy> { + reg: &'a mut Registers, } -impl<'a> MmioUart8250<'a> { +impl<'a, R: Register + Copy + 'static> MmioUart8250<'a, R> { /// Creates a new UART. /// /// # Safety @@ -670,7 +670,7 @@ impl<'a> MmioUart8250<'a> { /// /// A simple implementation, may be changed in the future #[cfg(feature = "fmt")] -impl<'a> fmt::Write for MmioUart8250<'a> { +impl<'a, R: Register + Copy + 'static> fmt::Write for MmioUart8250<'a, R> { fn write_str(&mut self, s: &str) -> fmt::Result { for c in s.as_bytes() { // If buffer is full, keep retrying. @@ -681,7 +681,7 @@ impl<'a> fmt::Write for MmioUart8250<'a> { } #[cfg(feature = "embedded")] -impl embedded_hal::serial::Read for MmioUart8250<'_> { +impl embedded_hal::serial::Read for MmioUart8250<'_, R> { type Error = Infallible; fn read(&mut self) -> nb::Result { @@ -690,7 +690,7 @@ impl embedded_hal::serial::Read for MmioUart8250<'_> { } #[cfg(feature = "embedded")] -impl embedded_hal::serial::Write for MmioUart8250<'_> { +impl embedded_hal::serial::Write for MmioUart8250<'_, R> { type Error = Infallible; fn write(&mut self, byte: u8) -> nb::Result<(), Self::Error> { @@ -720,7 +720,7 @@ mod tests { // Create a fake UART using an in-memory buffer, and check that it is initialised as // expected. let mut fake_registers: [u8; 8] = [0xff; 8]; - let uart = unsafe { MmioUart8250::new(&mut fake_registers as *mut u8 as usize) }; + let uart = unsafe { MmioUart8250::::new(&mut fake_registers as *mut u8 as usize) }; uart.init(11_059_200, 115200); @@ -732,7 +732,7 @@ mod tests { #[test] fn write() { let mut fake_registers: [u8; 8] = [0; 8]; - let uart = unsafe { MmioUart8250::new(&mut fake_registers as *mut u8 as usize) }; + let uart = unsafe { MmioUart8250::::new(&mut fake_registers as *mut u8 as usize) }; // Pretend that the transmit buffer is full. fake_registers[5] = 0; @@ -748,7 +748,7 @@ mod tests { #[test] fn read() { let mut fake_registers: [u8; 8] = [0; 8]; - let uart = unsafe { MmioUart8250::new(&mut fake_registers as *mut u8 as usize) }; + let uart = unsafe { MmioUart8250::::new(&mut fake_registers as *mut u8 as usize) }; // First try to read when there is nothing available. assert_eq!(uart.read_byte(), None);