linux: Add Device::active_configuration

This commit is contained in:
Kevin Mehall 2023-12-16 11:45:46 -07:00
parent a1853db65d
commit 767d81131e
6 changed files with 67 additions and 8 deletions

View file

@ -20,11 +20,16 @@ fn inspect_device(dev: DeviceInfo) {
let dev = match dev.open() {
Ok(dev) => dev,
Err(e) => {
println!("\tFailed to open device: {}", e);
println!(" Failed to open device: {}", e);
return;
}
};
match dev.active_configuration() {
Ok(config) => println!(" Active configuration is {}", config.configuration_value()),
Err(e) => println!("Unknown active configuration: {e}"),
}
for config in dev.configurations() {
println!(" Configuration {}", config.configuration_value());
for intf in config.interfaces() {

View file

@ -1,7 +1,7 @@
use std::sync::Arc;
use crate::{
descriptors::Configuration,
descriptors::{ActiveConfigurationError, Configuration},
platform,
transfer::{ControlIn, ControlOut, EndpointType, Queue, RequestBuffer, TransferFuture},
DeviceInfo, Error,
@ -44,7 +44,18 @@ impl Device {
Ok(Interface { backend })
}
/// Iterate over the configurations of the device.
/// Get information about the active configuration.
pub fn active_configuration(&self) -> Result<Configuration, ActiveConfigurationError> {
let active = self.backend.active_configuration_value();
self.configurations()
.find(|c| c.configuration_value() == active)
.ok_or_else(|| ActiveConfigurationError {
configuration_value: active,
})
}
/// Iterate over all configurations of the device.
pub fn configurations(&self) -> impl Iterator<Item = Configuration> {
self.backend
.configuration_descriptors()
@ -53,6 +64,10 @@ impl Device {
/// Set the device configuration.
///
/// The argument is the desired configuration's `bConfigurationValue`
/// descriptor field from [`Configuration::configuration_value`] or `0` to
/// unconfigure the device.
///
/// ### Platform-specific notes
/// * Not supported on Windows
pub fn set_configuration(&self, configuration: u8) -> Result<(), Error> {

View file

@ -1,4 +1,13 @@
use std::{fs::File, io::Read, mem::ManuallyDrop, path::PathBuf, sync::Arc};
use std::{
fs::File,
io::Read,
mem::ManuallyDrop,
path::PathBuf,
sync::{
atomic::{AtomicU8, Ordering},
Arc,
},
};
use log::{debug, error};
use rustix::{
@ -10,6 +19,7 @@ use rustix::{
use super::{
events,
usbfs::{self, Urb},
SysfsPath,
};
use crate::{
descriptors::{parse_concatenated_config_descriptors, DESCRIPTOR_LEN_DEVICE},
@ -23,14 +33,17 @@ pub(crate) struct LinuxDevice {
/// Read from the fd, consists of device descriptor followed by configuration descriptors
descriptors: Vec<u8>,
sysfs: Option<SysfsPath>,
active_config: AtomicU8,
}
impl LinuxDevice {
pub(crate) fn from_device_info(d: &DeviceInfo) -> Result<Arc<LinuxDevice>, Error> {
Self::open(d.bus_number(), d.device_address())
}
let busnum = d.bus_number();
let devnum = d.device_address();
let active_config = d.path.read_attr("bConfigurationValue")?;
pub(crate) fn open(busnum: u8, devnum: u8) -> Result<Arc<LinuxDevice>, Error> {
let path = PathBuf::from(format!("/dev/bus/usb/{busnum:03}/{devnum:03}"));
debug!("Opening usbfs device {}", path.display());
let fd = rustix::fs::open(path, OFlags::RDWR | OFlags::CLOEXEC, Mode::empty())?;
@ -52,6 +65,8 @@ impl LinuxDevice {
fd,
events_id,
descriptors,
sysfs: Some(d.path.clone()),
active_config: AtomicU8::new(active_config),
}
});
@ -103,8 +118,24 @@ impl LinuxDevice {
parse_concatenated_config_descriptors(&self.descriptors[DESCRIPTOR_LEN_DEVICE as usize..])
}
pub(crate) fn active_configuration_value(&self) -> u8 {
if let Some(sysfs) = self.sysfs.as_ref() {
match sysfs.read_attr("bConfigurationValue") {
Ok(v) => {
self.active_config.store(v, Ordering::SeqCst);
return v;
}
Err(e) => {
error!("Failed to read sysfs bConfigurationValue: {e}, using cached value");
}
}
}
self.active_config.load(Ordering::SeqCst)
}
pub(crate) fn set_configuration(&self, configuration: u8) -> Result<(), Error> {
usbfs::set_configuration(&self.fd, configuration)?;
self.active_config.store(configuration, Ordering::SeqCst);
Ok(())
}

View file

@ -14,7 +14,7 @@ use crate::Speed;
pub struct SysfsPath(PathBuf);
impl SysfsPath {
fn read_attr<T: FromStr>(&self, attr: &str) -> Result<T, io::Error>
pub(crate) fn read_attr<T: FromStr>(&self, attr: &str) -> Result<T, io::Error>
where
T: FromStr,
T::Err: std::error::Error + Send + Sync + 'static,

View file

@ -33,6 +33,10 @@ impl MacDevice {
}))
}
pub(crate) fn active_configuration_value(&self) -> u8 {
1
}
pub(crate) fn configuration_descriptors(&self) -> impl Iterator<Item = &[u8]> {
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())

View file

@ -80,6 +80,10 @@ impl WindowsDevice {
}))
}
pub(crate) fn active_configuration_value(&self) -> u8 {
1
}
pub(crate) fn configuration_descriptors(&self) -> impl Iterator<Item = &[u8]> {
self.config_descriptors.iter().map(|d| &d[..])
}