1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
//! A new library for cross-platform low-level access to USB devices.
//!
//! `nusb` supports Windows, macOS, and Linux, and provides both async and
//! blocking APIs for listing and watching USB devices, reading descriptor
//! details, opening and managing devices and interfaces, and performing
//! transfers on control, bulk, and interrupt endpoints.
//!
//! `nusb` is comparable to the C library [libusb] and its Rust bindings [rusb],
//! but written in pure Rust.
//!
//! [libusb]: https://libusb.info
//! [rusb]: https://docs.rs/rusb/
//!
//! Use `nusb` to write user-space drivers in Rust for non-standard USB devices
//! or those without kernel support. For devices implementing a standard USB
//! class such as Mass Storage, CDC (Serial), HID, Audio, or Video, this is
//! probably not the library you're looking for -- use something built on the
//! existing kernel driver instead. (On some platforms you could detach or
//! replace the kernel driver and program the device from user-space using this
//! library, but you'd have to re-implement the class functionality yourself.)
//!
//! ## Example usage
//!
//! ```no_run
//! use nusb::{list_devices, MaybeFuture};
//! use nusb::transfer::{Bulk, In, Out, ControlOut, ControlType, Recipient};
//! use std::io::{Read, Write, Error, ErrorKind};
//! use std::time::Duration;
//!
//! # fn main() -> Result<(), std::io::Error> {
//! let device = list_devices().wait()?
//! .find(|dev| dev.vendor_id() == 0xAAAA && dev.product_id() == 0xBBBB)
//! .ok_or(Error::new(ErrorKind::NotFound, "device not found"))?;
//!
//! let device = device.open().wait()?;
//! let interface = device.claim_interface(0).wait()?;
//!
//! interface.control_out(ControlOut {
//! control_type: ControlType::Vendor,
//! recipient: Recipient::Device,
//! request: 0x10,
//! value: 0x0,
//! index: 0x0,
//! data: &[0x01, 0x02, 0x03, 0x04],
//! }, Duration::from_millis(100)).wait()?;
//!
//! let mut writer = interface.endpoint::<Bulk, Out>(0x01)?.writer(4096);
//! writer.write_all(&[0x00, 0xff])?;
//! writer.flush()?;
//!
//! let mut reader = interface.endpoint::<Bulk, In>(0x81)?.reader(4096);
//! let mut buf = [0; 64];
//! reader.read_exact(&mut buf)?;
//! # Ok(()) }
//! ```
//!
//! ## USB and usage overview
//!
//! When a USB device connects, the OS queries the device descriptor containing
//! basic device information such as the vendor and product ID (VID / PID) and
//! string descriptors like the manufacturer, product, and serial number
//! strings. [`list_devices`] returns an iterator listing connected USB devices,
//! which can be filtered by these fields to identify and select the desired
//! device.
//!
//! Call [`device_info.open()`](`DeviceInfo::open`) to open a selected device.
//! Additional information about the device can be queried with
//! [`device.active_configuration()`](`Device::active_configuration`).
//!
//! USB devices consist of one or more interfaces. A device with multiple
//! interfaces is known as a composite device. To open an interface, call
//! [`Device::claim_interface`]. Only one program (or kernel driver) may claim
//! an interface at a time.
//!
//! Use the resulting [`Interface`] to perform control transfers or open
//! an [`Endpoint`] to perform bulk or interrupt transfers. Submitting a
//! transfer is a non-blocking operation that adds the transfer to an
//! internal queue for the endpoint. Completed transfers can be popped
//! from the queue synchronously or asynchronously.
//!
//! The [`EndpointRead`][io::EndpointRead] and
//! [`EndpointWrite`][io::EndpointWrite] types wrap the endpoint and
//! manage transfers and buffers to implement the standard `Read` and
//! `Write` traits and their async equivalents.
//!
//! *For more details on how USB works, [USB in a
//! Nutshell](https://beyondlogic.org/usbnutshell/usb1.shtml) is a good
//! overview.*
//!
//! ## Logging
//!
//! `nusb` uses the [`log`](https://docs.rs/log) crate to log debug and error
//! information.
//!
//! When [submitting a bug report][gh-issues], please include the logs: use a
//! `log` backend like [`env_logger`](https://docs.rs/env_logger) and configure
//! it to enable log output for this crate (for `env_logger` set environment
//! variable `RUST_LOG=nusb=debug`.)
//!
//! [gh-issues]: https://github.com/kevinmehall/nusb/issues
//!
//! ## Platform support
//!
//! ### Linux
//!
//! `nusb` is built on the kernel's [usbfs] API.
//!
//! A user must have write access on the `/dev/bus/usb/XXX/YYY` nodes to
//! successfully open a device. Use [udev rules] to configure these permissions.
//!
//! For a single-user system used for development, it may be desirable to give
//! your user account access to all USB devices by placing the following in
//! `/etc/udev/rules.d/70-plugdev-usb.rules`:
//!
//! ```not_rust
//! SUBSYSTEM=="usb", MODE="0660", GROUP="plugdev"
//! ```
//!
//! This grants access on all USB devices to the `plugdev` group, which your
//! user may be a member of by default on Debian/Ubuntu-based distros. If you
//! are developing an app for others to install, you should scope the
//! permissions more narrowly using the `ATTRS{idVendor}=="ZZZZ",
//! ATTRS{idProduct}=="ZZZZ"` filters to only apply to your device.
//!
//! [usbfs]:
//! https://www.kernel.org/doc/html/latest/driver-api/usb/usb.html#the-usb-character-device-nodes
//! [udev rules]: https://www.reactivated.net/writing_udev_rules.html
//!
//! ### Windows
//!
//! `nusb` uses [WinUSB] on Windows.
//!
//! On Windows, devices are associated with a particular driver, which persists
//! across connections and reboots. Composite devices appear as multiple devices
//! in the Windows device model, and each interface can be associated with a
//! separate driver.
//!
//! To use `nusb`, your device or interface must be associated with the `WinUSB`
//! driver. If you control the device firmware, the recommended way is to use a
//! [WCID] descriptor to tell Windows to install the WinUSB driver automatically
//! when the device is first connected. Alternatively [Zadig] (GUI) or [libwdi]
//! (CLI / C library) can be used to manually install the WinUSB driver for a
//! device.
//!
//! [SetupAPI]:
//! https://learn.microsoft.com/en-us/windows-hardware/drivers/install/setupapi
//! [WinUSB]: https://learn.microsoft.com/en-us/windows/win32/api/winusb/
//! [WCID]: https://github.com/pbatard/libwdi/wiki/WCID-Devices
//! [Zadig]:https://zadig.akeo.ie/
//! [libwdi]: https://github.com/pbatard/libwdi
//!
//! ### macOS
//!
//! `nusb` uses IOKit on macOS.
//!
//! Users have access to USB devices by default, with no permission
//! configuration needed. Devices with a kernel driver are not accessible.
//!
//! Unlike other platforms, macOS will only set a configuration automatically
//! for devices with composite class (bDeviceClass = 0x00) or those with a
//! known driver. For vendor class devices, you may need to set a
//! configuration after opening the device:
//!
//! ```no_run
//! # 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().wait().expect("failed to open device");
//! if device.active_configuration().is_err() {
//! device.set_configuration(1).wait().expect("failed to set configuration");
//! }
//! ```
//!
//! ### WebUSB
//!
//! `nusb` can be used from WebAssembly in browsers with [WebUSB] support.
//!
//! Only the async APIs are available since the browser event loop does not
//! allow blocking.
//!
//! `web-sys` considers its WebUSB bindings unstable and [requires the root
//! crate to opt in][web_sys_unstable]. Put the following in your
//! `.cargo/config.toml`:
//!
//! ```toml
//! [target.wasm32-unknown-unknown]
//! rustflags = ["--cfg=web_sys_unstable_apis"]
//! ```
//!
//! WebUSB requires a user permission request to access a device. Use
//! [`request_device`] to prompt the user and get the selected device. Once
//! permissions are granted, the device will appear in [`list_devices`] as well.
//! Alternatively, use `Device::from_js` to wrap a `web_sys::UsbDevice` you
//! obtain yourself.
//!
//! [WebUSB]: https://wicg.github.io/webusb/
//! [web_sys_unstable]: https://wasm-bindgen.github.io/wasm-bindgen/web-sys/unstable-apis.html
//!
//! ## Async support
//!
//! Many methods in `nusb` return a [`MaybeFuture`] type, which can either be
//! `.await`ed (via `IntoFuture`) or `.wait()`ed (blocking the current thread).
//! This allows for async usage in an async context, or blocking usage in a
//! non-async context.
//!
//! Operations such as [`list_devices`], [`list_buses`], [`DeviceInfo::open`],
//! [`Device::set_configuration`], [`Device::reset`],
//! [`Device::claim_interface`], [`Interface::set_alt_setting`], and
//! [`Endpoint::clear_halt`] require blocking system calls. To use these in an
//! asynchronous context, `nusb` requires an async runtime to run these
//! operations on an IO thread to avoid blocking in async code. Enable the cargo
//! feature `tokio` or `smol` to use the corresponding runtime for blocking IO.
//! If neither feature is enabled, `.await` on these methods will panic.
//!
//! For blocking usage, `.wait()` always runs the blocking operation directly
//! without the overhead of handing off to an IO thread.
//!
//! These features do not affect and are not required for transfers, which are
//! implemented on top of natively-async OS APIs.
pub use BusInfo;
pub use ;
pub use ;
pub use MaybeFuture;
pub use ;
/// Get an iterator listing the connected devices.
///
/// ### Example
///
/// ```no_run
/// use nusb::{self, MaybeFuture};
/// let device = nusb::list_devices().wait().unwrap()
/// .find(|dev| dev.vendor_id() == 0xAAAA && dev.product_id() == 0xBBBB)
/// .expect("device not connected");
/// ```
/// Get a device that matches any of the provided [`DeviceSelector`]s and request user permission if necessary.
///
/// ### Example
///
/// ```no_run
/// use nusb::{self, DeviceSelector};
/// # async {
/// let device = nusb::request_device(&[DeviceSelector::all()])
/// .await
/// .unwrap()
/// .expect("no device found or permission denied");
/// # };
/// ```
///
/// Platform-specific notes:
///
/// * **WebUSB**: This prompts the user for permission to access matching
/// devices. If approved, the device selected by the user will be
/// returned. If cancelled, returns `Ok(None)`. The browser requires
/// [Transient User Activation] for this call: it must be called in response to
/// a user action, not unprompted on page load.
///
/// * On other platforms, this calls [`list_devices`] and finds an arbitrary
/// device that matches the selector, returning `Ok(None)` if no matching device is found.
///
/// [Transient User Activation]: https://developer.mozilla.org/en-US/docs/Web/Security/Defenses/User_activation
+ use<'_>
/// Get an iterator listing the system USB buses.
///
/// ### Example
///
/// Group devices by bus:
///
/// ```no_run
/// use std::collections::HashMap;
/// use nusb::MaybeFuture;
///
/// let devices = nusb::list_devices().wait().unwrap().collect::<Vec<_>>();
/// let buses: HashMap<_, _> = nusb::list_buses().wait().unwrap()
/// .map(|bus| {
/// let bus_id = bus.bus_id().to_owned();
/// let devs: Vec<_> = devices.iter().filter(|dev| dev.bus_id() == bus_id).cloned().collect();
/// (bus_id, (bus, devs))
/// })
/// .collect();
/// ```
/// Get a [`Stream`][`futures_core::Stream`] that yields an
/// [event][`hotplug::HotplugEvent`] when a USB device is connected or
/// disconnected from the system.
///
/// Events will be returned for devices connected or disconnected beginning at
/// the time this function is called. To maintain a list of connected devices,
/// call [`list_devices`] after creating the watch with this function to avoid
/// potentially missing a newly-attached device:
///
/// ## Example
///
/// ```no_run
/// use std::collections::HashMap;
/// use nusb::{MaybeFuture, DeviceInfo, DeviceId, hotplug::HotplugEvent};
/// let watch = nusb::watch_devices().unwrap();
/// let mut devices: HashMap<DeviceId, DeviceInfo> = nusb::list_devices().wait().unwrap()
/// .map(|d| (d.id(), d)).collect();
/// for event in futures_lite::stream::block_on(watch) {
/// match event {
/// HotplugEvent::Connected(d) => {
/// devices.insert(d.id(), d);
/// }
/// HotplugEvent::Disconnected(id) => {
/// devices.remove(&id);
/// }
/// }
/// }
/// ```
///
/// ### Platform-specific notes:
///
/// * On Windows, the interfaces of a composite device might not be ready
/// when the `Connected` event is emitted. If you are immediately opening the device
/// and claiming an interface when receiving a `Connected` event,
/// you should retry after a short delay if opening or claiming fails.