1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147
//! CPU-level input/output instructions, including `inb`, `outb`, etc., and
//! a high level Rust wrapper.
#![no_std]
use core::marker::PhantomData;
// These cfg statements should cause compiler errors on non-x86 platforms.
#[cfg(any(target_arch="x86", target_arch="x86_64"))]
mod x86;
#[cfg(any(target_arch="x86", target_arch="x86_64"))]
pub use x86::{inb, outb, inw, outw, inl, outl};
/// This trait is defined for any type which can be read from a port.
/// x86 processors support Port IO for `u8`, `u16` and `u32`.
pub trait PortIn {
/// Read a value from the specified port.
unsafe fn port_in(port: u16) -> Self;
}
/// This trait is defined for any type which can be read from a port.
/// x86 processors support Port IO for `u8`, `u16` and `u32`.
pub trait PortOut {
/// Write a value to the specified port.
unsafe fn port_out(port: u16, value: Self);
}
impl PortOut for u8 {
unsafe fn port_out(port: u16, value: Self) {
outb(value, port);
}
}
impl PortOut for u16 {
unsafe fn port_out(port: u16, value: Self) {
outw(value, port);
}
}
impl PortOut for u32 {
unsafe fn port_out(port: u16, value: Self) {
outl(value, port);
}
}
impl PortIn for u8 {
unsafe fn port_in(port: u16) -> Self {
inb(port)
}
}
impl PortIn for u16 {
unsafe fn port_in(port: u16) -> Self {
inw(port)
}
}
impl PortIn for u32 {
unsafe fn port_in(port: u16) -> Self {
inl(port)
}
}
/// A readable and writable I/O port over an arbitrary type supporting the `InOut` interface,
/// which is only `u8`, `u16`, or `u32`.
// /// which only includes types that losslessly convert into a `u8`, `u16`, and `u32`.
#[derive(Debug)]
pub struct Port<T: PortIn + PortOut> {
/// Port address (in the I/O space), which is always 16 bits.
port: u16,
_phantom: PhantomData<T>,
}
impl<T: PortIn + PortOut> Port<T> {
/// Create a new I/O port.
pub const fn new(port: u16) -> Port<T> {
Port { port: port, _phantom: PhantomData }
}
/// Returns the address of this port.
pub const fn port_address(&self) -> u16 {
self.port
}
/// Read data of size `T` from the port.
pub fn read(&self) -> T {
unsafe { T::port_in(self.port) }
}
/// Write data of size `T` to the port.
/// This is unsafe because writing to an arbitrary port may cause problems.
pub unsafe fn write(&self, value: T) {
T::port_out(self.port, value);
}
}
/// A read-only I/O port over an arbitrary type supporting the `InOut` interface,
/// which is only `u8`, `u16`, and `u32`.
#[derive(Debug)]
pub struct PortReadOnly<T: PortIn> {
/// Port address (in the I/O space), which is always 16 bits.
port: u16,
_phantom: PhantomData<T>,
}
impl<T: PortIn> PortReadOnly<T> {
/// Create a new read-only I/O port.
pub const fn new(port: u16) -> PortReadOnly<T> {
PortReadOnly { port: port, _phantom: PhantomData }
}
/// Returns the address of this port.
pub const fn port_address(&self) -> u16 {
self.port
}
/// Read data of size `T` from the port.
pub fn read(&self) -> T {
unsafe { T::port_in(self.port) }
}
}
/// A write-only I/O port over an arbitrary type supporting the `InOut` interface,
/// which is only `u8`, `u16`, and `u32`.
#[derive(Debug)]
pub struct PortWriteOnly<T: PortOut> {
/// Port address (in the I/O space), which is always 16 bits.
port: u16,
_phantom: PhantomData<T>,
}
impl<T: PortOut> PortWriteOnly<T> {
/// Create a new read-only I/O port.
pub const fn new(port: u16) -> PortWriteOnly<T> {
PortWriteOnly { port: port, _phantom: PhantomData }
}
/// Returns the address of this port.
pub const fn port_address(&self) -> u16 {
self.port
}
/// Write data of size `T` to the port.
/// This is unsafe because writing to an arbitrary port may cause problems.
pub unsafe fn write(&self, value: T) {
T::port_out(self.port, value);
}
}