use core::{num::NonZero, ptr::NonNull};
use crate::{ReadableRegister, UartAddress, WriteableRegister};
pub struct PortAddress(NonZero<u16>);
impl PortAddress {
pub const unsafe fn new(base: NonZero<u16>) -> Self {
Self(base)
}
}
unsafe impl UartAddress for PortAddress {
unsafe fn read(&self, register: ReadableRegister) -> u8 {
let port_address = self.0.checked_add(register.as_index()).unwrap();
let value: u8;
#[cfg(target_arch = "x86_64")]
unsafe {
core::arch::asm!(
"in al, dx",
out("al") value,
in("dx") port_address.get(),
options(nostack, nomem, preserves_flags)
);
}
#[cfg(not(target_arch = "x86_64"))]
unimplemented!();
value
}
unsafe fn write(&self, register: WriteableRegister, value: u8) {
let port_address = self.0.checked_add(register.as_index()).unwrap();
#[cfg(target_arch = "x86_64")]
unsafe {
core::arch::asm!(
"out dx, al",
in("dx") port_address.get(),
in("al") value,
options(nostack, nomem, preserves_flags)
);
}
#[cfg(not(target_arch = "x86_64"))]
unimplemented!();
}
}
pub struct MmioAddress {
base: NonNull<u8>,
stride: usize,
}
impl MmioAddress {
pub const unsafe fn new(base: NonNull<u8>, stride: usize) -> Self {
Self { base, stride }
}
}
unsafe impl UartAddress for MmioAddress {
unsafe fn write(&self, register: WriteableRegister, value: u8) {
unsafe {
self.base
.byte_add(usize::from(register.as_index()) * self.stride)
.write_volatile(value);
}
}
unsafe fn read(&self, register: ReadableRegister) -> u8 {
unsafe {
self.base
.byte_add(usize::from(register.as_index()) * self.stride)
.read_volatile()
}
}
}