Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,5 +33,8 @@ core-foundation = "0.9.3"
core-foundation-sys = "0.8.4"
io-kit-sys = "0.4.0"

[target.'cfg(any(target_os="linux", target_os="android", target_os="windows", target_os="macos"))'.dependencies]
blocking ="1.6.1"

[lints.rust]
unexpected_cfgs = { level = "warn", check-cfg = ['cfg(fuzzing)'] }
10 changes: 7 additions & 3 deletions examples/blocking.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,21 @@
use std::time::Duration;

use nusb::transfer::{Control, ControlType, Recipient};
use nusb::{
transfer::{Control, ControlType, Recipient},
MaybeFuture,
};

fn main() {
env_logger::init();
let di = nusb::list_devices()
.wait()
.unwrap()
.find(|d| d.vendor_id() == 0x59e3 && d.product_id() == 0x0a23)
.expect("device should be connected");

println!("Device info: {di:?}");

let device = di.open().unwrap();
let device = di.open().wait().unwrap();

// Linux can make control transfers without claiming an interface
#[cfg(any(target_os = "linux", target_os = "macos"))]
Expand Down Expand Up @@ -49,7 +53,7 @@ fn main() {
}

// but we also provide an API on the `Interface` to support Windows
let interface = device.claim_interface(0).unwrap();
let interface = device.claim_interface(0).wait().unwrap();

let result = interface.control_out_blocking(
Control {
Expand Down
7 changes: 4 additions & 3 deletions examples/bulk.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
use futures_lite::future::block_on;
use nusb::transfer::RequestBuffer;
use nusb::{transfer::RequestBuffer, MaybeFuture};

fn main() {
env_logger::init();
let di = nusb::list_devices()
.wait()
.unwrap()
.find(|d| d.vendor_id() == 0x59e3 && d.product_id() == 0x0a23)
.expect("device should be connected");

println!("Device info: {di:?}");

let device = di.open().unwrap();
let interface = device.claim_interface(0).unwrap();
let device = di.open().wait().unwrap();
let interface = device.claim_interface(0).wait().unwrap();

block_on(interface.bulk_out(0x02, Vec::from([1, 2, 3, 4, 5])))
.into_result()
Expand Down
4 changes: 3 additions & 1 deletion examples/buses.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use nusb::MaybeFuture;

fn main() {
env_logger::init();
for dev in nusb::list_buses().unwrap() {
for dev in nusb::list_buses().wait().unwrap() {
println!("{:#?}", dev);
}
}
10 changes: 7 additions & 3 deletions examples/control.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
use futures_lite::future::block_on;
use nusb::transfer::{ControlIn, ControlOut, ControlType, Recipient};
use nusb::{
transfer::{ControlIn, ControlOut, ControlType, Recipient},
MaybeFuture,
};

fn main() {
env_logger::init();
let di = nusb::list_devices()
.wait()
.unwrap()
.find(|d| d.vendor_id() == 0x59e3 && d.product_id() == 0x0a23)
.expect("device should be connected");

println!("Device info: {di:?}");

let device = di.open().unwrap();
let device = di.open().wait().unwrap();

// Linux can make control transfers without claiming an interface
#[cfg(any(target_os = "linux", target_os = "macos"))]
Expand All @@ -37,7 +41,7 @@ fn main() {
}

// but we also provide an API on the `Interface` to support Windows
let interface = device.claim_interface(0).unwrap();
let interface = device.claim_interface(0).wait().unwrap();

let result = block_on(interface.control_out(ControlOut {
control_type: ControlType::Vendor,
Expand Down
6 changes: 3 additions & 3 deletions examples/descriptors.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use nusb::DeviceInfo;
use nusb::{DeviceInfo, MaybeFuture};

fn main() {
env_logger::init();
for dev in nusb::list_devices().unwrap() {
for dev in nusb::list_devices().wait().unwrap() {
inspect_device(dev);
}
}
Expand All @@ -17,7 +17,7 @@ fn inspect_device(dev: DeviceInfo) {
dev.manufacturer_string().unwrap_or(""),
dev.product_string().unwrap_or("")
);
let dev = match dev.open() {
let dev = match dev.open().wait() {
Ok(dev) => dev,
Err(e) => {
println!("Failed to open device: {}", e);
Expand Down
5 changes: 4 additions & 1 deletion examples/detach.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
//! Detach the kernel driver for an FTDI device and then reattach it.
use std::{thread::sleep, time::Duration};

use nusb::MaybeFuture;
fn main() {
env_logger::init();
let di = nusb::list_devices()
.wait()
.unwrap()
.find(|d| d.vendor_id() == 0x0403 && d.product_id() == 0x6001)
.expect("device should be connected");

let device = di.open().unwrap();
let device = di.open().wait().unwrap();
device.detach_kernel_driver(0).unwrap();
sleep(Duration::from_secs(10));
device.attach_kernel_driver(0).unwrap();
Expand Down
7 changes: 5 additions & 2 deletions examples/detach_claim.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
//! Detach the kernel driver for an FTDI device, claim the USB interface, and
//! then reattach it.
use std::{thread::sleep, time::Duration};

use nusb::MaybeFuture;
fn main() {
env_logger::init();
let di = nusb::list_devices()
.wait()
.unwrap()
.find(|d| d.vendor_id() == 0x0403 && d.product_id() == 0x6010)
.expect("device should be connected");

let device = di.open().unwrap();
let interface = device.detach_and_claim_interface(0).unwrap();
let device = di.open().wait().unwrap();
let interface = device.detach_and_claim_interface(0).wait().unwrap();
sleep(Duration::from_secs(1));
drop(interface);
}
4 changes: 3 additions & 1 deletion examples/list.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use nusb::MaybeFuture;

fn main() {
env_logger::init();
for dev in nusb::list_devices().unwrap() {
for dev in nusb::list_devices().wait().unwrap() {
println!("{:#?}", dev);
}
}
6 changes: 3 additions & 3 deletions examples/string_descriptors.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
use std::time::Duration;

use nusb::{descriptors::language_id::US_ENGLISH, DeviceInfo};
use nusb::{descriptors::language_id::US_ENGLISH, DeviceInfo, MaybeFuture};

fn main() {
env_logger::init();
for dev in nusb::list_devices().unwrap() {
for dev in nusb::list_devices().wait().unwrap() {
inspect_device(dev);
}
}
Expand All @@ -19,7 +19,7 @@ fn inspect_device(dev: DeviceInfo) {
dev.manufacturer_string().unwrap_or(""),
dev.product_string().unwrap_or("")
);
let dev = match dev.open() {
let dev = match dev.open().wait() {
Ok(dev) => dev,
Err(e) => {
println!("Failed to open device: {}", e);
Expand Down
87 changes: 52 additions & 35 deletions src/device.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use crate::{
Control, ControlIn, ControlOut, EndpointType, Queue, RequestBuffer, TransferError,
TransferFuture,
},
DeviceInfo, Error, Speed,
DeviceInfo, Error, MaybeFuture, Speed,
};
use log::error;
use std::{io::ErrorKind, sync::Arc, time::Duration};
Expand All @@ -18,12 +18,12 @@ use std::{io::ErrorKind, sync::Arc, time::Duration};
/// Obtain a `Device` by calling [`DeviceInfo::open`]:
///
/// ```no_run
/// use nusb;
/// let device_info = nusb::list_devices().unwrap()
/// use nusb::{self, MaybeFuture};
/// let device_info = nusb::list_devices().wait().unwrap()
/// .find(|dev| dev.vendor_id() == 0xAAAA && dev.product_id() == 0xBBBB)
/// .expect("device not connected");
///
/// let device = device_info.open().expect("failed to open device");
/// let device = device_info.open().wait().expect("failed to open device");
/// let interface = device.claim_interface(0);
/// ```
///
Expand All @@ -39,33 +39,40 @@ pub struct Device {
}

impl Device {
pub(crate) fn open(d: &DeviceInfo) -> Result<Device, std::io::Error> {
let backend = platform::Device::from_device_info(d)?;
Ok(Device { backend })
pub(crate) fn wrap(backend: Arc<platform::Device>) -> Device {
Device { backend }
}

pub(crate) fn open(
d: &DeviceInfo,
) -> impl MaybeFuture<Output = Result<Device, std::io::Error>> {
platform::Device::from_device_info(d)
}

/// Wraps a device that is already open.
#[cfg(any(target_os = "android", target_os = "linux"))]
pub fn from_fd(fd: std::os::fd::OwnedFd) -> Result<Device, Error> {
Ok(Device {
backend: platform::Device::from_fd(fd)?,
})
pub fn from_fd(fd: std::os::fd::OwnedFd) -> impl MaybeFuture<Output = Result<Device, Error>> {
platform::Device::from_fd(fd)
}

/// Open an interface of the device and claim it for exclusive use.
pub fn claim_interface(&self, interface: u8) -> Result<Interface, Error> {
let backend = self.backend.claim_interface(interface)?;
Ok(Interface { backend })
pub fn claim_interface(
&self,
interface: u8,
) -> impl MaybeFuture<Output = Result<Interface, Error>> {
self.backend.clone().claim_interface(interface)
}

/// Detach kernel drivers and open an interface of the device and claim it for exclusive use.
///
/// ### Platform notes
/// This function can only detach kernel drivers on Linux. Calling on other platforms has
/// the same effect as [`claim_interface`][`Device::claim_interface`].
pub fn detach_and_claim_interface(&self, interface: u8) -> Result<Interface, Error> {
let backend = self.backend.detach_and_claim_interface(interface)?;
Ok(Interface { backend })
pub fn detach_and_claim_interface(
&self,
interface: u8,
) -> impl MaybeFuture<Output = Result<Interface, Error>> {
self.backend.clone().detach_and_claim_interface(interface)
}

/// Detach kernel drivers for the specified interface.
Expand Down Expand Up @@ -138,8 +145,11 @@ impl Device {
///
/// ### Platform-specific notes
/// * Not supported on Windows
pub fn set_configuration(&self, configuration: u8) -> Result<(), Error> {
self.backend.set_configuration(configuration)
pub fn set_configuration(
&self,
configuration: u8,
) -> impl MaybeFuture<Output = Result<(), Error>> {
self.backend.clone().set_configuration(configuration)
}

/// Request a descriptor from the device.
Expand Down Expand Up @@ -248,8 +258,8 @@ impl Device {
///
/// ### Platform-specific notes
/// * Not supported on Windows
pub fn reset(&self) -> Result<(), Error> {
self.backend.reset()
pub fn reset(&self) -> impl MaybeFuture<Output = Result<(), Error>> {
self.backend.clone().reset()
}

/// Synchronously perform a single **IN (device-to-host)** transfer on the default **control** endpoint.
Expand Down Expand Up @@ -295,9 +305,10 @@ impl Device {
/// ```no_run
/// use futures_lite::future::block_on;
/// use nusb::transfer::{ ControlIn, ControlType, Recipient };
/// # use nusb::MaybeFuture;
/// # fn main() -> Result<(), std::io::Error> {
/// # let di = nusb::list_devices().unwrap().next().unwrap();
/// # let device = di.open().unwrap();
/// # let di = nusb::list_devices().wait().unwrap().next().unwrap();
/// # let device = di.open().wait().unwrap();
///
/// let data: Vec<u8> = block_on(device.control_in(ControlIn {
/// control_type: ControlType::Vendor,
Expand Down Expand Up @@ -328,9 +339,10 @@ impl Device {
/// ```no_run
/// use futures_lite::future::block_on;
/// use nusb::transfer::{ ControlOut, ControlType, Recipient };
/// # use nusb::MaybeFuture;
/// # fn main() -> Result<(), std::io::Error> {
/// # let di = nusb::list_devices().unwrap().next().unwrap();
/// # let device = di.open().unwrap();
/// # let di = nusb::list_devices().wait().unwrap().next().unwrap();
/// # let device = di.open().wait().unwrap();
///
/// block_on(device.control_out(ControlOut {
/// control_type: ControlType::Vendor,
Expand Down Expand Up @@ -368,13 +380,16 @@ pub struct Interface {
}

impl Interface {
pub(crate) fn wrap(backend: Arc<platform::Interface>) -> Self {
Interface { backend }
}
/// Select the alternate setting of this interface.
///
/// An alternate setting is a mode of the interface that makes particular endpoints available
/// and may enable or disable functionality of the device. The OS resets the device to the default
/// alternate setting when the interface is released or the program exits.
pub fn set_alt_setting(&self, alt_setting: u8) -> Result<(), Error> {
self.backend.set_alt_setting(alt_setting)
pub fn set_alt_setting(&self, alt_setting: u8) -> impl MaybeFuture<Output = Result<(), Error>> {
self.backend.clone().set_alt_setting(alt_setting)
}

/// Synchronously perform a single **IN (device-to-host)** transfer on the default **control** endpoint.
Expand Down Expand Up @@ -424,10 +439,11 @@ impl Interface {
/// ```no_run
/// use futures_lite::future::block_on;
/// use nusb::transfer::{ ControlIn, ControlType, Recipient };
/// # use nusb::MaybeFuture;
/// # fn main() -> Result<(), std::io::Error> {
/// # let di = nusb::list_devices().unwrap().next().unwrap();
/// # let device = di.open().unwrap();
/// # let interface = device.claim_interface(0).unwrap();
/// # let di = nusb::list_devices().wait().unwrap().next().unwrap();
/// # let device = di.open().wait().unwrap();
/// # let interface = device.claim_interface(0).wait().unwrap();
///
/// let data: Vec<u8> = block_on(interface.control_in(ControlIn {
/// control_type: ControlType::Vendor,
Expand Down Expand Up @@ -459,10 +475,11 @@ impl Interface {
/// ```no_run
/// use futures_lite::future::block_on;
/// use nusb::transfer::{ ControlOut, ControlType, Recipient };
/// # use nusb::MaybeFuture;
/// # fn main() -> Result<(), std::io::Error> {
/// # let di = nusb::list_devices().unwrap().next().unwrap();
/// # let device = di.open().unwrap();
/// # let interface = device.claim_interface(0).unwrap();
/// # let di = nusb::list_devices().wait().unwrap().next().unwrap();
/// # let device = di.open().wait().unwrap();
/// # let interface = device.claim_interface(0).wait().unwrap();
///
/// block_on(interface.control_out(ControlOut {
/// control_type: ControlType::Vendor,
Expand Down Expand Up @@ -567,8 +584,8 @@ impl Interface {
/// resume use of the endpoint.
///
/// This should not be called when transfers are pending on the endpoint.
pub fn clear_halt(&self, endpoint: u8) -> Result<(), Error> {
self.backend.clear_halt(endpoint)
pub fn clear_halt(&self, endpoint: u8) -> impl MaybeFuture<Output = Result<(), Error>> {
self.backend.clone().clear_halt(endpoint)
}

/// Get the interface number.
Expand Down
Loading