1use core::marker::PhantomData;
6
7use crate::{Accessible, IoHandle, LayoutOver, Register};
8
9pub type Port<Layout, Base, Access> = Register<Layout, Access, PortIo<Base, Access>>;
19
20impl<Layout, Base, Access> Port<Layout, Base, Access>
21where
22 Layout: LayoutOver<Base>,
23 Base: Copy,
24 Access: Accessible,
25{
26 pub const fn new(port: u16) -> Self {
28 unsafe { Register::from_io(PortIo::new(port)) }
30 }
31}
32
33#[derive(Debug)]
35pub struct PortIo<Base, Access: Accessible> {
36 port: u16,
37 _marker: PhantomData<(Base, Access)>,
38}
39
40impl<Base, Access: Accessible> PortIo<Base, Access> {
41 pub const fn new(port: u16) -> Self {
43 Self { port, _marker: PhantomData }
44 }
45
46 pub const fn port(&self) -> u16 {
48 self.port
49 }
50}
51
52impl<Base, Access: Accessible> Clone for PortIo<Base, Access> {
53 fn clone(&self) -> Self {
54 Self { port: self.port, _marker: PhantomData }
55 }
56}
57
58impl<Base, Access: Accessible> Copy for PortIo<Base, Access> {}
59
60impl<Base: Copy, Access: Accessible> IoHandle for PortIo<Base, Access> {
61 type Base = Base;
62}
63
64#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
65mod x86_only {
66 use core::arch::asm;
67
68 use super::*;
69 use crate::{ReadHandle, Readable, Writable, WriteHandle};
70
71 macro_rules! impl_port_io_handle_for_small_base {
72 ($ty:ty, $reg:tt) => {
73 impl<Access: Readable> ReadHandle for PortIo<$ty, Access> {
74 #[inline]
75 unsafe fn read_raw(&self) -> $ty {
76 let value: $ty;
77 unsafe {
78 asm!(
79 concat!("in ", $reg, ", dx"),
80 in("dx") self.port,
81 out($reg) value,
82 options(nostack, preserves_flags),
83 );
84 }
85 value
86 }
87 }
88
89 impl<Access: Writable> WriteHandle for PortIo<$ty, Access> {
90 #[inline]
91 unsafe fn write_raw(&self, value: $ty) {
92 unsafe {
93 asm!(
94 concat!("out dx, ", $reg),
95 in("dx") self.port,
96 in($reg) value,
97 options(nostack, preserves_flags),
98 );
99 }
100 }
101 }
102 };
103 }
104
105 impl_port_io_handle_for_small_base!(u8, "al");
106 impl_port_io_handle_for_small_base!(u16, "ax");
107 impl_port_io_handle_for_small_base!(u32, "eax");
108
109 impl<Access: Readable> ReadHandle for PortIo<u64, Access> {
110 #[inline]
111 unsafe fn read_raw(&self) -> u64 {
112 let low = unsafe { PortIo::<u32, Access>::new(self.port).read_raw() };
113 let high = unsafe { PortIo::<u32, Access>::new(self.port + 1).read_raw() };
114 u64::from(high) << 32 | u64::from(low)
115 }
116 }
117
118 impl<Access: Writable> WriteHandle for PortIo<u64, Access> {
119 #[inline]
120 unsafe fn write_raw(&self, value: u64) {
121 let low = value as u32;
122 let high = (value >> 32) as u32;
123 unsafe {
124 PortIo::<u32, Access>::new(self.port).write_raw(low);
125 PortIo::<u32, Access>::new(self.port + 1).write_raw(high);
126 }
127 }
128 }
129}