diff --git a/src/device.rs b/src/device.rs index 6dd478a..8377703 100644 --- a/src/device.rs +++ b/src/device.rs @@ -391,6 +391,19 @@ impl Interface { self.backend.clone().set_alt_setting(alt_setting) } + /// Clear a halt / stall condition on the given endpoint and reset the + /// host-side data toggle. + /// + /// Use this after receiving + /// [`TransferError::Stall`][crate::transfer::TransferError::Stall] to clear + /// the error and resume use of the endpoint. + /// + /// Unlike [`Endpoint::clear_halt`], this operates directly by endpoint + /// address without requiring an open [`Endpoint`]. + pub fn clear_halt(&self, endpoint: u8) -> impl MaybeFuture> { + self.backend.clone().clear_halt(endpoint) + } + /// Get the current alternate setting of this interface. pub fn get_alt_setting(&self) -> u8 { self.backend.get_alt_setting() diff --git a/src/platform/linux_usbfs/device.rs b/src/platform/linux_usbfs/device.rs index 3e6640a..b7210a1 100644 --- a/src/platform/linux_usbfs/device.rs +++ b/src/platform/linux_usbfs/device.rs @@ -757,6 +757,16 @@ impl LinuxInterface { }) } + pub fn clear_halt(self: Arc, endpoint: u8) -> impl MaybeFuture> { + Blocking::new(move || { + debug!("Clear halt, endpoint {endpoint:02x}"); + usbfs::clear_halt(&self.device.fd, endpoint).map_err(|e| match e { + Errno::NODEV => Error::new_os(ErrorKind::Disconnected, "device disconnected", e), + _ => Error::new_os(ErrorKind::Other, "failed to clear halt", e), + }) + }) + } + pub fn endpoint( self: &Arc, descriptor: EndpointDescriptor, diff --git a/src/platform/macos_iokit/device.rs b/src/platform/macos_iokit/device.rs index 9f20f39..e70dc75 100644 --- a/src/platform/macos_iokit/device.rs +++ b/src/platform/macos_iokit/device.rs @@ -422,6 +422,23 @@ impl MacInterface { }) } + pub fn clear_halt(self: Arc, endpoint: u8) -> impl MaybeFuture> { + Blocking::new(move || { + debug!("Clear halt, endpoint {endpoint:02x}"); + let pipe_ref = self.interface.find_pipe_ref(endpoint).ok_or_else(|| { + Error::new(ErrorKind::NotFound, "endpoint not found on interface") + })?; + self.interface + .clear_pipe_stall_both_ends(pipe_ref) + .map_err(|e| match e { + io_kit_sys::ret::kIOReturnNoDevice => { + Error::new_os(ErrorKind::Disconnected, "device disconnected", e) + } + _ => Error::new_os(ErrorKind::Other, "failed to clear halt on endpoint", e), + }) + }) + } + pub fn get_alt_setting(&self) -> u8 { self.state.lock().unwrap().alt_setting } diff --git a/src/platform/windows_winusb/device.rs b/src/platform/windows_winusb/device.rs index fd5b79d..9677d11 100644 --- a/src/platform/windows_winusb/device.rs +++ b/src/platform/windows_winusb/device.rs @@ -508,6 +508,21 @@ impl WindowsInterface { }) } + pub fn clear_halt(self: Arc, endpoint: u8) -> impl MaybeFuture> { + Blocking::new(move || { + debug!("Clear halt, endpoint {endpoint:02x}"); + unsafe { + if WinUsb_ResetPipe(self.winusb_handle, endpoint) == TRUE { + Ok(()) + } else { + Err(match GetLastError() { + e => Error::new_os(ErrorKind::Other, "failed to clear halt", e), + }) + } + } + }) + } + pub fn get_alt_setting(&self) -> u8 { self.state.lock().unwrap().alt_setting }