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);
    }
}