Improve (subjective...) the descriptor fetching.
This commit is contained in:
+1
-1
@@ -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");
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
@@ -10,3 +10,5 @@ pub struct ConfigDescriptor {
|
||||
pub attributes: u8,
|
||||
pub max_power: u8,
|
||||
}
|
||||
|
||||
unsafe impl plain::Plain for ConfigDescriptor {}
|
||||
|
||||
@@ -16,3 +16,5 @@ pub struct DeviceDescriptor {
|
||||
pub serial_str: u8,
|
||||
pub configurations: u8,
|
||||
}
|
||||
|
||||
unsafe impl plain::Plain for DeviceDescriptor {}
|
||||
|
||||
@@ -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 {}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
@@ -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
@@ -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> {
|
||||
|
||||
@@ -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(
|
||||
|
||||
Reference in New Issue
Block a user