use super::ExtendedCapability;
use accessor::{array, single, Mapper};
use bit_field::BitField;
use core::convert::TryInto;
use num_derive::FromPrimitive;
use num_traits::FromPrimitive;
#[derive(Debug)]
pub struct XhciSupportedProtocol<M>
where
M: Mapper + Clone,
{
pub header: single::ReadWrite<Header, M>,
pub psis: Option<array::ReadWrite<ProtocolSpeedId, M>>,
}
impl<M> XhciSupportedProtocol<M>
where
M: Mapper + Clone,
{
pub unsafe fn new(base: usize, mapper: M) -> Self {
let header: single::ReadWrite<Header, M> = single::ReadWrite::new(base, mapper.clone());
let len = header.read_volatile().protocol_speed_id_count();
let psis = if len > 0 {
Some(array::ReadWrite::new(base + 0x10, len.into(), mapper))
} else {
None
};
Self { header, psis }
}
}
impl<M> From<XhciSupportedProtocol<M>> for ExtendedCapability<M>
where
M: Mapper + Clone,
{
fn from(x: XhciSupportedProtocol<M>) -> Self {
ExtendedCapability::XhciSupportedProtocol(x)
}
}
#[repr(transparent)]
#[derive(Copy, Clone)]
pub struct Header([u32; 4]);
impl Header {
#[must_use]
pub fn minor_revision(self) -> u8 {
self.0[0].get_bits(16..=23).try_into().unwrap()
}
#[must_use]
pub fn major_revision(self) -> u8 {
self.0[0].get_bits(24..=31).try_into().unwrap()
}
#[must_use]
pub fn name_string(&self) -> u32 {
self.0[1]
}
#[must_use]
pub fn compatible_port_offset(self) -> u8 {
self.0[2].get_bits(0..=7).try_into().unwrap()
}
#[must_use]
pub fn compatible_port_count(self) -> u8 {
self.0[2].get_bits(8..=15).try_into().unwrap()
}
#[must_use]
pub fn link_soft_error_count_capability(self) -> bool {
self.0[2].get_bit(24)
}
#[must_use]
pub fn high_speed_only(self) -> bool {
self.0[2].get_bit(17)
}
#[must_use]
pub fn integrated_hub_implemented(self) -> bool {
self.0[2].get_bit(18)
}
#[must_use]
pub fn hardware_lpm_capability(self) -> bool {
self.0[2].get_bit(19)
}
#[must_use]
pub fn besl_lpm_capability(self) -> bool {
self.0[2].get_bit(20)
}
#[must_use]
pub fn hub_depth(self) -> u8 {
self.0[2].get_bits(25..=27).try_into().unwrap()
}
#[must_use]
pub fn protocol_speed_id_count(self) -> u8 {
self.0[2].get_bits(28..=31).try_into().unwrap()
}
#[must_use]
pub fn protocol_slot_type(self) -> u8 {
self.0[3].get_bits(0..=4).try_into().unwrap()
}
}
impl_debug_from_methods! {
Header {
minor_revision,
major_revision,
name_string,
compatible_port_offset,
compatible_port_count,
link_soft_error_count_capability,
high_speed_only,
integrated_hub_implemented,
hardware_lpm_capability,
besl_lpm_capability,
hub_depth,
protocol_speed_id_count,
protocol_slot_type,
}
}
#[repr(transparent)]
#[derive(Copy, Clone)]
pub struct ProtocolSpeedId(u32);
impl ProtocolSpeedId {
#[must_use]
pub fn protocol_speed_id_value(self) -> u8 {
self.0.get_bits(0..=3).try_into().unwrap()
}
#[must_use]
pub fn protocol_speed_id_exponent(self) -> BitRate {
let r = FromPrimitive::from_u32(self.0.get_bits(4..=5));
r.expect("The value must be less than 4.")
}
#[must_use]
pub fn psi_type(self) -> PsiType {
let r = FromPrimitive::from_u32(self.0.get_bits(6..=7));
r.expect("The PSI Type must not take the reserved value.")
}
#[must_use]
pub fn psi_full_duplex(self) -> bool {
self.0.get_bit(8)
}
#[must_use]
pub fn link_protocol(self) -> LinkProtocol {
let r = FromPrimitive::from_u32(self.0.get_bits(14..=15));
r.expect("The Link Protocol field must not take the reserved value.")
}
#[must_use]
pub fn protocol_speed_id_mantissa(self) -> u16 {
self.0.get_bits(16..=31).try_into().unwrap()
}
}
impl_debug_from_methods! {
ProtocolSpeedId {
protocol_speed_id_value,
protocol_speed_id_exponent,
psi_type,
psi_full_duplex,
link_protocol,
protocol_speed_id_mantissa,
}
}
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, FromPrimitive)]
pub enum BitRate {
Bits = 0,
Kb = 1,
Mb = 2,
Gb = 3,
}
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, FromPrimitive)]
pub enum PsiType {
Symmetric = 0,
AsymmetricRx = 2,
AsymmetricTx = 3,
}
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, FromPrimitive)]
pub enum LinkProtocol {
SuperSpeed = 0,
SuperSpeedPlus = 1,
}