Improve (subjective...) the descriptor fetching.

This commit is contained in:
4lDO2
2020-01-12 13:18:39 +11:00
parent 8b375518d9
commit dd4dd952d0
10 changed files with 380 additions and 67 deletions
+1 -1
View File
@@ -37,7 +37,7 @@ fn main() {
// Daemonize
if unsafe { syscall::clone(0).unwrap() } == 0 {
let socket_fd = syscall::open(format!(":usb/{}-{}-{}", name, bar_str, irq_str), syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK).expect("xhcid: failed to create usb scheme");
let socket_fd = syscall::open(format!(":usb/{}", name), syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK).expect("xhcid: failed to create usb scheme");
let socket = Arc::new(RefCell::new(unsafe { File::from_raw_fd(socket_fd as RawFd) }));
let mut irq_file = File::open(format!("irq:{}", irq)).expect("xhcid: failed to open IRQ file");
+134
View File
@@ -0,0 +1,134 @@
#[repr(packed)]
#[derive(Clone, Copy, Debug, Default)]
pub struct BosDescriptor {
pub len: u8,
pub kind: u8,
pub total_len: u16,
pub cap_count: u8,
}
unsafe impl plain::Plain for BosDescriptor {}
#[repr(packed)]
#[derive(Clone, Copy, Debug, Default)]
pub struct BosDevDescriptorBase {
pub len: u8,
pub kind: u8,
pub cap_ty: u8,
}
unsafe impl plain::Plain for BosDevDescriptorBase {}
#[repr(packed)]
#[derive(Clone, Copy, Debug, Default)]
pub struct BosSuperSpeedDesc {
pub len: u8,
pub kind: u8,
pub cap_ty: u8,
pub attrs: u8,
pub speed_supp: u16,
pub func_supp: u8,
pub u1_dev_exit_lat: u8,
pub u2_dev_exit_lat: u16,
}
#[repr(packed)]
#[derive(Clone, Copy, Debug, Default)]
pub struct BosUsb2ExtDesc {
pub len: u8,
pub kind: u8,
pub cap_ty: u8,
pub attrs: u32,
}
unsafe impl plain::Plain for BosUsb2ExtDesc {}
#[repr(u8)]
pub enum DeviceCapability {
Usb2Ext = 2,
SuperSpeed = 3,
}
unsafe impl plain::Plain for BosSuperSpeedDesc {}
pub struct BosDevDescIter<'a> {
bytes: &'a [u8],
}
impl<'a> BosDevDescIter<'a> {
pub fn new(bytes: &'a [u8]) -> Self {
Self {
bytes,
}
}
}
impl<'a> From<&'a [u8]> for BosDevDescIter<'a> {
fn from(slice: &'a [u8]) -> Self {
Self::new(slice)
}
}
impl<'a> Iterator for BosDevDescIter<'a> {
type Item = (BosDevDescriptorBase, &'a [u8]);
fn next(&mut self) -> Option<Self::Item> {
if let Some(desc) = plain::from_bytes::<BosDevDescriptorBase>(self.bytes).ok() {
if desc.len as usize > self.bytes.len() { return None };
let bytes_ret = &self.bytes[..desc.len as usize];
self.bytes = &self.bytes[desc.len as usize..];
Some((*desc, bytes_ret))
} else {
return None;
}
}
}
#[derive(Debug)]
pub enum BosAnyDevDesc {
SuperSpeed(BosSuperSpeedDesc),
Usb2Ext(BosUsb2ExtDesc),
}
impl BosAnyDevDesc {
pub fn is_superspeed(&self) -> bool {
match self {
Self::SuperSpeed(_) => true,
_ => false,
}
}
}
pub struct BosAnyDevDescIter<'a> {
inner: BosDevDescIter<'a>,
}
impl<'a> From<BosDevDescIter<'a>> for BosAnyDevDescIter<'a> {
fn from(ll: BosDevDescIter<'a>) -> Self {
Self { inner: ll }
}
}
impl<'a> From<&'a [u8]> for BosAnyDevDescIter<'a> {
fn from(slice: &'a [u8]) -> Self {
Self::from(BosDevDescIter::from(slice))
}
}
impl<'a> Iterator for BosAnyDevDescIter<'a> {
type Item = BosAnyDevDesc;
fn next(&mut self) -> Option<Self::Item> {
let (base, slice) = self.inner.next()?;
if base.cap_ty == DeviceCapability::Usb2Ext as u8 {
Some(BosAnyDevDesc::Usb2Ext(*plain::from_bytes(slice).ok()?))
} else if base.cap_ty == DeviceCapability::SuperSpeed as u8 {
Some(BosAnyDevDesc::SuperSpeed(*plain::from_bytes(slice).ok()?))
} else if base.cap_ty == 0 {
// TODO
return None;
} else {
unimplemented!("USB device capability of type: {}", base.cap_ty)
}
}
}
pub fn bos_capability_descs<'a>(desc: BosDescriptor, data: &'a [u8]) -> impl Iterator<Item = BosAnyDevDesc> + 'a {
BosAnyDevDescIter::from(&data[..desc.total_len as usize - std::mem::size_of_val(&desc)]).take(desc.cap_count as usize)
}
+2
View File
@@ -10,3 +10,5 @@ pub struct ConfigDescriptor {
pub attributes: u8,
pub max_power: u8,
}
unsafe impl plain::Plain for ConfigDescriptor {}
+2
View File
@@ -16,3 +16,5 @@ pub struct DeviceDescriptor {
pub serial_str: u8,
pub configurations: u8,
}
unsafe impl plain::Plain for DeviceDescriptor {}
+12
View File
@@ -12,3 +12,15 @@ pub struct EndpointDescriptor {
}
unsafe impl Plain for EndpointDescriptor {}
#[repr(packed)]
#[derive(Clone, Copy, Debug, Default)]
pub struct SuperSpeedCompanionDescriptor {
pub length: u8,
pub kind: u8,
pub max_burst: u8,
pub attributes: u8,
pub bytes_per_interval: u16,
}
unsafe impl Plain for SuperSpeedCompanionDescriptor {}
+5 -1
View File
@@ -1,6 +1,7 @@
pub use self::bos::{BosDescriptor, BosAnyDevDesc, BosSuperSpeedDesc, bos_capability_descs};
pub use self::config::ConfigDescriptor;
pub use self::device::DeviceDescriptor;
pub use self::endpoint::EndpointDescriptor;
pub use self::endpoint::{EndpointDescriptor, SuperSpeedCompanionDescriptor};
pub use self::interface::InterfaceDescriptor;
pub use self::setup::Setup;
@@ -16,8 +17,11 @@ pub enum DescriptorKind {
OtherSpeedConfiguration,
InterfacePower,
OnTheGo,
BinaryObjectStorage = 15,
SuperSpeedCompanion = 48,
}
mod bos;
mod config;
mod device;
mod endpoint;
+2 -1
View File
@@ -23,7 +23,8 @@ pub struct EndpointContext {
#[repr(packed)]
pub struct DeviceContext {
pub slot: SlotContext,
pub endpoints: [EndpointContext; 15]
pub endpoints: [EndpointContext; 15],
// Shouldn't this be 31 (both for in and out)?
}
#[repr(packed)]
+18 -2
View File
@@ -88,6 +88,16 @@ impl<'a> Device<'a> {
Ok(*desc)
}
fn get_bos(&mut self) -> Result<(usb::BosDescriptor, [u8; 4087])> {
let mut desc = Dma::<(usb::BosDescriptor, [u8; 4087])>::zeroed()?;
self.get_desc(
usb::DescriptorKind::BinaryObjectStorage,
0,
&mut desc,
);
Ok(*desc)
}
fn get_string(&mut self, index: u8) -> Result<String> {
let mut sdesc = Dma::<(u8, u8, [u16; 127])>::zeroed()?;
self.get_desc(
@@ -295,13 +305,19 @@ impl Xhci {
{
input.add_context.write(1 << 1 | 1);
input.device.slot.a.write((1 << 27) | (speed << 20));
input.device.slot.a.write((1 << 27) | (speed << 20)); // FIXME: The speed field, bits 23:20, is deprecated.
input.device.slot.b.write(((i as u32 + 1) & 0xFF) << 16);
input.device.endpoints[0].b.write(4096 << 16 | 4 << 3 | 3 << 1);
// control endpoint?
input.device.endpoints[0].b.write(4096 << 16 | 4 << 3 | 3 << 1); // packet size | control endpoint | allowed error count
let tr = ring.register();
input.device.endpoints[0].trh.write((tr >> 32) as u32);
input.device.endpoints[0].trl.write(tr as u32);
// TODO: I presume that there should be additional endpoint contexts, for the
// endpoints specified in the USB descriptors. Perhaps the specific USB drivers
// (HID drivers, mass storage drivers, etc.) should enable these endpoints
// themselves.
}
{
+192 -62
View File
@@ -1,4 +1,5 @@
use std::{cmp, mem, str};
use std::convert::TryFrom;
use std::io::prelude::*;
use plain::Plain;
@@ -23,6 +24,8 @@ pub enum Handle {
TopLevel(usize, Vec<u8>), // offset, contents (ports)
Port(usize, usize, Vec<u8>), // port, offset, contents
PortDesc(usize, usize, Vec<u8>), // port, offset, contents
Endpoints(usize, usize, Vec<u8>), // port, offset, contents
Endpoint(usize, usize, usize), // port, endpoint, offset
}
#[derive(Serialize)]
@@ -70,6 +73,17 @@ struct EndpDescJson {
max_packet_size: u16,
interval: u8,
}
impl From<usb::EndpointDescriptor> for EndpDescJson {
fn from(d: usb::EndpointDescriptor) -> Self {
Self {
kind: d.kind,
address: d.address,
attributes: d.attributes,
interval: d.interval,
max_packet_size: d.max_packet_size,
}
}
}
#[derive(Serialize)]
struct IfDescJson {
@@ -81,7 +95,81 @@ struct IfDescJson {
sub_class: u8,
protocol: u8,
interface_str: Option<String>,
endpoints: SmallVec<[EndpDescJson; 2]>,
endpoints: SmallVec<[AnyEndpDescJson; 4]>,
}
impl IfDescJson {
fn new(dev: &mut Device, desc: usb::InterfaceDescriptor, endps: impl IntoIterator<Item = AnyEndpDescJson>) -> Result<Self> {
Ok(Self {
alternate_setting: desc.alternate_setting,
class: desc.class,
interface_str: if desc.interface_str > 0 { Some(dev.get_string(desc.interface_str)?) } else { None },
kind: desc.kind,
number: desc.number,
protocol: desc.protocol,
sub_class: desc.sub_class,
endpoints: endps.into_iter().collect(),
})
}
}
#[derive(Serialize)]
struct SuperSpeedCmpJson {
kind: u8,
max_burst: u8,
attributes: u8,
bytes_per_interval: u16,
}
impl From<usb::SuperSpeedCompanionDescriptor> for SuperSpeedCmpJson {
fn from(d: usb::SuperSpeedCompanionDescriptor) -> Self {
Self {
kind: d.kind,
attributes: d.attributes,
bytes_per_interval: d.bytes_per_interval,
max_burst: d.max_burst,
}
}
}
#[derive(Serialize)]
enum AnyEndpDescJson {
Endp(EndpDescJson),
SuperSpeedCmp(SuperSpeedCmpJson),
}
/// Any descriptor that can be stored in the config desc "data" area.
#[derive(Debug)]
enum AnyDescriptor {
// These are the ones that I have found, but there are more.
Device(usb::DeviceDescriptor),
Config(usb::ConfigDescriptor),
Interface(usb::InterfaceDescriptor),
Endpoint(usb::EndpointDescriptor),
SuperSpeedCompanion(usb::SuperSpeedCompanionDescriptor),
}
impl AnyDescriptor {
fn parse(bytes: &[u8]) -> Option<(Self, usize)> {
// There has to be at least two bytes for the kind and length.
if bytes.len() < 2 { return None }
let len = bytes[0];
let kind = bytes[1];
if bytes.len() < len.into() { return None }
Some((match kind {
1 => Self::Device(*plain::from_bytes(bytes).ok()?),
2 => Self::Config(*plain::from_bytes(bytes).ok()?),
4 => Self::Interface(*plain::from_bytes(bytes).ok()?),
5 => Self::Endpoint(*plain::from_bytes(bytes).ok()?),
48 => Self::SuperSpeedCompanion(*plain::from_bytes(bytes).ok()?),
_ => {
//println!("Descriptor unknown {}: bytes {:#0x?}", kind, bytes);
return None;
}
}, len.into()))
}
}
impl Xhci {
@@ -118,6 +206,11 @@ impl Xhci {
} else { None },
);
let (bos_desc, bos_data) = dev.get_bos()?;
writeln!(contents, "BOS BASE {:?}", bos_desc).unwrap();
let has_superspeed = usb::bos_capability_descs(bos_desc, &bos_data).inspect(|item| println!("{:?}", item)).any(|desc| desc.is_superspeed());
let config_descs = (0..raw_dd.configurations).map(|index| -> Result<_> {
// TODO: Actually, it seems like all descriptors contain a length field, and I
// encountered a SuperSpeed descriptor when endpoints were expected. The right way
@@ -127,48 +220,45 @@ impl Xhci {
let (desc, data) = dev.get_config(index)?;
let extra_length = desc.total_length as usize - mem::size_of_val(&desc);
let data = &data[..extra_length];
let mut i = 0;
let mut descriptors = Vec::new();
let mut interface_descs = SmallVec::with_capacity(desc.interfaces as usize);
while let Some((descriptor, len)) = AnyDescriptor::parse(&data[i..]) {
descriptors.push(descriptor);
i += len;
}
for _ in 0..desc.interfaces {
let mut idesc = usb::InterfaceDescriptor::default();
if i < extra_length && i < data.len() && idesc.copy_from_bytes(&data[i..extra_length]).is_ok() {
i += mem::size_of_val(&idesc);
let mut interface_descs = SmallVec::new();
let mut iter = descriptors.into_iter();
let mut endpoints = SmallVec::with_capacity(idesc.endpoints as usize);
while let Some(item) = iter.next() {
if let AnyDescriptor::Interface(idesc) = item {
let mut endpoints = SmallVec::<[AnyEndpDescJson; 4]>::new();
while endpoints.len() < idesc.endpoints as usize {
let mut edesc = usb::EndpointDescriptor::default();
if i < extra_length && i < data.len() && edesc.copy_from_bytes(&data[i..extra_length]).is_ok() {
match edesc.kind {
// TODO: Constants
5 => i += mem::size_of_val(&edesc),
48 => { i += 6; continue } // SuperSpeed Endpoint Companion Descriptor
_ => unimplemented!(),
}
for _ in 0..idesc.endpoints {
let next = match iter.next() {
Some(AnyDescriptor::Endpoint(n)) => n,
_ => break,
};
endpoints.push(AnyEndpDescJson::Endp(EndpDescJson::from(next)));
endpoints.push(EndpDescJson {
address: edesc.address,
attributes: edesc.attributes,
interval: edesc.interval,
kind: edesc.kind,
max_packet_size: edesc.max_packet_size,
})
} else { break }
if has_superspeed {
dbg!();
let next = match iter.next() {
Some(AnyDescriptor::SuperSpeedCompanion(n)) => n,
_ => break,
};
dbg!();
endpoints.push(AnyEndpDescJson::SuperSpeedCmp(SuperSpeedCmpJson::from(next)));
}
}
interface_descs.push(IfDescJson {
kind: idesc.kind,
number: idesc.number,
alternate_setting: idesc.alternate_setting,
class: idesc.class,
sub_class: idesc.sub_class,
protocol: idesc.protocol,
interface_str: if idesc.interface_str > 0 { Some(dev.get_string(idesc.interface_str)?) } else { None },
endpoints,
});
interface_descs.push(IfDescJson::new(&mut dev, idesc, endpoints)?);
} else {
// TODO
break;
}
}
@@ -236,32 +326,66 @@ impl SchemeMut for Xhci {
let num_str = &path_str[4..slash_idx.unwrap_or(path_str.len())];
let num = num_str.parse::<usize>().or(Err(Error::new(ENOENT)))?;
if slash_idx.is_some() && slash_idx.unwrap() + 1 < path_str.len() && &path_str[slash_idx.unwrap() + 1..] == "descriptors" {
if flags & O_DIRECTORY != 0 {
return Err(Error::new(ENOTDIR));
}
let mut contents = Vec::new();
self.write_port_desc(num, &mut contents)?;
let fd = self.next_handle;
self.handles.insert(fd, Handle::PortDesc(num, 0, contents));
self.next_handle += 1;
return Ok(fd);
}
if flags & O_DIRECTORY != 0 || flags & O_STAT != 0 {
let mut contents = Vec::new();
write!(contents, "descriptors\n").unwrap();
let fd = self.next_handle;
self.handles.insert(fd, Handle::Port(num, 0, contents));
self.next_handle += 1;
Ok(fd)
let subdir_str = if slash_idx.is_some() && slash_idx.unwrap() + 1 < path_str.len() {
Some(&path_str[slash_idx.unwrap() + 1..])
} else {
return Err(Error::new(EISDIR));
}
None
};
let handle = match subdir_str {
Some("descriptors") => {
if flags & O_DIRECTORY != 0 {
return Err(Error::new(ENOTDIR));
}
let mut contents = Vec::new();
self.write_port_desc(num, &mut contents)?;
Handle::PortDesc(num, 0, contents)
}
Some(other) if other.contains('/') => {
let slash_idx = other.chars().position(|c| c == '/').ok_or(Error::new(ENOENT))?;
if slash_idx + 2 >= other.len() {
return Err(Error::new(ENOENT));
}
let slice = &other[slash_idx + 2..];
let endpoint_num = slice.parse::<usize>().or(Err(Error::new(ENOENT)))?;
Handle::Endpoint(num, endpoint_num, 0)
}
Some("endpoints") => {
if flags & O_DIRECTORY == 0 && flags & O_STAT == 0 {
return Err(Error::new(EISDIR));
};
let mut contents = Vec::new();
let ps = &self.port_states[&num];
for (ep_num, _) in ps.input_context.device.endpoints.iter().enumerate().filter(|(_, ep)| ep.a.read() & 0b111 == 1) {
write!(contents, "i{}", ep_num).unwrap();
}
for (ep_num, _) in self.dev_ctx.contexts[ps.slot as usize].endpoints.iter().enumerate().filter(|(_, ep)| ep.a.read() & 0b111 == 1) {
write!(contents, "o{}", ep_num).unwrap();
}
Handle::Endpoints(num, 0, contents)
}
Some(_) => return Err(Error::new(ENOENT)),
None => if flags & O_DIRECTORY != 0 || flags & O_STAT != 0 {
let mut contents = Vec::new();
write!(contents, "descriptors\n").unwrap();
Handle::Port(num, 0, contents)
} else {
return Err(Error::new(EISDIR));
}
};
let fd = self.next_handle;
self.next_handle += 1;
self.handles.insert(fd, handle);
Ok(fd)
} else {
return Err(Error::new(ENOSYS));
}
@@ -269,7 +393,7 @@ impl SchemeMut for Xhci {
fn fstat(&mut self, id: usize, stat: &mut Stat) -> Result<usize> {
match self.handles.get(&id).ok_or(Error::new(EBADF))? {
Handle::TopLevel(_, ref buf) | Handle::Port(_, _, ref buf) => {
Handle::TopLevel(_, ref buf) | Handle::Port(_, _, ref buf) | Handle::Endpoints(_, _, ref buf) => {
// TODO: Known size perhaps?
stat.st_mode = MODE_DIR;
stat.st_size = buf.len() as u64;
@@ -280,12 +404,16 @@ impl SchemeMut for Xhci {
stat.st_size = buf.len() as u64;
Ok(0)
}
Handle::Endpoint(_, _, _) => {
stat.st_mode = MODE_FILE;
Ok(0)
}
}
}
fn seek(&mut self, fd: usize, pos: usize, whence: usize) -> Result<usize> {
match self.handles.get_mut(&fd).ok_or(Error::new(EBADF))? {
Handle::TopLevel(ref mut offset, ref buf) | Handle::Port(_, ref mut offset, ref buf) | Handle::PortDesc(_, ref mut offset, ref buf) => {
Handle::TopLevel(ref mut offset, ref buf) | Handle::Port(_, ref mut offset, ref buf) | Handle::PortDesc(_, ref mut offset, ref buf) | Handle::Endpoints(_, ref mut offset, ref buf) => {
*offset = match whence {
SEEK_SET => cmp::max(0, cmp::min(pos, buf.len())),
SEEK_CUR => cmp::max(0, cmp::min(*offset + pos, buf.len())),
@@ -294,12 +422,13 @@ impl SchemeMut for Xhci {
};
Ok(*offset)
}
Handle::Endpoint(_, _, _) => unimplemented!(),
}
}
fn read(&mut self, fd: usize, buf: &mut [u8]) -> Result<usize> {
match self.handles.get_mut(&fd).ok_or(Error::new(EBADF))? {
Handle::TopLevel(ref mut offset, ref src_buf) | Handle::Port(_, ref mut offset, ref src_buf) | Handle::PortDesc(_, ref mut offset, ref src_buf) => {
Handle::TopLevel(ref mut offset, ref src_buf) | Handle::Port(_, ref mut offset, ref src_buf) | Handle::PortDesc(_, ref mut offset, ref src_buf) | Handle::Endpoints(_, ref mut offset, ref src_buf) => {
let max_bytes_to_read = cmp::min(src_buf.len(), buf.len());
let bytes_to_read = cmp::max(max_bytes_to_read, *offset) - *offset;
@@ -308,6 +437,7 @@ impl SchemeMut for Xhci {
Ok(bytes_to_read)
}
Handle::Endpoint(_, _, _) => unimplemented!(),
}
}
fn close(&mut self, fd: usize) -> Result<usize> {
+12
View File
@@ -164,6 +164,18 @@ impl Trb {
(cycle as u32)
);
}
// Synchronizes the input context endpoints with the device context endpoints, it think.
pub fn configure_endpoint(&mut self, slot_id: u8, input_ctx_ptr: usize, cycle: bool) {
assert_eq!(input_ctx_ptr & 0xFFFF_FFFF_FFFF_FFF0, input_ctx_ptr);
self.set(
(input_ctx_ptr >> 4) as u64,
0,
(u32::from(slot_id) << 24) |
((TrbType::ConfigureEndpoint as u32) << 10) |
(cycle as u32),
)
}
pub fn setup(&mut self, setup: usb::Setup, transfer: TransferKind, cycle: bool) {
self.set(