Add periodic (driver interface-level) transfers.

This commit is contained in:
4lDO2
2020-02-10 23:12:11 +01:00
parent d64cb02986
commit d82ae0a5f6
11 changed files with 680 additions and 166 deletions
+6 -4
View File
@@ -1,6 +1,6 @@
use std::env;
use xhcid_interface::{ConfigureEndpointsReq, XhciClientHandle};
use xhcid_interface::{ConfigureEndpointsReq, DeviceReqData, XhciClientHandle};
pub mod protocol;
pub mod scsi;
@@ -39,14 +39,16 @@ fn main() {
let mut protocol = protocol::setup(&handle, protocol, &desc, &conf_desc, &if_desc).expect("Failed to setup protocol");
let get_info = {
/*let get_info = {
// Max number of bytes that can be recieved from a "REPORT IDENTIFYING INFORMATION"
// command.
let alloc_len = 256;
let info_ty = scsi::cmds::ReportIdInfoInfoTy::IdentInfoSupp;
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(&get_info) }).expect("Failed to send command");
protocol.send_command(unsafe { plain::as_bytes(&inquiry) }, DeviceReqData::In(&mut buffer)).expect("Failed to send command");
}
+76 -23
View File
@@ -4,7 +4,7 @@ use std::io::prelude::*;
use std::{io, slice};
use thiserror::Error;
use xhcid_interface::{ConfDesc, DeviceReqData, EndpDirection, EndpointStatus, IfDesc, PortReqDirection, PortReqTy, PortReqRecipient, XhciClientHandle, XhciClientHandleError, XhciEndpStatusHandle};
use xhcid_interface::{ConfDesc, DeviceReqData, EndpBinaryDirection, EndpDirection, EndpointStatus, IfDesc, Invalid, PortReqDirection, PortReqTy, PortReqRecipient, PortTransferStatus, XhciClientHandle, XhciClientHandleError, XhciEndpStatusHandle, XhciEndpTransferHandle};
use super::{Protocol, ProtocolError};
@@ -25,6 +25,28 @@ pub struct CommandBlockWrapper {
pub cb_len: u8,
pub command_block: [u8; 16],
}
impl CommandBlockWrapper {
pub fn new(tag: u32, data_transfer_len: u32, direction: EndpBinaryDirection, lun: u8, cb: &[u8]) -> Result<Self, ProtocolError> {
let mut command_block = [0u8; 16];
if cb.len() > 16 {
return Err(ProtocolError::TooLargeCommandBlock(cb.len()));
}
command_block[..cb.len()].copy_from_slice(&cb);
Ok(Self {
signature: CBW_SIGNATURE,
tag,
data_transfer_len,
flags: match direction {
EndpBinaryDirection::Out => 0,
EndpBinaryDirection::In => 1,
} << CBW_FLAGS_DIRECTION_SHIFT,
lun,
cb_len: cb.len() as u8,
command_block,
})
}
}
unsafe impl plain::Plain for CommandBlockWrapper {}
pub const CSW_SIGNATURE: u32 = 0x53425355;
@@ -47,10 +69,16 @@ pub struct CommandStatusWrapper {
}
unsafe impl plain::Plain for CommandStatusWrapper {}
impl CommandStatusWrapper {
pub fn is_valid(&self) -> bool {
self.signature == CSW_SIGNATURE
}
}
pub struct BulkOnlyTransport<'a> {
handle: &'a XhciClientHandle,
bulk_in: File,
bulk_out: File,
bulk_in: XhciEndpTransferHandle,
bulk_out: XhciEndpTransferHandle,
bulk_in_status: XhciEndpStatusHandle,
bulk_out_status: XhciEndpStatusHandle,
bulk_in_num: u8,
@@ -59,6 +87,8 @@ pub struct BulkOnlyTransport<'a> {
current_tag: u32,
}
pub const FEATURE_ENDPOINT_HALT: u16 = 0;
impl<'a> BulkOnlyTransport<'a> {
pub fn init(handle: &'a XhciClientHandle, config_desc: &ConfDesc, if_desc: &IfDesc) -> Result<Self, ProtocolError> {
let endpoints = &if_desc.endpoints;
@@ -81,11 +111,13 @@ impl<'a> BulkOnlyTransport<'a> {
current_tag: 0,
})
}
fn recover_from_stall(&mut self) -> Result<(), ProtocolError> {
fn clear_stall(&mut self, endp_num: u8) -> Result<(), XhciClientHandleError> {
self.handle.clear_feature(PortReqRecipient::Endpoint, u16::from(endp_num), FEATURE_ENDPOINT_HALT)
}
fn reset_recovery(&mut self) -> Result<(), ProtocolError> {
bulk_only_mass_storage_reset(self.handle, 0)?;
const ENDPOINT_HALT: u16 = 0;
self.handle.clear_feature(PortReqRecipient::Endpoint, self.bulk_in_num.into(), ENDPOINT_HALT)?;
self.handle.clear_feature(PortReqRecipient::Endpoint, self.bulk_out_num.into(), ENDPOINT_HALT)?;
self.clear_stall(self.bulk_in_num.into())?;
self.clear_stall(self.bulk_out_num.into())?;
if self.bulk_in_status.current_status()? == EndpointStatus::Halted || self.bulk_out_status.current_status()? == EndpointStatus::Halted {
return Err(ProtocolError::RecoveryFailed)
@@ -95,7 +127,7 @@ impl<'a> BulkOnlyTransport<'a> {
}
impl<'a> Protocol for BulkOnlyTransport<'a> {
fn send_command(&mut self, cb: &[u8]) -> Result<(), ProtocolError> {
fn send_command(&mut self, cb: &[u8], data: DeviceReqData) -> Result<(), ProtocolError> {
dbg!(self.bulk_in_status.current_status()?);
dbg!(self.bulk_out_status.current_status()?);
self.current_tag += 1;
@@ -110,34 +142,55 @@ impl<'a> Protocol for BulkOnlyTransport<'a> {
let cbw = CommandBlockWrapper {
signature: CBW_SIGNATURE,
tag,
data_transfer_len: 256, // TODO
data_transfer_len: data.len() as u32,
lun: 0, // TODO
flags: 1 << 7, // TODO
flags: u8::from(data.direction() == PortReqDirection::DeviceToHost) << 7,
cb_len: cb.len().try_into().or(Err(ProtocolError::TooLargeCommandBlock(cb.len())))?,
command_block,
};
let bytes_written = self.bulk_out.write(unsafe { plain::as_bytes(&cbw) })?;
if bytes_written != 31 {
panic!("invalid number of cbw bytes written");
match self.bulk_out.transfer_write(unsafe { plain::as_bytes(&cbw) })? {
PortTransferStatus::ShortPacket(31) => (),
PortTransferStatus::Stalled => {
panic!("bulk out endpoint stalled when sending CBW");
}
_ => panic!("invalid number of CBW bytes written; expected a short packed of length 31 (0x1F)"),
}
let mut buffer = [0u8; 256];
let bytes_read = self.bulk_in.read(&mut buffer)?;
if bytes_read != 256 {
panic!("invalid number of bytes read");
}
println!("{}", base64::encode(&buffer[..]));
match data {
DeviceReqData::In(buffer) => {
match self.bulk_in.transfer_read(buffer)? {
PortTransferStatus::Success => (),
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)?;
}
PortTransferStatus::Unknown => return Err(ProtocolError::XhciError(XhciClientHandleError::InvalidResponse(Invalid("unknown transfer status")))),
};
println!("{}", base64::encode(&buffer[..]));
}
DeviceReqData::Out(ref buffer) => todo!(),
DeviceReqData::NoData => todo!(),
};
let mut csw = CommandStatusWrapper::default();
let csw_bytes_read = self.bulk_in.read(unsafe { plain::as_mut_bytes(&mut csw) })?;
if csw_bytes_read != 13 {
panic!("invalid number of csw bytes read");
match self.bulk_in.transfer_read(unsafe { plain::as_mut_bytes(&mut csw) })? {
PortTransferStatus::ShortPacket(13) => (),
PortTransferStatus::Stalled => {
println!("bulk in endpoint stalled when reading CSW");
self.clear_stall(self.bulk_in_num)?;
}
_ => panic!("invalid number of CSW bytes read; expected a short packet of length 13 (0xD)"),
};
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 {
println!("Trying to recover from stall");
self.recover_from_stall()?;
dbg!(self.bulk_in_status.current_status()?, self.bulk_out_status.current_status()?);
}
+2 -2
View File
@@ -1,7 +1,7 @@
use std::io;
use thiserror::Error;
use xhcid_interface::{DevDesc, ConfDesc, IfDesc, XhciClientHandle, XhciClientHandleError};
use xhcid_interface::{DeviceReqData, DevDesc, ConfDesc, IfDesc, XhciClientHandle, XhciClientHandleError};
#[derive(Debug, Error)]
pub enum ProtocolError {
@@ -19,7 +19,7 @@ pub enum ProtocolError {
}
pub trait Protocol {
fn send_command(&mut self, command: &[u8]) -> Result<(), ProtocolError>;
fn send_command(&mut self, command: &[u8], data: DeviceReqData) -> Result<(), ProtocolError>;
}
/// Bulk-only transport
+23
View File
@@ -122,3 +122,26 @@ pub struct OneCommandParam {
pub a: u8,
// TODO
}
#[repr(packed)]
pub struct Inquiry {
pub opcode: u8,
/// bits 7:2 are reserved, bit 1 (CMDDT) is obsolete, bit 0 is EVPD
pub evpd: u8,
pub page_code: u8,
/// little endian
pub alloc_len: u16,
pub control: u8,
}
impl Inquiry {
pub fn new(evpd: bool, page_code: u8, alloc_len: u16, control: u8) -> Self {
Self {
opcode: Opcode::Inquiry as u8,
evpd: evpd as u8,
page_code,
alloc_len: u16::to_le(alloc_len),
control,
}
}
}
+154 -22
View File
@@ -63,6 +63,21 @@ pub enum EndpDirection {
In,
Bidirectional,
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum EndpBinaryDirection {
Out,
In,
}
impl From<EndpBinaryDirection> for EndpDirection {
fn from(b: EndpBinaryDirection) -> Self {
match b {
EndpBinaryDirection::In => Self::In,
EndpBinaryDirection::Out => Self::Out,
}
}
}
impl From<PortReqDirection> for EndpDirection {
fn from(d: PortReqDirection) -> Self {
match d {
@@ -185,7 +200,7 @@ pub struct PortReq {
pub length: u16,
pub transfers_data: bool,
}
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
pub enum PortReqDirection {
HostToDevice,
DeviceToHost,
@@ -230,7 +245,7 @@ impl PortState {
}
#[derive(Debug, Error)]
#[error("invalid input")]
pub struct Invalid;
pub struct Invalid(pub &'static str);
impl str::FromStr for PortState {
type Err = Invalid;
@@ -241,7 +256,7 @@ impl str::FromStr for PortState {
"default" => Self::Default,
"addressed" => Self::Addressed,
"configured" => Self::Configured,
_ => return Err(Invalid),
_ => return Err(Invalid("read reserved port state")),
})
}
}
@@ -256,6 +271,14 @@ pub enum EndpointStatus {
Error,
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
pub enum PortTransferStatus {
Success,
ShortPacket(u16),
Stalled,
Unknown,
}
impl EndpointStatus {
pub fn as_str(&self) -> &'static str {
match self {
@@ -278,7 +301,7 @@ impl str::FromStr for EndpointStatus {
"halted" => Self::Halted,
"stopped" => Self::Stopped,
"error" => Self::Error,
_ => return Err(Invalid),
_ => return Err(Invalid("read reserved endpoint state")),
})
}
}
@@ -334,7 +357,9 @@ impl XhciClientHandle {
let mut file = OpenOptions::new().read(false).write(true).open(path)?;
let json_bytes_written = file.write(&json)?;
if json_bytes_written != json.len() {
return Err(XhciClientHandleError::InvalidResponse(Invalid));
return Err(XhciClientHandleError::InvalidResponse(Invalid(
"configure_endpoints didn't read as many bytes as were requested",
)));
}
Ok(())
}
@@ -356,14 +381,35 @@ impl XhciClientHandle {
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)?))
Ok(XhciEndpStatusHandle(
OpenOptions::new()
.read(true)
.write(false)
.create(false)
.open(path)?,
))
}
pub fn open_endpoint(&self, num: u8, direction: PortReqDirection) -> result::Result<File, XhciClientHandleError> {
let path = format!("{}:port{}/endpoints/{}/transfer", self.scheme, self.port, num);
Ok(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)?,
})
pub fn open_endpoint(
&self,
num: u8,
direction: PortReqDirection,
) -> result::Result<XhciEndpTransferHandle, XhciClientHandleError> {
let path = format!(
"{}:port{}/endpoints/{}/transfer",
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)?,
}))
}
pub fn device_request<'a>(
&self,
@@ -374,7 +420,8 @@ impl XhciClientHandle {
index: u16,
data: DeviceReqData<'a>,
) -> result::Result<(), XhciClientHandleError> {
let length = u16::try_from(data.len()).or(Err(XhciClientHandleError::TransferBufTooLarge(data.len())))?;
let length = u16::try_from(data.len())
.or(Err(XhciClientHandleError::TransferBufTooLarge(data.len())))?;
let req = PortReq {
direction: data.direction(),
@@ -393,7 +440,9 @@ impl XhciClientHandle {
let json_bytes_written = file.write(&json)?;
if json_bytes_written != json.len() {
return Err(XhciClientHandleError::InvalidResponse(Invalid));
return Err(XhciClientHandleError::InvalidResponse(Invalid(
"device_request didn't return the same number of bytes as were written",
)));
}
match data {
@@ -401,25 +450,55 @@ impl XhciClientHandle {
let bytes_read = file.read(buf)?;
if bytes_read != buf.len() {
return Err(XhciClientHandleError::InvalidResponse(Invalid));
return Err(XhciClientHandleError::InvalidResponse(Invalid(
"device_request didn't transfer (host2dev) all bytes",
)));
}
}
DeviceReqData::Out(buf) => {
let bytes_read = file.write(&buf)?;
if bytes_read != buf.len() {
return Err(XhciClientHandleError::InvalidResponse(Invalid));
return Err(XhciClientHandleError::InvalidResponse(Invalid(
"device_request didn't transfer (dev2host) all bytes",
)));
}
}
DeviceReqData::NoData => (),
}
Ok(())
}
pub fn get_descriptor(&self, recipient: PortReqRecipient, ty: u8, idx: u8, windex: u16, buffer: &mut [u8]) -> result::Result<(), XhciClientHandleError> {
self.device_request(PortReqTy::Standard, recipient, 0x06, (u16::from(ty) << 8) | u16::from(idx), windex, DeviceReqData::In(buffer))
pub fn get_descriptor(
&self,
recipient: PortReqRecipient,
ty: u8,
idx: u8,
windex: u16,
buffer: &mut [u8],
) -> result::Result<(), XhciClientHandleError> {
self.device_request(
PortReqTy::Standard,
recipient,
0x06,
(u16::from(ty) << 8) | u16::from(idx),
windex,
DeviceReqData::In(buffer),
)
}
pub fn clear_feature(&self, recipient: PortReqRecipient, index: u16, feature_sel: u16) -> result::Result<(), XhciClientHandleError> {
self.device_request(PortReqTy::Standard, recipient, 0x01, feature_sel, index, DeviceReqData::NoData)
pub fn clear_feature(
&self,
recipient: PortReqRecipient,
index: u16,
feature_sel: u16,
) -> result::Result<(), XhciClientHandleError> {
self.device_request(
PortReqTy::Standard,
recipient,
0x01,
feature_sel,
index,
DeviceReqData::NoData,
)
}
}
@@ -431,8 +510,61 @@ impl XhciEndpStatusHandle {
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)))?;
Ok(status.parse::<EndpointStatus>().or(Err(XhciClientHandleError::InvalidResponse(Invalid)))?)
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
}
}
#[derive(Debug)]
pub struct XhciEndpTransferHandle(File);
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)?;
let status = serde_json::from_slice(dbg!(&status_buf[..status_bytes_read]))?;
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")));
}
}
Ok(status)
}
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)
}
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 into_inner(self) -> File {
self.0
}
}
+2 -1
View File
@@ -39,7 +39,8 @@ impl CapabilityRegs {
as u8
}
pub fn max_ports(&self) -> u8 {
((self.hcs_params1.read() & HCS_PARAMS1_MAX_PORTS_MASK) >> HCS_PARAMS1_MAX_PORTS_SHIFT) as u8
((self.hcs_params1.read() & HCS_PARAMS1_MAX_PORTS_MASK) >> HCS_PARAMS1_MAX_PORTS_SHIFT)
as u8
}
pub fn max_slots(&self) -> u8 {
(self.hcs_params1.read() & HCS_PARAMS1_MAX_SLOTS_MASK) as u8
+24 -14
View File
@@ -8,9 +8,7 @@ pub struct ExtendedCapabilitiesIter {
}
impl ExtendedCapabilitiesIter {
pub unsafe fn new(base: *const u8) -> Self {
Self {
base,
}
Self { base }
}
}
impl Iterator for ExtendedCapabilitiesIter {
@@ -26,7 +24,11 @@ impl Iterator for ExtendedCapabilitiesIter {
let next_rel = u16::from(next_rel_in_dwords) << 2;
self.base = if next_rel != 0 { self.base.offset(next_rel as isize) } else { ptr::null() };
self.base = if next_rel != 0 {
self.base.offset(next_rel as isize)
} else {
ptr::null()
};
Some((current, capability_id))
}
@@ -109,9 +111,7 @@ pub enum Lp {
impl ProtocolSpeed {
pub const fn from_raw(raw: u32) -> Self {
Self {
a: Mmio::from(raw),
}
Self { a: Mmio::from(raw) }
}
pub fn is_lowspeed(&self) -> bool {
self.psim() == 1500 && self.psie() == Psie::Kbps
@@ -196,11 +196,17 @@ pub const SUPP_PROTO_CAP_PORT_SLOT_TYPE_SHIFT: u8 = 0;
impl SupportedProtoCap {
pub unsafe fn protocol_speeds(&self) -> &[ProtocolSpeed] {
slice::from_raw_parts(&self.protocol_speeds as *const u8 as *const _, self.psic() as usize)
slice::from_raw_parts(
&self.protocol_speeds as *const u8 as *const _,
self.psic() as usize,
)
}
pub unsafe fn protocol_speeds_mut(&mut self) -> &mut [ProtocolSpeed] {
// XXX: Variance really is annoying sometimes.
slice::from_raw_parts_mut(&self.protocol_speeds as *const u8 as *mut u8 as *mut _, self.psic() as usize)
slice::from_raw_parts_mut(
&self.protocol_speeds as *const u8 as *mut u8 as *mut _,
self.psic() as usize,
)
}
pub fn rev_minor(&self) -> u8 {
((self.a.read() & SUPP_PROTO_CAP_REV_MIN_MASK) >> SUPP_PROTO_CAP_REV_MIN_SHIFT) as u8
@@ -213,10 +219,12 @@ impl SupportedProtoCap {
u32::to_le_bytes(self.b.read())
}
pub fn compat_port_offset(&self) -> u8 {
((self.c.read() & SUPP_PROTO_CAP_COMPAT_PORT_OFF_MASK) >> SUPP_PROTO_CAP_COMPAT_PORT_OFF_SHIFT) as u8
((self.c.read() & SUPP_PROTO_CAP_COMPAT_PORT_OFF_MASK)
>> SUPP_PROTO_CAP_COMPAT_PORT_OFF_SHIFT) as u8
}
pub fn compat_port_count(&self) -> u8 {
((self.c.read() & SUPP_PROTO_CAP_COMPAT_PORT_CNT_MASK) >> SUPP_PROTO_CAP_COMPAT_PORT_CNT_SHIFT) as u8
((self.c.read() & SUPP_PROTO_CAP_COMPAT_PORT_CNT_MASK)
>> SUPP_PROTO_CAP_COMPAT_PORT_CNT_SHIFT) as u8
}
pub fn compat_port_range(&self) -> Range<u8> {
self.compat_port_offset()..self.compat_port_offset() + self.compat_port_count()
@@ -229,12 +237,12 @@ impl SupportedProtoCap {
((self.c.read() & SUPP_PROTO_CAP_PSIC_MASK) >> SUPP_PROTO_CAP_PSIC_SHIFT) as u8
}
pub fn proto_slot_ty(&self) -> u8 {
((self.d.read() & SUPP_PROTO_CAP_PORT_SLOT_TYPE_MASK) >> SUPP_PROTO_CAP_PORT_SLOT_TYPE_SHIFT) as u8
((self.d.read() & SUPP_PROTO_CAP_PORT_SLOT_TYPE_MASK)
>> SUPP_PROTO_CAP_PORT_SLOT_TYPE_SHIFT) as u8
}
}
impl fmt::Debug for SupportedProtoCap {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("SupportedProtoCap")
.field("rev_minor", &self.rev_minor())
.field("rev_major", &self.rev_major())
@@ -244,7 +252,9 @@ impl fmt::Debug for SupportedProtoCap {
.field("proto_defined", &self.proto_defined())
.field("psic", &self.psic())
.field("proto_slot_ty", &self.proto_slot_ty())
.field("proto_speeds", unsafe { &self.protocol_speeds().to_owned() })
.field("proto_speeds", unsafe {
&self.protocol_speeds().to_owned()
})
.finish()
}
}
+34 -19
View File
@@ -351,7 +351,11 @@ impl Xhci {
{
input.add_context.write(1 << 1 | 1); // Enable the slot (zeroth bit) and the control endpoint (first bit).
input.device.slot.a.write((1 << 27) | (u32::from(speed) << 20)); // FIXME: The speed field, bits 23:20, is deprecated.
input
.device
.slot
.a
.write((1 << 27) | (u32::from(speed) << 20)); // FIXME: The speed field, bits 23:20, is deprecated.
input.device.slot.b.write(((i as u32 + 1) & 0xFF) << 16);
// control endpoint?
@@ -501,18 +505,26 @@ impl Xhci {
Ok(())
}
pub fn capabilities_iter(&self) -> ExtendedCapabilitiesIter {
unsafe { ExtendedCapabilitiesIter::new((self.base as *mut u8).offset((self.cap.ext_caps_ptr_in_dwords() << 2) as isize)) }
unsafe {
ExtendedCapabilitiesIter::new(
(self.base as *mut u8).offset((self.cap.ext_caps_ptr_in_dwords() << 2) as isize),
)
}
}
pub fn supported_protocols_iter(&self) -> impl Iterator<Item = &'static SupportedProtoCap> {
self.capabilities_iter().filter_map(|(pointer, cap_num)| unsafe {
if cap_num == CapabilityId::SupportedProtocol as u8 {
Some(&*pointer.cast::<SupportedProtoCap>().as_ptr())
} else {
None
}
})
self.capabilities_iter()
.filter_map(|(pointer, cap_num)| unsafe {
if cap_num == CapabilityId::SupportedProtocol as u8 {
Some(&*pointer.cast::<SupportedProtoCap>().as_ptr())
} else {
None
}
})
}
pub fn supported_protocol_speeds(&self, port: u8) -> Option<impl Iterator<Item = &'static ProtocolSpeed>> {
pub fn supported_protocol_speeds(
&self,
port: u8,
) -> Option<impl Iterator<Item = &'static ProtocolSpeed>> {
use extended::*;
const DEFAULT_SUPP_PROTO_SPEEDS: [ProtocolSpeed; 7] = [
// Full-speed
@@ -521,7 +533,7 @@ impl Xhci {
| (false as u32) << PROTO_SPEED_PFD_SHIFT
| (Psie::Mbps as u32) << PROTO_SPEED_PSIE_SHIFT
| 12 << PROTO_SPEED_PSIM_SHIFT
| 1 << PROTO_SPEED_PSIV_SHIFT
| 1 << PROTO_SPEED_PSIV_SHIFT,
),
// Low-speed
ProtocolSpeed::from_raw(
@@ -529,7 +541,7 @@ impl Xhci {
| (false as u32) << PROTO_SPEED_PFD_SHIFT
| (Psie::Kbps as u32) << PROTO_SPEED_PSIE_SHIFT
| 1500 << PROTO_SPEED_PSIM_SHIFT
| 2 << PROTO_SPEED_PSIV_SHIFT
| 2 << PROTO_SPEED_PSIV_SHIFT,
),
// High-speed
ProtocolSpeed::from_raw(
@@ -537,7 +549,7 @@ impl Xhci {
| (false as u32) << PROTO_SPEED_PFD_SHIFT
| (Psie::Mbps as u32) << PROTO_SPEED_PSIE_SHIFT
| 480 << PROTO_SPEED_PSIM_SHIFT
| 3 << PROTO_SPEED_PSIV_SHIFT
| 3 << PROTO_SPEED_PSIV_SHIFT,
),
// SuperSpeed Gen1 x1
ProtocolSpeed::from_raw(
@@ -546,7 +558,7 @@ impl Xhci {
| (Psie::Gbps as u32) << PROTO_SPEED_PSIE_SHIFT
| 5 << PROTO_SPEED_PSIM_SHIFT
| (Lp::SuperSpeed as u32) << PROTO_SPEED_LP_SHIFT
| 4 << PROTO_SPEED_PSIV_SHIFT
| 4 << PROTO_SPEED_PSIV_SHIFT,
),
// SuperSpeedPlus Gen2 x1
ProtocolSpeed::from_raw(
@@ -555,7 +567,7 @@ impl Xhci {
| (Psie::Gbps as u32) << PROTO_SPEED_PSIE_SHIFT
| 10 << PROTO_SPEED_PSIM_SHIFT
| (Lp::SuperSpeedPlus as u32) << PROTO_SPEED_LP_SHIFT
| 5 << PROTO_SPEED_PSIV_SHIFT
| 5 << PROTO_SPEED_PSIV_SHIFT,
),
// SuperSpeedPlus Gen1 x2
ProtocolSpeed::from_raw(
@@ -564,7 +576,7 @@ impl Xhci {
| (Psie::Gbps as u32) << PROTO_SPEED_PSIE_SHIFT
| 10 << PROTO_SPEED_PSIM_SHIFT
| (Lp::SuperSpeedPlus as u32) << PROTO_SPEED_LP_SHIFT
| 6 << PROTO_SPEED_PSIV_SHIFT
| 6 << PROTO_SPEED_PSIV_SHIFT,
),
// SuperSpeedPlus Gen2 x2
ProtocolSpeed::from_raw(
@@ -573,10 +585,12 @@ impl Xhci {
| (Psie::Gbps as u32) << PROTO_SPEED_PSIE_SHIFT
| 20 << PROTO_SPEED_PSIM_SHIFT
| (Lp::SuperSpeedPlus as u32) << PROTO_SPEED_LP_SHIFT
| 7 << PROTO_SPEED_PSIV_SHIFT
| 7 << PROTO_SPEED_PSIV_SHIFT,
),
];
let supp_proto = self.supported_protocols_iter().find(|supp_proto| supp_proto.compat_port_range().contains(&port))?;
let supp_proto = self
.supported_protocols_iter()
.find(|supp_proto| supp_proto.compat_port_range().contains(&port))?;
Some(if supp_proto.psic() != 0 {
unsafe { supp_proto.protocol_speeds().iter() }
@@ -585,7 +599,8 @@ impl Xhci {
})
}
pub fn lookup_psiv(&self, port: u8, psiv: u8) -> Option<&'static ProtocolSpeed> {
self.supported_protocol_speeds(port)?.find(|speed| speed.psiv() == psiv)
self.supported_protocol_speeds(port)?
.find(|speed| speed.psiv() == psiv)
}
}
#[derive(Deserialize)]
+1 -1
View File
@@ -1,5 +1,5 @@
use std::slice;
use std::num::NonZeroU8;
use std::slice;
use syscall::io::{Io, Mmio};
use super::CapabilityRegs;
+303 -72
View File
@@ -1,6 +1,6 @@
use std::convert::TryFrom;
use std::io::prelude::*;
use std::{cmp, mem, path, str};
use std::{cmp, io, mem, path, str};
use serde::{Deserialize, Serialize};
use smallvec::{smallvec, SmallVec};
@@ -8,9 +8,9 @@ use smallvec::{smallvec, SmallVec};
use syscall::io::{Dma, Io};
use syscall::scheme::SchemeMut;
use syscall::{
Error, Result, Stat, EACCES, EBADF, EBADFD, EBADMSG, EEXIST, EINVAL, EIO, EISDIR, ENOENT, ENOSYS,
ENOTDIR, ENXIO, EOPNOTSUPP, EOVERFLOW, EPERM, ESPIPE, MODE_CHR, MODE_DIR, MODE_FILE, O_CREAT, O_DIRECTORY,
O_RDONLY, O_RDWR, O_STAT, O_WRONLY, SEEK_CUR, SEEK_END, SEEK_SET,
Error, Result, Stat, EACCES, EBADF, EBADFD, EBADMSG, EEXIST, EINVAL, EIO, EISDIR, ENOENT,
ENOSYS, ENOTDIR, ENXIO, EOPNOTSUPP, EOVERFLOW, EPERM, ESPIPE, MODE_CHR, MODE_DIR, MODE_FILE,
O_CREAT, O_DIRECTORY, O_RDONLY, O_RDWR, O_STAT, O_WRONLY, SEEK_CUR, SEEK_END, SEEK_SET,
};
use super::{port, usb};
@@ -33,7 +33,7 @@ use crate::driver_interface::*;
pub enum EndpointHandleTy {
/// portX/endpoints/Y/transfer. Write calls transfer data to the device, and read calls
/// transfer data from the device.
Transfer,
Transfer(PortTransferState),
/// portX/endpoints/Y/status
Status(usize), // offset
@@ -42,10 +42,19 @@ pub enum EndpointHandleTy {
Root(usize, Vec<u8>), // offset, content
}
#[derive(Clone, Copy)]
pub enum PortTransferState {
/// Ready to read or write to do another transfer
Ready,
/// Transfer has completed, and the status has to be read.
WaitingForStatusReq(PortTransferStatus),
}
pub enum PortReqState {
Init,
WaitingForDeviceBytes(Dma<[u8]>, usb::Setup), // buffer, setup params
WaitingForHostBytes(Dma<[u8]>, usb::Setup), // buffer, setup params
WaitingForHostBytes(Dma<[u8]>, usb::Setup), // buffer, setup params
TmpSetup(usb::Setup),
Tmp,
}
@@ -182,11 +191,7 @@ impl Xhci {
{
let (cmd, cycle) = ring.next();
cmd.setup(
req,
TransferKind::NoData,
cycle,
);
cmd.setup(req, TransferKind::NoData, cycle);
}
{
let (cmd, cycle) = ring.next();
@@ -203,10 +208,7 @@ impl Xhci {
let control = event.control.read();
if (status >> 24) != TrbCompletionCode::Success as u32 {
println!(
"DEVICE_REQ ERROR, COMPLETION CODE {:#0x}",
(status >> 24)
);
println!("DEVICE_REQ ERROR, COMPLETION CODE {:#0x}", (status >> 24));
}
println!(
@@ -224,15 +226,56 @@ impl Xhci {
fn set_configuration(&mut self, port: usize, config: u8) -> Result<()> {
self.device_req_no_data(port, usb::Setup::set_configuration(config))
}
fn set_interface(&mut self, port: usize, interface_num: u8, alternate_setting: u8) -> Result<()> {
self.device_req_no_data(port, usb::Setup::set_interface(interface_num, alternate_setting))
fn set_interface(
&mut self,
port: usize,
interface_num: u8,
alternate_setting: u8,
) -> Result<()> {
self.device_req_no_data(
port,
usb::Setup::set_interface(interface_num, alternate_setting),
)
}
fn reset_endpoint(&mut self, port_num: usize, endp_num: u8, tsp: bool) -> Result<()> {
let slot = self
.port_states
.get(&port_num)
.ok_or(Error::new(EBADF))?
.slot;
{
let (cmd, cycle, event) = self.cmd.next();
cmd.reset_endpoint(slot, endp_num + 1, tsp, cycle);
self.dbs[0].write(0);
while event.data.read() == 0 {
println!(" - Waiting for event");
}
if event.completion_code() != TrbCompletionCode::Success as u8
|| event.trb_type() != TrbType::CommandCompletion as u8
{
println!("RESET_ENDPOINT failed with event TRB ({:#0x} {:#0x} {:#0x}) and command TRB ({:#0x} {:#0x} {:#0x})", event.data.read(), event.status.read(), event.control.read(), cmd.data.read(), cmd.status.read(), cmd.control.read());
return Err(Error::new(EIO));
}
cmd.reserved(false);
event.reserved(false);
self.run.ints[0].erdp.write(self.cmd.erdp());
}
Ok(())
}
fn configure_endpoints(&mut self, port: usize, json_buf: &[u8]) -> Result<()> {
let mut req: ConfigureEndpointsReq =
serde_json::from_slice(json_buf).or(Err(Error::new(EBADMSG)))?;
if (!self.cap.cic() || !self.op.cie()) && (req.config_desc != 0 || req.interface_desc != None || req.alternate_setting != None) {
if (!self.cap.cic() || !self.op.cie())
&& (req.config_desc != 0 || req.interface_desc != None || req.alternate_setting != None)
{
//return Err(Error::new(EOPNOTSUPP));
req.config_desc = 0;
req.alternate_setting = None;
@@ -259,8 +302,13 @@ impl Xhci {
let current_slot_a = input_context.device.slot.a.read();
let endpoints =
&port_state.dev_desc.config_descs.get(req.config_desc as usize).ok_or(Error::new(EBADMSG))?.interface_descs[0].endpoints;
let endpoints = &port_state
.dev_desc
.config_descs
.get(req.config_desc as usize)
.ok_or(Error::new(EBADMSG))?
.interface_descs[0]
.endpoints;
if endpoints.len() >= 31 {
return Err(Error::new(EIO));
@@ -273,7 +321,11 @@ impl Xhci {
| ((u32::from(new_context_entries) << CONTEXT_ENTRIES_SHIFT)
& CONTEXT_ENTRIES_MASK),
);
input_context.control.write((u32::from(req.alternate_setting.unwrap_or(0)) << 16) | (u32::from(req.interface_desc.unwrap_or(0)) << 8) | u32::from(req.config_desc));
input_context.control.write(
(u32::from(req.alternate_setting.unwrap_or(0)) << 16)
| (u32::from(req.interface_desc.unwrap_or(0)) << 8)
| u32::from(req.config_desc),
);
let lec = self.cap.lec();
@@ -425,20 +477,49 @@ impl Xhci {
.configuration_value;
self.set_configuration(port, configuration_value)?;
if let (Some(interface_num), Some(alternate_setting)) = (req.interface_desc, req.alternate_setting) {
if let (Some(interface_num), Some(alternate_setting)) =
(req.interface_desc, req.alternate_setting)
{
self.set_interface(port, interface_num, alternate_setting)?;
}
Ok(())
}
fn transfer_read(&mut self, port_num: usize, endp_idx: u8, buf: &mut [u8]) -> Result<u32> {
self.transfer(port_num, endp_idx, if !buf.is_empty() { DeviceReqData::In(buf) } else { DeviceReqData::NoData })
fn transfer_read(
&mut self,
port_num: usize,
endp_idx: u8,
buf: &mut [u8],
) -> Result<(u8, u32)> {
self.transfer(
port_num,
endp_idx,
if !buf.is_empty() {
DeviceReqData::In(buf)
} else {
DeviceReqData::NoData
},
)
}
fn transfer_write(&mut self, port_num: usize, endp_idx: u8, buf: &[u8]) -> Result<u32> {
self.transfer(port_num, endp_idx, if !buf.is_empty() { DeviceReqData::Out(buf) } else { DeviceReqData::NoData })
fn transfer_write(&mut self, port_num: usize, endp_idx: u8, buf: &[u8]) -> Result<(u8, u32)> {
self.transfer(
port_num,
endp_idx,
if !buf.is_empty() {
DeviceReqData::Out(buf)
} else {
DeviceReqData::NoData
},
)
}
// TODO: Rename DeviceReqData to something more general.
fn transfer(&mut self, port_num: usize, endp_idx: u8, mut buf: DeviceReqData) -> Result<u32> {
fn transfer(
&mut self,
port_num: usize,
endp_idx: u8,
mut buf: DeviceReqData,
) -> Result<(u8, u32)> {
// TODO: Check that only readable enpoints are read, etc.
let endp_num = endp_idx + 1;
let xhc_endp_num = endp_num + 1;
// TODO: Check that buf has a nonzero size, otherwise (at least for Rust's GlobalAlloc),
@@ -455,8 +536,21 @@ impl Xhci {
DeviceReqData::NoData => None,
};
let port_state = self.port_states.get_mut(&port_num).ok_or(Error::new(EBADFD))?;
let endp_desc: &EndpDesc = port_state.dev_desc.config_descs.get(0).ok_or(Error::new(EIO))?.interface_descs.get(0).ok_or(Error::new(EIO))?.endpoints.get(endp_idx as usize).ok_or(Error::new(EBADFD))?;
let port_state = self
.port_states
.get_mut(&port_num)
.ok_or(Error::new(EBADFD))?;
let endp_desc: &EndpDesc = port_state
.dev_desc
.config_descs
.get(0)
.ok_or(Error::new(EIO))?
.interface_descs
.get(0)
.ok_or(Error::new(EIO))?
.endpoints
.get(endp_idx as usize)
.ok_or(Error::new(EBADFD))?;
if endp_desc.is_isoch() {
return Err(Error::new(ENOSYS));
@@ -467,11 +561,19 @@ impl Xhci {
return Err(Error::new(EBADF));
}
let endp_state = port_state.endpoint_states.get_mut(&endp_num).ok_or(Error::new(EBADF))?;
let endp_state = port_state
.endpoint_states
.get_mut(&endp_num)
.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)) => stream_ctx_array.rings.get_mut(&1).ok_or(Error::new(EBADF))?,
EndpointState::Ready(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.
@@ -485,42 +587,72 @@ impl Xhci {
bytes[..len as usize].copy_from_slice(&sbuf[..len as usize]);
// FIXME: little endian, right?
(u64::from_le_bytes(bytes), true)
}).unwrap_or((0, false))
})
.unwrap_or((0, false))
} else {
(dma_buffer.as_ref().map(|dma| dma.physical()).unwrap_or(0) as u64, false)
(
dma_buffer.as_ref().map(|dma| dma.physical()).unwrap_or(0) as u64,
false,
)
};
let estimated_td_size = mem::size_of_val(&trb) as u8; // one trb per td
trb.normal(buffer, len, cycle, estimated_td_size, false, true, false, true, idt, false);
trb.normal(
buffer,
len,
cycle,
estimated_td_size,
false,
true,
false,
true,
idt,
false,
);
}
let stream_id = 1u16;
self.dbs[port_state.slot as usize].write(u32::from(xhc_endp_num) | (u32::from(stream_id) << 16));
self.dbs[port_state.slot as usize]
.write(u32::from(xhc_endp_num) | (u32::from(stream_id) << 16));
let bytes_transferred = {
let (completion_code, bytes_transferred) = {
let event = self.cmd.next_event();
while event.data.read() == 0 {
println!(" - Waiting for event");
}
// FIXME: EDTLA if event data was set
if event.completion_code() != TrbCompletionCode::ShortPacket as u8 && event.transfer_length() != 0 {
println!("Event trb yielded a short packet, but all bytes were still transferred");
if event.completion_code() != TrbCompletionCode::ShortPacket as u8
&& event.transfer_length() != 0
{
println!(
"Event trb didn't yield a short packet, but some bytes were not transferred"
);
}
if event.completion_code() != TrbCompletionCode::Success as u8 || event.trb_type() != TrbType::Transfer as u8 {
println!("Custom transfer event failed with {:#0x} {:#0x} {:#0x}", event.data.read(), event.status.read(), event.control.read());
if event.completion_code() != TrbCompletionCode::Success as u8
|| event.trb_type() != TrbType::Transfer as u8
{
println!(
"Custom transfer event failed with {:#0x} {:#0x} {:#0x}",
event.data.read(),
event.status.read(),
event.control.read()
);
}
// TODO: Handle event data
println!("EVENT DATA: {:?}", event.event_data());
u32::from(len) - event.transfer_length()
(
event.completion_code(),
u32::from(len) - event.transfer_length(),
)
};
if let DeviceReqData::In(dbuf) = &mut buf {
dbuf.copy_from_slice(&*dma_buffer.as_ref().unwrap());
}
Ok(bytes_transferred)
Ok((completion_code, bytes_transferred as u32))
}
pub(crate) fn get_dev_desc(&mut self, port_id: usize) -> Result<DevDesc> {
let st = self
@@ -689,7 +821,13 @@ impl Xhci {
bytes_to_read
}
fn port_req_transfer(&mut self, port_num: usize, data_buffer: Option<&mut Dma<[u8]>>, setup: usb::Setup, transfer_kind: TransferKind) -> Result<()> {
fn port_req_transfer(
&mut self,
port_num: usize,
data_buffer: Option<&mut Dma<[u8]>>,
setup: usb::Setup,
transfer_kind: TransferKind,
) -> Result<()> {
// TODO: This json format might be too high level, but is useful for debugging,
// but when actual device-specific drivers are written, a binary format would
// be better. Maybe something simple like bincode could be used, if a custom binary struct
@@ -786,7 +924,13 @@ impl Xhci {
// FIXME: Make sure there aren't any other PortReq handles, perhaps by storing the state in
// PortState?
}
fn handle_port_req_write(&mut self, fd: usize, port_num: usize, mut st: PortReqState, buf: &[u8]) -> Result<usize> {
fn handle_port_req_write(
&mut self,
fd: usize,
port_num: usize,
mut st: PortReqState,
buf: &[u8],
) -> Result<usize> {
let bytes_written = match st {
PortReqState::Init => {
let req = serde_json::from_slice::<PortReq>(buf).or(Err(Error::new(EBADMSG)))?;
@@ -821,7 +965,13 @@ impl Xhci {
}
Ok(bytes_written)
}
fn handle_port_req_read(&mut self, fd: usize, port_num: usize, mut st: PortReqState, buf: &mut [u8]) -> Result<usize> {
fn handle_port_req_read(
&mut self,
fd: usize,
port_num: usize,
mut st: PortReqState,
buf: &mut [u8],
) -> Result<usize> {
let bytes_read = match st {
PortReqState::WaitingForDeviceBytes(mut dma_buffer, setup) => {
if buf.len() != dma_buffer.len() {
@@ -834,7 +984,9 @@ impl Xhci {
buf.len()
}
PortReqState::Init | PortReqState::WaitingForHostBytes(_, _) => return Err(Error::new(EBADF)),
PortReqState::Init | PortReqState::WaitingForHostBytes(_, _) => {
return Err(Error::new(EBADF))
}
PortReqState::Tmp | PortReqState::TmpSetup(_) => unreachable!(),
};
match self.handles.get_mut(&fd).ok_or(Error::new(EBADF))? {
@@ -843,6 +995,84 @@ 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 {
@@ -982,11 +1212,7 @@ impl SchemeMut for Xhci {
let port_state = self.port_states.get(&port_num).ok_or(Error::new(ENOENT))?;
if port_state
.endpoint_states
.get(&endpoint_num)
.is_none()
{
if port_state.endpoint_states.get(&endpoint_num).is_none() {
return Err(Error::new(ENOENT));
}
@@ -1004,17 +1230,23 @@ impl SchemeMut for Xhci {
// 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))?;
match endp_desc.direction() {
EndpDirection::Out => if flags & O_RDWR != O_WRONLY && flags & O_STAT != 0 {
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));
}
EndpDirection::In => if flags & O_RDWR != O_RDONLY && flags & O_STAT != 0 {
return Err(Error::new(EACCES));
}
_ => (),
}
EndpointHandleTy::Transfer
EndpointHandleTy::Transfer(PortTransferState::Ready)
}
_ => return Err(Error::new(ENOENT)),
};
@@ -1064,15 +1296,19 @@ impl SchemeMut for Xhci {
stat.st_mode = MODE_FILE;
stat.st_size = buf.len() as u64;
}
Handle::PortReq(_, PortReqState::WaitingForDeviceBytes(ref buf, _)) | Handle::PortReq(_, PortReqState::WaitingForHostBytes(ref buf, _)) => {
Handle::PortReq(_, PortReqState::WaitingForDeviceBytes(ref buf, _))
| Handle::PortReq(_, PortReqState::WaitingForHostBytes(ref buf, _)) => {
stat.st_mode = MODE_CHR;
stat.st_size = buf.len() as u64;
}
Handle::PortReq(_, PortReqState::Tmp) | Handle::PortReq(_, PortReqState::TmpSetup(_)) => unreachable!(),
Handle::PortReq(_, PortReqState::Tmp)
| Handle::PortReq(_, PortReqState::TmpSetup(_)) => unreachable!(),
Handle::PortState(_, _) | Handle::PortReq(_, _) => stat.st_mode = MODE_CHR,
Handle::Endpoint(_, _, st) => match st {
EndpointHandleTy::Status(_) | EndpointHandleTy::Transfer => stat.st_mode = MODE_CHR,
EndpointHandleTy::Status(_) | EndpointHandleTy::Transfer(_) => {
stat.st_mode = MODE_CHR
}
EndpointHandleTy::Root(_, ref buf) => {
stat.st_mode = MODE_DIR;
stat.st_size = buf.len() as u64;
@@ -1107,7 +1343,7 @@ impl SchemeMut for Xhci {
match st {
EndpointHandleTy::Root(_, _) => "",
EndpointHandleTy::Status(_) => "status",
EndpointHandleTy::Transfer => "transfer",
EndpointHandleTy::Transfer(_) => "transfer",
}
)
.unwrap(),
@@ -1172,11 +1408,8 @@ impl SchemeMut for Xhci {
Handle::ConfigureEndpoints(_) => return Err(Error::new(EBADF)),
&mut Handle::Endpoint(port_num, endp_num, ref mut st) => match st {
EndpointHandleTy::Transfer => {
self.transfer_read(port_num, endp_num - 1, buf)?;
// TODO: Perhaps transfers with large buffers could be broken up a to smaller
// transfers.
Ok(buf.len())
&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))?;
@@ -1245,10 +1478,8 @@ impl SchemeMut for Xhci {
self.configure_endpoints(port_num, buf)?;
Ok(buf.len())
}
&mut Handle::Endpoint(port_num, endp_num, EndpointHandleTy::Transfer) => {
self.transfer_write(port_num, endp_num - 1, buf)?;
// TODO
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::PortReq(port_num, ref mut st) => {
let state = std::mem::replace(st, PortReqState::Tmp);
+55 -8
View File
@@ -154,10 +154,15 @@ impl Trb {
self.control.readf(TRB_CONTROL_EVENT_DATA_BIT)
}
pub fn event_data(&self) -> Option<u64> {
if self.event_data_bit() { Some(self.data.read()) } else { None }
if self.event_data_bit() {
Some(self.data.read())
} else {
None
}
}
pub fn endpoint_id(&self) -> u8 {
((self.control.read() & TRB_CONTROL_ENDPOINT_ID_MASK) >> TRB_CONTROL_ENDPOINT_ID_SHIFT) as u8
((self.control.read() & TRB_CONTROL_ENDPOINT_ID_MASK) >> TRB_CONTROL_ENDPOINT_ID_SHIFT)
as u8
}
pub fn trb_type(&self) -> u8 {
((self.control.read() & TRB_CONTROL_TRB_TYPE_MASK) >> TRB_CONTROL_TRB_TYPE_SHIFT) as u8
@@ -205,8 +210,39 @@ impl Trb {
0,
(u32::from(slot_id) << 24)
| ((TrbType::ConfigureEndpoint as u32) << 10)
| (cycle as u32),
)
| u32::from(cycle),
);
}
pub fn reset_endpoint(&mut self, slot_id: u8, endp_num_xhc: u8, tsp: bool, cycle: bool) {
assert_eq!(endp_num_xhc & 0x1F, endp_num_xhc);
self.set(
0,
0,
(u32::from(slot_id) << 24)
| (u32::from(endp_num_xhc) << 16)
| ((TrbType::ResetEndpoint as u32) << 10)
| (u32::from(tsp) << 9)
| u32::from(cycle),
);
}
pub fn stop_endpoint(&mut self, slot_id: u8, endp_num_xhc: u8, suspend: bool, cycle: bool) {
assert_eq!(endp_num_xhc & 0x1F, endp_num_xhc);
self.set(
0,
0,
(u32::from(slot_id) << 24)
| (u32::from(suspend) << 23)
| (u32::from(endp_num_xhc) << 16)
| ((TrbType::StopEndpoint as u32) << 10)
| u32::from(cycle),
);
}
pub fn reset_device(&mut self, slot_id: u8, cycle: bool) {
self.set(
0,
0,
(u32::from(slot_id) << 24) | ((TrbType::ResetDevice as u32) << 10) | u32::from(cycle),
);
}
pub fn setup(&mut self, setup: usb::Setup, transfer: TransferKind, cycle: bool) {
@@ -238,13 +274,24 @@ impl Trb {
| (cycle as u32),
);
}
pub fn normal(&mut self, buffer: u64, len: u16, cycle: bool, estimated_td_size: u8, ent: bool, isp: bool, chain: bool, ioc: bool, idt: bool, bei: bool) {
pub fn normal(
&mut self,
buffer: u64,
len: u16,
cycle: bool,
estimated_td_size: u8,
ent: bool,
isp: bool,
chain: bool,
ioc: bool,
idt: bool,
bei: bool,
) {
assert_eq!(estimated_td_size & 0x1F, estimated_td_size);
// 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(cycle)
| (u32::from(ent) << 1)
| (u32::from(isp) << 2)
@@ -252,7 +299,7 @@ impl Trb {
| (u32::from(ioc) << 5)
| (u32::from(idt) << 6)
| (u32::from(bei) << 9)
| ((TrbType::Normal as u32) << 10)
| ((TrbType::Normal as u32) << 10),
)
}
}