use crate::{
descriptors::{
decode_string_descriptor, validate_string_descriptor, ConfigurationDescriptor,
DeviceDescriptor, InterfaceDescriptor, DESCRIPTOR_TYPE_STRING,
},
io::{EndpointRead, EndpointWrite},
platform,
transfer::{
Buffer, BulkOrInterrupt, Completion, ControlIn, ControlOut, Direction, EndpointDirection,
EndpointType, In, Out, TransferError,
},
ActiveConfigurationError, DeviceInfo, Error, ErrorKind, GetDescriptorError, MaybeFuture, Speed,
};
use log::{error, warn};
use std::{
fmt::Debug,
future::{poll_fn, Future},
marker::PhantomData,
num::NonZeroU8,
sync::Arc,
task::{Context, Poll},
time::Duration,
};
#[derive(Clone)]
pub struct Device {
backend: Arc<crate::platform::Device>,
}
impl Device {
pub(crate) fn wrap(backend: Arc<platform::Device>) -> Device {
Device { backend }
}
pub(crate) fn open(d: &DeviceInfo) -> impl MaybeFuture<Output = Result<Device, Error>> {
platform::Device::from_device_info(d).map(|d| d.map(Device::wrap))
}
#[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).map(|d| d.map(Device::wrap))
}
pub fn claim_interface(
&self,
interface: u8,
) -> impl MaybeFuture<Output = Result<Interface, Error>> {
self.backend
.clone()
.claim_interface(interface)
.map(|i| i.map(Interface::wrap))
}
pub fn detach_and_claim_interface(
&self,
interface: u8,
) -> impl MaybeFuture<Output = Result<Interface, Error>> {
self.backend
.clone()
.detach_and_claim_interface(interface)
.map(|i| i.map(Interface::wrap))
}
pub fn detach_kernel_driver(&self, interface: u8) -> Result<(), Error> {
#[cfg(target_os = "linux")]
self.backend.detach_kernel_driver(interface)?;
let _ = interface;
Ok(())
}
pub fn attach_kernel_driver(&self, interface: u8) -> Result<(), Error> {
#[cfg(target_os = "linux")]
self.backend.attach_kernel_driver(interface)?;
let _ = interface;
Ok(())
}
pub fn device_descriptor(&self) -> DeviceDescriptor {
self.backend.device_descriptor()
}
pub fn speed(&self) -> Option<Speed> {
self.backend.speed()
}
pub fn active_configuration(
&self,
) -> Result<ConfigurationDescriptor<'_>, ActiveConfigurationError> {
let active = self.backend.active_configuration_value();
self.configurations()
.find(|c| c.configuration_value() == active)
.ok_or(ActiveConfigurationError {
configuration_value: active,
})
}
pub fn configurations(&self) -> impl Iterator<Item = ConfigurationDescriptor<'_>> {
self.backend.configuration_descriptors()
}
pub fn set_configuration(
&self,
configuration: u8,
) -> impl MaybeFuture<Output = Result<(), Error>> {
self.backend.clone().set_configuration(configuration)
}
pub fn get_descriptor(
&self,
desc_type: u8,
desc_index: u8,
language_id: u16,
timeout: Duration,
) -> impl MaybeFuture<Output = Result<Vec<u8>, GetDescriptorError>> {
#[cfg(target_os = "windows")]
{
let _ = timeout;
self.backend
.clone()
.get_descriptor(desc_type, desc_index, language_id)
.map(|r| r.map_err(GetDescriptorError::Transfer))
}
#[cfg(not(target_os = "windows"))]
{
const STANDARD_REQUEST_GET_DESCRIPTOR: u8 = 0x06;
use crate::transfer::{ControlType, Recipient};
self.control_in(
ControlIn {
control_type: ControlType::Standard,
recipient: Recipient::Device,
request: STANDARD_REQUEST_GET_DESCRIPTOR,
value: ((desc_type as u16) << 8) | desc_index as u16,
index: language_id,
length: 4096,
},
timeout,
)
.map(|r| r.map_err(GetDescriptorError::Transfer))
}
}
pub fn get_string_descriptor_supported_languages(
&self,
timeout: Duration,
) -> impl MaybeFuture<Output = Result<impl Iterator<Item = u16>, GetDescriptorError>> {
self.get_descriptor(DESCRIPTOR_TYPE_STRING, 0, 0, timeout)
.map(move |r| {
let data = r?;
if !validate_string_descriptor(&data) {
error!("String descriptor language list read {data:?}, not a valid string descriptor");
return Err(GetDescriptorError::InvalidDescriptor)
}
let mut iter = data.into_iter().skip(2);
Ok(std::iter::from_fn(move || {
Some(u16::from_le_bytes([iter.next()?, iter.next()?]))
}))
})
}
pub fn get_string_descriptor(
&self,
desc_index: NonZeroU8,
language_id: u16,
timeout: Duration,
) -> impl MaybeFuture<Output = Result<String, GetDescriptorError>> {
self.get_descriptor(
DESCRIPTOR_TYPE_STRING,
desc_index.get(),
language_id,
timeout,
)
.map(|r| {
let data = r?;
decode_string_descriptor(&data).map_err(|_| GetDescriptorError::InvalidDescriptor)
})
}
pub fn reset(&self) -> impl MaybeFuture<Output = Result<(), Error>> {
self.backend.clone().reset()
}
#[cfg(any(target_os = "linux", target_os = "macos", target_os = "android"))]
pub fn control_in(
&self,
data: ControlIn,
timeout: Duration,
) -> impl MaybeFuture<Output = Result<Vec<u8>, TransferError>> {
self.backend.clone().control_in(data, timeout)
}
#[cfg(any(target_os = "linux", target_os = "macos", target_os = "android"))]
pub fn control_out(
&self,
data: ControlOut,
timeout: Duration,
) -> impl MaybeFuture<Output = Result<(), TransferError>> {
self.backend.clone().control_out(data, timeout)
}
}
impl Debug for Device {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Device").finish()
}
}
#[derive(Clone)]
pub struct Interface {
backend: Arc<platform::Interface>,
}
impl Interface {
pub(crate) fn wrap(backend: Arc<platform::Interface>) -> Self {
Interface { backend }
}
pub fn set_alt_setting(&self, alt_setting: u8) -> impl MaybeFuture<Output = Result<(), Error>> {
self.backend.clone().set_alt_setting(alt_setting)
}
pub fn get_alt_setting(&self) -> u8 {
self.backend.get_alt_setting()
}
pub fn control_in(
&self,
data: ControlIn,
timeout: Duration,
) -> impl MaybeFuture<Output = Result<Vec<u8>, TransferError>> {
self.backend.clone().control_in(data, timeout)
}
pub fn control_out(
&self,
data: ControlOut,
timeout: Duration,
) -> impl MaybeFuture<Output = Result<(), TransferError>> {
self.backend.clone().control_out(data, timeout)
}
pub fn interface_number(&self) -> u8 {
self.backend.interface_number
}
pub fn descriptors(&self) -> impl Iterator<Item = InterfaceDescriptor<'_>> {
let active = self.backend.device.active_configuration_value();
let configuration = self
.backend
.device
.configuration_descriptors()
.find(|c| c.configuration_value() == active);
configuration
.into_iter()
.flat_map(|i| i.interface_alt_settings())
.filter(|g| g.interface_number() == self.backend.interface_number)
}
pub fn descriptor(&self) -> Option<InterfaceDescriptor<'_>> {
self.descriptors()
.find(|i| i.alternate_setting() == self.get_alt_setting())
}
pub fn endpoint<EpType: EndpointType, Dir: EndpointDirection>(
&self,
address: u8,
) -> Result<Endpoint<EpType, Dir>, Error> {
let intf_desc = self.descriptor();
let ep_desc =
intf_desc.and_then(|desc| desc.endpoints().find(|ep| ep.address() == address));
let Some(ep_desc) = ep_desc else {
return Err(Error::new(
ErrorKind::NotFound,
"specified endpoint does not exist on this interface",
));
};
if address & Direction::MASK != Dir::DIR as u8 {
return Err(Error::new(ErrorKind::Other, "incorrect endpoint direction"));
}
if ep_desc.transfer_type() != EpType::TYPE {
return Err(Error::new(ErrorKind::Other, "incorrect endpoint type"));
}
let backend = self.backend.endpoint(ep_desc)?;
Ok(Endpoint {
backend,
ep_type: PhantomData,
ep_dir: PhantomData,
})
}
}
impl Debug for Interface {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Interface")
.field("number", &self.backend.interface_number)
.finish()
}
}
pub struct Endpoint<EpType, Dir> {
backend: platform::Endpoint,
ep_type: PhantomData<EpType>,
ep_dir: PhantomData<Dir>,
}
impl<EpType: EndpointType, Dir: EndpointDirection> Endpoint<EpType, Dir> {
pub fn endpoint_address(&self) -> u8 {
self.backend.endpoint_address()
}
pub fn max_packet_size(&self) -> usize {
self.backend.max_packet_size
}
pub fn pending(&self) -> usize {
self.backend.pending()
}
pub fn cancel_all(&mut self) {
self.backend.cancel_all()
}
}
impl<EpType: BulkOrInterrupt> Endpoint<EpType, Out> {
pub fn writer(self, buffer_size: usize) -> EndpointWrite<EpType> {
EndpointWrite::new(self, buffer_size)
}
}
impl<EpType: BulkOrInterrupt> Endpoint<EpType, In> {
pub fn reader(self, buffer_size: usize) -> EndpointRead<EpType> {
EndpointRead::new(self, buffer_size)
}
}
impl<EpType: BulkOrInterrupt, Dir: EndpointDirection> Endpoint<EpType, Dir> {
pub fn allocate(&self, len: usize) -> Buffer {
#[cfg(any(target_os = "linux", target_os = "android"))]
{
if let Ok(b) = self.backend.allocate(len) {
return b;
}
}
Buffer::new(len)
}
pub fn submit(&mut self, buf: Buffer) {
if Dir::DIR == Direction::In {
let req_len = buf.requested_len();
if req_len == 0 || req_len % self.max_packet_size() != 0 {
warn!(
"Submitting transfer with length {req_len} which is not a multiple of max packet size {} on IN endpoint {:02x}",
self.max_packet_size(),
self.endpoint_address(),
);
return self.backend.submit_err(buf, TransferError::InvalidArgument);
}
}
self.backend.submit(buf)
}
pub fn next_complete(&mut self) -> impl Future<Output = Completion> + Send + Sync + '_ {
poll_fn(|cx| self.poll_next_complete(cx))
}
pub fn poll_next_complete(&mut self, cx: &mut Context<'_>) -> Poll<Completion> {
self.backend.poll_next_complete(cx)
}
pub fn wait_next_complete(&mut self, timeout: Duration) -> Option<Completion> {
self.backend.wait_next_complete(timeout)
}
pub fn transfer_blocking(&mut self, buf: Buffer, timeout: Duration) -> Completion {
assert!(self.pending() == 0, "a transfer is already pending");
self.submit(buf);
if let Some(completion) = self.wait_next_complete(timeout) {
return completion;
}
self.cancel_all();
loop {
if let Some(completion) = self.wait_next_complete(Duration::from_secs(1)) {
return completion;
}
log::warn!("cancelled transfer due to timeout, but it has not yet returned");
}
}
pub fn clear_halt(&mut self) -> impl MaybeFuture<Output = Result<(), Error>> {
self.backend.clear_halt()
}
}
impl<EpType: BulkOrInterrupt, Dir: EndpointDirection> Debug for Endpoint<EpType, Dir> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Endpoint")
.field(
"address",
&format_args!("0x{:02x}", self.endpoint_address()),
)
.field("type", &EpType::TYPE)
.field("direction", &Dir::DIR)
.finish()
}
}
#[test]
fn assert_send_sync() {
use crate::transfer::{Bulk, In, Interrupt, Out};
fn require_send_sync<T: Send + Sync>() {}
require_send_sync::<Interface>();
require_send_sync::<Device>();
require_send_sync::<Endpoint<Bulk, In>>();
require_send_sync::<Endpoint<Bulk, Out>>();
require_send_sync::<Endpoint<Interrupt, In>>();
require_send_sync::<Endpoint<Interrupt, Out>>();
}