140 lines
3.5 KiB
Rust
140 lines
3.5 KiB
Rust
use core::mem::MaybeUninit;
|
|
|
|
use alloc::{boxed::Box, sync::Arc};
|
|
use async_trait::async_trait;
|
|
use libk_mm::{address::AsPhysicalAddress, PageSlice};
|
|
use ygg_driver_usb::{
|
|
communication::UsbDirection,
|
|
error::{TransferError, UsbError},
|
|
pipe::{
|
|
control::{ControlTransferSetup, UsbControlPipe},
|
|
normal::{UsbNormalPipeIn, UsbNormalPipeOut},
|
|
},
|
|
};
|
|
|
|
use crate::{controller::Xhci, ring::transfer::TransferRing};
|
|
|
|
pub struct ControlPipe {
|
|
xhci: Arc<Xhci>,
|
|
pub(crate) ring: Arc<TransferRing>,
|
|
}
|
|
|
|
pub struct NormalInPipe {
|
|
xhci: Arc<Xhci>,
|
|
pub(crate) ring: Arc<TransferRing>,
|
|
}
|
|
|
|
pub struct NormalOutPipe {
|
|
xhci: Arc<Xhci>,
|
|
pub(crate) ring: Arc<TransferRing>,
|
|
}
|
|
|
|
impl ControlPipe {
|
|
pub fn new(
|
|
xhci: Arc<Xhci>,
|
|
slot_id: u8,
|
|
endpoint_id: u8,
|
|
capacity: usize,
|
|
) -> Result<(Self, Arc<TransferRing>), UsbError> {
|
|
let ring = Arc::new(TransferRing::new(slot_id, endpoint_id, capacity)?);
|
|
Ok((
|
|
Self {
|
|
xhci,
|
|
ring: ring.clone(),
|
|
},
|
|
ring,
|
|
))
|
|
}
|
|
}
|
|
|
|
impl NormalInPipe {
|
|
pub fn new(
|
|
xhci: Arc<Xhci>,
|
|
slot_id: u8,
|
|
endpoint_id: u8,
|
|
capacity: usize,
|
|
) -> Result<(Self, Arc<TransferRing>), UsbError> {
|
|
let ring = Arc::new(TransferRing::new(slot_id, endpoint_id, capacity)?);
|
|
Ok((
|
|
Self {
|
|
xhci,
|
|
ring: ring.clone(),
|
|
},
|
|
ring,
|
|
))
|
|
}
|
|
}
|
|
|
|
impl NormalOutPipe {
|
|
pub fn new(
|
|
xhci: Arc<Xhci>,
|
|
slot_id: u8,
|
|
endpoint_id: u8,
|
|
capacity: usize,
|
|
) -> Result<(Self, Arc<TransferRing>), UsbError> {
|
|
let ring = Arc::new(TransferRing::new(slot_id, endpoint_id, capacity)?);
|
|
Ok((
|
|
Self {
|
|
xhci,
|
|
ring: ring.clone(),
|
|
},
|
|
ring,
|
|
))
|
|
}
|
|
}
|
|
|
|
#[async_trait]
|
|
impl UsbControlPipe for ControlPipe {
|
|
async fn control_transfer(
|
|
&self,
|
|
setup: ControlTransferSetup,
|
|
data: Option<(&mut PageSlice<MaybeUninit<u8>>, UsbDirection)>,
|
|
) -> Result<usize, UsbError> {
|
|
let data_len = data.as_ref().map_or(0, |(data, _)| data.len());
|
|
let result = self
|
|
.ring
|
|
.control_transfer(self.xhci.as_ref(), setup, data)
|
|
.await;
|
|
allow_short_packet(data_len, result)
|
|
}
|
|
}
|
|
|
|
#[async_trait]
|
|
impl UsbNormalPipeIn for NormalInPipe {
|
|
async fn read(&self, buffer: &mut PageSlice<u8>) -> Result<usize, UsbError> {
|
|
let data_len = buffer.len();
|
|
let result = self
|
|
.ring
|
|
.normal_transfer(
|
|
self.xhci.as_ref(),
|
|
unsafe { buffer.as_physical_address() },
|
|
buffer.len(),
|
|
)
|
|
.await;
|
|
allow_short_packet(data_len, result)
|
|
}
|
|
}
|
|
|
|
#[async_trait]
|
|
impl UsbNormalPipeOut for NormalOutPipe {
|
|
async fn write(&self, buffer: &PageSlice<u8>) -> Result<usize, UsbError> {
|
|
self.ring
|
|
.normal_transfer(
|
|
self.xhci.as_ref(),
|
|
unsafe { buffer.as_physical_address() },
|
|
buffer.len(),
|
|
)
|
|
.await
|
|
}
|
|
}
|
|
|
|
fn allow_short_packet(data_len: usize, result: Result<usize, UsbError>) -> Result<usize, UsbError> {
|
|
match result {
|
|
// Short packets are okay for control transfers
|
|
Err(UsbError::TransferFailed(TransferError::ShortPacket(residual))) => {
|
|
Ok(data_len.saturating_sub(residual))
|
|
}
|
|
result => result,
|
|
}
|
|
}
|