linux: refactor device initial get_configuration
This commit is contained in:
parent
f1f4bec4a1
commit
592f57a3e0
1 changed files with 65 additions and 76 deletions
|
|
@ -80,11 +80,10 @@ impl LinuxDevice {
|
|||
let sysfs_path = d.path.clone();
|
||||
|
||||
Blocking::new(move || {
|
||||
let active_config = sysfs_path.read_attr("bConfigurationValue")?;
|
||||
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}"))?;
|
||||
Self::create_inner(fd, Some(sysfs_path), Some(active_config))
|
||||
Self::create_inner(fd, Some(sysfs_path))
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -93,23 +92,15 @@ impl LinuxDevice {
|
|||
) -> 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)
|
||||
Self::create_inner(fd, None)
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn create_inner(
|
||||
fd: OwnedFd,
|
||||
sysfs: Option<SysfsPath>,
|
||||
active_config: Option<u8>,
|
||||
) -> 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
|
||||
file.seek(std::io::SeekFrom::Start(0))?;
|
||||
let mut buf = Vec::new();
|
||||
file.read_to_end(&mut buf)?;
|
||||
buf
|
||||
};
|
||||
let descriptors = read_all_from_fd(&fd)?;
|
||||
|
||||
let Some(_) = DeviceDescriptor::new(&descriptors) else {
|
||||
return Err(Error::new(
|
||||
|
|
@ -118,10 +109,23 @@ impl LinuxDevice {
|
|||
));
|
||||
};
|
||||
|
||||
let active_config = if let Some(active_config) = active_config {
|
||||
active_config
|
||||
let active_config: u8 = if let Some(sysfs) = sysfs.as_ref() {
|
||||
sysfs.read_attr("bConfigurationValue").inspect_err(|e| {
|
||||
warn!("failed to read sysfs bConfigurationValue: {e}");
|
||||
})?
|
||||
} else {
|
||||
Self::get_config(&descriptors, &fd)?
|
||||
request_configuration(&fd).unwrap_or_else(|()| {
|
||||
let mut config_descriptors = parse_concatenated_config_descriptors(
|
||||
&descriptors[DESCRIPTOR_LEN_DEVICE as usize..],
|
||||
);
|
||||
|
||||
if let Some(config) = config_descriptors.next() {
|
||||
config.configuration_value()
|
||||
} else {
|
||||
error!("no configurations for device fd {}", fd.as_raw_fd());
|
||||
0
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
let timerfd = timerfd_create(
|
||||
|
|
@ -467,67 +471,6 @@ impl LinuxDevice {
|
|||
}
|
||||
}
|
||||
|
||||
fn get_config(descriptors: &[u8], fd: &OwnedFd) -> Result<u8, Error> {
|
||||
const REQUEST_GET_CONFIGURATION: u8 = 0x08;
|
||||
|
||||
let mut dst = [0u8; 1];
|
||||
let r = usbfs::control(
|
||||
fd,
|
||||
usbfs::CtrlTransfer {
|
||||
bRequestType: request_type(Direction::In, ControlType::Standard, Recipient::Device),
|
||||
bRequest: REQUEST_GET_CONFIGURATION,
|
||||
wValue: 0,
|
||||
wIndex: 0,
|
||||
wLength: dst.len() as u16,
|
||||
timeout: Duration::from_millis(50)
|
||||
.as_millis()
|
||||
.try_into()
|
||||
.expect("timeout must fit in u32 ms"),
|
||||
data: &mut dst[0] as *mut u8 as *mut c_void,
|
||||
},
|
||||
);
|
||||
|
||||
match r {
|
||||
Ok(n) => {
|
||||
if n == dst.len() {
|
||||
let active_config = dst[0];
|
||||
debug!("Obtained active configuration for fd {} from GET_CONFIGURATION request: {active_config}", fd.as_raw_fd());
|
||||
return Ok(active_config);
|
||||
} else {
|
||||
warn!("GET_CONFIGURATION request returned incorrect length: {n}, expected 1",);
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
warn!(
|
||||
"GET_CONFIGURATION request failed: {:?}",
|
||||
errno_to_transfer_error(e)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if descriptors.len() < DESCRIPTOR_LEN_DEVICE as usize {
|
||||
warn!(
|
||||
"Descriptors for device fd {} too short to use fallback configuration",
|
||||
fd.as_raw_fd()
|
||||
);
|
||||
return Err(ErrorKind::Other.into());
|
||||
}
|
||||
|
||||
// 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..]);
|
||||
if let Some(config) = descriptors.next() {
|
||||
return Ok(config.configuration_value());
|
||||
}
|
||||
|
||||
error!(
|
||||
"No available configurations for device fd {}",
|
||||
fd.as_raw_fd()
|
||||
);
|
||||
Err(ErrorKind::Other.into())
|
||||
}
|
||||
|
||||
pub(crate) fn speed(&self) -> Option<Speed> {
|
||||
usbfs::get_speed(&self.fd)
|
||||
.inspect_err(|e| log::error!("USBDEVFS_GET_SPEED failed: {e}"))
|
||||
|
|
@ -544,6 +487,52 @@ impl LinuxDevice {
|
|||
}
|
||||
}
|
||||
|
||||
fn read_all_from_fd(fd: &OwnedFd) -> Result<Vec<u8>, std::io::Error> {
|
||||
let mut file = unsafe { ManuallyDrop::new(File::from_raw_fd(fd.as_raw_fd())) };
|
||||
file.seek(std::io::SeekFrom::Start(0))?;
|
||||
let mut buf = Vec::new();
|
||||
file.read_to_end(&mut buf)?;
|
||||
Ok(buf)
|
||||
}
|
||||
|
||||
/// Get the active configuration with a blocking request to the device.
|
||||
fn request_configuration(fd: &OwnedFd) -> Result<u8, ()> {
|
||||
const REQUEST_GET_CONFIGURATION: u8 = 0x08;
|
||||
|
||||
let mut dst = [0u8; 1];
|
||||
let r = usbfs::control(
|
||||
fd,
|
||||
usbfs::CtrlTransfer {
|
||||
bRequestType: request_type(Direction::In, ControlType::Standard, Recipient::Device),
|
||||
bRequest: REQUEST_GET_CONFIGURATION,
|
||||
wValue: 0,
|
||||
wIndex: 0,
|
||||
wLength: dst.len() as u16,
|
||||
timeout: 50,
|
||||
data: &mut dst[0] as *mut u8 as *mut c_void,
|
||||
},
|
||||
);
|
||||
|
||||
match r {
|
||||
Ok(1) => {
|
||||
let active_config = dst[0];
|
||||
debug!("Obtained active configuration for fd {} from GET_CONFIGURATION request: {active_config}", fd.as_raw_fd());
|
||||
return Ok(active_config);
|
||||
}
|
||||
Ok(n) => {
|
||||
warn!("GET_CONFIGURATION request returned unexpected length: {n}, expected 1");
|
||||
Err(())
|
||||
}
|
||||
Err(e) => {
|
||||
warn!(
|
||||
"GET_CONFIGURATION request failed: {:?}",
|
||||
errno_to_transfer_error(e)
|
||||
);
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for LinuxDevice {
|
||||
fn drop(&mut self) {
|
||||
debug!("Closing device {}", self.events_id);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue