use std::{
collections::{btree_map::Entry, BTreeMap, VecDeque},
ffi::c_void,
io,
mem::{size_of_val, transmute},
os::windows::{
io::{AsRawHandle, RawHandle},
prelude::OwnedHandle,
},
ptr::{self, null_mut},
sync::{Arc, Mutex},
task::{Context, Poll},
time::Duration,
};
use log::{debug, error, warn};
use windows_sys::Win32::{
Devices::Usb::{
self, WinUsb_ControlTransfer, WinUsb_Free, WinUsb_GetAssociatedInterface,
WinUsb_Initialize, WinUsb_ReadPipe, WinUsb_ResetPipe, WinUsb_SetCurrentAlternateSetting,
WinUsb_SetPipePolicy, WinUsb_WritePipe, USB_DEVICE_DESCRIPTOR, WINUSB_INTERFACE_HANDLE,
WINUSB_SETUP_PACKET,
},
Foundation::{
GetLastError, ERROR_BAD_COMMAND, ERROR_DEVICE_NOT_CONNECTED, ERROR_FILE_NOT_FOUND,
ERROR_IO_PENDING, ERROR_NOT_FOUND, ERROR_NO_MORE_ITEMS, ERROR_NO_SUCH_DEVICE, FALSE,
HANDLE, TRUE,
},
System::IO::{CancelIoEx, OVERLAPPED},
};
use crate::{
bitset::EndpointBitSet,
descriptors::{
ConfigurationDescriptor, DeviceDescriptor, EndpointDescriptor, DESCRIPTOR_LEN_DEVICE,
DESCRIPTOR_TYPE_CONFIGURATION,
},
maybe_future::{blocking::Blocking, Ready},
transfer::{
internal::{
notify_completion, take_completed_from_queue, Idle, Notify, Pending, TransferFuture,
},
Buffer, Completion, ControlIn, ControlOut, Direction, Recipient, TransferError,
},
DeviceInfo, Error, ErrorKind, MaybeFuture, Speed,
};
use super::{
enumeration::{
find_usbccgp_child, get_driver_name, get_usbccgp_winusb_device_path, get_winusb_device_path,
},
hub::HubPort,
transfer::TransferData,
util::{create_file, raw_handle, WCStr},
DevInst,
};
pub(crate) struct WindowsDevice {
device_descriptor: DeviceDescriptor,
config_descriptors: Vec<Vec<u8>>,
active_config: u8,
speed: Option<Speed>,
devinst: DevInst,
handles: Mutex<BTreeMap<u8, WinusbFileHandle>>,
}
impl WindowsDevice {
pub(crate) fn from_device_info(
d: &DeviceInfo,
) -> impl MaybeFuture<Output = Result<Arc<WindowsDevice>, Error>> {
let instance_id = d.instance_id.clone();
let devinst = d.devinst;
Blocking::new(move || {
debug!("Creating device for {:?}", instance_id);
let hub_port = HubPort::by_child_devinst(devinst)?;
let connection_info = hub_port.get_info()?;
let device_descriptor = unsafe {
&transmute::<USB_DEVICE_DESCRIPTOR, [u8; DESCRIPTOR_LEN_DEVICE as usize]>(
connection_info.device_desc,
)
};
let device_descriptor = DeviceDescriptor::new(device_descriptor)
.ok_or_else(|| Error::new(ErrorKind::Other, "invalid device descriptor"))?;
let num_configurations = connection_info.device_desc.bNumConfigurations;
let config_descriptors = (0..num_configurations)
.flat_map(|i| {
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(Arc::new(WindowsDevice {
device_descriptor,
config_descriptors,
speed: connection_info.speed,
active_config: connection_info.active_config,
devinst,
handles: Mutex::new(BTreeMap::new()),
}))
})
}
pub(crate) fn device_descriptor(&self) -> DeviceDescriptor {
self.device_descriptor.clone()
}
pub(crate) fn speed(&self) -> Option<Speed> {
self.speed
}
pub(crate) fn active_configuration_value(&self) -> u8 {
self.active_config
}
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(
&self,
_configuration: u8,
) -> impl MaybeFuture<Output = Result<(), Error>> {
Ready(Err(Error::new(
ErrorKind::Unsupported,
"set_configuration not supported by WinUSB",
)))
}
pub(crate) fn get_descriptor(
self: Arc<Self>,
desc_type: u8,
desc_index: u8,
language_id: u16,
) -> impl MaybeFuture<Output = Result<Vec<u8>, TransferError>> {
Blocking::new(move || {
fn to_transfer_error(e: Error) -> TransferError {
match e.kind() {
ErrorKind::Disconnected => TransferError::Disconnected,
_ => TransferError::Unknown(e.os_error().unwrap_or(0)),
}
}
HubPort::by_child_devinst(self.devinst)
.map_err(to_transfer_error)?
.get_descriptor(desc_type, desc_index, language_id)
.map_err(to_transfer_error)
})
}
pub(crate) fn reset(&self) -> impl MaybeFuture<Output = Result<(), Error>> {
Ready(Err(Error::new(
ErrorKind::Unsupported,
"reset not supported by WinUSB",
)))
}
pub(crate) fn claim_interface(
self: Arc<Self>,
interface_number: u8,
) -> impl MaybeFuture<Output = Result<Arc<WindowsInterface>, Error>> {
Blocking::new(move || {
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 {
debug!("Device driver is {driver:?}, not WinUSB or USBCCGP");
Err(Error::new(
ErrorKind::Unsupported,
"incompatible driver is installed for this device",
))
}
})
}
pub(crate) fn detach_and_claim_interface(
self: Arc<Self>,
interface: u8,
) -> impl MaybeFuture<Output = Result<Arc<WindowsInterface>, Error>> {
self.claim_interface(interface)
}
}
struct BitSet256([u64; 4]);
impl BitSet256 {
fn new() -> Self {
Self([0; 4])
}
fn idx(bit: u8) -> usize {
(bit / 64) as usize
}
fn mask(bit: u8) -> u64 {
1u64 << (bit % 64)
}
fn is_set(&self, bit: u8) -> bool {
self.0[Self::idx(bit)] & Self::mask(bit) != 0
}
fn is_empty(&self) -> bool {
self.0 == [0; 4]
}
fn set(&mut self, bit: u8) {
self.0[Self::idx(bit)] |= Self::mask(bit)
}
fn clear(&mut self, bit: u8) {
self.0[Self::idx(bit)] &= !Self::mask(bit)
}
}
pub(crate) struct WinusbFileHandle {
first_interface: u8,
handle: OwnedHandle,
winusb_handle: WINUSB_INTERFACE_HANDLE,
claimed_interfaces: BitSet256,
}
unsafe impl Send for WinusbFileHandle {}
unsafe impl Sync for WinusbFileHandle {}
impl WinusbFileHandle {
fn new(path: &WCStr, first_interface: u8) -> Result<Self, Error> {
let handle = create_file(path)
.map_err(|e| Error::new_os(ErrorKind::Other, "failed to open device", e).log_debug())?;
super::events::register(&handle)?;
let winusb_handle = unsafe {
let mut h = ptr::null_mut();
if WinUsb_Initialize(raw_handle(&handle), &mut h) == FALSE {
return Err(Error::new_os(
ErrorKind::Other,
"failed to initialize WinUSB",
GetLastError(),
)
.log_debug());
}
h
};
debug!("Opened WinUSB handle for {path} (interface {first_interface})");
Ok(WinusbFileHandle {
first_interface,
handle,
winusb_handle,
claimed_interfaces: BitSet256::new(),
})
}
fn claim_interface(
&mut self,
device: &Arc<WindowsDevice>,
interface_number: u8,
) -> Result<Arc<WindowsInterface>, Error> {
assert!(interface_number >= self.first_interface);
if self.claimed_interfaces.is_set(interface_number) {
return Err(Error::new(ErrorKind::Busy, "interface is already claimed"));
}
let winusb_handle = if self.first_interface == interface_number {
self.winusb_handle
} else {
unsafe {
let mut out_handle = ptr::null_mut();
let idx = interface_number - self.first_interface - 1;
if WinUsb_GetAssociatedInterface(self.winusb_handle, idx, &mut out_handle) == FALSE
{
let err = GetLastError();
debug!(
"WinUsb_GetAssociatedInterface for interface {} using handle for {} failed: {:?}",
interface_number, self.first_interface, err
);
return Err(match err {
ERROR_NO_MORE_ITEMS => {
Error::new_os(ErrorKind::NotFound, "interface not found", err)
}
_ => Error::new_os(
ErrorKind::Other,
"failed to initialize WinUSB for associated interface",
err,
),
});
}
out_handle
}
};
log::debug!(
"Claiming interface {interface_number} using handle for {}",
self.first_interface
);
self.claimed_interfaces.set(interface_number);
Ok(Arc::new(WindowsInterface {
handle: self.handle.as_raw_handle(),
device: device.clone(),
interface_number,
first_interface_number: self.first_interface,
winusb_handle,
state: Mutex::new(InterfaceState::default()),
}))
}
}
impl Drop for WinusbFileHandle {
fn drop(&mut self) {
log::debug!(
"Closing WinUSB handle for interface {}",
self.first_interface
);
unsafe {
WinUsb_Free(self.winusb_handle);
}
}
}
pub(crate) struct WindowsInterface {
pub(crate) handle: RawHandle,
pub(crate) device: Arc<WindowsDevice>,
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,
endpoints: EndpointBitSet,
}
unsafe impl Send for WindowsInterface {}
unsafe impl Sync for WindowsInterface {}
impl Drop for WindowsInterface {
fn drop(&mut self) {
let is_first_interface = self.interface_number == self.first_interface_number;
if !is_first_interface {
log::debug!(
"Closing WinUSB handle for associated interface {}",
self.interface_number
);
unsafe {
WinUsb_Free(self.winusb_handle);
}
}
let mut handles = self.device.handles.lock().unwrap();
let Entry::Occupied(mut entry) = handles.entry(self.first_interface_number) else {
panic!("missing handle that should be open")
};
entry
.get_mut()
.claimed_interfaces
.clear(self.interface_number);
if entry.get().claimed_interfaces.is_empty() {
entry.remove();
} else if is_first_interface {
log::debug!(
"Released interface {}, but retaining handle for shared use",
self.interface_number
);
}
}
}
impl WindowsInterface {
pub fn control_in(
self: &Arc<Self>,
data: ControlIn,
timeout: Duration,
) -> impl MaybeFuture<Output = Result<Vec<u8>, TransferError>> {
let mut t = TransferData::new(0x80);
t.set_buffer(Buffer::new(data.length as usize));
let pkt = WINUSB_SETUP_PACKET {
RequestType: data.request_type(),
Request: data.request,
Value: data.value,
Index: data.index,
Length: data.length,
};
let intf = self.clone();
TransferFuture::new(t, |t| self.submit_control(t, pkt)).map(move |mut t| {
let c = t.take_completion(&intf);
c.status?;
Ok(c.buffer.into_vec())
})
}
pub fn control_out(
self: &Arc<Self>,
data: ControlOut,
timeout: Duration,
) -> impl MaybeFuture<Output = Result<(), TransferError>> {
let mut t = TransferData::new(0x00);
t.set_buffer(Buffer::from(data.data.to_vec()));
let pkt = WINUSB_SETUP_PACKET {
RequestType: data.request_type(),
Request: data.request,
Value: data.value,
Index: data.index,
Length: data.data.len().try_into().expect("transfer too large"),
};
let intf = self.clone();
TransferFuture::new(t, |t| self.submit_control(t, pkt)).map(move |mut t| {
let c = t.take_completion(&intf);
c.status
})
}
pub fn set_alt_setting(
self: Arc<Self>,
alt_setting: u8,
) -> impl MaybeFuture<Output = Result<(), Error>> {
Blocking::new(move || unsafe {
let mut state = self.state.lock().unwrap();
if !state.endpoints.is_empty() {
return Err(Error::new(
ErrorKind::Busy,
"can't change alternate setting while endpoints are in use",
));
}
let r = WinUsb_SetCurrentAlternateSetting(self.winusb_handle, alt_setting);
if r == TRUE {
debug!(
"Set interface {} alt setting to {alt_setting}",
self.interface_number
);
state.alt_setting = alt_setting;
Ok(())
} else {
Err(match GetLastError() {
e @ ERROR_NOT_FOUND => {
Error::new_os(ErrorKind::NotFound, "alternate setting not found", e)
}
e @ ERROR_BAD_COMMAND => {
Error::new_os(ErrorKind::Disconnected, "device disconnected", e)
}
e => Error::new_os(ErrorKind::Other, "failed to set alternate setting", e),
})
}
})
}
pub fn get_alt_setting(&self) -> u8 {
self.state.lock().unwrap().alt_setting
}
pub fn endpoint(
self: &Arc<Self>,
descriptor: EndpointDescriptor,
) -> Result<WindowsEndpoint, Error> {
let address = descriptor.address();
let max_packet_size = descriptor.max_packet_size();
let mut state = self.state.lock().unwrap();
if state.endpoints.is_set(address) {
return Err(Error::new(ErrorKind::Busy, "endpoint already in use"));
}
state.endpoints.set(address);
if Direction::from_address(address) == Direction::In {
unsafe {
let enable: u8 = 1;
let r = WinUsb_SetPipePolicy(
self.winusb_handle,
address,
Usb::RAW_IO,
size_of_val(&enable) as u32,
&enable as *const _ as *const c_void,
);
if r != TRUE {
let err = GetLastError();
warn!("Failed to enable RAW_IO on endpoint {address:02X}: error {err:x}",);
}
}
}
Ok(WindowsEndpoint {
inner: Arc::new(EndpointInner {
address,
interface: self.clone(),
notify: Notify::new(),
}),
max_packet_size,
pending: VecDeque::new(),
idle_transfer: None,
})
}
fn submit(&self, mut t: Idle<TransferData>) -> Pending<TransferData> {
let endpoint = t.endpoint;
let dir = Direction::from_address(endpoint);
let len = t.request_len;
let buf = t.buf;
t.overlapped.InternalHigh = 0;
t.error_from_submit = Ok(());
let t = t.pre_submit();
let ptr = t.as_ptr();
debug!("Submit transfer {ptr:?} on endpoint {endpoint:02X} for {len} bytes {dir:?}");
let r = unsafe {
match dir {
Direction::Out => WinUsb_WritePipe(
self.winusb_handle,
endpoint,
buf,
len,
null_mut(),
ptr as *mut OVERLAPPED,
),
Direction::In => WinUsb_ReadPipe(
self.winusb_handle,
endpoint,
buf,
len,
null_mut(),
ptr as *mut OVERLAPPED,
),
}
};
self.post_submit(r, t)
}
fn submit_control(
&self,
mut t: Idle<TransferData>,
pkt: WINUSB_SETUP_PACKET,
) -> Pending<TransferData> {
let endpoint = t.endpoint;
let dir = Direction::from_address(endpoint);
let len = t.request_len;
let buf = t.buf;
t.overlapped.InternalHigh = 0;
t.error_from_submit = Ok(());
if pkt.RequestType & 0x1f == Recipient::Interface as u8
&& pkt.Index as u8 != self.interface_number
{
warn!("WinUSB requires control transfer with `Recipient::Interface` to pass the interface number in `index`");
t.error_from_submit = Err(TransferError::InvalidArgument);
return t.simulate_complete();
}
let t = t.pre_submit();
let ptr = t.as_ptr();
debug!("Submit control {dir:?} transfer {ptr:?} for {len} bytes");
let r = unsafe {
WinUsb_ControlTransfer(
self.winusb_handle,
pkt,
buf,
len,
null_mut(),
ptr as *mut OVERLAPPED,
)
};
self.post_submit(r, t)
}
fn post_submit(&self, r: i32, t: Pending<TransferData>) -> Pending<TransferData> {
if r == TRUE {
error!("Transfer submit completed synchronously")
}
let err = unsafe { GetLastError() };
if err != ERROR_IO_PENDING {
error!("submit failed: {}", io::Error::from_raw_os_error(err as _));
unsafe {
(*t.as_ptr()).error_from_submit = match err {
ERROR_BAD_COMMAND
| ERROR_FILE_NOT_FOUND
| ERROR_DEVICE_NOT_CONNECTED
| ERROR_NO_SUCH_DEVICE => Err(TransferError::Disconnected),
other => Err(TransferError::Unknown(other)),
};
notify_completion::<TransferData>(t.as_ptr());
}
}
t
}
fn cancel(&self, t: &mut Pending<TransferData>) {
debug!("Cancelling transfer {:?}", t.as_ptr());
unsafe {
let r = CancelIoEx(self.handle as HANDLE, t.as_ptr() as *mut OVERLAPPED);
if r == 0 {
let err = GetLastError();
if err != ERROR_NOT_FOUND {
error!(
"CancelIoEx failed: {}",
io::Error::from_raw_os_error(err as i32)
);
}
}
}
}
}
pub(crate) struct WindowsEndpoint {
inner: Arc<EndpointInner>,
pub(crate) max_packet_size: usize,
pending: VecDeque<Pending<TransferData>>,
idle_transfer: Option<Idle<TransferData>>,
}
struct EndpointInner {
interface: Arc<WindowsInterface>,
address: u8,
notify: Notify,
}
impl WindowsEndpoint {
pub(crate) fn endpoint_address(&self) -> u8 {
self.inner.address
}
pub(crate) fn pending(&self) -> usize {
self.pending.len()
}
pub(crate) fn cancel_all(&mut self) {
for transfer in self.pending.iter_mut().rev() {
self.inner.interface.cancel(transfer);
}
}
fn make_transfer(&mut self, buffer: Buffer) -> Idle<TransferData> {
let mut t = self.idle_transfer.take().unwrap_or_else(|| {
Idle::new(self.inner.clone(), TransferData::new(self.inner.address))
});
t.set_buffer(buffer);
t
}
pub(crate) fn submit(&mut self, buffer: Buffer) {
let t = self.make_transfer(buffer);
let t = self.inner.interface.submit(t);
self.pending.push_back(t);
}
pub(crate) fn submit_err(&mut self, buffer: Buffer, err: TransferError) {
let mut t = self.make_transfer(buffer);
t.error_from_submit = Err(err);
self.pending.push_back(t.simulate_complete());
}
pub(crate) fn poll_next_complete(&mut self, cx: &mut Context) -> Poll<Completion> {
self.inner.notify.subscribe(cx);
if let Some(mut transfer) = take_completed_from_queue(&mut self.pending) {
let completion = transfer.take_completion(&self.inner.interface);
self.idle_transfer = Some(transfer);
Poll::Ready(completion)
} else {
Poll::Pending
}
}
pub(crate) fn wait_next_complete(&mut self, timeout: Duration) -> Option<Completion> {
self.inner.notify.wait_timeout(timeout, || {
take_completed_from_queue(&mut self.pending).map(|mut transfer| {
let completion = transfer.take_completion(&self.inner.interface);
self.idle_transfer = Some(transfer);
completion
})
})
}
pub(crate) fn clear_halt(&mut self) -> impl MaybeFuture<Output = Result<(), Error>> {
let inner = self.inner.clone();
Blocking::new(move || {
let endpoint = inner.address;
debug!("Clear halt, endpoint {endpoint:02x}");
unsafe {
if WinUsb_ResetPipe(inner.interface.winusb_handle, endpoint) == TRUE {
Ok(())
} else {
Err(match GetLastError() {
e => Error::new_os(ErrorKind::Other, "failed to clear halt", e),
})
}
}
})
}
}
impl Drop for WindowsEndpoint {
fn drop(&mut self) {
if !self.pending.is_empty() {
debug!(
"Dropping endpoint {:02x} with {} pending transfers",
self.inner.address,
self.pending.len()
);
self.cancel_all();
}
}
}
impl AsRef<Notify> for EndpointInner {
fn as_ref(&self) -> &Notify {
&self.notify
}
}
impl Drop for EndpointInner {
fn drop(&mut self) {
let mut state = self.interface.state.lock().unwrap();
state.endpoints.clear(self.address);
}
}