Simplify the endpoint interface.
This commit is contained in:
@@ -47,8 +47,11 @@ fn main() {
|
||||
let control = 0; // TODO: NACA?
|
||||
scsi::cmds::ReportIdentInfo::new(alloc_len, info_ty, control)
|
||||
};*/
|
||||
let inquiry = scsi::cmds::Inquiry::new(false, 0, 36, 0);
|
||||
let mut buffer = [0u8; 36];
|
||||
use protocol::Protocol;
|
||||
protocol.send_command(unsafe { plain::as_bytes(&inquiry) }, DeviceReqData::In(&mut buffer)).expect("Failed to send command");
|
||||
let mut buffer = [0u8; 5];
|
||||
let mut command_buffer = [0u8; 6];
|
||||
{
|
||||
let mut inquiry = plain::from_mut_bytes(&mut command_buffer).unwrap();
|
||||
*inquiry = scsi::cmds::Inquiry::new(false, 0, 5, 0);
|
||||
}
|
||||
protocol.send_command(&command_buffer, DeviceReqData::In(&mut buffer)).expect("Failed to send command");
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ use std::io::prelude::*;
|
||||
use std::{io, slice};
|
||||
|
||||
use thiserror::Error;
|
||||
use xhcid_interface::{ConfDesc, DeviceReqData, EndpBinaryDirection, EndpDirection, EndpointStatus, IfDesc, Invalid, PortReqDirection, PortReqTy, PortReqRecipient, PortTransferStatus, XhciClientHandle, XhciClientHandleError, XhciEndpStatusHandle, XhciEndpTransferHandle};
|
||||
use xhcid_interface::{ConfDesc, DeviceReqData, EndpBinaryDirection, EndpDirection, EndpointStatus, IfDesc, Invalid, PortReqDirection, PortReqTy, PortReqRecipient, PortTransferStatus, XhciClientHandle, XhciClientHandleError, XhciEndpHandle};
|
||||
|
||||
use super::{Protocol, ProtocolError};
|
||||
|
||||
@@ -77,10 +77,8 @@ impl CommandStatusWrapper {
|
||||
|
||||
pub struct BulkOnlyTransport<'a> {
|
||||
handle: &'a XhciClientHandle,
|
||||
bulk_in: XhciEndpTransferHandle,
|
||||
bulk_out: XhciEndpTransferHandle,
|
||||
bulk_in_status: XhciEndpStatusHandle,
|
||||
bulk_out_status: XhciEndpStatusHandle,
|
||||
bulk_in: XhciEndpHandle,
|
||||
bulk_out: XhciEndpHandle,
|
||||
bulk_in_num: u8,
|
||||
bulk_out_num: u8,
|
||||
max_lun: u8,
|
||||
@@ -103,10 +101,8 @@ impl<'a> BulkOnlyTransport<'a> {
|
||||
println!("BOT_MAX_LUN {}", max_lun);
|
||||
|
||||
Ok(Self {
|
||||
bulk_in: handle.open_endpoint(bulk_in_num, PortReqDirection::DeviceToHost)?,
|
||||
bulk_out: handle.open_endpoint(bulk_out_num, PortReqDirection::HostToDevice)?,
|
||||
bulk_in_status: handle.open_endpoint_status(bulk_in_num)?,
|
||||
bulk_out_status: handle.open_endpoint_status(bulk_out_num)?,
|
||||
bulk_in: handle.open_endpoint(bulk_in_num)?,
|
||||
bulk_out: handle.open_endpoint(bulk_out_num)?,
|
||||
bulk_in_num,
|
||||
bulk_out_num,
|
||||
handle,
|
||||
@@ -115,15 +111,20 @@ impl<'a> BulkOnlyTransport<'a> {
|
||||
interface_num: if_desc.number,
|
||||
})
|
||||
}
|
||||
fn clear_stall(&mut self, endp_num: u8) -> Result<(), XhciClientHandleError> {
|
||||
self.handle.clear_feature(PortReqRecipient::Endpoint, u16::from(endp_num), FEATURE_ENDPOINT_HALT)
|
||||
fn clear_stall_in(&mut self) -> Result<(), XhciClientHandleError> {
|
||||
self.bulk_in.reset(false);
|
||||
self.handle.clear_feature(PortReqRecipient::Endpoint, u16::from(self.bulk_in_num), FEATURE_ENDPOINT_HALT)
|
||||
}
|
||||
fn clear_stall_out(&mut self) -> Result<(), XhciClientHandleError> {
|
||||
self.bulk_out.reset(false);
|
||||
self.handle.clear_feature(PortReqRecipient::Endpoint, u16::from(self.bulk_out_num), FEATURE_ENDPOINT_HALT)
|
||||
}
|
||||
fn reset_recovery(&mut self) -> Result<(), ProtocolError> {
|
||||
bulk_only_mass_storage_reset(self.handle, self.interface_num.into())?;
|
||||
self.clear_stall(self.bulk_in_num.into())?;
|
||||
self.clear_stall(self.bulk_out_num.into())?;
|
||||
self.clear_stall_in()?;
|
||||
self.clear_stall_out()?;
|
||||
|
||||
if self.bulk_in_status.current_status()? == EndpointStatus::Halted || self.bulk_out_status.current_status()? == EndpointStatus::Halted {
|
||||
if self.bulk_in.status()? == EndpointStatus::Halted || self.bulk_out.status()? == EndpointStatus::Halted {
|
||||
return Err(ProtocolError::RecoveryFailed)
|
||||
}
|
||||
Ok(())
|
||||
@@ -135,25 +136,23 @@ impl<'a> Protocol for BulkOnlyTransport<'a> {
|
||||
self.current_tag += 1;
|
||||
let tag = self.current_tag;
|
||||
|
||||
let mut command_block = [0u8; 16];
|
||||
if cb.len() > 16 {
|
||||
return Err(ProtocolError::TooLargeCommandBlock(cb.len()));
|
||||
}
|
||||
command_block[..cb.len()].copy_from_slice(&cb);
|
||||
println!("{}", base64::encode(cb));
|
||||
println!();
|
||||
|
||||
let cbw = CommandBlockWrapper {
|
||||
signature: CBW_SIGNATURE,
|
||||
tag,
|
||||
data_transfer_len: data.len() as u32,
|
||||
lun: 0, // TODO
|
||||
flags: u8::from(data.direction() == PortReqDirection::DeviceToHost) << 7,
|
||||
cb_len: cb.len().try_into().or(Err(ProtocolError::TooLargeCommandBlock(cb.len())))?,
|
||||
command_block,
|
||||
};
|
||||
match self.bulk_out.transfer_write(unsafe { plain::as_bytes(&cbw) })? {
|
||||
let mut cbw_bytes = [0u8; 31];
|
||||
let cbw = plain::from_mut_bytes::<CommandBlockWrapper>(&mut cbw_bytes).unwrap();
|
||||
|
||||
*cbw = CommandBlockWrapper::new(tag, data.len() as u32, data.direction().into(), 0, cb)?;
|
||||
println!("{}", base64::encode(&cbw_bytes));
|
||||
|
||||
dbg!(self.bulk_in.status()?, self.bulk_out.status()?);
|
||||
|
||||
match self.bulk_out.transfer_write(&cbw_bytes)? {
|
||||
PortTransferStatus::ShortPacket(31) => (),
|
||||
PortTransferStatus::Stalled => {
|
||||
panic!("bulk out endpoint stalled when sending CBW");
|
||||
println!("bulk out endpoint stalled when sending CBW");
|
||||
self.reset_recovery()?;
|
||||
dbg!(self.bulk_in.status()?, self.bulk_out.status()?);
|
||||
}
|
||||
_ => panic!("invalid number of CBW bytes written; expected a short packed of length 31 (0x1F)"),
|
||||
}
|
||||
@@ -165,7 +164,7 @@ impl<'a> Protocol for BulkOnlyTransport<'a> {
|
||||
PortTransferStatus::ShortPacket(len) => panic!("received short packed (len {}) when transferring data", len),
|
||||
PortTransferStatus::Stalled => {
|
||||
println!("bulk in endpoint stalled when reading data");
|
||||
self.clear_stall(self.bulk_in_num)?;
|
||||
self.clear_stall_in()?;
|
||||
}
|
||||
PortTransferStatus::Unknown => return Err(ProtocolError::XhciError(XhciClientHandleError::InvalidResponse(Invalid("unknown transfer status")))),
|
||||
};
|
||||
@@ -173,27 +172,29 @@ impl<'a> Protocol for BulkOnlyTransport<'a> {
|
||||
}
|
||||
DeviceReqData::Out(ref buffer) => todo!(),
|
||||
DeviceReqData::NoData => todo!(),
|
||||
};
|
||||
}
|
||||
|
||||
let mut csw = CommandStatusWrapper::default();
|
||||
let mut csw_buffer = [0u8; 13];
|
||||
|
||||
match self.bulk_in.transfer_read(unsafe { plain::as_mut_bytes(&mut csw) })? {
|
||||
match self.bulk_in.transfer_read(&mut csw_buffer)? {
|
||||
PortTransferStatus::ShortPacket(13) => (),
|
||||
PortTransferStatus::Stalled => {
|
||||
println!("bulk in endpoint stalled when reading CSW");
|
||||
self.clear_stall(self.bulk_in_num)?;
|
||||
self.clear_stall_in()?;
|
||||
}
|
||||
_ => panic!("invalid number of CSW bytes read; expected a short packet of length 13 (0xD)"),
|
||||
};
|
||||
println!("{}", base64::encode(&csw_buffer));
|
||||
let csw = plain::from_bytes::<CommandStatusWrapper>(&csw_buffer).unwrap();
|
||||
|
||||
if !csw.is_valid() {
|
||||
self.reset_recovery()?;
|
||||
}
|
||||
dbg!(csw);
|
||||
|
||||
if self.bulk_in_status.current_status()? == EndpointStatus::Halted || self.bulk_out_status.current_status()? == EndpointStatus::Halted {
|
||||
if self.bulk_in.status()? == EndpointStatus::Halted || self.bulk_out.status()? == EndpointStatus::Halted {
|
||||
println!("Trying to recover from stall");
|
||||
dbg!(self.bulk_in_status.current_status()?, self.bulk_out_status.current_status()?);
|
||||
dbg!(self.bulk_in.status()?, self.bulk_out.status()?);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@@ -204,7 +205,7 @@ pub fn bulk_only_mass_storage_reset(handle: &XhciClientHandle, if_num: u16) -> R
|
||||
handle.device_request(PortReqTy::Class, PortReqRecipient::Interface, 0xFF, 0, if_num, DeviceReqData::NoData)
|
||||
}
|
||||
pub fn get_max_lun(handle: &XhciClientHandle, if_num: u16) -> Result<u8, XhciClientHandleError> {
|
||||
let mut lun = 0;
|
||||
let mut lun = 0u8;
|
||||
let buffer = slice::from_mut(&mut lun);
|
||||
handle.device_request(PortReqTy::Class, PortReqRecipient::Interface, 0xFE, 0, if_num, DeviceReqData::In(buffer))?;
|
||||
Ok(lun)
|
||||
|
||||
@@ -13,6 +13,8 @@ pub struct ReportIdentInfo {
|
||||
pub info_ty: u8,
|
||||
pub control: u8,
|
||||
}
|
||||
unsafe impl plain::Plain for ReportIdentInfo {}
|
||||
|
||||
impl ReportIdentInfo {
|
||||
pub fn new(alloc_len: u32, info_ty: ReportIdInfoInfoTy, control: u8) -> Self {
|
||||
Self {
|
||||
@@ -52,6 +54,8 @@ pub struct ReportSuppOpcodes {
|
||||
pub _rsvd: u8,
|
||||
pub control: u8,
|
||||
}
|
||||
unsafe impl plain::Plain for ReportSuppOpcodes {}
|
||||
|
||||
impl ReportSuppOpcodes {
|
||||
pub const fn new(rep_opts: ReportSuppOpcodesOptions, rctd: bool, req_opcode: u8, req_serviceaction: u16, alloc_len: u32, control: u8) -> Self {
|
||||
Self {
|
||||
@@ -115,6 +119,7 @@ pub struct CommandDescriptor {
|
||||
/// little endian
|
||||
pub cdb_len: u16,
|
||||
}
|
||||
|
||||
#[repr(packed)]
|
||||
pub struct OneCommandParam {
|
||||
pub _rsvd: u8,
|
||||
@@ -133,6 +138,7 @@ pub struct Inquiry {
|
||||
pub alloc_len: u16,
|
||||
pub control: u8,
|
||||
}
|
||||
unsafe impl plain::Plain for Inquiry {}
|
||||
|
||||
impl Inquiry {
|
||||
pub fn new(evpd: bool, page_code: u8, alloc_len: u16, control: u8) -> Self {
|
||||
|
||||
+115
-88
@@ -79,6 +79,16 @@ pub enum EndpBinaryDirection {
|
||||
Out,
|
||||
In,
|
||||
}
|
||||
|
||||
impl From<PortReqDirection> for EndpBinaryDirection {
|
||||
fn from(d: PortReqDirection) -> Self {
|
||||
match d {
|
||||
PortReqDirection::DeviceToHost => Self::In,
|
||||
PortReqDirection::HostToDevice => Self::Out,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<EndpBinaryDirection> for EndpDirection {
|
||||
fn from(b: EndpBinaryDirection) -> Self {
|
||||
match b {
|
||||
@@ -305,7 +315,7 @@ impl str::FromStr for PortState {
|
||||
}
|
||||
|
||||
#[repr(u8)]
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
||||
pub enum EndpointStatus {
|
||||
Disabled,
|
||||
Enabled,
|
||||
@@ -411,48 +421,28 @@ impl XhciClientHandle {
|
||||
let string = std::fs::read_to_string(path)?;
|
||||
Ok(string.parse()?)
|
||||
}
|
||||
pub fn endpoint_onetime_status(
|
||||
pub fn open_endpoint_ctl(
|
||||
&self,
|
||||
num: u8,
|
||||
) -> result::Result<EndpointStatus, XhciClientHandleError> {
|
||||
let path = format!("{}:port{}/endpoints/{}/status", self.scheme, self.port, num);
|
||||
let string = std::fs::read_to_string(path)?;
|
||||
Ok(string.parse()?)
|
||||
) -> result::Result<File, XhciClientHandleError> {
|
||||
let path = format!("{}:port{}/endpoints/{}/ctl", self.scheme, self.port, num);
|
||||
Ok(File::open(path)?)
|
||||
}
|
||||
pub fn open_endpoint_status(
|
||||
pub fn open_endpoint_data(
|
||||
&self,
|
||||
num: u8,
|
||||
) -> result::Result<XhciEndpStatusHandle, XhciClientHandleError> {
|
||||
let path = format!("{}:port{}/endpoints/{}/status", self.scheme, self.port, num);
|
||||
Ok(XhciEndpStatusHandle(
|
||||
OpenOptions::new()
|
||||
.read(true)
|
||||
.write(false)
|
||||
.create(false)
|
||||
.open(path)?,
|
||||
))
|
||||
}
|
||||
pub fn open_endpoint(
|
||||
&self,
|
||||
num: u8,
|
||||
direction: PortReqDirection,
|
||||
) -> result::Result<XhciEndpTransferHandle, XhciClientHandleError> {
|
||||
) -> result::Result<File, XhciClientHandleError> {
|
||||
let path = format!(
|
||||
"{}:port{}/endpoints/{}/transfer",
|
||||
"{}:port{}/endpoints/{}/data",
|
||||
self.scheme, self.port, num
|
||||
);
|
||||
Ok(XhciEndpTransferHandle(match direction {
|
||||
PortReqDirection::HostToDevice => OpenOptions::new()
|
||||
.read(false)
|
||||
.write(true)
|
||||
.create(false)
|
||||
.open(path)?,
|
||||
PortReqDirection::DeviceToHost => OpenOptions::new()
|
||||
.read(true)
|
||||
.write(false)
|
||||
.create(false)
|
||||
.open(path)?,
|
||||
}))
|
||||
Ok(File::open(path)?)
|
||||
}
|
||||
pub fn open_endpoint(&self, num: u8) -> result::Result<XhciEndpHandle, XhciClientHandleError> {
|
||||
Ok(XhciEndpHandle {
|
||||
ctl: self.open_endpoint_ctl(num)?,
|
||||
data: self.open_endpoint_data(num)?,
|
||||
})
|
||||
}
|
||||
pub fn device_request<'a>(
|
||||
&self,
|
||||
@@ -546,68 +536,105 @@ impl XhciClientHandle {
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct XhciEndpStatusHandle(File);
|
||||
|
||||
impl XhciEndpStatusHandle {
|
||||
pub fn current_status(&mut self) -> result::Result<EndpointStatus, XhciClientHandleError> {
|
||||
self.0.seek(io::SeekFrom::Start(0))?;
|
||||
let mut status_buf = [0u8; 16];
|
||||
let len = self.0.read(&mut status_buf)?;
|
||||
let status = std::str::from_utf8(&status_buf[..len]).or(Err(
|
||||
XhciClientHandleError::InvalidResponse(Invalid("non-utf8 endpoint state")),
|
||||
))?;
|
||||
Ok(status
|
||||
.parse::<EndpointStatus>()
|
||||
.or(Err(XhciClientHandleError::InvalidResponse(Invalid(
|
||||
"malformed endpoint state",
|
||||
))))?)
|
||||
}
|
||||
pub fn into_inner(self) -> File {
|
||||
self.0
|
||||
}
|
||||
pub struct XhciEndpHandle {
|
||||
data: File,
|
||||
ctl: File,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct XhciEndpTransferHandle(File);
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
||||
pub enum XhciEndpCtlDirection {
|
||||
Out,
|
||||
In,
|
||||
NoData,
|
||||
}
|
||||
|
||||
impl XhciEndpTransferHandle {
|
||||
fn get_status(
|
||||
&mut self,
|
||||
requested_len: usize,
|
||||
bytes_transferred: usize,
|
||||
) -> result::Result<PortTransferStatus, XhciClientHandleError> {
|
||||
let mut status_buf = [0u8; 32];
|
||||
let status_bytes_read = self.0.read(&mut status_buf)?;
|
||||
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
|
||||
#[non_exhaustive]
|
||||
pub enum XhciEndpCtlReq {
|
||||
// TODO: Reduce the number of direction enums from 5 to perhaps 2.
|
||||
// TODO: Allow to send multiple buffers in one transfer.
|
||||
/// Tells xhcid that a buffer is about to be sent from the Data interface file, to the
|
||||
/// endpoint.
|
||||
Transfer(XhciEndpCtlDirection),
|
||||
// TODO: Allow clients to specify what to reset.
|
||||
|
||||
let status = serde_json::from_slice(&status_buf[..status_bytes_read])?;
|
||||
/// Tells xhcid that the endpoint is going to be reset.
|
||||
Reset {
|
||||
/// Only issue the Reset Endpoint and Set TR Dequeue Pointer commands, and let the client
|
||||
/// itself send a potential ClearFeature(ENDPOINT_HALT).
|
||||
no_clear_feature: bool,
|
||||
},
|
||||
|
||||
if let PortTransferStatus::ShortPacket(len) = status {
|
||||
if len as usize != bytes_transferred {
|
||||
return Err(XhciClientHandleError::InvalidResponse(Invalid("xhcid gave a short packet with a different length than the bytes transferred (which should have been the same)")));
|
||||
}
|
||||
} else if let PortTransferStatus::Success = status {
|
||||
if requested_len != bytes_transferred {
|
||||
return Err(XhciClientHandleError::InvalidResponse(Invalid("xhcid transferred fewer or more bytes than requested, but didn't return a short packed")));
|
||||
}
|
||||
/// Tells xhcid that the endpoint status is going to be retrieved from the Ctl interface file.
|
||||
Status,
|
||||
}
|
||||
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
|
||||
#[non_exhaustive]
|
||||
pub enum XhciEndpCtlRes {
|
||||
/// Xhcid responded with the current state of an endpoint.
|
||||
Status(EndpointStatus),
|
||||
|
||||
/// Xhci sent the result of a transfer.
|
||||
TransferResult(PortTransferStatus),
|
||||
|
||||
/// Xhcid is waiting for data to be sent or received on the Data interface file.
|
||||
Pending,
|
||||
|
||||
/// No Ctl request is currently being processed by xhcid.
|
||||
Idle,
|
||||
}
|
||||
|
||||
impl XhciEndpHandle {
|
||||
fn ctl_req(&mut self, ctl_req: &XhciEndpCtlReq) -> result::Result<(), XhciClientHandleError> {
|
||||
let ctl_buffer = serde_json::to_vec(ctl_req)?;
|
||||
|
||||
let ctl_bytes_written = self.ctl.write(&ctl_buffer)?;
|
||||
if ctl_bytes_written != ctl_buffer.len() {
|
||||
return Err(Invalid("xhcid didn't process all of the ctl bytes").into());
|
||||
}
|
||||
Ok(status)
|
||||
|
||||
Ok(())
|
||||
}
|
||||
pub fn transfer_write(
|
||||
&mut self,
|
||||
buffer: &[u8],
|
||||
) -> result::Result<PortTransferStatus, XhciClientHandleError> {
|
||||
let bytes_transferred = self.0.write(buffer)?;
|
||||
self.get_status(buffer.len(), bytes_transferred)
|
||||
fn ctl_res(&mut self) -> result::Result<XhciEndpCtlRes, XhciClientHandleError> {
|
||||
// a response must never exceed 256 bytes
|
||||
let mut ctl_buffer = [0u8; 256];
|
||||
let ctl_bytes_read = self.ctl.read(&mut ctl_buffer)?;
|
||||
|
||||
let ctl_res = serde_json::from_slice(&ctl_buffer[..ctl_bytes_read as usize])?;
|
||||
Ok(ctl_res)
|
||||
}
|
||||
pub fn transfer_read(
|
||||
&mut self,
|
||||
buffer: &mut [u8],
|
||||
) -> result::Result<PortTransferStatus, XhciClientHandleError> {
|
||||
let bytes_transferred = self.0.read(buffer)?;
|
||||
self.get_status(buffer.len(), bytes_transferred)
|
||||
pub fn reset(&mut self, no_clear_feature: bool) -> result::Result<(), XhciClientHandleError> {
|
||||
self.ctl_req(&XhciEndpCtlReq::Reset { no_clear_feature })
|
||||
}
|
||||
pub fn into_inner(self) -> File {
|
||||
self.0
|
||||
pub fn status(&mut self) -> result::Result<EndpointStatus, XhciClientHandleError> {
|
||||
self.ctl_req(&XhciEndpCtlReq::Status)?;
|
||||
match self.ctl_res()? {
|
||||
XhciEndpCtlRes::Status(s) => Ok(s),
|
||||
_ => Err(Invalid("expected status response").into()),
|
||||
}
|
||||
}
|
||||
fn generic_transfer<F: FnOnce(&mut File) -> io::Result<usize>>(&mut self, direction: XhciEndpCtlDirection, f: F, expected_len: usize) -> result::Result<PortTransferStatus, XhciClientHandleError> {
|
||||
let req = XhciEndpCtlReq::Transfer(XhciEndpCtlDirection::Out);
|
||||
self.ctl_req(&req)?;
|
||||
|
||||
let bytes_read = f(&mut self.data)?;
|
||||
let res = self.ctl_res()?;
|
||||
|
||||
match res {
|
||||
XhciEndpCtlRes::TransferResult(PortTransferStatus::Success) if bytes_read != expected_len => Err(Invalid("no short packet, but fewer bytes were read/written").into()),
|
||||
XhciEndpCtlRes::TransferResult(r) => Ok(r),
|
||||
_ => Err(Invalid("expected transfer result").into()),
|
||||
}
|
||||
}
|
||||
pub fn transfer_write(&mut self, buf: &[u8]) -> result::Result<PortTransferStatus, XhciClientHandleError> {
|
||||
self.generic_transfer(XhciEndpCtlDirection::Out, |data| data.write(buf), buf.len())
|
||||
}
|
||||
pub fn transfer_read(&mut self, buf: &mut [u8]) -> result::Result<PortTransferStatus, XhciClientHandleError> {
|
||||
let len = buf.len();
|
||||
self.generic_transfer(XhciEndpCtlDirection::In, |data| data.read(buf), len)
|
||||
}
|
||||
pub fn transfer_nodata(&mut self, buf: &[u8]) -> result::Result<PortTransferStatus, XhciClientHandleError> {
|
||||
self.generic_transfer(XhciEndpCtlDirection::NoData, |_| Ok(0), buf.len())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+11
-10
@@ -35,6 +35,8 @@ use self::ring::Ring;
|
||||
use self::runtime::{Interrupter, RuntimeRegs};
|
||||
use self::trb::{TransferKind, TrbCompletionCode, TrbType};
|
||||
|
||||
use self::scheme::EndpIfState;
|
||||
|
||||
use crate::driver_interface::*;
|
||||
|
||||
struct Device<'a> {
|
||||
@@ -151,14 +153,14 @@ pub(crate) enum RingOrStreams {
|
||||
Streams(StreamContextArray),
|
||||
}
|
||||
|
||||
pub(crate) enum EndpointState {
|
||||
Ready(RingOrStreams),
|
||||
Init,
|
||||
pub(crate) struct EndpointState {
|
||||
pub transfer: RingOrStreams,
|
||||
pub driver_if_state: EndpIfState,
|
||||
}
|
||||
impl EndpointState {
|
||||
fn ring(&mut self) -> Option<&mut Ring> {
|
||||
match self {
|
||||
Self::Ready(RingOrStreams::Ring(ring)) => Some(ring),
|
||||
match self.transfer {
|
||||
RingOrStreams::Ring(ref mut ring) => Some(ring),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
@@ -294,10 +296,6 @@ impl Xhci {
|
||||
self.dbs[0].write(0);
|
||||
|
||||
println!(" - XHCI initialized");
|
||||
|
||||
for (pointer, capability) in self.capabilities_iter() {
|
||||
dbg!(pointer, capability);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn enable_port_slot(cmd: &mut CommandRing, dbs: &mut [Doorbell]) -> u8 {
|
||||
@@ -365,7 +363,10 @@ impl Xhci {
|
||||
dev_desc,
|
||||
endpoint_states: std::iter::once((
|
||||
0,
|
||||
EndpointState::Ready(RingOrStreams::Ring(ring)),
|
||||
EndpointState {
|
||||
transfer: RingOrStreams::Ring(ring),
|
||||
driver_if_state: EndpIfState::Init,
|
||||
}
|
||||
))
|
||||
.collect::<BTreeMap<_, _>>(),
|
||||
};
|
||||
|
||||
+150
-176
@@ -30,14 +30,21 @@ use super::usb::endpoint::{EndpointTy, ENDP_ATTR_TY_MASK};
|
||||
|
||||
use crate::driver_interface::*;
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub enum EndpIfState {
|
||||
Init,
|
||||
WaitingForDataPipe(XhciEndpCtlDirection),
|
||||
WaitingForStatus,
|
||||
WaitingForTransferResult(PortTransferStatus),
|
||||
}
|
||||
|
||||
/// Subdirs of an endpoint
|
||||
pub enum EndpointHandleTy {
|
||||
/// portX/endpoints/Y/transfer. Write calls transfer data to the device, and read calls
|
||||
/// transfer data from the device.
|
||||
Transfer(PortTransferState),
|
||||
/// portX/endpoints/Y/data. Allows clients to read and write data associated with ctl requests.
|
||||
Data,
|
||||
|
||||
/// portX/endpoints/Y/status
|
||||
Status(usize), // offset
|
||||
Ctl,
|
||||
|
||||
/// portX/endpoints/Y/
|
||||
Root(usize, Vec<u8>), // offset, content
|
||||
@@ -469,7 +476,7 @@ impl Xhci {
|
||||
);
|
||||
port_state.endpoint_states.insert(
|
||||
endp_num,
|
||||
EndpointState::Ready(super::RingOrStreams::Streams(array)),
|
||||
EndpointState { transfer: super::RingOrStreams::Streams(array), driver_if_state: EndpIfState::Init },
|
||||
);
|
||||
|
||||
array_ptr
|
||||
@@ -484,7 +491,7 @@ impl Xhci {
|
||||
);
|
||||
port_state.endpoint_states.insert(
|
||||
endp_num,
|
||||
EndpointState::Ready(super::RingOrStreams::Ring(ring)),
|
||||
EndpointState { transfer: super::RingOrStreams::Ring(ring), driver_if_state: EndpIfState::Init },
|
||||
);
|
||||
ring_ptr
|
||||
};
|
||||
@@ -627,7 +634,6 @@ impl Xhci {
|
||||
}
|
||||
|
||||
if EndpDirection::from(buf.direction()) != endp_desc.direction() {
|
||||
dbg!(buf.direction(), endp_desc, endp_idx, endp_num);
|
||||
return Err(Error::new(EBADF));
|
||||
}
|
||||
|
||||
@@ -637,14 +643,13 @@ impl Xhci {
|
||||
.ok_or(Error::new(EBADF))?;
|
||||
|
||||
let ring: &mut Ring = match endp_state {
|
||||
EndpointState::Ready(super::RingOrStreams::Ring(ref mut ring)) => ring,
|
||||
EndpointState::Ready(super::RingOrStreams::Streams(stream_ctx_array)) => {
|
||||
EndpointState { transfer: super::RingOrStreams::Ring(ref mut ring), .. } => ring,
|
||||
EndpointState { transfer: super::RingOrStreams::Streams(stream_ctx_array), .. } => {
|
||||
stream_ctx_array
|
||||
.rings
|
||||
.get_mut(&1)
|
||||
.ok_or(Error::new(EBADF))?
|
||||
}
|
||||
EndpointState::Init => return Err(Error::new(EIO)),
|
||||
};
|
||||
// TODO: Scatter-gather transfers, possibly allowing >64KiB sizes.
|
||||
let len = u16::try_from(buf.len()).or(Err(Error::new(ENOSYS)))?;
|
||||
@@ -671,6 +676,7 @@ impl Xhci {
|
||||
len,
|
||||
cycle,
|
||||
estimated_td_size,
|
||||
0,
|
||||
false,
|
||||
true,
|
||||
false,
|
||||
@@ -922,7 +928,7 @@ impl Xhci {
|
||||
.get_mut(&0)
|
||||
.ok_or(Error::new(EIO))?
|
||||
{
|
||||
EndpointState::Ready(super::RingOrStreams::Ring(ref mut ring)) => ring,
|
||||
EndpointState { transfer: super::RingOrStreams::Ring(ref mut ring), .. } => ring,
|
||||
|
||||
// Control endpoints never use streams
|
||||
_ => return Err(Error::new(EIO)),
|
||||
@@ -1074,84 +1080,6 @@ impl Xhci {
|
||||
}
|
||||
Ok(bytes_read)
|
||||
}
|
||||
fn completion_code_to_status(
|
||||
completion_code: u8,
|
||||
bytes_transferred: u16,
|
||||
) -> PortTransferStatus {
|
||||
if completion_code == TrbCompletionCode::Success as u8 {
|
||||
PortTransferStatus::Success
|
||||
} else if completion_code == TrbCompletionCode::ShortPacket as u8 {
|
||||
PortTransferStatus::ShortPacket(bytes_transferred as u16)
|
||||
} else if completion_code == TrbCompletionCode::Stall as u8 {
|
||||
PortTransferStatus::Stalled
|
||||
} else {
|
||||
PortTransferStatus::Unknown
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_transfer_write(
|
||||
&mut self,
|
||||
fd: usize,
|
||||
port_num: usize,
|
||||
endp_num: u8,
|
||||
mut st: PortTransferState,
|
||||
buf: &[u8],
|
||||
) -> Result<usize> {
|
||||
let bytes_written = match st {
|
||||
PortTransferState::Ready => {
|
||||
let (completion_code, bytes_written) =
|
||||
self.transfer_write(port_num, endp_num - 1, buf)?;
|
||||
st = PortTransferState::WaitingForStatusReq(Self::completion_code_to_status(
|
||||
completion_code,
|
||||
bytes_written as u16,
|
||||
));
|
||||
bytes_written
|
||||
}
|
||||
PortTransferState::WaitingForStatusReq(_) => return Err(Error::new(EBADF)),
|
||||
};
|
||||
match self.handles.get_mut(&fd).ok_or(Error::new(EBADF))? {
|
||||
Handle::Endpoint(_, _, EndpointHandleTy::Transfer(ref mut state)) => *state = st,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
Ok(bytes_written as usize)
|
||||
}
|
||||
fn handle_transfer_read(
|
||||
&mut self,
|
||||
fd: usize,
|
||||
port_num: usize,
|
||||
endp_num: u8,
|
||||
mut st: PortTransferState,
|
||||
mut buf: &mut [u8],
|
||||
) -> Result<usize> {
|
||||
let bytes_read = match st {
|
||||
PortTransferState::Ready => {
|
||||
let (completion_code, bytes_transferred) =
|
||||
self.transfer_read(port_num, endp_num - 1, buf)?;
|
||||
// TODO: Perhaps transfers with large buffers could be broken up to smaller
|
||||
// transfers.
|
||||
st = PortTransferState::WaitingForStatusReq(Self::completion_code_to_status(
|
||||
completion_code,
|
||||
bytes_transferred as u16,
|
||||
));
|
||||
bytes_transferred as usize
|
||||
}
|
||||
PortTransferState::WaitingForStatusReq(status) => {
|
||||
// Use a cursor to count the number of bytes written
|
||||
let mut cursor = io::Cursor::new(buf);
|
||||
serde_json::to_writer(&mut cursor, &status).or(Err(Error::new(EIO)))?;
|
||||
st = PortTransferState::Ready;
|
||||
|
||||
cursor
|
||||
.seek(io::SeekFrom::Current(0))
|
||||
.or(Err(Error::new(EIO)))? as usize
|
||||
}
|
||||
};
|
||||
match self.handles.get_mut(&fd).ok_or(Error::new(EBADF))? {
|
||||
Handle::Endpoint(_, _, EndpointHandleTy::Transfer(ref mut state)) => *state = st,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
Ok(bytes_read)
|
||||
}
|
||||
}
|
||||
|
||||
impl SchemeMut for Xhci {
|
||||
@@ -1268,16 +1196,10 @@ impl SchemeMut for Xhci {
|
||||
/*if self.dev_ctx.contexts[port_state.slot as usize].endpoints.get(endpoint_num as usize).ok_or(Error::new(ENOENT))?.a.read() & 0b111 != 1 {
|
||||
return Err(Error::new(ENXIO)); // TODO: Find a proper error code for "endpoint not initialized".
|
||||
}*/
|
||||
let contents = match port_state
|
||||
.endpoint_states
|
||||
.get(&endpoint_num)
|
||||
.ok_or(Error::new(ENOENT))?
|
||||
{
|
||||
EndpointState::Ready { .. } if endpoint_num != 0 => "transfer\nstatus\n",
|
||||
EndpointState::Init | EndpointState::Ready { .. } => "status\n",
|
||||
if !port_state.endpoint_states.contains_key(&endpoint_num) {
|
||||
return Err(Error::new(ENOENT));
|
||||
}
|
||||
.as_bytes()
|
||||
.to_owned();
|
||||
let contents = "ctl\ndata\n".as_bytes().to_owned();
|
||||
|
||||
Handle::Endpoint(port_num, endpoint_num, EndpointHandleTy::Root(0, contents))
|
||||
}
|
||||
@@ -1296,37 +1218,8 @@ impl SchemeMut for Xhci {
|
||||
}
|
||||
|
||||
let st = match sub {
|
||||
"status" => {
|
||||
// status is read-only
|
||||
if flags & O_RDWR != O_RDONLY && flags & O_STAT == 0 {
|
||||
return Err(Error::new(EACCES));
|
||||
}
|
||||
EndpointHandleTy::Status(0)
|
||||
}
|
||||
"transfer" => {
|
||||
if endpoint_num == 0 {
|
||||
// Don't allow user programs to interface directly with the control
|
||||
// endpoint.
|
||||
return Err(Error::new(ENOENT));
|
||||
}
|
||||
let endp_desc = &port_state
|
||||
.dev_desc
|
||||
.config_descs
|
||||
.get(0)
|
||||
.ok_or(Error::new(EIO))?
|
||||
.interface_descs
|
||||
.get(0)
|
||||
.ok_or(Error::new(EIO))?
|
||||
.endpoints
|
||||
.get(endpoint_num as usize - 1)
|
||||
.ok_or(Error::new(ENOENT))?;
|
||||
if let EndpDirection::In = endp_desc.direction() {
|
||||
if flags & O_RDWR != O_RDONLY && flags & O_STAT != 0 {
|
||||
return Err(Error::new(EACCES));
|
||||
}
|
||||
}
|
||||
EndpointHandleTy::Transfer(PortTransferState::Ready)
|
||||
}
|
||||
"ctl" => EndpointHandleTy::Ctl,
|
||||
"data" => EndpointHandleTy::Data,
|
||||
_ => return Err(Error::new(ENOENT)),
|
||||
};
|
||||
Handle::Endpoint(port_num, endpoint_num, st)
|
||||
@@ -1385,9 +1278,7 @@ impl SchemeMut for Xhci {
|
||||
|
||||
Handle::PortState(_, _) | Handle::PortReq(_, _) => stat.st_mode = MODE_CHR,
|
||||
Handle::Endpoint(_, _, st) => match st {
|
||||
EndpointHandleTy::Status(_) | EndpointHandleTy::Transfer(_) => {
|
||||
stat.st_mode = MODE_CHR
|
||||
}
|
||||
EndpointHandleTy::Ctl | EndpointHandleTy::Data => stat.st_mode = MODE_CHR,
|
||||
EndpointHandleTy::Root(_, ref buf) => {
|
||||
stat.st_mode = MODE_DIR;
|
||||
stat.st_size = buf.len() as u64;
|
||||
@@ -1421,8 +1312,8 @@ impl SchemeMut for Xhci {
|
||||
endp_num,
|
||||
match st {
|
||||
EndpointHandleTy::Root(_, _) => "",
|
||||
EndpointHandleTy::Status(_) => "status",
|
||||
EndpointHandleTy::Transfer(_) => "transfer",
|
||||
EndpointHandleTy::Ctl => "ctl",
|
||||
EndpointHandleTy::Data => "data",
|
||||
}
|
||||
)
|
||||
.unwrap(),
|
||||
@@ -1451,13 +1342,11 @@ impl SchemeMut for Xhci {
|
||||
};
|
||||
Ok(*offset)
|
||||
}
|
||||
// Read-only unknown-length status strings
|
||||
Handle::Endpoint(_, _, EndpointHandleTy::Status(ref mut offset))
|
||||
| Handle::PortState(_, ref mut offset) => {
|
||||
*offset = match whence {
|
||||
SEEK_SET => cmp::max(0, pos),
|
||||
SEEK_CUR => cmp::max(0, *offset + pos),
|
||||
SEEK_END => return Err(Error::new(ESPIPE)),
|
||||
Handle::PortState(_, ref mut offset) => {
|
||||
match whence {
|
||||
SEEK_SET => *offset = pos,
|
||||
SEEK_CUR => *offset = pos,
|
||||
SEEK_END => *offset = pos,
|
||||
_ => return Err(Error::new(EINVAL)),
|
||||
};
|
||||
Ok(*offset)
|
||||
@@ -1487,39 +1376,9 @@ impl SchemeMut for Xhci {
|
||||
Handle::ConfigureEndpoints(_) => return Err(Error::new(EBADF)),
|
||||
|
||||
&mut Handle::Endpoint(port_num, endp_num, ref mut st) => match st {
|
||||
&mut EndpointHandleTy::Transfer(state) => {
|
||||
self.handle_transfer_read(fd, port_num, endp_num, state, buf)
|
||||
}
|
||||
EndpointHandleTy::Status(ref mut offset) => {
|
||||
let ps = self.port_states.get(&port_num).ok_or(Error::new(EBADF))?;
|
||||
let status = self
|
||||
.dev_ctx
|
||||
.contexts
|
||||
.get(ps.slot as usize)
|
||||
.ok_or(Error::new(EBADF))?
|
||||
.endpoints
|
||||
.get(endp_num as usize)
|
||||
.ok_or(Error::new(EBADF))?
|
||||
.a
|
||||
.read()
|
||||
& ENDPOINT_CONTEXT_STATUS_MASK;
|
||||
|
||||
let string = match status {
|
||||
0 => Some(EndpointStatus::Disabled),
|
||||
1 => Some(EndpointStatus::Enabled),
|
||||
2 => Some(EndpointStatus::Halted),
|
||||
3 => Some(EndpointStatus::Stopped),
|
||||
4 => Some(EndpointStatus::Error),
|
||||
_ => None,
|
||||
}
|
||||
.as_ref()
|
||||
.map(EndpointStatus::as_str)
|
||||
.unwrap_or("unknown")
|
||||
.as_bytes();
|
||||
|
||||
Ok(Self::write_dyn_string(string, buf, offset))
|
||||
}
|
||||
EndpointHandleTy::Root(_, _) => unreachable!(),
|
||||
EndpointHandleTy::Ctl => self.on_read_endp_ctl(port_num, endp_num, buf),
|
||||
EndpointHandleTy::Data => self.on_read_endp_data(port_num, endp_num, buf),
|
||||
EndpointHandleTy::Root(_, _) => return Err(Error::new(EBADF)),
|
||||
},
|
||||
&mut Handle::PortState(port_num, ref mut offset) => {
|
||||
let ps = self.port_states.get(&port_num).ok_or(Error::new(EBADF))?;
|
||||
@@ -1557,8 +1416,10 @@ impl SchemeMut for Xhci {
|
||||
self.configure_endpoints(port_num, buf)?;
|
||||
Ok(buf.len())
|
||||
}
|
||||
&mut Handle::Endpoint(port_num, endp_num, EndpointHandleTy::Transfer(state)) => {
|
||||
self.handle_transfer_write(fd, port_num, endp_num, state, buf)
|
||||
&mut Handle::Endpoint(port_num, endp_num, ref ep_file_ty) => match ep_file_ty {
|
||||
EndpointHandleTy::Ctl => self.on_write_endp_ctl(port_num, endp_num, buf),
|
||||
EndpointHandleTy::Data => self.on_write_endp_data(port_num, endp_num, buf),
|
||||
_ => return Err(Error::new(EBADF)),
|
||||
}
|
||||
&mut Handle::PortReq(port_num, ref mut st) => {
|
||||
let state = std::mem::replace(st, PortReqState::Tmp);
|
||||
@@ -1576,3 +1437,116 @@ impl SchemeMut for Xhci {
|
||||
Ok(0)
|
||||
}
|
||||
}
|
||||
impl Xhci {
|
||||
pub fn get_endp_status(&mut self, port_num: usize, endp_num: u8) -> Result<EndpointStatus> {
|
||||
let slot = self.port_states.get(&port_num).ok_or(Error::new(EBADFD))?.slot;
|
||||
let raw = self.dev_ctx.contexts.get(slot as usize).ok_or(Error::new(EBADFD))?.endpoints.get(endp_num as usize).ok_or(Error::new(EBADFD))?.a.read() & super::context::ENDPOINT_CONTEXT_STATUS_MASK;
|
||||
Ok(match raw {
|
||||
0 => EndpointStatus::Disabled,
|
||||
1 => EndpointStatus::Enabled,
|
||||
2 => EndpointStatus::Halted,
|
||||
3 => EndpointStatus::Stopped,
|
||||
4 => EndpointStatus::Error,
|
||||
_ => return Err(Error::new(EIO)),
|
||||
})
|
||||
}
|
||||
pub fn on_req_reset_device(&mut self, port_num: usize, endp_num: u8, no_clear_feature: bool) {
|
||||
}
|
||||
pub fn on_write_endp_ctl(&mut self, port_num: usize, endp_num: u8, buf: &[u8]) -> Result<usize> {
|
||||
let ep_if_state = &mut self.port_states.get_mut(&port_num).ok_or(Error::new(EBADF))?.endpoint_states.get_mut(&endp_num).ok_or(Error::new(EBADF))?.driver_if_state;
|
||||
let req = serde_json::from_slice::<XhciEndpCtlReq>(buf).or(Err(Error::new(EBADMSG)))?;
|
||||
match req {
|
||||
XhciEndpCtlReq::Status => match ep_if_state {
|
||||
state @ EndpIfState::Init => *state = EndpIfState::WaitingForStatus,
|
||||
_ => return Err(Error::new(EBADF)),
|
||||
}
|
||||
XhciEndpCtlReq::Reset { no_clear_feature } => match ep_if_state {
|
||||
EndpIfState::Init => self.on_req_reset_device(port_num, endp_num, no_clear_feature),
|
||||
_ => return Err(Error::new(EBADF)),
|
||||
}
|
||||
XhciEndpCtlReq::Transfer(direction) => match ep_if_state {
|
||||
state @ EndpIfState::Init => if direction == XhciEndpCtlDirection::NoData {
|
||||
// Yield the result directly because no bytes have to be sent or received
|
||||
// beforehand.
|
||||
let (completion_code, bytes_transferred) = self.transfer(port_num, endp_num - 1, DeviceReqData::NoData)?;
|
||||
if bytes_transferred > 0 { return Err(Error::new(EIO)) }
|
||||
let result = Self::transfer_result(completion_code, 0);
|
||||
|
||||
let new_state = &mut self.port_states.get_mut(&port_num).ok_or(Error::new(EBADF))?.endpoint_states.get_mut(&endp_num).ok_or(Error::new(EBADF))?.driver_if_state;
|
||||
*new_state = EndpIfState::WaitingForTransferResult(result)
|
||||
} else {
|
||||
*state = EndpIfState::WaitingForDataPipe(direction)
|
||||
}
|
||||
_ => return Err(Error::new(EBADF)),
|
||||
}
|
||||
_ => return Err(Error::new(ENOSYS)),
|
||||
}
|
||||
Ok(buf.len())
|
||||
}
|
||||
fn transfer_result(completion_code: u8, bytes_transferred: u32) -> PortTransferStatus {
|
||||
if completion_code == TrbCompletionCode::Success as u8 {
|
||||
PortTransferStatus::Success
|
||||
} else if completion_code == TrbCompletionCode::ShortPacket as u8 {
|
||||
PortTransferStatus::ShortPacket(bytes_transferred as u16)
|
||||
} else if completion_code == TrbCompletionCode::Stall as u8 {
|
||||
PortTransferStatus::Stalled
|
||||
} else {
|
||||
PortTransferStatus::Unknown
|
||||
}
|
||||
}
|
||||
pub fn on_write_endp_data(&mut self, port_num: usize, endp_num: u8, buf: &[u8]) -> Result<usize> {
|
||||
{
|
||||
let ep_if_state = &mut self.port_states.get_mut(&port_num).ok_or(Error::new(EBADF))?.endpoint_states.get_mut(&endp_num).ok_or(Error::new(EBADF))?.driver_if_state;
|
||||
match ep_if_state {
|
||||
state @ EndpIfState::WaitingForDataPipe(XhciEndpCtlDirection::Out) => (),
|
||||
_ => return Err(Error::new(EBADF)),
|
||||
}
|
||||
}
|
||||
{
|
||||
let (completion_code, bytes_transferred) = self.transfer_write(port_num, endp_num - 1, buf)?;
|
||||
let result = Self::transfer_result(completion_code, bytes_transferred);
|
||||
|
||||
let ep_if_state = &mut self.port_states.get_mut(&port_num).ok_or(Error::new(EBADF))?.endpoint_states.get_mut(&endp_num).ok_or(Error::new(EBADF))?.driver_if_state;
|
||||
*ep_if_state = EndpIfState::WaitingForTransferResult(result);
|
||||
Ok(bytes_transferred as usize)
|
||||
}
|
||||
}
|
||||
pub fn on_read_endp_ctl(&mut self, port_num: usize, endp_num: u8, buf: &mut [u8]) -> Result<usize> {
|
||||
let ep_if_state = &mut self.port_states.get_mut(&port_num).ok_or(Error::new(EBADF))?.endpoint_states.get_mut(&endp_num).ok_or(Error::new(EBADF))?.driver_if_state;
|
||||
|
||||
let res: XhciEndpCtlRes = match ep_if_state {
|
||||
&mut EndpIfState::Init => XhciEndpCtlRes::Idle,
|
||||
|
||||
state @ &mut EndpIfState::WaitingForStatus => {
|
||||
*state = EndpIfState::Init;
|
||||
XhciEndpCtlRes::Status(self.get_endp_status(port_num, endp_num)?)
|
||||
}
|
||||
&mut EndpIfState::WaitingForDataPipe(_) => XhciEndpCtlRes::Pending,
|
||||
&mut EndpIfState::WaitingForTransferResult(status) => {
|
||||
*ep_if_state = EndpIfState::Init;
|
||||
XhciEndpCtlRes::TransferResult(status)
|
||||
}
|
||||
};
|
||||
|
||||
let mut cursor = io::Cursor::new(buf);
|
||||
serde_json::to_writer(&mut cursor, &res).or(Err(Error::new(EIO)))?;
|
||||
Ok(cursor.seek(io::SeekFrom::Current(0)).unwrap() as usize)
|
||||
}
|
||||
pub fn on_read_endp_data(&mut self, port_num: usize, endp_num: u8, buf: &mut [u8]) -> Result<usize> {
|
||||
{
|
||||
let ep_if_state = &mut self.port_states.get_mut(&port_num).ok_or(Error::new(EBADF))?.endpoint_states.get_mut(&endp_num).ok_or(Error::new(EBADF))?.driver_if_state;
|
||||
match ep_if_state {
|
||||
EndpIfState::WaitingForDataPipe(XhciEndpCtlDirection::In) => (),
|
||||
_ => return Err(Error::new(EBADF)),
|
||||
}
|
||||
}
|
||||
{
|
||||
let (completion_code, bytes_transferred) = self.transfer_read(port_num, endp_num, buf)?;
|
||||
let result = Self::transfer_result(completion_code, bytes_transferred);
|
||||
|
||||
let ep_if_state = &mut self.port_states.get_mut(&port_num).ok_or(Error::new(EBADF))?.endpoint_states.get_mut(&endp_num).ok_or(Error::new(EBADF))?.driver_if_state;
|
||||
*ep_if_state = EndpIfState::WaitingForTransferResult(result);
|
||||
Ok(bytes_transferred as usize)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -297,6 +297,7 @@ impl Trb {
|
||||
len: u16,
|
||||
cycle: bool,
|
||||
estimated_td_size: u8,
|
||||
interrupter: u8,
|
||||
ent: bool,
|
||||
isp: bool,
|
||||
chain: bool,
|
||||
@@ -308,11 +309,11 @@ impl Trb {
|
||||
// NOTE: The interrupter target and no snoop flags have been omitted.
|
||||
self.set(
|
||||
buffer,
|
||||
u32::from(len) | (u32::from(estimated_td_size) << 17),
|
||||
u32::from(len) | (u32::from(estimated_td_size) << 17) | (u32::from(interrupter) << 21),
|
||||
u32::from(cycle)
|
||||
| (u32::from(ent) << 1)
|
||||
| (u32::from(isp) << 2)
|
||||
| (u32::from(ent) << 4)
|
||||
| (u32::from(chain) << 4)
|
||||
| (u32::from(ioc) << 5)
|
||||
| (u32::from(idt) << 6)
|
||||
| (u32::from(bei) << 9)
|
||||
|
||||
Reference in New Issue
Block a user