use crate::backend::{Backend, MmioAddress, MmioBackend, RegisterAddress};
#[cfg(any(target_arch = "x86", target_arch = "x86_64", doc))]
use crate::backend::{PioBackend, PortIoAddress};
use crate::{Config, InitError, InvalidAddressError, LoopbackError, Uart16550};
use core::error::Error;
use core::fmt::{self, Display, Formatter};
use core::ptr::NonNull;
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub enum Uart16550TtyError<A: RegisterAddress> {
AddressError(InvalidAddressError<A>),
InitError(InitError),
TestError(LoopbackError),
}
impl<A: RegisterAddress> Display for Uart16550TtyError<A> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self {
Self::AddressError(e) => {
write!(f, "{e}")
}
Self::InitError(e) => {
write!(f, "error initializing the device: {e}")
}
Self::TestError(e) => {
write!(f, "error testing the device: {e}")
}
}
}
}
impl<A: RegisterAddress + 'static> Error for Uart16550TtyError<A> {
fn source(&self) -> Option<&(dyn Error + 'static)> {
match self {
Self::AddressError(e) => Some(e),
Self::InitError(e) => Some(e),
Self::TestError(e) => Some(e),
}
}
}
#[cfg_attr(
any(target_arch = "x86", target_arch = "x86_64"),
doc = "```rust,no_run"
)]
#[cfg_attr(
not(any(target_arch = "x86", target_arch = "x86_64")),
doc = "```rust,ignore"
)]
#[derive(Debug)]
pub struct Uart16550Tty<B: Backend>(Uart16550<B>);
#[cfg(any(target_arch = "x86", target_arch = "x86_64", doc))]
impl Uart16550Tty<PioBackend> {
pub unsafe fn new_port(
base_port: u16,
config: Config,
) -> Result<Self, Uart16550TtyError<PortIoAddress>> {
let mut inner =
unsafe { Uart16550::new_port(base_port).map_err(Uart16550TtyError::AddressError)? };
inner.init(config).map_err(Uart16550TtyError::InitError)?;
inner
.test_loopback()
.map_err(Uart16550TtyError::TestError)?;
Ok(Self(inner))
}
}
impl Uart16550Tty<MmioBackend> {
pub unsafe fn new_mmio(
base_address: NonNull<u8>,
stride: u8,
config: Config,
) -> Result<Self, Uart16550TtyError<MmioAddress>> {
let mut inner = unsafe {
Uart16550::new_mmio(base_address, stride).map_err(Uart16550TtyError::AddressError)?
};
inner.init(config).map_err(Uart16550TtyError::InitError)?;
inner
.test_loopback()
.map_err(Uart16550TtyError::TestError)?;
Ok(Self(inner))
}
}
impl<B: Backend> Uart16550Tty<B> {
pub const fn inner(&self) -> &Uart16550<B> {
&self.0
}
pub const fn inner_mut(&mut self) -> &mut Uart16550<B> {
&mut self.0
}
}
impl<B: Backend> fmt::Write for Uart16550Tty<B> {
fn write_str(&mut self, s: &str) -> fmt::Result {
for &byte in s.as_bytes() {
match byte {
8 | 0x7F => {
self.0.send_bytes_exact(&[8]);
self.0.send_bytes_exact(b" ");
self.0.send_bytes_exact(&[8]);
}
b'\n' => {
self.0.send_bytes_exact(b"\r");
self.0.send_bytes_exact(b"\n");
}
data => {
self.0.send_bytes_exact(&[data]);
}
}
}
Ok(())
}
}