use super::registers::capability::CapabilityParameters1;
use accessor::single;
use accessor::Mapper;
use bit_field::BitField;
use core::convert::TryInto;
use debug::Debug;
use num_derive::FromPrimitive;
use num_traits::FromPrimitive;
use usb_legacy_support_capability::UsbLegacySupport;
pub use hci_extended_power_management::HciExtendedPowerManagement;
pub use xhci_extended_message_interrupt::XhciExtendedMessageInterrupt;
pub use xhci_local_memory::XhciLocalMemory;
pub use xhci_message_interrupt::XhciMessageInterrupt;
pub use xhci_supported_protocol::XhciSupportedProtocol;
pub mod debug;
pub mod hci_extended_power_management;
pub mod usb_legacy_support_capability;
pub mod xhci_extended_message_interrupt;
pub mod xhci_local_memory;
pub mod xhci_message_interrupt;
pub mod xhci_supported_protocol;
#[derive(Debug)]
pub struct List<M>
where
M: Mapper + Clone,
{
base: usize,
m: M,
}
impl<M> List<M>
where
M: Mapper + Clone,
{
pub unsafe fn new(
mmio_base: usize,
hccparams1: CapabilityParameters1,
mapper: M,
) -> Option<Self> {
let xecp: usize = hccparams1.xhci_extended_capabilities_pointer().into();
if xecp == 0 {
None
} else {
let base = mmio_base + (xecp << 2);
Some(Self { base, m: mapper })
}
}
}
impl<M> IntoIterator for &mut List<M>
where
M: Mapper + Clone,
{
type Item = Result<ExtendedCapability<M>, NotSupportedId>;
type IntoIter = IterMut<M>;
fn into_iter(self) -> Self::IntoIter {
IterMut::new(self)
}
}
#[derive(Debug)]
pub struct IterMut<M>
where
M: Mapper + Clone,
{
current: Option<usize>,
m: M,
}
impl<M> IterMut<M>
where
M: Mapper + Clone,
{
fn new(l: &List<M>) -> Self {
Self {
current: Some(l.base),
m: l.m.clone(),
}
}
}
impl<M> Iterator for IterMut<M>
where
M: Mapper + Clone,
{
type Item = Result<ExtendedCapability<M>, NotSupportedId>;
fn next(&mut self) -> Option<Self::Item> {
let current = self.current?;
let h: Header = unsafe { single::ReadWrite::new(current, self.m.clone()) }.read_volatile();
self.current = if h.next() == 0 {
None
} else {
Some(current + (usize::from(h.next()) << 2))
};
let c = unsafe { ExtendedCapability::new(current, h, self.m.clone()) };
Some(c.ok_or_else(|| NotSupportedId(h.id())))
}
}
#[derive(Debug)]
pub enum ExtendedCapability<M>
where
M: Mapper + Clone,
{
UsbLegacySupport(UsbLegacySupport<M>),
XhciSupportedProtocol(XhciSupportedProtocol<M>),
HciExtendedPowerManagementCapability(single::ReadWrite<HciExtendedPowerManagement, M>),
XhciMessageInterrupt(XhciMessageInterrupt<M>),
XhciLocalMemory(XhciLocalMemory<M>),
Debug(Debug<M>),
XhciExtendedMessageInterrupt(single::ReadWrite<XhciExtendedMessageInterrupt, M>),
}
impl<M> ExtendedCapability<M>
where
M: Mapper + Clone,
{
unsafe fn new(base: usize, h: Header, m: M) -> Option<Self> {
let ty = FromPrimitive::from_u8(h.id())?;
Self::from_ty(base, ty, m)
}
unsafe fn from_ty(base: usize, ty: Ty, m: M) -> Option<Self> {
let v = match ty {
Ty::UsbLegacySupport => UsbLegacySupport::new(base, m).into(),
Ty::SupportedProtocol => XhciSupportedProtocol::new(base, m).into(),
Ty::ExtendedPowerManagement => {
single::ReadWrite::<HciExtendedPowerManagement, M>::new(base, m).into()
}
Ty::MessageInterrupt => XhciMessageInterrupt::new(base, m).into(),
Ty::LocalMemory => XhciLocalMemory::new(base, m)?.into(),
Ty::UsbDebugCapability => Debug::new(base, &m).into(),
Ty::ExtendedMessageInterrupt => {
single::ReadWrite::<XhciExtendedMessageInterrupt, M>::new(base, m).into()
}
};
Some(v)
}
}
#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Default, Debug)]
pub struct NotSupportedId(pub u8);
#[repr(transparent)]
#[derive(Copy, Clone)]
struct Header(u32);
impl Header {
fn id(self) -> u8 {
self.0.get_bits(0..=7).try_into().unwrap()
}
fn next(self) -> u8 {
self.0.get_bits(8..=15).try_into().unwrap()
}
}
#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, FromPrimitive)]
enum Ty {
UsbLegacySupport = 1,
SupportedProtocol = 2,
ExtendedPowerManagement = 3,
MessageInterrupt = 5,
LocalMemory = 6,
UsbDebugCapability = 10,
ExtendedMessageInterrupt = 17,
}