Make the usb scsi scheme able to do block I/O.

This commit is contained in:
4lDO2
2020-02-15 00:26:19 +01:00
parent d44296dec9
commit bd0892e45d
13 changed files with 1104 additions and 323 deletions
+50 -20
View File
@@ -20,15 +20,26 @@ fn main() {
const USAGE: &'static str = "usbscsid <scheme> <port> <protocol>";
let scheme = args.next().expect(USAGE);
let port = args.next().expect(USAGE).parse::<usize>().expect("port has to be a number");
let protocol = args.next().expect(USAGE).parse::<u8>().expect("protocol has to be a number 0-255");
let port = args
.next()
.expect(USAGE)
.parse::<usize>()
.expect("port has to be a number");
let protocol = args
.next()
.expect(USAGE)
.parse::<u8>()
.expect("protocol has to be a number 0-255");
println!("USB SCSI driver spawned with scheme `{}`, port {}, protocol {}", scheme, port, protocol);
println!(
"USB SCSI driver spawned with scheme `{}`, port {}, protocol {}",
scheme, port, protocol
);
// Daemonize so that xhcid can continue to do other useful work (until proper IRQs,
// async-await, and multithreading :D)
if unsafe { syscall::clone(CloneFlags::empty()).unwrap() } != 0 {
return
return;
}
let disk_scheme_name = format!(":disk/{}-{}_scsi", scheme, port);
@@ -36,30 +47,46 @@ fn main() {
// TODO: Use eventfds.
let handle = XhciClientHandle::new(scheme, port);
let desc = handle.get_standard_descs().expect("Failed to get standard descriptors");
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");
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: configuration_value,
interface_desc: Some(interface_num),
alternate_setting: Some(alternate_setting),
}).expect("Failed to configure endpoints");
handle
.configure_endpoints(&ConfigureEndpointsReq {
config_desc: configuration_value,
interface_desc: Some(interface_num),
alternate_setting: Some(alternate_setting),
})
.expect("Failed to configure endpoints");
let mut protocol = protocol::setup(&handle, protocol, &desc, &conf_desc, &if_desc).expect("Failed to setup protocol");
let mut protocol = protocol::setup(&handle, protocol, &desc, &conf_desc, &if_desc)
.expect("Failed to setup protocol");
// TODO: Let all of the USB drivers syscall clone(2), and xhcid won't have to keep track of all
// the drivers.
let socket_fd = syscall::open(disk_scheme_name, syscall::O_RDWR | syscall::O_CREAT).expect("usbscsid: failed to create disk scheme");
let socket_fd = syscall::open(disk_scheme_name, syscall::O_RDWR | syscall::O_CREAT)
.expect("usbscsid: failed to create disk scheme");
let mut socket_file = unsafe { File::from_raw_fd(socket_fd as RawFd) };
//syscall::setrens(0, 0).expect("scsid: failed to enter null namespace");
@@ -78,5 +105,8 @@ fn main() {
Err(err) => panic!("scsid: failed to read disk scheme: {}", err),
}
scsi_scheme.handle(&mut packet);
socket_file
.write(&packet)
.expect("scsid: failed to write packet");
}
}
+101 -30
View File
@@ -1,7 +1,11 @@
use std::num::NonZeroU32;
use std::slice;
use xhcid_interface::{ConfDesc, DeviceReqData, EndpBinaryDirection, EndpDirection, EndpointStatus, IfDesc, Invalid, PortReqTy, PortReqRecipient, PortTransferStatus, XhciClientHandle, XhciClientHandleError, XhciEndpHandle};
use xhcid_interface::{
ConfDesc, DeviceReqData, EndpBinaryDirection, EndpDirection, EndpointStatus, IfDesc, Invalid,
PortReqRecipient, PortReqTy, PortTransferStatus, XhciClientHandle, XhciClientHandleError,
XhciEndpHandle,
};
use super::{Protocol, ProtocolError, SendCommandStatus, SendCommandStatusKind};
@@ -18,12 +22,18 @@ pub struct CommandBlockWrapper {
pub tag: u32,
pub data_transfer_len: u32,
pub flags: u8, // upper nibble reserved
pub lun: u8, // bits 7:5 reserved
pub lun: u8, // bits 7:5 reserved
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> {
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()));
@@ -86,11 +96,23 @@ pub struct BulkOnlyTransport<'a> {
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> {
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 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);
@@ -108,26 +130,40 @@ impl<'a> BulkOnlyTransport<'a> {
}
fn clear_stall_in(&mut self) -> Result<(), XhciClientHandleError> {
self.bulk_in.reset(false)?;
self.handle.clear_feature(PortReqRecipient::Endpoint, u16::from(self.bulk_in_num), FEATURE_ENDPOINT_HALT)
self.handle.clear_feature(
PortReqRecipient::Endpoint,
u16::from(self.bulk_in_num),
FEATURE_ENDPOINT_HALT,
)
}
fn clear_stall_out(&mut self) -> Result<(), XhciClientHandleError> {
self.bulk_out.reset(false)?;
self.handle.clear_feature(PortReqRecipient::Endpoint, u16::from(self.bulk_out_num), FEATURE_ENDPOINT_HALT)
self.handle.clear_feature(
PortReqRecipient::Endpoint,
u16::from(self.bulk_out_num),
FEATURE_ENDPOINT_HALT,
)
}
fn reset_recovery(&mut self) -> Result<(), ProtocolError> {
bulk_only_mass_storage_reset(self.handle, self.interface_num.into())?;
self.clear_stall_in()?;
self.clear_stall_out()?;
if self.bulk_in.status()? == EndpointStatus::Halted || self.bulk_out.status()? == EndpointStatus::Halted {
return Err(ProtocolError::RecoveryFailed)
if self.bulk_in.status()? == EndpointStatus::Halted
|| self.bulk_out.status()? == EndpointStatus::Halted
{
return Err(ProtocolError::RecoveryFailed);
}
Ok(())
}
}
impl<'a> Protocol for BulkOnlyTransport<'a> {
fn send_command(&mut self, cb: &[u8], data: DeviceReqData) -> Result<SendCommandStatus, ProtocolError> {
fn send_command(
&mut self,
cb: &[u8],
data: DeviceReqData,
) -> Result<SendCommandStatus, ProtocolError> {
self.current_tag += 1;
let tag = self.current_tag;
@@ -160,26 +196,38 @@ impl<'a> Protocol for BulkOnlyTransport<'a> {
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::ShortPacket(len) => {
panic!("received short packed (len {}) when transferring data", len)
}
PortTransferStatus::Stalled => {
println!("bulk in endpoint stalled when reading data");
self.clear_stall_in()?;
}
PortTransferStatus::Unknown => return Err(ProtocolError::XhciError(XhciClientHandleError::InvalidResponse(Invalid("unknown transfer status")))),
PortTransferStatus::Unknown => {
return Err(ProtocolError::XhciError(
XhciClientHandleError::InvalidResponse(Invalid(
"unknown transfer status",
)),
))
}
};
println!("{}", base64::encode(&buffer[..]));
}
DeviceReqData::Out(buffer) => {
match self.bulk_out.transfer_write(buffer)? {
PortTransferStatus::Success => (),
PortTransferStatus::ShortPacket(len) => panic!("received short packed (len {}) when transferring data", len),
PortTransferStatus::Stalled => {
println!("bulk out endpoint stalled when reading data");
self.clear_stall_out()?;
}
PortTransferStatus::Unknown => return Err(ProtocolError::XhciError(XhciClientHandleError::InvalidResponse(Invalid("unknown transfer status")))),
DeviceReqData::Out(buffer) => match self.bulk_out.transfer_write(buffer)? {
PortTransferStatus::Success => (),
PortTransferStatus::ShortPacket(len) => {
panic!("received short packed (len {}) when transferring data", len)
}
}
PortTransferStatus::Stalled => {
println!("bulk out endpoint stalled when reading data");
self.clear_stall_out()?;
}
PortTransferStatus::Unknown => {
return Err(ProtocolError::XhciError(
XhciClientHandleError::InvalidResponse(Invalid("unknown transfer status")),
))
}
},
DeviceReqData::NoData => (),
}
@@ -190,18 +238,22 @@ impl<'a> Protocol for BulkOnlyTransport<'a> {
println!("bulk in endpoint stalled when reading CSW");
self.clear_stall_in()?;
}
PortTransferStatus::ShortPacket(n) if n != 13 => panic!("received a short packet when reading CSW ({} != 13)", n),
PortTransferStatus::ShortPacket(n) if n != 13 => {
panic!("received a short packet when reading CSW ({} != 13)", n)
}
_ => (),
};
println!("{}", base64::encode(&csw_buffer));
let csw = plain::from_bytes::<CommandStatusWrapper>(&csw_buffer).unwrap();
dbg!(csw);
if !csw.is_valid() || csw.tag != cbw.tag {
self.reset_recovery()?;
}
dbg!(csw);
if self.bulk_in.status()? == EndpointStatus::Halted || self.bulk_out.status()? == EndpointStatus::Halted {
if self.bulk_in.status()? == EndpointStatus::Halted
|| self.bulk_out.status()? == EndpointStatus::Halted
{
println!("Trying to recover from stall");
dbg!(self.bulk_in.status()?, self.bulk_out.status()?);
}
@@ -212,19 +264,38 @@ impl<'a> Protocol for BulkOnlyTransport<'a> {
} else if csw.status == CswStatus::Failed as u8 {
SendCommandStatusKind::Failed
} else {
return Err(ProtocolError::ProtocolError("bulk-only transport phase error, or other"));
return Err(ProtocolError::ProtocolError(
"bulk-only transport phase error, or other",
));
},
residue: NonZeroU32::new(csw.data_residue),
})
}
}
pub fn bulk_only_mass_storage_reset(handle: &XhciClientHandle, if_num: u16) -> Result<(), XhciClientHandleError> {
handle.device_request(PortReqTy::Class, PortReqRecipient::Interface, 0xFF, 0, if_num, DeviceReqData::NoData)
pub fn bulk_only_mass_storage_reset(
handle: &XhciClientHandle,
if_num: u16,
) -> Result<(), XhciClientHandleError> {
handle.device_request(
PortReqTy::Class,
PortReqRecipient::Interface,
0xFF,
0,
if_num,
DeviceReqData::NoData,
)
}
pub fn get_max_lun(handle: &XhciClientHandle, if_num: u16) -> Result<u8, XhciClientHandleError> {
let mut lun = 0u8;
let buffer = slice::from_mut(&mut lun);
handle.device_request(PortReqTy::Class, PortReqRecipient::Interface, 0xFE, 0, if_num, DeviceReqData::In(buffer))?;
handle.device_request(
PortReqTy::Class,
PortReqRecipient::Interface,
0xFE,
0,
if_num,
DeviceReqData::In(buffer),
)?;
Ok(lun)
}
+18 -5
View File
@@ -2,7 +2,9 @@ use std::io;
use std::num::NonZeroU32;
use thiserror::Error;
use xhcid_interface::{DeviceReqData, DevDesc, ConfDesc, IfDesc, XhciClientHandle, XhciClientHandleError};
use xhcid_interface::{
ConfDesc, DevDesc, DeviceReqData, IfDesc, XhciClientHandle, XhciClientHandleError,
};
#[derive(Debug, Error)]
pub enum ProtocolError {
@@ -40,7 +42,6 @@ pub enum SendCommandStatusKind {
Failed,
}
impl Default for SendCommandStatusKind {
fn default() -> Self {
Self::Success
@@ -48,7 +49,11 @@ impl Default for SendCommandStatusKind {
}
pub trait Protocol {
fn send_command(&mut self, command: &[u8], data: DeviceReqData) -> Result<SendCommandStatus, ProtocolError>;
fn send_command(
&mut self,
command: &[u8],
data: DeviceReqData,
) -> Result<SendCommandStatus, ProtocolError>;
}
/// Bulk-only transport
@@ -60,9 +65,17 @@ mod uas {
use bot::BulkOnlyTransport;
pub fn setup<'a>(handle: &'a XhciClientHandle, protocol: u8, dev_desc: &DevDesc, conf_desc: &ConfDesc, if_desc: &IfDesc) -> 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, conf_desc, if_desc).unwrap())),
0x50 => Some(Box::new(
BulkOnlyTransport::init(handle, conf_desc, if_desc).unwrap(),
)),
_ => None,
}
}
+43 -10
View File
@@ -4,12 +4,12 @@ use std::{cmp, str};
use crate::protocol::Protocol;
use crate::scsi::Scsi;
use syscall::SchemeMut;
use syscall::error::{Error, Result};
use syscall::error::{EACCES, EBADF, EINVAL, EIO, ENOENT, ENOSYS};
use syscall::flag::{O_DIRECTORY, O_STAT};
use syscall::flag::{MODE_CHR, MODE_DIR};
use syscall::flag::{O_DIRECTORY, O_STAT};
use syscall::flag::{SEEK_CUR, SEEK_END, SEEK_SET};
use syscall::SchemeMut;
// TODO: Only one disk, right?
const LIST_CONTENTS: &'static [u8] = b"0\n";
@@ -43,7 +43,9 @@ impl<'a> SchemeMut for ScsiScheme<'a> {
if uid != 0 {
return Err(Error::new(EACCES));
}
let path_str = str::from_utf8(path).or(Err(Error::new(ENOENT)))?.trim_start_matches('/');
let path_str = str::from_utf8(path)
.or(Err(Error::new(ENOENT)))?
.trim_start_matches('/');
let handle = if path_str.is_empty() {
// List
Handle::List(0)
@@ -55,7 +57,7 @@ impl<'a> SchemeMut for ScsiScheme<'a> {
};
self.next_fd += 1;
self.handles.insert(self.next_fd, handle);
Err(Error::new(ENOSYS))
Ok(self.next_fd)
}
fn fstat(&mut self, fd: usize, stat: &mut syscall::Stat) -> Result<usize> {
match self.handles.get(&fd).ok_or(Error::new(EBADF))? {
@@ -70,10 +72,17 @@ impl<'a> SchemeMut for ScsiScheme<'a> {
stat.st_size = LIST_CONTENTS.len() as u64;
}
}
Err(Error::new(ENOSYS))
Ok(0)
}
fn fpath(&mut self, fd: usize, path: &mut [u8]) -> Result<usize> {
Err(Error::new(ENOSYS))
fn fpath(&mut self, fd: usize, buf: &mut [u8]) -> Result<usize> {
let path = match self.handles.get_mut(&fd).ok_or(Error::new(EBADF))? {
Handle::Disk(_) => "0",
Handle::List(_) => "",
}
.as_bytes();
let min = std::cmp::min(path.len(), buf.len());
buf[..min].copy_from_slice(&path[..min]);
Ok(min)
}
fn seek(&mut self, fd: usize, pos: usize, whence: usize) -> Result<usize> {
match self.handles.get_mut(&fd).ok_or(Error::new(EBADF))? {
@@ -102,11 +111,18 @@ impl<'a> SchemeMut for ScsiScheme<'a> {
fn read(&mut self, fd: usize, buf: &mut [u8]) -> Result<usize> {
match self.handles.get_mut(&fd).ok_or(Error::new(EBADF))? {
Handle::Disk(ref mut offset) => {
if *offset as u64 % u64::from(self.scsi.block_size) != 0 || buf.len() as u64 % u64::from(self.scsi.block_size) != 0 {
if *offset as u64 % u64::from(self.scsi.block_size) != 0
|| buf.len() as u64 % u64::from(self.scsi.block_size) != 0
{
return Err(Error::new(EINVAL));
}
let lba = *offset as u64 / u64::from(self.scsi.block_size);
let bytes_read = self.scsi.read(self.protocol, lba, buf).map_err(|err| dbg!(err)).or(Err(Error::new(EIO)))?;
let bytes_read = self
.scsi
.read(self.protocol, lba, buf)
.map_err(|err| dbg!(err))
.or(Err(Error::new(EIO)))?;
*offset += bytes_read as usize;
Ok(bytes_read as usize)
}
Handle::List(ref mut offset) => {
@@ -121,6 +137,23 @@ impl<'a> SchemeMut for ScsiScheme<'a> {
}
}
fn write(&mut self, fd: usize, buf: &[u8]) -> Result<usize> {
Err(Error::new(ENOSYS))
match self.handles.get_mut(&fd).ok_or(Error::new(EBADF))? {
Handle::Disk(ref mut offset) => {
if *offset as u64 % u64::from(self.scsi.block_size) != 0
|| buf.len() as u64 % u64::from(self.scsi.block_size) != 0
{
return Err(Error::new(EINVAL));
}
let lba = *offset as u64 / u64::from(self.scsi.block_size);
let bytes_written = self
.scsi
.write(self.protocol, lba, buf)
.map_err(|err| dbg!(err))
.or(Err(Error::new(EIO)))?;
*offset += bytes_written as usize;
Ok(bytes_written as usize)
}
Handle::List(_) => Err(Error::new(EBADF)),
}
}
}
+64 -10
View File
@@ -1,5 +1,5 @@
use std::{fmt, mem, slice};
use super::opcodes::Opcode;
use std::{fmt, mem, slice};
#[repr(packed)]
pub struct Inquiry {
@@ -124,7 +124,10 @@ impl FixedFormatSenseData {
self.add_sense_len as u16 + 7
}
pub unsafe fn add_sense_bytes(&self) -> &[u8] {
slice::from_raw_parts(&self.add_sense_len as *const u8, self.add_sense_len as usize - 18)
slice::from_raw_parts(
&self.add_sense_len as *const u8,
self.add_sense_len as usize - 18,
)
}
pub fn sense_key(&self) -> SenseKey {
let sense_key_raw = self.b & 0b1111;
@@ -189,6 +192,32 @@ impl Read16 {
}
}
#[repr(packed)]
#[derive(Clone, Copy, Debug)]
pub struct Write16 {
pub opcode: u8,
pub a: u8,
pub lba: u64, // big endian
pub transfer_len: u32,
pub b: u8,
pub control: u8,
}
unsafe impl plain::Plain for Write16 {}
impl Write16 {
pub const fn new(lba: u64, transfer_len: u32, control: u8) -> Self {
Self {
// TODO
opcode: Opcode::Write16 as u8,
a: 0,
lba,
transfer_len,
b: 0,
control,
}
}
}
#[repr(packed)]
#[derive(Clone, Copy, Debug)]
pub struct ModeSense6 {
@@ -202,7 +231,14 @@ pub struct ModeSense6 {
unsafe impl plain::Plain for ModeSense6 {}
impl ModeSense6 {
pub const fn new(dbd: bool, page_code: u8, pc: u8, subpage_code: u8, alloc_len: u8, control: u8) -> Self {
pub const fn new(
dbd: bool,
page_code: u8,
pc: u8,
subpage_code: u8,
alloc_len: u8,
control: u8,
) -> Self {
Self {
opcode: Opcode::ModeSense6 as u8,
a: (dbd as u8) << 3,
@@ -228,7 +264,15 @@ pub struct ModeSense10 {
unsafe impl plain::Plain for ModeSense10 {}
impl ModeSense10 {
pub const fn new(dbd: bool, llbaa: bool, page_code: u8, pc: ModePageControl, subpage_code: u8, alloc_len: u16, control: u8) -> Self {
pub const fn new(
dbd: bool,
llbaa: bool,
page_code: u8,
pc: ModePageControl,
subpage_code: u8,
alloc_len: u16,
control: u8,
) -> Self {
Self {
opcode: Opcode::ModeSense10 as u8,
a: ((dbd as u8) << 3) | ((llbaa as u8) << 4),
@@ -240,7 +284,15 @@ impl ModeSense10 {
}
}
pub const fn get_block_desc(alloc_len: u16, control: u8) -> Self {
Self::new(false, true, 0x3F, ModePageControl::CurrentValues, 0x00, alloc_len, control)
Self::new(
false,
true,
0x3F,
ModePageControl::CurrentValues,
0x00,
alloc_len,
control,
)
}
}
@@ -279,9 +331,7 @@ impl fmt::Debug for ShortLbaModeParamBlkDesc {
}
const fn u24_be_to_u32(u24: [u8; 3]) -> u32 {
((u24[0] as u32) << 16)
| ((u24[1] as u32) << 8)
| (u24[2] as u32)
((u24[0] as u32) << 16) | ((u24[1] as u32) << 8) | (u24[2] as u32)
}
/// From SPC-3, when LONGLBA is not set, and the peripheral device type of the INQUIRY data indicates that the device is not a direct access device. Otherwise, `ShortLbaModeParamBlkDesc` is used instead.
@@ -434,7 +484,9 @@ impl<'a> Iterator for ModePageIter<'a> {
if !spf {
if page_code == 0x01 {
Some(AnyModePage::RwErrorRecovery(plain::from_bytes(next_buf).ok()?))
Some(AnyModePage::RwErrorRecovery(
plain::from_bytes(next_buf).ok()?,
))
} else {
println!("Unimplemented sub_page {}", base64::encode(next_buf));
None
@@ -447,5 +499,7 @@ impl<'a> Iterator for ModePageIter<'a> {
}
pub fn mode_page_iter(buffer: &[u8]) -> impl Iterator<Item = AnyModePage> {
ModePageIter { raw: ModePageIterRaw { buffer } }
ModePageIter {
raw: ModePageIterRaw { buffer },
}
}
+120 -18
View File
@@ -1,5 +1,5 @@
use std::{mem, ops};
use std::convert::TryFrom;
use std::{mem, ops};
pub mod cmds;
pub mod opcodes;
@@ -29,6 +29,9 @@ const MIN_REPORT_SUPP_OPCODES_ALLOC_LEN: u32 = 4;
pub enum ScsiError {
#[error("protocol error when sending command: {0}")]
ProtocolError(#[from] ProtocolError),
#[error("overflow")]
Overflow(&'static str),
}
impl Scsi {
@@ -70,31 +73,67 @@ impl Scsi {
let inquiry = self.cmd_inquiry();
*inquiry = cmds::Inquiry::new(false, 0, max_inquiry_len, 0);
protocol.send_command(&self.command_buffer[..INQUIRY_CMD_LEN as usize], DeviceReqData::In(&mut self.inquiry_buffer[..max_inquiry_len as usize])).expect("Failed to send INQUIRY command");
protocol
.send_command(
&self.command_buffer[..INQUIRY_CMD_LEN as usize],
DeviceReqData::In(&mut self.inquiry_buffer[..max_inquiry_len as usize]),
)
.expect("Failed to send INQUIRY command");
}
pub fn get_ff_sense(&mut self, protocol: &mut dyn Protocol, alloc_len: u8) {
let request_sense = self.cmd_request_sense();
*request_sense = cmds::RequestSense::new(false, alloc_len, 0);
self.data_buffer.resize(alloc_len.into(), 0);
protocol.send_command(&self.command_buffer[..REQUEST_SENSE_CMD_LEN as usize], DeviceReqData::In(&mut self.data_buffer[..alloc_len as usize])).expect("Failed to send REQUEST_SENSE command");
protocol
.send_command(
&self.command_buffer[..REQUEST_SENSE_CMD_LEN as usize],
DeviceReqData::In(&mut self.data_buffer[..alloc_len as usize]),
)
.expect("Failed to send REQUEST_SENSE command");
}
pub fn get_mode_sense10(&mut self, protocol: &mut dyn Protocol) -> Result<(&cmds::ModeParamHeader10, BlkDescSlice, impl Iterator<Item = cmds::AnyModePage>), ScsiError> {
pub fn get_mode_sense10(
&mut self,
protocol: &mut dyn Protocol,
) -> Result<
(
&cmds::ModeParamHeader10,
BlkDescSlice,
impl Iterator<Item = cmds::AnyModePage>,
),
ScsiError,
> {
let initial_alloc_len = 4; // covers both mode_data_len and blk_desc_len.
let mode_sense10 = self.cmd_mode_sense10();
*mode_sense10 = cmds::ModeSense10::get_block_desc(initial_alloc_len, 0);
self.data_buffer.resize(mem::size_of::<cmds::ModeParamHeader10>(), 0);
if let SendCommandStatus { kind: SendCommandStatusKind::Failed, .. } = protocol.send_command(&self.command_buffer[..10], DeviceReqData::In(&mut self.data_buffer[..initial_alloc_len as usize]))? {
self.data_buffer
.resize(mem::size_of::<cmds::ModeParamHeader10>(), 0);
if let SendCommandStatus {
kind: SendCommandStatusKind::Failed,
..
} = protocol.send_command(
&self.command_buffer[..10],
DeviceReqData::In(&mut self.data_buffer[..initial_alloc_len as usize]),
)? {
self.get_ff_sense(protocol, 252);
panic!("{:?}", self.res_ff_sense_data());
}
let optimal_alloc_len = self.res_mode_param_header10().block_desc_len() + self.res_mode_param_header10().mode_data_len() + mem::size_of::<cmds::ModeParamHeader10>() as u16;
let optimal_alloc_len = self.res_mode_param_header10().block_desc_len()
+ self.res_mode_param_header10().mode_data_len()
+ mem::size_of::<cmds::ModeParamHeader10>() as u16;
let mode_sense10 = self.cmd_mode_sense10();
*mode_sense10 = cmds::ModeSense10::get_block_desc(optimal_alloc_len, 0);
self.data_buffer.resize(optimal_alloc_len as usize, 0);
protocol.send_command(&self.command_buffer[..10], DeviceReqData::In(&mut self.data_buffer[..optimal_alloc_len as usize]))?;
Ok((self.res_mode_param_header10(), self.res_blkdesc_mode10(), self.res_mode_pages10()))
protocol.send_command(
&self.command_buffer[..10],
DeviceReqData::In(&mut self.data_buffer[..optimal_alloc_len as usize]),
)?;
Ok((
self.res_mode_param_header10(),
self.res_blkdesc_mode10(),
self.res_mode_pages10(),
))
}
pub fn cmd_inquiry(&mut self) -> &mut cmds::Inquiry {
@@ -112,6 +151,9 @@ impl Scsi {
pub fn cmd_read16(&mut self) -> &mut cmds::Read16 {
plain::from_mut_bytes(&mut self.command_buffer).unwrap()
}
pub fn cmd_write16(&mut self) -> &mut cmds::Write16 {
plain::from_mut_bytes(&mut self.command_buffer).unwrap()
}
pub fn res_standard_inquiry_data(&self) -> &StandardInquiryData {
plain::from_bytes(&self.inquiry_buffer).unwrap()
}
@@ -127,17 +169,41 @@ impl Scsi {
pub fn res_blkdesc_mode6(&self) -> &[cmds::ShortLbaModeParamBlkDesc] {
let header = self.res_mode_param_header6();
let descs_start = mem::size_of::<cmds::ModeParamHeader6>();
plain::slice_from_bytes(&self.data_buffer[descs_start..descs_start + usize::from(header.block_desc_len)]).unwrap()
plain::slice_from_bytes(
&self.data_buffer[descs_start..descs_start + usize::from(header.block_desc_len)],
)
.unwrap()
}
pub fn res_blkdesc_mode10(&self) -> BlkDescSlice {
let header = self.res_mode_param_header10();
let descs_start = mem::size_of::<cmds::ModeParamHeader10>();
if header.longlba() {
BlkDescSlice::Long(plain::slice_from_bytes(&self.data_buffer[descs_start..descs_start + usize::from(header.block_desc_len())]).unwrap())
} else if self.res_standard_inquiry_data().periph_dev_ty() != cmds::PeriphDeviceType::DirectAccess as u8 && self.res_standard_inquiry_data().version() == cmds::InquiryVersion::Spc3 as u8 {
BlkDescSlice::General(plain::slice_from_bytes(&self.data_buffer[descs_start..descs_start + usize::from(header.block_desc_len())]).unwrap())
BlkDescSlice::Long(
plain::slice_from_bytes(
&self.data_buffer
[descs_start..descs_start + usize::from(header.block_desc_len())],
)
.unwrap(),
)
} else if self.res_standard_inquiry_data().periph_dev_ty()
!= cmds::PeriphDeviceType::DirectAccess as u8
&& self.res_standard_inquiry_data().version() == cmds::InquiryVersion::Spc3 as u8
{
BlkDescSlice::General(
plain::slice_from_bytes(
&self.data_buffer
[descs_start..descs_start + usize::from(header.block_desc_len())],
)
.unwrap(),
)
} else {
BlkDescSlice::Short(plain::slice_from_bytes(&self.data_buffer[descs_start..descs_start + usize::from(header.block_desc_len())]).unwrap())
BlkDescSlice::Short(
plain::slice_from_bytes(
&self.data_buffer
[descs_start..descs_start + usize::from(header.block_desc_len())],
)
.unwrap(),
)
}
}
@@ -150,15 +216,51 @@ impl Scsi {
pub fn get_disk_size(&mut self) -> u64 {
self.block_count * u64::from(self.block_size)
}
pub fn read(&mut self, protocol: &mut dyn Protocol, lba: u64, buffer: &mut [u8]) -> Result<u32, ScsiError> {
pub fn read(
&mut self,
protocol: &mut dyn Protocol,
lba: u64,
buffer: &mut [u8],
) -> Result<u32, ScsiError> {
let blocks_to_read = buffer.len() as u64 / u64::from(self.block_size);
let transfer_len = u32::try_from(blocks_to_read * u64::from(self.block_size)).ok().unwrap_or(std::u32::MAX);
let bytes_to_read = blocks_to_read as usize * self.block_size as usize;
let transfer_len = u32::try_from(blocks_to_read).or(Err(ScsiError::Overflow(
"number of blocks to read couldn't fit inside a u32",
)))?;
{
let read = self.cmd_read16();
*read = cmds::Read16::new(lba, transfer_len, 0);
}
let status = protocol.send_command(&self.command_buffer[..16], DeviceReqData::In(&mut buffer[..transfer_len as usize]))?;
Ok(status.bytes_transferred(transfer_len))
// TODO: Use the to-be-written TransferReadStream instead of relying on everything being
// able to fit within a single buffer.
let status = protocol.send_command(
&self.command_buffer[..16],
DeviceReqData::In(&mut buffer[..bytes_to_read]),
)?;
Ok(status.bytes_transferred(bytes_to_read as u32))
}
pub fn write(
&mut self,
protocol: &mut dyn Protocol,
lba: u64,
buffer: &[u8],
) -> Result<u32, ScsiError> {
let blocks_to_write = buffer.len() as u64 / u64::from(self.block_size);
let bytes_to_write = blocks_to_write as usize * self.block_size as usize;
let transfer_len = u32::try_from(blocks_to_write).or(Err(ScsiError::Overflow(
"number of blocks to write couldn't fit inside a u32",
)))?;
{
let read = self.cmd_write16();
*read = cmds::Write16::new(lba, transfer_len, 0);
}
// TODO: Use the to-be-written TransferReadStream instead of relying on everything being
// able to fit within a single buffer.
let status = protocol.send_command(
&self.command_buffer[..16],
DeviceReqData::Out(&buffer[..bytes_to_write]),
)?;
Ok(status.bytes_transferred(bytes_to_write as u32))
}
}
#[derive(Debug)]
+101 -33
View File
@@ -190,7 +190,9 @@ impl EndpDesc {
}
pub fn isoch_mult(&self, lec: bool) -> u8 {
if !lec && self.is_isoch() {
if self.is_superspeedplus() { return 0 }
if self.is_superspeedplus() {
return 0;
}
self.ssc
.as_ref()
.map(|ssc| ssc.attributes & 0x3)
@@ -203,7 +205,9 @@ impl EndpDesc {
self.ssc.map(|ssc| ssc.max_burst).unwrap_or(0)
}
pub fn has_ssp_companion(&self) -> bool {
self.ssc.map(|ssc| ssc.attributes & (1 << 7) != 0).unwrap_or(false)
self.ssc
.map(|ssc| ssc.attributes & (1 << 7) != 0)
.unwrap_or(false)
}
}
#[derive(Clone, Debug, Serialize, Deserialize)]
@@ -421,21 +425,12 @@ impl XhciClientHandle {
let string = std::fs::read_to_string(path)?;
Ok(string.parse()?)
}
pub fn open_endpoint_ctl(
&self,
num: u8,
) -> result::Result<File, XhciClientHandleError> {
pub fn open_endpoint_ctl(&self, num: u8) -> result::Result<File, XhciClientHandleError> {
let path = format!("{}:port{}/endpoints/{}/ctl", self.scheme, self.port, num);
Ok(File::open(path)?)
}
pub fn open_endpoint_data(
&self,
num: u8,
) -> result::Result<File, XhciClientHandleError> {
let path = format!(
"{}:port{}/endpoints/{}/data",
self.scheme, self.port, num
);
pub fn open_endpoint_data(&self, num: u8) -> result::Result<File, XhciClientHandleError> {
let path = format!("{}:port{}/endpoints/{}/data", self.scheme, self.port, num);
Ok(File::open(path)?)
}
pub fn open_endpoint(&self, num: u8) -> result::Result<XhciEndpHandle, XhciClientHandleError> {
@@ -541,13 +536,18 @@ pub struct XhciEndpHandle {
ctl: File,
}
/// The direction of a transfer.
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
pub enum XhciEndpCtlDirection {
/// Host to device
Out,
/// Device to host
In,
/// No data, and hence no I/O on the Data interface file at all.
NoData,
}
/// A request to an endpoint Ctl interface file. Currently serialized with JSON.
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
#[non_exhaustive]
pub enum XhciEndpCtlReq {
@@ -555,9 +555,19 @@ pub enum XhciEndpCtlReq {
// TODO: Allow to send multiple buffers in one transfer.
/// Tells xhcid that a buffer is about to be sent from the Data interface file, to the
/// endpoint.
Transfer(XhciEndpCtlDirection),
// TODO: Allow clients to specify what to reset.
Transfer {
/// The direction of the transfer. If the direction is `XhciEndpCtlDirection::NoData`, no
/// bytes will be transferred, and therefore no reads or writes shall be done to the Data
/// driver interface file.
direction: XhciEndpCtlDirection,
/// The number of bytes to be read or written. This field must be set to zero if the
/// direction is `XhciEndpCtlDirection::NoData`. When all bytes have been read or written,
/// the transfer will be considered complete by xhcid, and a non-pending status will be
/// returned.
count: u32,
},
// TODO: Allow clients to specify what to reset.
/// Tells xhcid that the endpoint is going to be reset.
Reset {
/// Only issue the Reset Endpoint and Set TR Dequeue Pointer commands, and let the client
@@ -568,6 +578,7 @@ pub enum XhciEndpCtlReq {
/// Tells xhcid that the endpoint status is going to be retrieved from the Ctl interface file.
Status,
}
/// A response from an endpoint Ctl interface file. Currently serialized with JSON.
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
#[non_exhaustive]
pub enum XhciEndpCtlRes {
@@ -586,9 +597,9 @@ pub enum XhciEndpCtlRes {
impl XhciEndpHandle {
fn ctl_req(&mut self, ctl_req: &XhciEndpCtlReq) -> result::Result<(), XhciClientHandleError> {
let ctl_buffer = serde_json::to_vec(ctl_req)?;
let ctl_buffer = serde_json::to_vec(ctl_req).expect("serde");
let ctl_bytes_written = self.ctl.write(&ctl_buffer)?;
let ctl_bytes_written = self.ctl.write(&ctl_buffer).expect("ctlwrite");
if ctl_bytes_written != ctl_buffer.len() {
return Err(Invalid("xhcid didn't process all of the ctl bytes").into());
}
@@ -598,7 +609,7 @@ impl XhciEndpHandle {
fn ctl_res(&mut self) -> result::Result<XhciEndpCtlRes, XhciClientHandleError> {
// a response must never exceed 256 bytes
let mut ctl_buffer = [0u8; 256];
let ctl_bytes_read = self.ctl.read(&mut ctl_buffer)?;
let ctl_bytes_read = self.ctl.read(&mut ctl_buffer).expect("ctlread");
let ctl_res = serde_json::from_slice(&ctl_buffer[..ctl_bytes_read as usize])?;
Ok(ctl_res)
@@ -607,35 +618,89 @@ impl XhciEndpHandle {
self.ctl_req(&XhciEndpCtlReq::Reset { no_clear_feature })
}
pub fn status(&mut self) -> result::Result<EndpointStatus, XhciClientHandleError> {
self.ctl_req(&XhciEndpCtlReq::Status)?;
match self.ctl_res()? {
self.ctl_req(&XhciEndpCtlReq::Status)
.expect("status ctlreq");
match self.ctl_res().expect("status ctlres") {
XhciEndpCtlRes::Status(s) => Ok(s),
_ => Err(Invalid("expected status response").into()),
}
}
fn generic_transfer<F: FnOnce(&mut File) -> io::Result<usize>>(&mut self, direction: XhciEndpCtlDirection, f: F, expected_len: usize) -> result::Result<PortTransferStatus, XhciClientHandleError> {
let req = XhciEndpCtlReq::Transfer(direction);
self.ctl_req(&req)?;
fn generic_transfer<F: FnOnce(&mut File) -> io::Result<usize>>(
&mut self,
direction: XhciEndpCtlDirection,
f: F,
expected_len: u32,
) -> result::Result<PortTransferStatus, XhciClientHandleError> {
let req = XhciEndpCtlReq::Transfer {
direction,
count: expected_len,
};
self.ctl_req(&req).expect("ctl_req");
let bytes_read = f(&mut self.data)?;
let res = self.ctl_res()?;
let bytes_read = f(&mut self.data).expect("f");
let res = self.ctl_res().expect("ctl_res");
match res {
XhciEndpCtlRes::TransferResult(PortTransferStatus::Success) if bytes_read != expected_len => Err(Invalid("no short packet, but fewer bytes were read/written").into()),
XhciEndpCtlRes::TransferResult(PortTransferStatus::Success)
if bytes_read != expected_len as usize =>
{
Err(Invalid("no short packet, but fewer bytes were read/written").into())
}
XhciEndpCtlRes::TransferResult(r) => Ok(r),
_ => Err(Invalid("expected transfer result").into()),
}
}
pub fn transfer_write(&mut self, buf: &[u8]) -> result::Result<PortTransferStatus, XhciClientHandleError> {
self.generic_transfer(XhciEndpCtlDirection::Out, |data| data.write(buf), buf.len())
pub fn transfer_write(
&mut self,
buf: &[u8],
) -> result::Result<PortTransferStatus, XhciClientHandleError> {
self.generic_transfer(
XhciEndpCtlDirection::Out,
|data| data.write(buf),
buf.len() as u32,
)
}
pub fn transfer_read(&mut self, buf: &mut [u8]) -> result::Result<PortTransferStatus, XhciClientHandleError> {
let len = buf.len();
pub fn transfer_read(
&mut self,
buf: &mut [u8],
) -> result::Result<PortTransferStatus, XhciClientHandleError> {
let len = buf.len() as u32;
self.generic_transfer(XhciEndpCtlDirection::In, |data| data.read(buf), len)
}
pub fn transfer_nodata(&mut self, buf: &[u8]) -> result::Result<PortTransferStatus, XhciClientHandleError> {
self.generic_transfer(XhciEndpCtlDirection::NoData, |_| Ok(0), buf.len())
pub fn transfer_nodata(&mut self) -> result::Result<PortTransferStatus, XhciClientHandleError> {
self.generic_transfer(XhciEndpCtlDirection::NoData, |_| Ok(0), 0)
}
fn transfer_stream(&mut self, total_len: u32) -> TransferStream {
TransferStream {
bytes_to_transfer: total_len,
bytes_transferred: 0,
bytes_per_transfer: 32768, // TODO
endp_handle: self,
}
}
pub fn transfer_write_stream(&mut self, total_len: u32) -> TransferWriteStream {
TransferWriteStream {
inner: self.transfer_stream(total_len),
}
}
pub fn transfer_read_stream(&mut self, total_len: u32) -> TransferReadStream {
TransferReadStream {
inner: self.transfer_stream(total_len),
}
}
}
pub struct TransferWriteStream<'a> {
inner: TransferStream<'a>,
}
pub struct TransferReadStream<'a> {
inner: TransferStream<'a>,
}
struct TransferStream<'a> {
bytes_to_transfer: u32,
bytes_transferred: u32,
bytes_per_transfer: u32,
endp_handle: &'a mut XhciEndpHandle,
}
#[derive(Debug, Error)]
@@ -651,4 +716,7 @@ pub enum XhciClientHandleError {
#[error("transfer buffer too large ({0} > 65536)")]
TransferBufTooLarge(usize),
#[error("unexpected short packet of size {0}")]
UnexpectedShortPacket(usize),
}
+9 -2
View File
@@ -75,7 +75,12 @@ impl BosSuperSpeedPlusDesc {
(self.attrs & 0x0000_000F) as u8
}
pub fn sublink_speed_attr(&self) -> &[u32] {
unsafe { slice::from_raw_parts(&self.sublink_speed_attr as *const u32, self.ssac() as usize + 1) }
unsafe {
slice::from_raw_parts(
&self.sublink_speed_attr as *const u32,
self.ssac() as usize + 1,
)
}
}
}
@@ -155,7 +160,9 @@ impl<'a> Iterator for BosAnyDevDescIter<'a> {
} else if base.cap_ty == DeviceCapability::SuperSpeed as u8 {
Some(BosAnyDevDesc::SuperSpeed(*plain::from_bytes(slice).ok()?))
} else if base.cap_ty == DeviceCapability::SuperSpeedPlus as u8 {
Some(BosAnyDevDesc::SuperSpeedPlus(*plain::from_bytes(slice).ok()?))
Some(BosAnyDevDesc::SuperSpeedPlus(
*plain::from_bytes(slice).ok()?,
))
} else if base.cap_ty == 0 {
// TODO
return None;
+2 -1
View File
@@ -2,7 +2,8 @@ pub use self::bos::{bos_capability_descs, BosAnyDevDesc, BosDescriptor, BosSuper
pub use self::config::ConfigDescriptor;
pub use self::device::DeviceDescriptor;
pub use self::endpoint::{
EndpointDescriptor, EndpointTy, HidDescriptor, SuperSpeedCompanionDescriptor, SuperSpeedPlusIsochCmpDescriptor, ENDP_ATTR_TY_MASK,
EndpointDescriptor, EndpointTy, HidDescriptor, SuperSpeedCompanionDescriptor,
SuperSpeedPlusIsochCmpDescriptor, ENDP_ATTR_TY_MASK,
};
pub use self::interface::InterfaceDescriptor;
pub use self::setup::Setup;
+16 -4
View File
@@ -126,16 +126,28 @@ impl ProtocolSpeed {
self.psim() == 5 && self.psie() == Psie::Gbps && self.pfd() && self.lp() == Lp::SuperSpeed
}
pub fn is_superspeedplus_gen2x1(&self) -> bool {
self.psim() == 10 && self.psie() == Psie::Gbps && self.pfd() && self.lp() == Lp::SuperSpeedPlus
self.psim() == 10
&& self.psie() == Psie::Gbps
&& self.pfd()
&& self.lp() == Lp::SuperSpeedPlus
}
pub fn is_superspeedplus_gen1x2(&self) -> bool {
self.psim() == 10 && self.psie() == Psie::Gbps && self.pfd() && self.lp() == Lp::SuperSpeedPlus
self.psim() == 10
&& self.psie() == Psie::Gbps
&& self.pfd()
&& self.lp() == Lp::SuperSpeedPlus
}
pub fn is_superspeedplus_gen2x2(&self) -> bool {
self.psim() == 20 && self.psie() == Psie::Gbps && self.pfd() && self.lp() == Lp::SuperSpeedPlus
self.psim() == 20
&& self.psie() == Psie::Gbps
&& self.pfd()
&& self.lp() == Lp::SuperSpeedPlus
}
pub fn is_superspeed_gen_x(&self) -> bool {
self.is_superspeed_gen1x1() || self.is_superspeedplus_gen2x1() || self.is_superspeedplus_gen1x2() || self.is_superspeedplus_gen2x2()
self.is_superspeed_gen1x1()
|| self.is_superspeedplus_gen2x1()
|| self.is_superspeedplus_gen1x2()
|| self.is_superspeedplus_gen2x2()
}
/// Protocol speed ID value
pub fn psiv(&self) -> u8 {
+33 -15
View File
@@ -301,7 +301,8 @@ impl Xhci {
pub fn enable_port_slot(&mut self, slot_ty: u8) -> Result<u8> {
assert_eq!(slot_ty & 0x1F, slot_ty);
let cloned_event_trb = self.execute_command("ENABLE_SLOT", |cmd, cycle| cmd.enable_slot(0, cycle))?;
let cloned_event_trb =
self.execute_command("ENABLE_SLOT", |cmd, cycle| cmd.enable_slot(0, cycle))?;
Ok(cloned_event_trb.event_slot())
}
pub fn disable_port_slot(&mut self, slot: u8) -> Result<()> {
@@ -329,7 +330,10 @@ impl Xhci {
println!(" - Enable slot");
let slot_ty = self.supported_protocol(i as u8).expect("Failed to find supported protocol information for port").proto_slot_ty();
let slot_ty = self
.supported_protocol(i as u8)
.expect("Failed to find supported protocol information for port")
.proto_slot_ty();
let slot = self.enable_port_slot(slot_ty)?;
println!(" - Slot {}", slot);
@@ -358,7 +362,7 @@ impl Xhci {
EndpointState {
transfer: RingOrStreams::Ring(ring),
driver_if_state: EndpIfState::Init,
}
},
))
.collect::<BTreeMap<_, _>>(),
};
@@ -379,7 +383,12 @@ impl Xhci {
Ok(())
}
pub fn update_default_control_pipe(&mut self, input_context: &mut Dma<InputContext>, slot_id: u8, dev_desc: &DevDesc) -> Result<()> {
pub fn update_default_control_pipe(
&mut self,
input_context: &mut Dma<InputContext>,
slot_id: u8,
dev_desc: &DevDesc,
) -> Result<()> {
input_context.add_context.write(1 << 1);
input_context.drop_context.write(0);
@@ -393,14 +402,21 @@ impl Xhci {
b &= 0x0000_FFFF;
b |= (new_max_packet_size) << 16;
endp_ctx.b.write(b);
self.execute_command("EVALUATE_CONTEXT", |trb, cycle| {
trb.evaluate_context(slot_id, input_context.physical(), false, cycle)
})?;
Ok(())
}
pub fn address_device(&mut self, input_context: &mut Dma<InputContext>, i: usize, slot_ty: u8, slot: u8, speed: u8) -> Result<Ring> {
pub fn address_device(
&mut self,
input_context: &mut Dma<InputContext>,
i: usize,
slot_ty: u8,
slot: u8,
speed: u8,
) -> Result<Ring> {
let mut ring = Ring::new(true)?;
{
@@ -418,7 +434,7 @@ impl Xhci {
route_string
| (u32::from(mtt) << 25)
| (u32::from(hub) << 26)
| (u32::from(context_entries) << 27)
| (u32::from(context_entries) << 27),
);
let max_exit_latency = 0u16;
@@ -427,7 +443,7 @@ impl Xhci {
slot_ctx.b.write(
u32::from(max_exit_latency)
| (u32::from(root_hub_port_num) << 16)
| (u32::from(number_of_ports) << 24)
| (u32::from(number_of_ports) << 24),
);
// TODO
@@ -441,12 +457,14 @@ impl Xhci {
u32::from(parent_hud_slot_id)
| (u32::from(parent_port_num) << 8)
| (u32::from(ttt) << 16)
| (u32::from(interrupter) << 22)
| (u32::from(interrupter) << 22),
);
let endp_ctx = &mut input_context.device.endpoints[0];
let speed_id = self.lookup_psiv(root_hub_port_num, speed).expect("Failed to retrieve speed ID");
let speed_id = self
.lookup_psiv(root_hub_port_num, speed)
.expect("Failed to retrieve speed ID");
let max_error_count = 3u8; // recommended value according to the XHCI spec
let ep_ty = 4u8; // control endpoint, bidirectional
@@ -470,19 +488,20 @@ impl Xhci {
| (u32::from(ep_ty) << 3)
| (u32::from(host_initiate_disable) << 7)
| (u32::from(max_burst_size) << 8)
| (u32::from(max_packet_size) << 16)
| (u32::from(max_packet_size) << 16),
);
let tr = ring.register();
endp_ctx.trh.write((tr >> 32) as u32);
endp_ctx.trl.write(tr as u32);
}
let input_context_physical = input_context.physical();
self.execute_command("ADDRESS_DEVICE", |trb, cycle| {
trb.address_device(slot, input_context_physical, false, cycle)
}).expect("ADDRESS_DEVICE failed");
})
.expect("ADDRESS_DEVICE failed");
Ok(ring)
}
@@ -584,8 +603,7 @@ impl Xhci {
})
}
pub fn supported_protocol(&self, port: u8) -> Option<&'static SupportedProtoCap> {
self
.supported_protocols_iter()
self.supported_protocols_iter()
.find(|supp_proto| supp_proto.compat_port_range().contains(&port))
}
pub fn supported_protocol_speeds(
+527 -169
View File
File diff suppressed because it is too large Load Diff
+20 -6
View File
@@ -213,7 +213,10 @@ impl Trb {
self.set(
input_ctx_ptr as u64,
0,
(u32::from(slot_id) << 24) | ((TrbType::AddressDevice as u32) << 10) | (u32::from(bsr) << 9) | u32::from(cycle),
(u32::from(slot_id) << 24)
| ((TrbType::AddressDevice as u32) << 10)
| (u32::from(bsr) << 9)
| u32::from(cycle),
);
}
// Synchronizes the input context endpoints with the device context endpoints, I think.
@@ -241,7 +244,10 @@ impl Trb {
self.set(
input_ctx_ptr as u64,
0,
(u32::from(slot_id) << 24) | ((TrbType::EvaluateContext as u32) << 10) | (u32::from(bsr) << 9) | u32::from(cycle),
(u32::from(slot_id) << 24)
| ((TrbType::EvaluateContext as u32) << 10)
| (u32::from(bsr) << 9)
| u32::from(cycle),
);
}
pub fn reset_endpoint(&mut self, slot_id: u8, endp_num_xhc: u8, tsp: bool, cycle: bool) {
@@ -257,7 +263,15 @@ impl Trb {
);
}
/// The deque_ptr has to contain the DCS bit (bit 0).
pub fn set_tr_deque_ptr(&mut self, deque_ptr: u64, cycle: bool, sct: StreamContextType, stream_id: u16, endp_num_xhc: u8, slot: u8) {
pub fn set_tr_deque_ptr(
&mut self,
deque_ptr: u64,
cycle: bool,
sct: StreamContextType,
stream_id: u16,
endp_num_xhc: u8,
slot: u8,
) {
assert_eq!(deque_ptr & 0xFFFF_FFFF_FFFF_FFF1, deque_ptr);
assert_eq!(endp_num_xhc & 0x1F, endp_num_xhc);
@@ -298,7 +312,7 @@ impl Trb {
| (u32::from(ioc) << 5)
| (u32::from(ch) << 4)
| (u32::from(ent) << 1)
| u32::from(cycle)
| u32::from(cycle),
);
}
@@ -334,7 +348,7 @@ impl Trb {
pub fn normal(
&mut self,
buffer: u64,
len: u16,
len: u32,
cycle: bool,
estimated_td_size: u8,
interrupter: u8,
@@ -349,7 +363,7 @@ impl Trb {
// NOTE: The interrupter target and no snoop flags have been omitted.
self.set(
buffer,
u32::from(len) | (u32::from(estimated_td_size) << 17) | (u32::from(interrupter) << 22),
len | (u32::from(estimated_td_size) << 17) | (u32::from(interrupter) << 22),
u32::from(cycle)
| (u32::from(ent) << 1)
| (u32::from(isp) << 2)