1 //! Types and macros for VirtIO device configuration space.
2
3 use crate::{transport::Transport, Error};
4 use zerocopy::{FromBytes, Immutable, IntoBytes};
5
6 /// A configuration space register from which the driver can only read.
7 #[derive(Default, FromBytes, Immutable, IntoBytes)]
8 #[repr(transparent)]
9 pub struct ReadOnly<T: Copy + FromBytes>(pub T);
10
11 impl<T: Copy + FromBytes> ReadOnly<T> {
12 /// Constructs a new instance for testing.
new(value: T) -> Self13 pub const fn new(value: T) -> Self {
14 Self(value)
15 }
16 }
17
18 /// A configuration space register to which the driver can only write.
19 #[derive(Default, FromBytes, Immutable, IntoBytes)]
20 #[repr(transparent)]
21 pub struct WriteOnly<T: Copy + Immutable + IntoBytes>(pub T);
22
23 impl<T: Copy + Immutable + IntoBytes> WriteOnly<T> {
24 /// Constructs a new instance for testing.
new(value: T) -> Self25 pub const fn new(value: T) -> Self {
26 Self(value)
27 }
28 }
29
30 /// A configuration space register which the driver may both read and write.
31 #[derive(Default, FromBytes, Immutable, IntoBytes)]
32 #[repr(transparent)]
33 pub struct ReadWrite<T: Copy + FromBytes + Immutable + IntoBytes>(pub T);
34
35 impl<T: Copy + FromBytes + Immutable + IntoBytes> ReadWrite<T> {
36 /// Constructs a new instance for testing.
new(value: T) -> Self37 pub const fn new(value: T) -> Self {
38 Self(value)
39 }
40 }
41
42 /// Marker trait for configuration space registers from which the driver may read.
43 pub trait ConfigReadable<T> {}
44
45 /// Marker trait for configuration space registers to which the driver may write.
46 pub trait ConfigWritable<T> {}
47
48 impl<T: Copy + FromBytes> ConfigReadable<T> for ReadOnly<T> {}
49 impl<T: Copy + FromBytes + Immutable + IntoBytes> ConfigReadable<T> for ReadWrite<T> {}
50 impl<T: Copy + FromBytes + Immutable + IntoBytes> ConfigWritable<T> for ReadWrite<T> {}
51 impl<T: Copy + Immutable + IntoBytes> ConfigWritable<T> for WriteOnly<T> {}
52
53 /// Wrapper for `Transport::read_config_space`` with an extra dummy parameter to force the correct
54 /// type to be inferred.
55 #[inline(always)]
read_help<T, V, R>( transport: &T, offset: usize, _dummy_r: Option<R>, ) -> Result<V, Error> where T: Transport, V: FromBytes, R: ConfigReadable<V>,56 pub(crate) fn read_help<T, V, R>(
57 transport: &T,
58 offset: usize,
59 _dummy_r: Option<R>,
60 ) -> Result<V, Error>
61 where
62 T: Transport,
63 V: FromBytes,
64 R: ConfigReadable<V>,
65 {
66 transport.read_config_space(offset)
67 }
68
69 /// Wrapper for Transport::write_config_space with an extra dummy parameter to force the correct
70 /// type to be inferred.
71 #[inline(always)]
write_help<T, V, W>( transport: &mut T, offset: usize, value: V, _dummy_w: Option<W>, ) -> Result<(), Error> where T: Transport, V: Immutable + IntoBytes, W: ConfigWritable<V>,72 pub(crate) fn write_help<T, V, W>(
73 transport: &mut T,
74 offset: usize,
75 value: V,
76 _dummy_w: Option<W>,
77 ) -> Result<(), Error>
78 where
79 T: Transport,
80 V: Immutable + IntoBytes,
81 W: ConfigWritable<V>,
82 {
83 transport.write_config_space(offset, value)
84 }
85
86 /// Reads the given field of the given struct from the device config space via the given transport.
87 macro_rules! read_config {
88 ($transport:expr, $struct:ty, $field:ident) => {{
89 let dummy_struct: Option<$struct> = None;
90 let dummy_field = dummy_struct.map(|s| s.$field);
91 crate::config::read_help(
92 &$transport,
93 core::mem::offset_of!($struct, $field),
94 dummy_field,
95 )
96 }};
97 }
98
99 /// Writes the given field of the given struct from the device config space via the given transport.
100 macro_rules! write_config {
101 ($transport:expr, $struct:ty, $field:ident, $value:expr) => {{
102 let dummy_struct: Option<$struct> = None;
103 let dummy_field = dummy_struct.map(|s| s.$field);
104 crate::config::write_help(
105 &mut $transport,
106 core::mem::offset_of!($struct, $field),
107 $value,
108 dummy_field,
109 )
110 }};
111 }
112
113 pub(crate) use read_config;
114 pub(crate) use write_config;
115