linux: Add Device::active_configuration
This commit is contained in:
parent
a1853db65d
commit
767d81131e
6 changed files with 67 additions and 8 deletions
|
|
@ -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() {
|
||||
|
|
|
|||
|
|
@ -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> {
|
||||
|
|
|
|||
|
|
@ -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(())
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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())
|
||||
|
|
|
|||
|
|
@ -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[..])
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue