diff --git a/src/extended_capabilities/debug.rs b/src/extended_capabilities/debug.rs index 8d8f030e..80189519 100644 --- a/src/extended_capabilities/debug.rs +++ b/src/extended_capabilities/debug.rs @@ -85,11 +85,13 @@ where #[derive(Copy, Clone)] pub struct Id(u32); impl Id { - /// Returns the value of the Debug Capability Event Ring Segment Table Max field. - #[must_use] - pub fn debug_capability_event_ring_segment_table_max(self) -> u8 { - self.0.get_bits(16..=20).try_into().unwrap() - } + ro_field!( + pub, self, + self.0; 16..=20, + debug_capability_event_ring_segment_table_max, + "Debug Capability Event Ring Segment Table Max", + u8 + ); } impl_debug_from_methods! { Id { @@ -102,10 +104,12 @@ impl_debug_from_methods! { #[derive(Copy, Clone, Debug)] pub struct Doorbell(u32); impl Doorbell { - /// Sets the value of the Doorbell Target field. - pub fn set_doorbell_target(&mut self, target: u8) { - self.0.set_bits(8..=15, target.into()); - } + rw_field!( + pub, self, + self.0; 8..=15, + "Doorbell Target", + u8 + ); } /// Debug Capability Event Ring Segment Table Size Register. @@ -113,16 +117,7 @@ impl Doorbell { #[derive(Copy, Clone)] pub struct EventRingSegmentTableSize(u32); impl EventRingSegmentTableSize { - /// Returns the value of the Event Ring Segment Table Size field. - #[must_use] - pub fn get(self) -> u16 { - self.0.get_bits(0..=15).try_into().unwrap() - } - - /// Sets the value of the Event Ring Segment Table Size field. - pub fn set(&mut self, sz: u16) { - self.0.set_bits(0..=15, sz.into()); - } + rw_field!(pub, self, self.0; 0..=15, "Event Ring Segment Table Size", u16); } impl_debug_from_methods! { EventRingSegmentTableSize { @@ -135,25 +130,12 @@ impl_debug_from_methods! { #[derive(Copy, Clone)] pub struct EventRingSegmentTableBaseAddress(u64); impl EventRingSegmentTableBaseAddress { - /// Returns the value of the Event Ring Segment Table Base Address field. - #[must_use] - pub fn get(self) -> u64 { - self.0 - } - - /// Sets the value of the Event Ring Segment Table Base Address field. - /// - /// # Panics - /// - /// This method panics if the address is not 16-byte aligned. - pub fn set(&mut self, a: u64) { - assert!( - a.trailing_zeros() >= 4, - "The base address of the Event Ring Segment Table must be 16-byte aligned." - ); - - self.0 = a; - } + rw_zero_trailing!( + pub, self, + self.0; 4~; "64-byte aligned", + "Event Ring Segment Table Base Address", + u64 + ); } impl_debug_from_methods! { EventRingSegmentTableBaseAddress { @@ -166,36 +148,20 @@ impl_debug_from_methods! { #[derive(Copy, Clone)] pub struct EventRingDequeuePointer(u64); impl EventRingDequeuePointer { - /// Returns the value of the Dequeue ERST Segment Index field. - #[must_use] - pub fn dequeue_erst_segment_index(self) -> u8 { - self.0.get_bits(0..=2).try_into().unwrap() - } - - /// Sets the value of the Dequeue ERST Segment Index field. - pub fn set_dequeue_erst_segment_index(&mut self, i: u8) { - self.0.set_bits(0..=2, i.into()); - } - - /// Returns the value of the Dequeue Pointer field. - #[must_use] - pub fn dequeue_pointer(self) -> u64 { - self.0 & !0b1111 - } - - /// Sets the value of the Dequeue Pointer field. - /// - /// # Panics - /// - /// This method panics if the address is not 16-byte aligned. - pub fn set_dequeue_pointer(&mut self, a: u64) { - assert!( - a.trailing_zeros() >= 4, - "The Event Ring Dequeue Pointer must be 16-byte aligned." - ); - - self.0.set_bits(4..=63, a.get_bits(4..=63)); - } + rw_field!( + pub, self, + self.0; 0..=2, + dequeue_erst_segment_index, + "Dequeue ERST Segment Index", + u8 + ); + rw_zero_trailing!( + pub, self, + self.0; 4~; "16-byte aligned", + dequeue_pointer, + "Event Ring Dequeue Pointer", + u64 + ); } impl_debug_from_methods! { EventRingDequeuePointer { @@ -209,11 +175,11 @@ impl_debug_from_methods! { #[derive(Copy, Clone)] pub struct Control(u32); impl Control { - ro_bit!(0, dbc_run, "DbC Run"); - rw_bit!(1, link_status_event_enable, "Link Status Event Enable"); - rw1s_bit!(2, halt_out_tr, "Halt OUT TR"); - rw1s_bit!(3, halt_in_tr, "Halt IN TR"); - rw1c_bit!(4, dbc_run_change, "DbC Run Change"); + ro_bit!(pub, self, self.0; 0, dbc_run, "DbC Run"); + rw_bit!(pub, self, self.0; 1, link_status_event_enable, "Link Status Event Enable"); + rw1s_bit!(pub, self, self.0; 2, halt_out_tr, "Halt OUT TR"); + rw1s_bit!(pub, self, self.0; 3, halt_in_tr, "Halt IN TR"); + rw1c_bit!(pub, self, self.0; 4, dbc_run_change, "DbC Run Change"); /// Returns the value of the Debug Max Burst Size field. #[must_use] @@ -227,7 +193,7 @@ impl Control { self.0.get_bits(24..=30).try_into().unwrap() } - rw_bit!(31, debug_capability_enable, "Debug Capability Enable"); + rw_bit!(pub, self, self.0; 31, debug_capability_enable, "Debug Capability Enable"); } impl_debug_from_methods! { Control { @@ -247,8 +213,8 @@ impl_debug_from_methods! { #[derive(Copy, Clone)] pub struct Status(u32); impl Status { - ro_bit!(0, event_ring_not_empty, "Event Ring Not Empty"); - ro_bit!(1, dbc_system_bus_reset, "DbC System Bus Reset"); + ro_bit!(pub, self, self.0; 0, event_ring_not_empty, "Event Ring Not Empty"); + ro_bit!(pub, self, self.0; 1, dbc_system_bus_reset, "DbC System Bus Reset"); /// Returns the value of the Debug Port Number field. #[must_use] @@ -269,9 +235,9 @@ impl_debug_from_methods! { #[derive(Copy, Clone)] pub struct PortStatusAndControl(u32); impl PortStatusAndControl { - ro_bit!(0, current_connect_status, "Current Connect Status"); - rw_bit!(1, port_enabled_disabled, "Port Enabled/Disabled"); - ro_bit!(4, port_reset, "Port Reset"); + ro_bit!(pub, self, self.0; 0, current_connect_status, "Current Connect Status"); + rw_bit!(pub, self, self.0; 1, port_enabled_disabled, "Port Enabled/Disabled"); + ro_bit!(pub, self, self.0; 4, port_reset, "Port Reset"); /// Returns the value of the Port Link State field. #[must_use] @@ -285,10 +251,10 @@ impl PortStatusAndControl { self.0.get_bits(10..=13).try_into().unwrap() } - rw1c_bit!(17, connect_status_change, "Connect Status Change"); - rw1c_bit!(21, port_reset_change, "Port Reset Change"); - rw1c_bit!(22, port_link_status_change, "Port Link Status Change"); - rw1c_bit!(23, port_config_error_change, "Port Config Error Change"); + rw1c_bit!(pub, self, self.0; 17, connect_status_change, "Connect Status Change"); + rw1c_bit!(pub, self, self.0; 21, port_reset_change, "Port Reset Change"); + rw1c_bit!(pub, self, self.0; 22, port_link_status_change, "Port Link Status Change"); + rw1c_bit!(pub, self, self.0; 23, port_config_error_change, "Port Config Error Change"); } impl_debug_from_methods! { PortStatusAndControl { @@ -309,22 +275,12 @@ impl_debug_from_methods! { #[derive(Copy, Clone, Debug)] pub struct ContextPointer(u64); impl ContextPointer { - /// Returns the start address of the Debug Capability Context data structure. - #[must_use] - pub fn get(self) -> u64 { - self.0 - } - - /// Sets the start address of the Debug Capability Context data structure. - /// - /// # Panics - /// - /// This method panics if the address is not 16-byte aligned. - pub fn set(&mut self, a: u64) { - assert!(a.trailing_zeros()>=4,"The start address of the Debug Capability Context data structure must be 16-byte aligned."); - - self.0 = a; - } + rw_zero_trailing!( + pub, self, + self.0; 4~; "16-byte aligned", + "Debug Capability Context Base Pointer", + u64 + ); } /// Debug Capability Device Descriptor Info Register 1 @@ -332,27 +288,8 @@ impl ContextPointer { #[derive(Copy, Clone)] pub struct DeviceDescriptorInfo1(u32); impl DeviceDescriptorInfo1 { - /// Returns the value of the DbC Protocol field. - #[must_use] - pub fn dbc_protocol(self) -> u8 { - self.0.get_bits(0..=7).try_into().unwrap() - } - - /// Sets the value of the DbC Protocol field. - pub fn set_dbc_protocol(&mut self, protocol: u8) { - self.0.set_bits(0..=7, protocol.into()); - } - - /// Returns the value of the Vendor ID field. - #[must_use] - pub fn vendor_id(self) -> u16 { - self.0.get_bits(16..=31).try_into().unwrap() - } - - /// Sets the value of the Vendor ID field. - pub fn set_vendor_id(&mut self, id: u16) { - self.0.set_bits(16..=31, id.into()); - } + rw_field!(pub, self, self.0; 0..=7, dbc_protocol, "DbC Protocol", u8); + rw_field!(pub, self, self.0; 16..=31, vendor_id, "Vendor ID", u16); } impl_debug_from_methods! { DeviceDescriptorInfo1 { @@ -366,27 +303,8 @@ impl_debug_from_methods! { #[derive(Copy, Clone)] pub struct DeviceDescriptorInfo2(u32); impl DeviceDescriptorInfo2 { - /// Returns the value of the Product ID field. - #[must_use] - pub fn product_id(self) -> u16 { - self.0.get_bits(0..=15).try_into().unwrap() - } - - /// Sets the value of the Product ID field. - pub fn set_product_id(&mut self, id: u16) { - self.0.set_bits(0..=15, id.into()); - } - - /// Returns the value of the Device Revision field. - #[must_use] - pub fn device_revision(self) -> u16 { - self.0.get_bits(16..=31).try_into().unwrap() - } - - /// Sets the value of the Device Revision field. - pub fn set_device_revision(&mut self, revision: u16) { - self.0.set_bits(16..=31, revision.into()); - } + rw_field!(pub, self, self.0; 0..=15, product_id, "Product ID", u16); + rw_field!(pub, self, self.0; 16..=31, device_revision, "Device Revision", u16); } impl_debug_from_methods! { DeviceDescriptorInfo2 { diff --git a/src/extended_capabilities/hci_extended_power_management.rs b/src/extended_capabilities/hci_extended_power_management.rs index b3e9d705..86e53248 100644 --- a/src/extended_capabilities/hci_extended_power_management.rs +++ b/src/extended_capabilities/hci_extended_power_management.rs @@ -32,13 +32,13 @@ where #[derive(Copy, Clone)] pub struct PowerManagementCapabilities(u16); impl PowerManagementCapabilities { - ro_field!(11..=15, pme_support, "PME_Support", u8); - ro_bit!(10, d2_support, "D2_Support"); - ro_bit!(9, d1_support, "D1_Support"); - ro_field!(6..=8, aux_current, "Aux_Current", u8); - ro_bit!(5, dsi, "DSI"); - ro_bit!(3, pme_clock, "PME Clock"); - ro_field!(0..=2, version, "Version", u8); + ro_field!(pub, self, self.0; 11..=15, pme_support, "PME_Support", u8); + ro_bit!(pub, self, self.0; 10, d2_support, "D2_Support"); + ro_bit!(pub, self, self.0; 9, d1_support, "D1_Support"); + ro_field!(pub, self, self.0; 6..=8, aux_current, "Aux_Current", u8); + ro_bit!(pub, self, self.0; 5, dsi, "DSI"); + ro_bit!(pub, self, self.0; 3, pme_clock, "PME Clock"); + ro_field!(pub, self, self.0; 0..=2, version, "Version", u8); } impl_debug_from_methods! { PowerManagementCapabilities { @@ -57,11 +57,11 @@ impl_debug_from_methods! { #[derive(Copy, Clone)] pub struct PowerManagementControlStatusRegister(u16); impl PowerManagementControlStatusRegister { - rw1c_bit!(15, pme_status, "PME_Status"); - ro_field!(13..=14, data_scale, "Data_Scale", u8); - rw_field!(9..=12, data_select, "Data_Select", u8); - rw_bit!(8, pme_en, "PME_En"); - rw_field!(0..=1, power_state, "PowerState", u8); + rw1c_bit!(pub, self, self.0; 15, pme_status, "PME_Status"); + ro_field!(pub, self, self.0; 13..=14, data_scale, "Data_Scale", u8); + rw_field!(pub, self, self.0; 9..=12, data_select, "Data_Select", u8); + rw_bit!(pub, self, self.0; 8, pme_en, "PME_En"); + rw_field!(pub, self, self.0; 0..=1, power_state, "PowerState", u8); } impl_debug_from_methods! { PowerManagementControlStatusRegister { @@ -78,8 +78,8 @@ impl_debug_from_methods! { #[derive(Copy, Clone)] pub struct PmesrBse(u8); impl PmesrBse { - ro_bit!(7, bpcc_en, "BPCC_En"); - ro_bit!(6, b2_b3, "B2_B3"); + ro_bit!(pub, self, self.0; 7, bpcc_en, "BPCC_En"); + ro_bit!(pub, self, self.0; 6, b2_b3, "B2_B3"); } impl_debug_from_methods! { PmesrBse { diff --git a/src/extended_capabilities/usb_legacy_support_capability.rs b/src/extended_capabilities/usb_legacy_support_capability.rs index a55db0bc..d496da62 100644 --- a/src/extended_capabilities/usb_legacy_support_capability.rs +++ b/src/extended_capabilities/usb_legacy_support_capability.rs @@ -53,8 +53,8 @@ where #[derive(Copy, Clone)] pub struct LegSup(u32); impl LegSup { - rw_bit!(16, hc_bios_owned_semaphore, "HC BIOS Owned Semaphore"); - rw_bit!(24, hc_os_owned_semaphore, "HC OS Owned Semaphore"); + rw_bit!(pub, self, self.0; 16, hc_bios_owned_semaphore, "HC BIOS Owned Semaphore"); + rw_bit!(pub, self, self.0; 24, hc_os_owned_semaphore, "HC OS Owned Semaphore"); } impl_debug_from_methods! { LegSup { @@ -68,20 +68,21 @@ impl_debug_from_methods! { #[derive(Copy, Clone)] pub struct UsbLegacySupportControlStatus(u32); impl UsbLegacySupportControlStatus { - rw_bit!(0, usb_smi_enable, "USB SMI Enable"); + rw_bit!(pub, self, self.0; 0, usb_smi_enable, "USB SMI Enable"); rw_bit!( - 4, + pub, self, + self.0; 4, smi_on_host_system_error_enable, "SMI on Host System Error Enable" ); - rw_bit!(13, smi_on_os_ownership_enable, "SMI on OS Ownership Enable"); - rw_bit!(14, smi_on_pci_command_enable, "SMI on PCI Command Enable"); - rw_bit!(15, smi_on_bar_enable, "SMI on BAR Enable"); - ro_bit!(16, smi_on_event_interrupt, "SMI on Event Interrupt"); - ro_bit!(20, smi_on_host_system_error, "SMI on Host System Error"); - rw1c_bit!(29, smi_on_os_ownership_change, "SMI on OS Ownership Change"); - rw1c_bit!(30, smi_on_pci_command, "SMI on PCI Command"); - rw1c_bit!(31, smi_on_bar, "SMI on BAR"); + rw_bit!(pub, self, self.0; 13, smi_on_os_ownership_enable, "SMI on OS Ownership Enable"); + rw_bit!(pub, self, self.0; 14, smi_on_pci_command_enable, "SMI on PCI Command Enable"); + rw_bit!(pub, self, self.0; 15, smi_on_bar_enable, "SMI on BAR Enable"); + ro_bit!(pub, self, self.0; 16, smi_on_event_interrupt, "SMI on Event Interrupt"); + ro_bit!(pub, self, self.0; 20, smi_on_host_system_error, "SMI on Host System Error"); + rw1c_bit!(pub, self, self.0; 29, smi_on_os_ownership_change, "SMI on OS Ownership Change"); + rw1c_bit!(pub, self, self.0; 30, smi_on_pci_command, "SMI on PCI Command"); + rw1c_bit!(pub, self, self.0; 31, smi_on_bar, "SMI on BAR"); } impl_debug_from_methods! { UsbLegacySupportControlStatus { diff --git a/src/extended_capabilities/xhci_extended_message_interrupt.rs b/src/extended_capabilities/xhci_extended_message_interrupt.rs index bb2af1cf..3bf689d4 100644 --- a/src/extended_capabilities/xhci_extended_message_interrupt.rs +++ b/src/extended_capabilities/xhci_extended_message_interrupt.rs @@ -33,7 +33,7 @@ where #[derive(Copy, Clone)] pub struct MessageControl(u16); impl MessageControl { - rw_bit!(15, msi_x_enable, "MSI-X Enable"); + rw_bit!(pub, self, self.0; 15, msi_x_enable, "MSI-X Enable"); /// Returns the value of the Table Size field. #[must_use] diff --git a/src/extended_capabilities/xhci_local_memory.rs b/src/extended_capabilities/xhci_local_memory.rs index bc2d296e..05ffba99 100644 --- a/src/extended_capabilities/xhci_local_memory.rs +++ b/src/extended_capabilities/xhci_local_memory.rs @@ -2,7 +2,6 @@ use super::ExtendedCapability; use accessor::{array, single, Mapper}; -use bit_field::BitField; use core::convert::TryInto; /// xHCI Local Memory Capability. @@ -61,21 +60,12 @@ where #[derive(Copy, Clone)] pub struct Header([u32; 2]); impl Header { - /// Returns the Local Memory Enable bit. - #[must_use] - pub fn local_memory_enable(self) -> bool { - self.0[0].get_bit(16) - } - - /// Sets the Local Memory Enable bit. - pub fn set_local_memory_enable(&mut self) { - self.0[0].set_bit(16, true); - } - - /// Clears the Local Memory Enable bit. - pub fn clear_local_memory_enable(&mut self) { - self.0[0].set_bit(16, false); - } + rw_bit!( + pub, self, + self.0[0]; 16, + local_memory_enable, + "Local Memory Enable" + ); fn size(self) -> u32 { self.0[1] diff --git a/src/extended_capabilities/xhci_message_interrupt.rs b/src/extended_capabilities/xhci_message_interrupt.rs index 1bbc91c9..6a199731 100644 --- a/src/extended_capabilities/xhci_message_interrupt.rs +++ b/src/extended_capabilities/xhci_message_interrupt.rs @@ -3,7 +3,7 @@ use super::ExtendedCapability; use accessor::single; use accessor::Mapper; -use bit_field::BitField; +// use bit_field::BitField; use core::convert::TryFrom; use core::convert::TryInto; @@ -113,27 +113,23 @@ impl MessageAddress for u64 {} #[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"); - - /// Returns the value of the Multiple Message Enable field. - #[must_use] - pub fn multiple_message_enable(self) -> u8 { - self.0.get_bits(4..=6).try_into().unwrap() - } - - /// Sets the value of the Multiple Message Enable field. - pub fn set_multiple_message_enable(&mut self, m: u8) { - self.0.set_bits(4..=6, m.into()); - } - - /// Returns the value of the Multiple Message Capable field. - #[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"); + rw_bit!(pub, self, self.0; 0, msi_enable, "MSI Enable"); + ro_field!( + pub, self, + self.0; 1..=3, + multiple_message_capable, + "Multiple Message Capable", + u8 + ); + rw_field!( + pub, self, + self.0; 4..=6, + multiple_message_enable, + "Multiple Message Enable", + u8 + ); + ro_bit!(pub, self, self.0; 7, bit64_address_capable, "64 bit address capable"); + ro_bit!(pub, self, self.0; 8, per_vector_masking_capable, "Per-vector masking capable"); } impl_debug_from_methods! { MessageControl { diff --git a/src/macros.rs b/src/macros.rs index c3dea317..b7495922 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -13,257 +13,317 @@ macro_rules! impl_debug_from_methods { } macro_rules! bit_getter { - ([$offset:literal]($bit:literal),$method:ident,$name:literal) => { + ($vis:vis,$self_:ident,$from:expr;$bit:literal,$method:ident,$name:literal) => { #[doc = "Returns the"] #[doc = $name] #[doc = "bit."] #[must_use] - pub fn $method(self) -> bool { + $vis fn $method(&$self_) -> bool { use bit_field::BitField; - self.0[$offset].get_bit($bit) - } - }; - ($bit:literal,$method:ident,$name:literal) => { - #[doc = "Returns the"] - #[doc = $name] - #[doc = "bit."] - #[must_use] - pub fn $method(self) -> bool { - use bit_field::BitField; - self.0.get_bit($bit) + $from.get_bit($bit) } }; } -macro_rules! bit_modifier { - ([$offset:literal]($bit:literal),$method:ident,$name:literal) => { +macro_rules! bit_raiser { + ($vis:vis,$self_:ident,$from:expr;$bit:literal,$method:ident,$name:literal) => { paste::paste! { #[doc = "Sets the"] #[doc = $name] #[doc = "bit."] - pub fn [](&mut self)->&mut Self{ + $vis fn [](&mut $self_)->&mut Self{ use bit_field::BitField; - self.0[$offset].set_bit($bit,true); - self + $from.set_bit($bit,true); + $self_ } + } + }; +} +macro_rules! bit_clearer { + ($vis:vis,$self_:ident,$from:expr;$bit:literal,$method:ident,$name:literal) => { + paste::paste! { #[doc = "Clears the"] #[doc = $name] #[doc = "bit."] - pub fn [](&mut self)->&mut Self{ + $vis fn [](&mut $self_)->&mut Self{ use bit_field::BitField; - self.0[$offset].set_bit($bit,false); - self + $from.set_bit($bit,false); + $self_ } } }; - ($bit:literal,$method:ident,$name:literal) => { +} + +macro_rules! bit_modifier_w1c { + ($vis:vis,$self_:ident,$from:expr;$bit:literal,$method:ident,$name:literal) => { paste::paste! { - #[doc = "Sets the"] + #[doc = "Assigns 1 to the"] #[doc = $name] - #[doc = "bit."] - pub fn [](&mut self)->&mut Self{ + #[doc = "bit. On register write, this results in clearing the bit."] + $vis fn [](&mut $self_)->&mut Self{ use bit_field::BitField; - self.0.set_bit($bit,true); - self + $from.set_bit($bit,true); + $self_ } - #[doc = "Clears the"] + #[doc = "Assigns 0 to the"] #[doc = $name] - #[doc = "bit."] - pub fn [](&mut self)->&mut Self{ + #[doc = "bit, preventing the bit from being cleared on write."] + $vis fn [](&mut $self_) -> &mut Self { use bit_field::BitField; - self.0.set_bit($bit,false); - self + $from.set_bit($bit,false); + $self_ } } }; } macro_rules! ro_bit { - ([$offset:literal]($bit:literal),$method:ident,$name:literal) => { - bit_getter!([$offset]($bit), $method, $name); - }; - ($bit:literal,$method:ident,$name:literal) => { - bit_getter!($bit, $method, $name); + ($vis:vis,$self_:ident,$from:expr;$bit:literal,$method:ident,$name:literal) => { + bit_getter!($vis, $self_, $from;$bit, $method, $name); }; } macro_rules! wo_bit { - ([$offset:literal]($bit:literal),$method:ident,$name:literal) => { - bit_modifier!([$offset]($bit), $method, $name); + ($vis:vis,$self_:ident,$from:expr;$bit:literal,$method:ident,$name:literal) => { + bit_raiser!($vis, $self_, $from;$bit, $method, $name); + bit_clearer!($vis, $self_, $from;$bit, $method, $name); }; - ($bit:literal,$method:ident,$name:literal) => { - bit_modifier!($bit, $method, $name); +} + +macro_rules! w1s_bit { + ($vis:vis,$self_:ident,$from:expr;$bit:literal,$method:ident,$name:literal) => { + bit_raiser!($vis, $self_, $from;$bit, $method, $name); }; } macro_rules! rw_bit { - ([$offset:literal]($bit:literal),$method:ident,$name:literal) => { - bit_getter!([$offset]($bit), $method, $name); - bit_modifier!([$offset]($bit), $method, $name); + ($vis:vis,$self_:ident,$from:expr;$bit:literal,$method:ident,$name:literal) => { + bit_getter!($vis, $self_, $from;$bit, $method, $name); + bit_raiser!($vis, $self_, $from;$bit, $method, $name); + bit_clearer!($vis, $self_, $from;$bit, $method, $name); }; - ($bit:literal,$method:ident,$name:literal) => { - bit_getter!($bit, $method, $name); - bit_modifier!($bit, $method, $name); +} + +macro_rules! rw1s_bit { + ($vis:vis,$self_:ident,$from:expr;$bit:literal,$method:ident,$name:literal) => { + bit_getter!($vis, $self_, $from;$bit, $method, $name); + bit_raiser!($vis, $self_, $from;$bit, $method, $name); }; } macro_rules! rw1c_bit { - ([$offset:literal]($bit:literal),$method:ident,$name:literal) => { - bit_getter!([$offset]($bit), $method, $name); - paste::paste! { - #[doc = "Assigns 1 to the"] - #[doc = $name] - #[doc = "bit. On register write, this results in clearing the bit."] - pub fn [](&mut self)->&mut Self{ - use bit_field::BitField; - self.0[$offset].set_bit($bit,true); - self - } + ($vis:vis,$self_:ident,$from:expr;$bit:literal,$method:ident,$name:literal) => { + bit_getter!($vis, $self_, $from;$bit, $method, $name); + bit_modifier_w1c!($vis, $self_, $from;$bit, $method, $name); + }; +} - #[doc = "Assigns 0 to the"] - #[doc = $name] - #[doc = "bit, preventing the bit from being cleared on write."] - pub fn [](&mut self) -> &mut Self { - use bit_field::BitField; - self.0[$offset].set_bit($bit,false); - self - } +macro_rules! field_getter { + ($vis:vis,$self_:ident,$from:expr;$range:expr,$method:ident,$name:literal,$ty:ty) => { + #[doc = "Returns the value of the"] + #[doc = $name] + #[doc = "field."] + #[must_use] + $vis fn $method(&$self_) -> $ty { + use bit_field::BitField; + use core::convert::TryInto; + $from.get_bits($range).try_into().unwrap() } }; - ($bit:literal,$method:ident,$name:literal) => { - bit_getter!($bit, $method, $name); - paste::paste! { - #[doc = "Assigns 1 to the"] - #[doc = $name] - #[doc = "bit. On register write, this results in clearing the bit."] - pub fn [](&mut self)->&mut Self{ - use bit_field::BitField; - self.0.set_bit($bit,true); - self - } +} - #[doc = "Assigns 0 to the"] - #[doc = $name] - #[doc = "bit, preventing the bit from being cleared on write."] - pub fn [](&mut self) -> &mut Self { - use bit_field::BitField; - self.0.set_bit($bit,false); - self - } +macro_rules! zero_trailing_getter { + ($vis:vis,$self_:ident,$from:expr;$start:literal~,$method:ident,$name:literal,$ty:ty) => { + #[doc = "Returns the value of the"] + #[doc = $name] + #[doc = "field."] + #[must_use] + $vis fn $method(&$self_) -> $ty { + use core::convert::TryInto; + ($from >> $start << $start).try_into().unwrap() } }; } -macro_rules! w1s_bit { - ([$offset:literal]($bit:literal),$method:ident,$name:literal) => { +macro_rules! field_setter { + ($vis:vis,$self_:ident,$from:expr;$range:expr,$method:ident,$name:literal,$ty:ty) => { paste::paste! { - #[doc = "Sets the"] + #[doc = "Sets the value of the"] #[doc = $name] - #[doc = "bit."] - pub fn [](&mut self)->&mut Self{ + #[doc = "field."] + $vis fn $method(&mut $self_,value:$ty) -> &mut Self { use bit_field::BitField; - self.0[$offset].set_bit($bit,true); - self + use core::convert::TryInto; + $from.set_bits($range,value.try_into().unwrap()); + $self_ } } }; - ($bit:literal,$method:ident,$name:literal) => { +} + +macro_rules! zero_trailing_setter { + ($vis:vis,$self_:ident,$from:expr;$start:literal~;$expect:literal,$method:ident,$name:literal,$ty:ty) => { paste::paste! { - #[doc = "Sets the"] + #[doc = "Sets the value of the"] #[doc = $name] - #[doc = "bit."] - pub fn [](&mut self)->&mut Self{ + #[doc = "field."] + #[doc = "\n\n# Panics \n\n"] + #[doc = "This method panics if the given value is not"] + #[doc = $expect] + #[doc = "."] + $vis fn $method(&mut $self_,value:$ty) -> &mut Self { use bit_field::BitField; - self.0.set_bit($bit,true); - self + + assert!(value.trailing_zeros() >= $start, "The {} must be {}.", $name, $expect); + + $from.set_bits($start.., value.get_bits($start..)); + $self_ } } }; } -macro_rules! rw1s_bit { - ([$offset:literal]($bit:literal),$method:ident,$name:literal) => { - bit_getter!([$offset]($bit), $method, $name); - w1s_bit!([$offset]($bit), $method, $name); +macro_rules! ro_field { + ($vis:vis,$self_:ident,$from:expr;$range:expr,$method:ident,$name:literal,$ty:ty) => { + field_getter!($vis, $self_, $from;$range, $method, $name, $ty); }; - ($bit:literal,$method:ident,$name:literal) => { - bit_getter!($bit, $method, $name); - w1s_bit!($bit, $method, $name); + ($vis:vis,$self_:ident,$from:expr,$range:expr,$name:literal,$ty:ty) => { + field_getter!($vis, $self_, $from;$range, get, $name, $ty); }; } -macro_rules! field_getter { - ([$offset:literal]($range:expr),$method:ident,$name:literal,$ty:ty) => { +macro_rules! rw_field { + ($vis:vis,$self_:ident,$from:expr;$range:expr,$method:ident,$name:literal,$ty:ty) => { + paste::paste!{ + field_getter!($vis, $self_, $from;$range, $method, $name, $ty); + field_setter!($vis, $self_, $from;$range, [], $name, $ty); + } + }; + ($vis:vis,$self_:ident,$from:expr;$range:expr,$name:literal,$ty:ty) => { + field_getter!($vis, $self_, $from;$range, get, $name, $ty); + field_setter!($vis, $self_, $from;$range, set, $name, $ty); + }; +} + +macro_rules! rw_zero_trailing { + ($vis:vis,$self_:ident,$from:expr;$start:literal~;$expect:literal,$method:ident,$name:literal,$ty:ty) => { + paste::paste!{ + zero_trailing_getter!($vis, $self_, $from;$start~, $method, $name, $ty); + zero_trailing_setter!($vis, $self_, $from;$start~;$expect, [], $name, $ty); + } + }; + ($vis:vis,$self_:ident,$from:expr;$start:literal~;$expect:literal,$name:literal,$ty:ty) => { + zero_trailing_getter!($vis, $self_, $from;$start~, get, $name, $ty); + zero_trailing_setter!($vis, $self_, $from;$start~;$expect, set, $name, $ty); + }; +} + +macro_rules! double_field_getter { + ($vis:vis,$self_:ident,$arr:expr;[$off_lo:literal,$off_hi:literal],$method:ident,$name:literal,$bits:literal,$ty:ty) => { #[doc = "Returns the value of the"] #[doc = $name] #[doc = "field."] #[must_use] - pub fn $method(self) -> $ty { - use bit_field::BitField; - use core::convert::TryInto; - self.0[$offset].get_bits($range).try_into().unwrap() + $vis fn $method(&$self_) -> $ty { + let lo = $arr[$off_lo] as $ty; + let hi = $arr[$off_hi] as $ty; + + (hi << $bits) | lo } }; - ($range:expr,$method:ident,$name:literal,$ty:ty) => { +} + +macro_rules! double_zero_trailing_getter { + ($vis:vis,$self_:ident,$arr:expr;[$off_lo:literal,$off_hi:literal];$start:literal~,$method:ident,$name:literal,$bits:literal,$ty:ty) => { #[doc = "Returns the value of the"] #[doc = $name] #[doc = "field."] #[must_use] - pub fn $method(self) -> $ty { - use bit_field::BitField; - use core::convert::TryInto; - self.0.get_bits($range).try_into().unwrap() + $vis fn $method(&$self_) -> $ty { + let lo = ($arr[$off_lo] as $ty) >> $start << $start; + let hi = $arr[$off_hi] as $ty; + + (hi << $bits) | lo } }; } -macro_rules! field_setter { - ([$offset:literal]($range:expr),$method:ident,$name:literal,$ty:ty) => { - paste::paste! { - #[doc = "Sets the value of the"] - #[doc = $name] - #[doc = "field."] - pub fn [](&mut self,value:$ty) -> &mut Self { - use bit_field::BitField; - use core::convert::TryInto; - self.0[$offset].set_bits($range,value.try_into().unwrap()); - self - } +macro_rules! double_field_setter { + ($vis:vis,$self_:ident,$arr:expr;[$off_lo:literal,$off_hi:literal],$method:ident,$name:literal,$bits:literal,$ty:ty) => { + #[doc = "Sets the value of the"] + #[doc = $name] + #[doc = "field."] + $vis fn $method(&mut $self_, value: $ty) -> &mut Self { + use bit_field::BitField; + use core::convert::TryInto; + + let lo = value.get_bits(..$bits); + let hi = value.get_bits($bits..); + + $arr[$off_lo] = lo.try_into().unwrap(); + $arr[$off_hi] = hi.try_into().unwrap(); + $self_ } }; - ($range:expr,$method:ident,$name:literal,$ty:ty) => { - paste::paste! { - #[doc = "Sets the value of the"] - #[doc = $name] - #[doc = "field."] - pub fn [](&mut self,value:$ty) -> &mut Self { - use bit_field::BitField; - use core::convert::TryInto; - self.0.set_bits($range,value.try_into().unwrap()); - self - } +} + +macro_rules! double_zero_trailing_setter { + ($vis:vis,$self_:ident,$arr:expr;[$off_lo:literal,$off_hi:literal];$start:literal~;$expect:literal,$method:ident,$name:literal,$bits:literal,$ty:ty) => { + #[doc = "Sets the value of the"] + #[doc = $name] + #[doc = "field."] + #[doc = "\n\n# Panics \n\n"] + #[doc = "This method panics if the given value is not"] + #[doc = $expect] + #[doc = "."] + $vis fn $method(&mut $self_, value: $ty) -> &mut Self { + use bit_field::BitField; + use core::convert::TryInto; + + let lo = value.get_bits(..$bits); + let hi = value.get_bits($bits..); + + assert!(lo.trailing_zeros() >= $start, "The {} must be {}.", $name, $expect); + + $arr[$off_lo].set_bits( + $start.., + lo.get_bits($start..).try_into().unwrap() + ); + $arr[$off_hi] = hi.try_into().unwrap(); + $self_ } }; } -macro_rules! ro_field { - ([$offset:literal]($range:expr),$method:ident,$name:literal,$ty:ty) => { - field_getter!([$offset]($range), $method, $name, $ty); +macro_rules! ro_double_field { + ($vis:vis,$self_:ident,$arr:expr;[$off_lo:literal,$off_hi:literal],$method:ident,$name:literal,$bits:literal,$ty:ty) => { + double_field_getter!($vis, $self_, $arr; [$off_lo, $off_hi], $method, $name, $bits, $ty); }; - ($range:expr,$method:ident,$name:literal,$ty:ty) => { - field_getter!($range, $method, $name, $ty); + ($vis:vis,$self_:ident,$arr:expr;[$off_lo:literal,$off_hi:literal],$name:literal,$bits:literal,$ty:ty) => { + double_field_getter!($vis, $self_, $arr; [$off_lo, $off_hi], get, $name, $bits, $ty); }; } -macro_rules! rw_field { - ([$offset:literal]($range:expr),$method:ident,$name:literal,$ty:ty) => { - field_getter!([$offset]($range), $method, $name, $ty); - field_setter!([$offset]($range), $method, $name, $ty); +macro_rules! rw_double_field { + ($vis:vis,$self_:ident,$arr:expr;[$off_lo:literal,$off_hi:literal],$method:ident,$name:literal,$bits:literal,$ty:ty) => { + paste::paste! { + double_field_getter!($vis, $self_, $arr; [$off_lo, $off_hi], $method, $name, $bits, $ty); + double_field_setter!($vis, $self_, $arr; [$off_lo, $off_hi], [], $name, $bits, $ty); + } + }; + ($vis:vis,$self_:ident,$arr:expr;[$off_lo:literal,$off_hi:literal],$name:literal,$bits:literal,$ty:ty) => { + double_field_getter!($vis, $self_, $arr; [$off_lo, $off_hi], get, $name, $bits, $ty); + double_field_setter!($vis, $self_, $arr; [$off_lo, $off_hi], set, $name, $bits, $ty); }; - ($range:expr,$method:ident,$name:literal,$ty:ty) => { - field_getter!($range, $method, $name, $ty); - field_setter!($range, $method, $name, $ty); +} + +macro_rules! rw_double_zero_trailing { + ($vis:vis,$self_:ident,$arr:expr;[$off_lo:literal,$off_hi:literal];$start:literal~;$expect:literal,$method:ident,$name:literal,$bits:literal,$ty:ty) => { + paste::paste! { + double_zero_trailing_getter!($vis, $self_, $arr; [$off_lo, $off_hi]; $start~, $method, $name, $bits, $ty); + double_zero_trailing_setter!($vis, $self_, $arr; [$off_lo, $off_hi]; $start~; $expect, [], $name, $bits, $ty); + } }; } diff --git a/src/registers/capability.rs b/src/registers/capability.rs index 323863cc..af74ca2f 100644 --- a/src/registers/capability.rs +++ b/src/registers/capability.rs @@ -2,7 +2,7 @@ use accessor::single; use accessor::Mapper; -use bit_field::BitField; +// use bit_field::BitField; /// Host Controller Capability Registers #[derive(Debug)] @@ -105,9 +105,9 @@ impl InterfaceVersionNumber { #[derive(Copy, Clone)] pub struct StructuralParameters1(u32); impl StructuralParameters1 { - ro_field!(0..=7, number_of_device_slots, "Number of Device Slots", u8); - ro_field!(8..=18, number_of_interrupts, "Number of Interrupts", u16); - ro_field!(24..=31, number_of_ports, "Number of Ports", u8); + ro_field!(pub, self, self.0; 0..=7, number_of_device_slots, "Number of Device Slots", u8); + ro_field!(pub, self, self.0; 8..=18, number_of_interrupts, "Number of Interrupts", u16); + ro_field!(pub, self, self.0; 24..=31, number_of_ports, "Number of Ports", u8); } impl_debug_from_methods! { StructuralParameters1{ @@ -123,11 +123,17 @@ impl_debug_from_methods! { pub struct StructuralParameters2(u32); impl StructuralParameters2 { ro_field!( - 0..=3, + pub, self, + self.0; 0..=3, isochronous_scheduling_threshold, "Isochronous Scheduling Threshold", u8 ); + ro_field!(pub(self), self, self.0; 4..=7, erst_max, "ERST Max", u32); + + ro_field!(pub(self), self, self.0; 21..=25, max_scratchpad_buffers_hi, "Max Scratchpad Buffers HI", u32); + ro_bit!(pub, self, self.0; 26, scratchpad_restore, "Scratchpad Restore"); + ro_field!(pub(self), self, self.0; 27..=31, max_scratchpad_buffers_lo, "Max Scratchpad Buffers LO", u32); /// Returns the maximum number of the elements the Event Ring Segment Table can contain. /// @@ -146,20 +152,6 @@ impl StructuralParameters2 { h << 5 | l } - - ro_bit!(26, scratchpad_restore, "Scratchpad Restore"); - - fn erst_max(self) -> u32 { - self.0.get_bits(4..=7) - } - - fn max_scratchpad_buffers_hi(self) -> u32 { - self.0.get_bits(21..=25) - } - - fn max_scratchpad_buffers_lo(self) -> u32 { - self.0.get_bits(27..=31) - } } impl_debug_from_methods! { StructuralParameters2{ @@ -175,9 +167,16 @@ impl_debug_from_methods! { #[derive(Copy, Clone)] pub struct StructuralParameters3(u32); impl StructuralParameters3 { - ro_field!(0..=7, u1_device_exit_latency, "U1 Device Exit Latency", u8); ro_field!( - 16..=31, + pub, self, + self.0; 0..=7, + u1_device_exit_latency, + "U1 Device Exit Latency", + u8 + ); + ro_field!( + pub, self, + self.0; 16..=31, u2_device_exit_latency, "U2 Device Exit Latency", u16 @@ -196,38 +195,43 @@ impl_debug_from_methods! { #[allow(clippy::module_name_repetitions)] pub struct CapabilityParameters1(u32); impl CapabilityParameters1 { - ro_bit!(0, addressing_capability, "64-bit Addressing Capability"); - ro_bit!(1, bw_negotiation_capability, "BW Negotiation Capability"); - ro_bit!(2, context_size, "Context Size"); - ro_bit!(3, port_power_control, "Port Power Control"); - ro_bit!(4, port_indicators, "Port Indicators"); - ro_bit!(5, light_hc_reset_capability, "Light HC Reset Capability"); + ro_bit!(pub, self, self.0; 0, addressing_capability, "64-bit Addressing Capability"); + ro_bit!(pub, self, self.0; 1, bw_negotiation_capability, "BW Negotiation Capability"); + ro_bit!(pub, self, self.0; 2, context_size, "Context Size"); + ro_bit!(pub, self, self.0; 3, port_power_control, "Port Power Control"); + ro_bit!(pub, self, self.0; 4, port_indicators, "Port Indicators"); + ro_bit!(pub, self, self.0; 5, light_hc_reset_capability, "Light HC Reset Capability"); ro_bit!( - 6, + pub, self, + self.0; 6, latency_tolerance_messaging_capability, "Latency Tolerance Messaging Capability" ); - ro_bit!(7, no_secondary_sid_support, "No Secondary SID Support"); - ro_bit!(8, parse_all_event_data, "Parse All Event Data"); + ro_bit!(pub, self, self.0; 7, no_secondary_sid_support, "No Secondary SID Support"); + ro_bit!(pub, self, self.0; 8, parse_all_event_data, "Parse All Event Data"); ro_bit!( - 9, + pub, self, + self.0; 9, stopped_short_packet_capability, "Stopped - Short Packet Capability" ); - ro_bit!(10, stopped_edtla_capability, "Stopped EDTLA Capability"); + ro_bit!(pub, self, self.0; 10, stopped_edtla_capability, "Stopped EDTLA Capability"); ro_bit!( - 11, + pub, self, + self.0; 11, contiguous_frame_id_capability, "Contiguous Frame ID Capability" ); ro_field!( - 12..=15, + pub, self, + self.0; 12..=15, maximum_primary_stream_array_size, "Maximum Primary Stream Array Size", u8 ); ro_field!( - 16..=31, + pub, self, + self.0; 16..=31, xhci_extended_capabilities_pointer, "xHCI Extended Capabilities Pointer", u16 @@ -282,45 +286,53 @@ impl RuntimeRegisterSpaceOffset { #[derive(Copy, Clone)] pub struct CapabilityParameters2(u32); impl CapabilityParameters2 { - ro_bit!(0, u3_entry_capability, "U3 Entry Capability"); + ro_bit!(pub, self, self.0; 0, u3_entry_capability, "U3 Entry Capability"); ro_bit!( - 1, + pub, self, + self.0; 1, configure_endpoint_command_max_exit_latency_too_large_capability, "Configure Endpoint Command Max Exit Latency Too Large Capability" ); ro_bit!( - 2, + pub, self, + self.0; 2, force_save_context_capability, "Force Save Context Capability" ); ro_bit!( - 3, + pub, self, + self.0; 3, compliance_transition_capability, "Compliance Transition Capability" ); ro_bit!( - 4, + pub, self, + self.0; 4, large_esit_payload_capability, "Large ESIT Payload Capability" ); ro_bit!( - 5, + pub, self, + self.0; 5, configuration_information_capability, "Configuration Information Capability" ); - ro_bit!(6, extended_tbc_capability, "Extended TBC Capability"); + ro_bit!(pub, self, self.0; 6, extended_tbc_capability, "Extended TBC Capability"); ro_bit!( - 7, + pub, self, + self.0; 7, extended_tbc_trb_status_capability, "Extended TBC TRB Status Capability" ); ro_bit!( - 8, + pub, self, + self.0; 8, get_set_extended_property_capability, "Get/Set Extended Property Capability" ); ro_bit!( - 9, + pub, self, + self.0; 9, virtualization_based_trusted_io_capability, "Virtualization Based Trusted I/O Capability" ); diff --git a/src/registers/doorbell.rs b/src/registers/doorbell.rs index 0406013c..bdf73c72 100644 --- a/src/registers/doorbell.rs +++ b/src/registers/doorbell.rs @@ -45,8 +45,8 @@ impl Doorbell { ) } - rw_field!(0..=7, doorbell_target, "Doorbell Target", u8); - rw_field!(16..=31, doorbell_stream_id, "Doorbell Stream ID", u16); + rw_field!(pub, self, self.0; 0..=7, doorbell_target, "Doorbell Target", u8); + rw_field!(pub, self, self.0; 16..=31, doorbell_stream_id, "Doorbell Stream ID", u16); } impl fmt::Debug for Doorbell { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { diff --git a/src/registers/operational.rs b/src/registers/operational.rs index 02f1050f..f8a3bf13 100644 --- a/src/registers/operational.rs +++ b/src/registers/operational.rs @@ -77,27 +77,29 @@ where #[derive(Copy, Clone)] pub struct UsbCommandRegister(u32); impl UsbCommandRegister { - rw_bit!(0, run_stop, "Run/Stop"); - rw_bit!(1, host_controller_reset, "Host Controller Reset"); - rw_bit!(2, interrupter_enable, "Interrupter Enable"); - rw_bit!(3, host_system_error_enable, "Host System Error Enable"); + rw_bit!(pub, self, self.0; 0, run_stop, "Run/Stop"); + rw_bit!(pub, self, self.0; 1, host_controller_reset, "Host Controller Reset"); + rw_bit!(pub, self, self.0; 2, interrupter_enable, "Interrupter Enable"); + rw_bit!(pub, self, self.0; 3, host_system_error_enable, "Host System Error Enable"); rw_bit!( - 7, + pub, self, + self.0; 7, light_host_controller_reset, "Light Host Controller Reset" ); - rw_bit!(8, controller_save_state, "Controller Save State"); - rw_bit!(9, controller_restore_state, "Controller Restore State"); - rw_bit!(10, enable_wrap_event, "Enable Wrap Event"); - rw_bit!(11, enable_u3_mfindex_stop, "Enable U3 MFINDEX Stop"); - rw_bit!(13, cem_enable, "CEM Enable"); - ro_bit!(14, extended_tbc_enable, "Extended TBC Enable"); + rw_bit!(pub, self, self.0; 8, controller_save_state, "Controller Save State"); + rw_bit!(pub, self, self.0; 9, controller_restore_state, "Controller Restore State"); + rw_bit!(pub, self, self.0; 10, enable_wrap_event, "Enable Wrap Event"); + rw_bit!(pub, self, self.0; 11, enable_u3_mfindex_stop, "Enable U3 MFINDEX Stop"); + rw_bit!(pub, self, self.0; 13, cem_enable, "CEM Enable"); + ro_bit!(pub, self, self.0; 14, extended_tbc_enable, "Extended TBC Enable"); ro_bit!( - 15, + pub, self, + self.0; 15, extended_tbc_trb_status_enable, "Extended TBC TRB Status Enable" ); - rw_bit!(16, vtio_enable, "VTIO Enable"); + rw_bit!(pub, self, self.0; 16, vtio_enable, "VTIO Enable"); } impl_debug_from_methods! { UsbCommandRegister{ @@ -122,15 +124,15 @@ impl_debug_from_methods! { #[derive(Copy, Clone)] pub struct UsbStatusRegister(u32); impl UsbStatusRegister { - ro_bit!(0, hc_halted, "HC Halted"); - rw1c_bit!(2, host_system_error, "Host System Error"); - rw1c_bit!(3, event_interrupt, "Event Interrupt"); - rw1c_bit!(4, port_change_detect, "Port Change Detect"); - ro_bit!(8, save_state_status, "Save State Status"); - ro_bit!(9, restore_state_status, "Restore State Status"); - rw1c_bit!(10, save_restore_error, "Save/Restore Error"); - ro_bit!(11, controller_not_ready, "Controller Not Ready"); - ro_bit!(12, host_controller_error, "Host Controller Error"); + ro_bit!(pub, self, self.0; 0, hc_halted, "HC Halted"); + rw1c_bit!(pub, self, self.0; 2, host_system_error, "Host System Error"); + rw1c_bit!(pub, self, self.0; 3, event_interrupt, "Event Interrupt"); + rw1c_bit!(pub, self, self.0; 4, port_change_detect, "Port Change Detect"); + ro_bit!(pub, self, self.0; 8, save_state_status, "Save State Status"); + ro_bit!(pub, self, self.0; 9, restore_state_status, "Restore State Status"); + rw1c_bit!(pub, self, self.0; 10, save_restore_error, "Save/Restore Error"); + ro_bit!(pub, self, self.0; 11, controller_not_ready, "Controller Not Ready"); + ro_bit!(pub, self, self.0; 12, host_controller_error, "Host Controller Error"); } impl_debug_from_methods! { UsbStatusRegister{ @@ -212,25 +214,17 @@ impl DeviceNotificationControl { #[derive(Copy, Clone)] pub struct CommandRingControlRegister(u64); impl CommandRingControlRegister { - wo_bit!(0, ring_cycle_state, "Ring Cycle State"); - w1s_bit!(1, command_stop, "Command Stop"); - w1s_bit!(2, command_abort, "Command Abort"); - ro_bit!(3, command_ring_running, "Command Ring Running"); - - /// Sets the value of the Command Ring Pointer field. It must be 64 byte aligned. - /// - /// # Panics - /// - /// This method panics if the given pointer is not 64 byte aligned. - pub fn set_command_ring_pointer(&mut self, p: u64) { - assert!( - p.trailing_zeros() >= 6, - "The Command Ring Pointer must be 64-byte aligned." - ); - - let p = p >> 6; - self.0.set_bits(6..=63, p); - } + wo_bit!(pub, self, self.0; 0, ring_cycle_state, "Ring Cycle State"); + w1s_bit!(pub, self, self.0; 1, command_stop, "Command Stop"); + w1s_bit!(pub, self, self.0; 2, command_abort, "Command Abort"); + ro_bit!(pub, self, self.0; 3, command_ring_running, "Command Ring Running"); + rw_zero_trailing!( + pub, self, + self.0; 6~; "64-byte aligned", + command_ring_pointer, + "Command Ring Pointer", + u64 + ); } impl_debug_from_methods! { CommandRingControlRegister{ @@ -243,24 +237,12 @@ impl_debug_from_methods! { #[derive(Copy, Clone, Debug, Default)] pub struct DeviceContextBaseAddressArrayPointerRegister(u64); impl DeviceContextBaseAddressArrayPointerRegister { - /// Returns the value of the Device Context Base Address Array Pointer. - #[must_use] - pub fn get(self) -> u64 { - self.0 - } - - /// Sets the value of the Device Context Base Address Array Pointer. It must be 64 byte aligned. - /// - /// # Panics - /// - /// This method panics if the given pointer is not 64 byte aligned. - pub fn set(&mut self, p: u64) { - assert!( - p.trailing_zeros() >= 6, - "The Device Context Base Address Array Pointer must be 64-byte aligned." - ); - self.0 = p; - } + rw_zero_trailing!( + pub, self, + self.0; 6~;"64-byte aligned", + "Device Context Base Address Array Pointer", + u64 + ); } /// Configure Register @@ -269,14 +251,16 @@ impl DeviceContextBaseAddressArrayPointerRegister { pub struct ConfigureRegister(u32); impl ConfigureRegister { rw_field!( - 0..=7, + pub, self, + self.0; 0..=7, max_device_slots_enabled, "Max Device Slots Enabled", u8 ); - rw_bit!(8, u3_entry_enable, "U3 Entry Enable"); + rw_bit!(pub, self, self.0; 8, u3_entry_enable, "U3 Entry Enable"); rw_bit!( - 9, + pub, self, + self.0; 9, configuration_information_enable, "Configuration Information Enable" ); @@ -340,45 +324,49 @@ impl PortRegisterSet { #[derive(Copy, Clone)] pub struct PortStatusAndControlRegister(u32); impl PortStatusAndControlRegister { - ro_bit!(0, current_connect_status, "Current Connect Status"); - rw1c_bit!(1, port_enabled_disabled, "Port Enabled/Disabled"); - ro_bit!(3, over_current_active, "Over-current Active"); - rw1s_bit!(4, port_reset, "Port Reset"); - rw_field!(5..=8, port_link_state, "Port Link State", u8); - rw_bit!(9, port_power, "Port Power"); - ro_field!(10..=13, port_speed, "Port Speed", u8); + ro_bit!(pub, self, self.0; 0, current_connect_status, "Current Connect Status"); + rw1c_bit!(pub, self, self.0; 1, port_enabled_disabled, "Port Enabled/Disabled"); + ro_bit!(pub, self, self.0; 3, over_current_active, "Over-current Active"); + rw1s_bit!(pub, self, self.0; 4, port_reset, "Port Reset"); + rw_field!(pub, self, self.0; 5..=8, port_link_state, "Port Link State", u8); + rw_bit!(pub, self, self.0; 9, port_power, "Port Power"); + ro_field!(pub, self, self.0; 10..=13, port_speed, "Port Speed", u8); rw_field!( - 14..=15, + pub, self, + self.0; 14..=15, port_indicator_control, "Port Indicator Control", PortIndicator ); rw_bit!( - 16, + pub, self, + self.0; 16, port_link_state_write_strobe, "Port Link State Write Strobe" ); - rw1c_bit!(17, connect_status_change, "Connect Status Change"); + rw1c_bit!(pub, self, self.0; 17, connect_status_change, "Connect Status Change"); rw1c_bit!( - 18, + pub, self, + self.0; 18, port_enabled_disabled_change, "Port Enabled/Disabled Change" ); - rw1c_bit!(19, warm_port_reset_change, "Warm Port Reset Change"); - rw1c_bit!(20, over_current_change, "Over-Current Change"); - rw1c_bit!(21, port_reset_change, "Port Reset Change"); - rw1c_bit!(22, port_link_state_change, "Port Link State Change"); - rw1c_bit!(23, port_config_error_change, "Port Config Error Change"); - ro_bit!(24, cold_attach_status, "Cold Attach Status"); - rw_bit!(25, wake_on_connect_enable, "Wake on Connect Enable"); - rw_bit!(26, wake_on_disconnect_enable, "Wake on Disconnect Enable"); + rw1c_bit!(pub, self, self.0; 19, warm_port_reset_change, "Warm Port Reset Change"); + rw1c_bit!(pub, self, self.0; 20, over_current_change, "Over-Current Change"); + rw1c_bit!(pub, self, self.0; 21, port_reset_change, "Port Reset Change"); + rw1c_bit!(pub, self, self.0; 22, port_link_state_change, "Port Link State Change"); + rw1c_bit!(pub, self, self.0; 23, port_config_error_change, "Port Config Error Change"); + ro_bit!(pub, self, self.0; 24, cold_attach_status, "Cold Attach Status"); + rw_bit!(pub, self, self.0; 25, wake_on_connect_enable, "Wake on Connect Enable"); + rw_bit!(pub, self, self.0; 26, wake_on_disconnect_enable, "Wake on Disconnect Enable"); rw_bit!( - 27, + pub, self, + self.0; 27, wake_on_over_current_enable, "Wake on Over-Current Enable" ); - ro_bit!(30, device_removable, "Device Removable"); - rw1s_bit!(31, warm_port_reset, "Warm Port Reset"); + ro_bit!(pub, self, self.0; 30, device_removable, "Device Removable"); + rw1s_bit!(pub, self, self.0; 31, warm_port_reset, "Warm Port Reset"); } impl_debug_from_methods! { PortStatusAndControlRegister{ @@ -413,9 +401,9 @@ impl_debug_from_methods! { pub struct PortPowerManagementStatusAndControlRegister(u32); /// **These methods are only valid for USB3.** impl PortPowerManagementStatusAndControlRegister { - rw_field!(0..=7, u1_timeout, "U1 Timeout", u8); - rw_field!(8..=15, u2_timeout, "U2 Timeout", u8); - rw_bit!(16, force_link_pm_accept, "Force Link PM Accept"); + rw_field!(pub, self, self.0; 0..=7, u1_timeout, "U1 Timeout", u8); + rw_field!(pub, self, self.0; 8..=15, u2_timeout, "U2 Timeout", u8); + rw_bit!(pub, self, self.0; 16, force_link_pm_accept, "Force Link PM Accept"); } /// **These methods are only valid for USB2.** impl PortPowerManagementStatusAndControlRegister { @@ -428,15 +416,16 @@ impl PortPowerManagementStatusAndControlRegister { FromPrimitive::from_u32(s) } - rw_bit!(3, remote_wake_enable, "Remote Wake Enable"); + rw_bit!(pub, self, self.0; 3, remote_wake_enable, "Remote Wake Enable"); rw_field!( - 4..=7, + pub, self, + self.0; 4..=7, best_effort_service_latency, "Best Effort Service Latency", u8 ); - rw_field!(8..=15, l1_device_slot, "L1 Device Slot", u8); - rw_bit!(16, hardware_lpm_enable, "Hardware LPM Enable"); + rw_field!(pub, self, self.0; 8..=15, l1_device_slot, "L1 Device Slot", u8); + rw_bit!(pub, self, self.0; 16, hardware_lpm_enable, "Hardware LPM Enable"); /// Returns the value of the Port Test Control field. /// @@ -474,9 +463,9 @@ impl_debug_from_methods! { #[derive(Copy, Clone)] pub struct PortLinkInfoRegister(u32); impl PortLinkInfoRegister { - rw_field!(0..=15, link_error_count, "Link Error Count", u16); - ro_field!(16..=19, rx_lane_count, "Rx Lane Count", u8); - ro_field!(20..=23, tx_lane_count, "Tx Lane Count", u8); + rw_field!(pub, self, self.0; 0..=15, link_error_count, "Link Error Count", u16); + ro_field!(pub, self, self.0; 16..=19, rx_lane_count, "Rx Lane Count", u8); + ro_field!(pub, self, self.0; 20..=23, tx_lane_count, "Tx Lane Count", u8); } impl_debug_from_methods! { PortLinkInfoRegister{ @@ -494,14 +483,16 @@ impl_debug_from_methods! { pub struct PortHardwareLpmControlRegister(u32); impl PortHardwareLpmControlRegister { rw_field!( - 0..=1, + pub, self, + self.0; 0..=1, host_initiated_resume_duration_mode, "Host Initiated Resume Duration Mode", u8 ); - rw_field!(2..=9, l1_timeout, "L1 Timeout", u8); + rw_field!(pub, self, self.0; 2..=9, l1_timeout, "L1 Timeout", u8); rw_field!( - 10..=13, + pub, self, + self.0; 10..=13, best_effort_service_latency_deep, "Best Effort Service Latency Depp", u8 diff --git a/src/registers/runtime.rs b/src/registers/runtime.rs index 159e8471..1d9308d5 100644 --- a/src/registers/runtime.rs +++ b/src/registers/runtime.rs @@ -8,7 +8,7 @@ use accessor::marker::Readable; use accessor::single; use accessor::Mapper; use core::convert::TryFrom; -use core::convert::TryInto; +// use core::convert::TryInto; use core::marker::PhantomData; /// Runtime Registers @@ -51,7 +51,7 @@ where #[derive(Copy, Clone)] pub struct MicroframeIndexRegister(u32); impl MicroframeIndexRegister { - ro_field!(0..=13, microframe_index, "Microframe Index", u16); + ro_field!(pub, self, self.0; 0..=13, microframe_index, "Microframe Index", u16); } impl_debug_from_methods! { MicroframeIndexRegister { @@ -166,8 +166,8 @@ where #[derive(Copy, Clone)] pub struct InterrupterManagementRegister(u32); impl InterrupterManagementRegister { - rw1c_bit!(0, interrupt_pending, "Interrupt Pending"); - rw_bit!(1, interrupt_enable, "Interrupt Enable"); + rw1c_bit!(pub, self, self.0; 0, interrupt_pending, "Interrupt Pending"); + rw_bit!(pub, self, self.0; 1, interrupt_enable, "Interrupt Enable"); } impl_debug_from_methods! { InterrupterManagementRegister { @@ -182,13 +182,15 @@ impl_debug_from_methods! { pub struct InterrupterModerationRegister(u32); impl InterrupterModerationRegister { rw_field!( - 0..=15, + pub, self, + self.0; 0..=15, interrupt_moderation_interval, "Interrupt Moderation Interval", u16 ); rw_field!( - 16..=31, + pub, self, + self.0; 16..=31, interrupt_moderation_counter, "Interrupt Moderation Counter", u16 @@ -206,16 +208,12 @@ impl_debug_from_methods! { #[derive(Copy, Clone, Debug)] pub struct EventRingSegmentTableSizeRegister(u32); impl EventRingSegmentTableSizeRegister { - /// Returns the number of segments the Event Ring Segment Table supports. - #[must_use] - pub fn get(self) -> u16 { - self.0.try_into().unwrap() - } - - /// Sets the number of segments the Event Ring Segment Table supports. - pub fn set(&mut self, s: u16) { - self.0 = s.into(); - } + rw_field!( + pub, self, + self.0; 0..=15, + "Event Ring Segment Table Size (the number of segments)", + u16 + ); } /// Event Ring Segment Table Base Address Register. @@ -223,24 +221,12 @@ impl EventRingSegmentTableSizeRegister { #[derive(Copy, Clone, Debug)] pub struct EventRingSegmentTableBaseAddressRegister(u64); impl EventRingSegmentTableBaseAddressRegister { - /// Returns the base address of the Event Ring Segment Table. - #[must_use] - pub fn get(self) -> u64 { - self.0 - } - - /// Sets the base address of the Event Ring Segment Table. It must be 64 byte aligned. - /// - /// # Panics - /// - /// This method panics if the address is not 64 byte aligned. - pub fn set(&mut self, a: u64) { - assert!( - a.trailing_zeros() >= 6, - "The Event Ring Segment Table Base Address must be 64-byte aligned." - ); - self.0 = a; - } + rw_zero_trailing!( + pub, self, + self.0; 6~; "64-byte aligned", + "Event Ring Segment Table Base Address", + u64 + ); } /// Event Ring Dequeue Pointer Register. @@ -249,31 +235,20 @@ impl EventRingSegmentTableBaseAddressRegister { pub struct EventRingDequeuePointerRegister(u64); impl EventRingDequeuePointerRegister { rw_field!( - 0..=2, + pub, self, + self.0; 0..=2, dequeue_erst_segment_index, "Dequeue ERST Segment Index", u8 ); - rw1c_bit!(3, event_handler_busy, "Event Handler Busy"); - - /// Returns the address of the current Event Ring Dequeue Pointer. - #[must_use] - pub fn event_ring_dequeue_pointer(self) -> u64 { - self.0 & !0b1111 - } - - /// Sets the address of the current Event Ring Dequeue Pointer. It must be 16 byte aligned. - /// - /// # Panics - /// - /// This method panics if the address is not 16 byte aligned. - pub fn set_event_ring_dequeue_pointer(&mut self, p: u64) { - assert!( - p.trailing_zeros() >= 4, - "The Event Ring Dequeue Pointer must be 16-byte aligned." - ); - self.0 = p; - } + rw1c_bit!(pub, self, self.0; 3, event_handler_busy, "Event Handler Busy"); + rw_zero_trailing!( + pub, self, + self.0; 4~; "16-byte aligned", + event_ring_dequeue_pointer, + "current Event Ring Dequeue Pointer", + u64 + ); } impl_debug_from_methods! { EventRingDequeuePointerRegister{ diff --git a/src/ring/erst.rs b/src/ring/erst.rs new file mode 100644 index 00000000..5fc0fe51 --- /dev/null +++ b/src/ring/erst.rs @@ -0,0 +1,104 @@ +//! Data structures around the Event Ring Segment Table entry. + +use crate::ring::trb::{self, event}; +use core::ops::{Index, IndexMut}; +use core::mem::MaybeUninit; + +/// The Event Ring Segment Table entry. +/// This plays the same role as an array pointer, and require special care to guarantee memory safety. +/// +/// For example, the entry do not implement `Drop` trait, so the user should manually free its memory. +#[repr(transparent)] +#[derive(Clone, Copy, Debug)] +pub struct EventRingSegmentTableEntry([u32; 4]); + +impl EventRingSegmentTableEntry { + /// Create new segment table entry from base address `base` and entry count `len`. + /// `len` should be the entry count, not the size in bytes. + /// + /// # Panics + /// + /// This method will panic if `len >= 4096`. + pub unsafe fn new(base: *const event::TRB, len: usize) -> Self { + assert!(len <= u16::MAX as usize); + + let mut entry = Self([0; 4]); + entry + .set_ring_segment_base_address(base as usize as u64) + .set_ring_segment_size(len as u16); + entry + } + + /// Create new segment table entry from a event::TRB buffer. + pub unsafe fn from_buf(buf: &[event::TRB]) -> Self { + Self::new(buf.as_ptr(), buf.len()) + } + + /// Returns the entry count of the segment. + pub fn len(&self) -> usize { + return self.ring_segment_size() as usize / trb::BYTES; + } + + /// Returns the slice that this entry is representing. + pub fn as_slice(&self) -> &[event::TRB] { + unsafe { + let base = self.ring_segment_base_address() as usize as *const _; + let len = self.len(); + + core::slice::from_raw_parts(base, len) + } + } + + /// Returns the mutable slice that this entry is representing. + pub fn as_mut_slice(&mut self) -> &mut [event::TRB] { + unsafe { + let base = self.ring_segment_base_address() as usize as *mut _; + let len = self.len(); + + core::slice::from_raw_parts_mut(base, len) + } + } +} +impl EventRingSegmentTableEntry { + rw_double_zero_trailing!( + pub, self, + self.0; [0, 1]; 6~; "64-byte aligned", + ring_segment_base_address, + "Ring Segment Base Address", + 32, u64 + ); + + rw_field!( + pub, self, + self.0[2]; 0..=15, + ring_segment_size, + "Ring Segment Size (entry count)", + u16 + ); + + /// Returns the value of the ring segment end address. + pub fn ring_segment_bound_address(&self) -> u64 { + self.ring_segment_base_address() + (trb::BYTES * self.ring_segment_size() as usize) as u64 + } +} +impl Index for EventRingSegmentTableEntry { + type Output = event::TRB; + + fn index(&self, index: usize) -> &Self::Output { + let slice = self.as_slice(); + + &slice[index] + } +} +impl IndexMut for EventRingSegmentTableEntry { + fn index_mut(&mut self, index: usize) -> &mut Self::Output { + let slice = self.as_mut_slice(); + + &mut slice[index] + } +} + +/// An 64-byte aligned helper type to enforce the ERST base always 64-byte aligned. +#[derive(Copy, Clone, Debug)] +#[repr(align(64))] +pub struct EventRingSegmentTableEntryBlock(pub [MaybeUninit; 4]); diff --git a/src/ring/mod.rs b/src/ring/mod.rs index 4bf525a5..21bd47fb 100644 --- a/src/ring/mod.rs +++ b/src/ring/mod.rs @@ -1,3 +1,6 @@ //! TRB Ring. pub mod trb; +pub mod erst; + +pub use erst::EventRingSegmentTableEntry; \ No newline at end of file diff --git a/src/ring/trb/command.rs b/src/ring/trb/command.rs index d5cb52eb..a6bddc85 100644 --- a/src/ring/trb/command.rs +++ b/src/ring/trb/command.rs @@ -1,654 +1,425 @@ //! Command TRBs. -use super::{Link, Type}; use bit_field::BitField; -use core::convert::TryInto; +// use core::convert::TryInto; +use num_derive::FromPrimitive; use num_traits::FromPrimitive; -allowed! { - /// TRBs which are allowed to be pushed to the Command Ring. - enum { - /// Link TRB - Link, - /// Enable Slot Command TRB - EnableSlot, - /// Disable Slot Command TRB - DisableSlot, - /// Address Device Command TRB - AddressDevice, - /// Configure Endpoint Command TRB - ConfigureEndpoint, - /// Evaluate Context Command TRB - EvaluateContext, - /// Reset Endpoint Command TRB - ResetEndpoint, - /// Stop Endpoint Command TRB - StopEndpoint, - /// Set TR Dequeue Pointer Command TRB - SetTrDequeuePointer, - /// Reset Device Command TRB - ResetDevice, - /// Force Event Command TRB - ForceEvent, - /// Negotiate Bandwidth Command TRB - NegotiateBandwidth, - /// Set Latency Tolerance Value Command TRB - SetLatencyToleranceValue, - /// Get Port Bandwidth Command TRB - GetPortBandwidth, - /// Force Header Command TRB - ForceHeader, - /// No Op Command TRB - Noop, - /// Get Extended Property Command TRB - GetExtendedProperty, - /// Set Extended Property Command TRB - SetExtendedProperty - } +macro_rules! impl_input_context_pointer { + () => { + param_align_16!(input_context_pointer, "Input Context Pointer"); + }; } -impl TryFrom<[u32; 4]> for Allowed { - type Error = [u32; 4]; - - fn try_from(raw: [u32; 4]) -> Result { - try_from!( - raw => - Link, - EnableSlot, - DisableSlot, - AddressDevice, - ConfigureEndpoint, - EvaluateContext, - ResetEndpoint, - StopEndpoint, - SetTrDequeuePointer, - ResetDevice, - ForceEvent, - NegotiateBandwidth, - SetLatencyToleranceValue, - GetPortBandwidth, - ForceHeader, - Noop(Command), - GetExtendedProperty, - SetExtendedProperty, - ); - Err(raw) + +macro_rules! impl_subtype { + () => { + rw_field!(pub, self, self.0.0[3]; 16..=18, command_sub_type, "Command Sub Type", u8); } } -add_trb_with_default!(Noop, "No Op Command TRB", Type::NoopCommand); -reserved!(Noop(Type::NoopCommand) { - [0]0..=31; - [1]0..=31; - [2]0..=31; - [3]1..=9; - [3]21..=31; +allowed_trb!("Command TRB", { + /// Link TRB + Link = 6, + /// Enable Slot Command TRB + EnableSlot = 9, + /// Disable Slot Command TRB + DisableSlot = 10, + /// Address Device Command TRB + AddressDevice = 11, + /// Configure Endpoint Command TRB + ConfigureEndpoint = 12, + /// Evaluate Context Command TRB + EvaluateContext = 13, + /// Reset Endpoint Command TRB + ResetEndpoint = 14, + /// Stop Endpoint Command TRB + StopEndpoint = 15, + /// Set TR Dequeue Pointer Command TRB + SetTrDequeuePointer = 16, + /// Reset Device Command TRB + ResetDevice = 17, + /// Force Event Command TRB + ForceEvent = 18, + /// Negotiate Bandwidth Command TRB + NegotiateBandwidth = 19, + /// Set Latency Tolerance Value Command TRB + SetLatencyToleranceValue = 20, + /// Get Port Bandwidth Command TRB + GetPortBandwidth = 21, + /// Force Header Command TRB + ForceHeader = 22, + /// NoOp Command TRB + NoOp = 23, + /// Get Extended Property Command TRB + GetExtendedProperty = 24, + /// Set Extended Property Command TRB + SetExtendedProperty = 25, +}); + +impl Link { + impl_ring_segment_pointer!(); + + // impl_interrupter_target!(); // ignored in command ring + + impl_tc!(); + // impl_ch!(); // ignored in command ring + impl_ioc!(); +} +rsvdz_checking_try_from!(Link { + [0];0..=3, + [2];0..=21, + [3];2..=3, + [3];6..=9, + [3];16..=31, +}); +impl_debug_from_methods!(Link { + ring_segment_pointer, + // interrupter_target, + toggle_cycle, + // chain_bit, + interrupt_on_completion, }); -impl_debug_for_trb!(Noop {}); -add_trb_with_default!(EnableSlot, "Enable Slot Command TRB", Type::EnableSlot); -reserved!(EnableSlot(Type::EnableSlot) { - [0]0..=31; - [1]0..=31; - [2]0..=31; - [3]1..=9; - [3]21..=31; +impl NoOp {} +rsvdz_checking_try_from!(NoOp { + [0];0..=31, + [1];0..=31, + [2];0..=31, + [3];1..=9, + [3];16..=31, }); +impl_debug_from_methods!(NoOp {}); + impl EnableSlot { - rw_field!([3](16..=20), slot_type, "Slot Type", u8); + rw_field!(pub, self, self.0.0[3]; 16..=20, slot_type, "Slot Type", u8); } -impl_debug_for_trb!(EnableSlot { slot_type }); - -add_trb_with_default!(DisableSlot, "Disable Slot Command TRB", Type::DisableSlot); -reserved!(DisableSlot(Type::DisableSlot) { - [0]0..=31; - [1]0..=31; - [2]0..=31; - [3]1..=9; - [3]16..=23; +impl_debug_from_methods!(EnableSlot { slot_type }); +rsvdz_checking_try_from!(EnableSlot { + [0];0..=31, + [1];0..=31, + [2];0..=31, + [3];1..=9, + [3];21..=31, }); + impl DisableSlot { - rw_field!([3](24..=31), slot_id, "Slot ID", u8); + impl_slot_id!(); } -impl_debug_for_trb!(DisableSlot { slot_id }); - -add_trb_with_default!( - AddressDevice, - "Address Device Command TRB", - Type::AddressDevice -); -reserved!(AddressDevice(Type::AddressDevice) { - [0]0..=3; - [2]0..=31; - [3]1..=8; - [3]16..=23; +impl_debug_from_methods!(DisableSlot { slot_id }); +rsvdz_checking_try_from!(DisableSlot { + [0];0..=31, + [1];0..=31, + [2];0..=31, + [3];1..=9, + [3];16..=23, }); -impl AddressDevice { - /// Sets the value of the Input Context Pointer field. - /// - /// # Panics - /// - /// This method panics if `p` is not 16-byte aligned. - pub fn set_input_context_pointer(&mut self, p: u64) -> &mut Self { - assert_eq!( - p % 16, - 0, - "The Input Context Pointer must be 16-byte aligned." - ); - let l = p.get_bits(0..32); - let u = p.get_bits(32..64); - - self.0[0] = l.try_into().unwrap(); - self.0[1] = u.try_into().unwrap(); - self - } - - /// Returns the value of the Input Context Pointer field. - #[must_use] - pub fn input_context_pointer(&self) -> u64 { - let l: u64 = self.0[0].into(); - let u: u64 = self.0[1].into(); - - (u << 32) | l - } +impl AddressDevice { + impl_input_context_pointer!(); - rw_bit!( - [3](9), - block_set_address_request, - "Block Set Address Request" - ); - rw_field!([3](24..=31), slot_id, "Slot ID", u8); + rw_bit!(pub, self, self.0.0[3]; 9, block_set_address_request, "Block Set Address Request"); + impl_slot_id!(); } -impl_debug_for_trb!(AddressDevice { +impl_debug_from_methods!(AddressDevice { input_context_pointer, block_set_address_request, - slot_id + slot_id, }); - -add_trb_with_default!( - ConfigureEndpoint, - "Configure Endpoint Command TRB", - Type::ConfigureEndpoint -); -reserved!(ConfigureEndpoint(Type::ConfigureEndpoint) { - [0]0..=3; - [2]0..=31; - [3]1..=8; - [3]16..=23; +rsvdz_checking_try_from!(AddressDevice { + [0];0..=3, + [2];0..=31, + [3];1..=8, + [3];16..=23, }); -impl ConfigureEndpoint { - /// Sets the value of the Input Context Pointer field. - /// - /// # Panics - /// - /// This method panics if `p` is not 16-byte aligned. - pub fn set_input_context_pointer(&mut self, p: u64) -> &mut Self { - assert_eq!( - p % 16, - 0, - "The Input Context Pointer must be 16-byte aligned." - ); - - let l = p.get_bits(0..32); - let u = p.get_bits(32..64); - self.0[0] = l.try_into().unwrap(); - self.0[1] = u.try_into().unwrap(); - self - } - - /// Returns the value of the Input Context Pointer field. - #[must_use] - pub fn input_context_pointer(&self) -> u64 { - let l: u64 = self.0[0].into(); - let u: u64 = self.0[1].into(); - - (u << 32) | l - } +impl ConfigureEndpoint { + impl_input_context_pointer!(); - rw_bit!([3](9), deconfigure, "Deconfigure"); - rw_field!([3](24..=31), slot_id, "Slot ID", u8); + rw_bit!(pub, self, self.0.0[3]; 9, deconfigure, "Deconfigure"); + impl_slot_id!(); } -impl_debug_for_trb!(ConfigureEndpoint { +impl_debug_from_methods!(ConfigureEndpoint { input_context_pointer, deconfigure, - slot_id + slot_id, }); - -add_trb_with_default!( - EvaluateContext, - "Evaluate Context Command TRB", - Type::EvaluateContext -); -reserved!(EvaluateContext(Type::EvaluateContext) { - [0]0..=3; - [2]0..=31; - [3]1..=8; - [3]16..=23; +rsvdz_checking_try_from!(ConfigureEndpoint { + [0];0..=3, + [2];0..=31, + [3];1..=8, + [3];16..=23, }); -impl EvaluateContext { - /// Sets the value of the Input Context Pointer field. - /// - /// # Panics - /// - /// This method panics if `p` is not 16-byte aligned. - pub fn set_input_context_pointer(&mut self, p: u64) -> &mut Self { - assert_eq!( - p % 16, - 0, - "The Input Context Pointer must be 16-byte aligned." - ); - - let l = p.get_bits(0..32); - let u = p.get_bits(32..64); - - self.0[0] = l.try_into().unwrap(); - self.0[1] = u.try_into().unwrap(); - self - } - /// Returns the value of the Input Context Pointer field. - #[must_use] - pub fn input_context_pointer(&self) -> u64 { - let l: u64 = self.0[0].into(); - let u: u64 = self.0[1].into(); +impl EvaluateContext { + impl_input_context_pointer!(); - (u << 32) | l - } - rw_field!([3](24..=31), slot_id, "Slot ID", u8); + // rw_bit!(pub, self, self.0.0[3]; 9, block_set_address_request, "Block Set Address Request"); // unused (no rsvdz) + impl_slot_id!(); } -impl_debug_for_trb!(EvaluateContext { +impl_debug_from_methods!(EvaluateContext { input_context_pointer, - slot_id + slot_id, }); - -add_trb_with_default!( - ResetEndpoint, - "Reset Endpoint Command TRB", - Type::ResetEndpoint -); -reserved!(ResetEndpoint(Type::ResetEndpoint) { - [0]0..=31; - [1]0..=31; - [2]0..=31; - [3]1..=8; - [3]21..=23; +rsvdz_checking_try_from!(EvaluateContext { + [0];0..=3, + [2];0..=31, + [3];1..=8, + [3];16..=23, }); + impl ResetEndpoint { - rw_bit!([3](9), transfer_state_preserve, "Transfer State Preserve"); - rw_field!([3](16..=20), endpoint_id, "Endpoint ID", u8); - rw_field!([3](24..=31), slot_id, "Slot ID", u8); + rw_bit!(pub, self, self.0.0[3]; 9, transfer_state_preserve, "Transfer State Preserve"); + impl_ep_id!(); + impl_slot_id!(); } -impl_debug_for_trb!(ResetEndpoint { +impl_debug_from_methods!(ResetEndpoint { transfer_state_preserve, endpoint_id, - slot_id + slot_id, }); - -add_trb_with_default!( - StopEndpoint, - "Stop Endpoint Command TRB", - Type::StopEndpoint -); -reserved!(StopEndpoint(Type::StopEndpoint) { - [0]0..=31; - [1]0..=31; - [2]0..=31; - [3]1..=9; - [3]21..=22; +rsvdz_checking_try_from!(ResetEndpoint { + [0];0..=31, + [1];0..=31, + [2];0..=31, + [3];1..=8, + [3];21..=23, }); + impl StopEndpoint { - rw_field!([3](16..=20), endpoint_id, "Endpoint ID", u8); - rw_bit!([3](23), suspend, "Suspend"); - rw_field!([3](24..=31), slot_id, "Slot ID", u8); + impl_ep_id!(); + rw_bit!(pub, self, self.0.0[3]; 23, suspend, "Suspend"); + impl_slot_id!(); } -impl_debug_for_trb!(StopEndpoint { +impl_debug_from_methods!(StopEndpoint { endpoint_id, suspend, - slot_id + slot_id, }); - -add_trb_with_default!( - SetTrDequeuePointer, - "Set TR Dequeue Pointer Command TRB", - Type::SetTrDequeuePointer -); -reserved!(SetTrDequeuePointer(Type::SetTrDequeuePointer) { - [2]0..=15; - [3]1..=9; - [3]21..=23; +rsvdz_checking_try_from!(StopEndpoint { + [0];0..=31, + [1];0..=31, + [2];0..=31, + [3];1..=9, + [3];21..=22, }); -impl SetTrDequeuePointer { - rw_bit!([0](0), dequeue_cycle_state, "Dequeue Cycle State"); - rw_field!([0](1..=3), stream_context_type, "Stream Context Type", u8); - - /// Sets the value of the New TR Dequeue Pointer field. - /// - /// # Panics - /// - /// This method panics if `p` is not 16-byte aligned. - pub fn set_new_tr_dequeue_pointer(&mut self, p: u64) -> &mut Self { - assert_eq!( - p % 16, - 0, - "The New TR Dequeue Pointer must be 16-byte aligned." - ); - - let l = p.get_bits(0..32); - let u = p.get_bits(32..64); - self.0[0].set_bits(4..32, l.get_bits(4..32).try_into().unwrap()); - self.0[1] = u.try_into().unwrap(); - self - } - - /// Returns the value of the New TR Dequeue Pointer field. - #[must_use] - pub fn new_tr_dequeue_pointer(&self) -> u64 { - let l: u64 = self.0[0].into(); - let u: u64 = self.0[1].into(); - - ((u << 32) | l) & 0xffff_fff0 - } +impl SetTrDequeuePointer { + rw_bit!(pub, self, self.0.0[0]; 0, dequeue_cycle_state, "Dequeue Cycle State"); + rw_field!(pub, self, self.0.0[0]; 1..=3, stream_context_type, "Stream Context Type", u8); + param_align_16!(new_tr_dequeue_pointer, "New TR Dequeue Pointer"); + rw_field!(pub, self, self.0.0[2]; 16..=31, stream_id, "Stream ID", u16); - rw_field!([2](16..=31), stream_id, "Stream ID", u16); - rw_field!([3](16..=20), endpoint_id, "Endpoint ID", u8); - rw_field!([3](24..=31), slot_id, "Slot ID", u8); + impl_ep_id!(); + impl_slot_id!(); } -impl_debug_for_trb!(SetTrDequeuePointer { +impl_debug_from_methods!(SetTrDequeuePointer { dequeue_cycle_state, stream_context_type, new_tr_dequeue_pointer, stream_id, endpoint_id, - slot_id + slot_id, }); - -add_trb_with_default!(ResetDevice, "Reset Device Command TRB", Type::ResetDevice); -reserved!(ResetDevice(Type::ResetDevice) { - [0]0..=31; - [1]0..=31; - [2]0..=31; - [3]1..=9; - [3]16..=23; +rsvdz_checking_try_from!(SetTrDequeuePointer { + [2];0..=15, + [3];1..=9, + [3];21..=23, }); + impl ResetDevice { - rw_field!([3](24..=31), slot_id, "Slot ID", u8); + impl_slot_id!(); } -impl_debug_for_trb!(ResetDevice { slot_id }); - -add_trb_with_default!(ForceEvent, "Force Event Command TRB", Type::ForceEvent); -reserved!(ForceEvent(Type::ForceEvent) { - [0]0..=3; - [2]0..=21; - [3]1..=9; - [3]24..=31; +impl_debug_from_methods!(ResetDevice { slot_id }); +rsvdz_checking_try_from!(ResetDevice { + [0];0..=31, + [1];0..=31, + [2];0..=31, + [3];1..=9, + [3];16..=23, }); -impl ForceEvent { - /// Sets the value of the Event TRB Pointer field. - /// - /// # Panics - /// - /// This method panics if the `p` is not 16-byte aligned. - pub fn set_event_trb_pointer(&mut self, p: u64) -> &mut Self { - assert_eq!(p % 16, 0, "The Event TRB Pointer must be 16-byte aligned."); - - let l = p.get_bits(0..32); - let u = p.get_bits(32..64); - - self.0[0] = l.try_into().unwrap(); - self.0[1] = u.try_into().unwrap(); - self - } - - /// Returns the value of the Event TRB Pointer field. - #[must_use] - pub fn event_trb_pointer(&self) -> u64 { - let l: u64 = self.0[0].into(); - let u: u64 = self.0[1].into(); - - (u << 32) | l - } +impl ForceEvent { + param_align_16!(event_trb_pointer, "Event TRB Pointer"); rw_field!( - [2](22..=31), + pub, self, + self.0.0[2]; 22..=31, vf_interrupter_target, "VF Interrupter Target", u16 ); - rw_field!([3](16..=23), vf_id, "VF ID", u8); + + impl_vf_id!(); } -impl_debug_for_trb!(ForceEvent { +impl_debug_from_methods!(ForceEvent { event_trb_pointer, vf_interrupter_target, vf_id }); - -add_trb_with_default!( - NegotiateBandwidth, - "Negotiate Bandwidth Command TRB", - Type::NegotiateBandwidth -); -reserved!(NegotiateBandwidth(Type::NegotiateBandwidth) { - [0]0..=31; - [1]0..=31; - [2]0..=31; - [3]1..=9; - [3]16..=23; +rsvdz_checking_try_from!(ForceEvent { + [0];0..=3, + [2];0..=21, + [3];1..=9, + [3];24..=31, }); + impl NegotiateBandwidth { - rw_field!([3](24..=31), slot_id, "Slot ID", u8); + impl_slot_id!(); } -impl_debug_for_trb!(NegotiateBandwidth { slot_id }); - -add_trb_with_default!( - SetLatencyToleranceValue, - "Set Latency Tolerance Value Command TRB", - Type::SetLatencyToleranceValue -); -reserved!(SetLatencyToleranceValue(Type::SetLatencyToleranceValue) { - [0]0..=31; - [1]0..=31; - [2]0..=31; - [3]1..=9; - [3]28..=31; +impl_debug_from_methods!(NegotiateBandwidth { slot_id }); +rsvdz_checking_try_from!(NegotiateBandwidth { + [0];0..=31, + [1];0..=31, + [2];0..=31, + [3];1..=9, + [3];16..=23, }); + impl SetLatencyToleranceValue { rw_field!( - [3](16..=27), + pub, self, + self.0.0[3]; 16..=27, best_effort_latency_tolerance_value, "Best Effort Latency Tolerance Value", u16 ); } -impl_debug_for_trb!(SetLatencyToleranceValue { - best_effort_latency_tolerance_value +impl_debug_from_methods!(SetLatencyToleranceValue { + best_effort_latency_tolerance_value, }); - -add_trb_with_default!( - GetPortBandwidth, - "Get Port Bandwidth Command TRB", - Type::GetPortBandwidth -); -reserved!(GetPortBandwidth(Type::GetPortBandwidth) { - [0]0..=3; - [2]0..=31; - [3]1..=9; - [3]20..=23; +rsvdz_checking_try_from!(SetLatencyToleranceValue { + [0];0..=31, + [1];0..=31, + [2];0..=31, + [3];1..=9, + [3];28..=31, }); -impl GetPortBandwidth { - /// Sets the value of the Port Bandwidth Context Pointer field. - /// - /// # Panics - /// - /// This method panics if the `p` is not 16-byte aligned. - pub fn set_port_bandwidth_context_pointer(&mut self, p: u64) -> &mut Self { - assert_eq!( - p % 16, - 0, - "The Port Bandwidth Context Pointer must be 16-byte aligned." - ); - - let l = p.get_bits(0..32); - let u = p.get_bits(32..64); - - self.0[0] = l.try_into().unwrap(); - self.0[1] = u.try_into().unwrap(); - self - } - /// Returns the value of the Port Bandwidth Context Pointer field. - #[must_use] - pub fn port_bandwidth_context_pointer(&self) -> u64 { - let l: u64 = self.0[0].into(); - let u: u64 = self.0[1].into(); +impl GetPortBandwidth { + param_align_16!( + port_bandwidth_context_pointer, + "Port Bandwidth Context Pointer" + ); - (u << 32) | l - } - rw_field!([3](16..=19), dev_speed, "Dev Speed", u8); - rw_field!([3](24..=31), hub_slot_id, "Hub Slot ID", u8); + rw_field!(pub, self, self.0.0[3]; 16..=19, dev_speed, "Dev Speed", u8); + rw_field!(pub, self, self.0.0[3]; 24..=31, hub_slot_id, "Hub Slot ID", u8); } -impl_debug_for_trb!(GetPortBandwidth { +impl_debug_from_methods!(GetPortBandwidth { port_bandwidth_context_pointer, dev_speed, hub_slot_id }); - -add_trb_with_default!(ForceHeader, "Force Header Command TRB", Type::ForceHeader); -reserved!(ForceHeader(Type::ForceHeader) { - [3]1..=9; - [3]16..=23; +rsvdz_checking_try_from!(GetPortBandwidth { + [0];0..=3, + [2];0..=31, + [3];1..=9, + [3];20..=23, }); + impl ForceHeader { - rw_field!([0](0..=4), packet_type, "Packet Type", u8); + rw_field!(pub, self, self.0.0[0]; 0..=4, packet_type, "Packet Type", u8); /// Sets the value of the Header Info field. /// /// # Panics /// - /// This method panics if the lowest 5 bits of the `i[0]` are not 0. + /// This method panics if the lowest 5 bits of the `info[0]` are not 0. pub fn set_header_info(&mut self, info: [u32; 3]) -> &mut Self { assert!( info[0].trailing_zeros() >= 5, "The lowest 5 bits of the Header Info Low must be 0." ); - self.0[0].set_bits(5..=31, info[0].get_bits(5..=31)); - self.0[1] = info[1]; - self.0[2] = info[2]; + self.0 .0[0].set_bits(5.., info[0].get_bits(5..)); + self.0 .0[1] = info[1]; + self.0 .0[2] = info[2]; self } /// Returns the value of the Header Info field. #[must_use] pub fn header_info(&self) -> [u32; 3] { - [self.0[0] & 0xffff_ffe0, self.0[1], self.0[2]] + [self.0 .0[0] >> 5 << 5, self.0 .0[1], self.0 .0[2]] } rw_field!( - [3](24..=31), + pub, self, + self.0.0[3]; 24..=31, root_hub_port_number, "Root Hub Port Number", u8 ); } -impl_debug_for_trb!(ForceHeader { +impl_debug_from_methods!(ForceHeader { packet_type, header_info, - root_hub_port_number + root_hub_port_number, }); - -add_trb_with_default!( - GetExtendedProperty, - "Get Extended Property Command TRB", - Type::GetExtendedProperty -); -reserved!(GetExtendedProperty(Type::GetExtendedProperty) { - [0]0..=3; - [2]16..=31; - [3]1..=9; +rsvdz_checking_try_from!(ForceHeader { + [3];1..=9, + [3];16..=23, }); -impl GetExtendedProperty { - /// Sets the value of the Extended Property Context Pointer field. - /// - /// # Panics - /// - /// This method panics if the `p` is not 16-byte aligned. - pub fn set_extended_property_context_pointer(&mut self, p: u64) -> &mut Self { - assert_eq!( - p % 16, - 0, - "The Extended Property Context Pointer must be 16-byte aligned." - ); - - let l = p.get_bits(0..32); - let u = p.get_bits(32..64); - - self.0[0] = l.try_into().unwrap(); - self.0[1] = u.try_into().unwrap(); - self - } - - /// Returns the value of the Extended Property Context Pointer field. - #[must_use] - pub fn extended_property_context_pointer(&self) -> u64 { - let l: u64 = self.0[0].into(); - let u: u64 = self.0[1].into(); - (u << 32) | l - } +impl GetExtendedProperty { + param_align_16!( + extended_property_context_pointer, + "Extended Property Context Pointer" + ); rw_field!( - [2](0..=15), + pub, self, + self.0.0[2]; 0..=15, extended_capability_identifier, "Extended Capability Identifier", u16 ); - rw_field!([3](16..=18), command_sub_type, "Command Sub Type", u8); - rw_field!([3](19..=23), endpoint_id, "Endpoint ID", u8); - rw_field!([3](24..=31), slot_id, "Slot ID", u8); + + impl_subtype!(); + impl_ep_id!(); + impl_slot_id!(); } -impl_debug_for_trb!(GetExtendedProperty { +impl_debug_from_methods!(GetExtendedProperty { extended_property_context_pointer, extended_capability_identifier, command_sub_type, endpoint_id, - slot_id + slot_id, }); - -add_trb_with_default!( - SetExtendedProperty, - "Set Extended Property Command TRB", - Type::SetExtendedProperty -); -reserved!(SetExtendedProperty(Type::SetExtendedProperty) { - [0]0..=31; - [1]0..=31; - [2]24..=31; - [3]1..=9; +rsvdz_checking_try_from!(GetExtendedProperty { + [0];0..=3, + [2];16..=31, + [3];1..=9, }); + impl SetExtendedProperty { rw_field!( - [2](0..=15), + pub, self, + self.0.0[2]; 0..=15, extended_capability_identifier, - "Extended Cpaability Identifier", + "Extended Capability Identifier", u16 ); rw_field!( - [2](16..=23), + pub, self, + self.0.0[2]; 16..=23, capability_parameter, "Capability Parameter", u8 ); - rw_field!([3](16..=18), command_sub_type, "Command Sub Type", u8); - rw_field!([3](19..=23), endpoint_id, "Endpoint ID", u8); - rw_field!([3](24..=31), slot_id, "Slot ID", u8); + + impl_subtype!(); + impl_ep_id!(); + impl_slot_id!(); } -impl_debug_for_trb!(SetExtendedProperty { +impl_debug_from_methods!(SetExtendedProperty { extended_capability_identifier, capability_parameter, command_sub_type, endpoint_id, - slot_id + slot_id, +}); +rsvdz_checking_try_from!(SetExtendedProperty { + [0];0..=3, + [2];16..=31, + [3];1..=9, }); diff --git a/src/ring/trb/event.rs b/src/ring/trb/event.rs index 200a045a..9e553766 100644 --- a/src/ring/trb/event.rs +++ b/src/ring/trb/event.rs @@ -1,259 +1,217 @@ //! Event TRBs. -use super::Type; use bit_field::BitField; -use core::convert::{TryFrom, TryInto}; +// use core::convert::TryInto; use num_derive::FromPrimitive; use num_traits::FromPrimitive; -allowed! { - /// TRBs which are allowed to be pushed to the Event Ring. - enum { - /// Transfer Event TRB. - TransferEvent, - /// Command Completion Event TRB. - CommandCompletion, - /// Port Status Change Event TRB. - PortStatusChange, - /// Bandwidth Request Event TRB. - BandwidthRequest, - /// Doorbell Event TRB. - Doorbell, - /// Host Controller Event TRB. - HostController, - /// Device Notification Event TRB. - DeviceNotification, - /// MFINDEX Wrap Event TRB. - MfindexWrap - } -} -impl TryFrom<[u32; 4]> for Allowed { - type Error = [u32; 4]; - - fn try_from(raw: [u32; 4]) -> Result { - try_from!( - raw => - TransferEvent, - CommandCompletion, - PortStatusChange, - BandwidthRequest, - Doorbell, - HostController, - DeviceNotification, - MfindexWrap, - ); - Err(raw) - } -} - -macro_rules! completion_code { - ($name:ident) => { - impl $name { - /// Returns the Completion Code. - /// - /// # Errors - /// - /// This method may return an [`Err`] value with the Completion Code that is either reserved or - /// not implemented by this crate. - pub fn completion_code(&self) -> Result { - let c: u8 = self.0[2].get_bits(24..=31).try_into().unwrap(); - CompletionCode::from_u8(c).ok_or(c) - } +macro_rules! impl_cc { + (ro) => { + /// Returns the Completion Code. + /// + /// # Errors + /// + /// This method may return an [`Err`] variant with the Completion Code that is either reserved or + /// not implemented in this crate. + pub fn completion_code(&self) -> Result { + let c: u8 = self.0 .0[2].get_bits(24..=31).try_into().unwrap(); + CompletionCode::from_u8(c).ok_or(c) } }; } -macro_rules! event { - ($name:ident,$full:expr,$ty:expr) => { - add_trb_with_default!($name, $full, $ty); - completion_code!($name); - }; -} -macro_rules! impl_debug_for_event_trb{ - ($name:ident{})=>{ - impl_debug_for_trb!($name{ - completion_code - }); - }; - ($name:ident { - $($method:ident),* - })=>{ - impl_debug_for_trb!($name{ - completion_code, - $($method),* - }); - } -} -event!( - PortStatusChange, - "Port Status Change Event TRB", - Type::PortStatusChange -); -reserved!(PortStatusChange(Type::PortStatusChange){ - [0]0..=23; - [1]0..=31; - [2]0..=23; - [3]1..=9; - [3]16..=31; +allowed_trb!("Transfer TRB", { + /// Transfer Event TRB + TransferEvent = 32, + /// Command Completion Event TRB + CommandCompletion = 33, + /// Port Status Change Event TRB + PortStatusChange = 34, + /// Bandwidth Request Event TRB + BandwidthRequest = 35, + /// Doorbell Event TRB + Doorbell = 36, + /// Host Controller Event TRB + HostController = 37, + /// Device Notification Event TRB + DeviceNotification = 38, + /// MFINDEX Wrap Event TRB + MfindexWrap = 39, }); -impl PortStatusChange { - ro_field!([0](24..=31), port_id, "Port ID", u8); -} -impl_debug_for_event_trb!(PortStatusChange { port_id }); -event!(TransferEvent, "Transfer Event TRB", Type::TransferEvent); -reserved!(TransferEvent(Type::TransferEvent){ - [3]1..=1; - [3]3..=9; - [3]21..=23; -}); impl TransferEvent { - /// Returns the value of the TRB Pointer field. - #[must_use] - pub fn trb_pointer(&self) -> u64 { - let l: u64 = self.0[0].into(); - let u: u64 = self.0[1].into(); + ro_double_field!(pub, self, self.0.0; [0, 1], trb_pointer, "TRB Pointer (or event data)", 32, u64); - (u << 32) | l - } + ro_field!(pub, self, self.0.0[2]; 0..=23, trb_transfer_length, "TRB Transfer Length", u32); + impl_cc!(ro); - ro_field!([2](0..=23), trb_transfer_length, "TRB Transfer Length", u32); - ro_bit!([3](2), event_data, "Event Data"); - ro_field!([3](16..=20), endpoint_id, "Endpoint ID", u8); - ro_field!([3](24..=31), slot_id, "Slot ID", u8); + ro_bit!(pub, self, self.0.0[3]; 2, event_data, "Event Data Flag"); + impl_ep_id!(ro); + impl_slot_id!(ro); } -impl_debug_for_event_trb!(TransferEvent { +impl_debug_from_methods!(TransferEvent { trb_pointer, trb_transfer_length, + completion_code, event_data, endpoint_id, - slot_id + slot_id, }); - -event!( - CommandCompletion, - "Command Completion Event TRB", - Type::CommandCompletion -); -reserved!(CommandCompletion(Type::CommandCompletion){ - [0]0..=3; - [3]1..=9; +rsvdz_checking_try_from!(TransferEvent { + [3];1..=1, + [3];3..=9, + [3];21..=23, }); -impl CommandCompletion { - /// Returns the value of the Command TRB Pointer field. - #[must_use] - pub fn command_trb_pointer(&self) -> u64 { - let l: u64 = self.0[0].into(); - let u: u64 = self.0[1].into(); - (u << 32) | l - } +impl CommandCompletion { + ro_double_field!( + pub, self, + self.0.0; [0, 1], + command_trb_pointer, + "Command TRB Pointer", + 32, u64 + ); ro_field!( - [2](0..=23), + pub, self, + self.0.0[2]; 0..=23, command_completion_parameter, "Command Completion Parameter", u32 ); - ro_field!([3](16..=23), vf_id, "VF ID", u8); - ro_field!([3](24..=31), slot_id, "Slot ID", u8); + impl_cc!(ro); + + impl_vf_id!(ro); + impl_slot_id!(ro); } -impl_debug_for_event_trb!(CommandCompletion { +impl_debug_from_methods!(CommandCompletion { command_trb_pointer, command_completion_parameter, + completion_code, vf_id, - slot_id + slot_id, +}); +rsvdz_checking_try_from!(CommandCompletion { + [0];0..=3, + [3];1..=9, }); -event!( - BandwidthRequest, - "Bandwidth Request Event TRB", - Type::BandwidthRequest -); -reserved!(BandwidthRequest(Type::BandwidthRequest){ - [0]0..=31; - [1]0..=31; - [2]0..=23; - [3]1..=9; - [3]16..=23; +impl PortStatusChange { + ro_field!(pub, self, self.0.0[0]; 24..=31, port_id, "Port ID", u8); + + impl_cc!(ro); +} +impl_debug_from_methods!(PortStatusChange { + port_id, + completion_code, }); +rsvdz_checking_try_from!(PortStatusChange { + [0];0..=23, + [1];0..=31, + [2];0..=23, + [3];1..=9, + [3];16..=31, +}); + impl BandwidthRequest { - ro_field!([3](24..=31), slot_id, "Slot ID", u8); -} -impl_debug_for_event_trb!(BandwidthRequest { slot_id }); + impl_cc!(ro); -event!(Doorbell, "Doorbell Event TRB", Type::Doorbell); -reserved!(Doorbell(Type::Doorbell){ - [0]5..=31; - [1]0..=31; - [2]0..=23; - [3]1..=9; + impl_slot_id!(ro); +} +impl_debug_from_methods!(BandwidthRequest { + completion_code, + slot_id, +}); +rsvdz_checking_try_from!(BandwidthRequest { + [0];0..=31, + [1];0..=31, + [2];0..=23, + [3];1..=9, + [3];16..=23, }); + impl Doorbell { - ro_field!([0](0..=4), db_reason, "DB Reason", u8); - ro_field!([3](16..=23), vf_id, "VF ID", u8); - ro_field!([3](24..=31), slot_id, "Slot ID", u8); + ro_field!(pub, self, self.0.0[0]; 0..=4, db_reason, "DB Reason", u8); + + impl_cc!(ro); + + impl_vf_id!(ro); + impl_slot_id!(ro); } -impl_debug_for_event_trb!(Doorbell { +impl_debug_from_methods!(Doorbell { db_reason, + completion_code, vf_id, - slot_id + slot_id, }); - -event!( - HostController, - "Host Controller Event TRB", - Type::HostController -); -reserved!(HostController(Type::HostController){ - [0]0..=31; - [1]0..=31; - [2]0..=23; - [3]1..=9; - [3]16..=31; +rsvdz_checking_try_from!(Doorbell { + [0];5..=31, + [1];0..=31, + [2];0..=23, + [3];1..=9, }); -impl_debug_for_event_trb!(HostController {}); -event!( - DeviceNotification, - "Device Notification Event TRB", - Type::DeviceNotification -); -reserved!(DeviceNotification(Type::DeviceNotification){ - [0]0..=31; - [1]0..=31; - [2]0..=23; - [3]1..=9; - [3]16..=31; +impl HostController { + impl_cc!(ro); +} +impl_debug_from_methods!(HostController { completion_code }); +rsvdz_checking_try_from!(HostController { + [0];0..=31, + [1];0..=31, + [2];0..=23, + [3];1..=9, + [3];16..=31, }); -impl DeviceNotification { - ro_field!([0](4..=7), notification_type, "Notification Type", u8); +impl DeviceNotification { + ro_field!( + pub, self, + self.0.0[0]; 4..=7, + notification_type, + "Notification Type", + u8 + ); + ro_double_field!( + pub(self), self, + self.0.0; [0, 1], + device_notification_data_raw, + "Device Notification Data Raw", + 32, u64 + ); /// Returns the value of the Device Notification Data field. #[must_use] pub fn device_notification_data(&self) -> u64 { - let l: u64 = self.0[0].get_bits(8..=31).into(); - let u: u64 = self.0[1].into(); - - ((u << 32) | l) >> 8 + self.device_notification_data_raw() >> 8 } - ro_field!([3](24..=31), slot_id, "Slot ID", u8); + impl_cc!(ro); + + impl_slot_id!(ro); } -impl_debug_for_event_trb!(DeviceNotification { +impl_debug_from_methods!(DeviceNotification { notification_type, device_notification_data, - slot_id + completion_code, + slot_id, +}); +rsvdz_checking_try_from!(DeviceNotification { + [0];0..=3, + [2];0..=23, + [3];1..=9, + [3];16..=31, }); -event!(MfindexWrap, "MFINDEX Wrap Event TRB", Type::MfindexWrap); -reserved!(MfindexWrap(Type::MfindexWrap){ - [0]0..=3; - [2]0..=23; - [3]1..=9; - [3]16..=23; +impl MfindexWrap { + impl_cc!(ro); +} +impl_debug_from_methods!(MfindexWrap { completion_code }); +rsvdz_checking_try_from!(MfindexWrap { + [0];0..=31, + [1];0..=31, + [2];0..=23, + [3];1..=9, + [3];16..=31, }); -impl_debug_for_event_trb!(MfindexWrap {}); /// The TRB Completion Codes. /// @@ -351,24 +309,3 @@ pub enum CompletionCode { /// Asserted if an error is detected on a USB2 protocol endpoint for a split transaction. SplitTransactionError = 36, } - -#[cfg(test)] -mod test { - use super::*; - - #[test] - fn try_from_macro() { - let raw = [ - 0x00c8_8800, // address low - 0x0000_0000, // address high - 0x01_000000, // completion code 1, transfer length 0 - 0x0000_8401, // endpoint id 0, slot id 0, type 33, event data 0, cycle bit 1 - ]; - assert_eq!( - Allowed::try_from(raw), - Ok(Allowed::CommandCompletion( - CommandCompletion::try_from(raw).unwrap() - )), - ); - } -} diff --git a/src/ring/trb/mod.rs b/src/ring/trb/mod.rs index 20fa883c..3f16d8df 100644 --- a/src/ring/trb/mod.rs +++ b/src/ring/trb/mod.rs @@ -1,316 +1,172 @@ //! TRB (Transfer Request Block). -use bit_field::BitField; -use core::convert::TryInto; -use num_derive::FromPrimitive; - -macro_rules! reserved{ - ($name:ident($ty:expr) { - $([$index:expr] $range:expr);* $(;)? - })=>{ - impl TryFrom<[u32; 4]> for $name{ - type Error=[u32; 4]; - - fn try_from(raw:[u32;4])->Result{ - use crate::ring::trb::Type; - - $(if raw[$index].get_bits($range) != 0{ - return Err(raw); - })* +/// The bytes of a TRB. +pub const BYTES: usize = 16; - if raw[3].get_bits(10..=15)!=$ty as _ { - return Err(raw); - } +macro_rules! param_align_16 { + ($method:ident,$name:literal) => { + rw_double_zero_trailing!( + pub, self, + self.0.0; [0, 1]; 4~; "16-byte aligned", + $method, $name, 32, u64 + ); + } +} - Ok(Self(raw)) - } - } +macro_rules! impl_ring_segment_pointer { + () => { + param_align_16!(ring_segment_pointer, "Ring Segment Pointer"); }; } -macro_rules! try_from { - ($raw:ident => $($name:ident $(($t:ident))?),* $(,)?) => {{ - if let Some(ty) = Type::from_u32($raw[3].get_bits(10..=15)) { - paste::paste! { - match ty { - $( - Type::[<$name $($t)?>]=> { - if let Ok(t) = $name::try_from($raw) { - return Ok(Self::$name(t)); - } - } - )* - _ => {} - } - } - } - }}; + +macro_rules! impl_tc { + () => { + rw_bit!(pub, self, self.0.0[3]; 1, toggle_cycle, "Toggle Cycle"); + } } -macro_rules! add_trb { - ($name:ident,$full:expr,$ty:expr) => { - #[doc = $full ] - #[repr(transparent)] - #[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)] - pub struct $name([u32; 4]); - impl $name { - /// Returns the wrapped array. - #[must_use] - pub fn into_raw(self) -> [u32; 4] { - self.0 - } - rw_bit!([3](0), cycle_bit, "Cycle bit"); +macro_rules! impl_ioc { + () => { + rw_bit!( + pub, self, + self.0.0[3]; 5, + interrupt_on_completion, + "Interrupt On Completion" + ); + } +} - fn set_trb_type(&mut self) -> &mut Self { - use crate::ring::trb::Type; - use bit_field::BitField; - self.0[3].set_bits(10..=15, $ty as _); - self - } - } - impl AsRef<[u32]> for $name { - fn as_ref(&self) -> &[u32] { - &self.0 - } - } - impl From<$name> for [u32; 4] { - fn from(t: $name) -> Self { - t.0 - } - } +macro_rules! impl_ep_id { + () => { + rw_field!(pub, self, self.0.0[3]; 16..=20, endpoint_id, "Endpoint ID", u8); }; -} -macro_rules! impl_default_simply_adds_trb_id { - ($name:ident,$full:expr) => { - impl $name{ - paste::paste! { - #[doc = "Creates a new " $full ".\n\nThis method sets the sets the value of the TRB Type field properly. All the other fieldds are set to 0."] - #[must_use] - pub fn new()->Self{ - *Self([0;4]).set_trb_type() - } - } - } - impl Default for $name { - fn default() -> Self { - Self::new() - } - } + (ro) => { + ro_field!(pub, self, self.0.0[3]; 16..=20, endpoint_id, "Endpoint ID", u8); }; } -macro_rules! add_trb_with_default { - ($name:ident,$full:expr,$type:expr) => { - add_trb!($name, $full, $type); - impl_default_simply_adds_trb_id!($name, $full); + +macro_rules! impl_vf_id { + () => { + rw_field!(pub, self, self.0.0[3]; 16..=23, vf_id, "VF ID", u8); + }; + (ro) => { + ro_field!(pub, self, self.0.0[3]; 16..=23, vf_id, "VF ID", u8); }; } -macro_rules! impl_debug_for_trb{ - ($name:ident { - $($method:ident),* - })=>{ - impl_debug_from_methods!{ - $name { - $($method,)* - cycle_bit - } - } - } + +macro_rules! impl_slot_id { + () => { + rw_field!(pub, self, self.0.0[3]; 24..=31, slot_id, "Slot ID", u8); + }; + (ro) => { + ro_field!(pub, self, self.0.0[3]; 24..=31, slot_id, "Slot ID", u8); + }; } -macro_rules! allowed { - ( - $(#[$outer:meta])* - enum { - $($(#[$doc:meta])* $variant:ident),+ - } - ) => { - $(#[$outer])* - #[derive(Copy, Clone, Debug, Ord, PartialOrd, Eq, PartialEq, Hash)] - pub enum Allowed { - $($(#[$doc])* $variant($variant)),+ +macro_rules! allowed_trb { + ($name:literal, { + $($(#[$docs:meta])* $($deco:literal)? $variant:ident = $val:literal),+ $(,)? + }) => { + // defining AllowedType + paste::paste!( + #[doc = "Allowed TRB Type for " $name "."] + #[derive(Copy, Clone, Debug, Ord, PartialOrd, Eq, PartialEq, Hash, FromPrimitive)] + pub enum AllowedType { + $( + $(#[$docs])* + #[doc = ", " $val ""] + $variant = $val + ),+ } - impl Allowed{ - /// Sets the value of the Cycle Bit. - pub fn set_cycle_bit(&mut self)->&mut Self{ - match self{ - $( - Self::$variant(ref mut v) => { - v.set_cycle_bit(); - } - ),+ + ); + + // defining common block + paste::paste!( + #[doc = "A raw " $name " Block."] + #[repr(transparent)] + #[derive(Clone, Copy, Debug, PartialEq, Eq, Default, Hash)] + pub struct TRB(pub(crate) [u32; 4]); + impl TRB { + pub(crate) fn new(ty: AllowedType) -> Self { + *Self([0; 4]) + .set_trb_type(ty) + } + + pub(crate) fn trb_type(&self) -> Option { + AllowedType::from_u32(self.0[3].get_bits(10..=15)) } - self - } - /// Clears the value of the Cycle Bit. - pub fn clear_cycle_bit(&mut self)->&mut Self{ - match self{ - $( - Self::$variant(ref mut v) => { - v.clear_cycle_bit(); - } - ),+ + fn set_trb_type(&mut self, ty: AllowedType) -> &mut Self { + self.0[3].set_bits(10..=15, ty as u32); + self } - self + + rw_bit!(pub, self, self.0[3]; 0, cycle_bit, "Cycle"); } + ); - /// Returns the value of the Cycle Bit. - #[must_use] - pub fn cycle_bit(&self)->bool{ - match self{ - $( Self::$variant(ref v) => v.cycle_bit() ),+ + // defining individual TRB types + // all TRB types require `Self::new()`. Derive by simple default or manually implement it. + $( + paste::paste! { + $(#[$docs])* + #[doc = "."] + #[repr(transparent)] + #[derive(Clone, Copy, PartialEq, Eq, Hash)] + pub struct $variant(TRB); + + impl From<$variant> for TRB { + fn from(v: $variant) -> Self { + v.0 + } } + + impl Default for $variant { + fn default() -> Self { + Self::new() + } + } + + simple_default!($(#[$docs])* $($deco)? $variant); // this branches whether $def is "default" or empty. } + )+ + } +} - /// Returns the wrapped array. +macro_rules! simple_default { + ($(#[$docs:meta])* $variant:ident) => { + impl $variant{ + #[doc = "Creates a new "] + $(#[$docs])* + #[doc = ".\n\nThis method sets the value of the TRB Type field properly. "] + #[doc = "All the other fields are set to 0."] #[must_use] - pub fn into_raw(self)->[u32;4]{ - match self{ - $( Self::$variant(v) => v.into_raw() ),+ - } + pub fn new() -> Self{ + Self(TRB::new(AllowedType::$variant)) } } - impl AsRef<[u32]> for Allowed { - fn as_ref(&self) -> &[u32]{ - match self{ - $( Self::$variant(ref v) => v.as_ref() ),+ + }; + ($(#[$docs:meta])* "no-new" $variant:ident) => {}; +} + +macro_rules! rsvdz_checking_try_from { + ($name:ident { + $([$index:expr];$range:expr),* $(,)? + }) => { + impl TryFrom for $name { + type Error = TRB; + + fn try_from(block: TRB) -> Result { + if block.trb_type() != Some(AllowedType::$name) + $(|| block.0[$index].get_bits($range) != 0 )* { + return Err(block); } + Ok(Self(block)) } } - $( - impl From<$variant> for Allowed{ - fn from(v:$variant)->Self{ - Self::$variant(v) - } - } - )+ - }; + } } pub mod command; pub mod event; pub mod transfer; - -/// The bytes of a TRB. -pub const BYTES: usize = 16; - -add_trb_with_default!(Link, "Link TRB", Type::Link); -reserved!(Link(Type::Link){ - [0]0..=3; - [2]0..=21; - [3]2..=3; - [3]6..=9; - [3]16..=31; -}); -impl Link { - /// Sets the value of the Ring Segment Pointer field. - /// - /// # Panics - /// - /// This method panics if `p` is not 16-byte aligned. - pub fn set_ring_segment_pointer(&mut self, p: u64) -> &mut Self { - assert_eq!( - p % 16, - 0, - "The Ring Segment Pointer must be 16-byte aligned." - ); - - let l = p.get_bits(0..32); - let u = p.get_bits(32..64); - - self.0[0] = l.try_into().unwrap(); - self.0[1] = u.try_into().unwrap(); - self - } - - /// Returns the value of the Ring Segment Pointer field. - #[must_use] - pub fn ring_segment_pointer(&self) -> u64 { - let l: u64 = self.0[0].into(); - let u: u64 = self.0[1].into(); - - (u << 32) | l - } - - rw_field!([2](22..=31), interrupter_target, "Interrupter Target", u32); - rw_bit!([3](1), toggle_cycle, "Toggle Cycle"); - rw_bit!([3](4), chain_bit, "Chain bit"); - rw_bit!([3](5), interrupt_on_completion, "Interrupt On Completion"); -} -impl_debug_for_trb!(Link { - ring_segment_pointer, - interrupter_target, - toggle_cycle, - chain_bit, - interrupt_on_completion -}); - -/// TRB Type. -#[derive(Copy, Clone, Debug, Ord, PartialOrd, Eq, PartialEq, Hash, FromPrimitive)] -pub enum Type { - /// Normal TRB, 1 - Normal = 1, - /// Setup Stage TRB, 2 - SetupStage = 2, - /// Data Stage TRB, 3 - DataStage = 3, - /// Status Stage TRB, 4 - StatusStage = 4, - /// Isoch TRB, 5 - Isoch = 5, - /// Link TRB, 6 - Link = 6, - /// Event Data TRB, 7 - EventData = 7, - /// No Op TRB (Transfer), 8 - NoopTransfer = 8, - /// Enable Slot Command TRB, 9 - EnableSlot = 9, - /// Disable Slot Command TRB, 10 - DisableSlot = 10, - /// Address Device Command TRB, 11 - AddressDevice = 11, - /// Configure Endpoint Command TRB, 12 - ConfigureEndpoint = 12, - /// Evaluate Context Command TRB, 13 - EvaluateContext = 13, - /// Reset Endpoint Command TRB, 14 - ResetEndpoint = 14, - /// Stop Endpoint Command TRB, 15 - StopEndpoint = 15, - /// Set TR Dequeue Pointer Command TRB, 16 - SetTrDequeuePointer = 16, - /// Reset Device Command TRB, 17 - ResetDevice = 17, - /// Force Event Command TRB, 18 - ForceEvent = 18, - /// Negotiate Bandwidth Command TRB, 19 - NegotiateBandwidth = 19, - /// Set Latency Tolerance Value Command TRB, 20 - SetLatencyToleranceValue = 20, - /// Get Port Bandwidth Command TRB, 21 - GetPortBandwidth = 21, - /// Force Header Command TRB, 22 - ForceHeader = 22, - /// No Op Command TRB, 23 - NoopCommand = 23, - /// Get Extended Property Command TRB, 24 - GetExtendedProperty = 24, - /// Set Extended Property Command TRB, 25 - SetExtendedProperty = 25, - /// Transfer Event TRB, 32 - TransferEvent = 32, - /// Command Completion Event TRB, 33 - CommandCompletion = 33, - /// Port Status Change Event TRB, 34 - PortStatusChange = 34, - /// Bandwidth Request Event TRB, 35 - BandwidthRequest = 35, - /// Doorbell Event TRB, 36 - Doorbell = 36, - /// Host Controller Event TRB, 37 - HostController = 37, - /// Device Notification Event TRB, 38 - DeviceNotification = 38, - /// MFINDEX Wrap Event TRB, 39 - MfindexWrap = 39, -} diff --git a/src/ring/trb/transfer.rs b/src/ring/trb/transfer.rs index 87a1a4fb..e6bf364d 100644 --- a/src/ring/trb/transfer.rs +++ b/src/ring/trb/transfer.rs @@ -1,246 +1,169 @@ //! Transfer TRBs. -use super::{Link, Type}; use bit_field::BitField; -use core::convert::TryInto; +// use core::convert::TryInto; use num_derive::FromPrimitive; use num_traits::FromPrimitive; -allowed! { - /// TRBs which are allowed to be pushed to the Transfer Ring. - enum { - /// Normal TRB. - Normal, - /// Setup Stage TRB. - SetupStage, - /// Data Stage TRB. - DataStage, - /// Status Stage TRB. - StatusStage, - /// Isoch TRB. - Isoch, - /// Link TRB. - Link, - /// Event Data TRB. - EventData, - /// No Op TRB. - Noop - } -} -impl Allowed { - /// Sets the value of the Interrupt On Completion field. - pub fn set_interrupt_on_completion(&mut self) { - macro_rules! arm{ - ($($variant:ident),*)=>{ - match self { - $(Self::$variant(ref mut x)=>{ - x.set_interrupt_on_completion(); - },)* - } - }; - } - - arm!( - Normal, - SetupStage, - DataStage, - StatusStage, - Isoch, - Link, - EventData, - Noop +macro_rules! impl_data_buffer_pointer { + () => { + rw_double_field!( + pub, self, + self.0.0; [0, 1], + data_buffer_pointer, + "Data Buffer Pointer", + 32, u64 ); } +} - /// Clears the Interrupt On Completion bit. - pub fn clear_interrupt_on_completion(&mut self) { - macro_rules! arm{ - ($($variant:ident),*)=>{ - match self { - $(Self::$variant(ref mut x)=>{ - x.clear_interrupt_on_completion(); - },)* - } - }; - } - - arm!( - Normal, - SetupStage, - DataStage, - StatusStage, - Isoch, - Link, - EventData, - Noop - ); - } +// 17-bit trb transfer length only. +macro_rules! impl_trb_transfer_length { + () => { + rw_field!(pub, self, self.0.0[2]; 0..=16, trb_transfer_length, "TRB Transfer Length", u32); + }; + (prv) => { + rw_field!(pub(self), self, self.0.0[2]; 0..=16, trb_transfer_length, "TRB Transfer Length", u32); + }; +} - /// Returns the value of the Interrupt On Completion field. - #[must_use] - pub fn interrupt_on_completion(&self) -> bool { - macro_rules! arm{ - ($($variant:ident),*)=>{ - match self { - $(Self::$variant(x)=>{ - x.interrupt_on_completion() - },)* - } - }; - } +macro_rules! impl_td_size { + () => { + rw_field!(pub, self, self.0.0[2]; 17..=21, td_size, "TD Size", u8); + }; +} - arm!( - Normal, - SetupStage, - DataStage, - StatusStage, - Isoch, - Link, - EventData, - Noop - ) - } +macro_rules! impl_interrupter_target { + () => { + rw_field!(pub, self, self.0.0[2]; 22..=31, interrupter_target, "Interrupter Target", u16); + }; } -impl TryFrom<[u32; 4]> for Allowed { - type Error = [u32; 4]; - fn try_from(raw: [u32; 4]) -> Result { - try_from!( - raw => - Normal, - SetupStage, - DataStage, - StatusStage, - Isoch, - Link, - EventData, - Noop(Transfer), +macro_rules! impl_ent { + () => { + rw_bit!(pub, self, self.0.0[3]; 1, evaluate_next_trb, "Evaluate Next TRB"); + }; +} +macro_rules! impl_isp { + () => { + rw_bit!( + pub, self, + self.0.0[3]; 2, + interrupt_on_short_packet, + "Interrupt on Short Packet" ); - Err(raw) - } + }; } - -macro_rules! interrupt_on_completion { - ($name:ident) => { - impl $name { - rw_bit!([3](5), interrupt_on_completion, "Interrupt On Completion"); - } +macro_rules! impl_ns { + () => { + rw_bit!(pub, self, self.0.0[3]; 3, no_snoop, "No Snoop"); }; } -macro_rules! transfer_trb { - ($name:ident,$full:expr,$type:expr) => { - add_trb!($name, $full, $type); - interrupt_on_completion!($name); +macro_rules! impl_ch { + () => { + rw_bit!(pub, self, self.0.0[3]; 4, chain_bit, "Chain"); }; } -macro_rules! transfer_trb_with_default { - ($name:ident,$full:expr,$type:expr) => { - add_trb_with_default!($name, $full, $type); - interrupt_on_completion!($name); +macro_rules! impl_idt { + () => { + rw_bit!(pub, self, self.0.0[3]; 6, immediate_data, "Immediate Data"); + }; + (prv) => { + rw1s_bit!(pub(self), self, self.0.0[3]; 6, immediate_data, "Immediate Data"); }; } -macro_rules! impl_debug_for_transfer_trb{ - ($name:ident {})=>{ - impl_debug_for_trb!($name{ - interrupt_on_completion - }); +macro_rules! impl_bei { + () => { + rw_bit!(pub, self, self.0.0[3]; 9, block_event_interrupt, "Block Event Interrupt"); }; - ($name:ident { - $($method:ident),*$(,)? - })=>{ - impl_debug_for_trb!($name{ - interrupt_on_completion, - $($method),* - }); +} +macro_rules! impl_dir { + () => { + rw_bit!(pub, self, self.0.0[3]; 16, direction, "Direction (is-in)"); } } -transfer_trb_with_default!(Normal, "Normal TRB", Type::Normal); -reserved!(Normal(Type::Normal) { - [3]7..=8; - [3]16..=31; +allowed_trb!("Transfer TRB", { + /// Normal TRB + Normal = 1, + /// Setup Stage TRB + "no-new" SetupStage = 2, + /// Data Stage TRB + DataStage = 3, + /// Status Stage TRB + StatusStage = 4, + /// Isoch TRB + Isoch = 5, + /// Link TRB + Link = 6, + /// Event Data TRB + EventData = 7, + /// No Op Transfer TRB + NoOp = 8, }); -impl Normal { - /// Sets the value of the Data Buffer Pointer field. - pub fn set_data_buffer_pointer(&mut self, p: u64) -> &mut Self { - let l = p.get_bits(0..32); - let u = p.get_bits(32..64); - - self.0[0] = l.try_into().unwrap(); - self.0[1] = u.try_into().unwrap(); - self - } - - /// Returns the value of the Data Buffer Pointer field. - #[must_use] - pub fn data_buffer_pointer(&self) -> u64 { - let l: u64 = self.0[0].into(); - let u: u64 = self.0[1].into(); - - (u << 32) | l - } - - rw_field!([2](0..=16), trb_transfer_length, "TRB Transfer Length", u32); - rw_field!([2](17..=21), td_size, "TD Size", u8); - rw_field!([2](22..=31), interrupter_target, "Interrupter Target", u16); - rw_bit!([3](1), evaluate_next_trb, "Evaluate Next TRB"); - rw_bit!( - [3](2), - interrupt_on_short_packet, - "Interrupt-on Short Packet" - ); - rw_bit!([3](3), no_snoop, "No Snoop"); - rw_bit!([3](4), chain_bit, "Chain bit"); - rw_bit!([3](6), immediate_data, "Immediate Data"); - rw_bit!([3](9), block_event_interrupt, "Block Event Interrupt"); -} -impl_debug_for_transfer_trb! { - Normal { - data_buffer_pointer, - trb_transfer_length, - td_size, - interrupter_target, - cycle_bit, - evaluate_next_trb, - interrupt_on_short_packet, - no_snoop, - chain_bit, - interrupt_on_completion, - immediate_data, - block_event_interrupt, - } +impl TRB { + ro_bit!(pub, self, self.0[3]; 4, chain_bit, "Chain"); } -transfer_trb!(SetupStage, "Setup Stage TRB", Type::SetupStage); -reserved!(SetupStage(Type::SetupStage) { - [2]17..=21; - [3]1..=4; - [3]7..=9; - [3]18..=31; +impl Normal { + impl_data_buffer_pointer!(); + + impl_trb_transfer_length!(); + impl_td_size!(); + impl_interrupter_target!(); + + impl_ent!(); + impl_isp!(); + impl_ns!(); + impl_ch!(); + impl_ioc!(); + impl_idt!(); + impl_bei!(); +} +impl_debug_from_methods!(Normal { + data_buffer_pointer, + trb_transfer_length, + td_size, + interrupter_target, + evaluate_next_trb, + interrupt_on_short_packet, + no_snoop, + chain_bit, + interrupt_on_completion, + immediate_data, + block_event_interrupt, }); +rsvdz_checking_try_from!(Normal { + [3];7..=8, + [3];16..=31, +}); + impl SetupStage { /// Creates a new Setup Stage TRB. /// - /// This method sets the value of the TRB Type, TRB Transfer Length, and the Immediate Data field properly. All the - /// other fields are set to 0. + /// This method sets the value of the TRB Type, TRB Transfer Length, and the Immediate Data field properly. All the other fields are set to 0. #[must_use] pub fn new() -> Self { - *Self([0; 4]) - .set_trb_type() - .set_idt() - .set_trb_transfer_length() + *Self(TRB::new(AllowedType::SetupStage)) + .set_immediate_data() + .set_trb_transfer_length(8) } - rw_field!([0](0..=7), request_type, "bmRequestType", u8); - rw_field!([0](8..=15), request, "bRequest", u8); - rw_field!([0](16..=31), value, "wValue", u16); - rw_field!([1](0..=15), index, "wIndex", u16); - rw_field!([1](16..=31), length, "wLength", u16); - rw_field!([2](22..=31), interrupter_target, "Interrupter Target", u16); + rw_field!(pub, self, self.0.0[0]; 0..=7, request_type, "bmRequestType", u8); + rw_field!(pub, self, self.0.0[0]; 8..=15, request, "bRequest", u8); + rw_field!(pub, self, self.0.0[0]; 16..=31, value, "wValue", u16); + rw_field!(pub, self, self.0.0[1]; 0..=15, index, "wIndex", u16); + rw_field!(pub, self, self.0.0[1]; 16..=31, length, "wLength", u16); + + impl_trb_transfer_length!(prv); + impl_interrupter_target!(); + + impl_ioc!(); + impl_idt!(prv); /// Sets the value of the Transfer Type field. pub fn set_transfer_type(&mut self, t: TransferType) -> &mut Self { - self.0[3].set_bits(16..=17, t as _); + self.0 .0[3].set_bits(16..=17, t as _); self } @@ -251,85 +174,45 @@ impl SetupStage { /// This method panics if the Transfer Type field contains 1 which is reserved. #[must_use] pub fn transfer_type(&self) -> TransferType { - FromPrimitive::from_u32(self.0[3].get_bits(16..=17)).expect("Transfer Type 1 is reserved.") - } - - fn set_idt(&mut self) -> &mut Self { - self.0[3].set_bit(6, true); - self - } - - fn set_trb_transfer_length(&mut self) -> &mut Self { - self.0[2].set_bits(0..=16, 8); - self - } -} -impl Default for SetupStage { - fn default() -> Self { - Self::new() + FromPrimitive::from_u32(self.0 .0[3].get_bits(16..=17)) + .expect("Transfer Type 1 is reserved.") } } -impl_debug_for_transfer_trb!(SetupStage { +impl_debug_from_methods!(SetupStage { request_type, request, value, index, length, + trb_transfer_length, + interrupter_target, interrupt_on_completion, + immediate_data, // always true transfer_type, }); - -transfer_trb_with_default!(DataStage, "Data Stage TRB", Type::DataStage); -reserved!(DataStage(Type::DataStage) { - [3]7..=9; - [3]17..=31; +rsvdz_checking_try_from!(SetupStage { // this won't check IDT and transfer length field. + [2];17..=21, + [3];1..=4, + [3];7..=9, + [3];18..=31, }); -impl DataStage { - /// Sets the value of the Data Buffer Pointer field. - pub fn set_data_buffer_pointer(&mut self, p: u64) -> &mut Self { - let l = p.get_bits(0..32); - let u = p.get_bits(32..64); - - self.0[0] = l.try_into().unwrap(); - self.0[1] = u.try_into().unwrap(); - self - } - - /// Returns the value of the Data Buffer Pointer field. - #[must_use] - pub fn data_buffer_pointer(&self) -> u64 { - let l: u64 = self.0[0].into(); - let u: u64 = self.0[1].into(); - - (u << 32) | l - } - - rw_field!([2](0..=16), trb_transfer_length, "TRB Transfer Length", u32); - rw_field!([2](17..=21), td_size, "TD Size", u8); - rw_field!([2](22..=31), interrupter_target, "Interrupter Target", u16); - rw_bit!([3](1), evaluate_next_trb, "Evaluate Next TRB"); - rw_bit!( - [3](2), - interrupt_on_short_packet, - "Interrupt-on Short Packet" - ); - rw_bit!([3](3), no_snoop, "No Snoop"); - rw_bit!([3](4), chain_bit, "Chain bit"); - rw_bit!([3](6), immediate_data, "Immediate Data"); - /// Sets the value of the Direction field. - pub fn set_direction(&mut self, d: Direction) -> &mut Self { - self.0[3].set_bit(16, d.into()); - self - } - - /// Returns the value of the Direction field. - #[must_use] - pub fn direction(&self) -> Direction { - self.0[3].get_bit(16).into() - } +impl DataStage { + impl_data_buffer_pointer!(); + + impl_trb_transfer_length!(); + impl_td_size!(); + impl_interrupter_target!(); + + impl_ent!(); + impl_isp!(); + impl_ns!(); + impl_ch!(); + impl_ioc!(); + impl_idt!(); + impl_dir!(); } -impl_debug_for_transfer_trb!(DataStage { +impl_debug_from_methods!(DataStage { data_buffer_pointer, trb_transfer_length, td_size, @@ -340,80 +223,63 @@ impl_debug_for_transfer_trb!(DataStage { chain_bit, interrupt_on_completion, immediate_data, - direction + direction, }); - -transfer_trb_with_default!(StatusStage, "Status Stage TRB", Type::StatusStage); -reserved!(StatusStage(Type::StatusStage) { - [0]0..=31; - [1]0..=31; - [2]0..=21; - [3]2..=3; - [3]6..=9; - [3]17..=31; +rsvdz_checking_try_from!(DataStage { + [3];7..=9, + [3];17..=31, }); + impl StatusStage { - rw_field!([2](22..=31), interrupter_target, "Interrupter Target", u16); - rw_bit!([3](1), evaluate_next_trb, "Evaluate Next TRB"); - rw_bit!([3](4), chain_bit, "Chain bit"); - rw_bit!([3](16), direction, "Direction"); -} -impl_debug_for_transfer_trb! { - StatusStage { - interrupter_target, - evaluate_next_trb, - chain_bit, - interrupt_on_completion, - direction, - } + impl_interrupter_target!(); + + impl_ent!(); + impl_ch!(); + impl_ioc!(); + impl_dir!(); } +impl_debug_from_methods!(StatusStage { + interrupter_target, + evaluate_next_trb, + chain_bit, + interrupt_on_completion, + direction, +}); +rsvdz_checking_try_from!(StatusStage { + [0];0..=31, + [1];0..=31, + [2];0..=21, + [3];2..=3, + [3];6..=9, + [3];17..=31, +}); -transfer_trb_with_default!(Isoch, "Isoch TRB", Type::Isoch); -reserved!(Isoch(Type::Isoch) {}); impl Isoch { - /// Sets the value of the Data Buffer Pointer. - pub fn set_data_buffer_pointer(&mut self, p: u64) -> &mut Self { - let l = p.get_bits(0..32); - let u = p.get_bits(32..64); - - self.0[0] = l.try_into().unwrap(); - self.0[1] = u.try_into().unwrap(); - self - } - - /// Returns the value of the Data Buffer Pointer. - #[must_use] - pub fn data_buffer_pointer(&self) -> u64 { - let l: u64 = self.0[0].into(); - let u: u64 = self.0[1].into(); - - (u << 32) | l - } - - rw_field!([2](0..=16), trb_transfer_length, "TRB Transfer Length", u32); - rw_field!([2](17..=21), td_size_or_tbc, "TD Size/TBC", u8); - rw_field!([2](22..=31), interrupter_target, "Interrupter Target", u16); - rw_bit!([3](1), evaluate_next_trb, "Evaluate Next TRB"); - rw_bit!( - [3](2), - interrupt_on_short_packet, - "Interrupt on Short Packet" - ); - rw_bit!([3](3), no_snoop, "No Snoop"); - rw_bit!([3](4), chain_bit, "Chain bit"); - rw_bit!([3](6), immediate_data, "Immediate Data"); - rw_field!([3](7..=8), transfer_burst_count, "Transfer Burst Count", u8); - rw_bit!([3](9), block_event_interrupt, "Block Event Interrupt"); + impl_data_buffer_pointer!(); + + impl_trb_transfer_length!(); + rw_field!(pub, self, self.0.0[2]; 17..=21, td_size_or_tbc, "TD Size/TBC", u8); + impl_interrupter_target!(); + + impl_ent!(); + impl_isp!(); + impl_ns!(); + impl_ch!(); + impl_ioc!(); + impl_idt!(); + rw_field!(pub, self, self.0.0[3]; 7..=8, tbc_or_sts, "TBC/TRBSts", u8); + impl_bei!(); rw_field!( - [3](16..=19), + pub, self, + self.0.0[3]; 16..=19, transfer_last_burst_packet_count, "Transfer Last Burst Packet Count", u8 ); - rw_field!([3](20..=30), frame_id, "Frame ID", u16); - rw_bit!([3](31), start_isoch_asap, "Start Isoch ASAP"); + rw_field!(pub, self, self.0.0[3]; 20..=30, frame_id, "Frame ID", u16); + rw_bit!(pub, self, self.0.0[3]; 31, start_isoch_asap, "Start Isoch ASAP"); } -impl_debug_for_transfer_trb!(Isoch { +impl_debug_from_methods!(Isoch { data_buffer_pointer, trb_transfer_length, td_size_or_tbc, @@ -422,99 +288,89 @@ impl_debug_for_transfer_trb!(Isoch { interrupt_on_short_packet, no_snoop, chain_bit, + interrupt_on_completion, immediate_data, - transfer_burst_count, + tbc_or_sts, block_event_interrupt, transfer_last_burst_packet_count, frame_id, - start_isoch_asap + start_isoch_asap, }); +rsvdz_checking_try_from!(Isoch {}); -transfer_trb_with_default!(EventData, "Event Data TRB", Type::EventData); -reserved!(EventData(Type::EventData) { - [2]0..=21; - [3]2..=3; - [3]6..=8; - [3]16..=31; -}); -impl EventData { - /// Sets the value of the Event Data field. - pub fn set_event_data(&mut self, d: u64) -> &mut Self { - let l = d.get_bits(0..32); - let u = d.get_bits(32..64); +impl Link { + impl_ring_segment_pointer!(); - self.0[0] = l.try_into().unwrap(); - self.0[1] = u.try_into().unwrap(); - self - } + impl_interrupter_target!(); - /// Returns the value of the Event Data field. - #[must_use] - pub fn event_data(&self) -> u64 { - let l: u64 = self.0[0].into(); - let u: u64 = self.0[1].into(); - - (u << 32) | l - } + impl_tc!(); + impl_ch!(); + impl_ioc!(); +} +rsvdz_checking_try_from!(Link { + [0];0..=3, + [2];0..=21, + [3];2..=3, + [3];6..=9, + [3];16..=31, +}); +impl_debug_from_methods!(Link { + ring_segment_pointer, + interrupter_target, + toggle_cycle, + chain_bit, + interrupt_on_completion, +}); - rw_field!([2](22..=31), interrupter_target, "Interrupter Target", u16); - rw_bit!([3](1), evaluate_next_trb, "Evaluate Next TRB"); - rw_bit!([3](4), chain_bit, "Chain bit"); - rw_bit!([3](9), block_event_interrupt, "Block Event Interrupt"); +impl EventData { + rw_double_field!( + pub, self, + self.0.0; [0, 1], + event_data, + "Event Data", + 32, u64 + ); + impl_interrupter_target!(); + impl_ent!(); + impl_ch!(); + impl_ioc!(); + impl_bei!(); } -impl_debug_for_transfer_trb!(EventData { +impl_debug_from_methods!(EventData { event_data, interrupter_target, evaluate_next_trb, chain_bit, - block_event_interrupt + interrupt_on_completion, + block_event_interrupt, }); - -transfer_trb_with_default!(Noop, "No Op TRB", Type::NoopTransfer); -reserved!(Noop(Type::NoopTransfer) { - [0]0..=31; - [1]0..=31; - [2]0..=21; - [3]2..=3; - [3]6..=9; - [3]16..=31; +rsvdz_checking_try_from!(EventData { + [2];0..=21, + [3];2..=3, + [3];6..=8, + [3];16..=31, }); -impl Noop { - rw_field!([2](22..=31), interrupter_target, "Interrupter Target", u16); - rw_bit!([3](1), evaluate_next_trb, "Evaluate Next TRB"); - rw_bit!([3](4), chain_bit, "Chain bit"); + +impl NoOp { + impl_interrupter_target!(); + impl_ent!(); + impl_ch!(); + impl_ioc!(); } -impl_debug_for_transfer_trb!(Noop { +impl_debug_from_methods!(NoOp { interrupter_target, evaluate_next_trb, - chain_bit + chain_bit, + interrupt_on_completion, +}); +rsvdz_checking_try_from!(NoOp { + [0];0..=31, + [1];0..=31, + [2];0..=21, + [3];2..=3, + [3];6..=9, + [3];16..=31, }); - -/// The direction of the data transfer. -#[derive(Copy, Clone, Debug, Ord, PartialOrd, Eq, PartialEq, Hash, FromPrimitive)] -pub enum Direction { - /// Out (Write Data) - Out = 0, - /// In (Read Data) - In = 1, -} -impl From for bool { - fn from(d: Direction) -> Self { - match d { - Direction::Out => false, - Direction::In => true, - } - } -} -impl From for Direction { - fn from(b: bool) -> Self { - if b { - Direction::In - } else { - Direction::Out - } - } -} /// Transfer Type. #[derive(Copy, Clone, Debug, Ord, PartialOrd, Eq, PartialEq, Hash, FromPrimitive)] @@ -527,26 +383,3 @@ pub enum TransferType { /// In Data Stage. In = 3, } - -#[cfg(test)] -mod test { - use super::*; - - #[test] - fn normal_data_buffer_pointer() { - let mut normal = Normal::new(); - let pointer = 0x12345678_9abcdef0; - normal.set_data_buffer_pointer(pointer); - let pointer_read = normal.data_buffer_pointer(); - assert_eq!(pointer, pointer_read); - } - - #[test] - fn isoch_data_buffer_pointer() { - let mut isoch = Isoch::new(); - let pointer = 0xabcd1234_567890ef; - isoch.set_data_buffer_pointer(pointer); - let pointer_read = isoch.data_buffer_pointer(); - assert_eq!(pointer, pointer_read); - } -}