use super::capability::{Capability, CapabilityRegistersLength};
use accessor::Mapper;
use bit_field::BitField;
use core::convert::TryInto;
use num_derive::FromPrimitive;
use num_traits::FromPrimitive;
#[derive(Debug)]
pub struct Operational<M>
where
M: Mapper + Clone,
{
pub usbcmd: accessor::Single<UsbCommandRegister, M>,
pub usbsts: accessor::Single<UsbStatusRegister, M>,
pub pagesize: accessor::Single<PageSizeRegister, M>,
pub dnctrl: accessor::Single<DeviceNotificationControl, M>,
pub crcr: accessor::Single<CommandRingControlRegister, M>,
pub dcbaap: accessor::Single<DeviceContextBaseAddressArrayPointerRegister, M>,
pub config: accessor::Single<ConfigureRegister, M>,
}
impl<M> Operational<M>
where
M: Mapper + Clone,
{
pub unsafe fn new(mmio_base: usize, caplength: CapabilityRegistersLength, mapper: &M) -> Self
where
M: Mapper,
{
let base = mmio_base + usize::from(caplength.get());
macro_rules! m {
($offset:expr) => {
accessor::Single::new(base + $offset, mapper.clone())
};
}
Self {
usbcmd: m!(0x00),
usbsts: m!(0x04),
pagesize: m!(0x08),
dnctrl: m!(0x14),
crcr: m!(0x18),
dcbaap: m!(0x30),
config: m!(0x38),
}
}
}
#[repr(transparent)]
#[derive(Copy, Clone)]
pub struct UsbCommandRegister(u32);
impl UsbCommandRegister {
#[must_use]
pub fn run_stop(self) -> bool {
self.0.get_bit(0)
}
pub fn set_run_stop(&mut self, b: bool) {
self.0.set_bit(0, b);
}
#[must_use]
pub fn host_controller_reset(self) -> bool {
self.0.get_bit(1)
}
pub fn set_host_controller_reset(&mut self, b: bool) {
self.0.set_bit(1, b);
}
#[must_use]
pub fn interrupter_enable(self) -> bool {
self.0.get_bit(2)
}
pub fn set_interrupter_enable(&mut self, b: bool) {
self.0.set_bit(2, b);
}
#[must_use]
pub fn host_system_error_enable(self) -> bool {
self.0.get_bit(3)
}
pub fn set_host_system_error_enable(&mut self, b: bool) {
self.0.set_bit(3, b);
}
#[must_use]
pub fn light_host_controller_reset(self) -> bool {
self.0.get_bit(7)
}
pub fn set_light_host_controller_reset(&mut self, b: bool) {
self.0.set_bit(7, b);
}
#[must_use]
pub fn controller_save_state(self) -> bool {
self.0.get_bit(8)
}
pub fn set_controller_save_state(&mut self, b: bool) {
self.0.set_bit(8, b);
}
#[must_use]
pub fn controller_restore_state(self) -> bool {
self.0.get_bit(9)
}
pub fn set_controller_restore_state(&mut self, b: bool) {
self.0.set_bit(9, b);
}
#[must_use]
pub fn enable_wrap_event(self) -> bool {
self.0.get_bit(10)
}
pub fn set_enable_wrap_event(&mut self, b: bool) {
self.0.set_bit(10, b);
}
#[must_use]
pub fn enable_u3_mfindex_stop(self) -> bool {
self.0.get_bit(11)
}
pub fn set_enable_u3_mfindex_stop(&mut self, b: bool) {
self.0.set_bit(11, b);
}
#[must_use]
pub fn cem_enable(self) -> bool {
self.0.get_bit(13)
}
pub fn set_cem_enable(&mut self, b: bool) {
self.0.set_bit(13, b);
}
#[must_use]
pub fn extended_tbc_enable(self) -> bool {
self.0.get_bit(14)
}
pub fn set_extended_tbc_enable(&mut self, b: bool) {
self.0.set_bit(14, b);
}
#[must_use]
pub fn extended_tbc_status_enable(self) -> bool {
self.0.get_bit(15)
}
pub fn set_extended_tbc_status_enable(&mut self, b: bool) {
self.0.set_bit(15, b);
}
#[must_use]
pub fn vtio_enable(self) -> bool {
self.0.get_bit(16)
}
pub fn set_vtio_enable(&mut self, b: bool) {
self.0.set_bit(16, b);
}
}
impl_debug_from_methods! {
UsbCommandRegister{
run_stop,
host_controller_reset,
interrupter_enable,
host_system_error_enable,
light_host_controller_reset,
controller_save_state,
controller_restore_state,
enable_wrap_event,
enable_u3_mfindex_stop,
cem_enable,
extended_tbc_enable,
extended_tbc_status_enable,
vtio_enable,
}
}
#[repr(transparent)]
#[derive(Copy, Clone)]
pub struct UsbStatusRegister(u32);
impl UsbStatusRegister {
#[allow(clippy::doc_markdown)]
#[must_use]
pub fn hc_halted(self) -> bool {
self.0.get_bit(0)
}
#[must_use]
pub fn host_system_error(self) -> bool {
self.0.get_bit(2)
}
pub fn clear_host_system_error(&mut self) {
self.0.set_bit(2, true);
}
#[must_use]
pub fn event_interrupt(self) -> bool {
self.0.get_bit(3)
}
pub fn clear_event_interrupt(&mut self) {
self.0.set_bit(3, true);
}
#[must_use]
pub fn port_change_detect(self) -> bool {
self.0.get_bit(4)
}
pub fn clear_port_change_detect(&mut self) {
self.0.set_bit(4, true);
}
#[must_use]
pub fn save_state_status(self) -> bool {
self.0.get_bit(8)
}
#[must_use]
pub fn restore_state_status(self) -> bool {
self.0.get_bit(9)
}
#[must_use]
pub fn save_restore_error(self) -> bool {
self.0.get_bit(10)
}
pub fn clear_save_restore_error(&mut self) {
self.0.set_bit(10, true);
}
#[must_use]
pub fn controller_not_ready(self) -> bool {
self.0.get_bit(11)
}
#[must_use]
pub fn host_controller_error(self) -> bool {
self.0.get_bit(12)
}
}
impl_debug_from_methods! {
UsbStatusRegister{
hc_halted,
host_system_error,
event_interrupt,
port_change_detect,
save_state_status,
restore_state_status,
save_restore_error,
controller_not_ready,
host_controller_error,
}
}
#[repr(transparent)]
#[derive(Copy, Clone, Debug)]
pub struct PageSizeRegister(u32);
impl PageSizeRegister {
#[must_use]
pub fn get(self) -> u16 {
self.0.try_into().unwrap()
}
}
#[repr(transparent)]
#[derive(Copy, Clone, Debug)]
pub struct DeviceNotificationControl(u32);
impl DeviceNotificationControl {
#[must_use]
pub fn get(self, i: usize) -> bool {
Self::ensure_index_is_within_range(i);
self.0.get_bit(i)
}
pub fn set(&mut self, i: usize, ne: bool) -> &mut Self {
Self::ensure_index_is_within_range(i);
self.0.set_bit(i, ne);
self
}
fn ensure_index_is_within_range(i: usize) {
assert!(
i < 16,
"The index of the Notification Enable field must be less than 16."
);
}
}
#[repr(transparent)]
#[derive(Copy, Clone)]
pub struct CommandRingControlRegister(u64);
impl CommandRingControlRegister {
pub fn set_ring_cycle_state(&mut self, s: bool) {
self.0.set_bit(0, s);
}
pub fn set_command_stop(&mut self) {
self.0.set_bit(1, true);
}
pub fn set_command_abort(&mut self) {
self.0.set_bit(2, true);
}
#[must_use]
pub fn command_ring_running(self) -> bool {
self.0.get_bit(3)
}
pub fn set_command_ring_pointer(&mut self, p: u64) {
assert!(p.trailing_zeros() >= 6);
let p = p >> 6;
self.0.set_bits(6..=63, p);
}
}
impl_debug_from_methods! {
CommandRingControlRegister{
command_ring_running
}
}
#[repr(transparent)]
#[derive(Copy, Clone, Debug)]
pub struct DeviceContextBaseAddressArrayPointerRegister(u64);
impl DeviceContextBaseAddressArrayPointerRegister {
#[must_use]
pub fn get(self) -> u64 {
self.0
}
pub fn set(&mut self, p: u64) {
assert!(p.trailing_zeros() >= 6);
self.0 = p;
}
}
#[repr(transparent)]
#[derive(Copy, Clone)]
pub struct ConfigureRegister(u32);
impl ConfigureRegister {
#[must_use]
pub fn max_device_slots_enabled(self) -> u8 {
self.0.get_bits(0..=7).try_into().unwrap()
}
pub fn set_max_device_slots_enabled(&mut self, s: u8) {
self.0.set_bits(0..=7, s.into());
}
#[must_use]
pub fn u3_entry_enable(self) -> bool {
self.0.get_bit(8)
}
pub fn set_u3_entry_enable(&mut self, b: bool) {
self.0.set_bit(8, b);
}
#[must_use]
pub fn configuration_information_enable(self) -> bool {
self.0.get_bit(9)
}
pub fn set_configuration_information_enable(&mut self, b: bool) {
self.0.set_bit(9, b);
}
}
impl_debug_from_methods! {
ConfigureRegister {
max_device_slots_enabled,
u3_entry_enable,
configuration_information_enable,
}
}
#[repr(C)]
#[derive(Copy, Clone, Debug)]
pub struct PortRegisterSet {
pub portsc: PortStatusAndControlRegister,
pub portpmsc: PortPowerManagementStatusAndControlRegister,
pub portli: PortLinkInfoRegister,
pub porthlpmc: PortHardwareLpmControlRegister,
}
impl PortRegisterSet {
pub unsafe fn new<M1, M2>(
mmio_base: usize,
capability: &Capability<M2>,
mapper: M1,
) -> accessor::Array<Self, M1>
where
M1: Mapper,
M2: Mapper + Clone,
{
let base = mmio_base + usize::from(capability.caplength.read().get()) + 0x400;
accessor::Array::new(
base,
capability.hcsparams1.read().number_of_ports().into(),
mapper,
)
}
}
#[repr(transparent)]
#[derive(Copy, Clone)]
pub struct PortStatusAndControlRegister(u32);
impl PortStatusAndControlRegister {
#[must_use]
pub fn current_connect_status(self) -> bool {
self.0.get_bit(0)
}
#[must_use]
pub fn port_enabled_disabled(self) -> bool {
self.0.get_bit(1)
}
pub fn disable_port(&mut self) {
self.0.set_bit(1, true);
}
#[must_use]
pub fn over_current_active(self) -> bool {
self.0.get_bit(3)
}
#[must_use]
pub fn port_reset(self) -> bool {
self.0.get_bit(4)
}
pub fn set_port_reset(&mut self, b: bool) {
self.0.set_bit(4, b);
}
#[must_use]
pub fn port_link_state(self) -> u8 {
self.0.get_bits(5..=8).try_into().unwrap()
}
pub fn set_port_link_state(&mut self, state: u8) {
self.0.set_bits(5..=8, state.into());
}
#[must_use]
pub fn port_power(self) -> bool {
self.0.get_bit(9)
}
pub fn set_port_power(&mut self, b: bool) {
self.0.set_bit(9, b);
}
#[must_use]
pub fn port_speed(self) -> u8 {
self.0.get_bits(10..=13).try_into().unwrap()
}
#[must_use]
pub fn port_indicator_control(self) -> PortIndicator {
let i = FromPrimitive::from_u32(self.0.get_bits(14..=15));
i.expect("The indicator must be less than 4.")
}
pub fn set_port_indicator_control(&mut self, i: PortIndicator) {
self.0.set_bits(14..=15, i as _);
}
#[must_use]
pub fn port_link_state_write_strobe(self) -> bool {
self.0.get_bit(16)
}
pub fn set_port_link_state_write_strobe(&mut self, b: bool) {
self.0.set_bit(16, b);
}
#[must_use]
pub fn connect_status_change(self) -> bool {
self.0.get_bit(17)
}
pub fn clear_connect_status_change(&mut self) {
self.0.set_bit(17, true);
}
#[must_use]
pub fn port_enabled_disabled_change(self) -> bool {
self.0.get_bit(18)
}
pub fn clear_port_enabled_disabled_change(&mut self) {
self.0.set_bit(18, true);
}
#[must_use]
pub fn warm_port_reset_change(self) -> bool {
self.0.get_bit(19)
}
pub fn clear_warm_port_reset_change(&mut self) {
self.0.set_bit(19, true);
}
#[must_use]
pub fn over_current_change(self) -> bool {
self.0.get_bit(20)
}
pub fn clear_over_current_change(&mut self) {
self.0.set_bit(20, true);
}
#[must_use]
pub fn port_reset_changed(self) -> bool {
self.0.get_bit(21)
}
pub fn clear_reset_changed(&mut self) {
self.0.set_bit(21, true);
}
#[must_use]
pub fn port_link_state_change(self) -> bool {
self.0.get_bit(22)
}
pub fn clear_link_state_change(&mut self) {
self.0.set_bit(22, true);
}
#[must_use]
pub fn port_config_error_change(self) -> bool {
self.0.get_bit(23)
}
pub fn clear_port_config_error_change(&mut self) {
self.0.set_bit(23, true);
}
#[must_use]
pub fn cold_attach_status(self) -> bool {
self.0.get_bit(24)
}
#[must_use]
pub fn wake_on_connect_enable(self) -> bool {
self.0.get_bit(25)
}
pub fn set_wake_on_connect_enable(&mut self, b: bool) {
self.0.set_bit(25, b);
}
#[must_use]
pub fn wake_on_disconnect_enable(self) -> bool {
self.0.get_bit(26)
}
pub fn set_wake_on_disconnect_enable(&mut self, b: bool) {
self.0.set_bit(26, b);
}
#[must_use]
pub fn wake_on_over_current_enable(self) -> bool {
self.0.get_bit(27)
}
pub fn set_wake_on_over_current_enable(&mut self, b: bool) {
self.0.set_bit(27, b);
}
#[must_use]
pub fn device_removable(self) -> bool {
self.0.get_bit(30)
}
pub fn set_warm_port_rest(&mut self) {
self.0.set_bit(30, true);
}
}
impl_debug_from_methods! {
PortStatusAndControlRegister{
current_connect_status,
port_enabled_disabled,
over_current_active,
port_reset,
port_link_state,
port_power,
port_speed,
port_indicator_control,
port_link_state_write_strobe,
connect_status_change,
port_enabled_disabled_change,
warm_port_reset_change,
over_current_change,
port_reset_changed,
port_link_state_change,
port_config_error_change,
cold_attach_status,
wake_on_connect_enable,
wake_on_disconnect_enable,
wake_on_over_current_enable,
device_removable,
}
}
#[repr(transparent)]
#[derive(Copy, Clone)]
pub struct PortPowerManagementStatusAndControlRegister(u32);
impl PortPowerManagementStatusAndControlRegister {
#[must_use]
pub fn u1_timeout(self) -> u8 {
self.0.get_bits(0..=7).try_into().unwrap()
}
pub fn set_u1_timeout(&mut self, timeout: u8) {
self.0.set_bits(0..=7, timeout.into());
}
#[must_use]
pub fn u2_timeout(self) -> u8 {
self.0.get_bits(8..=15).try_into().unwrap()
}
pub fn set_u2_timeout(&mut self, timeout: u8) {
self.0.set_bits(8..=15, timeout.into());
}
#[must_use]
pub fn force_link_pm_accept(self) -> bool {
self.0.get_bit(16)
}
pub fn set_force_link_pm_accept(&mut self, b: bool) {
self.0.set_bit(16, b);
}
#[must_use]
pub fn l1_status(self) -> Option<L1Status> {
let s = self.0.get_bits(0..=2);
FromPrimitive::from_u32(s)
}
#[must_use]
pub fn remote_wake_enable(self) -> bool {
self.0.get_bit(3)
}
pub fn set_remote_wake_enable(&mut self, b: bool) {
self.0.set_bit(3, b);
}
#[must_use]
pub fn best_effort_service_latency(self) -> u8 {
self.0.get_bits(4..=7).try_into().unwrap()
}
pub fn set_best_effort_service_latency(&mut self, l: u8) {
self.0.set_bits(4..=7, l.into());
}
#[must_use]
pub fn l1_device_slot(self) -> u8 {
self.0.get_bits(8..=15).try_into().unwrap()
}
pub fn set_l1_device_slot(&mut self, slot: u8) {
self.0.set_bits(8..=15, slot.into());
}
#[must_use]
pub fn hardware_lpm_enable(self) -> bool {
self.0.get_bit(16)
}
pub fn set_hardware_lpm_enable(&mut self, b: bool) {
self.0.set_bit(16, b);
}
#[must_use]
pub fn port_test_control(self) -> Option<TestMode> {
let t = self.0.get_bits(28..=31);
FromPrimitive::from_u32(t)
}
pub fn set_port_test_control(&mut self, m: TestMode) {
self.0.set_bits(28..=31, m as _);
}
}
impl_debug_from_methods! {
PortPowerManagementStatusAndControlRegister{
u1_timeout,
u2_timeout,
force_link_pm_accept,
l1_status,
remote_wake_enable,
best_effort_service_latency,
l1_device_slot,
hardware_lpm_enable,
port_test_control,
}
}
#[repr(transparent)]
#[derive(Copy, Clone)]
pub struct PortLinkInfoRegister(u32);
impl PortLinkInfoRegister {
#[must_use]
pub fn link_error_count(self) -> u16 {
self.0.get_bits(0..=15).try_into().unwrap()
}
pub fn set_link_error_count(&mut self, c: u16) {
self.0.set_bits(0..=15, c.into());
}
#[must_use]
pub fn rx_lane_count(self) -> u8 {
self.0.get_bits(16..=19).try_into().unwrap()
}
#[must_use]
pub fn tx_lane_count(self) -> u8 {
self.0.get_bits(20..=23).try_into().unwrap()
}
}
impl_debug_from_methods! {
PortLinkInfoRegister{
link_error_count,
rx_lane_count,
tx_lane_count,
}
}
#[repr(transparent)]
#[derive(Copy, Clone)]
pub struct PortHardwareLpmControlRegister(u32);
impl PortHardwareLpmControlRegister {
#[must_use]
pub fn host_initiated_resume_duration_mode(self) -> u8 {
self.0.get_bits(0..=1).try_into().unwrap()
}
pub fn set_host_initiated_resume_duration_mode(&mut self, mode: u8) {
self.0.set_bits(0..=1, mode.into());
}
#[must_use]
pub fn l1_timeout(self) -> u8 {
self.0.get_bits(2..=9).try_into().unwrap()
}
pub fn set_l1_timeout(&mut self, timeout: u8) {
self.0.set_bits(2..=9, timeout.into());
}
#[must_use]
pub fn best_effort_service_latency_deep(self) -> u8 {
self.0.get_bits(10..=13).try_into().unwrap()
}
pub fn set_best_effort_service_latency_deep(&mut self, latency: u8) {
self.0.set_bits(10..=13, latency.into());
}
}
impl_debug_from_methods! {
PortHardwareLpmControlRegister {
host_initiated_resume_duration_mode,
l1_timeout,
best_effort_service_latency_deep,
}
}
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, FromPrimitive)]
pub enum PortIndicator {
Off = 0,
Amber = 1,
Green = 2,
Undefined = 3,
}
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, FromPrimitive)]
pub enum L1Status {
Invalid = 0,
Success = 1,
NotYet = 2,
NotSupported = 3,
TimeOutOrError = 4,
}
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, FromPrimitive)]
pub enum TestMode {
NotEnabled = 0,
JState = 1,
KState = 2,
Se0Nak = 3,
Pakcet = 4,
ForceEnable = 5,
PortTestControlError = 15,
}