ableos/ableos/src/devices/pci/port.rs

73 lines
2.1 KiB
Rust

use core::marker::PhantomData;
/// Trait for limiting [Port] to only being able to read/write u8/16/32.
pub(crate) trait PortRW {
/// Read a value (self) from the port
unsafe fn read_port(port: u16) -> Self;
/// Write a value (self) to the port
unsafe fn write_port(port: u16, value: Self);
}
// PortRW Implementations //////////////////////////////////////////////////////////////////////////
impl PortRW for u8 {
unsafe fn read_port(port: u16) -> Self {
let value: u8;
asm!("in al, dx", out("al") value, in("dx") port, options(nomem, nostack, preserves_flags));
value
}
unsafe fn write_port(port: u16, value: Self) {
asm!("out dx, al", in("dx") port, in("al") value, options(nomem, nostack, preserves_flags));
}
}
impl PortRW for u16 {
unsafe fn read_port(port: u16) -> Self {
let value: u16;
asm!("in ax, dx", out("ax") value, in("dx") port, options(nomem, nostack, preserves_flags));
value
}
unsafe fn write_port(port: u16, value: Self) {
asm!("out dx, ax", in("dx") port, in("ax") value, options(nomem, nostack, preserves_flags));
}
}
impl PortRW for u32 {
unsafe fn read_port(port: u16) -> Self {
let value: u32;
asm!("in eax, dx", out("eax") value, in("dx") port, options(nomem, nostack, preserves_flags));
value
}
unsafe fn write_port(port: u16, value: Self) {
asm!("out dx, eax", in("dx") port, in("eax") value, options(nomem, nostack, preserves_flags));
}
}
/// A simple wrapper around the asm instructions needed to read/write I/O ports.
pub(crate) struct Port<T: PortRW> {
addr: u16,
_phantom: PhantomData<T>,
}
impl<T: PortRW> Port<T> {
/// Create a new `Port` with the given address and data size
pub(crate) fn new(addr: u16) -> Self {
Self {
addr,
_phantom: PhantomData,
}
}
/// Read a value from the port
pub(crate) unsafe fn read(&self) -> T {
T::read_port(self.addr)
}
/// Write a value to the port
pub(crate) unsafe fn write(&self, value: T) {
T::write_port(self.addr, value);
}
}