use num_traits::{PrimInt, Unsigned};
use std::convert::TryInto;
use std::fmt::{self, Binary, Debug, LowerHex, UpperHex};
use std::io::{self, ErrorKind};
use std::marker::PhantomData;
use crate::regions::{AsPciSubregion, BackedByPciSubregion, PciRegion};
use private::Sealed;
mod private {
pub trait Sealed {}
}
pub trait PciRegisterValue:
PrimInt + Unsigned + Debug + LowerHex + UpperHex + Binary + Sealed
{
fn read(region: &dyn PciRegion, offset: u64) -> io::Result<Self>;
fn write(self, region: &dyn PciRegion, offset: u64) -> io::Result<()>;
}
impl Sealed for u8 {}
impl PciRegisterValue for u8 {
fn read(region: &dyn PciRegion, offset: u64) -> io::Result<Self> {
region.read_u8(offset)
}
fn write(self, region: &dyn PciRegion, offset: u64) -> io::Result<()> {
region.write_u8(offset, self)
}
}
impl Sealed for u16 {}
impl PciRegisterValue for u16 {
fn read(region: &dyn PciRegion, offset: u64) -> io::Result<Self> {
region.read_le_u16(offset)
}
fn write(self, region: &dyn PciRegion, offset: u64) -> io::Result<()> {
region.write_le_u16(offset, self)
}
}
impl Sealed for u32 {}
impl PciRegisterValue for u32 {
fn read(region: &dyn PciRegion, offset: u64) -> io::Result<Self> {
region.read_le_u32(offset)
}
fn write(self, region: &dyn PciRegion, offset: u64) -> io::Result<()> {
region.write_le_u32(offset, self)
}
}
fn print_debug_hex<T: Debug + LowerHex>(
value: io::Result<T>,
f: &mut fmt::Formatter,
) -> fmt::Result {
if let Ok(v) = value {
write!(f, "Ok({:#x})", v)
} else {
Debug::fmt(&value, f)
}
}
fn print_debug_bool(value: io::Result<bool>, f: &mut fmt::Formatter) -> fmt::Result {
if let Ok(v) = value {
write!(f, "Ok({})", v)
} else {
Debug::fmt(&value, f)
}
}
#[derive(Clone, Copy)]
pub struct PciRegisterRo<'a, T: PciRegisterValue> {
region: &'a dyn PciRegion,
offset: u64,
phantom: PhantomData<T>,
}
impl<'a, T: PciRegisterValue> PciRegisterRo<'a, T> {
pub fn read(&self) -> io::Result<T> {
T::read(self.region, self.offset)
}
}
impl<'a, T: PciRegisterValue> BackedByPciSubregion<'a> for PciRegisterRo<'a, T> {
fn backed_by(as_subregion: impl AsPciSubregion<'a>) -> Self {
let subregion = as_subregion.as_subregion();
PciRegisterRo {
region: subregion.underlying_region(),
offset: subregion.offset_in_underlying_region(),
phantom: PhantomData,
}
}
}
impl<T: PciRegisterValue> Debug for PciRegisterRo<'_, T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
print_debug_hex(self.read(), f)
}
}
#[derive(Clone, Copy)]
pub struct PciRegisterRw<'a, T: PciRegisterValue> {
region: &'a dyn PciRegion,
offset: u64,
phantom: PhantomData<T>,
}
impl<'a, T: PciRegisterValue> PciRegisterRw<'a, T> {
pub fn read(&self) -> io::Result<T> {
T::read(self.region, self.offset)
}
pub fn write(&self, value: T) -> io::Result<()> {
value.write(self.region, self.offset)
}
}
impl<'a, T: PciRegisterValue> BackedByPciSubregion<'a> for PciRegisterRw<'a, T> {
fn backed_by(as_subregion: impl AsPciSubregion<'a>) -> Self {
let subregion = as_subregion.as_subregion();
PciRegisterRw {
region: subregion.underlying_region(),
offset: subregion.offset_in_underlying_region(),
phantom: PhantomData,
}
}
}
impl<T: PciRegisterValue> Debug for PciRegisterRw<'_, T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
print_debug_hex(self.read(), f)
}
}
pub trait PciBitFieldReadable: Debug {
type Type: PciRegisterValue;
fn read(&self) -> io::Result<Self::Type>;
}
pub trait PciBitFieldWriteable: PciBitFieldReadable {
const WRITE_MASK: Self::Type;
fn write(&self, value: Self::Type) -> io::Result<()>;
}
#[derive(Clone, Copy)]
pub struct PciBitsReadOnly<'a, T, U>
where
T: PciRegisterValue + TryInto<U>,
T::Error: Debug,
U: PciRegisterValue,
{
region: &'a dyn PciRegion,
offset: u64,
mask: T,
shift: u8,
phantom: PhantomData<U>,
}
impl<'a, T, U> PciBitsReadOnly<'a, T, U>
where
T: PciRegisterValue + TryInto<U>,
T::Error: Debug,
U: PciRegisterValue,
{
pub fn backed_by(region: &'a dyn PciRegion, offset: u64, mask: T, shift: u8) -> Self {
PciBitsReadOnly {
region,
offset,
mask,
shift,
phantom: PhantomData,
}
}
pub fn read(&self) -> io::Result<U> {
let value = (T::read(self.region, self.offset)? & self.mask) >> self.shift.into();
Ok(value.try_into().unwrap())
}
}
impl<T, U> Debug for PciBitsReadOnly<'_, T, U>
where
T: PciRegisterValue + TryInto<U>,
T::Error: Debug,
U: PciRegisterValue,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
print_debug_hex(self.read(), f)
}
}
#[derive(Clone, Copy)]
pub struct PciBitsReadWrite<'a, T, U>
where
T: PciRegisterValue + TryInto<U>,
T::Error: Debug,
U: PciRegisterValue + Into<T>,
{
region: &'a dyn PciRegion,
offset: u64,
mask: T,
shift: u8,
write_mask: T, phantom: PhantomData<U>,
}
impl<'a, T, U> PciBitsReadWrite<'a, T, U>
where
T: PciRegisterValue + TryInto<U>,
T::Error: Debug,
U: PciRegisterValue + Into<T>,
{
pub fn backed_by(
region: &'a dyn PciRegion,
offset: u64,
mask: T,
shift: u8,
write_mask: T,
) -> Self {
PciBitsReadWrite {
region,
offset,
mask,
shift,
write_mask,
phantom: PhantomData,
}
}
pub fn read(&self) -> io::Result<U> {
let value = (T::read(self.region, self.offset)? & self.mask) >> self.shift.into();
Ok(value.try_into().unwrap())
}
pub fn write(&self, value: U) -> io::Result<()> {
let shifted = value.into() << self.shift.into();
if shifted >> self.shift.into() != value.into() || shifted & !self.mask != T::zero() {
return Err(io::Error::new(ErrorKind::InvalidInput, "Value is too big"));
}
let to_write = (T::read(self.region, self.offset)? & self.write_mask) | shifted;
to_write.write(self.region, self.offset)
}
}
impl<T, U> Debug for PciBitsReadWrite<'_, T, U>
where
T: PciRegisterValue + TryInto<U>,
T::Error: Debug,
U: PciRegisterValue + Into<T>,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
print_debug_hex(self.read(), f)
}
}
#[derive(Clone, Copy)]
pub struct PciBitReadOnly<'a, T: PciRegisterValue> {
region: &'a dyn PciRegion,
offset: u64,
mask: T,
}
impl<'a, T: PciRegisterValue> PciBitReadOnly<'a, T> {
pub fn backed_by(region: &'a dyn PciRegion, offset: u64, mask: T) -> Self {
PciBitReadOnly {
region,
offset,
mask,
}
}
pub fn read(&self) -> io::Result<bool> {
Ok(T::read(self.region, self.offset)? & self.mask != T::zero())
}
}
impl<T: PciRegisterValue> Debug for PciBitReadOnly<'_, T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
print_debug_bool(self.read(), f)
}
}
#[derive(Clone, Copy)]
pub struct PciBitReadWrite<'a, T: PciRegisterValue> {
region: &'a dyn PciRegion,
offset: u64,
mask: T,
write_mask: T, }
impl<'a, T: PciRegisterValue> PciBitReadWrite<'a, T> {
pub fn backed_by(region: &'a dyn PciRegion, offset: u64, mask: T, write_mask: T) -> Self {
PciBitReadWrite {
region,
offset,
mask,
write_mask,
}
}
pub fn read(&self) -> io::Result<bool> {
Ok(T::read(self.region, self.offset)? & self.mask != T::zero())
}
pub fn write(&self, value: bool) -> io::Result<()> {
let old = T::read(self.region, self.offset)? & self.write_mask;
let new = if value {
old | self.mask
} else {
old & !self.mask
};
new.write(self.region, self.offset)
}
}
impl<T: PciRegisterValue> Debug for PciBitReadWrite<'_, T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
print_debug_bool(self.read(), f)
}
}
#[derive(Clone, Copy)]
pub struct PciBitReadClear<'a, T: PciRegisterValue> {
rw: PciBitReadWrite<'a, T>,
}
impl<'a, T: PciRegisterValue> PciBitReadClear<'a, T> {
pub fn backed_by(region: &'a dyn PciRegion, offset: u64, mask: T, write_mask: T) -> Self {
PciBitReadClear {
rw: PciBitReadWrite {
region,
offset,
mask,
write_mask,
},
}
}
pub fn read(&self) -> io::Result<bool> {
self.rw.read()
}
pub fn clear(&self) -> io::Result<()> {
self.rw.write(true)
}
}
impl<T: PciRegisterValue> Debug for PciBitReadClear<'_, T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
print_debug_bool(self.read(), f)
}
}