Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
/target
/target
.idea
10 changes: 8 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion uart8250/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
4 changes: 2 additions & 2 deletions uart8250/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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::<u8>::new(0x1000_0000);
uart.init(11_059_200, 115200);
if let Some(c) = uart.read_byte() {
//...
Expand All @@ -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::<u8>::new(0x1000_0000);
uart.init(11_059_200, 115200);

pub fn print_uart(args: fmt::Arguments) {
Expand Down
35 changes: 34 additions & 1 deletion uart8250/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<R:Register + Copy+'static>(uart::MmioUart8250<'static, R>);


unsafe impl<R: Register + Copy + 'static> Send for MmioUart8250<R> {}
unsafe impl<R: Register + Copy + 'static> Sync for MmioUart8250<R> {}


impl MmioUart8250<u32> {
pub fn new(base_addr: usize) -> Self {
let uart_raw = unsafe { uart::MmioUart8250::<u32>::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<u32> {
type Target = uart::MmioUart8250<'static, u32>;

fn deref(&self) -> &Self::Target {
&self.0
}
}

impl DerefMut for MmioUart8250<u32> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
86 changes: 74 additions & 12 deletions uart8250/src/registers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<u8>,
pub ier_dlh: RW<u8>,
pub iir_fcr: RW<u8>,
pub lcr: RW<u8>,
pub mcr: RW<u8>,
pub lsr: RO<u8>,
pub msr: RO<u8>,
pub scratch: RW<u8>,
#[repr(C)]
pub struct Registers<R: Register + Copy> {
pub thr_rbr_dll: RwReg<R>,
pub ier_dlh: RwReg<R>,
pub iir_fcr: RwReg<R>,
pub lcr: RwReg<R>,
pub mcr: RwReg<R>,
pub lsr: RoReg<R>,
pub msr: RoReg<R>,
pub scratch: RwReg<R>,
}

impl Registers {
#[repr(C)]
pub struct RoReg<R: Register + Copy>(RO<R>);

impl<R: Register + Copy> RoReg<R> {
/// Reads the value of the register
#[inline(always)]
pub fn read(&self) -> u8 {
self.0.read().val()
}
}

#[repr(C)]
pub struct RwReg<R: Register + Copy>(RW<R>);

impl<R: Register + Copy> RwReg<R> {
/// Performs a read-modify-write operation
///
/// NOTE: `unsafe` because writes to a register are side effectful
#[inline(always)]
pub unsafe fn modify<F>(&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<R: Register + Copy> Registers<R> {
/// 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<R>)
}
}

pub trait Register: From<u8> {
/// 取出寄存器中的有效位。
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 _
}
}
20 changes: 10 additions & 10 deletions uart8250/src/uart.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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<R>,
}

impl<'a> MmioUart8250<'a> {
impl<'a, R: Register + Copy + 'static> MmioUart8250<'a, R> {
/// Creates a new UART.
///
/// # Safety
Expand Down Expand Up @@ -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.
Expand All @@ -681,7 +681,7 @@ impl<'a> fmt::Write for MmioUart8250<'a> {
}

#[cfg(feature = "embedded")]
impl embedded_hal::serial::Read<u8> for MmioUart8250<'_> {
impl<R: Register + Copy + 'static> embedded_hal::serial::Read<u8> for MmioUart8250<'_, R> {
type Error = Infallible;

fn read(&mut self) -> nb::Result<u8, Self::Error> {
Expand All @@ -690,7 +690,7 @@ impl embedded_hal::serial::Read<u8> for MmioUart8250<'_> {
}

#[cfg(feature = "embedded")]
impl embedded_hal::serial::Write<u8> for MmioUart8250<'_> {
impl<R: Register + Copy + 'static> embedded_hal::serial::Write<u8> for MmioUart8250<'_, R> {
type Error = Infallible;

fn write(&mut self, byte: u8) -> nb::Result<(), Self::Error> {
Expand Down Expand Up @@ -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::<u8>::new(&mut fake_registers as *mut u8 as usize) };

uart.init(11_059_200, 115200);

Expand All @@ -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::<u8>::new(&mut fake_registers as *mut u8 as usize) };

// Pretend that the transmit buffer is full.
fake_registers[5] = 0;
Expand All @@ -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::<u8>::new(&mut fake_registers as *mut u8 as usize) };

// First try to read when there is nothing available.
assert_eq!(uart.read_byte(), None);
Expand Down