use super::ExtendedCapability;
use accessor::single;
use accessor::Mapper;
use bit_field::BitField;
use core::convert::TryFrom;
use core::convert::TryInto;
#[derive(Debug)]
pub enum XhciMessageInterrupt<M>
where
M: Mapper,
{
Addr32(single::ReadWrite<Internal<u32>, M>),
Addr64(single::ReadWrite<Internal<u64>, M>),
}
impl<M> XhciMessageInterrupt<M>
where
M: Mapper + Clone,
{
pub unsafe fn new(base: usize, mapper: M) -> Self {
let control: single::ReadWrite<MessageControl, M> =
single::ReadWrite::new(base + 2, mapper.clone());
if control.read_volatile().bit64_address_capable() {
Self::Addr64(single::ReadWrite::new(base, mapper))
} else {
Self::Addr32(single::ReadWrite::new(base, mapper))
}
}
}
impl<M> From<XhciMessageInterrupt<M>> for ExtendedCapability<M>
where
M: Mapper + Clone,
{
fn from(x: XhciMessageInterrupt<M>) -> Self {
ExtendedCapability::XhciMessageInterrupt(x)
}
}
#[repr(C)]
#[derive(Copy, Clone, Debug)]
pub struct Internal<T>
where
T: MessageAddress,
<T as TryFrom<u64>>::Error: core::fmt::Debug,
{
_id: u8,
_next: u8,
pub control: MessageControl,
address: T,
pub data: u16,
pub mask_bits: u32,
pub pending_bits: u32,
}
impl<T> Internal<T>
where
T: MessageAddress,
<T as TryFrom<u64>>::Error: core::fmt::Debug,
{
pub fn set_addr(&mut self, a: u64) {
assert!(
a.trailing_zeros() >= 2,
"Bits 0..=1 of the Message Address must be 0."
);
self.address = a.try_into().expect("The address does not fit.");
}
pub fn get_addr(&self) -> u64 {
self.address.into()
}
}
pub trait MessageAddress: Into<u64> + TryFrom<u64> + Copy
where
<Self as TryFrom<u64>>::Error: core::fmt::Debug,
{
}
impl MessageAddress for u32 {}
impl MessageAddress for u64 {}
#[repr(transparent)]
#[derive(Copy, Clone)]
pub struct MessageControl(u16);
impl MessageControl {
ro_bit!(8, per_vector_masking_capable, "Per-vector masking capable");
ro_bit!(7, bit64_address_capable, "64 bit address capable");
#[must_use]
pub fn multiple_message_enable(self) -> u8 {
self.0.get_bits(4..=6).try_into().unwrap()
}
pub fn set_multiple_message_enable(&mut self, m: u8) {
self.0.set_bits(4..=6, m.into());
}
#[must_use]
pub fn multiple_message_capable(self) -> u8 {
self.0.get_bits(1..=3).try_into().unwrap()
}
rw_bit!(0, msi_enable, "MSI Enable");
}
impl_debug_from_methods! {
MessageControl {
per_vector_masking_capable,
bit64_address_capable,
multiple_message_enable,
multiple_message_capable,
msi_enable,
}
}