2024-02-27 14:26:51 +02:00
|
|
|
use core::mem::{size_of, MaybeUninit};
|
|
|
|
|
2024-02-27 17:30:41 +02:00
|
|
|
use bytemuck::{Pod, Zeroable};
|
2025-02-06 21:05:53 +02:00
|
|
|
use device_api::dma::DmaAllocator;
|
|
|
|
use libk::dma::{BusAddress, DmaBuffer};
|
2024-02-27 14:26:51 +02:00
|
|
|
use libk_util::sync::IrqSafeSpinlock;
|
2024-03-01 15:16:26 +02:00
|
|
|
use ygg_driver_usb::error::UsbError;
|
|
|
|
use yggdrasil_abi::define_bitfields;
|
2024-02-27 14:26:51 +02:00
|
|
|
|
2024-02-27 17:30:41 +02:00
|
|
|
use super::{command::CommandReply, GenericRing};
|
2024-02-27 14:26:51 +02:00
|
|
|
|
|
|
|
pub enum Event {
|
|
|
|
PortChange(usize),
|
|
|
|
CommandCompletion {
|
2025-02-06 21:05:53 +02:00
|
|
|
address: BusAddress,
|
2024-02-27 14:26:51 +02:00
|
|
|
reply: CommandReply,
|
|
|
|
},
|
|
|
|
Transfer {
|
2025-02-06 21:05:53 +02:00
|
|
|
address: BusAddress,
|
2024-02-27 14:26:51 +02:00
|
|
|
slot_id: u8,
|
|
|
|
endpoint_id: u8,
|
|
|
|
status: u32,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
#[repr(C, align(16))]
|
|
|
|
pub struct EventRingSegment {
|
2025-02-06 21:05:53 +02:00
|
|
|
address: BusAddress,
|
2024-02-27 14:26:51 +02:00
|
|
|
// Number of TRBs supported by the ring segment. Valid values are 16 to 4096
|
|
|
|
size: u16,
|
|
|
|
_0: u16,
|
|
|
|
_1: u32,
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct EventRingSegmentTable {
|
2025-02-06 21:05:53 +02:00
|
|
|
entries: DmaBuffer<[EventRingSegment]>,
|
2024-02-27 14:26:51 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
struct EventRingInner {
|
2025-02-06 21:05:53 +02:00
|
|
|
trbs: DmaBuffer<[MaybeUninit<RawEventTrb>]>,
|
2024-02-27 14:26:51 +02:00
|
|
|
dequeue_index: usize,
|
|
|
|
cycle_bit: bool,
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct EventRing {
|
|
|
|
inner: IrqSafeSpinlock<EventRingInner>,
|
|
|
|
capacity: usize,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl EventRingSegmentTable {
|
2025-02-06 21:05:53 +02:00
|
|
|
pub fn for_event_rings(dma: &dyn DmaAllocator, rings: &[&EventRing]) -> Result<Self, UsbError> {
|
|
|
|
let entries = DmaBuffer::new_slice_with(
|
|
|
|
dma,
|
|
|
|
|i| EventRingSegment {
|
|
|
|
address: rings[i].bus_base(),
|
|
|
|
size: rings[i].capacity.try_into().unwrap(),
|
|
|
|
_0: 0,
|
|
|
|
_1: 0,
|
|
|
|
},
|
|
|
|
rings.len(),
|
|
|
|
)
|
2024-03-01 15:16:26 +02:00
|
|
|
.map_err(UsbError::MemoryError)?;
|
2024-02-27 14:26:51 +02:00
|
|
|
|
|
|
|
Ok(Self { entries })
|
|
|
|
}
|
|
|
|
|
2025-02-06 21:05:53 +02:00
|
|
|
pub fn bus_address(&self) -> BusAddress {
|
|
|
|
self.entries.bus_address()
|
2024-02-27 14:26:51 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn capacity(&self) -> usize {
|
|
|
|
self.entries.len()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl GenericRing for EventRing {
|
2025-02-06 21:05:53 +02:00
|
|
|
fn bus_base(&self) -> BusAddress {
|
|
|
|
self.inner.lock().trbs.bus_address()
|
2024-02-27 14:26:51 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl EventRingInner {
|
|
|
|
fn try_dequeue(&mut self) -> Option<Event> {
|
|
|
|
let trb = unsafe { self.trbs[self.dequeue_index].assume_init_ref() };
|
|
|
|
|
|
|
|
// TRB cannot be consumed -- its cycle bit not toggled
|
2024-02-27 17:30:41 +02:00
|
|
|
let trb_cycle = trb.cycle_bit();
|
2024-02-27 14:26:51 +02:00
|
|
|
if trb_cycle != self.cycle_bit {
|
|
|
|
return None;
|
|
|
|
}
|
|
|
|
|
|
|
|
self.dequeue_index += 1;
|
|
|
|
|
|
|
|
if self.dequeue_index == self.trbs.len() {
|
|
|
|
self.dequeue_index = 0;
|
|
|
|
self.cycle_bit = !self.cycle_bit;
|
|
|
|
}
|
|
|
|
|
2024-02-27 17:30:41 +02:00
|
|
|
trb.into_event()
|
2024-02-27 14:26:51 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl EventRing {
|
2025-02-06 21:05:53 +02:00
|
|
|
pub fn new(dma: &dyn DmaAllocator, capacity: usize) -> Result<Self, UsbError> {
|
|
|
|
let trbs = DmaBuffer::new_zeroed_slice(dma, capacity).map_err(UsbError::MemoryError)?;
|
2024-02-27 14:26:51 +02:00
|
|
|
|
|
|
|
Ok(Self {
|
|
|
|
inner: IrqSafeSpinlock::new(EventRingInner {
|
|
|
|
trbs,
|
|
|
|
dequeue_index: 0,
|
|
|
|
cycle_bit: true,
|
|
|
|
}),
|
|
|
|
capacity,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn try_dequeue(&self) -> Option<Event> {
|
|
|
|
self.inner.lock().try_dequeue()
|
|
|
|
}
|
|
|
|
|
2025-02-06 21:05:53 +02:00
|
|
|
pub fn dequeue_pointer(&self) -> BusAddress {
|
2024-02-27 14:26:51 +02:00
|
|
|
let i = self.inner.lock();
|
2025-02-06 21:05:53 +02:00
|
|
|
i.trbs
|
|
|
|
.bus_address()
|
|
|
|
.add(i.dequeue_index * size_of::<RawEventTrb>())
|
2024-02-27 17:30:41 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// TRB implementations
|
|
|
|
|
|
|
|
define_bitfields! {
|
|
|
|
pub TransferEventStatus : u32 {
|
|
|
|
(24..32) => completion_code,
|
|
|
|
(0..24) => sub_length
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
define_bitfields! {
|
|
|
|
pub TransferEventFlags : u32 {
|
|
|
|
(24..32) => slot_id,
|
|
|
|
(16..20) => endpoint_id,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
define_bitfields! {
|
|
|
|
pub CommandCompletionEventStatus : u32 {
|
|
|
|
(24..32) => completion_code,
|
|
|
|
(0..24) => completion_parameter
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
define_bitfields! {
|
|
|
|
pub CommandCompletionEventFlags : u32 {
|
|
|
|
(24..32) => slot_id,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
define_bitfields! {
|
|
|
|
pub PortStatusChangeEventAddress : u32 {
|
|
|
|
(24..32) => port_id
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
define_bitfields! {
|
|
|
|
pub RawEventFlags : u32 {
|
|
|
|
(10..16) => ty,
|
|
|
|
0 => cycle
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Clone, Copy, Debug, Pod, Zeroable)]
|
|
|
|
#[repr(C, align(16))]
|
|
|
|
pub struct TransferEventTrb {
|
2025-02-06 21:05:53 +02:00
|
|
|
pub address: BusAddress,
|
2024-02-27 17:30:41 +02:00
|
|
|
pub status: TransferEventStatus,
|
|
|
|
pub flags: TransferEventFlags,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Clone, Copy, Debug, Pod, Zeroable)]
|
|
|
|
#[repr(C, align(16))]
|
|
|
|
pub struct CommandCompletionEventTrb {
|
2025-02-06 21:05:53 +02:00
|
|
|
pub address: BusAddress,
|
2024-02-27 17:30:41 +02:00
|
|
|
pub status: CommandCompletionEventStatus,
|
|
|
|
pub flags: CommandCompletionEventFlags,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Clone, Copy, Debug, Pod, Zeroable)]
|
|
|
|
#[repr(C, align(16))]
|
|
|
|
pub struct PortStatusChangeEventTrb {
|
|
|
|
pub address: PortStatusChangeEventAddress,
|
|
|
|
_0: [u32; 3],
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Clone, Copy, Pod, Zeroable)]
|
|
|
|
#[repr(C, align(16))]
|
|
|
|
pub struct RawEventTrb {
|
|
|
|
_0: [u32; 3],
|
|
|
|
pub flags: RawEventFlags,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl RawEventTrb {
|
|
|
|
pub fn into_event(self) -> Option<Event> {
|
|
|
|
match self.flags.ty() {
|
|
|
|
32 => {
|
|
|
|
let transfer: TransferEventTrb = bytemuck::cast(self);
|
|
|
|
|
|
|
|
Some(Event::Transfer {
|
|
|
|
address: transfer.address,
|
|
|
|
slot_id: transfer.flags.slot_id() as _,
|
|
|
|
endpoint_id: transfer.flags.endpoint_id() as _,
|
|
|
|
status: transfer.status.into_raw(),
|
|
|
|
})
|
|
|
|
}
|
|
|
|
33 => {
|
|
|
|
let command: CommandCompletionEventTrb = bytemuck::cast(self);
|
|
|
|
|
|
|
|
Some(Event::CommandCompletion {
|
|
|
|
address: command.address,
|
|
|
|
reply: CommandReply {
|
|
|
|
completion_code: command.status.completion_code() as _,
|
2025-01-30 14:23:21 +02:00
|
|
|
completion_parameter: command.status.completion_parameter(),
|
2024-02-27 17:30:41 +02:00
|
|
|
slot_id: command.flags.slot_id() as _,
|
|
|
|
},
|
|
|
|
})
|
|
|
|
}
|
|
|
|
34 => {
|
|
|
|
let port_status: PortStatusChangeEventTrb = bytemuck::cast(self);
|
|
|
|
|
|
|
|
Some(Event::PortChange(port_status.address.port_id() as _))
|
|
|
|
}
|
|
|
|
ty => {
|
|
|
|
log::warn!("Unhandled event TRB with type: {}", ty);
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn cycle_bit(&self) -> bool {
|
|
|
|
self.flags.cycle()
|
2024-02-27 14:26:51 +02:00
|
|
|
}
|
|
|
|
}
|