Add basic logic to usbscsid and support alternate interface.

This commit is contained in:
4lDO2
2020-02-10 11:23:18 +01:00
parent 62915fadb1
commit cff3cf0d28
12 changed files with 248 additions and 47 deletions
Generated
+7
View File
@@ -53,6 +53,11 @@ dependencies = [
"safemem 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "base64"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "bgad"
version = "0.1.0"
@@ -1337,6 +1342,7 @@ dependencies = [
name = "usbscsid"
version = "0.1.0"
dependencies = [
"base64 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
"plain 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"thiserror 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)",
"xhcid 0.1.0",
@@ -1470,6 +1476,7 @@ dependencies = [
"checksum arrayvec 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "cd9fd44efafa8690358b7408d253adf110036b88f55672a933f01d616ad9b1b9"
"checksum autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2"
"checksum autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d"
"checksum base64 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b41b7ea54a0c9d92199de89e20e58d49f02f8e699814ef3fdf266f6f748d15c7"
"checksum base64 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "489d6c0ed21b11d038c31b6ceccca973e65d73ba3bd8ecb9a2babf5546164643"
"checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d"
"checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
+1 -1
View File
@@ -107,7 +107,7 @@ fn main() {
println!("{:?}", item);
}
handle.configure_endpoints(&ConfigureEndpointsReq { config_desc: 0 }).expect("Failed to configure endpoints");
handle.configure_endpoints(&ConfigureEndpointsReq { config_desc: 0, interface_desc: None, alternate_setting: None }).expect("Failed to configure endpoints");
let (mut global_state, mut local_state, mut stack) = (GlobalItemsState::default(), LocalItemsState::default(), Vec::new());
+1
View File
@@ -8,6 +8,7 @@ license = "MIT"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
base64 = "0.11" # Only for debugging
plain = "0.2"
thiserror = "1"
xhcid = { path = "../xhcid" }
+28 -2
View File
@@ -18,9 +18,35 @@ fn main() {
let handle = XhciClientHandle::new(scheme, port);
let desc = handle.get_standard_descs().expect("Failed to get standard descriptors");
// TODO: Perhaps the drivers should just be given the config, interface, and alternate setting
// from xhcid.
let (conf_desc, configuration_value, (if_desc, interface_num, alternate_setting)) = desc.config_descs.iter().find_map(|config_desc| {
let interface_desc = config_desc.interface_descs.iter().find_map(|if_desc| if if_desc.class == 8 && if_desc.sub_class == 6 && if_desc.protocol == 0x50 {
Some((if_desc.clone(), if_desc.number, if_desc.alternate_setting))
} else {
None
})?;
Some((config_desc.clone(), config_desc.configuration_value, interface_desc))
}).expect("Failed to find suitable configuration");
handle.configure_endpoints(&ConfigureEndpointsReq {
config_desc: 0,
config_desc: configuration_value,
interface_desc: Some(interface_num),
alternate_setting: Some(alternate_setting),
}).expect("Failed to configure endpoints");
let protocol = protocol::setup(&handle, protocol);
let mut protocol = protocol::setup(&handle, protocol, &desc, &conf_desc, &if_desc).expect("Failed to setup protocol");
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)
};
use protocol::Protocol;
protocol.send_command(unsafe { plain::as_bytes(&get_info) }).expect("Failed to send command");
}
+92 -10
View File
@@ -1,7 +1,10 @@
use std::slice;
use std::convert::TryInto;
use std::fs::File;
use std::io::prelude::*;
use std::{io, slice};
use thiserror::Error;
use xhcid_interface::{DeviceReqData, PortReqTy, PortReqRecipient, XhciClientHandle, XhciClientHandleError};
use xhcid_interface::{ConfDesc, DeviceReqData, EndpDirection, EndpointStatus, IfDesc, PortReqDirection, PortReqTy, PortReqRecipient, XhciClientHandle, XhciClientHandleError, XhciEndpStatusHandle};
use super::{Protocol, ProtocolError};
@@ -12,6 +15,7 @@ pub const CBW_FLAGS_DIRECTION_BIT: u8 = 1 << CBW_FLAGS_DIRECTION_SHIFT;
pub const CBW_FLAGS_DIRECTION_SHIFT: u8 = 7;
#[repr(packed)]
#[derive(Clone, Copy, Debug, Default)]
pub struct CommandBlockWrapper {
pub signature: u32,
pub tag: u32,
@@ -21,6 +25,7 @@ pub struct CommandBlockWrapper {
pub cb_len: u8,
pub command_block: [u8; 16],
}
unsafe impl plain::Plain for CommandBlockWrapper {}
pub const CSW_SIGNATURE: u32 = 0x53425355;
@@ -33,33 +38,110 @@ pub enum CswStatus {
}
#[repr(packed)]
#[derive(Clone, Copy, Debug, Default)]
pub struct CommandStatusWrapper {
pub signature: u32,
pub tag: u32,
pub data_residue: u32,
pub status: u8,
}
unsafe impl plain::Plain for CommandStatusWrapper {}
pub struct BulkOnlyTransport<'a> {
handle: &'a XhciClientHandle,
bulk_in: File,
bulk_out: File,
bulk_in_status: XhciEndpStatusHandle,
bulk_out_status: XhciEndpStatusHandle,
bulk_in_num: u8,
bulk_out_num: u8,
max_lun: u8,
current_tag: u32,
}
impl<'a> BulkOnlyTransport<'a> {
pub fn init(handle: &'a XhciClientHandle) -> Result<Self, ProtocolError> {
let lun = get_max_lun(handle, 0)?;
println!("BOT_MAX_LUN {}", lun);
pub fn init(handle: &'a XhciClientHandle, config_desc: &ConfDesc, if_desc: &IfDesc) -> Result<Self, ProtocolError> {
let endpoints = &if_desc.endpoints;
let bulk_in_num = (endpoints.iter().position(|endpoint| endpoint.direction() == EndpDirection::In).unwrap() + 1) as u8;
let bulk_out_num = (endpoints.iter().position(|endpoint| endpoint.direction() == EndpDirection::Out).unwrap() + 1) as u8;
let max_lun = get_max_lun(handle, 0)?;
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_num,
bulk_out_num,
handle,
max_lun,
current_tag: 0,
})
}
fn recover_from_stall(&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)?;
if self.bulk_in_status.current_status()? == EndpointStatus::Halted || self.bulk_out_status.current_status()? == EndpointStatus::Halted {
return Err(ProtocolError::RecoveryFailed)
}
Ok(())
}
}
impl<'a> Protocol for BulkOnlyTransport<'a> {
fn send_command_block(&mut self, cb: &[u8]) -> Result<(), ProtocolError> {
todo!()
}
fn recv_command_block(&mut self, cb: &mut [u8]) -> Result<(), ProtocolError> {
todo!()
fn send_command(&mut self, cb: &[u8]) -> Result<(), ProtocolError> {
dbg!(self.bulk_in_status.current_status()?);
dbg!(self.bulk_out_status.current_status()?);
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);
let cbw = CommandBlockWrapper {
signature: CBW_SIGNATURE,
tag,
data_transfer_len: 256, // TODO
lun: 0, // TODO
flags: 1 << 7, // TODO
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");
}
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[..]));
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");
}
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()?);
}
Ok(())
}
}
+12 -5
View File
@@ -1,5 +1,7 @@
use std::io;
use thiserror::Error;
use xhcid_interface::{XhciClientHandle, XhciClientHandleError};
use xhcid_interface::{DevDesc, ConfDesc, IfDesc, XhciClientHandle, XhciClientHandleError};
#[derive(Debug, Error)]
pub enum ProtocolError {
@@ -8,11 +10,16 @@ pub enum ProtocolError {
#[error("xhcid connection error: {0}")]
XhciError(#[from] XhciClientHandleError),
#[error("i/o error")]
IoError(#[from] io::Error),
#[error("attempted recovery failed")]
RecoveryFailed,
}
pub trait Protocol {
fn send_command_block(&mut self, cb: &[u8]) -> Result<(), ProtocolError>;
fn recv_command_block(&mut self, cb: &mut [u8]) -> Result<(), ProtocolError>;
fn send_command(&mut self, command: &[u8]) -> Result<(), ProtocolError>;
}
/// Bulk-only transport
@@ -24,9 +31,9 @@ mod uas {
use bot::BulkOnlyTransport;
pub fn setup<'a>(handle: &'a XhciClientHandle, protocol: u8) -> Option<Box<dyn Protocol + 'a>> {
pub fn setup<'a>(handle: &'a XhciClientHandle, protocol: u8, dev_desc: &DevDesc, conf_desc: &ConfDesc, if_desc: &IfDesc) -> Option<Box<dyn Protocol + 'a>> {
match protocol {
0x50 => Some(Box::new(BulkOnlyTransport::init(handle).unwrap())),
0x50 => Some(Box::new(BulkOnlyTransport::init(handle, conf_desc, if_desc).unwrap())),
_ => None,
}
}
+20
View File
@@ -13,6 +13,26 @@ pub struct ReportIdentInfo {
pub info_ty: u8,
pub control: u8,
}
impl ReportIdentInfo {
pub fn new(alloc_len: u32, info_ty: ReportIdInfoInfoTy, control: u8) -> Self {
Self {
opcode: Opcode::ServiceActionA3 as u8,
serviceaction: ServiceActionA3::ReportIdentInfo as u8,
_rsvd: 0,
restricted: 0,
alloc_len: u32::to_le(alloc_len),
info_ty: (info_ty as u8) << REP_ID_INFO_INFO_TY_SHIFT,
control,
}
}
}
#[repr(u8)]
pub enum ReportIdInfoInfoTy {
PeripheralDevIdInfo = 0b000_0000,
PeripheralDevTextIdInfo = 0b000_0010,
IdentInfoSupp = 0b111_1111,
// every other number ending with a 1 is restricted
}
pub const REP_ID_INFO_INFO_TY_MASK: u8 = 0xFE;
pub const REP_ID_INFO_INFO_TY_SHIFT: u8 = 1;
+28 -7
View File
@@ -16,8 +16,9 @@ pub use crate::usb::{EndpointTy, ENDP_ATTR_TY_MASK};
#[derive(Serialize, Deserialize)]
pub struct ConfigureEndpointsReq {
/// Index into the configuration descriptors of the device descriptor.
pub config_desc: usize,
// TODO: Support multiple alternate interfaces as well.
pub config_desc: u8,
pub interface_desc: Option<u8>,
pub alternate_setting: Option<u8>,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
@@ -65,8 +66,8 @@ pub enum EndpDirection {
impl From<PortReqDirection> for EndpDirection {
fn from(d: PortReqDirection) -> Self {
match d {
PortReqDirection::DeviceToHost => Self::In,
PortReqDirection::HostToDevice => Self::Out,
PortReqDirection::DeviceToHost => Self::In,
}
}
}
@@ -305,9 +306,6 @@ impl DeviceReqData<'_> {
_ => None,
}
}
}
impl<'a> DeviceReqData<'a> {
pub fn direction(&self) -> PortReqDirection {
match self {
DeviceReqData::Out(_) => PortReqDirection::HostToDevice,
@@ -345,7 +343,7 @@ impl XhciClientHandle {
let string = std::fs::read_to_string(path)?;
Ok(string.parse()?)
}
pub fn endpoint_status(
pub fn endpoint_onetime_status(
&self,
num: u8,
) -> result::Result<EndpointStatus, XhciClientHandleError> {
@@ -353,6 +351,13 @@ impl XhciClientHandle {
let string = std::fs::read_to_string(path)?;
Ok(string.parse()?)
}
pub fn open_endpoint_status(
&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<File, XhciClientHandleError> {
let path = format!("{}:port{}/endpoints/{}/transfer", self.scheme, self.port, num);
Ok(match direction {
@@ -413,6 +418,22 @@ impl XhciClientHandle {
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)
}
}
#[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)))?;
Ok(status.parse::<EndpointStatus>().or(Err(XhciClientHandleError::InvalidResponse(Invalid)))?)
}
}
#[derive(Debug, Error)]
+11 -2
View File
@@ -172,13 +172,22 @@ impl Setup {
}
}
pub const fn set_configuration(value: u16) -> Self {
pub const fn set_configuration(value: u8) -> Self {
Self {
kind: 0b0000_0000,
request: 0x09,
value: value,
value: value as u16,
index: 0,
length: 0,
}
}
pub const fn set_interface(interface: u8, alternate_setting: u8) -> Self {
Self {
kind: 0b0000_0001,
request: 0x09,
value: alternate_setting as u16,
index: interface as u16,
length: 0,
}
}
}
+4
View File
@@ -398,6 +398,10 @@ impl Xhci {
.collect::<BTreeMap<_, _>>(),
};
if self.cap.cic() {
self.op.set_cie(true);
}
/*match self.spawn_drivers(i, &mut port_state) {
Ok(()) => (),
Err(err) => println!("Failed to spawn driver for port {}: `{}`", i, err),
+2 -2
View File
@@ -16,10 +16,10 @@ pub struct OperationalRegs {
pub const OP_CONFIG_CIE_BIT: u32 = 1 << 9;
impl OperationalRegs {
fn cie(&self) -> bool {
pub fn cie(&self) -> bool {
self.config.readf(OP_CONFIG_CIE_BIT)
}
fn set_cie(&mut self, value: bool) {
pub fn set_cie(&mut self, value: bool) {
self.config.writef(OP_CONFIG_CIE_BIT, value)
}
}
+42 -18
View File
@@ -8,8 +8,8 @@ use smallvec::{smallvec, SmallVec};
use syscall::io::{Dma, Io};
use syscall::scheme::SchemeMut;
use syscall::{
Error, Result, Stat, EACCES, EBADF, EBADMSG, EEXIST, EINVAL, EIO, EISDIR, ENOENT, ENOSYS,
ENOTDIR, ENXIO, EOVERFLOW, EPERM, ESPIPE, MODE_CHR, MODE_DIR, MODE_FILE, O_CREAT, O_DIRECTORY,
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,
};
@@ -168,7 +168,7 @@ impl AnyDescriptor {
}
impl Xhci {
fn set_configuration(&mut self, port: usize, config: u16) -> Result<()> {
fn device_req_no_data(&mut self, port: usize, req: usb::Setup) -> Result<()> {
let ps = self.port_states.get_mut(&port).ok_or(Error::new(EIO))?;
let ring = ps
.endpoint_states
@@ -180,7 +180,7 @@ impl Xhci {
{
let (cmd, cycle) = ring.next();
cmd.setup(
usb::Setup::set_configuration(config),
req,
TransferKind::NoData,
cycle,
);
@@ -201,13 +201,13 @@ impl Xhci {
if (status >> 24) != TrbCompletionCode::Success as u32 {
println!(
"SET_CONFIGURATION ERROR, COMPLETION CODE {:#0x}",
"DEVICE_REQ ERROR, COMPLETION CODE {:#0x}",
(status >> 24)
);
}
println!(
"SET_CONFIGURATION EVENT {:#0x} {:#0x} {:#0x}",
"DEVICE_REQ EVENT {:#0x} {:#0x} {:#0x}",
event.data.read(),
status,
control
@@ -218,11 +218,27 @@ impl Xhci {
Ok(())
}
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 configure_endpoints(&mut self, port: usize, json_buf: &[u8]) -> Result<()> {
let req: ConfigureEndpointsReq =
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) {
//return Err(Error::new(EOPNOTSUPP));
req.config_desc = 0;
req.alternate_setting = None;
req.interface_desc = None;
}
if req.interface_desc.is_some() != req.alternate_setting.is_some() {
return Err(Error::new(EBADMSG));
}
let port_state = self.port_states.get_mut(&port).ok_or(Error::new(ENOENT))?;
let input_context: &mut Dma<InputContext> = &mut port_state.input_context;
@@ -236,7 +252,7 @@ impl Xhci {
let current_slot_a = input_context.device.slot.a.read();
let endpoints =
&port_state.dev_desc.config_descs[req.config_desc].interface_descs[0].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));
@@ -249,13 +265,15 @@ 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));
let lec = self.cap.lec();
for index in 0..endpoints.len() as u8 {
let endp_num = index + 1;
let xhc_endp_num = endp_num + 1;
input_context.add_context.writef(1 << (endp_num + 1), true);
input_context.add_context.writef(1 << xhc_endp_num, true);
let endp_ctx = input_context
.device
@@ -394,10 +412,14 @@ impl Xhci {
let configuration_value = port_state
.dev_desc
.config_descs
.get(req.config_desc)
.get(req.config_desc as usize)
.ok_or(Error::new(EIO))?
.configuration_value;
self.set_configuration(port, configuration_value.into())?;
self.set_configuration(port, configuration_value)?;
if let (Some(interface_num), Some(alternate_setting)) = (req.interface_desc, req.alternate_setting) {
self.set_interface(port, interface_num, alternate_setting)?;
}
Ok(())
}
@@ -410,6 +432,7 @@ impl Xhci {
// TODO: Rename DeviceReqData to something more general.
fn transfer(&mut self, port_num: usize, endp_idx: u8, mut buf: DeviceReqData) -> Result<u32> {
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),
// UB.
let dma_buffer = match buf {
@@ -424,18 +447,19 @@ impl Xhci {
DeviceReqData::NoData => None,
};
let port_state = self.port_states.get_mut(&port_num).ok_or(Error::new(EBADF))?;
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(EBADF))?;
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));
}
if EndpDirection::from(buf.direction()) != endp_desc.direction() {
dbg!(buf.direction(), endp_desc, endp_idx, endp_num);
return Err(Error::new(EBADF));
}
let endp_state = port_state.endpoint_states.get_mut(&endp_idx).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,
@@ -462,7 +486,7 @@ impl Xhci {
}
let stream_id = 1u16;
self.dbs[port_state.slot as usize].write(u32::from(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 event = self.cmd.next_event();
@@ -924,7 +948,7 @@ 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).ok_or(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 {
return Err(Error::new(EACCES));
@@ -1092,7 +1116,7 @@ impl SchemeMut for Xhci {
&mut Handle::Endpoint(port_num, endp_num, ref mut st) => match st {
EndpointHandleTy::Transfer => {
self.transfer_read(port_num, endp_num, buf)?;
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())
@@ -1172,7 +1196,7 @@ impl SchemeMut for Xhci {
Ok(buf.len())
}
&mut Handle::Endpoint(port_num, endp_num, EndpointHandleTy::Transfer) => {
self.transfer_write(port_num, endp_num, buf)?;
self.transfer_write(port_num, endp_num - 1, buf)?;
// TODO
Ok(buf.len())
}