Merge pull request #116 from kevinmehall/refactor

Refactor
This commit is contained in:
Kevin Mehall 2025-02-23 17:49:16 -07:00 committed by GitHub
commit c3ad79ceac
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
13 changed files with 536 additions and 391 deletions

View file

@ -7,13 +7,14 @@ use std::{
fmt::{Debug, Display},
io::ErrorKind,
iter,
num::NonZeroU8,
ops::Deref,
};
use log::warn;
use crate::{
transfer::{Direction, EndpointType},
transfer::{Direction, TransferType},
Error,
};
@ -85,9 +86,9 @@ impl<'a> Deref for Descriptor<'a> {
/// An iterator over a sequence of USB descriptors.
#[derive(Clone)]
pub struct Descriptors<'a>(&'a [u8]);
pub struct DescriptorIter<'a>(&'a [u8]);
impl<'a> Descriptors<'a> {
impl<'a> DescriptorIter<'a> {
/// Get the concatenated bytes of the remaining descriptors.
pub fn as_bytes(&self) -> &'a [u8] {
self.0
@ -151,7 +152,7 @@ impl<'a> Descriptors<'a> {
}
}
impl<'a> Iterator for Descriptors<'a> {
impl<'a> Iterator for DescriptorIter<'a> {
type Item = Descriptor<'a>;
fn next(&mut self) -> Option<Self::Item> {
@ -181,37 +182,6 @@ macro_rules! descriptor_fields {
}
}
/// Check whether the buffer contains a valid device descriptor.
/// On success, it will return length of the descriptor, or returns `None`.
#[allow(unused)]
pub(crate) fn validate_device_descriptor(buf: &[u8]) -> Option<usize> {
if buf.len() < DESCRIPTOR_LEN_DEVICE as usize {
if buf.len() != 0 {
warn!(
"device descriptor buffer is {} bytes, need {}",
buf.len(),
DESCRIPTOR_LEN_DEVICE
);
}
return None;
}
if buf[0] < DESCRIPTOR_LEN_DEVICE {
warn!("invalid device descriptor bLength");
return None;
}
if buf[1] != DESCRIPTOR_TYPE_DEVICE {
warn!(
"device bDescriptorType is {}, not a device descriptor",
buf[1]
);
return None;
}
return Some(buf[0] as usize);
}
/// Information about a USB device.
#[derive(Clone)]
pub struct DeviceDescriptor([u8; DESCRIPTOR_LEN_DEVICE as usize]);
@ -222,14 +192,31 @@ impl DeviceDescriptor {
/// You normally obtain a `DeviceDescriptor` from a [`Device`][crate::Device], but this allows creating
/// one from your own descriptor bytes for tests.
///
/// ### Panics
/// * when the buffer is too short for a device descriptor
/// * when the first descriptor is not a device descriptor
pub fn new(buf: &[u8]) -> Self {
assert!(buf.len() >= DESCRIPTOR_LEN_DEVICE as usize);
assert!(buf[0] as usize >= DESCRIPTOR_LEN_DEVICE as usize);
assert!(buf[1] == DESCRIPTOR_TYPE_DEVICE);
Self(buf[0..DESCRIPTOR_LEN_DEVICE as usize].try_into().unwrap())
/// This ignores any trailing data after the `bLength` specified in the descriptor.
pub fn new(buf: &[u8]) -> Option<Self> {
let Some(buf) = buf.get(0..DESCRIPTOR_LEN_DEVICE as usize) else {
if buf.len() != 0 {
warn!(
"device descriptor buffer is {} bytes, need {}",
buf.len(),
DESCRIPTOR_LEN_DEVICE
);
}
return None;
};
let buf: [u8; DESCRIPTOR_LEN_DEVICE as usize] = buf.try_into().ok()?;
if buf[0] < DESCRIPTOR_LEN_DEVICE {
warn!("invalid device descriptor bLength");
None
} else if buf[1] != DESCRIPTOR_TYPE_DEVICE {
warn!(
"device bDescriptorType is {}, not a device descriptor",
buf[1]
);
None
} else {
Some(Self(buf))
}
}
/// Get the bytes of the descriptor.
@ -321,18 +308,18 @@ descriptor_fields! {
impl DeviceDescriptor {
/// `iManufacturer` descriptor field: Index for manufacturer description string.
pub fn manufacturer_string_index(&self) -> Option<u8> {
Some(self.manufacturer_string_index_raw()).filter(|&i| i != 0)
pub fn manufacturer_string_index(&self) -> Option<NonZeroU8> {
NonZeroU8::new(self.manufacturer_string_index_raw())
}
/// `iProduct` descriptor field: Index for product description string.
pub fn product_string_index(&self) -> Option<u8> {
Some(self.product_string_index_raw()).filter(|&i| i != 0)
pub fn product_string_index(&self) -> Option<NonZeroU8> {
NonZeroU8::new(self.product_string_index_raw())
}
/// `iSerialNumber` descriptor field: Index for serial number string.
pub fn serial_number_string_index(&self) -> Option<u8> {
Some(self.serial_number_string_index_raw()).filter(|&i| i != 0)
pub fn serial_number_string_index(&self) -> Option<NonZeroU8> {
NonZeroU8::new(self.serial_number_string_index_raw())
}
}
impl Debug for DeviceDescriptor {
@ -363,69 +350,67 @@ impl Debug for DeviceDescriptor {
}
}
#[allow(unused)]
pub(crate) fn validate_config_descriptor(buf: &[u8]) -> Option<usize> {
if buf.len() < DESCRIPTOR_LEN_CONFIGURATION as usize {
if buf.len() != 0 {
warn!(
"config descriptor buffer is {} bytes, need {}",
buf.len(),
DESCRIPTOR_LEN_CONFIGURATION
);
}
return None;
}
if buf[0] < DESCRIPTOR_LEN_CONFIGURATION {
warn!("invalid config descriptor bLength");
return None;
}
if buf[1] != DESCRIPTOR_TYPE_CONFIGURATION {
warn!(
"config bDescriptorType is {}, not a configuration descriptor",
buf[0]
);
return None;
}
let total_len = u16::from_le_bytes(buf[2..4].try_into().unwrap()) as usize;
if total_len < buf[0] as usize || total_len > buf.len() {
warn!(
"invalid config descriptor wTotalLen of {total_len} (buffer size is {bufsize})",
bufsize = buf.len()
);
return None;
}
Some(total_len)
}
/// Information about a USB configuration with access to all associated interfaces, endpoints, and other descriptors.
#[derive(Clone)]
pub struct ConfigurationDescriptor<'a>(&'a [u8]);
impl<'a> ConfigurationDescriptor<'a> {
/// Create a `Configuration` from a buffer containing a series of descriptors.
/// Create a `ConfigurationDescriptor` from a buffer containing a series of descriptors.
///
/// You normally obtain a `Configuration` from a [`Device`][crate::Device], but this allows creating
/// You normally obtain a `ConfigurationDescriptor` from a [`Device`][crate::Device], but this allows creating
/// one from your own descriptor bytes for tests.
///
/// ### Panics
/// * when the buffer is too short for a configuration descriptor
/// * when the bLength and wTotalLength fields are longer than the buffer
/// * when the first descriptor is not a configuration descriptor
pub fn new(buf: &[u8]) -> ConfigurationDescriptor {
assert!(buf.len() >= DESCRIPTOR_LEN_CONFIGURATION as usize);
assert!(buf[0] as usize >= DESCRIPTOR_LEN_CONFIGURATION as usize);
assert!(buf[1] == DESCRIPTOR_TYPE_CONFIGURATION);
assert!(buf.len() == u16::from_le_bytes(buf[2..4].try_into().unwrap()) as usize);
ConfigurationDescriptor(buf)
/// This ignores any trailing data after the length specified in `wTotalLen`.
pub fn new(buf: &[u8]) -> Option<ConfigurationDescriptor> {
if buf.len() < DESCRIPTOR_LEN_CONFIGURATION as usize {
if buf.len() != 0 {
warn!(
"config descriptor buffer is {} bytes, need {}",
buf.len(),
DESCRIPTOR_LEN_CONFIGURATION
);
}
return None;
}
if buf[0] < DESCRIPTOR_LEN_CONFIGURATION {
warn!("invalid config descriptor bLength");
return None;
}
if buf[1] != DESCRIPTOR_TYPE_CONFIGURATION {
warn!(
"config bDescriptorType is {}, not a configuration descriptor",
buf[0]
);
return None;
}
let total_len = u16::from_le_bytes(buf[2..4].try_into().unwrap()) as usize;
if total_len < buf[0] as usize || total_len > buf.len() {
warn!(
"invalid config descriptor wTotalLen of {total_len} (buffer size is {bufsize})",
bufsize = buf.len()
);
return None;
}
Some(ConfigurationDescriptor(&buf[..total_len]))
}
/// Get the configuration descriptor followed by all trailing interface and other descriptors.
pub fn descriptors(&self) -> Descriptors<'a> {
Descriptors(self.0)
#[allow(unused)]
pub(crate) fn new_unchecked(d: &'a [u8]) -> Self {
Self(d)
}
/// The bytes of the configuration descriptor and all trailing descriptors.
pub fn as_bytes(&self) -> &'a [u8] {
self.0
}
/// Iterate all trailing interface and other descriptors.
pub fn descriptors(&self) -> DescriptorIter<'a> {
DescriptorIter(&self.0[self.0[0] as usize..])
}
/// Iterate all interfaces and alternate settings settings of this configuration.
@ -484,8 +469,8 @@ descriptor_fields! {
impl<'a> ConfigurationDescriptor<'a> {
/// Index of the string descriptor describing this configuration.
#[doc(alias = "iConfiguration")]
pub fn string_index(&self) -> Option<u8> {
Some(self.string_index_raw()).filter(|&i| i != 0)
pub fn string_index(&self) -> Option<NonZeroU8> {
NonZeroU8::new(self.string_index_raw())
}
}
@ -556,10 +541,15 @@ impl<'a> InterfaceDescriptors<'a> {
pub struct InterfaceDescriptor<'a>(&'a [u8]);
impl<'a> InterfaceDescriptor<'a> {
/// Get the interface descriptor followed by all trailing endpoint and other
/// descriptors up to the next interface descriptor.
pub fn descriptors(&self) -> Descriptors<'a> {
Descriptors(self.0)
/// The bytes of the interface descriptor and all trailing descriptors.
pub fn as_bytes(&self) -> &[u8] {
self.0
}
/// Iterate all trailing endpoint and other descriptors up to the next
/// interface descriptor.
pub fn descriptors(&self) -> DescriptorIter<'a> {
DescriptorIter(&self.0[self.0[0] as usize..])
}
/// Get the endpoints of this interface.
@ -607,8 +597,8 @@ descriptor_fields! {
impl<'a> InterfaceDescriptor<'a> {
/// Index of the string descriptor describing this interface or alternate setting.
#[doc(alias = "iInterface")]
pub fn string_index(&self) -> Option<u8> {
Some(self.string_index_raw()).filter(|&i| i != 0)
pub fn string_index(&self) -> Option<NonZeroU8> {
NonZeroU8::new(self.string_index_raw())
}
}
@ -631,26 +621,28 @@ impl<'a> Debug for InterfaceDescriptor<'a> {
pub struct EndpointDescriptor<'a>(&'a [u8]);
impl<'a> EndpointDescriptor<'a> {
/// Get the endpoint descriptor followed by all trailing descriptors up to the next endpoint or interface descriptor.
pub fn descriptors(&self) -> impl Iterator<Item = Descriptor<'a>> {
Descriptors(self.0)
/// The bytes of the endpoint descriptor and all trailing descriptors.
pub fn as_bytes(&self) -> &'a [u8] {
self.0
}
/// Iterate all trailing descriptors up to the next endpoint or interface descriptor.
pub fn descriptors(&self) -> DescriptorIter<'a> {
DescriptorIter(&self.0[self.0[0] as usize..])
}
/// Get the endpoint's direction.
pub fn direction(&self) -> Direction {
match self.address() & 0x80 {
0 => Direction::Out,
_ => Direction::In,
}
Direction::from_address(self.address())
}
/// Get the endpoint's transfer type.
pub fn transfer_type(&self) -> EndpointType {
pub fn transfer_type(&self) -> TransferType {
match self.attributes() & 0x03 {
0 => EndpointType::Control,
1 => EndpointType::Isochronous,
2 => EndpointType::Bulk,
3 => EndpointType::Interrupt,
0 => TransferType::Control,
1 => TransferType::Isochronous,
2 => TransferType::Bulk,
3 => TransferType::Interrupt,
_ => unreachable!(),
}
}
@ -734,12 +726,13 @@ impl From<ActiveConfigurationError> for Error {
/// Split a chain of concatenated configuration descriptors by `wTotalLength`
#[allow(unused)]
pub(crate) fn parse_concatenated_config_descriptors(mut buf: &[u8]) -> impl Iterator<Item = &[u8]> {
pub(crate) fn parse_concatenated_config_descriptors(
mut buf: &[u8],
) -> impl Iterator<Item = ConfigurationDescriptor> {
iter::from_fn(move || {
let total_len = validate_config_descriptor(buf)?;
let descriptors = &buf[..total_len];
buf = &buf[total_len..];
Some(descriptors)
let desc = ConfigurationDescriptor::new(buf)?;
buf = &buf[desc.0.len()..];
Some(desc)
})
}
@ -774,15 +767,19 @@ mod test_concatenated {
#[test]
fn test_empty() {
assert_eq!(
parse_concatenated_config_descriptors(&[]).collect::<Vec<&[u8]>>(),
Vec::<&[u8]>::new()
parse_concatenated_config_descriptors(&[])
.collect::<Vec<_>>()
.len(),
0
);
}
#[test]
fn test_short() {
assert_eq!(
parse_concatenated_config_descriptors(&[0]).collect::<Vec<&[u8]>>(),
parse_concatenated_config_descriptors(&[0])
.map(|d| d.descriptors().as_bytes())
.collect::<Vec<_>>(),
Vec::<&[u8]>::new()
);
}
@ -791,7 +788,8 @@ mod test_concatenated {
fn test_invalid_total_len() {
assert_eq!(
parse_concatenated_config_descriptors(&[9, 2, 0, 0, 0, 0, 0, 0, 0])
.collect::<Vec<&[u8]>>(),
.map(|d| d.descriptors().as_bytes())
.collect::<Vec<_>>(),
Vec::<&[u8]>::new()
);
}
@ -800,13 +798,15 @@ mod test_concatenated {
fn test_one_config() {
assert_eq!(
parse_concatenated_config_descriptors(&[9, 2, 9, 0, 0, 0, 0, 0, 0])
.collect::<Vec<&[u8]>>(),
.map(|d| d.as_bytes())
.collect::<Vec<_>>(),
vec![&[9, 2, 9, 0, 0, 0, 0, 0, 0]]
);
assert_eq!(
parse_concatenated_config_descriptors(&[9, 2, 13, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0])
.collect::<Vec<&[u8]>>(),
.map(|d| d.as_bytes())
.collect::<Vec<_>>(),
vec![&[9, 2, 13, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0]]
);
}
@ -817,7 +817,8 @@ mod test_concatenated {
parse_concatenated_config_descriptors(&[
9, 2, 13, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 9, 2, 9, 0, 0, 0, 0, 0, 0
])
.collect::<Vec<&[u8]>>(),
.map(|d| d.as_bytes())
.collect::<Vec<_>>(),
vec![
[9, 2, 13, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0].as_slice(),
[9, 2, 9, 0, 0, 0, 0, 0, 0].as_slice()
@ -847,7 +848,7 @@ fn test_linux_root_hub() {
let dev = DeviceDescriptor::new(&[
0x12, 0x01, 0x00, 0x02, 0x09, 0x00, 0x01, 0x40, 0x6b,
0x1d, 0x02, 0x00, 0x10, 0x05, 0x03, 0x02, 0x01, 0x01
]);
]).unwrap();
assert_eq!(dev.usb_version(), 0x0200);
assert_eq!(dev.class(), 0x09);
assert_eq!(dev.subclass(), 0x00);
@ -856,9 +857,9 @@ fn test_linux_root_hub() {
assert_eq!(dev.vendor_id(), 0x1d6b);
assert_eq!(dev.product_id(), 0x0002);
assert_eq!(dev.device_version(), 0x0510);
assert_eq!(dev.manufacturer_string_index(), Some(3));
assert_eq!(dev.product_string_index(), Some(2));
assert_eq!(dev.serial_number_string_index(), Some(1));
assert_eq!(dev.manufacturer_string_index(), NonZeroU8::new(3));
assert_eq!(dev.product_string_index(), NonZeroU8::new(2));
assert_eq!(dev.serial_number_string_index(), NonZeroU8::new(1));
assert_eq!(dev.num_configurations(), 1);
let c = ConfigurationDescriptor(&[
@ -887,7 +888,7 @@ fn test_linux_root_hub() {
let endpoint = alt.endpoints().next().unwrap();
assert_eq!(endpoint.address(), 0x81);
assert_eq!(endpoint.transfer_type(), EndpointType::Interrupt);
assert_eq!(endpoint.transfer_type(), TransferType::Interrupt);
assert_eq!(endpoint.max_packet_size(), 4);
assert_eq!(endpoint.interval(), 12);
@ -1009,7 +1010,6 @@ fn test_dell_webcam() {
assert_eq!(alt.protocol(), 0);
let mut descriptors = alt.descriptors();
assert_eq!(descriptors.next().unwrap().descriptor_type(), DESCRIPTOR_TYPE_INTERFACE);
for _ in 0..6 {
assert_eq!(descriptors.next().unwrap().descriptor_type(), 0x24);
}
@ -1021,10 +1021,10 @@ fn test_dell_webcam() {
let endpoint = endpoints.next().unwrap();
assert_eq!(endpoint.address(), 0x83);
assert_eq!(endpoint.transfer_type(), EndpointType::Interrupt);
assert_eq!(endpoint.transfer_type(), TransferType::Interrupt);
assert_eq!(endpoint.max_packet_size(), 16);
assert_eq!(endpoint.descriptors().nth(1).unwrap().descriptor_type(), 0x25);
assert_eq!(endpoint.descriptors().next().unwrap().descriptor_type(), 0x25);
assert!(endpoints.next().is_none());
assert!(alts.next().is_none());
@ -1054,7 +1054,7 @@ fn test_dell_webcam() {
let endpoint = endpoints.next().unwrap();
assert_eq!(endpoint.address(), 0x81);
assert_eq!(endpoint.transfer_type(), EndpointType::Isochronous);
assert_eq!(endpoint.transfer_type(), TransferType::Isochronous);
assert_eq!(endpoint.max_packet_size(), 128);
assert!(endpoints.next().is_none());
@ -1070,7 +1070,7 @@ fn test_dell_webcam() {
let endpoint = endpoints.next().unwrap();
assert_eq!(endpoint.address(), 0x81);
assert_eq!(endpoint.transfer_type(), EndpointType::Isochronous);
assert_eq!(endpoint.transfer_type(), TransferType::Isochronous);
assert_eq!(endpoint.max_packet_size(), 256);
assert_eq!(endpoint.packets_per_microframe(), 1);
@ -1087,7 +1087,7 @@ fn test_dell_webcam() {
let endpoint = endpoints.next().unwrap();
assert_eq!(endpoint.address(), 0x81);
assert_eq!(endpoint.transfer_type(), EndpointType::Isochronous);
assert_eq!(endpoint.transfer_type(), TransferType::Isochronous);
assert_eq!(endpoint.max_packet_size(), 800);
assert_eq!(endpoint.packets_per_microframe(), 1);
@ -1104,7 +1104,7 @@ fn test_dell_webcam() {
let endpoint = endpoints.next().unwrap();
assert_eq!(endpoint.address(), 0x81);
assert_eq!(endpoint.transfer_type(), EndpointType::Isochronous);
assert_eq!(endpoint.transfer_type(), TransferType::Isochronous);
assert_eq!(endpoint.max_packet_size(), 800);
assert_eq!(endpoint.packets_per_microframe(), 2);
@ -1119,7 +1119,7 @@ fn test_dell_webcam() {
let endpoint = endpoints.next().unwrap();
assert_eq!(endpoint.address(), 0x81);
assert_eq!(endpoint.transfer_type(), EndpointType::Isochronous);
assert_eq!(endpoint.transfer_type(), TransferType::Isochronous);
assert_eq!(endpoint.max_packet_size(), 800);
assert_eq!(endpoint.packets_per_microframe(), 3);
@ -1134,7 +1134,7 @@ fn test_dell_webcam() {
let endpoint = endpoints.next().unwrap();
assert_eq!(endpoint.address(), 0x81);
assert_eq!(endpoint.transfer_type(), EndpointType::Isochronous);
assert_eq!(endpoint.transfer_type(), TransferType::Isochronous);
assert_eq!(endpoint.max_packet_size(), 1024);
assert_eq!(endpoint.packets_per_microframe(), 3);

View file

@ -5,13 +5,13 @@ use crate::{
},
platform,
transfer::{
Control, ControlIn, ControlOut, EndpointType, Queue, RequestBuffer, TransferError,
TransferFuture,
Control, ControlIn, ControlOut, Queue, RequestBuffer, TransferError, TransferFuture,
TransferType,
},
DeviceInfo, Error, MaybeFuture, Speed,
};
use log::error;
use std::{io::ErrorKind, sync::Arc, time::Duration};
use std::{io::ErrorKind, num::NonZeroU8, sync::Arc, time::Duration};
/// An opened USB device.
///
@ -46,13 +46,13 @@ impl Device {
pub(crate) fn open(
d: &DeviceInfo,
) -> impl MaybeFuture<Output = Result<Device, std::io::Error>> {
platform::Device::from_device_info(d)
platform::Device::from_device_info(d).map(|d| d.map(Device::wrap))
}
/// Wraps a device that is already open.
#[cfg(any(target_os = "android", target_os = "linux"))]
pub fn from_fd(fd: std::os::fd::OwnedFd) -> impl MaybeFuture<Output = Result<Device, Error>> {
platform::Device::from_fd(fd)
platform::Device::from_fd(fd).map(|d| d.map(Device::wrap))
}
/// Open an interface of the device and claim it for exclusive use.
@ -60,7 +60,10 @@ impl Device {
&self,
interface: u8,
) -> impl MaybeFuture<Output = Result<Interface, Error>> {
self.backend.clone().claim_interface(interface)
self.backend
.clone()
.claim_interface(interface)
.map(|i| i.map(Interface::wrap))
}
/// Detach kernel drivers and open an interface of the device and claim it for exclusive use.
@ -72,7 +75,10 @@ impl Device {
&self,
interface: u8,
) -> impl MaybeFuture<Output = Result<Interface, Error>> {
self.backend.clone().detach_and_claim_interface(interface)
self.backend
.clone()
.detach_and_claim_interface(interface)
.map(|i| i.map(Interface::wrap))
}
/// Detach kernel drivers for the specified interface.
@ -134,9 +140,7 @@ impl Device {
///
/// This returns cached data and does not perform IO.
pub fn configurations(&self) -> impl Iterator<Item = ConfigurationDescriptor> {
self.backend
.configuration_descriptors()
.map(ConfigurationDescriptor::new)
self.backend.configuration_descriptors()
}
/// Set the device configuration.
@ -237,17 +241,16 @@ impl Device {
/// See notes on [`get_descriptor`][`Self::get_descriptor`].
pub fn get_string_descriptor(
&self,
desc_index: u8,
desc_index: NonZeroU8,
language_id: u16,
timeout: Duration,
) -> Result<String, Error> {
if desc_index == 0 {
return Err(Error::new(
ErrorKind::InvalidInput,
"string descriptor index 0 is reserved for the language table",
));
}
let data = self.get_descriptor(DESCRIPTOR_TYPE_STRING, desc_index, language_id, timeout)?;
let data = self.get_descriptor(
DESCRIPTOR_TYPE_STRING,
desc_index.get(),
language_id,
timeout,
)?;
decode_string_descriptor(&data)
.map_err(|_| Error::new(ErrorKind::InvalidData, "string descriptor data was invalid"))
@ -394,6 +397,11 @@ impl Interface {
self.backend.clone().set_alt_setting(alt_setting)
}
/// Get the current alternate setting of this interface.
pub fn get_alt_setting(&self) -> u8 {
self.backend.get_alt_setting()
}
/// Synchronously perform a single **IN (device-to-host)** transfer on the default **control** endpoint.
///
/// ### Platform-specific notes
@ -465,7 +473,7 @@ impl Interface {
/// least significant byte differs from the interface number, and this may
/// become an error in the future.
pub fn control_in(&self, data: ControlIn) -> TransferFuture<ControlIn> {
let mut t = self.backend.make_transfer(0, EndpointType::Control);
let mut t = self.backend.make_transfer(0, TransferType::Control);
t.submit::<ControlIn>(data);
TransferFuture::new(t)
}
@ -501,7 +509,7 @@ impl Interface {
/// least significant byte differs from the interface number, and this may
/// become an error in the future.
pub fn control_out(&self, data: ControlOut) -> TransferFuture<ControlOut> {
let mut t = self.backend.make_transfer(0, EndpointType::Control);
let mut t = self.backend.make_transfer(0, TransferType::Control);
t.submit::<ControlOut>(data);
TransferFuture::new(t)
}
@ -511,7 +519,7 @@ impl Interface {
/// * The requested length must be a multiple of the endpoint's maximum packet size
/// * An IN endpoint address must have the top (`0x80`) bit set.
pub fn bulk_in(&self, endpoint: u8, buf: RequestBuffer) -> TransferFuture<RequestBuffer> {
let mut t = self.backend.make_transfer(endpoint, EndpointType::Bulk);
let mut t = self.backend.make_transfer(endpoint, TransferType::Bulk);
t.submit(buf);
TransferFuture::new(t)
}
@ -520,7 +528,7 @@ impl Interface {
///
/// * An OUT endpoint address must have the top (`0x80`) bit clear.
pub fn bulk_out(&self, endpoint: u8, buf: Vec<u8>) -> TransferFuture<Vec<u8>> {
let mut t = self.backend.make_transfer(endpoint, EndpointType::Bulk);
let mut t = self.backend.make_transfer(endpoint, TransferType::Bulk);
t.submit(buf);
TransferFuture::new(t)
}
@ -529,14 +537,14 @@ impl Interface {
///
/// * An IN endpoint address must have the top (`0x80`) bit set.
pub fn bulk_in_queue(&self, endpoint: u8) -> Queue<RequestBuffer> {
Queue::new(self.backend.clone(), endpoint, EndpointType::Bulk)
Queue::new(self.backend.clone(), endpoint, TransferType::Bulk)
}
/// Create a queue for managing multiple **OUT (host-to-device)** transfers on a **bulk** endpoint.
///
/// * An OUT endpoint address must have the top (`0x80`) bit clear.
pub fn bulk_out_queue(&self, endpoint: u8) -> Queue<Vec<u8>> {
Queue::new(self.backend.clone(), endpoint, EndpointType::Bulk)
Queue::new(self.backend.clone(), endpoint, TransferType::Bulk)
}
/// Submit a single **IN (device-to-host)** transfer on the specified **interrupt** endpoint.
@ -546,7 +554,7 @@ impl Interface {
pub fn interrupt_in(&self, endpoint: u8, buf: RequestBuffer) -> TransferFuture<RequestBuffer> {
let mut t = self
.backend
.make_transfer(endpoint, EndpointType::Interrupt);
.make_transfer(endpoint, TransferType::Interrupt);
t.submit(buf);
TransferFuture::new(t)
}
@ -557,7 +565,7 @@ impl Interface {
pub fn interrupt_out(&self, endpoint: u8, buf: Vec<u8>) -> TransferFuture<Vec<u8>> {
let mut t = self
.backend
.make_transfer(endpoint, EndpointType::Interrupt);
.make_transfer(endpoint, TransferType::Interrupt);
t.submit(buf);
TransferFuture::new(t)
}
@ -566,14 +574,14 @@ impl Interface {
///
/// * An IN endpoint address must have the top (`0x80`) bit set.
pub fn interrupt_in_queue(&self, endpoint: u8) -> Queue<RequestBuffer> {
Queue::new(self.backend.clone(), endpoint, EndpointType::Interrupt)
Queue::new(self.backend.clone(), endpoint, TransferType::Interrupt)
}
/// Create a queue for managing multiple **OUT (device-to-host)** transfers on an **interrupt** endpoint.
///
/// * An OUT endpoint address must have the top (`0x80`) bit clear.
pub fn interrupt_out_queue(&self, endpoint: u8) -> Queue<Vec<u8>> {
Queue::new(self.backend.clone(), endpoint, EndpointType::Interrupt)
Queue::new(self.backend.clone(), endpoint, TransferType::Interrupt)
}
/// Clear a bulk or interrupt endpoint's halt / stall condition.
@ -605,7 +613,6 @@ impl Interface {
.backend
.device
.configuration_descriptors()
.map(ConfigurationDescriptor::new)
.find(|c| c.configuration_value() == active);
configuration
@ -613,6 +620,12 @@ impl Interface {
.flat_map(|i| i.interface_alt_settings())
.filter(|g| g.interface_number() == self.backend.interface_number)
}
/// Get the interface descriptor for the current alternate setting.
pub fn descriptor(&self) -> Option<InterfaceDescriptor> {
self.descriptors()
.find(|i| i.alternate_setting() == self.get_alt_setting())
}
}
#[test]

View file

@ -1,4 +1,8 @@
use std::future::IntoFuture;
use std::{
future::{Future, IntoFuture},
pin::Pin,
task::{Context, Poll},
};
/// IO that may be performed synchronously or asynchronously.
///
@ -8,6 +12,17 @@ pub trait MaybeFuture: IntoFuture {
/// Block waiting for the action to complete
#[cfg(not(target_arch = "wasm32"))]
fn wait(self) -> Self::Output;
/// Apply a function to the output.
fn map<T: FnOnce(Self::Output) -> R + Unpin, R>(self, f: T) -> Map<Self, T>
where
Self: Sized,
{
Map {
wrapped: self,
func: f,
}
}
}
#[cfg(any(
@ -73,3 +88,47 @@ impl<T> MaybeFuture for Ready<T> {
self.0
}
}
pub struct Map<F, T> {
wrapped: F,
func: T,
}
impl<F: MaybeFuture, T: FnOnce(F::Output) -> R, R> IntoFuture for Map<F, T> {
type Output = R;
type IntoFuture = MapFut<F::IntoFuture, T>;
fn into_future(self) -> Self::IntoFuture {
MapFut {
wrapped: self.wrapped.into_future(),
func: Some(self.func),
}
}
}
impl<F: MaybeFuture, T: FnOnce(F::Output) -> R, R> MaybeFuture for Map<F, T> {
fn wait(self) -> Self::Output {
(self.func)(self.wrapped.wait())
}
}
pub struct MapFut<F, T> {
wrapped: F,
func: Option<T>,
}
impl<F: Future, T: FnOnce(F::Output) -> R, R> Future for MapFut<F, T> {
type Output = R;
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
// SAFETY: structural pin projection: `self.wrapped` is always pinned.
let wrapped = unsafe { self.as_mut().map_unchecked_mut(|s| &mut s.wrapped) };
Future::poll(wrapped, cx).map(|output| {
// SAFETY: `self.func` is never pinned.
let func = unsafe { &mut self.as_mut().get_unchecked_mut().func };
(func.take().expect("polled after completion"))(output)
})
}
}

View file

@ -1,4 +1,5 @@
use std::io::{ErrorKind, Seek};
use std::sync::{Mutex, Weak};
use std::{ffi::c_void, time::Duration};
use std::{
fs::File,
@ -19,24 +20,26 @@ use rustix::{
fs::{Mode, OFlags},
io::Errno,
};
use slab::Slab;
use super::{
errno_to_transfer_error, events,
usbfs::{self, Urb},
SysfsPath,
};
use crate::descriptors::{validate_device_descriptor, ConfigurationDescriptor, DeviceDescriptor};
use crate::descriptors::{ConfigurationDescriptor, DeviceDescriptor};
use crate::maybe_future::{blocking::Blocking, MaybeFuture};
use crate::platform::linux_usbfs::events::Watch;
use crate::transfer::{ControlType, Recipient};
use crate::{
descriptors::{parse_concatenated_config_descriptors, DESCRIPTOR_LEN_DEVICE},
transfer::{
notify_completion, Control, Direction, EndpointType, TransferError, TransferHandle,
notify_completion, Control, Direction, TransferError, TransferHandle, TransferType,
},
DeviceInfo, Error, Speed,
};
static DEVICES: Mutex<Slab<Weak<LinuxDevice>>> = Mutex::new(Slab::new());
pub(crate) struct LinuxDevice {
fd: OwnedFd,
events_id: usize,
@ -51,7 +54,7 @@ pub(crate) struct LinuxDevice {
impl LinuxDevice {
pub(crate) fn from_device_info(
d: &DeviceInfo,
) -> impl MaybeFuture<Output = Result<crate::Device, Error>> {
) -> impl MaybeFuture<Output = Result<Arc<LinuxDevice>, Error>> {
let busnum = d.busnum();
let devnum = d.device_address();
let sysfs_path = d.path.clone();
@ -61,16 +64,13 @@ impl LinuxDevice {
let path = PathBuf::from(format!("/dev/bus/usb/{busnum:03}/{devnum:03}"));
let fd = rustix::fs::open(&path, OFlags::RDWR | OFlags::CLOEXEC, Mode::empty())
.inspect_err(|e| warn!("Failed to open device {path:?}: {e}"))?;
let inner = Self::create_inner(fd, Some(sysfs_path), Some(active_config));
if inner.is_ok() {
debug!("Opened device bus={busnum} addr={devnum}",);
}
inner
Self::create_inner(fd, Some(sysfs_path), Some(active_config))
})
}
pub(crate) fn from_fd(fd: OwnedFd) -> impl MaybeFuture<Output = Result<crate::Device, Error>> {
pub(crate) fn from_fd(
fd: OwnedFd,
) -> impl MaybeFuture<Output = Result<Arc<LinuxDevice>, Error>> {
Blocking::new(move || {
debug!("Wrapping fd {} as usbfs device", fd.as_raw_fd());
Self::create_inner(fd, None, None)
@ -81,7 +81,7 @@ impl LinuxDevice {
fd: OwnedFd,
sysfs: Option<SysfsPath>,
active_config: Option<u8>,
) -> Result<crate::Device, Error> {
) -> Result<Arc<LinuxDevice>, Error> {
let descriptors = {
let mut file = unsafe { ManuallyDrop::new(File::from_raw_fd(fd.as_raw_fd())) };
// NOTE: Seek required on android
@ -91,7 +91,7 @@ impl LinuxDevice {
buf
};
let Some(_) = validate_device_descriptor(&descriptors) else {
let Some(_) = DeviceDescriptor::new(&descriptors) else {
return Err(Error::new(
ErrorKind::InvalidData,
"invalid device descriptor",
@ -104,19 +104,8 @@ impl LinuxDevice {
Self::get_config(&descriptors, &fd)?
};
// because there's no Arc::try_new_cyclic
let mut events_err = None;
let arc = Arc::new_cyclic(|weak| {
let res = events::register(
fd.as_fd(),
Watch::Device(weak.clone()),
epoll::EventFlags::OUT,
);
let events_id = *res.as_ref().unwrap_or(&usize::MAX);
events_err = res.err();
if events_err.is_none() {
debug!("Opened device fd={} with id {}", fd.as_raw_fd(), events_id,);
}
let events_id = DEVICES.lock().unwrap().insert(weak.clone());
LinuxDevice {
fd,
events_id,
@ -126,15 +115,29 @@ impl LinuxDevice {
}
});
if let Some(err) = events_err {
error!("Failed to initialize event loop: {err}");
Err(err)
} else {
Ok(crate::Device::wrap(arc))
debug!(
"Opened device fd={} with id {}",
arc.fd.as_raw_fd(),
arc.events_id
);
events::register_fd(
arc.fd.as_fd(),
events::Tag::Device(arc.events_id),
epoll::EventFlags::OUT,
)?;
Ok(arc)
}
pub(crate) fn handle_usb_epoll(id: usize) {
let device = DEVICES.lock().unwrap().get(id).and_then(|w| w.upgrade());
if let Some(device) = device {
device.handle_events();
}
}
pub(crate) fn handle_events(&self) {
fn handle_events(&self) {
debug!("Handling events for device {}", self.events_id);
match usbfs::reap_urb_ndelay(&self.fd) {
Ok(urb_ptr) => {
@ -167,10 +170,12 @@ impl LinuxDevice {
}
pub(crate) fn device_descriptor(&self) -> DeviceDescriptor {
DeviceDescriptor::new(&self.descriptors)
DeviceDescriptor::new(&self.descriptors).unwrap()
}
pub(crate) fn configuration_descriptors(&self) -> impl Iterator<Item = &[u8]> {
pub(crate) fn configuration_descriptors(
&self,
) -> impl Iterator<Item = ConfigurationDescriptor<'_>> {
parse_concatenated_config_descriptors(&self.descriptors[DESCRIPTOR_LEN_DEVICE as usize..])
}
@ -274,14 +279,14 @@ impl LinuxDevice {
self.clone(),
None,
0,
EndpointType::Control,
TransferType::Control,
))
}
pub(crate) fn claim_interface(
self: Arc<Self>,
interface_number: u8,
) -> impl MaybeFuture<Output = Result<crate::Interface, Error>> {
) -> impl MaybeFuture<Output = Result<Arc<LinuxInterface>, Error>> {
Blocking::new(move || {
usbfs::claim_interface(&self.fd, interface_number).inspect_err(|e| {
warn!(
@ -293,29 +298,31 @@ impl LinuxDevice {
"Claimed interface {interface_number} on device id {dev}",
dev = self.events_id
);
Ok(crate::Interface::wrap(Arc::new(LinuxInterface {
Ok(Arc::new(LinuxInterface {
device: self,
interface_number,
reattach: false,
})))
state: Mutex::new(Default::default()),
}))
})
}
pub(crate) fn detach_and_claim_interface(
self: Arc<Self>,
interface_number: u8,
) -> impl MaybeFuture<Output = Result<crate::Interface, Error>> {
) -> impl MaybeFuture<Output = Result<Arc<LinuxInterface>, Error>> {
Blocking::new(move || {
usbfs::detach_and_claim_interface(&self.fd, interface_number)?;
debug!(
"Detached and claimed interface {interface_number} on device id {dev}",
dev = self.events_id
);
Ok(crate::Interface::wrap(Arc::new(LinuxInterface {
Ok(Arc::new(LinuxInterface {
device: self,
interface_number,
reattach: true,
})))
state: Mutex::new(Default::default()),
}))
})
}
@ -421,9 +428,7 @@ impl LinuxDevice {
// Assume the current configuration is the first one
// See: https://github.com/libusb/libusb/blob/467b6a8896daea3d104958bf0887312c5d14d150/libusb/os/linux_usbfs.c#L865
let mut descriptors =
parse_concatenated_config_descriptors(&descriptors[DESCRIPTOR_LEN_DEVICE as usize..])
.map(ConfigurationDescriptor::new);
parse_concatenated_config_descriptors(&descriptors[DESCRIPTOR_LEN_DEVICE as usize..]);
if let Some(config) = descriptors.next() {
return Ok(config.configuration_value());
}
@ -454,21 +459,28 @@ impl LinuxDevice {
impl Drop for LinuxDevice {
fn drop(&mut self) {
debug!("Closing device {}", self.events_id);
events::unregister(self.fd.as_fd(), self.events_id)
events::unregister_fd(self.fd.as_fd());
DEVICES.lock().unwrap().remove(self.events_id);
}
}
pub(crate) struct LinuxInterface {
pub(crate) interface_number: u8,
pub(crate) device: Arc<LinuxDevice>,
pub(crate) reattach: bool,
reattach: bool,
state: Mutex<InterfaceState>,
}
#[derive(Default)]
struct InterfaceState {
alt_setting: u8,
}
impl LinuxInterface {
pub(crate) fn make_transfer(
self: &Arc<Self>,
endpoint: u8,
ep_type: EndpointType,
ep_type: TransferType,
) -> TransferHandle<super::TransferData> {
TransferHandle::new(super::TransferData::new(
self.device.clone(),
@ -496,20 +508,23 @@ impl LinuxInterface {
self.device.control_out_blocking(control, data, timeout)
}
pub fn get_alt_setting(&self) -> u8 {
self.state.lock().unwrap().alt_setting
}
pub fn set_alt_setting(
self: Arc<Self>,
alt_setting: u8,
) -> impl MaybeFuture<Output = Result<(), Error>> {
Blocking::new(move || {
let mut state = self.state.lock().unwrap();
debug!(
"Set interface {} alt setting to {alt_setting}",
self.interface_number
);
Ok(usbfs::set_interface(
&self.device.fd,
self.interface_number,
alt_setting,
)?)
usbfs::set_interface(&self.device.fd, self.interface_number, alt_setting)?;
state.alt_setting = alt_setting;
Ok(())
})
}

View file

@ -1,16 +1,17 @@
use atomic_waker::AtomicWaker;
/// Epoll based event loop for Linux.
///
/// Launches a thread when opening the first device that polls
/// for events on usbfs devices and arbitrary file descriptors
/// (used for udev hotplug).
///
/// ### Why not share an event loop with `tokio` or `async-io`?
///
/// This event loop will call USBFS_REAP_URB on the event thread and
/// dispatch to the transfer's waker directly. Since all USB transfers
/// on a device use the same file descriptor, putting USB-specific
/// dispatch in the event loop avoids additonal synchronization.
//! Epoll based event loop for Linux.
//!
//! Launches a thread when opening the first device that polls
//! for events on usbfs devices and arbitrary file descriptors
//! (used for udev hotplug).
//!
//! ### Why not share an event loop with `tokio` or `async-io`?
//!
//! This event loop will call USBFS_REAP_URB on the event thread and
//! dispatch to the transfer's waker directly. Since all USB transfers
//! on a device use the same file descriptor, putting USB-specific
//! dispatch in the event loop avoids additonal synchronization.
use crate::Error;
use once_cell::sync::OnceCell;
use rustix::{
event::epoll::{self, EventData, EventFlags},
@ -20,42 +21,63 @@ use rustix::{
use slab::Slab;
use std::{
io,
sync::{Arc, Mutex, Weak},
sync::{Arc, Mutex},
task::Waker,
thread,
};
use crate::Error;
use atomic_waker::AtomicWaker;
use super::Device;
static EPOLL_FD: OnceCell<OwnedFd> = OnceCell::new();
static WATCHES: Mutex<Slab<Watch>> = Mutex::new(Slab::new());
pub(super) enum Watch {
Device(Weak<Device>),
Fd(Arc<AtomicWaker>),
pub(crate) enum Tag {
Device(usize),
Waker(usize),
}
pub(super) fn register(fd: BorrowedFd, watch: Watch, flags: EventFlags) -> Result<usize, Error> {
impl Tag {
const DEVICE: u64 = 1;
const WAKER: u64 = 3;
fn as_event_data(&self) -> EventData {
let (tag, id) = match *self {
Tag::Device(id) => (Self::DEVICE, id),
Tag::Waker(id) => (Self::WAKER, id),
};
EventData::new_u64((id as u64) << 3 | tag)
}
fn from_event_data(data: EventData) -> Self {
let id = (data.u64() >> 3) as usize;
let tag = data.u64() & 0b111;
match (tag, id as usize) {
(Self::DEVICE, id) => Tag::Device(id),
(Self::WAKER, id) => Tag::Waker(id),
_ => panic!("Invalid event data"),
}
}
}
pub(super) fn register_fd(fd: BorrowedFd, tag: Tag, flags: EventFlags) -> Result<(), Error> {
let mut start_thread = false;
let epoll_fd = EPOLL_FD.get_or_try_init(|| {
start_thread = true;
epoll::create(epoll::CreateFlags::CLOEXEC)
epoll::create(epoll::CreateFlags::CLOEXEC).inspect_err(|e| {
log::error!("Failed to initialize epoll: {e}");
})
})?;
let id = {
let mut watches = WATCHES.lock().unwrap();
watches.insert(watch)
};
if start_thread {
thread::spawn(event_loop);
}
let data = EventData::new_u64(id as u64);
epoll::add(epoll_fd, fd, data, flags)?;
Ok(id)
epoll::add(epoll_fd, fd, tag.as_event_data(), flags).inspect_err(|e| {
log::error!("Failed to add epoll watch: {e}");
})?;
Ok(())
}
pub(super) fn unregister_fd(fd: BorrowedFd) {
@ -63,39 +85,27 @@ pub(super) fn unregister_fd(fd: BorrowedFd) {
epoll::delete(epoll_fd, fd).ok();
}
pub(super) fn unregister(fd: BorrowedFd, events_id: usize) {
let epoll_fd = EPOLL_FD.get().unwrap();
epoll::delete(epoll_fd, fd).ok();
WATCHES.lock().unwrap().remove(events_id);
}
fn event_loop() {
let epoll_fd = EPOLL_FD.get().unwrap();
let mut event_list = epoll::EventVec::with_capacity(4);
loop {
retry_on_intr(|| epoll::wait(epoll_fd, &mut event_list, -1)).unwrap();
for event in &event_list {
let key = event.data.u64() as usize;
log::trace!("event on {key}");
let lock = WATCHES.lock().unwrap();
let Some(watch) = lock.get(key) else { continue };
match watch {
Watch::Device(w) => {
if let Some(device) = w.upgrade() {
drop(lock);
device.handle_events();
// `device` gets dropped here. if it was the last reference, the LinuxDevice will be dropped.
// That will unregister its fd, so it's important that WATCHES is unlocked here, or we'd deadlock.
match Tag::from_event_data(event.data) {
Tag::Device(id) => Device::handle_usb_epoll(id),
Tag::Waker(id) => {
if let Some(waker) = WAKERS.lock().unwrap().get(id) {
waker.wake();
}
}
Watch::Fd(waker) => waker.wake(),
}
}
}
}
pub(crate) struct Async<T> {
static WAKERS: Mutex<Slab<Arc<AtomicWaker>>> = Mutex::new(Slab::new());
pub(crate) struct Async<T: AsFd> {
pub(crate) inner: T,
waker: Arc<AtomicWaker>,
id: usize,
@ -104,7 +114,8 @@ pub(crate) struct Async<T> {
impl<T: AsFd> Async<T> {
pub fn new(inner: T) -> Result<Self, io::Error> {
let waker = Arc::new(AtomicWaker::new());
let id = register(inner.as_fd(), Watch::Fd(waker.clone()), EventFlags::empty())?;
let id = WAKERS.lock().unwrap().insert(waker.clone());
register_fd(inner.as_fd(), Tag::Waker(id), EventFlags::empty())?;
Ok(Async { inner, id, waker })
}
@ -114,9 +125,16 @@ impl<T: AsFd> Async<T> {
epoll::modify(
epoll_fd,
self.inner.as_fd(),
EventData::new_u64(self.id as u64),
Tag::Waker(self.id).as_event_data(),
EventFlags::ONESHOT | EventFlags::IN,
)?;
Ok(())
}
}
impl<T: AsFd> Drop for Async<T> {
fn drop(&mut self) {
unregister_fd(self.inner.as_fd());
WAKERS.lock().unwrap().remove(self.id);
}
}

View file

@ -8,8 +8,8 @@ use std::{
use rustix::io::Errno;
use crate::transfer::{
Completion, ControlIn, ControlOut, EndpointType, PlatformSubmit, PlatformTransfer,
RequestBuffer, ResponseBuffer, TransferError, SETUP_PACKET_SIZE,
Completion, ControlIn, ControlOut, PlatformSubmit, PlatformTransfer, RequestBuffer,
ResponseBuffer, TransferError, TransferType, SETUP_PACKET_SIZE,
};
use super::{
@ -43,13 +43,13 @@ impl TransferData {
device: Arc<super::Device>,
interface: Option<Arc<super::Interface>>,
endpoint: u8,
ep_type: EndpointType,
ep_type: TransferType,
) -> TransferData {
let ep_type = match ep_type {
EndpointType::Control => USBDEVFS_URB_TYPE_CONTROL,
EndpointType::Interrupt => USBDEVFS_URB_TYPE_INTERRUPT,
EndpointType::Bulk => USBDEVFS_URB_TYPE_BULK,
EndpointType::Isochronous => USBDEVFS_URB_TYPE_ISO,
TransferType::Control => USBDEVFS_URB_TYPE_CONTROL,
TransferType::Interrupt => USBDEVFS_URB_TYPE_INTERRUPT,
TransferType::Bulk => USBDEVFS_URB_TYPE_BULK,
TransferType::Isochronous => USBDEVFS_URB_TYPE_ISO,
};
TransferData {

View file

@ -12,9 +12,9 @@ use std::{
use log::{debug, error};
use crate::{
descriptors::DeviceDescriptor,
descriptors::{ConfigurationDescriptor, DeviceDescriptor},
maybe_future::blocking::Blocking,
transfer::{Control, Direction, EndpointType, TransferError, TransferHandle},
transfer::{Control, Direction, TransferError, TransferHandle, TransferType},
DeviceInfo, Error, MaybeFuture, Speed,
};
@ -53,7 +53,7 @@ fn guess_active_config(dev: &IoKitDevice) -> Option<u8> {
impl MacDevice {
pub(crate) fn from_device_info(
d: &DeviceInfo,
) -> impl MaybeFuture<Output = Result<crate::Device, Error>> {
) -> impl MaybeFuture<Output = Result<Arc<MacDevice>, Error>> {
let registry_id = d.registry_id;
let speed = d.speed;
Blocking::new(move || {
@ -88,7 +88,7 @@ impl MacDevice {
res.unwrap_or(0)
};
Ok(crate::Device::wrap(Arc::new(MacDevice {
Ok(Arc::new(MacDevice {
_event_registration,
device,
device_descriptor,
@ -96,7 +96,7 @@ impl MacDevice {
active_config: AtomicU8::new(active_config),
is_open_exclusive: Mutex::new(opened),
claimed_interfaces: AtomicUsize::new(0),
})))
}))
})
}
@ -112,9 +112,13 @@ impl MacDevice {
self.active_config.load(Ordering::SeqCst)
}
pub(crate) fn configuration_descriptors(&self) -> impl Iterator<Item = &[u8]> {
pub(crate) fn configuration_descriptors(
&self,
) -> impl Iterator<Item = ConfigurationDescriptor> {
let num_configs = self.device.get_number_of_configurations().unwrap_or(0);
(0..num_configs).flat_map(|i| self.device.get_configuration_descriptor(i).ok())
(0..num_configs)
.flat_map(|i| self.device.get_configuration_descriptor(i).ok())
.flat_map(ConfigurationDescriptor::new)
}
fn require_open_exclusive(&self) -> Result<(), Error> {
@ -232,7 +236,7 @@ impl MacDevice {
pub(crate) fn claim_interface(
self: Arc<Self>,
interface_number: u8,
) -> impl MaybeFuture<Output = Result<crate::Interface, Error>> {
) -> impl MaybeFuture<Output = Result<Arc<MacInterface>, Error>> {
Blocking::new(move || {
let intf_service = self
.device
@ -250,20 +254,21 @@ impl MacDevice {
self.claimed_interfaces.fetch_add(1, Ordering::Acquire);
Ok(crate::Interface::wrap(Arc::new(MacInterface {
Ok(Arc::new(MacInterface {
device: self.clone(),
interface_number,
interface,
endpoints: Mutex::new(endpoints),
state: Mutex::new(InterfaceState::default()),
_event_registration,
})))
}))
})
}
pub(crate) fn detach_and_claim_interface(
self: Arc<Self>,
interface: u8,
) -> impl MaybeFuture<Output = Result<crate::Interface, Error>> {
) -> impl MaybeFuture<Output = Result<Arc<MacInterface>, Error>> {
self.claim_interface(interface)
}
}
@ -284,18 +289,23 @@ pub(crate) struct MacInterface {
_event_registration: EventRegistration,
pub(crate) interface: IoKitInterface,
pub(crate) device: Arc<MacDevice>,
/// Map from address to a structure that contains the `pipe_ref` used by iokit
pub(crate) endpoints: Mutex<BTreeMap<u8, EndpointInfo>>,
state: Mutex<InterfaceState>,
}
#[derive(Default)]
struct InterfaceState {
alt_setting: u8,
}
impl MacInterface {
pub(crate) fn make_transfer(
self: &Arc<Self>,
endpoint: u8,
ep_type: EndpointType,
ep_type: TransferType,
) -> TransferHandle<super::TransferData> {
if ep_type == EndpointType::Control {
if ep_type == TransferType::Control {
assert!(endpoint == 0);
TransferHandle::new(super::TransferData::new_control(self.device.clone()))
} else {
@ -337,6 +347,7 @@ impl MacInterface {
alt_setting: u8,
) -> impl MaybeFuture<Output = Result<(), Error>> {
Blocking::new(move || {
let mut state = self.state.lock().unwrap();
debug!(
"Set interface {} alt setting to {alt_setting}",
self.interface_number
@ -353,11 +364,16 @@ impl MacInterface {
*endpoints = self.interface.endpoints()?;
debug!("Found endpoints: {endpoints:?}");
state.alt_setting = alt_setting;
Ok(())
})
}
pub fn get_alt_setting(&self) -> u8 {
self.state.lock().unwrap().alt_setting
}
pub fn clear_halt(
self: Arc<Self>,
endpoint: u8,

View file

@ -24,12 +24,12 @@ use windows_sys::Win32::{
use crate::{
descriptors::{
validate_config_descriptor, DeviceDescriptor, DESCRIPTOR_LEN_DEVICE,
ConfigurationDescriptor, DeviceDescriptor, DESCRIPTOR_LEN_DEVICE,
DESCRIPTOR_TYPE_CONFIGURATION,
},
maybe_future::{blocking::Blocking, MaybeFuture, Ready},
transfer::{Control, Direction, EndpointType, Recipient, TransferError, TransferHandle},
DeviceInfo, Error, Speed,
maybe_future::{blocking::Blocking, Ready},
transfer::{Control, Direction, Recipient, TransferError, TransferHandle, TransferType},
DeviceInfo, Error, MaybeFuture, Speed,
};
use super::{
@ -53,7 +53,7 @@ pub(crate) struct WindowsDevice {
impl WindowsDevice {
pub(crate) fn from_device_info(
d: &DeviceInfo,
) -> impl MaybeFuture<Output = Result<crate::Device, Error>> {
) -> impl MaybeFuture<Output = Result<Arc<WindowsDevice>, Error>> {
let instance_id = d.instance_id.clone();
let devinst = d.devinst;
Blocking::new(move || {
@ -68,33 +68,31 @@ impl WindowsDevice {
// Safety: Windows API struct is repr(C), packed, and we're assuming Windows is little-endian
let device_descriptor = unsafe {
DeviceDescriptor::new(&transmute::<_, [u8; DESCRIPTOR_LEN_DEVICE as usize]>(
connection_info.device_desc,
))
&transmute::<_, [u8; DESCRIPTOR_LEN_DEVICE as usize]>(connection_info.device_desc)
};
let device_descriptor = DeviceDescriptor::new(device_descriptor)
.ok_or_else(|| Error::new(ErrorKind::InvalidData, "invalid device descriptor"))?;
let num_configurations = connection_info.device_desc.bNumConfigurations;
let config_descriptors = (0..num_configurations)
.flat_map(|i| {
let res = hub_port.get_descriptor(DESCRIPTOR_TYPE_CONFIGURATION, i, 0);
match res {
Ok(v) => validate_config_descriptor(&v[..]).map(|_| v),
Err(e) => {
error!("Failed to read config descriptor {}: {}", i, e);
None
}
}
let d = hub_port
.get_descriptor(DESCRIPTOR_TYPE_CONFIGURATION, i, 0)
.inspect_err(|e| error!("Failed to read config descriptor {}: {}", i, e))
.ok()?;
ConfigurationDescriptor::new(&d).is_some().then_some(d)
})
.collect();
Ok(crate::Device::wrap(Arc::new(WindowsDevice {
Ok(Arc::new(WindowsDevice {
device_descriptor,
config_descriptors,
speed: connection_info.speed,
active_config: connection_info.active_config,
devinst: devinst,
handles: Mutex::new(BTreeMap::new()),
})))
}))
})
}
@ -110,8 +108,12 @@ impl WindowsDevice {
self.active_config
}
pub(crate) fn configuration_descriptors(&self) -> impl Iterator<Item = &[u8]> {
self.config_descriptors.iter().map(|d| &d[..])
pub(crate) fn configuration_descriptors(
&self,
) -> impl Iterator<Item = ConfigurationDescriptor> {
self.config_descriptors
.iter()
.map(|d| ConfigurationDescriptor::new_unchecked(&d[..]))
}
pub(crate) fn set_configuration(
@ -143,63 +145,55 @@ impl WindowsDevice {
pub(crate) fn claim_interface(
self: Arc<Self>,
interface_number: u8,
) -> impl MaybeFuture<Output = Result<crate::Interface, Error>> {
) -> impl MaybeFuture<Output = Result<Arc<WindowsInterface>, Error>> {
Blocking::new(move || {
self.claim_interface_blocking(interface_number)
.map(crate::Interface::wrap)
let driver = get_driver_name(self.devinst);
let mut handles = self.handles.lock().unwrap();
if driver.eq_ignore_ascii_case("winusb") {
match handles.entry(0) {
Entry::Occupied(mut e) => e.get_mut().claim_interface(&self, interface_number),
Entry::Vacant(e) => {
let path = get_winusb_device_path(self.devinst)?;
let mut handle = WinusbFileHandle::new(&path, 0)?;
let intf = handle.claim_interface(&self, interface_number)?;
e.insert(handle);
Ok(intf)
}
}
} else if driver.eq_ignore_ascii_case("usbccgp") {
let (first_interface, child_dev) =
find_usbccgp_child(self.devinst, interface_number)
.ok_or_else(|| Error::new(ErrorKind::NotFound, "Interface not found"))?;
if first_interface != interface_number {
debug!("Guessing that interface {interface_number} is an associated interface of {first_interface}");
}
match handles.entry(first_interface) {
Entry::Occupied(mut e) => e.get_mut().claim_interface(&self, interface_number),
Entry::Vacant(e) => {
let path = get_usbccgp_winusb_device_path(child_dev)?;
let mut handle = WinusbFileHandle::new(&path, first_interface)?;
let intf = handle.claim_interface(&self, interface_number)?;
e.insert(handle);
Ok(intf)
}
}
} else {
Err(Error::new(
ErrorKind::Unsupported,
format!("Device driver is {driver:?}, not WinUSB or USBCCGP"),
))
}
})
}
fn claim_interface_blocking(
self: &Arc<Self>,
interface_number: u8,
) -> Result<Arc<WindowsInterface>, Error> {
let driver = get_driver_name(self.devinst);
let mut handles = self.handles.lock().unwrap();
if driver.eq_ignore_ascii_case("winusb") {
match handles.entry(0) {
Entry::Occupied(mut e) => e.get_mut().claim_interface(self, interface_number),
Entry::Vacant(e) => {
let path = get_winusb_device_path(self.devinst)?;
let mut handle = WinusbFileHandle::new(&path, 0)?;
let intf = handle.claim_interface(self, interface_number)?;
e.insert(handle);
Ok(intf)
}
}
} else if driver.eq_ignore_ascii_case("usbccgp") {
let (first_interface, child_dev) =
find_usbccgp_child(self.devinst, interface_number)
.ok_or_else(|| Error::new(ErrorKind::NotFound, "Interface not found"))?;
if first_interface != interface_number {
debug!("Guessing that interface {interface_number} is an associated interface of {first_interface}");
}
match handles.entry(first_interface) {
Entry::Occupied(mut e) => e.get_mut().claim_interface(self, interface_number),
Entry::Vacant(e) => {
let path = get_usbccgp_winusb_device_path(child_dev)?;
let mut handle = WinusbFileHandle::new(&path, first_interface)?;
let intf = handle.claim_interface(self, interface_number)?;
e.insert(handle);
Ok(intf)
}
}
} else {
Err(Error::new(
ErrorKind::Unsupported,
format!("Device driver is {driver:?}, not WinUSB or USBCCGP"),
))
}
}
pub(crate) fn detach_and_claim_interface(
self: Arc<Self>,
interface: u8,
) -> impl MaybeFuture<Output = Result<crate::Interface, Error>> {
) -> impl MaybeFuture<Output = Result<Arc<WindowsInterface>, Error>> {
self.claim_interface(interface)
}
}
@ -319,6 +313,7 @@ impl WinusbFileHandle {
interface_number,
first_interface_number: self.first_interface,
winusb_handle,
state: Mutex::new(InterfaceState::default()),
}))
}
}
@ -341,6 +336,12 @@ pub(crate) struct WindowsInterface {
pub(crate) first_interface_number: u8,
pub(crate) interface_number: u8,
pub(crate) winusb_handle: WINUSB_INTERFACE_HANDLE,
state: Mutex<InterfaceState>,
}
#[derive(Default)]
struct InterfaceState {
alt_setting: u8,
}
unsafe impl Send for WindowsInterface {}
@ -386,7 +387,7 @@ impl WindowsInterface {
pub(crate) fn make_transfer(
self: &Arc<Self>,
endpoint: u8,
ep_type: EndpointType,
ep_type: TransferType,
) -> TransferHandle<super::TransferData> {
TransferHandle::new(super::TransferData::new(self.clone(), endpoint, ep_type))
}
@ -507,8 +508,14 @@ impl WindowsInterface {
alt_setting: u8,
) -> impl MaybeFuture<Output = Result<(), Error>> {
Blocking::new(move || unsafe {
let mut state = self.state.lock().unwrap();
let r = WinUsb_SetCurrentAlternateSetting(self.winusb_handle, alt_setting.into());
if r == TRUE {
debug!(
"Set interface {} alt setting to {alt_setting}",
self.interface_number
);
state.alt_setting = alt_setting;
Ok(())
} else {
Err(io::Error::last_os_error())
@ -516,6 +523,10 @@ impl WindowsInterface {
})
}
pub fn get_alt_setting(&self) -> u8 {
self.state.lock().unwrap().alt_setting
}
pub fn clear_halt(
self: Arc<Self>,
endpoint: u8,

View file

@ -15,8 +15,8 @@ use windows_sys::Win32::Devices::{
use crate::{
descriptors::{
decode_string_descriptor, language_id::US_ENGLISH, validate_config_descriptor,
ConfigurationDescriptor, DESCRIPTOR_TYPE_CONFIGURATION, DESCRIPTOR_TYPE_STRING,
decode_string_descriptor, language_id::US_ENGLISH, ConfigurationDescriptor,
DESCRIPTOR_TYPE_CONFIGURATION, DESCRIPTOR_TYPE_STRING,
},
maybe_future::{blocking::Blocking, MaybeFuture},
BusInfo, DeviceInfo, Error, InterfaceInfo, UsbControllerType,
@ -206,8 +206,7 @@ fn list_interfaces_from_desc(hub_port: &HubPort, active_config: u8) -> Option<Ve
0,
)
.ok()?;
let len = validate_config_descriptor(&buf)?;
let desc = ConfigurationDescriptor::new(&buf[..len]);
let desc = ConfigurationDescriptor::new(&buf[..])?;
if desc.configuration_value() != active_config {
return None;

View file

@ -21,8 +21,8 @@ use windows_sys::Win32::{
};
use crate::transfer::{
notify_completion, Completion, ControlIn, ControlOut, EndpointType, PlatformSubmit,
PlatformTransfer, Recipient, RequestBuffer, ResponseBuffer, TransferError,
notify_completion, Completion, ControlIn, ControlOut, PlatformSubmit, PlatformTransfer,
Recipient, RequestBuffer, ResponseBuffer, TransferError, TransferType,
};
#[repr(C)]
@ -38,7 +38,7 @@ pub struct TransferData {
buf: *mut u8,
capacity: usize,
endpoint: u8,
ep_type: EndpointType,
ep_type: TransferType,
submit_error: Option<WIN32_ERROR>,
}
@ -48,7 +48,7 @@ impl TransferData {
pub(crate) fn new(
interface: std::sync::Arc<super::Interface>,
endpoint: u8,
ep_type: EndpointType,
ep_type: TransferType,
) -> TransferData {
TransferData {
interface,
@ -225,7 +225,7 @@ impl PlatformSubmit<RequestBuffer> for TransferData {
impl PlatformSubmit<ControlIn> for TransferData {
unsafe fn submit(&mut self, data: ControlIn, user_data: *mut c_void) {
assert_eq!(self.endpoint, 0);
assert_eq!(self.ep_type, EndpointType::Control);
assert_eq!(self.ep_type, TransferType::Control);
if data.recipient == Recipient::Interface
&& data.index as u8 != self.interface.interface_number
@ -274,7 +274,7 @@ impl PlatformSubmit<ControlIn> for TransferData {
impl PlatformSubmit<ControlOut<'_>> for TransferData {
unsafe fn submit(&mut self, data: ControlOut, user_data: *mut c_void) {
assert_eq!(self.endpoint, 0);
assert_eq!(self.ep_type, EndpointType::Control);
assert_eq!(self.ep_type, TransferType::Control);
if data.recipient == Recipient::Interface
&& data.index as u8 != self.interface.interface_number

View file

@ -8,7 +8,17 @@ pub enum Direction {
Out = 0,
/// Device to host
In = 1,
In = 0x80,
}
impl Direction {
pub(crate) fn from_address(addr: u8) -> Direction {
match addr & Self::MASK {
0 => Self::Out,
_ => Self::In,
}
}
pub(crate) const MASK: u8 = 0x80;
}
/// Specification defining the request.
@ -200,10 +210,14 @@ fn pack_setup(
]
}
fn request_type(direction: Direction, control_type: ControlType, recipient: Recipient) -> u8 {
((direction as u8) << 7) | ((control_type as u8) << 5) | (recipient as u8)
}
impl TransferRequest for ControlIn {
type Response = Vec<u8>;
}
pub(crate) fn request_type(
direction: Direction,
control_type: ControlType,
recipient: Recipient,
) -> u8 {
(direction as u8) | ((control_type as u8) << 5) | (recipient as u8)
}

View file

@ -32,7 +32,7 @@ pub(crate) use internal::{
/// Endpoint type.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[allow(dead_code)]
pub enum EndpointType {
pub enum TransferType {
/// Control endpoint.
Control = 0,

View file

@ -8,7 +8,7 @@ use std::{
use crate::{platform, Error, MaybeFuture};
use super::{Completion, EndpointType, PlatformSubmit, TransferHandle, TransferRequest};
use super::{Completion, PlatformSubmit, TransferHandle, TransferRequest, TransferType};
/// Manages a stream of transfers on an endpoint.
///
@ -113,7 +113,7 @@ use super::{Completion, EndpointType, PlatformSubmit, TransferHandle, TransferRe
pub struct Queue<R: TransferRequest> {
interface: Arc<platform::Interface>,
endpoint: u8,
endpoint_type: EndpointType,
endpoint_type: TransferType,
/// A queue of pending transfers, expected to complete in order
pending: VecDeque<TransferHandle<platform::TransferData>>,
@ -132,7 +132,7 @@ where
pub(crate) fn new(
interface: Arc<platform::Interface>,
endpoint: u8,
endpoint_type: EndpointType,
endpoint_type: TransferType,
) -> Queue<R> {
Queue {
interface,