use super::capability::RuntimeRegisterSpaceOffset;
use accessor::marker::AccessorTypeSpecifier;
use accessor::marker::ReadOnly;
use accessor::marker::ReadWrite;
use accessor::marker::Readable;
use accessor::single;
use accessor::Mapper;
use core::convert::TryFrom;
use core::convert::TryInto;
use core::marker::PhantomData;
#[derive(Debug)]
pub struct Runtime<M>
where
M: Mapper,
{
pub mfindex: single::ReadWrite<MicroframeIndexRegister, M>,
}
impl<M> Runtime<M>
where
M: Mapper,
{
pub unsafe fn new(mmio_base: usize, rtoff: RuntimeRegisterSpaceOffset, mapper: M) -> Self {
let base = mmio_base + usize::try_from(rtoff.get()).unwrap();
Self {
mfindex: single::ReadWrite::new(base, mapper),
}
}
}
#[repr(transparent)]
#[derive(Copy, Clone)]
pub struct MicroframeIndexRegister(u32);
impl MicroframeIndexRegister {
ro_field!(0..=13, microframe_index, "Microframe Index", u16);
}
impl_debug_from_methods! {
MicroframeIndexRegister {
microframe_index,
}
}
#[repr(C)]
#[derive(Debug)]
pub struct InterrupterRegisterSet<M>
where
M: Mapper + Clone,
{
base: usize,
mapper: M,
}
impl<M> InterrupterRegisterSet<M>
where
M: Mapper + Clone,
{
pub unsafe fn new(mmio_base: usize, rtoff: RuntimeRegisterSpaceOffset, mapper: M) -> Self {
let base = mmio_base + usize::try_from(rtoff.get()).unwrap() + 0x20;
assert!(base % 0x20 == 0, "base is not aligned");
Self { base, mapper }
}
pub fn interrupter(&self, index: usize) -> Interrupter<'_, M, ReadOnly> {
unsafe { Interrupter::new(self.base, index, self.mapper.clone()) }
}
pub fn interrupter_mut(&mut self, index: usize) -> Interrupter<'_, M, ReadWrite> {
unsafe { Interrupter::new(self.base, index, self.mapper.clone()) }
}
}
#[derive(Debug)]
pub struct Interrupter<'a, M, A>
where
M: Mapper + Clone,
A: AccessorTypeSpecifier + Readable,
{
pub iman: single::Generic<InterrupterManagementRegister, M, A>,
pub imod: single::Generic<InterrupterModerationRegister, M, A>,
pub erstsz: single::Generic<EventRingSegmentTableSizeRegister, M, A>,
pub erstba: single::Generic<EventRingSegmentTableBaseAddressRegister, M, A>,
pub erdp: single::Generic<EventRingDequeuePointerRegister, M, A>,
_marker: PhantomData<&'a InterrupterRegisterSet<M>>,
}
impl<M, A> Interrupter<'_, M, A>
where
M: Mapper + Clone,
A: AccessorTypeSpecifier + Readable,
{
unsafe fn new(interrupter_register_set_base: usize, index: usize, mapper: M) -> Self {
assert!(index < 1024, "index out of range");
let base = interrupter_register_set_base + index * 0x20;
Self {
iman: single::Generic::new(base, mapper.clone()),
imod: single::Generic::new(base + 0x4, mapper.clone()),
erstsz: single::Generic::new(base + 0x8, mapper.clone()),
erstba: single::Generic::new(base + 0x10, mapper.clone()),
erdp: single::Generic::new(base + 0x18, mapper),
_marker: PhantomData,
}
}
}
#[repr(transparent)]
#[derive(Copy, Clone)]
pub struct InterrupterManagementRegister(u32);
impl InterrupterManagementRegister {
rw1c_bit!(0, interrupt_pending, "Interrupt Pending");
rw_bit!(1, interrupt_enable, "Interrupt Enable");
}
impl_debug_from_methods! {
InterrupterManagementRegister {
interrupt_pending,
interrupt_enable,
}
}
#[repr(transparent)]
#[derive(Copy, Clone, Default)]
pub struct InterrupterModerationRegister(u32);
impl InterrupterModerationRegister {
rw_field!(
0..=15,
interrupt_moderation_interval,
"Interrupt Moderation Interval",
u16
);
rw_field!(
16..=31,
interrupt_moderation_counter,
"Interrupt Moderation Counter",
u16
);
}
impl_debug_from_methods! {
InterrupterModerationRegister{
interrupt_moderation_interval,
interrupt_moderation_counter,
}
}
#[repr(transparent)]
#[derive(Copy, Clone, Debug)]
pub struct EventRingSegmentTableSizeRegister(u32);
impl EventRingSegmentTableSizeRegister {
#[must_use]
pub fn get(self) -> u16 {
self.0.try_into().unwrap()
}
pub fn set(&mut self, s: u16) {
self.0 = s.into();
}
}
#[repr(transparent)]
#[derive(Copy, Clone, Debug)]
pub struct EventRingSegmentTableBaseAddressRegister(u64);
impl EventRingSegmentTableBaseAddressRegister {
#[must_use]
pub fn get(self) -> u64 {
self.0
}
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;
}
}
#[repr(transparent)]
#[derive(Copy, Clone, Default)]
pub struct EventRingDequeuePointerRegister(u64);
impl EventRingDequeuePointerRegister {
rw_field!(
0..=2,
dequeue_erst_segment_index,
"Dequeue ERST Segment Index",
u8
);
rw1c_bit!(3, event_handler_busy, "Event Handler Busy");
#[must_use]
pub fn event_ring_dequeue_pointer(self) -> u64 {
self.0 & !0b1111
}
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;
}
}
impl_debug_from_methods! {
EventRingDequeuePointerRegister{
dequeue_erst_segment_index,
event_handler_busy,
event_ring_dequeue_pointer
}
}