Add basic logic to usbscsid and support alternate interface.
This commit is contained in:
Generated
+7
@@ -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
@@ -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());
|
||||
|
||||
|
||||
@@ -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
@@ -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");
|
||||
}
|
||||
|
||||
@@ -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(())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
@@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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
@@ -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())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user