pci_driver/regions/
structured.rs

1// SPDX-License-Identifier: MIT OR Apache-2.0
2
3/* ---------------------------------------------------------------------------------------------- */
4
5use num_traits::{PrimInt, Unsigned};
6use std::convert::TryInto;
7use std::fmt::{self, Binary, Debug, LowerHex, UpperHex};
8use std::io::{self, ErrorKind};
9use std::marker::PhantomData;
10
11use crate::regions::{AsPciSubregion, BackedByPciSubregion, PciRegion};
12
13/* ---------------------------------------------------------------------------------------------- */
14
15use private::Sealed;
16mod private {
17    /// Like [`crate::device::private::Sealed`].
18    pub trait Sealed {}
19}
20
21/// Trait for types that represent the value of a PCI field or register.
22///
23/// This is implemented for [`u8`], [`u16`], and [`u32`].
24///
25/// This trait is _sealed_, and thus cannot be implemented by users of the crate.
26pub trait PciRegisterValue:
27    PrimInt + Unsigned + Debug + LowerHex + UpperHex + Binary + Sealed
28{
29    /// Delegates to [`PciRegion::read_u8`], [`PciRegion::read_le_u16`], or
30    /// [`PciRegion::read_le_u32`].
31    fn read(region: &dyn PciRegion, offset: u64) -> io::Result<Self>;
32
33    /// Delegates to [`PciRegion::write_u8`], [`PciRegion::write_le_u16`], or
34    /// [`PciRegion::write_le_u32`].
35    fn write(self, region: &dyn PciRegion, offset: u64) -> io::Result<()>;
36}
37
38impl Sealed for u8 {}
39impl PciRegisterValue for u8 {
40    fn read(region: &dyn PciRegion, offset: u64) -> io::Result<Self> {
41        region.read_u8(offset)
42    }
43
44    fn write(self, region: &dyn PciRegion, offset: u64) -> io::Result<()> {
45        region.write_u8(offset, self)
46    }
47}
48
49impl Sealed for u16 {}
50impl PciRegisterValue for u16 {
51    fn read(region: &dyn PciRegion, offset: u64) -> io::Result<Self> {
52        region.read_le_u16(offset)
53    }
54
55    fn write(self, region: &dyn PciRegion, offset: u64) -> io::Result<()> {
56        region.write_le_u16(offset, self)
57    }
58}
59
60impl Sealed for u32 {}
61impl PciRegisterValue for u32 {
62    fn read(region: &dyn PciRegion, offset: u64) -> io::Result<Self> {
63        region.read_le_u32(offset)
64    }
65
66    fn write(self, region: &dyn PciRegion, offset: u64) -> io::Result<()> {
67        region.write_le_u32(offset, self)
68    }
69}
70
71fn print_debug_hex<T: Debug + LowerHex>(
72    value: io::Result<T>,
73    f: &mut fmt::Formatter,
74) -> fmt::Result {
75    if let Ok(v) = value {
76        // Avoid newlines around short values, and print in hex since that is usually more useful.
77        write!(f, "Ok({:#x})", v)
78    } else {
79        Debug::fmt(&value, f)
80    }
81}
82
83fn print_debug_bool(value: io::Result<bool>, f: &mut fmt::Formatter) -> fmt::Result {
84    if let Ok(v) = value {
85        // Avoid newlines around short values.
86        write!(f, "Ok({})", v)
87    } else {
88        Debug::fmt(&value, f)
89    }
90}
91
92/* ---------------------------------------------------------------------------------------------- */
93
94// READ-ONLY REGISTERS
95
96/// An 8-bit, 16-bit, or 32-bit PCI register that is read-only.
97#[derive(Clone, Copy)]
98pub struct PciRegisterRo<'a, T: PciRegisterValue> {
99    region: &'a dyn PciRegion,
100    offset: u64,
101    phantom: PhantomData<T>,
102}
103
104impl<'a, T: PciRegisterValue> PciRegisterRo<'a, T> {
105    /// Read the field.
106    pub fn read(&self) -> io::Result<T> {
107        T::read(self.region, self.offset)
108    }
109}
110
111impl<'a, T: PciRegisterValue> BackedByPciSubregion<'a> for PciRegisterRo<'a, T> {
112    fn backed_by(as_subregion: impl AsPciSubregion<'a>) -> Self {
113        let subregion = as_subregion.as_subregion();
114        PciRegisterRo {
115            region: subregion.underlying_region(),
116            offset: subregion.offset_in_underlying_region(),
117            phantom: PhantomData,
118        }
119    }
120}
121
122impl<T: PciRegisterValue> Debug for PciRegisterRo<'_, T> {
123    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
124        print_debug_hex(self.read(), f)
125    }
126}
127
128// READ-WRITE REGISTERS
129
130/// An 8-bit, 16-bit, or 32-bit PCI register that is read-write.
131#[derive(Clone, Copy)]
132pub struct PciRegisterRw<'a, T: PciRegisterValue> {
133    region: &'a dyn PciRegion,
134    offset: u64,
135    phantom: PhantomData<T>,
136}
137
138impl<'a, T: PciRegisterValue> PciRegisterRw<'a, T> {
139    /// Read the field.
140    pub fn read(&self) -> io::Result<T> {
141        T::read(self.region, self.offset)
142    }
143
144    /// Write the field.
145    pub fn write(&self, value: T) -> io::Result<()> {
146        value.write(self.region, self.offset)
147    }
148}
149
150impl<'a, T: PciRegisterValue> BackedByPciSubregion<'a> for PciRegisterRw<'a, T> {
151    fn backed_by(as_subregion: impl AsPciSubregion<'a>) -> Self {
152        let subregion = as_subregion.as_subregion();
153        PciRegisterRw {
154            region: subregion.underlying_region(),
155            offset: subregion.offset_in_underlying_region(),
156            phantom: PhantomData,
157        }
158    }
159}
160
161impl<T: PciRegisterValue> Debug for PciRegisterRw<'_, T> {
162    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
163        print_debug_hex(self.read(), f)
164    }
165}
166
167/* ---------------------------------------------------------------------------------------------- */
168
169// BIT FIELD TRAITS
170
171/// A PCI register of type that is a bit field and may be read.
172pub trait PciBitFieldReadable: Debug {
173    /// The type of the register's value.
174    type Type: PciRegisterValue;
175
176    /// Read the entire bit field at once.
177    fn read(&self) -> io::Result<Self::Type>;
178}
179
180/// A PCI register of type that is a bit field and may be written.
181pub trait PciBitFieldWriteable: PciBitFieldReadable {
182    /// Write mask for the register.
183    ///
184    /// One wants to alter the value of only some bits of the register. However, the register may
185    /// only be read/written in its entirety. Further, some of the bits in the register may need to
186    /// be written with the value 0 in order not to change their actual state in the device. This
187    /// write mask has those bits set to 0, and the others set to 1. Thus, to alter the value of
188    /// only some bits of the register, this must be done:
189    ///
190    /// - Read the register into `x`;
191    /// - Apply the write mask to `x`, _i.e._, `let y = x & WRITE_MASK`;
192    /// - Modify `y` as needed;
193    /// - Write the resulting value into the register.
194    ///
195    /// Of course, you most likely can just use the member functions that this type provides to
196    /// manipulate individual parts of the register, but sometimes you may need to do these steps by
197    /// yourself, _e.g._, to atomically alter several parts of the register at once.
198    const WRITE_MASK: Self::Type;
199
200    /// Write the entire bit field at once.
201    fn write(&self, value: Self::Type) -> io::Result<()>;
202}
203
204// TODO: Probably make these below use a PciSubregion, so they can check if they are reading/writing
205// past the end of the region.
206
207// READ-ONLY BIT SEQUENCES
208
209/// A read-only sequence of bits that is part of a PCI register.
210#[derive(Clone, Copy)]
211pub struct PciBitsReadOnly<'a, T, U>
212where
213    T: PciRegisterValue + TryInto<U>,
214    T::Error: Debug,
215    U: PciRegisterValue,
216{
217    region: &'a dyn PciRegion,
218    offset: u64,
219    mask: T,
220    shift: u8,
221    phantom: PhantomData<U>,
222}
223
224impl<'a, T, U> PciBitsReadOnly<'a, T, U>
225where
226    T: PciRegisterValue + TryInto<U>,
227    T::Error: Debug,
228    U: PciRegisterValue,
229{
230    pub fn backed_by(region: &'a dyn PciRegion, offset: u64, mask: T, shift: u8) -> Self {
231        PciBitsReadOnly {
232            region,
233            offset,
234            mask,
235            shift,
236            phantom: PhantomData,
237        }
238    }
239
240    /// Read the bit sequence.
241    ///
242    /// This reads the entire register and then masks and shifts the part we're interested in.
243    pub fn read(&self) -> io::Result<U> {
244        let value = (T::read(self.region, self.offset)? & self.mask) >> self.shift.into();
245        // TODO: Ensure at compile time that this can't fail.
246        Ok(value.try_into().unwrap())
247    }
248}
249
250impl<T, U> Debug for PciBitsReadOnly<'_, T, U>
251where
252    T: PciRegisterValue + TryInto<U>,
253    T::Error: Debug,
254    U: PciRegisterValue,
255{
256    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
257        print_debug_hex(self.read(), f)
258    }
259}
260
261// READ-WRITE BIT SEQUENCES
262
263/// A read-write sequence of bits that is part of a PCI register.
264#[derive(Clone, Copy)]
265pub struct PciBitsReadWrite<'a, T, U>
266where
267    T: PciRegisterValue + TryInto<U>,
268    T::Error: Debug,
269    U: PciRegisterValue + Into<T>,
270{
271    region: &'a dyn PciRegion,
272    offset: u64,
273    mask: T,
274    shift: u8,
275    write_mask: T, // must 'and' with this after reading but before altering the bits
276    phantom: PhantomData<U>,
277}
278
279impl<'a, T, U> PciBitsReadWrite<'a, T, U>
280where
281    T: PciRegisterValue + TryInto<U>,
282    T::Error: Debug,
283    U: PciRegisterValue + Into<T>,
284{
285    pub fn backed_by(
286        region: &'a dyn PciRegion,
287        offset: u64,
288        mask: T,
289        shift: u8,
290        write_mask: T,
291    ) -> Self {
292        PciBitsReadWrite {
293            region,
294            offset,
295            mask,
296            shift,
297            write_mask,
298            phantom: PhantomData,
299        }
300    }
301
302    /// Read the bit sequence.
303    ///
304    /// This reads the entire register and then masks and shifts the part we're interested in.
305    pub fn read(&self) -> io::Result<U> {
306        let value = (T::read(self.region, self.offset)? & self.mask) >> self.shift.into();
307        // TODO: Ensure at compile time that this can't fail.
308        Ok(value.try_into().unwrap())
309    }
310
311    /// Write the bit sequence.
312    ///
313    /// This shifts the value and makes sure to not affect any other bits in the underlying
314    /// register.
315    pub fn write(&self, value: U) -> io::Result<()> {
316        let shifted = value.into() << self.shift.into();
317
318        if shifted >> self.shift.into() != value.into() || shifted & !self.mask != T::zero() {
319            return Err(io::Error::new(ErrorKind::InvalidInput, "Value is too big"));
320        }
321
322        let to_write = (T::read(self.region, self.offset)? & self.write_mask) | shifted;
323        to_write.write(self.region, self.offset)
324    }
325}
326
327impl<T, U> Debug for PciBitsReadWrite<'_, T, U>
328where
329    T: PciRegisterValue + TryInto<U>,
330    T::Error: Debug,
331    U: PciRegisterValue + Into<T>,
332{
333    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
334        print_debug_hex(self.read(), f)
335    }
336}
337
338// READ-ONLY INDIVIDUAL BITS
339
340/// A read-only single bit that is part of a PCI register.
341#[derive(Clone, Copy)]
342pub struct PciBitReadOnly<'a, T: PciRegisterValue> {
343    region: &'a dyn PciRegion,
344    offset: u64,
345    mask: T,
346}
347
348impl<'a, T: PciRegisterValue> PciBitReadOnly<'a, T> {
349    pub fn backed_by(region: &'a dyn PciRegion, offset: u64, mask: T) -> Self {
350        PciBitReadOnly {
351            region,
352            offset,
353            mask,
354        }
355    }
356
357    /// Read the bit.
358    ///
359    /// This reads the entire register and then checks the bit we're interested in.
360    pub fn read(&self) -> io::Result<bool> {
361        Ok(T::read(self.region, self.offset)? & self.mask != T::zero())
362    }
363}
364
365impl<T: PciRegisterValue> Debug for PciBitReadOnly<'_, T> {
366    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
367        print_debug_bool(self.read(), f)
368    }
369}
370
371// READ-WRITE INDIVIDUAL BITS
372
373/// A read-write single bit that is part of a PCI register.
374#[derive(Clone, Copy)]
375pub struct PciBitReadWrite<'a, T: PciRegisterValue> {
376    region: &'a dyn PciRegion,
377    offset: u64,
378    mask: T,
379    write_mask: T, // must 'and' with this after reading but before altering the bits
380}
381
382impl<'a, T: PciRegisterValue> PciBitReadWrite<'a, T> {
383    pub fn backed_by(region: &'a dyn PciRegion, offset: u64, mask: T, write_mask: T) -> Self {
384        PciBitReadWrite {
385            region,
386            offset,
387            mask,
388            write_mask,
389        }
390    }
391
392    /// Read the bit.
393    ///
394    /// This reads the entire register and then checks the bit we're interested in.
395    pub fn read(&self) -> io::Result<bool> {
396        Ok(T::read(self.region, self.offset)? & self.mask != T::zero())
397    }
398
399    /// Write the bit.
400    ///
401    /// This makes sure to not affect any other bits in the underlying register.
402    pub fn write(&self, value: bool) -> io::Result<()> {
403        let old = T::read(self.region, self.offset)? & self.write_mask;
404
405        let new = if value {
406            old | self.mask
407        } else {
408            old & !self.mask
409        };
410
411        new.write(self.region, self.offset)
412    }
413}
414
415impl<T: PciRegisterValue> Debug for PciBitReadWrite<'_, T> {
416    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
417        print_debug_bool(self.read(), f)
418    }
419}
420
421// READ-CLEAR INDIVIDUAL BITS
422
423/// A read-clear (RW1C in the spec) single bit that is part of a PCI register.
424#[derive(Clone, Copy)]
425pub struct PciBitReadClear<'a, T: PciRegisterValue> {
426    rw: PciBitReadWrite<'a, T>,
427}
428
429impl<'a, T: PciRegisterValue> PciBitReadClear<'a, T> {
430    pub fn backed_by(region: &'a dyn PciRegion, offset: u64, mask: T, write_mask: T) -> Self {
431        PciBitReadClear {
432            rw: PciBitReadWrite {
433                region,
434                offset,
435                mask,
436                write_mask,
437            },
438        }
439    }
440
441    /// Read the bit.
442    ///
443    /// This reads the entire register and then checks the bit we're interested in.
444    pub fn read(&self) -> io::Result<bool> {
445        self.rw.read()
446    }
447
448    /// Clear the bit (_i.e._, set it to 0).
449    ///
450    /// This makes sure to not affect any other bits in the underlying register.
451    pub fn clear(&self) -> io::Result<()> {
452        self.rw.write(true)
453    }
454}
455
456impl<T: PciRegisterValue> Debug for PciBitReadClear<'_, T> {
457    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
458        print_debug_bool(self.read(), f)
459    }
460}
461
462/* ---------------------------------------------------------------------------------------------- */