diff options
32 files changed, 1546 insertions, 6496 deletions
diff --git a/Cargo.lock b/Cargo.lock index 074bca4..b1fc0c2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -530,13 +530,22 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] +name = "usb_sys" +version = "0.1.0" +dependencies = [ + "sys_util 0.1.0", +] + +[[package]] name = "usb_util" version = "0.1.0" dependencies = [ "assertions 0.1.0", "data_model 0.1.0", - "pkg-config 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)", - "sync 0.1.0", + "libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)", + "remain 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "sys_util 0.1.0", + "usb_sys 0.1.0", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index bd90dcf..371a64f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -32,7 +32,6 @@ default-no-sandbox = [] gpu = ["devices/gpu"] gpu-forward = ["render_node_forward"] plugin = ["protos/plugin", "crosvm_plugin", "protobuf"] -sandboxed-libusb = ["devices/sandboxed-libusb", "vm_control/sandboxed-libusb"] tpm = ["devices/tpm"] wl-dmabuf = ["devices/wl-dmabuf", "gpu_buffer", "resources/wl-dmabuf"] x = ["devices/x"] diff --git a/devices/Cargo.toml b/devices/Cargo.toml index ab240c3..18a203a 100644 --- a/devices/Cargo.toml +++ b/devices/Cargo.toml @@ -6,7 +6,6 @@ edition = "2018" [features] gpu = ["gpu_buffer", "gpu_display", "gpu_renderer"] -sandboxed-libusb = ["usb_util/sandboxed-libusb"] tpm = ["protos/trunks", "tpm2"] wl-dmabuf = [] x = ["gpu_display/x"] diff --git a/devices/src/usb/host_backend/context.rs b/devices/src/usb/host_backend/context.rs deleted file mode 100644 index 76ad4a4..0000000 --- a/devices/src/usb/host_backend/context.rs +++ /dev/null @@ -1,145 +0,0 @@ -// Copyright 2019 The Chromium OS Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -use super::error::*; -use crate::utils::{EventHandler, EventLoop}; -use std::os::raw::c_short; -use std::os::unix::io::RawFd; -use std::sync::{Arc, Weak}; -use sys_util::{error, WatchingEvents}; -#[cfg(feature = "sandboxed-libusb")] -use usb_util::device_handle::DeviceHandle; -use usb_util::hotplug::UsbHotplugHandler; -use usb_util::libusb_context::{LibUsbContext, LibUsbPollfdChangeHandler}; -#[cfg(not(feature = "sandboxed-libusb"))] -use usb_util::libusb_device::LibUsbDevice; -use vm_control::MaybeOwnedFd; - -/// Context wraps libusb context with libusb event handling. -pub struct Context { - context: LibUsbContext, - event_loop: Arc<EventLoop>, - event_handler: Arc<dyn EventHandler>, -} - -impl Context { - /// Create a new context. - pub fn new(event_loop: Arc<EventLoop>) -> Result<Context> { - let context = LibUsbContext::new().map_err(Error::CreateLibUsbContext)?; - let ctx = Context { - context: context.clone(), - event_loop, - event_handler: Arc::new(LibUsbEventHandler { - context: context.clone(), - }), - }; - ctx.init_event_handler()?; - Ok(ctx) - } - - pub fn set_hotplug_handler<H: UsbHotplugHandler + Sized>(&self, handler: H) { - if let Err(e) = self.context.set_hotplug_cb(handler) { - error!("cannot set hotplug handler: {:?}", e); - } - } - - fn init_event_handler(&self) -> Result<()> { - for pollfd in self.context.get_pollfd_iter() { - usb_debug!("event loop add event {} events handler", pollfd.fd); - self.event_loop - .add_event( - &MaybeOwnedFd::Borrowed(pollfd.fd), - WatchingEvents::new(pollfd.events as u32), - Arc::downgrade(&self.event_handler), - ) - .map_err(Error::AddToEventLoop)?; - } - - self.context - .set_pollfd_notifiers(Box::new(PollfdChangeHandler { - event_loop: self.event_loop.clone(), - event_handler: Arc::downgrade(&self.event_handler), - })); - Ok(()) - } - - /// Get libusb device with matching bus, addr, vid and pid. - #[cfg(not(feature = "sandboxed-libusb"))] - pub fn get_device(&self, bus: u8, addr: u8, vid: u16, pid: u16) -> Option<LibUsbDevice> { - let device_iter = match self.context.get_device_iter() { - Ok(iter) => iter, - Err(e) => { - error!("could not get libusb device iterator: {:?}", e); - return None; - } - }; - for device in device_iter { - if device.get_bus_number() == bus && device.get_address() == addr { - if let Ok(descriptor) = device.get_device_descriptor() { - if descriptor.idProduct == pid && descriptor.idVendor == vid { - return Some(device); - } - } - } - } - error!("device not found bus {}, addr {}", bus, addr); - None - } - - #[cfg(feature = "sandboxed-libusb")] - pub fn get_device_handle(&self, fd: std::fs::File) -> Option<DeviceHandle> { - match self.context.handle_from_file(fd) { - Ok(handle) => Some(handle), - Err(e) => { - error!("could not build device from fd: {:?}", e); - None - } - } - } -} - -struct LibUsbEventHandler { - context: LibUsbContext, -} - -impl EventHandler for LibUsbEventHandler { - fn on_event(&self) -> std::result::Result<(), ()> { - self.context.handle_events_nonblock(); - Ok(()) - } -} - -struct PollfdChangeHandler { - event_loop: Arc<EventLoop>, - event_handler: Weak<dyn EventHandler>, -} - -impl LibUsbPollfdChangeHandler for PollfdChangeHandler { - fn add_poll_fd(&self, fd: RawFd, events: c_short) { - if let Err(e) = self.event_loop.add_event( - &MaybeOwnedFd::Borrowed(fd), - WatchingEvents::new(events as u32), - self.event_handler.clone(), - ) { - error!("cannot add event to event loop: {}", e); - } - } - - fn remove_poll_fd(&self, fd: RawFd) { - if let Some(h) = self.event_handler.upgrade() { - if let Err(e) = h.on_event() { - error!("cannot handle event: {:?}", e); - } - } - if let Err(e) = self - .event_loop - .remove_event_for_fd(&MaybeOwnedFd::Borrowed(fd)) - { - error!( - "failed to remove poll change handler from event loop: {}", - e - ); - } - } -} diff --git a/devices/src/usb/host_backend/error.rs b/devices/src/usb/host_backend/error.rs index ef097f9..3f1fed4 100644 --- a/devices/src/usb/host_backend/error.rs +++ b/devices/src/usb/host_backend/error.rs @@ -7,7 +7,7 @@ use crate::usb::xhci::xhci_transfer::Error as XhciTransferError; use crate::utils::Error as UtilsError; use msg_socket::MsgError; use std::fmt::{self, Display}; -use usb_util::error::Error as UsbUtilError; +use usb_util::Error as UsbUtilError; #[derive(Debug)] pub enum Error { @@ -19,6 +19,7 @@ pub enum Error { SetActiveConfig(UsbUtilError), SetInterfaceAltSetting(UsbUtilError), ClearHalt(UsbUtilError), + CreateTransfer(UsbUtilError), GetEndpointType, CreateControlSock(std::io::Error), SetupControlSock(std::io::Error), @@ -30,7 +31,7 @@ pub enum Error { WriteBuffer(BufferError), BufferLen(BufferError), /// Cannot get interface descriptor for (interface, altsetting). - GetInterfaceDescriptor((i32, u16)), + GetInterfaceDescriptor((u8, u8)), GetEndpointDescriptor(u8), BadXhciTransferState, BadBackendProviderState, @@ -49,6 +50,7 @@ impl Display for Error { SetActiveConfig(e) => write!(f, "failed to set active config: {:?}", e), SetInterfaceAltSetting(e) => write!(f, "failed to set interface alt setting: {:?}", e), ClearHalt(e) => write!(f, "failed to clear halt: {:?}", e), + CreateTransfer(e) => write!(f, "failed to create transfer: {:?}", e), GetEndpointType => write!(f, "failed to get endpoint type"), CreateControlSock(e) => write!(f, "failed to create contro sock: {}", e), SetupControlSock(e) => write!(f, "failed to setup control sock: {}", e), diff --git a/devices/src/usb/host_backend/host_backend_device_provider.rs b/devices/src/usb/host_backend/host_backend_device_provider.rs index f479bcb..f60983f 100644 --- a/devices/src/usb/host_backend/host_backend_device_provider.rs +++ b/devices/src/usb/host_backend/host_backend_device_provider.rs @@ -4,22 +4,23 @@ use std::sync::Arc; -use super::context::Context; use super::error::*; use super::host_device::HostDevice; -use super::hotplug::HotplugHandler; use crate::usb::xhci::usb_hub::UsbHub; use crate::usb::xhci::xhci_backend_device_provider::XhciBackendDeviceProvider; use crate::utils::AsyncJobQueue; use crate::utils::{EventHandler, EventLoop, FailHandle}; use msg_socket::{MsgReceiver, MsgSender, MsgSocket}; +use std::collections::HashMap; use std::mem; use std::os::unix::io::{AsRawFd, RawFd}; use std::time::Duration; +use sync::Mutex; use sys_util::net::UnixSeqpacket; use sys_util::{error, WatchingEvents}; +use usb_util::Device; use vm_control::{ - UsbControlAttachedDevice, UsbControlCommand, UsbControlResult, UsbControlSocket, + MaybeOwnedFd, UsbControlAttachedDevice, UsbControlCommand, UsbControlResult, UsbControlSocket, USB_CONTROL_MAX_PORTS, }; @@ -64,12 +65,15 @@ impl HostBackendDeviceProvider { ) -> Result<()> { match mem::replace(self, HostBackendDeviceProvider::Failed) { HostBackendDeviceProvider::Created { sock } => { - let ctx = Context::new(event_loop.clone())?; - let hotplug_handler = HotplugHandler::new(hub.clone()); - ctx.set_hotplug_handler(hotplug_handler); let job_queue = AsyncJobQueue::init(&event_loop).map_err(Error::StartAsyncJobQueue)?; - let inner = Arc::new(ProviderInner::new(fail_handle, job_queue, ctx, sock, hub)); + let inner = Arc::new(ProviderInner::new( + fail_handle, + job_queue, + event_loop.clone(), + sock, + hub, + )); let handler: Arc<dyn EventHandler> = inner.clone(); event_loop .add_event( @@ -123,25 +127,125 @@ impl XhciBackendDeviceProvider for HostBackendDeviceProvider { pub struct ProviderInner { fail_handle: Arc<dyn FailHandle>, job_queue: Arc<AsyncJobQueue>, - ctx: Context, + event_loop: Arc<EventLoop>, sock: MsgSocket<UsbControlResult, UsbControlCommand>, usb_hub: Arc<UsbHub>, + + // Map of USB hub port number to per-device context. + devices: Mutex<HashMap<u8, HostDeviceContext>>, +} + +struct HostDeviceContext { + event_handler: Arc<dyn EventHandler>, + device: Arc<Mutex<Device>>, } impl ProviderInner { fn new( fail_handle: Arc<dyn FailHandle>, job_queue: Arc<AsyncJobQueue>, - ctx: Context, + event_loop: Arc<EventLoop>, sock: MsgSocket<UsbControlResult, UsbControlCommand>, usb_hub: Arc<UsbHub>, ) -> ProviderInner { ProviderInner { fail_handle, job_queue, - ctx, + event_loop, sock, usb_hub, + devices: Mutex::new(HashMap::new()), + } + } + + /// Open a usbdevfs file to create a host USB device object. + /// `fd` should be an open file descriptor for a file in `/dev/bus/usb`. + fn handle_attach_device(&self, fd: Option<MaybeOwnedFd>) -> UsbControlResult { + let usb_file = match fd { + Some(MaybeOwnedFd::Owned(file)) => file, + _ => { + error!("missing fd in UsbControlCommand::AttachDevice message"); + return UsbControlResult::FailedToOpenDevice; + } + }; + + let raw_fd = usb_file.as_raw_fd(); + let device = match Device::new(usb_file) { + Ok(d) => d, + Err(e) => { + error!("could not construct USB device from fd: {}", e); + return UsbControlResult::NoSuchDevice; + } + }; + + let arc_mutex_device = Arc::new(Mutex::new(device)); + + let event_handler: Arc<dyn EventHandler> = Arc::new(UsbUtilEventHandler { + device: arc_mutex_device.clone(), + }); + + if let Err(e) = self.event_loop.add_event( + &MaybeOwnedFd::Borrowed(raw_fd), + WatchingEvents::empty().set_read().set_write(), + Arc::downgrade(&event_handler), + ) { + error!("failed to add USB device fd to event handler: {}", e); + return UsbControlResult::FailedToOpenDevice; + } + + let device_ctx = HostDeviceContext { + event_handler, + device: arc_mutex_device.clone(), + }; + + // Resetting the device is used to make sure it is in a known state, but it may + // still function if the reset fails. + if let Err(e) = arc_mutex_device.lock().reset() { + error!("failed to reset device after attach: {:?}", e); + } + + let host_device = Box::new(HostDevice::new( + self.fail_handle.clone(), + self.job_queue.clone(), + arc_mutex_device, + )); + let port = self.usb_hub.connect_backend(host_device); + match port { + Ok(port) => { + self.devices.lock().insert(port, device_ctx); + UsbControlResult::Ok { port } + } + Err(e) => { + error!("failed to connect device to hub: {}", e); + UsbControlResult::NoAvailablePort + } + } + } + + fn handle_detach_device(&self, port: u8) -> UsbControlResult { + match self.usb_hub.disconnect_port(port) { + Ok(()) => { + if let Some(device_ctx) = self.devices.lock().remove(&port) { + let _ = device_ctx.event_handler.on_event(); + let device = device_ctx.device.lock(); + let fd = device.fd(); + + if let Err(e) = self + .event_loop + .remove_event_for_fd(&MaybeOwnedFd::Borrowed(fd.as_raw_fd())) + { + error!( + "failed to remove poll change handler from event loop: {}", + e + ); + } + } + UsbControlResult::Ok { port } + } + Err(e) => { + error!("failed to disconnect device from port {}: {}", port, e); + UsbControlResult::NoSuchDevice + } } } @@ -168,146 +272,13 @@ impl ProviderInner { fn on_event_helper(&self) -> Result<()> { let cmd = self.sock.recv().map_err(Error::ReadControlSock)?; - match cmd { - UsbControlCommand::AttachDevice { - bus, - addr, - vid, - pid, - fd: usb_fd, - } => { - let _ = usb_fd; - #[cfg(not(feature = "sandboxed-libusb"))] - let device = match self.ctx.get_device(bus, addr, vid, pid) { - Some(d) => d, - None => { - error!( - "cannot get device bus: {}, addr: {}, vid: {}, pid: {}", - bus, addr, vid, pid - ); - // The send failure will be logged, but event loop still think the event is - // handled. - let _ = self - .sock - .send(&UsbControlResult::NoSuchDevice) - .map_err(Error::WriteControlSock)?; - return Ok(()); - } - }; - #[cfg(feature = "sandboxed-libusb")] - let (device, device_handle) = { - use vm_control::MaybeOwnedFd; - - let usb_file = match usb_fd { - Some(MaybeOwnedFd::Owned(file)) => file, - _ => { - let _ = self - .sock - .send(&UsbControlResult::FailedToOpenDevice) - .map_err(Error::WriteControlSock); - return Ok(()); - } - }; - - let device_handle = match self.ctx.get_device_handle(usb_file) { - Some(d) => d, - None => { - error!( - "cannot get device bus: {}, addr: {}, vid: {}, pid: {}", - bus, addr, vid, pid - ); - // The send failure will be logged, but event loop still think the event - // is handled. - let _ = self - .sock - .send(&UsbControlResult::NoSuchDevice) - .map_err(Error::WriteControlSock); - return Ok(()); - } - }; - - let device = device_handle.get_device(); - - // Resetting the device is used to make sure it is in a known state, but it may - // still function if the reset fails. - if let Err(e) = device_handle.reset() { - error!("failed to reset device after attach: {:?}", e); - } - (device, device_handle) - }; - - #[cfg(not(feature = "sandboxed-libusb"))] - let device_handle = match device.open() { - Ok(handle) => handle, - Err(e) => { - error!("fail to open device: {:?}", e); - // The send failure will be logged, but event loop still think the event is - // handled. - let _ = self - .sock - .send(&UsbControlResult::FailedToOpenDevice) - .map_err(Error::WriteControlSock); - return Ok(()); - } - }; - let device = Box::new(HostDevice::new( - self.fail_handle.clone(), - self.job_queue.clone(), - device, - device_handle, - )); - let port = self.usb_hub.connect_backend(device); - match port { - Ok(port) => { - // The send failure will be logged, but event loop still think the event is - // handled. - let _ = self - .sock - .send(&UsbControlResult::Ok { port }) - .map_err(Error::WriteControlSock); - } - Err(e) => { - error!("failed to connect device to hub: {}", e); - // The send failure will be logged, but event loop still think the event is - // handled. - let _ = self - .sock - .send(&UsbControlResult::NoAvailablePort) - .map_err(Error::WriteControlSock); - } - } - Ok(()) - } - UsbControlCommand::DetachDevice { port } => { - match self.usb_hub.disconnect_port(port) { - Ok(()) => { - // The send failure will be logged, but event loop still think the event is - // handled. - let _ = self - .sock - .send(&UsbControlResult::Ok { port }) - .map_err(Error::WriteControlSock); - } - Err(e) => { - error!("failed to disconnect device from port {}: {}", port, e); - // The send failure will be logged, but event loop still think the event is - // handled. - let _ = self - .sock - .send(&UsbControlResult::NoSuchDevice) - .map_err(Error::WriteControlSock); - } - } - Ok(()) - } - UsbControlCommand::ListDevice { ports } => { - let result = self.handle_list_devices(ports); - // The send failure will be logged, but event loop still think the event is - // handled. - let _ = self.sock.send(&result).map_err(Error::WriteControlSock); - Ok(()) - } - } + let result = match cmd { + UsbControlCommand::AttachDevice { fd, .. } => self.handle_attach_device(fd), + UsbControlCommand::DetachDevice { port } => self.handle_detach_device(port), + UsbControlCommand::ListDevice { ports } => self.handle_list_devices(ports), + }; + self.sock.send(&result).map_err(Error::WriteControlSock)?; + Ok(()) } } @@ -318,3 +289,13 @@ impl EventHandler for ProviderInner { }) } } + +struct UsbUtilEventHandler { + device: Arc<Mutex<Device>>, +} + +impl EventHandler for UsbUtilEventHandler { + fn on_event(&self) -> std::result::Result<(), ()> { + self.device.lock().poll_transfers().map_err(|_e| ()) + } +} diff --git a/devices/src/usb/host_backend/host_device.rs b/devices/src/usb/host_backend/host_device.rs index 8841f00..3b85ea2 100644 --- a/devices/src/usb/host_backend/host_device.rs +++ b/devices/src/usb/host_backend/host_device.rs @@ -4,7 +4,6 @@ use std::mem::drop; use std::sync::Arc; -use sync::Mutex; use super::error::*; use super::usb_endpoint::UsbEndpoint; @@ -14,17 +13,14 @@ use crate::usb::xhci::xhci_backend_device::{BackendType, UsbDeviceAddress, XhciB use crate::usb::xhci::xhci_transfer::{XhciTransfer, XhciTransferState, XhciTransferType}; use crate::utils::AsyncJobQueue; use crate::utils::FailHandle; +use data_model::DataInit; use std::collections::HashMap; +use std::mem; +use sync::Mutex; use sys_util::{error, warn}; -use usb_util::device_handle::DeviceHandle; -use usb_util::error::Error as LibUsbError; -use usb_util::libusb_device::LibUsbDevice; -use usb_util::types::{ - ControlRequestDataPhaseTransferDirection, ControlRequestRecipient, StandardControlRequest, - UsbRequestSetup, -}; -use usb_util::usb_transfer::{ - control_transfer, ControlTransferBuffer, TransferStatus, UsbTransfer, +use usb_util::{ + ConfigDescriptorTree, ControlRequestDataPhaseTransferDirection, ControlRequestRecipient, + Device, StandardControlRequest, Transfer, TransferStatus, UsbRequestSetup, }; #[derive(PartialEq)] @@ -43,11 +39,10 @@ pub struct HostDevice { // Endpoints only contains data endpoints (1 to 30). Control transfers are handled at device // level. endpoints: Vec<UsbEndpoint>, - device: LibUsbDevice, - device_handle: Arc<Mutex<DeviceHandle>>, + device: Arc<Mutex<Device>>, ctl_ep_state: ControlEndpointState, - alt_settings: HashMap<u16, u16>, - claimed_interfaces: Vec<i32>, + alt_settings: HashMap<u8, u8>, + claimed_interfaces: Vec<u8>, control_request_setup: UsbRequestSetup, executed: bool, job_queue: Arc<AsyncJobQueue>, @@ -64,14 +59,12 @@ impl HostDevice { pub fn new( fail_handle: Arc<dyn FailHandle>, job_queue: Arc<AsyncJobQueue>, - device: LibUsbDevice, - device_handle: DeviceHandle, + device: Arc<Mutex<Device>>, ) -> HostDevice { HostDevice { fail_handle, endpoints: vec![], device, - device_handle: Arc::new(Mutex::new(device_handle)), ctl_ep_state: ControlEndpointState::SetupStage, alt_settings: HashMap::new(), claimed_interfaces: vec![], @@ -81,30 +74,6 @@ impl HostDevice { } } - fn get_interface_number_of_active_config(&self) -> i32 { - match self.device.get_active_config_descriptor() { - Err(LibUsbError::NotFound) => { - usb_debug!("device is in unconfigured state"); - 0 - } - Err(e) => { - // device might be disconnected now. - error!("unexpected error: {:?}", e); - 0 - } - Ok(descriptor) => descriptor.bNumInterfaces as i32, - } - } - - fn release_interfaces(&mut self) { - for i in &self.claimed_interfaces { - if let Err(e) = self.device_handle.lock().release_interface(*i) { - error!("could not release interface: {:?}", e); - } - } - self.claimed_interfaces = Vec::new(); - } - // Check for requests that should be intercepted and emulated using libusb // functions rather than passed directly to the device. // Returns true if the request has been intercepted or false if the request @@ -167,20 +136,34 @@ impl HostDevice { xhci_transfer: Arc<XhciTransfer>, buffer: Option<ScatterGatherBuffer>, ) -> Result<()> { - let mut control_transfer = control_transfer(0); - control_transfer - .buffer_mut() - .set_request_setup(&self.control_request_setup); - if self.intercepted_control_transfer(&xhci_transfer)? { return Ok(()); } + // Default buffer size for control data transfer. + const CONTROL_DATA_BUFFER_SIZE: usize = 1024; + + // Buffer type for control transfer. The first 8 bytes is a UsbRequestSetup struct. + #[derive(Copy, Clone)] + #[repr(C, packed)] + struct ControlTransferBuffer { + pub setup: UsbRequestSetup, + pub data: [u8; CONTROL_DATA_BUFFER_SIZE], + } + + // Safe because it only has data and has no implicit padding. + unsafe impl DataInit for ControlTransferBuffer {} + + let mut control_request = ControlTransferBuffer { + setup: self.control_request_setup, + data: [0; CONTROL_DATA_BUFFER_SIZE], + }; + let direction = self.control_request_setup.get_direction(); let buffer = if direction == ControlRequestDataPhaseTransferDirection::HostToDevice { if let Some(buffer) = buffer { buffer - .read(&mut control_transfer.buffer_mut().data_buffer) + .read(&mut control_request.data) .map_err(Error::ReadBuffer)?; } // buffer is consumed here for HostToDevice transfers. @@ -190,8 +173,13 @@ impl HostDevice { buffer }; + let control_buffer = control_request.as_slice().to_vec(); + + let mut control_transfer = + Transfer::new_control(control_buffer).map_err(Error::CreateTransfer)?; + let tmp_transfer = xhci_transfer.clone(); - let callback = move |t: UsbTransfer<ControlTransferBuffer>| { + let callback = move |t: Transfer| { usb_debug!("setup token control transfer callback invoked"); update_transfer_state(&xhci_transfer, &t)?; let state = xhci_transfer.state().lock(); @@ -207,10 +195,14 @@ impl HostDevice { let status = t.status(); let actual_length = t.actual_length(); if direction == ControlRequestDataPhaseTransferDirection::DeviceToHost { - if let Some(buffer) = &buffer { - buffer - .write(&t.buffer().data_buffer) - .map_err(Error::WriteBuffer)?; + if let Some(control_request_data) = + t.buffer.get(mem::size_of::<UsbRequestSetup>()..) + { + if let Some(buffer) = &buffer { + buffer + .write(&control_request_data) + .map_err(Error::WriteBuffer)?; + } } } drop(state); @@ -231,20 +223,18 @@ impl HostDevice { }; let fail_handle = self.fail_handle.clone(); - control_transfer.set_callback( - move |t: UsbTransfer<ControlTransferBuffer>| match callback(t) { - Ok(_) => {} - Err(e) => { - error!("control transfer callback failed {:?}", e); - fail_handle.fail(); - } - }, - ); + control_transfer.set_callback(move |t: Transfer| match callback(t) { + Ok(_) => {} + Err(e) => { + error!("control transfer callback failed {:?}", e); + fail_handle.fail(); + } + }); submit_transfer( self.fail_handle.clone(), &self.job_queue, tmp_transfer, - &self.device_handle, + &mut self.device.lock(), control_transfer, ) } @@ -309,40 +299,50 @@ impl HostDevice { fn set_config(&mut self) -> Result<TransferStatus> { // It's a standard, set_config, device request. - let config = (self.control_request_setup.value & 0xff) as i32; + let config = (self.control_request_setup.value & 0xff) as u8; usb_debug!( "Set config control transfer is received with config: {}", config ); self.release_interfaces(); let cur_config = self - .device_handle + .device .lock() .get_active_configuration() .map_err(Error::GetActiveConfig)?; usb_debug!("current config is: {}", cur_config); if config != cur_config { - self.device_handle + self.device .lock() .set_active_configuration(config) .map_err(Error::SetActiveConfig)?; } - self.claim_interfaces(); - self.create_endpoints()?; + let config_descriptor = self + .device + .lock() + .get_active_config_descriptor() + .map_err(Error::GetActiveConfig)?; + self.claim_interfaces(&config_descriptor); + self.create_endpoints(&config_descriptor)?; Ok(TransferStatus::Completed) } fn set_interface(&mut self) -> Result<TransferStatus> { usb_debug!("set interface"); // It's a standard, set_interface, interface request. - let interface = self.control_request_setup.index; - let alt_setting = self.control_request_setup.value; - self.device_handle + let interface = self.control_request_setup.index as u8; + let alt_setting = self.control_request_setup.value as u8; + self.device .lock() - .set_interface_alt_setting(interface as i32, alt_setting as i32) + .set_interface_alt_setting(interface, alt_setting) .map_err(Error::SetInterfaceAltSetting)?; self.alt_settings.insert(interface, alt_setting); - self.create_endpoints()?; + let config_descriptor = self + .device + .lock() + .get_active_config_descriptor() + .map_err(Error::GetActiveConfig)?; + self.create_endpoints(&config_descriptor)?; Ok(TransferStatus::Completed) } @@ -352,7 +352,7 @@ impl HostDevice { // It's a standard, clear_feature, endpoint request. const STD_FEATURE_ENDPOINT_HALT: u16 = 0; if request_setup.value == STD_FEATURE_ENDPOINT_HALT { - self.device_handle + self.device .lock() .clear_halt(request_setup.index as u8) .map_err(Error::ClearHalt)?; @@ -360,9 +360,9 @@ impl HostDevice { Ok(TransferStatus::Completed) } - fn claim_interfaces(&mut self) { - for i in 0..self.get_interface_number_of_active_config() { - match self.device_handle.lock().claim_interface(i) { + fn claim_interfaces(&mut self, config_descriptor: &ConfigDescriptorTree) { + for i in 0..config_descriptor.num_interfaces() { + match self.device.lock().claim_interface(i) { Ok(()) => { usb_debug!("claimed interface {}", i); self.claimed_interfaces.push(i); @@ -374,23 +374,16 @@ impl HostDevice { } } - fn create_endpoints(&mut self) -> Result<()> { + fn create_endpoints(&mut self, config_descriptor: &ConfigDescriptorTree) -> Result<()> { self.endpoints = Vec::new(); - let config_descriptor = match self.device.get_active_config_descriptor() { - Err(e) => { - error!("device might be disconnected: {:?}", e); - return Ok(()); - } - Ok(descriptor) => descriptor, - }; for i in &self.claimed_interfaces { - let alt_setting = self.alt_settings.get(&(*i as u16)).unwrap_or(&0); + let alt_setting = self.alt_settings.get(i).unwrap_or(&0); let interface = config_descriptor - .get_interface_descriptor(*i as u8, *alt_setting as i32) + .get_interface_descriptor(*i, *alt_setting) .ok_or(Error::GetInterfaceDescriptor((*i, *alt_setting)))?; for ep_idx in 0..interface.bNumEndpoints { let ep_dp = interface - .endpoint_descriptor(ep_idx) + .get_endpoint_descriptor(ep_idx) .ok_or(Error::GetEndpointDescriptor(ep_idx))?; let ep_num = ep_dp.get_endpoint_number(); if ep_num == 0 { @@ -402,7 +395,7 @@ impl HostDevice { self.endpoints.push(UsbEndpoint::new( self.fail_handle.clone(), self.job_queue.clone(), - self.device_handle.clone(), + self.device.clone(), ep_num, direction, ty, @@ -412,6 +405,15 @@ impl HostDevice { Ok(()) } + fn release_interfaces(&mut self) { + for i in &self.claimed_interfaces { + if let Err(e) = self.device.lock().release_interface(*i) { + error!("could not release interface: {:?}", e); + } + } + self.claimed_interfaces = Vec::new(); + } + fn submit_transfer_helper(&mut self, transfer: XhciTransfer) -> Result<()> { if transfer.get_endpoint_number() == 0 { return self.handle_control_transfer(transfer); @@ -430,7 +432,7 @@ impl HostDevice { impl XhciBackendDevice for HostDevice { fn get_backend_type(&self) -> BackendType { - let d = match self.device.get_device_descriptor() { + let d = match self.device.lock().get_device_descriptor() { Ok(d) => d, Err(_) => return BackendType::Usb2, }; @@ -443,16 +445,8 @@ impl XhciBackendDevice for HostDevice { } } - fn host_bus(&self) -> u8 { - self.device.get_bus_number() - } - - fn host_address(&self) -> u8 { - self.device.get_address() - } - fn get_vid(&self) -> u16 { - match self.device.get_device_descriptor() { + match self.device.lock().get_device_descriptor() { Ok(d) => d.idVendor, Err(e) => { error!("cannot get device descriptor: {:?}", e); @@ -462,7 +456,7 @@ impl XhciBackendDevice for HostDevice { } fn get_pid(&self) -> u16 { - match self.device.get_device_descriptor() { + match self.device.lock().get_device_descriptor() { Ok(d) => d.idProduct, Err(e) => { error!("cannot get device descriptor: {:?}", e); @@ -488,16 +482,9 @@ impl XhciBackendDevice for HostDevice { fn reset(&mut self) -> std::result::Result<(), ()> { usb_debug!("resetting host device"); - let result = self.device_handle.lock().reset(); - match result { - Err(LibUsbError::NotFound) => { - // libusb will return NotFound if it fails to re-claim - // the interface after the reset. - Ok(()) - } - _ => result.map_err(|e| { - error!("failed to reset device: {:?}", e); - }), - } + self.device + .lock() + .reset() + .map_err(|e| error!("failed to reset device: {:?}", e)) } } diff --git a/devices/src/usb/host_backend/hotplug.rs b/devices/src/usb/host_backend/hotplug.rs deleted file mode 100644 index 0764660..0000000 --- a/devices/src/usb/host_backend/hotplug.rs +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright 2019 The Chromium OS Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -use std::sync::Arc; - -use crate::usb::xhci::usb_hub::UsbHub; -use sys_util::error; -use usb_util::hotplug::{HotplugEvent, UsbHotplugHandler}; -use usb_util::libusb_device::LibUsbDevice; - -pub struct HotplugHandler { - hub: Arc<UsbHub>, -} - -impl HotplugHandler { - pub fn new(hub: Arc<UsbHub>) -> Self { - HotplugHandler { hub } - } -} - -impl UsbHotplugHandler for HotplugHandler { - fn hotplug_event(&self, device: LibUsbDevice, event: HotplugEvent) { - if event != HotplugEvent::DeviceLeft { - return; - } - - let bus = device.get_bus_number(); - let address = device.get_address(); - let descriptor = match device.get_device_descriptor() { - Ok(d) => d, - Err(e) => { - error!("cannot get device descriptor: {:?}", e); - return; - } - }; - let vid = descriptor.idVendor; - let pid = descriptor.idProduct; - - if let Err(e) = self.hub.try_detach(bus, address, vid, pid) { - error!("device left event triggered failed detach from hub: {}", e); - return; - } - } -} diff --git a/devices/src/usb/host_backend/mod.rs b/devices/src/usb/host_backend/mod.rs index ea0f44c..aa0f568 100644 --- a/devices/src/usb/host_backend/mod.rs +++ b/devices/src/usb/host_backend/mod.rs @@ -2,10 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -pub mod context; pub mod error; pub mod host_backend_device_provider; pub mod host_device; -mod hotplug; pub mod usb_endpoint; mod utils; diff --git a/devices/src/usb/host_backend/usb_endpoint.rs b/devices/src/usb/host_backend/usb_endpoint.rs index 329d6ff..f9f06ff 100644 --- a/devices/src/usb/host_backend/usb_endpoint.rs +++ b/devices/src/usb/host_backend/usb_endpoint.rs @@ -4,7 +4,6 @@ use std::cmp; use std::sync::Arc; -use sync::Mutex; use super::error::*; use super::utils::{submit_transfer, update_transfer_state}; @@ -14,18 +13,17 @@ use crate::usb::xhci::xhci_transfer::{ }; use crate::utils::AsyncJobQueue; use crate::utils::FailHandle; +use sync::Mutex; use sys_util::error; -use usb_util::device_handle::DeviceHandle; -use usb_util::types::{EndpointDirection, EndpointType, ENDPOINT_DIRECTION_OFFSET}; -use usb_util::usb_transfer::{ - bulk_transfer, interrupt_transfer, BulkTransferBuffer, TransferStatus, UsbTransfer, +use usb_util::{ + Device, EndpointDirection, EndpointType, Transfer, TransferStatus, ENDPOINT_DIRECTION_OFFSET, }; /// Isochronous, Bulk or Interrupt endpoint. pub struct UsbEndpoint { fail_handle: Arc<dyn FailHandle>, job_queue: Arc<AsyncJobQueue>, - device_handle: Arc<Mutex<DeviceHandle>>, + device: Arc<Mutex<Device>>, endpoint_number: u8, direction: EndpointDirection, ty: EndpointType, @@ -36,7 +34,7 @@ impl UsbEndpoint { pub fn new( fail_handle: Arc<dyn FailHandle>, job_queue: Arc<AsyncJobQueue>, - device_handle: Arc<Mutex<DeviceHandle>>, + device: Arc<Mutex<Device>>, endpoint_number: u8, direction: EndpointDirection, ty: EndpointType, @@ -45,7 +43,7 @@ impl UsbEndpoint { UsbEndpoint { fail_handle, job_queue, - device_handle, + device, endpoint_number, direction, ty, @@ -101,13 +99,23 @@ impl UsbEndpoint { Ok(()) } + fn get_transfer_buffer(&self, buffer: &ScatterGatherBuffer) -> Result<Vec<u8>> { + let mut v = vec![0u8; buffer.len().map_err(Error::BufferLen)?]; + if self.direction == EndpointDirection::HostToDevice { + // Read data from ScatterGatherBuffer to a continuous memory. + buffer.read(v.as_mut_slice()).map_err(Error::ReadBuffer)?; + } + Ok(v) + } + fn handle_bulk_transfer( &self, xhci_transfer: XhciTransfer, buffer: ScatterGatherBuffer, ) -> Result<()> { + let transfer_buffer = self.get_transfer_buffer(&buffer)?; let usb_transfer = - bulk_transfer(self.ep_addr(), 0, buffer.len().map_err(Error::BufferLen)?); + Transfer::new_bulk(self.ep_addr(), transfer_buffer).map_err(Error::CreateTransfer)?; self.do_handle_transfer(xhci_transfer, usb_transfer, buffer) } @@ -116,32 +124,28 @@ impl UsbEndpoint { xhci_transfer: XhciTransfer, buffer: ScatterGatherBuffer, ) -> Result<()> { - let usb_transfer = - interrupt_transfer(self.ep_addr(), 0, buffer.len().map_err(Error::BufferLen)?); + let transfer_buffer = self.get_transfer_buffer(&buffer)?; + let usb_transfer = Transfer::new_interrupt(self.ep_addr(), transfer_buffer) + .map_err(Error::CreateTransfer)?; self.do_handle_transfer(xhci_transfer, usb_transfer, buffer) } fn do_handle_transfer( &self, xhci_transfer: XhciTransfer, - mut usb_transfer: UsbTransfer<BulkTransferBuffer>, + mut usb_transfer: Transfer, buffer: ScatterGatherBuffer, ) -> Result<()> { let xhci_transfer = Arc::new(xhci_transfer); let tmp_transfer = xhci_transfer.clone(); match self.direction { EndpointDirection::HostToDevice => { - // Read data from ScatterGatherBuffer to a continuous memory. - buffer - .read(usb_transfer.buffer_mut().as_mut_slice()) - .map_err(Error::ReadBuffer)?; usb_debug!( - "out transfer ep_addr {:#x}, buffer len {:?}, data {:#x?}", + "out transfer ep_addr {:#x}, buffer len {:?}", self.ep_addr(), buffer.len(), - usb_transfer.buffer_mut().as_mut_slice() ); - let callback = move |t: UsbTransfer<BulkTransferBuffer>| { + let callback = move |t: Transfer| { usb_debug!("out transfer callback"); update_transfer_state(&xhci_transfer, &t)?; let state = xhci_transfer.state().lock(); @@ -168,20 +172,18 @@ impl UsbEndpoint { } }; let fail_handle = self.fail_handle.clone(); - usb_transfer.set_callback( - move |t: UsbTransfer<BulkTransferBuffer>| match callback(t) { - Ok(_) => {} - Err(e) => { - error!("bulk transfer callback failed: {:?}", e); - fail_handle.fail(); - } - }, - ); + usb_transfer.set_callback(move |t: Transfer| match callback(t) { + Ok(_) => {} + Err(e) => { + error!("bulk transfer callback failed: {:?}", e); + fail_handle.fail(); + } + }); submit_transfer( self.fail_handle.clone(), &self.job_queue, tmp_transfer, - &self.device_handle, + &mut self.device.lock(), usb_transfer, )?; } @@ -192,12 +194,8 @@ impl UsbEndpoint { buffer.len() ); let _addr = self.ep_addr(); - let callback = move |t: UsbTransfer<BulkTransferBuffer>| { - usb_debug!( - "ep {:#x} in transfer data {:?}", - _addr, - t.buffer().as_slice() - ); + let callback = move |t: Transfer| { + usb_debug!("ep {:#x} in transfer data {:?}", _addr, t.buffer.as_slice()); update_transfer_state(&xhci_transfer, &t)?; let state = xhci_transfer.state().lock(); match *state { @@ -212,7 +210,7 @@ impl UsbEndpoint { let status = t.status(); let actual_length = t.actual_length() as usize; let copied_length = buffer - .write(t.buffer().as_slice()) + .write(t.buffer.as_slice()) .map_err(Error::WriteBuffer)?; let actual_length = cmp::min(actual_length, copied_length); drop(state); @@ -230,21 +228,19 @@ impl UsbEndpoint { }; let fail_handle = self.fail_handle.clone(); - usb_transfer.set_callback( - move |t: UsbTransfer<BulkTransferBuffer>| match callback(t) { - Ok(_) => {} - Err(e) => { - error!("bulk transfer callback {:?}", e); - fail_handle.fail(); - } - }, - ); + usb_transfer.set_callback(move |t: Transfer| match callback(t) { + Ok(_) => {} + Err(e) => { + error!("bulk transfer callback {:?}", e); + fail_handle.fail(); + } + }); submit_transfer( self.fail_handle.clone(), &self.job_queue, tmp_transfer, - &self.device_handle, + &mut self.device.lock(), usb_transfer, )?; } diff --git a/devices/src/usb/host_backend/utils.rs b/devices/src/usb/host_backend/utils.rs index bcbec20..ac506e7 100644 --- a/devices/src/usb/host_backend/utils.rs +++ b/devices/src/usb/host_backend/utils.rs @@ -4,20 +4,18 @@ use std::mem; use std::sync::Arc; -use sync::Mutex; use super::error::*; use crate::usb::xhci::xhci_transfer::{XhciTransfer, XhciTransferState}; use crate::utils::AsyncJobQueue; use crate::utils::FailHandle; use sys_util::{error, warn}; -use usb_util::device_handle::DeviceHandle; -use usb_util::usb_transfer::{TransferStatus, UsbTransfer, UsbTransferBuffer}; +use usb_util::{Device, Transfer, TransferStatus}; /// Helper function to update xhci_transfer state. -pub fn update_transfer_state<T: UsbTransferBuffer>( +pub fn update_transfer_state( xhci_transfer: &Arc<XhciTransfer>, - usb_transfer: &UsbTransfer<T>, + usb_transfer: &Transfer, ) -> Result<()> { let status = usb_transfer.status(); let mut state = xhci_transfer.state().lock(); @@ -44,12 +42,12 @@ pub fn update_transfer_state<T: UsbTransferBuffer>( } /// Helper function to submit usb_transfer to device handle. -pub fn submit_transfer<T: UsbTransferBuffer>( +pub fn submit_transfer( fail_handle: Arc<dyn FailHandle>, job_queue: &Arc<AsyncJobQueue>, xhci_transfer: Arc<XhciTransfer>, - device_handle: &Arc<Mutex<DeviceHandle>>, - usb_transfer: UsbTransfer<T>, + device: &mut Device, + usb_transfer: Transfer, ) -> Result<()> { let transfer_status = { // We need to hold the lock to avoid race condition. @@ -58,7 +56,7 @@ pub fn submit_transfer<T: UsbTransferBuffer>( let mut state = xhci_transfer.state().lock(); match mem::replace(&mut *state, XhciTransferState::Cancelled) { XhciTransferState::Created => { - match device_handle.lock().submit_async_transfer(usb_transfer) { + match device.submit_transfer(usb_transfer) { Err(e) => { error!("fail to submit transfer {:?}", e); *state = XhciTransferState::Completed; @@ -66,13 +64,12 @@ pub fn submit_transfer<T: UsbTransferBuffer>( } // If it's submitted, we don't need to send on_transfer_complete now. Ok(canceller) => { - // TODO(jkwang) refactor canceller to return Cancel::Ok or Cancel::Err. - let cancel_callback = Box::new(move || match canceller.try_cancel() { - true => { - usb_debug!("cancel issued to libusb backend"); + let cancel_callback = Box::new(move || match canceller.cancel() { + Ok(()) => { + usb_debug!("cancel issued to kernel"); } - false => { - usb_debug!("fail to cancel"); + Err(e) => { + usb_debug!("fail to cancel: {}", e); } }); *state = XhciTransferState::Submitted { cancel_callback }; diff --git a/devices/src/usb/xhci/usb_hub.rs b/devices/src/usb/xhci/usb_hub.rs index 28c7f19..d54eaa9 100644 --- a/devices/src/usb/xhci/usb_hub.rs +++ b/devices/src/usb/xhci/usb_hub.rs @@ -205,41 +205,6 @@ impl UsbHub { UsbHub { ports } } - /// Try to detach device of bus, addr, vid, pid - pub fn try_detach(&self, bus: u8, addr: u8, vid: u16, pid: u16) -> Result<()> { - for port in &self.ports { - // This block exists so that we only hold the backend device - // lock while checking the address. It needs to be dropped before - // calling port.detach(), because that acquires the backend - // device lock again. - { - let backend_device = port.get_backend_device(); - - let d = match backend_device.as_ref() { - None => continue, - Some(d) => d, - }; - - if d.host_bus() != bus - || d.host_address() != addr - || d.get_vid() != vid - || d.get_pid() != pid - { - continue; - } - } - - return port.detach(); - } - - Err(Error::NoSuchDevice { - bus, - addr, - vid, - pid, - }) - } - /// Reset all ports. pub fn reset(&self) -> Result<()> { usb_debug!("reseting usb hub"); diff --git a/devices/src/usb/xhci/xhci_backend_device.rs b/devices/src/usb/xhci/xhci_backend_device.rs index e104cdc..a3d9e66 100644 --- a/devices/src/usb/xhci/xhci_backend_device.rs +++ b/devices/src/usb/xhci/xhci_backend_device.rs @@ -18,10 +18,6 @@ pub enum BackendType { pub trait XhciBackendDevice: Send { /// Returns the type of USB device provided by this device. fn get_backend_type(&self) -> BackendType; - /// Returns host bus number of this device. - fn host_bus(&self) -> u8; - /// Returns host address of this device. - fn host_address(&self) -> u8; /// Get vendor id of this device. fn get_vid(&self) -> u16; /// Get product id of this device. diff --git a/devices/src/usb/xhci/xhci_transfer.rs b/devices/src/usb/xhci/xhci_transfer.rs index fa6d5de..625f97e 100644 --- a/devices/src/usb/xhci/xhci_transfer.rs +++ b/devices/src/usb/xhci/xhci_transfer.rs @@ -17,8 +17,7 @@ use std::mem; use std::sync::{Arc, Weak}; use sync::Mutex; use sys_util::{error, Error as SysError, EventFd, GuestMemory}; -use usb_util::types::UsbRequestSetup; -use usb_util::usb_transfer::TransferStatus; +use usb_util::{TransferStatus, UsbRequestSetup}; #[derive(Debug)] pub enum Error { @@ -67,7 +66,7 @@ pub enum XhciTransferState { /// When transfer is submitted, it will contain a transfer callback, which should be invoked /// when the transfer is cancelled. Submitted { - cancel_callback: Box<dyn FnMut() + Send>, + cancel_callback: Box<dyn FnOnce() + Send>, }, Cancelling, Cancelled, @@ -78,9 +77,7 @@ impl XhciTransferState { /// Try to cancel this transfer, if it's possible. pub fn try_cancel(&mut self) { match mem::replace(self, XhciTransferState::Created) { - XhciTransferState::Submitted { - mut cancel_callback, - } => { + XhciTransferState::Submitted { cancel_callback } => { *self = XhciTransferState::Cancelling; cancel_callback(); } diff --git a/usb_sys/src/lib.rs b/usb_sys/src/lib.rs index fadad76..d4f2982 100644 --- a/usb_sys/src/lib.rs +++ b/usb_sys/src/lib.rs @@ -139,6 +139,10 @@ impl Default for usbdevfs_urb { } } +// The structure that embeds this should ensure that this is safe. +unsafe impl Send for usbdevfs_urb {} +unsafe impl Sync for usbdevfs_urb {} + #[repr(C)] #[derive(Copy, Clone)] pub struct usbdevfs_ioctl { diff --git a/usb_util/Cargo.toml b/usb_util/Cargo.toml index fab07d6..ed505ff 100644 --- a/usb_util/Cargo.toml +++ b/usb_util/Cargo.toml @@ -3,15 +3,11 @@ name = "usb_util" version = "0.1.0" authors = ["The Chromium OS Authors"] edition = "2018" -build = "build.rs" - -[features] -sandboxed-libusb = [] [dependencies] assertions = { path = "../assertions" } data_model = { path = "../data_model" } -sync = { path = "../sync" } - -[build-dependencies] -pkg-config = "=0.3.11" +libc = "*" +remain = "*" +sys_util = { path = "../sys_util" } +usb_sys = { path = "../usb_sys" } diff --git a/usb_util/build.rs b/usb_util/build.rs deleted file mode 100644 index 34e14da..0000000 --- a/usb_util/build.rs +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright 2018 The Chromium OS Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -use std::env; - -fn main() { - env::set_var("PKG_CONFIG_ALLOW_CROSS", "1"); - pkg_config::probe_library("libusb-1.0").unwrap(); -} diff --git a/usb_util/src/bindings.rs b/usb_util/src/bindings.rs deleted file mode 100644 index 8f62a01..0000000 --- a/usb_util/src/bindings.rs +++ /dev/null @@ -1,4638 +0,0 @@ -// Copyright 2019 The Chromium OS Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -/* automatically generated by rust-bindgen */ - -#[repr(C)] -#[derive(Default)] -pub struct __IncompleteArrayField<T>(::std::marker::PhantomData<T>); -impl<T> __IncompleteArrayField<T> { - #[inline] - pub fn new() -> Self { - __IncompleteArrayField(::std::marker::PhantomData) - } - #[inline] - pub unsafe fn as_ptr(&self) -> *const T { - ::std::mem::transmute(self) - } - #[inline] - pub unsafe fn as_mut_ptr(&mut self) -> *mut T { - ::std::mem::transmute(self) - } - #[inline] - pub unsafe fn as_slice(&self, len: usize) -> &[T] { - ::std::slice::from_raw_parts(self.as_ptr(), len) - } - #[inline] - pub unsafe fn as_mut_slice(&mut self, len: usize) -> &mut [T] { - ::std::slice::from_raw_parts_mut(self.as_mut_ptr(), len) - } -} -impl<T> ::std::fmt::Debug for __IncompleteArrayField<T> { - fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { - fmt.write_str("__IncompleteArrayField") - } -} -impl<T> ::std::clone::Clone for __IncompleteArrayField<T> { - #[inline] - fn clone(&self) -> Self { - Self::new() - } -} -impl<T> ::std::marker::Copy for __IncompleteArrayField<T> {} -pub const _STDINT_H: u32 = 1; -pub const _FEATURES_H: u32 = 1; -pub const _DEFAULT_SOURCE: u32 = 1; -pub const __USE_ISOC11: u32 = 1; -pub const __USE_ISOC99: u32 = 1; -pub const __USE_ISOC95: u32 = 1; -pub const __USE_POSIX_IMPLICITLY: u32 = 1; -pub const _POSIX_SOURCE: u32 = 1; -pub const _POSIX_C_SOURCE: u32 = 200809; -pub const __USE_POSIX: u32 = 1; -pub const __USE_POSIX2: u32 = 1; -pub const __USE_POSIX199309: u32 = 1; -pub const __USE_POSIX199506: u32 = 1; -pub const __USE_XOPEN2K: u32 = 1; -pub const __USE_XOPEN2K8: u32 = 1; -pub const _ATFILE_SOURCE: u32 = 1; -pub const __USE_MISC: u32 = 1; -pub const __USE_ATFILE: u32 = 1; -pub const __USE_FORTIFY_LEVEL: u32 = 0; -pub const _STDC_PREDEF_H: u32 = 1; -pub const __STDC_IEC_559__: u32 = 1; -pub const __STDC_IEC_559_COMPLEX__: u32 = 1; -pub const __STDC_ISO_10646__: u32 = 201605; -pub const __STDC_NO_THREADS__: u32 = 1; -pub const __GNU_LIBRARY__: u32 = 6; -pub const __GLIBC__: u32 = 2; -pub const __GLIBC_MINOR__: u32 = 24; -pub const _SYS_CDEFS_H: u32 = 1; -pub const __WORDSIZE: u32 = 64; -pub const __WORDSIZE_TIME64_COMPAT32: u32 = 1; -pub const __SYSCALL_WORDSIZE: u32 = 64; -pub const _BITS_WCHAR_H: u32 = 1; -pub const INT8_MIN: i32 = -128; -pub const INT16_MIN: i32 = -32768; -pub const INT32_MIN: i32 = -2147483648; -pub const INT8_MAX: u32 = 127; -pub const INT16_MAX: u32 = 32767; -pub const INT32_MAX: u32 = 2147483647; -pub const UINT8_MAX: u32 = 255; -pub const UINT16_MAX: u32 = 65535; -pub const UINT32_MAX: u32 = 4294967295; -pub const INT_LEAST8_MIN: i32 = -128; -pub const INT_LEAST16_MIN: i32 = -32768; -pub const INT_LEAST32_MIN: i32 = -2147483648; -pub const INT_LEAST8_MAX: u32 = 127; -pub const INT_LEAST16_MAX: u32 = 32767; -pub const INT_LEAST32_MAX: u32 = 2147483647; -pub const UINT_LEAST8_MAX: u32 = 255; -pub const UINT_LEAST16_MAX: u32 = 65535; -pub const UINT_LEAST32_MAX: u32 = 4294967295; -pub const INT_FAST8_MIN: i32 = -128; -pub const INT_FAST16_MIN: i64 = -9223372036854775808; -pub const INT_FAST32_MIN: i64 = -9223372036854775808; -pub const INT_FAST8_MAX: u32 = 127; -pub const INT_FAST16_MAX: u64 = 9223372036854775807; -pub const INT_FAST32_MAX: u64 = 9223372036854775807; -pub const UINT_FAST8_MAX: u32 = 255; -pub const UINT_FAST16_MAX: i32 = -1; -pub const UINT_FAST32_MAX: i32 = -1; -pub const INTPTR_MIN: i64 = -9223372036854775808; -pub const INTPTR_MAX: u64 = 9223372036854775807; -pub const UINTPTR_MAX: i32 = -1; -pub const PTRDIFF_MIN: i64 = -9223372036854775808; -pub const PTRDIFF_MAX: u64 = 9223372036854775807; -pub const SIG_ATOMIC_MIN: i32 = -2147483648; -pub const SIG_ATOMIC_MAX: u32 = 2147483647; -pub const SIZE_MAX: i32 = -1; -pub const WINT_MIN: u32 = 0; -pub const WINT_MAX: u32 = 4294967295; -pub const _SYS_TYPES_H: u32 = 1; -pub const _BITS_TYPES_H: u32 = 1; -pub const _BITS_TYPESIZES_H: u32 = 1; -pub const __OFF_T_MATCHES_OFF64_T: u32 = 1; -pub const __INO_T_MATCHES_INO64_T: u32 = 1; -pub const __FD_SETSIZE: u32 = 1024; -pub const __clock_t_defined: u32 = 1; -pub const __time_t_defined: u32 = 1; -pub const __clockid_t_defined: u32 = 1; -pub const __timer_t_defined: u32 = 1; -pub const __BIT_TYPES_DEFINED__: u32 = 1; -pub const _ENDIAN_H: u32 = 1; -pub const __LITTLE_ENDIAN: u32 = 1234; -pub const __BIG_ENDIAN: u32 = 4321; -pub const __PDP_ENDIAN: u32 = 3412; -pub const __BYTE_ORDER: u32 = 1234; -pub const __FLOAT_WORD_ORDER: u32 = 1234; -pub const LITTLE_ENDIAN: u32 = 1234; -pub const BIG_ENDIAN: u32 = 4321; -pub const PDP_ENDIAN: u32 = 3412; -pub const BYTE_ORDER: u32 = 1234; -pub const _BITS_BYTESWAP_H: u32 = 1; -pub const _SYS_SELECT_H: u32 = 1; -pub const __FD_ZERO_STOS: &'static [u8; 6usize] = b"stosq\0"; -pub const _SIGSET_H_types: u32 = 1; -pub const __timespec_defined: u32 = 1; -pub const _STRUCT_TIMEVAL: u32 = 1; -pub const FD_SETSIZE: u32 = 1024; -pub const _SYS_SYSMACROS_H: u32 = 1; -pub const _BITS_PTHREADTYPES_H: u32 = 1; -pub const __SIZEOF_PTHREAD_ATTR_T: u32 = 56; -pub const __SIZEOF_PTHREAD_MUTEX_T: u32 = 40; -pub const __SIZEOF_PTHREAD_MUTEXATTR_T: u32 = 4; -pub const __SIZEOF_PTHREAD_COND_T: u32 = 48; -pub const __SIZEOF_PTHREAD_CONDATTR_T: u32 = 4; -pub const __SIZEOF_PTHREAD_RWLOCK_T: u32 = 56; -pub const __SIZEOF_PTHREAD_RWLOCKATTR_T: u32 = 8; -pub const __SIZEOF_PTHREAD_BARRIER_T: u32 = 32; -pub const __SIZEOF_PTHREAD_BARRIERATTR_T: u32 = 4; -pub const __have_pthread_attr_t: u32 = 1; -pub const __PTHREAD_MUTEX_HAVE_PREV: u32 = 1; -pub const __PTHREAD_RWLOCK_INT_FLAGS_SHARED: u32 = 1; -pub const _SYS_TIME_H: u32 = 1; -pub const _TIME_H: u32 = 1; -pub const _BITS_TIME_H: u32 = 1; -pub const CLOCK_REALTIME: u32 = 0; -pub const CLOCK_MONOTONIC: u32 = 1; -pub const CLOCK_PROCESS_CPUTIME_ID: u32 = 2; -pub const CLOCK_THREAD_CPUTIME_ID: u32 = 3; -pub const CLOCK_MONOTONIC_RAW: u32 = 4; -pub const CLOCK_REALTIME_COARSE: u32 = 5; -pub const CLOCK_MONOTONIC_COARSE: u32 = 6; -pub const CLOCK_BOOTTIME: u32 = 7; -pub const CLOCK_REALTIME_ALARM: u32 = 8; -pub const CLOCK_BOOTTIME_ALARM: u32 = 9; -pub const CLOCK_TAI: u32 = 11; -pub const TIMER_ABSTIME: u32 = 1; -pub const TIME_UTC: u32 = 1; -pub const _XLOCALE_H: u32 = 1; -pub const _LIBC_LIMITS_H_: u32 = 1; -pub const MB_LEN_MAX: u32 = 16; -pub const _BITS_POSIX1_LIM_H: u32 = 1; -pub const _POSIX_AIO_LISTIO_MAX: u32 = 2; -pub const _POSIX_AIO_MAX: u32 = 1; -pub const _POSIX_ARG_MAX: u32 = 4096; -pub const _POSIX_CHILD_MAX: u32 = 25; -pub const _POSIX_DELAYTIMER_MAX: u32 = 32; -pub const _POSIX_HOST_NAME_MAX: u32 = 255; -pub const _POSIX_LINK_MAX: u32 = 8; -pub const _POSIX_LOGIN_NAME_MAX: u32 = 9; -pub const _POSIX_MAX_CANON: u32 = 255; -pub const _POSIX_MAX_INPUT: u32 = 255; -pub const _POSIX_MQ_OPEN_MAX: u32 = 8; -pub const _POSIX_MQ_PRIO_MAX: u32 = 32; -pub const _POSIX_NAME_MAX: u32 = 14; -pub const _POSIX_NGROUPS_MAX: u32 = 8; -pub const _POSIX_OPEN_MAX: u32 = 20; -pub const _POSIX_PATH_MAX: u32 = 256; -pub const _POSIX_PIPE_BUF: u32 = 512; -pub const _POSIX_RE_DUP_MAX: u32 = 255; -pub const _POSIX_RTSIG_MAX: u32 = 8; -pub const _POSIX_SEM_NSEMS_MAX: u32 = 256; -pub const _POSIX_SEM_VALUE_MAX: u32 = 32767; -pub const _POSIX_SIGQUEUE_MAX: u32 = 32; -pub const _POSIX_SSIZE_MAX: u32 = 32767; -pub const _POSIX_STREAM_MAX: u32 = 8; -pub const _POSIX_SYMLINK_MAX: u32 = 255; -pub const _POSIX_SYMLOOP_MAX: u32 = 8; -pub const _POSIX_TIMER_MAX: u32 = 32; -pub const _POSIX_TTY_NAME_MAX: u32 = 9; -pub const _POSIX_TZNAME_MAX: u32 = 6; -pub const _POSIX_CLOCKRES_MIN: u32 = 20000000; -pub const NR_OPEN: u32 = 1024; -pub const NGROUPS_MAX: u32 = 65536; -pub const ARG_MAX: u32 = 131072; -pub const LINK_MAX: u32 = 127; -pub const MAX_CANON: u32 = 255; -pub const MAX_INPUT: u32 = 255; -pub const NAME_MAX: u32 = 255; -pub const PATH_MAX: u32 = 4096; -pub const PIPE_BUF: u32 = 4096; -pub const XATTR_NAME_MAX: u32 = 255; -pub const XATTR_SIZE_MAX: u32 = 65536; -pub const XATTR_LIST_MAX: u32 = 65536; -pub const RTSIG_MAX: u32 = 32; -pub const _POSIX_THREAD_KEYS_MAX: u32 = 128; -pub const PTHREAD_KEYS_MAX: u32 = 1024; -pub const _POSIX_THREAD_DESTRUCTOR_ITERATIONS: u32 = 4; -pub const PTHREAD_DESTRUCTOR_ITERATIONS: u32 = 4; -pub const _POSIX_THREAD_THREADS_MAX: u32 = 64; -pub const AIO_PRIO_DELTA_MAX: u32 = 20; -pub const PTHREAD_STACK_MIN: u32 = 16384; -pub const DELAYTIMER_MAX: u32 = 2147483647; -pub const TTY_NAME_MAX: u32 = 32; -pub const LOGIN_NAME_MAX: u32 = 256; -pub const HOST_NAME_MAX: u32 = 64; -pub const MQ_PRIO_MAX: u32 = 32768; -pub const SEM_VALUE_MAX: u32 = 2147483647; -pub const _BITS_POSIX2_LIM_H: u32 = 1; -pub const _POSIX2_BC_BASE_MAX: u32 = 99; -pub const _POSIX2_BC_DIM_MAX: u32 = 2048; -pub const _POSIX2_BC_SCALE_MAX: u32 = 99; -pub const _POSIX2_BC_STRING_MAX: u32 = 1000; -pub const _POSIX2_COLL_WEIGHTS_MAX: u32 = 2; -pub const _POSIX2_EXPR_NEST_MAX: u32 = 32; -pub const _POSIX2_LINE_MAX: u32 = 2048; -pub const _POSIX2_RE_DUP_MAX: u32 = 255; -pub const _POSIX2_CHARCLASS_NAME_MAX: u32 = 14; -pub const BC_BASE_MAX: u32 = 99; -pub const BC_DIM_MAX: u32 = 2048; -pub const BC_SCALE_MAX: u32 = 99; -pub const BC_STRING_MAX: u32 = 1000; -pub const COLL_WEIGHTS_MAX: u32 = 255; -pub const EXPR_NEST_MAX: u32 = 32; -pub const LINE_MAX: u32 = 2048; -pub const CHARCLASS_NAME_MAX: u32 = 2048; -pub const RE_DUP_MAX: u32 = 32767; -pub const LIBUSB_API_VERSION: u32 = 16777477; -pub const LIBUSBX_API_VERSION: u32 = 16777477; -pub const LIBUSB_DT_DEVICE_SIZE: u32 = 18; -pub const LIBUSB_DT_CONFIG_SIZE: u32 = 9; -pub const LIBUSB_DT_INTERFACE_SIZE: u32 = 9; -pub const LIBUSB_DT_ENDPOINT_SIZE: u32 = 7; -pub const LIBUSB_DT_ENDPOINT_AUDIO_SIZE: u32 = 9; -pub const LIBUSB_DT_HUB_NONVAR_SIZE: u32 = 7; -pub const LIBUSB_DT_SS_ENDPOINT_COMPANION_SIZE: u32 = 6; -pub const LIBUSB_DT_BOS_SIZE: u32 = 5; -pub const LIBUSB_DT_DEVICE_CAPABILITY_SIZE: u32 = 3; -pub const LIBUSB_BT_USB_2_0_EXTENSION_SIZE: u32 = 7; -pub const LIBUSB_BT_SS_USB_DEVICE_CAPABILITY_SIZE: u32 = 10; -pub const LIBUSB_BT_CONTAINER_ID_SIZE: u32 = 20; -pub const LIBUSB_DT_BOS_MAX_SIZE: u32 = 42; -pub const LIBUSB_ENDPOINT_ADDRESS_MASK: u32 = 15; -pub const LIBUSB_ENDPOINT_DIR_MASK: u32 = 128; -pub const LIBUSB_TRANSFER_TYPE_MASK: u32 = 3; -pub const LIBUSB_ISO_SYNC_TYPE_MASK: u32 = 12; -pub const LIBUSB_ISO_USAGE_TYPE_MASK: u32 = 48; -pub const LIBUSB_ERROR_COUNT: u32 = 14; -pub const LIBUSB_HOTPLUG_MATCH_ANY: i32 = -1; -pub type int_least8_t = ::std::os::raw::c_schar; -pub type int_least16_t = ::std::os::raw::c_short; -pub type int_least32_t = ::std::os::raw::c_int; -pub type int_least64_t = ::std::os::raw::c_long; -pub type uint_least8_t = ::std::os::raw::c_uchar; -pub type uint_least16_t = ::std::os::raw::c_ushort; -pub type uint_least32_t = ::std::os::raw::c_uint; -pub type uint_least64_t = ::std::os::raw::c_ulong; -pub type int_fast8_t = ::std::os::raw::c_schar; -pub type int_fast16_t = ::std::os::raw::c_long; -pub type int_fast32_t = ::std::os::raw::c_long; -pub type int_fast64_t = ::std::os::raw::c_long; -pub type uint_fast8_t = ::std::os::raw::c_uchar; -pub type uint_fast16_t = ::std::os::raw::c_ulong; -pub type uint_fast32_t = ::std::os::raw::c_ulong; -pub type uint_fast64_t = ::std::os::raw::c_ulong; -pub type intmax_t = ::std::os::raw::c_long; -pub type uintmax_t = ::std::os::raw::c_ulong; -pub type __u_char = ::std::os::raw::c_uchar; -pub type __u_short = ::std::os::raw::c_ushort; -pub type __u_int = ::std::os::raw::c_uint; -pub type __u_long = ::std::os::raw::c_ulong; -pub type __int8_t = ::std::os::raw::c_schar; -pub type __uint8_t = ::std::os::raw::c_uchar; -pub type __int16_t = ::std::os::raw::c_short; -pub type __uint16_t = ::std::os::raw::c_ushort; -pub type __int32_t = ::std::os::raw::c_int; -pub type __uint32_t = ::std::os::raw::c_uint; -pub type __int64_t = ::std::os::raw::c_long; -pub type __uint64_t = ::std::os::raw::c_ulong; -pub type __quad_t = ::std::os::raw::c_long; -pub type __u_quad_t = ::std::os::raw::c_ulong; -pub type __dev_t = ::std::os::raw::c_ulong; -pub type __uid_t = ::std::os::raw::c_uint; -pub type __gid_t = ::std::os::raw::c_uint; -pub type __ino_t = ::std::os::raw::c_ulong; -pub type __ino64_t = ::std::os::raw::c_ulong; -pub type __mode_t = ::std::os::raw::c_uint; -pub type __nlink_t = ::std::os::raw::c_ulong; -pub type __off_t = ::std::os::raw::c_long; -pub type __off64_t = ::std::os::raw::c_long; -pub type __pid_t = ::std::os::raw::c_int; -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct __fsid_t { - pub __val: [::std::os::raw::c_int; 2usize], -} -#[test] -fn bindgen_test_layout___fsid_t() { - assert_eq!( - ::std::mem::size_of::<__fsid_t>(), - 8usize, - concat!("Size of: ", stringify!(__fsid_t)) - ); - assert_eq!( - ::std::mem::align_of::<__fsid_t>(), - 4usize, - concat!("Alignment of ", stringify!(__fsid_t)) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<__fsid_t>())).__val as *const _ as usize }, - 0usize, - concat!( - "Offset of field: ", - stringify!(__fsid_t), - "::", - stringify!(__val) - ) - ); -} -pub type __clock_t = ::std::os::raw::c_long; -pub type __rlim_t = ::std::os::raw::c_ulong; -pub type __rlim64_t = ::std::os::raw::c_ulong; -pub type __id_t = ::std::os::raw::c_uint; -pub type __time_t = ::std::os::raw::c_long; -pub type __useconds_t = ::std::os::raw::c_uint; -pub type __suseconds_t = ::std::os::raw::c_long; -pub type __daddr_t = ::std::os::raw::c_int; -pub type __key_t = ::std::os::raw::c_int; -pub type __clockid_t = ::std::os::raw::c_int; -pub type __timer_t = *mut ::std::os::raw::c_void; -pub type __blksize_t = ::std::os::raw::c_long; -pub type __blkcnt_t = ::std::os::raw::c_long; -pub type __blkcnt64_t = ::std::os::raw::c_long; -pub type __fsblkcnt_t = ::std::os::raw::c_ulong; -pub type __fsblkcnt64_t = ::std::os::raw::c_ulong; -pub type __fsfilcnt_t = ::std::os::raw::c_ulong; -pub type __fsfilcnt64_t = ::std::os::raw::c_ulong; -pub type __fsword_t = ::std::os::raw::c_long; -pub type __ssize_t = ::std::os::raw::c_long; -pub type __syscall_slong_t = ::std::os::raw::c_long; -pub type __syscall_ulong_t = ::std::os::raw::c_ulong; -pub type __loff_t = __off64_t; -pub type __qaddr_t = *mut __quad_t; -pub type __caddr_t = *mut ::std::os::raw::c_char; -pub type __intptr_t = ::std::os::raw::c_long; -pub type __socklen_t = ::std::os::raw::c_uint; -pub type u_char = __u_char; -pub type u_short = __u_short; -pub type u_int = __u_int; -pub type u_long = __u_long; -pub type quad_t = __quad_t; -pub type u_quad_t = __u_quad_t; -pub type fsid_t = __fsid_t; -pub type loff_t = __loff_t; -pub type ino_t = __ino_t; -pub type dev_t = __dev_t; -pub type gid_t = __gid_t; -pub type mode_t = __mode_t; -pub type nlink_t = __nlink_t; -pub type uid_t = __uid_t; -pub type off_t = __off_t; -pub type pid_t = __pid_t; -pub type id_t = __id_t; -pub type daddr_t = __daddr_t; -pub type caddr_t = __caddr_t; -pub type key_t = __key_t; -pub type clock_t = __clock_t; -pub type time_t = __time_t; -pub type clockid_t = __clockid_t; -pub type timer_t = __timer_t; -pub type ulong = ::std::os::raw::c_ulong; -pub type ushort = ::std::os::raw::c_ushort; -pub type uint = ::std::os::raw::c_uint; -pub type u_int8_t = ::std::os::raw::c_uchar; -pub type u_int16_t = ::std::os::raw::c_ushort; -pub type u_int32_t = ::std::os::raw::c_uint; -pub type u_int64_t = ::std::os::raw::c_ulong; -pub type register_t = ::std::os::raw::c_long; -pub type __sig_atomic_t = ::std::os::raw::c_int; -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct __sigset_t { - pub __val: [::std::os::raw::c_ulong; 16usize], -} -#[test] -fn bindgen_test_layout___sigset_t() { - assert_eq!( - ::std::mem::size_of::<__sigset_t>(), - 128usize, - concat!("Size of: ", stringify!(__sigset_t)) - ); - assert_eq!( - ::std::mem::align_of::<__sigset_t>(), - 8usize, - concat!("Alignment of ", stringify!(__sigset_t)) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<__sigset_t>())).__val as *const _ as usize }, - 0usize, - concat!( - "Offset of field: ", - stringify!(__sigset_t), - "::", - stringify!(__val) - ) - ); -} -pub type sigset_t = __sigset_t; -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct timespec { - pub tv_sec: __time_t, - pub tv_nsec: __syscall_slong_t, -} -#[test] -fn bindgen_test_layout_timespec() { - assert_eq!( - ::std::mem::size_of::<timespec>(), - 16usize, - concat!("Size of: ", stringify!(timespec)) - ); - assert_eq!( - ::std::mem::align_of::<timespec>(), - 8usize, - concat!("Alignment of ", stringify!(timespec)) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<timespec>())).tv_sec as *const _ as usize }, - 0usize, - concat!( - "Offset of field: ", - stringify!(timespec), - "::", - stringify!(tv_sec) - ) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<timespec>())).tv_nsec as *const _ as usize }, - 8usize, - concat!( - "Offset of field: ", - stringify!(timespec), - "::", - stringify!(tv_nsec) - ) - ); -} -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct timeval { - pub tv_sec: __time_t, - pub tv_usec: __suseconds_t, -} -#[test] -fn bindgen_test_layout_timeval() { - assert_eq!( - ::std::mem::size_of::<timeval>(), - 16usize, - concat!("Size of: ", stringify!(timeval)) - ); - assert_eq!( - ::std::mem::align_of::<timeval>(), - 8usize, - concat!("Alignment of ", stringify!(timeval)) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<timeval>())).tv_sec as *const _ as usize }, - 0usize, - concat!( - "Offset of field: ", - stringify!(timeval), - "::", - stringify!(tv_sec) - ) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<timeval>())).tv_usec as *const _ as usize }, - 8usize, - concat!( - "Offset of field: ", - stringify!(timeval), - "::", - stringify!(tv_usec) - ) - ); -} -pub type suseconds_t = __suseconds_t; -pub type __fd_mask = ::std::os::raw::c_long; -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct fd_set { - pub __fds_bits: [__fd_mask; 16usize], -} -#[test] -fn bindgen_test_layout_fd_set() { - assert_eq!( - ::std::mem::size_of::<fd_set>(), - 128usize, - concat!("Size of: ", stringify!(fd_set)) - ); - assert_eq!( - ::std::mem::align_of::<fd_set>(), - 8usize, - concat!("Alignment of ", stringify!(fd_set)) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<fd_set>())).__fds_bits as *const _ as usize }, - 0usize, - concat!( - "Offset of field: ", - stringify!(fd_set), - "::", - stringify!(__fds_bits) - ) - ); -} -pub type fd_mask = __fd_mask; -extern "C" { - pub fn select( - __nfds: ::std::os::raw::c_int, - __readfds: *mut fd_set, - __writefds: *mut fd_set, - __exceptfds: *mut fd_set, - __timeout: *mut timeval, - ) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn pselect( - __nfds: ::std::os::raw::c_int, - __readfds: *mut fd_set, - __writefds: *mut fd_set, - __exceptfds: *mut fd_set, - __timeout: *const timespec, - __sigmask: *const __sigset_t, - ) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn gnu_dev_major(__dev: ::std::os::raw::c_ulonglong) -> ::std::os::raw::c_uint; -} -extern "C" { - pub fn gnu_dev_minor(__dev: ::std::os::raw::c_ulonglong) -> ::std::os::raw::c_uint; -} -extern "C" { - pub fn gnu_dev_makedev( - __major: ::std::os::raw::c_uint, - __minor: ::std::os::raw::c_uint, - ) -> ::std::os::raw::c_ulonglong; -} -pub type blksize_t = __blksize_t; -pub type blkcnt_t = __blkcnt_t; -pub type fsblkcnt_t = __fsblkcnt_t; -pub type fsfilcnt_t = __fsfilcnt_t; -pub type pthread_t = ::std::os::raw::c_ulong; -#[repr(C)] -#[derive(Copy, Clone)] -pub union pthread_attr_t { - pub __size: [::std::os::raw::c_char; 56usize], - pub __align: ::std::os::raw::c_long, - _bindgen_union_align: [u64; 7usize], -} -#[test] -fn bindgen_test_layout_pthread_attr_t() { - assert_eq!( - ::std::mem::size_of::<pthread_attr_t>(), - 56usize, - concat!("Size of: ", stringify!(pthread_attr_t)) - ); - assert_eq!( - ::std::mem::align_of::<pthread_attr_t>(), - 8usize, - concat!("Alignment of ", stringify!(pthread_attr_t)) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<pthread_attr_t>())).__size as *const _ as usize }, - 0usize, - concat!( - "Offset of field: ", - stringify!(pthread_attr_t), - "::", - stringify!(__size) - ) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<pthread_attr_t>())).__align as *const _ as usize }, - 0usize, - concat!( - "Offset of field: ", - stringify!(pthread_attr_t), - "::", - stringify!(__align) - ) - ); -} -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct __pthread_internal_list { - pub __prev: *mut __pthread_internal_list, - pub __next: *mut __pthread_internal_list, -} -#[test] -fn bindgen_test_layout___pthread_internal_list() { - assert_eq!( - ::std::mem::size_of::<__pthread_internal_list>(), - 16usize, - concat!("Size of: ", stringify!(__pthread_internal_list)) - ); - assert_eq!( - ::std::mem::align_of::<__pthread_internal_list>(), - 8usize, - concat!("Alignment of ", stringify!(__pthread_internal_list)) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<__pthread_internal_list>())).__prev as *const _ as usize }, - 0usize, - concat!( - "Offset of field: ", - stringify!(__pthread_internal_list), - "::", - stringify!(__prev) - ) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<__pthread_internal_list>())).__next as *const _ as usize }, - 8usize, - concat!( - "Offset of field: ", - stringify!(__pthread_internal_list), - "::", - stringify!(__next) - ) - ); -} -pub type __pthread_list_t = __pthread_internal_list; -#[repr(C)] -#[derive(Copy, Clone)] -pub union pthread_mutex_t { - pub __data: pthread_mutex_t___pthread_mutex_s, - pub __size: [::std::os::raw::c_char; 40usize], - pub __align: ::std::os::raw::c_long, - _bindgen_union_align: [u64; 5usize], -} -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct pthread_mutex_t___pthread_mutex_s { - pub __lock: ::std::os::raw::c_int, - pub __count: ::std::os::raw::c_uint, - pub __owner: ::std::os::raw::c_int, - pub __nusers: ::std::os::raw::c_uint, - pub __kind: ::std::os::raw::c_int, - pub __spins: ::std::os::raw::c_short, - pub __elision: ::std::os::raw::c_short, - pub __list: __pthread_list_t, -} -#[test] -fn bindgen_test_layout_pthread_mutex_t___pthread_mutex_s() { - assert_eq!( - ::std::mem::size_of::<pthread_mutex_t___pthread_mutex_s>(), - 40usize, - concat!("Size of: ", stringify!(pthread_mutex_t___pthread_mutex_s)) - ); - assert_eq!( - ::std::mem::align_of::<pthread_mutex_t___pthread_mutex_s>(), - 8usize, - concat!( - "Alignment of ", - stringify!(pthread_mutex_t___pthread_mutex_s) - ) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::<pthread_mutex_t___pthread_mutex_s>())).__lock as *const _ - as usize - }, - 0usize, - concat!( - "Offset of field: ", - stringify!(pthread_mutex_t___pthread_mutex_s), - "::", - stringify!(__lock) - ) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::<pthread_mutex_t___pthread_mutex_s>())).__count as *const _ - as usize - }, - 4usize, - concat!( - "Offset of field: ", - stringify!(pthread_mutex_t___pthread_mutex_s), - "::", - stringify!(__count) - ) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::<pthread_mutex_t___pthread_mutex_s>())).__owner as *const _ - as usize - }, - 8usize, - concat!( - "Offset of field: ", - stringify!(pthread_mutex_t___pthread_mutex_s), - "::", - stringify!(__owner) - ) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::<pthread_mutex_t___pthread_mutex_s>())).__nusers as *const _ - as usize - }, - 12usize, - concat!( - "Offset of field: ", - stringify!(pthread_mutex_t___pthread_mutex_s), - "::", - stringify!(__nusers) - ) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::<pthread_mutex_t___pthread_mutex_s>())).__kind as *const _ - as usize - }, - 16usize, - concat!( - "Offset of field: ", - stringify!(pthread_mutex_t___pthread_mutex_s), - "::", - stringify!(__kind) - ) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::<pthread_mutex_t___pthread_mutex_s>())).__spins as *const _ - as usize - }, - 20usize, - concat!( - "Offset of field: ", - stringify!(pthread_mutex_t___pthread_mutex_s), - "::", - stringify!(__spins) - ) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::<pthread_mutex_t___pthread_mutex_s>())).__elision as *const _ - as usize - }, - 22usize, - concat!( - "Offset of field: ", - stringify!(pthread_mutex_t___pthread_mutex_s), - "::", - stringify!(__elision) - ) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::<pthread_mutex_t___pthread_mutex_s>())).__list as *const _ - as usize - }, - 24usize, - concat!( - "Offset of field: ", - stringify!(pthread_mutex_t___pthread_mutex_s), - "::", - stringify!(__list) - ) - ); -} -#[test] -fn bindgen_test_layout_pthread_mutex_t() { - assert_eq!( - ::std::mem::size_of::<pthread_mutex_t>(), - 40usize, - concat!("Size of: ", stringify!(pthread_mutex_t)) - ); - assert_eq!( - ::std::mem::align_of::<pthread_mutex_t>(), - 8usize, - concat!("Alignment of ", stringify!(pthread_mutex_t)) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<pthread_mutex_t>())).__data as *const _ as usize }, - 0usize, - concat!( - "Offset of field: ", - stringify!(pthread_mutex_t), - "::", - stringify!(__data) - ) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<pthread_mutex_t>())).__size as *const _ as usize }, - 0usize, - concat!( - "Offset of field: ", - stringify!(pthread_mutex_t), - "::", - stringify!(__size) - ) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<pthread_mutex_t>())).__align as *const _ as usize }, - 0usize, - concat!( - "Offset of field: ", - stringify!(pthread_mutex_t), - "::", - stringify!(__align) - ) - ); -} -#[repr(C)] -#[derive(Copy, Clone)] -pub union pthread_mutexattr_t { - pub __size: [::std::os::raw::c_char; 4usize], - pub __align: ::std::os::raw::c_int, - _bindgen_union_align: u32, -} -#[test] -fn bindgen_test_layout_pthread_mutexattr_t() { - assert_eq!( - ::std::mem::size_of::<pthread_mutexattr_t>(), - 4usize, - concat!("Size of: ", stringify!(pthread_mutexattr_t)) - ); - assert_eq!( - ::std::mem::align_of::<pthread_mutexattr_t>(), - 4usize, - concat!("Alignment of ", stringify!(pthread_mutexattr_t)) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<pthread_mutexattr_t>())).__size as *const _ as usize }, - 0usize, - concat!( - "Offset of field: ", - stringify!(pthread_mutexattr_t), - "::", - stringify!(__size) - ) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<pthread_mutexattr_t>())).__align as *const _ as usize }, - 0usize, - concat!( - "Offset of field: ", - stringify!(pthread_mutexattr_t), - "::", - stringify!(__align) - ) - ); -} -#[repr(C)] -#[derive(Copy, Clone)] -pub union pthread_cond_t { - pub __data: pthread_cond_t__bindgen_ty_1, - pub __size: [::std::os::raw::c_char; 48usize], - pub __align: ::std::os::raw::c_longlong, - _bindgen_union_align: [u64; 6usize], -} -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct pthread_cond_t__bindgen_ty_1 { - pub __lock: ::std::os::raw::c_int, - pub __futex: ::std::os::raw::c_uint, - pub __total_seq: ::std::os::raw::c_ulonglong, - pub __wakeup_seq: ::std::os::raw::c_ulonglong, - pub __woken_seq: ::std::os::raw::c_ulonglong, - pub __mutex: *mut ::std::os::raw::c_void, - pub __nwaiters: ::std::os::raw::c_uint, - pub __broadcast_seq: ::std::os::raw::c_uint, -} -#[test] -fn bindgen_test_layout_pthread_cond_t__bindgen_ty_1() { - assert_eq!( - ::std::mem::size_of::<pthread_cond_t__bindgen_ty_1>(), - 48usize, - concat!("Size of: ", stringify!(pthread_cond_t__bindgen_ty_1)) - ); - assert_eq!( - ::std::mem::align_of::<pthread_cond_t__bindgen_ty_1>(), - 8usize, - concat!("Alignment of ", stringify!(pthread_cond_t__bindgen_ty_1)) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::<pthread_cond_t__bindgen_ty_1>())).__lock as *const _ as usize - }, - 0usize, - concat!( - "Offset of field: ", - stringify!(pthread_cond_t__bindgen_ty_1), - "::", - stringify!(__lock) - ) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::<pthread_cond_t__bindgen_ty_1>())).__futex as *const _ as usize - }, - 4usize, - concat!( - "Offset of field: ", - stringify!(pthread_cond_t__bindgen_ty_1), - "::", - stringify!(__futex) - ) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::<pthread_cond_t__bindgen_ty_1>())).__total_seq as *const _ - as usize - }, - 8usize, - concat!( - "Offset of field: ", - stringify!(pthread_cond_t__bindgen_ty_1), - "::", - stringify!(__total_seq) - ) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::<pthread_cond_t__bindgen_ty_1>())).__wakeup_seq as *const _ - as usize - }, - 16usize, - concat!( - "Offset of field: ", - stringify!(pthread_cond_t__bindgen_ty_1), - "::", - stringify!(__wakeup_seq) - ) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::<pthread_cond_t__bindgen_ty_1>())).__woken_seq as *const _ - as usize - }, - 24usize, - concat!( - "Offset of field: ", - stringify!(pthread_cond_t__bindgen_ty_1), - "::", - stringify!(__woken_seq) - ) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::<pthread_cond_t__bindgen_ty_1>())).__mutex as *const _ as usize - }, - 32usize, - concat!( - "Offset of field: ", - stringify!(pthread_cond_t__bindgen_ty_1), - "::", - stringify!(__mutex) - ) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::<pthread_cond_t__bindgen_ty_1>())).__nwaiters as *const _ as usize - }, - 40usize, - concat!( - "Offset of field: ", - stringify!(pthread_cond_t__bindgen_ty_1), - "::", - stringify!(__nwaiters) - ) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::<pthread_cond_t__bindgen_ty_1>())).__broadcast_seq as *const _ - as usize - }, - 44usize, - concat!( - "Offset of field: ", - stringify!(pthread_cond_t__bindgen_ty_1), - "::", - stringify!(__broadcast_seq) - ) - ); -} -#[test] -fn bindgen_test_layout_pthread_cond_t() { - assert_eq!( - ::std::mem::size_of::<pthread_cond_t>(), - 48usize, - concat!("Size of: ", stringify!(pthread_cond_t)) - ); - assert_eq!( - ::std::mem::align_of::<pthread_cond_t>(), - 8usize, - concat!("Alignment of ", stringify!(pthread_cond_t)) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<pthread_cond_t>())).__data as *const _ as usize }, - 0usize, - concat!( - "Offset of field: ", - stringify!(pthread_cond_t), - "::", - stringify!(__data) - ) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<pthread_cond_t>())).__size as *const _ as usize }, - 0usize, - concat!( - "Offset of field: ", - stringify!(pthread_cond_t), - "::", - stringify!(__size) - ) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<pthread_cond_t>())).__align as *const _ as usize }, - 0usize, - concat!( - "Offset of field: ", - stringify!(pthread_cond_t), - "::", - stringify!(__align) - ) - ); -} -#[repr(C)] -#[derive(Copy, Clone)] -pub union pthread_condattr_t { - pub __size: [::std::os::raw::c_char; 4usize], - pub __align: ::std::os::raw::c_int, - _bindgen_union_align: u32, -} -#[test] -fn bindgen_test_layout_pthread_condattr_t() { - assert_eq!( - ::std::mem::size_of::<pthread_condattr_t>(), - 4usize, - concat!("Size of: ", stringify!(pthread_condattr_t)) - ); - assert_eq!( - ::std::mem::align_of::<pthread_condattr_t>(), - 4usize, - concat!("Alignment of ", stringify!(pthread_condattr_t)) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<pthread_condattr_t>())).__size as *const _ as usize }, - 0usize, - concat!( - "Offset of field: ", - stringify!(pthread_condattr_t), - "::", - stringify!(__size) - ) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<pthread_condattr_t>())).__align as *const _ as usize }, - 0usize, - concat!( - "Offset of field: ", - stringify!(pthread_condattr_t), - "::", - stringify!(__align) - ) - ); -} -pub type pthread_key_t = ::std::os::raw::c_uint; -pub type pthread_once_t = ::std::os::raw::c_int; -#[repr(C)] -#[derive(Copy, Clone)] -pub union pthread_rwlock_t { - pub __data: pthread_rwlock_t__bindgen_ty_1, - pub __size: [::std::os::raw::c_char; 56usize], - pub __align: ::std::os::raw::c_long, - _bindgen_union_align: [u64; 7usize], -} -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct pthread_rwlock_t__bindgen_ty_1 { - pub __lock: ::std::os::raw::c_int, - pub __nr_readers: ::std::os::raw::c_uint, - pub __readers_wakeup: ::std::os::raw::c_uint, - pub __writer_wakeup: ::std::os::raw::c_uint, - pub __nr_readers_queued: ::std::os::raw::c_uint, - pub __nr_writers_queued: ::std::os::raw::c_uint, - pub __writer: ::std::os::raw::c_int, - pub __shared: ::std::os::raw::c_int, - pub __rwelision: ::std::os::raw::c_schar, - pub __pad1: [::std::os::raw::c_uchar; 7usize], - pub __pad2: ::std::os::raw::c_ulong, - pub __flags: ::std::os::raw::c_uint, -} -#[test] -fn bindgen_test_layout_pthread_rwlock_t__bindgen_ty_1() { - assert_eq!( - ::std::mem::size_of::<pthread_rwlock_t__bindgen_ty_1>(), - 56usize, - concat!("Size of: ", stringify!(pthread_rwlock_t__bindgen_ty_1)) - ); - assert_eq!( - ::std::mem::align_of::<pthread_rwlock_t__bindgen_ty_1>(), - 8usize, - concat!("Alignment of ", stringify!(pthread_rwlock_t__bindgen_ty_1)) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::<pthread_rwlock_t__bindgen_ty_1>())).__lock as *const _ as usize - }, - 0usize, - concat!( - "Offset of field: ", - stringify!(pthread_rwlock_t__bindgen_ty_1), - "::", - stringify!(__lock) - ) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::<pthread_rwlock_t__bindgen_ty_1>())).__nr_readers as *const _ - as usize - }, - 4usize, - concat!( - "Offset of field: ", - stringify!(pthread_rwlock_t__bindgen_ty_1), - "::", - stringify!(__nr_readers) - ) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::<pthread_rwlock_t__bindgen_ty_1>())).__readers_wakeup as *const _ - as usize - }, - 8usize, - concat!( - "Offset of field: ", - stringify!(pthread_rwlock_t__bindgen_ty_1), - "::", - stringify!(__readers_wakeup) - ) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::<pthread_rwlock_t__bindgen_ty_1>())).__writer_wakeup as *const _ - as usize - }, - 12usize, - concat!( - "Offset of field: ", - stringify!(pthread_rwlock_t__bindgen_ty_1), - "::", - stringify!(__writer_wakeup) - ) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::<pthread_rwlock_t__bindgen_ty_1>())).__nr_readers_queued - as *const _ as usize - }, - 16usize, - concat!( - "Offset of field: ", - stringify!(pthread_rwlock_t__bindgen_ty_1), - "::", - stringify!(__nr_readers_queued) - ) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::<pthread_rwlock_t__bindgen_ty_1>())).__nr_writers_queued - as *const _ as usize - }, - 20usize, - concat!( - "Offset of field: ", - stringify!(pthread_rwlock_t__bindgen_ty_1), - "::", - stringify!(__nr_writers_queued) - ) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::<pthread_rwlock_t__bindgen_ty_1>())).__writer as *const _ as usize - }, - 24usize, - concat!( - "Offset of field: ", - stringify!(pthread_rwlock_t__bindgen_ty_1), - "::", - stringify!(__writer) - ) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::<pthread_rwlock_t__bindgen_ty_1>())).__shared as *const _ as usize - }, - 28usize, - concat!( - "Offset of field: ", - stringify!(pthread_rwlock_t__bindgen_ty_1), - "::", - stringify!(__shared) - ) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::<pthread_rwlock_t__bindgen_ty_1>())).__rwelision as *const _ - as usize - }, - 32usize, - concat!( - "Offset of field: ", - stringify!(pthread_rwlock_t__bindgen_ty_1), - "::", - stringify!(__rwelision) - ) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::<pthread_rwlock_t__bindgen_ty_1>())).__pad1 as *const _ as usize - }, - 33usize, - concat!( - "Offset of field: ", - stringify!(pthread_rwlock_t__bindgen_ty_1), - "::", - stringify!(__pad1) - ) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::<pthread_rwlock_t__bindgen_ty_1>())).__pad2 as *const _ as usize - }, - 40usize, - concat!( - "Offset of field: ", - stringify!(pthread_rwlock_t__bindgen_ty_1), - "::", - stringify!(__pad2) - ) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::<pthread_rwlock_t__bindgen_ty_1>())).__flags as *const _ as usize - }, - 48usize, - concat!( - "Offset of field: ", - stringify!(pthread_rwlock_t__bindgen_ty_1), - "::", - stringify!(__flags) - ) - ); -} -#[test] -fn bindgen_test_layout_pthread_rwlock_t() { - assert_eq!( - ::std::mem::size_of::<pthread_rwlock_t>(), - 56usize, - concat!("Size of: ", stringify!(pthread_rwlock_t)) - ); - assert_eq!( - ::std::mem::align_of::<pthread_rwlock_t>(), - 8usize, - concat!("Alignment of ", stringify!(pthread_rwlock_t)) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<pthread_rwlock_t>())).__data as *const _ as usize }, - 0usize, - concat!( - "Offset of field: ", - stringify!(pthread_rwlock_t), - "::", - stringify!(__data) - ) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<pthread_rwlock_t>())).__size as *const _ as usize }, - 0usize, - concat!( - "Offset of field: ", - stringify!(pthread_rwlock_t), - "::", - stringify!(__size) - ) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<pthread_rwlock_t>())).__align as *const _ as usize }, - 0usize, - concat!( - "Offset of field: ", - stringify!(pthread_rwlock_t), - "::", - stringify!(__align) - ) - ); -} -#[repr(C)] -#[derive(Copy, Clone)] -pub union pthread_rwlockattr_t { - pub __size: [::std::os::raw::c_char; 8usize], - pub __align: ::std::os::raw::c_long, - _bindgen_union_align: u64, -} -#[test] -fn bindgen_test_layout_pthread_rwlockattr_t() { - assert_eq!( - ::std::mem::size_of::<pthread_rwlockattr_t>(), - 8usize, - concat!("Size of: ", stringify!(pthread_rwlockattr_t)) - ); - assert_eq!( - ::std::mem::align_of::<pthread_rwlockattr_t>(), - 8usize, - concat!("Alignment of ", stringify!(pthread_rwlockattr_t)) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<pthread_rwlockattr_t>())).__size as *const _ as usize }, - 0usize, - concat!( - "Offset of field: ", - stringify!(pthread_rwlockattr_t), - "::", - stringify!(__size) - ) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<pthread_rwlockattr_t>())).__align as *const _ as usize }, - 0usize, - concat!( - "Offset of field: ", - stringify!(pthread_rwlockattr_t), - "::", - stringify!(__align) - ) - ); -} -pub type pthread_spinlock_t = ::std::os::raw::c_int; -#[repr(C)] -#[derive(Copy, Clone)] -pub union pthread_barrier_t { - pub __size: [::std::os::raw::c_char; 32usize], - pub __align: ::std::os::raw::c_long, - _bindgen_union_align: [u64; 4usize], -} -#[test] -fn bindgen_test_layout_pthread_barrier_t() { - assert_eq!( - ::std::mem::size_of::<pthread_barrier_t>(), - 32usize, - concat!("Size of: ", stringify!(pthread_barrier_t)) - ); - assert_eq!( - ::std::mem::align_of::<pthread_barrier_t>(), - 8usize, - concat!("Alignment of ", stringify!(pthread_barrier_t)) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<pthread_barrier_t>())).__size as *const _ as usize }, - 0usize, - concat!( - "Offset of field: ", - stringify!(pthread_barrier_t), - "::", - stringify!(__size) - ) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<pthread_barrier_t>())).__align as *const _ as usize }, - 0usize, - concat!( - "Offset of field: ", - stringify!(pthread_barrier_t), - "::", - stringify!(__align) - ) - ); -} -#[repr(C)] -#[derive(Copy, Clone)] -pub union pthread_barrierattr_t { - pub __size: [::std::os::raw::c_char; 4usize], - pub __align: ::std::os::raw::c_int, - _bindgen_union_align: u32, -} -#[test] -fn bindgen_test_layout_pthread_barrierattr_t() { - assert_eq!( - ::std::mem::size_of::<pthread_barrierattr_t>(), - 4usize, - concat!("Size of: ", stringify!(pthread_barrierattr_t)) - ); - assert_eq!( - ::std::mem::align_of::<pthread_barrierattr_t>(), - 4usize, - concat!("Alignment of ", stringify!(pthread_barrierattr_t)) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<pthread_barrierattr_t>())).__size as *const _ as usize }, - 0usize, - concat!( - "Offset of field: ", - stringify!(pthread_barrierattr_t), - "::", - stringify!(__size) - ) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<pthread_barrierattr_t>())).__align as *const _ as usize }, - 0usize, - concat!( - "Offset of field: ", - stringify!(pthread_barrierattr_t), - "::", - stringify!(__align) - ) - ); -} -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct timezone { - pub tz_minuteswest: ::std::os::raw::c_int, - pub tz_dsttime: ::std::os::raw::c_int, -} -#[test] -fn bindgen_test_layout_timezone() { - assert_eq!( - ::std::mem::size_of::<timezone>(), - 8usize, - concat!("Size of: ", stringify!(timezone)) - ); - assert_eq!( - ::std::mem::align_of::<timezone>(), - 4usize, - concat!("Alignment of ", stringify!(timezone)) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<timezone>())).tz_minuteswest as *const _ as usize }, - 0usize, - concat!( - "Offset of field: ", - stringify!(timezone), - "::", - stringify!(tz_minuteswest) - ) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<timezone>())).tz_dsttime as *const _ as usize }, - 4usize, - concat!( - "Offset of field: ", - stringify!(timezone), - "::", - stringify!(tz_dsttime) - ) - ); -} -pub type __timezone_ptr_t = *mut timezone; -extern "C" { - pub fn gettimeofday(__tv: *mut timeval, __tz: __timezone_ptr_t) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn settimeofday(__tv: *const timeval, __tz: *const timezone) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn adjtime(__delta: *const timeval, __olddelta: *mut timeval) -> ::std::os::raw::c_int; -} -pub const ITIMER_REAL: __itimer_which = 0; -pub const ITIMER_VIRTUAL: __itimer_which = 1; -pub const ITIMER_PROF: __itimer_which = 2; -pub type __itimer_which = u32; -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct itimerval { - pub it_interval: timeval, - pub it_value: timeval, -} -#[test] -fn bindgen_test_layout_itimerval() { - assert_eq!( - ::std::mem::size_of::<itimerval>(), - 32usize, - concat!("Size of: ", stringify!(itimerval)) - ); - assert_eq!( - ::std::mem::align_of::<itimerval>(), - 8usize, - concat!("Alignment of ", stringify!(itimerval)) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<itimerval>())).it_interval as *const _ as usize }, - 0usize, - concat!( - "Offset of field: ", - stringify!(itimerval), - "::", - stringify!(it_interval) - ) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<itimerval>())).it_value as *const _ as usize }, - 16usize, - concat!( - "Offset of field: ", - stringify!(itimerval), - "::", - stringify!(it_value) - ) - ); -} -pub type __itimer_which_t = ::std::os::raw::c_int; -extern "C" { - pub fn getitimer(__which: __itimer_which_t, __value: *mut itimerval) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn setitimer( - __which: __itimer_which_t, - __new: *const itimerval, - __old: *mut itimerval, - ) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn utimes( - __file: *const ::std::os::raw::c_char, - __tvp: *const timeval, - ) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn lutimes( - __file: *const ::std::os::raw::c_char, - __tvp: *const timeval, - ) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn futimes(__fd: ::std::os::raw::c_int, __tvp: *const timeval) -> ::std::os::raw::c_int; -} -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct tm { - pub tm_sec: ::std::os::raw::c_int, - pub tm_min: ::std::os::raw::c_int, - pub tm_hour: ::std::os::raw::c_int, - pub tm_mday: ::std::os::raw::c_int, - pub tm_mon: ::std::os::raw::c_int, - pub tm_year: ::std::os::raw::c_int, - pub tm_wday: ::std::os::raw::c_int, - pub tm_yday: ::std::os::raw::c_int, - pub tm_isdst: ::std::os::raw::c_int, - pub tm_gmtoff: ::std::os::raw::c_long, - pub tm_zone: *const ::std::os::raw::c_char, -} -#[test] -fn bindgen_test_layout_tm() { - assert_eq!( - ::std::mem::size_of::<tm>(), - 56usize, - concat!("Size of: ", stringify!(tm)) - ); - assert_eq!( - ::std::mem::align_of::<tm>(), - 8usize, - concat!("Alignment of ", stringify!(tm)) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<tm>())).tm_sec as *const _ as usize }, - 0usize, - concat!( - "Offset of field: ", - stringify!(tm), - "::", - stringify!(tm_sec) - ) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<tm>())).tm_min as *const _ as usize }, - 4usize, - concat!( - "Offset of field: ", - stringify!(tm), - "::", - stringify!(tm_min) - ) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<tm>())).tm_hour as *const _ as usize }, - 8usize, - concat!( - "Offset of field: ", - stringify!(tm), - "::", - stringify!(tm_hour) - ) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<tm>())).tm_mday as *const _ as usize }, - 12usize, - concat!( - "Offset of field: ", - stringify!(tm), - "::", - stringify!(tm_mday) - ) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<tm>())).tm_mon as *const _ as usize }, - 16usize, - concat!( - "Offset of field: ", - stringify!(tm), - "::", - stringify!(tm_mon) - ) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<tm>())).tm_year as *const _ as usize }, - 20usize, - concat!( - "Offset of field: ", - stringify!(tm), - "::", - stringify!(tm_year) - ) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<tm>())).tm_wday as *const _ as usize }, - 24usize, - concat!( - "Offset of field: ", - stringify!(tm), - "::", - stringify!(tm_wday) - ) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<tm>())).tm_yday as *const _ as usize }, - 28usize, - concat!( - "Offset of field: ", - stringify!(tm), - "::", - stringify!(tm_yday) - ) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<tm>())).tm_isdst as *const _ as usize }, - 32usize, - concat!( - "Offset of field: ", - stringify!(tm), - "::", - stringify!(tm_isdst) - ) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<tm>())).tm_gmtoff as *const _ as usize }, - 40usize, - concat!( - "Offset of field: ", - stringify!(tm), - "::", - stringify!(tm_gmtoff) - ) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<tm>())).tm_zone as *const _ as usize }, - 48usize, - concat!( - "Offset of field: ", - stringify!(tm), - "::", - stringify!(tm_zone) - ) - ); -} -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct itimerspec { - pub it_interval: timespec, - pub it_value: timespec, -} -#[test] -fn bindgen_test_layout_itimerspec() { - assert_eq!( - ::std::mem::size_of::<itimerspec>(), - 32usize, - concat!("Size of: ", stringify!(itimerspec)) - ); - assert_eq!( - ::std::mem::align_of::<itimerspec>(), - 8usize, - concat!("Alignment of ", stringify!(itimerspec)) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<itimerspec>())).it_interval as *const _ as usize }, - 0usize, - concat!( - "Offset of field: ", - stringify!(itimerspec), - "::", - stringify!(it_interval) - ) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<itimerspec>())).it_value as *const _ as usize }, - 16usize, - concat!( - "Offset of field: ", - stringify!(itimerspec), - "::", - stringify!(it_value) - ) - ); -} -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct sigevent { - _unused: [u8; 0], -} -extern "C" { - pub fn clock() -> clock_t; -} -extern "C" { - pub fn time(__timer: *mut time_t) -> time_t; -} -extern "C" { - pub fn difftime(__time1: time_t, __time0: time_t) -> f64; -} -extern "C" { - pub fn mktime(__tp: *mut tm) -> time_t; -} -extern "C" { - pub fn strftime( - __s: *mut ::std::os::raw::c_char, - __maxsize: usize, - __format: *const ::std::os::raw::c_char, - __tp: *const tm, - ) -> usize; -} -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct __locale_struct { - pub __locales: [*mut __locale_data; 13usize], - pub __ctype_b: *const ::std::os::raw::c_ushort, - pub __ctype_tolower: *const ::std::os::raw::c_int, - pub __ctype_toupper: *const ::std::os::raw::c_int, - pub __names: [*const ::std::os::raw::c_char; 13usize], -} -#[test] -fn bindgen_test_layout___locale_struct() { - assert_eq!( - ::std::mem::size_of::<__locale_struct>(), - 232usize, - concat!("Size of: ", stringify!(__locale_struct)) - ); - assert_eq!( - ::std::mem::align_of::<__locale_struct>(), - 8usize, - concat!("Alignment of ", stringify!(__locale_struct)) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<__locale_struct>())).__locales as *const _ as usize }, - 0usize, - concat!( - "Offset of field: ", - stringify!(__locale_struct), - "::", - stringify!(__locales) - ) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<__locale_struct>())).__ctype_b as *const _ as usize }, - 104usize, - concat!( - "Offset of field: ", - stringify!(__locale_struct), - "::", - stringify!(__ctype_b) - ) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<__locale_struct>())).__ctype_tolower as *const _ as usize }, - 112usize, - concat!( - "Offset of field: ", - stringify!(__locale_struct), - "::", - stringify!(__ctype_tolower) - ) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<__locale_struct>())).__ctype_toupper as *const _ as usize }, - 120usize, - concat!( - "Offset of field: ", - stringify!(__locale_struct), - "::", - stringify!(__ctype_toupper) - ) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<__locale_struct>())).__names as *const _ as usize }, - 128usize, - concat!( - "Offset of field: ", - stringify!(__locale_struct), - "::", - stringify!(__names) - ) - ); -} -pub type __locale_t = *mut __locale_struct; -pub type locale_t = __locale_t; -extern "C" { - pub fn strftime_l( - __s: *mut ::std::os::raw::c_char, - __maxsize: usize, - __format: *const ::std::os::raw::c_char, - __tp: *const tm, - __loc: __locale_t, - ) -> usize; -} -extern "C" { - pub fn gmtime(__timer: *const time_t) -> *mut tm; -} -extern "C" { - pub fn localtime(__timer: *const time_t) -> *mut tm; -} -extern "C" { - pub fn gmtime_r(__timer: *const time_t, __tp: *mut tm) -> *mut tm; -} -extern "C" { - pub fn localtime_r(__timer: *const time_t, __tp: *mut tm) -> *mut tm; -} -extern "C" { - pub fn asctime(__tp: *const tm) -> *mut ::std::os::raw::c_char; -} -extern "C" { - pub fn ctime(__timer: *const time_t) -> *mut ::std::os::raw::c_char; -} -extern "C" { - pub fn asctime_r( - __tp: *const tm, - __buf: *mut ::std::os::raw::c_char, - ) -> *mut ::std::os::raw::c_char; -} -extern "C" { - pub fn ctime_r( - __timer: *const time_t, - __buf: *mut ::std::os::raw::c_char, - ) -> *mut ::std::os::raw::c_char; -} -extern "C" { - #[link_name = "\u{1}__tzname"] - pub static mut __tzname: [*mut ::std::os::raw::c_char; 2usize]; -} -extern "C" { - #[link_name = "\u{1}__daylight"] - pub static mut __daylight: ::std::os::raw::c_int; -} -extern "C" { - #[link_name = "\u{1}__timezone"] - pub static mut __timezone: ::std::os::raw::c_long; -} -extern "C" { - #[link_name = "\u{1}tzname"] - pub static mut tzname: [*mut ::std::os::raw::c_char; 2usize]; -} -extern "C" { - pub fn tzset(); -} -extern "C" { - #[link_name = "\u{1}daylight"] - pub static mut daylight: ::std::os::raw::c_int; -} -extern "C" { - #[link_name = "\u{1}timezone"] - pub static mut timezone: ::std::os::raw::c_long; -} -extern "C" { - pub fn stime(__when: *const time_t) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn timegm(__tp: *mut tm) -> time_t; -} -extern "C" { - pub fn timelocal(__tp: *mut tm) -> time_t; -} -extern "C" { - pub fn dysize(__year: ::std::os::raw::c_int) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn nanosleep( - __requested_time: *const timespec, - __remaining: *mut timespec, - ) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn clock_getres(__clock_id: clockid_t, __res: *mut timespec) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn clock_gettime(__clock_id: clockid_t, __tp: *mut timespec) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn clock_settime(__clock_id: clockid_t, __tp: *const timespec) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn clock_nanosleep( - __clock_id: clockid_t, - __flags: ::std::os::raw::c_int, - __req: *const timespec, - __rem: *mut timespec, - ) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn clock_getcpuclockid(__pid: pid_t, __clock_id: *mut clockid_t) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn timer_create( - __clock_id: clockid_t, - __evp: *mut sigevent, - __timerid: *mut timer_t, - ) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn timer_delete(__timerid: timer_t) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn timer_settime( - __timerid: timer_t, - __flags: ::std::os::raw::c_int, - __value: *const itimerspec, - __ovalue: *mut itimerspec, - ) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn timer_gettime(__timerid: timer_t, __value: *mut itimerspec) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn timer_getoverrun(__timerid: timer_t) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn timespec_get( - __ts: *mut timespec, - __base: ::std::os::raw::c_int, - ) -> ::std::os::raw::c_int; -} -/// In the context of a \ref libusb_device_descriptor "device descriptor", -/// this bDeviceClass value indicates that each interface specifies its -/// own class information and all interfaces operate independently. -pub const LIBUSB_CLASS_PER_INTERFACE: libusb_class_code = 0; -/// Audio class -pub const LIBUSB_CLASS_AUDIO: libusb_class_code = 1; -/// Communications class -pub const LIBUSB_CLASS_COMM: libusb_class_code = 2; -/// Human Interface Device class -pub const LIBUSB_CLASS_HID: libusb_class_code = 3; -/// Physical -pub const LIBUSB_CLASS_PHYSICAL: libusb_class_code = 5; -/// Printer class -pub const LIBUSB_CLASS_PRINTER: libusb_class_code = 7; -/// Image class -pub const LIBUSB_CLASS_PTP: libusb_class_code = 6; -/// Image class -pub const LIBUSB_CLASS_IMAGE: libusb_class_code = 6; -/// Mass storage class -pub const LIBUSB_CLASS_MASS_STORAGE: libusb_class_code = 8; -/// Hub class -pub const LIBUSB_CLASS_HUB: libusb_class_code = 9; -/// Data class -pub const LIBUSB_CLASS_DATA: libusb_class_code = 10; -/// Smart Card -pub const LIBUSB_CLASS_SMART_CARD: libusb_class_code = 11; -/// Content Security -pub const LIBUSB_CLASS_CONTENT_SECURITY: libusb_class_code = 13; -/// Video -pub const LIBUSB_CLASS_VIDEO: libusb_class_code = 14; -/// Personal Healthcare -pub const LIBUSB_CLASS_PERSONAL_HEALTHCARE: libusb_class_code = 15; -/// Diagnostic Device -pub const LIBUSB_CLASS_DIAGNOSTIC_DEVICE: libusb_class_code = 220; -/// Wireless class -pub const LIBUSB_CLASS_WIRELESS: libusb_class_code = 224; -/// Application class -pub const LIBUSB_CLASS_APPLICATION: libusb_class_code = 254; -/// Class is vendor-specific -pub const LIBUSB_CLASS_VENDOR_SPEC: libusb_class_code = 255; -/// \ingroup libusb_desc -/// Device and/or Interface Class codes -pub type libusb_class_code = u32; -/// Device descriptor. See libusb_device_descriptor. -pub const LIBUSB_DT_DEVICE: libusb_descriptor_type = 1; -/// Configuration descriptor. See libusb_config_descriptor. -pub const LIBUSB_DT_CONFIG: libusb_descriptor_type = 2; -/// String descriptor -pub const LIBUSB_DT_STRING: libusb_descriptor_type = 3; -/// Interface descriptor. See libusb_interface_descriptor. -pub const LIBUSB_DT_INTERFACE: libusb_descriptor_type = 4; -/// Endpoint descriptor. See libusb_endpoint_descriptor. -pub const LIBUSB_DT_ENDPOINT: libusb_descriptor_type = 5; -/// BOS descriptor -pub const LIBUSB_DT_BOS: libusb_descriptor_type = 15; -/// Device Capability descriptor -pub const LIBUSB_DT_DEVICE_CAPABILITY: libusb_descriptor_type = 16; -/// HID descriptor -pub const LIBUSB_DT_HID: libusb_descriptor_type = 33; -/// HID report descriptor -pub const LIBUSB_DT_REPORT: libusb_descriptor_type = 34; -/// Physical descriptor -pub const LIBUSB_DT_PHYSICAL: libusb_descriptor_type = 35; -/// Hub descriptor -pub const LIBUSB_DT_HUB: libusb_descriptor_type = 41; -/// SuperSpeed Hub descriptor -pub const LIBUSB_DT_SUPERSPEED_HUB: libusb_descriptor_type = 42; -/// SuperSpeed Endpoint Companion descriptor -pub const LIBUSB_DT_SS_ENDPOINT_COMPANION: libusb_descriptor_type = 48; -/// \ingroup libusb_desc -/// Descriptor types as defined by the USB specification. -pub type libusb_descriptor_type = u32; -/// In: device-to-host -pub const LIBUSB_ENDPOINT_IN: libusb_endpoint_direction = 128; -/// Out: host-to-device -pub const LIBUSB_ENDPOINT_OUT: libusb_endpoint_direction = 0; -/// \ingroup libusb_desc -/// Endpoint direction. Values for bit 7 of the -/// \ref libusb_endpoint_descriptor::bEndpointAddress "endpoint address" scheme. -pub type libusb_endpoint_direction = u32; -/// Control endpoint -pub const LIBUSB_TRANSFER_TYPE_CONTROL: libusb_transfer_type = 0; -/// Isochronous endpoint -pub const LIBUSB_TRANSFER_TYPE_ISOCHRONOUS: libusb_transfer_type = 1; -/// Bulk endpoint -pub const LIBUSB_TRANSFER_TYPE_BULK: libusb_transfer_type = 2; -/// Interrupt endpoint -pub const LIBUSB_TRANSFER_TYPE_INTERRUPT: libusb_transfer_type = 3; -/// Stream endpoint -pub const LIBUSB_TRANSFER_TYPE_BULK_STREAM: libusb_transfer_type = 4; -/// \ingroup libusb_desc -/// Endpoint transfer type. Values for bits 0:1 of the -/// \ref libusb_endpoint_descriptor::bmAttributes "endpoint attributes" field. -pub type libusb_transfer_type = u32; -/// Request status of the specific recipient -pub const LIBUSB_REQUEST_GET_STATUS: libusb_standard_request = 0; -/// Clear or disable a specific feature -pub const LIBUSB_REQUEST_CLEAR_FEATURE: libusb_standard_request = 1; -/// Set or enable a specific feature -pub const LIBUSB_REQUEST_SET_FEATURE: libusb_standard_request = 3; -/// Set device address for all future accesses -pub const LIBUSB_REQUEST_SET_ADDRESS: libusb_standard_request = 5; -/// Get the specified descriptor -pub const LIBUSB_REQUEST_GET_DESCRIPTOR: libusb_standard_request = 6; -/// Used to update existing descriptors or add new descriptors -pub const LIBUSB_REQUEST_SET_DESCRIPTOR: libusb_standard_request = 7; -/// Get the current device configuration value -pub const LIBUSB_REQUEST_GET_CONFIGURATION: libusb_standard_request = 8; -/// Set device configuration -pub const LIBUSB_REQUEST_SET_CONFIGURATION: libusb_standard_request = 9; -/// Return the selected alternate setting for the specified interface -pub const LIBUSB_REQUEST_GET_INTERFACE: libusb_standard_request = 10; -/// Select an alternate interface for the specified interface -pub const LIBUSB_REQUEST_SET_INTERFACE: libusb_standard_request = 11; -/// Set then report an endpoint's synchronization frame -pub const LIBUSB_REQUEST_SYNCH_FRAME: libusb_standard_request = 12; -/// Sets both the U1 and U2 Exit Latency -pub const LIBUSB_REQUEST_SET_SEL: libusb_standard_request = 48; -/// Delay from the time a host transmits a packet to the time it is -/// received by the device. -pub const LIBUSB_SET_ISOCH_DELAY: libusb_standard_request = 49; -/// \ingroup libusb_misc -/// Standard requests, as defined in table 9-5 of the USB 3.0 specifications -pub type libusb_standard_request = u32; -/// Standard -pub const LIBUSB_REQUEST_TYPE_STANDARD: libusb_request_type = 0; -/// Class -pub const LIBUSB_REQUEST_TYPE_CLASS: libusb_request_type = 32; -/// Vendor -pub const LIBUSB_REQUEST_TYPE_VENDOR: libusb_request_type = 64; -/// Reserved -pub const LIBUSB_REQUEST_TYPE_RESERVED: libusb_request_type = 96; -/// \ingroup libusb_misc -/// Request type bits of the -/// \ref libusb_control_setup::bmRequestType "bmRequestType" field in control -/// transfers. -pub type libusb_request_type = u32; -/// Device -pub const LIBUSB_RECIPIENT_DEVICE: libusb_request_recipient = 0; -/// Interface -pub const LIBUSB_RECIPIENT_INTERFACE: libusb_request_recipient = 1; -/// Endpoint -pub const LIBUSB_RECIPIENT_ENDPOINT: libusb_request_recipient = 2; -/// Other -pub const LIBUSB_RECIPIENT_OTHER: libusb_request_recipient = 3; -/// \ingroup libusb_misc -/// Recipient bits of the -/// \ref libusb_control_setup::bmRequestType "bmRequestType" field in control -/// transfers. Values 4 through 31 are reserved. -pub type libusb_request_recipient = u32; -/// No synchronization -pub const LIBUSB_ISO_SYNC_TYPE_NONE: libusb_iso_sync_type = 0; -/// Asynchronous -pub const LIBUSB_ISO_SYNC_TYPE_ASYNC: libusb_iso_sync_type = 1; -/// Adaptive -pub const LIBUSB_ISO_SYNC_TYPE_ADAPTIVE: libusb_iso_sync_type = 2; -/// Synchronous -pub const LIBUSB_ISO_SYNC_TYPE_SYNC: libusb_iso_sync_type = 3; -/// \ingroup libusb_desc -/// Synchronization type for isochronous endpoints. Values for bits 2:3 of the -/// \ref libusb_endpoint_descriptor::bmAttributes "bmAttributes" field in -/// libusb_endpoint_descriptor. -pub type libusb_iso_sync_type = u32; -/// Data endpoint -pub const LIBUSB_ISO_USAGE_TYPE_DATA: libusb_iso_usage_type = 0; -/// Feedback endpoint -pub const LIBUSB_ISO_USAGE_TYPE_FEEDBACK: libusb_iso_usage_type = 1; -/// Implicit feedback Data endpoint -pub const LIBUSB_ISO_USAGE_TYPE_IMPLICIT: libusb_iso_usage_type = 2; -/// \ingroup libusb_desc -/// Usage type for isochronous endpoints. Values for bits 4:5 of the -/// \ref libusb_endpoint_descriptor::bmAttributes "bmAttributes" field in -/// libusb_endpoint_descriptor. -pub type libusb_iso_usage_type = u32; -/// \ingroup libusb_desc -/// A structure representing the standard USB device descriptor. This -/// descriptor is documented in section 9.6.1 of the USB 3.0 specification. -/// All multiple-byte fields are represented in host-endian format. -#[repr(C)] -#[derive(Default, Debug, Copy, Clone)] -pub struct libusb_device_descriptor { - /// Size of this descriptor (in bytes) - pub bLength: u8, - /// Descriptor type. Will have value - /// \ref libusb_descriptor_type::LIBUSB_DT_DEVICE LIBUSB_DT_DEVICE in this - /// context. - pub bDescriptorType: u8, - /// USB specification release number in binary-coded decimal. A value of - /// 0x0200 indicates USB 2.0, 0x0110 indicates USB 1.1, etc. - pub bcdUSB: u16, - /// USB-IF class code for the device. See \ref libusb_class_code. - pub bDeviceClass: u8, - /// USB-IF subclass code for the device, qualified by the bDeviceClass - /// value - pub bDeviceSubClass: u8, - /// USB-IF protocol code for the device, qualified by the bDeviceClass and - /// bDeviceSubClass values - pub bDeviceProtocol: u8, - /// Maximum packet size for endpoint 0 - pub bMaxPacketSize0: u8, - /// USB-IF vendor ID - pub idVendor: u16, - /// USB-IF product ID - pub idProduct: u16, - /// Device release number in binary-coded decimal - pub bcdDevice: u16, - /// Index of string descriptor describing manufacturer - pub iManufacturer: u8, - /// Index of string descriptor describing product - pub iProduct: u8, - /// Index of string descriptor containing device serial number - pub iSerialNumber: u8, - /// Number of possible configurations - pub bNumConfigurations: u8, -} -#[test] -fn bindgen_test_layout_libusb_device_descriptor() { - assert_eq!( - ::std::mem::size_of::<libusb_device_descriptor>(), - 18usize, - concat!("Size of: ", stringify!(libusb_device_descriptor)) - ); - assert_eq!( - ::std::mem::align_of::<libusb_device_descriptor>(), - 2usize, - concat!("Alignment of ", stringify!(libusb_device_descriptor)) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::<libusb_device_descriptor>())).bLength as *const _ as usize - }, - 0usize, - concat!( - "Offset of field: ", - stringify!(libusb_device_descriptor), - "::", - stringify!(bLength) - ) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::<libusb_device_descriptor>())).bDescriptorType as *const _ - as usize - }, - 1usize, - concat!( - "Offset of field: ", - stringify!(libusb_device_descriptor), - "::", - stringify!(bDescriptorType) - ) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<libusb_device_descriptor>())).bcdUSB as *const _ as usize }, - 2usize, - concat!( - "Offset of field: ", - stringify!(libusb_device_descriptor), - "::", - stringify!(bcdUSB) - ) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::<libusb_device_descriptor>())).bDeviceClass as *const _ as usize - }, - 4usize, - concat!( - "Offset of field: ", - stringify!(libusb_device_descriptor), - "::", - stringify!(bDeviceClass) - ) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::<libusb_device_descriptor>())).bDeviceSubClass as *const _ - as usize - }, - 5usize, - concat!( - "Offset of field: ", - stringify!(libusb_device_descriptor), - "::", - stringify!(bDeviceSubClass) - ) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::<libusb_device_descriptor>())).bDeviceProtocol as *const _ - as usize - }, - 6usize, - concat!( - "Offset of field: ", - stringify!(libusb_device_descriptor), - "::", - stringify!(bDeviceProtocol) - ) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::<libusb_device_descriptor>())).bMaxPacketSize0 as *const _ - as usize - }, - 7usize, - concat!( - "Offset of field: ", - stringify!(libusb_device_descriptor), - "::", - stringify!(bMaxPacketSize0) - ) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::<libusb_device_descriptor>())).idVendor as *const _ as usize - }, - 8usize, - concat!( - "Offset of field: ", - stringify!(libusb_device_descriptor), - "::", - stringify!(idVendor) - ) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::<libusb_device_descriptor>())).idProduct as *const _ as usize - }, - 10usize, - concat!( - "Offset of field: ", - stringify!(libusb_device_descriptor), - "::", - stringify!(idProduct) - ) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::<libusb_device_descriptor>())).bcdDevice as *const _ as usize - }, - 12usize, - concat!( - "Offset of field: ", - stringify!(libusb_device_descriptor), - "::", - stringify!(bcdDevice) - ) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::<libusb_device_descriptor>())).iManufacturer as *const _ as usize - }, - 14usize, - concat!( - "Offset of field: ", - stringify!(libusb_device_descriptor), - "::", - stringify!(iManufacturer) - ) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::<libusb_device_descriptor>())).iProduct as *const _ as usize - }, - 15usize, - concat!( - "Offset of field: ", - stringify!(libusb_device_descriptor), - "::", - stringify!(iProduct) - ) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::<libusb_device_descriptor>())).iSerialNumber as *const _ as usize - }, - 16usize, - concat!( - "Offset of field: ", - stringify!(libusb_device_descriptor), - "::", - stringify!(iSerialNumber) - ) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::<libusb_device_descriptor>())).bNumConfigurations as *const _ - as usize - }, - 17usize, - concat!( - "Offset of field: ", - stringify!(libusb_device_descriptor), - "::", - stringify!(bNumConfigurations) - ) - ); -} -/// \ingroup libusb_desc -/// A structure representing the standard USB endpoint descriptor. This -/// descriptor is documented in section 9.6.6 of the USB 3.0 specification. -/// All multiple-byte fields are represented in host-endian format. -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct libusb_endpoint_descriptor { - /// Size of this descriptor (in bytes) - pub bLength: u8, - /// Descriptor type. Will have value - /// \ref libusb_descriptor_type::LIBUSB_DT_ENDPOINT LIBUSB_DT_ENDPOINT in - /// this context. - pub bDescriptorType: u8, - /// The address of the endpoint described by this descriptor. Bits 0:3 are - /// the endpoint number. Bits 4:6 are reserved. Bit 7 indicates direction, - /// see \ref libusb_endpoint_direction. - pub bEndpointAddress: u8, - /// Attributes which apply to the endpoint when it is configured using - /// the bConfigurationValue. Bits 0:1 determine the transfer type and - /// correspond to \ref libusb_transfer_type. Bits 2:3 are only used for - /// isochronous endpoints and correspond to \ref libusb_iso_sync_type. - /// Bits 4:5 are also only used for isochronous endpoints and correspond to - /// \ref libusb_iso_usage_type. Bits 6:7 are reserved. - pub bmAttributes: u8, - /// Maximum packet size this endpoint is capable of sending/receiving. - pub wMaxPacketSize: u16, - /// Interval for polling endpoint for data transfers. - pub bInterval: u8, - /// For audio devices only: the rate at which synchronization feedback - /// is provided. - pub bRefresh: u8, - /// For audio devices only: the address if the synch endpoint - pub bSynchAddress: u8, - /// Extra descriptors. If libusb encounters unknown endpoint descriptors, - /// it will store them here, should you wish to parse them. - pub extra: *const ::std::os::raw::c_uchar, - /// Length of the extra descriptors, in bytes. - pub extra_length: ::std::os::raw::c_int, -} -#[test] -fn bindgen_test_layout_libusb_endpoint_descriptor() { - assert_eq!( - ::std::mem::size_of::<libusb_endpoint_descriptor>(), - 32usize, - concat!("Size of: ", stringify!(libusb_endpoint_descriptor)) - ); - assert_eq!( - ::std::mem::align_of::<libusb_endpoint_descriptor>(), - 8usize, - concat!("Alignment of ", stringify!(libusb_endpoint_descriptor)) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::<libusb_endpoint_descriptor>())).bLength as *const _ as usize - }, - 0usize, - concat!( - "Offset of field: ", - stringify!(libusb_endpoint_descriptor), - "::", - stringify!(bLength) - ) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::<libusb_endpoint_descriptor>())).bDescriptorType as *const _ - as usize - }, - 1usize, - concat!( - "Offset of field: ", - stringify!(libusb_endpoint_descriptor), - "::", - stringify!(bDescriptorType) - ) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::<libusb_endpoint_descriptor>())).bEndpointAddress as *const _ - as usize - }, - 2usize, - concat!( - "Offset of field: ", - stringify!(libusb_endpoint_descriptor), - "::", - stringify!(bEndpointAddress) - ) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::<libusb_endpoint_descriptor>())).bmAttributes as *const _ as usize - }, - 3usize, - concat!( - "Offset of field: ", - stringify!(libusb_endpoint_descriptor), - "::", - stringify!(bmAttributes) - ) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::<libusb_endpoint_descriptor>())).wMaxPacketSize as *const _ - as usize - }, - 4usize, - concat!( - "Offset of field: ", - stringify!(libusb_endpoint_descriptor), - "::", - stringify!(wMaxPacketSize) - ) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::<libusb_endpoint_descriptor>())).bInterval as *const _ as usize - }, - 6usize, - concat!( - "Offset of field: ", - stringify!(libusb_endpoint_descriptor), - "::", - stringify!(bInterval) - ) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::<libusb_endpoint_descriptor>())).bRefresh as *const _ as usize - }, - 7usize, - concat!( - "Offset of field: ", - stringify!(libusb_endpoint_descriptor), - "::", - stringify!(bRefresh) - ) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::<libusb_endpoint_descriptor>())).bSynchAddress as *const _ - as usize - }, - 8usize, - concat!( - "Offset of field: ", - stringify!(libusb_endpoint_descriptor), - "::", - stringify!(bSynchAddress) - ) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::<libusb_endpoint_descriptor>())).extra as *const _ as usize - }, - 16usize, - concat!( - "Offset of field: ", - stringify!(libusb_endpoint_descriptor), - "::", - stringify!(extra) - ) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::<libusb_endpoint_descriptor>())).extra_length as *const _ as usize - }, - 24usize, - concat!( - "Offset of field: ", - stringify!(libusb_endpoint_descriptor), - "::", - stringify!(extra_length) - ) - ); -} -/// \ingroup libusb_desc -/// A structure representing the standard USB interface descriptor. This -/// descriptor is documented in section 9.6.5 of the USB 3.0 specification. -/// All multiple-byte fields are represented in host-endian format. -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct libusb_interface_descriptor { - /// Size of this descriptor (in bytes) - pub bLength: u8, - /// Descriptor type. Will have value - /// \ref libusb_descriptor_type::LIBUSB_DT_INTERFACE LIBUSB_DT_INTERFACE - /// in this context. - pub bDescriptorType: u8, - /// Number of this interface - pub bInterfaceNumber: u8, - /// Value used to select this alternate setting for this interface - pub bAlternateSetting: u8, - /// Number of endpoints used by this interface (excluding the control - /// endpoint). - pub bNumEndpoints: u8, - /// USB-IF class code for this interface. See \ref libusb_class_code. - pub bInterfaceClass: u8, - /// USB-IF subclass code for this interface, qualified by the - /// bInterfaceClass value - pub bInterfaceSubClass: u8, - /// USB-IF protocol code for this interface, qualified by the - /// bInterfaceClass and bInterfaceSubClass values - pub bInterfaceProtocol: u8, - /// Index of string descriptor describing this interface - pub iInterface: u8, - /// Array of endpoint descriptors. This length of this array is determined - /// by the bNumEndpoints field. - pub endpoint: *const libusb_endpoint_descriptor, - /// Extra descriptors. If libusb encounters unknown interface descriptors, - /// it will store them here, should you wish to parse them. - pub extra: *const ::std::os::raw::c_uchar, - /// Length of the extra descriptors, in bytes. - pub extra_length: ::std::os::raw::c_int, -} -#[test] -fn bindgen_test_layout_libusb_interface_descriptor() { - assert_eq!( - ::std::mem::size_of::<libusb_interface_descriptor>(), - 40usize, - concat!("Size of: ", stringify!(libusb_interface_descriptor)) - ); - assert_eq!( - ::std::mem::align_of::<libusb_interface_descriptor>(), - 8usize, - concat!("Alignment of ", stringify!(libusb_interface_descriptor)) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::<libusb_interface_descriptor>())).bLength as *const _ as usize - }, - 0usize, - concat!( - "Offset of field: ", - stringify!(libusb_interface_descriptor), - "::", - stringify!(bLength) - ) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::<libusb_interface_descriptor>())).bDescriptorType as *const _ - as usize - }, - 1usize, - concat!( - "Offset of field: ", - stringify!(libusb_interface_descriptor), - "::", - stringify!(bDescriptorType) - ) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::<libusb_interface_descriptor>())).bInterfaceNumber as *const _ - as usize - }, - 2usize, - concat!( - "Offset of field: ", - stringify!(libusb_interface_descriptor), - "::", - stringify!(bInterfaceNumber) - ) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::<libusb_interface_descriptor>())).bAlternateSetting as *const _ - as usize - }, - 3usize, - concat!( - "Offset of field: ", - stringify!(libusb_interface_descriptor), - "::", - stringify!(bAlternateSetting) - ) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::<libusb_interface_descriptor>())).bNumEndpoints as *const _ - as usize - }, - 4usize, - concat!( - "Offset of field: ", - stringify!(libusb_interface_descriptor), - "::", - stringify!(bNumEndpoints) - ) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::<libusb_interface_descriptor>())).bInterfaceClass as *const _ - as usize - }, - 5usize, - concat!( - "Offset of field: ", - stringify!(libusb_interface_descriptor), - "::", - stringify!(bInterfaceClass) - ) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::<libusb_interface_descriptor>())).bInterfaceSubClass as *const _ - as usize - }, - 6usize, - concat!( - "Offset of field: ", - stringify!(libusb_interface_descriptor), - "::", - stringify!(bInterfaceSubClass) - ) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::<libusb_interface_descriptor>())).bInterfaceProtocol as *const _ - as usize - }, - 7usize, - concat!( - "Offset of field: ", - stringify!(libusb_interface_descriptor), - "::", - stringify!(bInterfaceProtocol) - ) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::<libusb_interface_descriptor>())).iInterface as *const _ as usize - }, - 8usize, - concat!( - "Offset of field: ", - stringify!(libusb_interface_descriptor), - "::", - stringify!(iInterface) - ) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::<libusb_interface_descriptor>())).endpoint as *const _ as usize - }, - 16usize, - concat!( - "Offset of field: ", - stringify!(libusb_interface_descriptor), - "::", - stringify!(endpoint) - ) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::<libusb_interface_descriptor>())).extra as *const _ as usize - }, - 24usize, - concat!( - "Offset of field: ", - stringify!(libusb_interface_descriptor), - "::", - stringify!(extra) - ) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::<libusb_interface_descriptor>())).extra_length as *const _ - as usize - }, - 32usize, - concat!( - "Offset of field: ", - stringify!(libusb_interface_descriptor), - "::", - stringify!(extra_length) - ) - ); -} -/// \ingroup libusb_desc -/// A collection of alternate settings for a particular USB interface. -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct libusb_interface { - /// Array of interface descriptors. The length of this array is determined - /// by the num_altsetting field. - pub altsetting: *const libusb_interface_descriptor, - /// The number of alternate settings that belong to this interface - pub num_altsetting: ::std::os::raw::c_int, -} -#[test] -fn bindgen_test_layout_libusb_interface() { - assert_eq!( - ::std::mem::size_of::<libusb_interface>(), - 16usize, - concat!("Size of: ", stringify!(libusb_interface)) - ); - assert_eq!( - ::std::mem::align_of::<libusb_interface>(), - 8usize, - concat!("Alignment of ", stringify!(libusb_interface)) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<libusb_interface>())).altsetting as *const _ as usize }, - 0usize, - concat!( - "Offset of field: ", - stringify!(libusb_interface), - "::", - stringify!(altsetting) - ) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<libusb_interface>())).num_altsetting as *const _ as usize }, - 8usize, - concat!( - "Offset of field: ", - stringify!(libusb_interface), - "::", - stringify!(num_altsetting) - ) - ); -} -/// \ingroup libusb_desc -/// A structure representing the standard USB configuration descriptor. This -/// descriptor is documented in section 9.6.3 of the USB 3.0 specification. -/// All multiple-byte fields are represented in host-endian format. -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct libusb_config_descriptor { - /// Size of this descriptor (in bytes) - pub bLength: u8, - /// Descriptor type. Will have value - /// \ref libusb_descriptor_type::LIBUSB_DT_CONFIG LIBUSB_DT_CONFIG - /// in this context. - pub bDescriptorType: u8, - /// Total length of data returned for this configuration - pub wTotalLength: u16, - /// Number of interfaces supported by this configuration - pub bNumInterfaces: u8, - /// Identifier value for this configuration - pub bConfigurationValue: u8, - /// Index of string descriptor describing this configuration - pub iConfiguration: u8, - /// Configuration characteristics - pub bmAttributes: u8, - /// Maximum power consumption of the USB device from this bus in this - /// configuration when the device is fully operation. Expressed in units - /// of 2 mA when the device is operating in high-speed mode and in units - /// of 8 mA when the device is operating in super-speed mode. - pub MaxPower: u8, - /// Array of interfaces supported by this configuration. The length of - /// this array is determined by the bNumInterfaces field. - pub interface: *const libusb_interface, - /// Extra descriptors. If libusb encounters unknown configuration - /// descriptors, it will store them here, should you wish to parse them. - pub extra: *const ::std::os::raw::c_uchar, - /// Length of the extra descriptors, in bytes. - pub extra_length: ::std::os::raw::c_int, -} -#[test] -fn bindgen_test_layout_libusb_config_descriptor() { - assert_eq!( - ::std::mem::size_of::<libusb_config_descriptor>(), - 40usize, - concat!("Size of: ", stringify!(libusb_config_descriptor)) - ); - assert_eq!( - ::std::mem::align_of::<libusb_config_descriptor>(), - 8usize, - concat!("Alignment of ", stringify!(libusb_config_descriptor)) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::<libusb_config_descriptor>())).bLength as *const _ as usize - }, - 0usize, - concat!( - "Offset of field: ", - stringify!(libusb_config_descriptor), - "::", - stringify!(bLength) - ) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::<libusb_config_descriptor>())).bDescriptorType as *const _ - as usize - }, - 1usize, - concat!( - "Offset of field: ", - stringify!(libusb_config_descriptor), - "::", - stringify!(bDescriptorType) - ) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::<libusb_config_descriptor>())).wTotalLength as *const _ as usize - }, - 2usize, - concat!( - "Offset of field: ", - stringify!(libusb_config_descriptor), - "::", - stringify!(wTotalLength) - ) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::<libusb_config_descriptor>())).bNumInterfaces as *const _ as usize - }, - 4usize, - concat!( - "Offset of field: ", - stringify!(libusb_config_descriptor), - "::", - stringify!(bNumInterfaces) - ) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::<libusb_config_descriptor>())).bConfigurationValue as *const _ - as usize - }, - 5usize, - concat!( - "Offset of field: ", - stringify!(libusb_config_descriptor), - "::", - stringify!(bConfigurationValue) - ) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::<libusb_config_descriptor>())).iConfiguration as *const _ as usize - }, - 6usize, - concat!( - "Offset of field: ", - stringify!(libusb_config_descriptor), - "::", - stringify!(iConfiguration) - ) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::<libusb_config_descriptor>())).bmAttributes as *const _ as usize - }, - 7usize, - concat!( - "Offset of field: ", - stringify!(libusb_config_descriptor), - "::", - stringify!(bmAttributes) - ) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::<libusb_config_descriptor>())).MaxPower as *const _ as usize - }, - 8usize, - concat!( - "Offset of field: ", - stringify!(libusb_config_descriptor), - "::", - stringify!(MaxPower) - ) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::<libusb_config_descriptor>())).interface as *const _ as usize - }, - 16usize, - concat!( - "Offset of field: ", - stringify!(libusb_config_descriptor), - "::", - stringify!(interface) - ) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<libusb_config_descriptor>())).extra as *const _ as usize }, - 24usize, - concat!( - "Offset of field: ", - stringify!(libusb_config_descriptor), - "::", - stringify!(extra) - ) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::<libusb_config_descriptor>())).extra_length as *const _ as usize - }, - 32usize, - concat!( - "Offset of field: ", - stringify!(libusb_config_descriptor), - "::", - stringify!(extra_length) - ) - ); -} -/// \ingroup libusb_desc -/// A structure representing the superspeed endpoint companion -/// descriptor. This descriptor is documented in section 9.6.7 of -/// the USB 3.0 specification. All multiple-byte fields are represented in -/// host-endian format. -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct libusb_ss_endpoint_companion_descriptor { - /// Size of this descriptor (in bytes) - pub bLength: u8, - /// Descriptor type. Will have value - /// \ref libusb_descriptor_type::LIBUSB_DT_SS_ENDPOINT_COMPANION in - /// this context. - pub bDescriptorType: u8, - /// The maximum number of packets the endpoint can send or - /// receive as part of a burst. - pub bMaxBurst: u8, - /// In bulk EP: bits 4:0 represents the maximum number of - /// streams the EP supports. In isochronous EP: bits 1:0 - /// represents the Mult - a zero based value that determines - /// the maximum number of packets within a service interval - pub bmAttributes: u8, - /// The total number of bytes this EP will transfer every - /// service interval. valid only for periodic EPs. - pub wBytesPerInterval: u16, -} -#[test] -fn bindgen_test_layout_libusb_ss_endpoint_companion_descriptor() { - assert_eq!( - ::std::mem::size_of::<libusb_ss_endpoint_companion_descriptor>(), - 6usize, - concat!( - "Size of: ", - stringify!(libusb_ss_endpoint_companion_descriptor) - ) - ); - assert_eq!( - ::std::mem::align_of::<libusb_ss_endpoint_companion_descriptor>(), - 2usize, - concat!( - "Alignment of ", - stringify!(libusb_ss_endpoint_companion_descriptor) - ) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::<libusb_ss_endpoint_companion_descriptor>())).bLength as *const _ - as usize - }, - 0usize, - concat!( - "Offset of field: ", - stringify!(libusb_ss_endpoint_companion_descriptor), - "::", - stringify!(bLength) - ) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::<libusb_ss_endpoint_companion_descriptor>())).bDescriptorType - as *const _ as usize - }, - 1usize, - concat!( - "Offset of field: ", - stringify!(libusb_ss_endpoint_companion_descriptor), - "::", - stringify!(bDescriptorType) - ) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::<libusb_ss_endpoint_companion_descriptor>())).bMaxBurst - as *const _ as usize - }, - 2usize, - concat!( - "Offset of field: ", - stringify!(libusb_ss_endpoint_companion_descriptor), - "::", - stringify!(bMaxBurst) - ) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::<libusb_ss_endpoint_companion_descriptor>())).bmAttributes - as *const _ as usize - }, - 3usize, - concat!( - "Offset of field: ", - stringify!(libusb_ss_endpoint_companion_descriptor), - "::", - stringify!(bmAttributes) - ) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::<libusb_ss_endpoint_companion_descriptor>())).wBytesPerInterval - as *const _ as usize - }, - 4usize, - concat!( - "Offset of field: ", - stringify!(libusb_ss_endpoint_companion_descriptor), - "::", - stringify!(wBytesPerInterval) - ) - ); -} -/// \ingroup libusb_desc -/// A generic representation of a BOS Device Capability descriptor. It is -/// advised to check bDevCapabilityType and call the matching -/// libusb_get_*_descriptor function to get a structure fully matching the type. -#[repr(C)] -#[derive(Debug)] -pub struct libusb_bos_dev_capability_descriptor { - /// Size of this descriptor (in bytes) - pub bLength: u8, - /// Descriptor type. Will have value - /// \ref libusb_descriptor_type::LIBUSB_DT_DEVICE_CAPABILITY - /// LIBUSB_DT_DEVICE_CAPABILITY in this context. - pub bDescriptorType: u8, - /// Device Capability type - pub bDevCapabilityType: u8, - /// Device Capability data (bLength - 3 bytes) - pub dev_capability_data: __IncompleteArrayField<u8>, -} -#[test] -fn bindgen_test_layout_libusb_bos_dev_capability_descriptor() { - assert_eq!( - ::std::mem::size_of::<libusb_bos_dev_capability_descriptor>(), - 3usize, - concat!( - "Size of: ", - stringify!(libusb_bos_dev_capability_descriptor) - ) - ); - assert_eq!( - ::std::mem::align_of::<libusb_bos_dev_capability_descriptor>(), - 1usize, - concat!( - "Alignment of ", - stringify!(libusb_bos_dev_capability_descriptor) - ) - ); -} -/// \ingroup libusb_desc -/// A structure representing the Binary Device Object Store (BOS) descriptor. -/// This descriptor is documented in section 9.6.2 of the USB 3.0 specification. -/// All multiple-byte fields are represented in host-endian format. -#[repr(C)] -#[derive(Debug)] -pub struct libusb_bos_descriptor { - /// Size of this descriptor (in bytes) - pub bLength: u8, - /// Descriptor type. Will have value - /// \ref libusb_descriptor_type::LIBUSB_DT_BOS LIBUSB_DT_BOS - /// in this context. - pub bDescriptorType: u8, - /// Length of this descriptor and all of its sub descriptors - pub wTotalLength: u16, - /// The number of separate device capability descriptors in - /// the BOS - pub bNumDeviceCaps: u8, - /// bNumDeviceCap Device Capability Descriptors - pub dev_capability: __IncompleteArrayField<*mut libusb_bos_dev_capability_descriptor>, - pub __bindgen_align: [u64; 0usize], -} -#[test] -fn bindgen_test_layout_libusb_bos_descriptor() { - assert_eq!( - ::std::mem::size_of::<libusb_bos_descriptor>(), - 8usize, - concat!("Size of: ", stringify!(libusb_bos_descriptor)) - ); - assert_eq!( - ::std::mem::align_of::<libusb_bos_descriptor>(), - 8usize, - concat!("Alignment of ", stringify!(libusb_bos_descriptor)) - ); -} -/// \ingroup libusb_desc -/// A structure representing the USB 2.0 Extension descriptor -/// This descriptor is documented in section 9.6.2.1 of the USB 3.0 specification. -/// All multiple-byte fields are represented in host-endian format. -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct libusb_usb_2_0_extension_descriptor { - /// Size of this descriptor (in bytes) - pub bLength: u8, - /// Descriptor type. Will have value - /// \ref libusb_descriptor_type::LIBUSB_DT_DEVICE_CAPABILITY - /// LIBUSB_DT_DEVICE_CAPABILITY in this context. - pub bDescriptorType: u8, - /// Capability type. Will have value - /// \ref libusb_capability_type::LIBUSB_BT_USB_2_0_EXTENSION - /// LIBUSB_BT_USB_2_0_EXTENSION in this context. - pub bDevCapabilityType: u8, - /// Bitmap encoding of supported device level features. - /// A value of one in a bit location indicates a feature is - /// supported; a value of zero indicates it is not supported. - /// See \ref libusb_usb_2_0_extension_attributes. - pub bmAttributes: u32, -} -#[test] -fn bindgen_test_layout_libusb_usb_2_0_extension_descriptor() { - assert_eq!( - ::std::mem::size_of::<libusb_usb_2_0_extension_descriptor>(), - 8usize, - concat!("Size of: ", stringify!(libusb_usb_2_0_extension_descriptor)) - ); - assert_eq!( - ::std::mem::align_of::<libusb_usb_2_0_extension_descriptor>(), - 4usize, - concat!( - "Alignment of ", - stringify!(libusb_usb_2_0_extension_descriptor) - ) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::<libusb_usb_2_0_extension_descriptor>())).bLength as *const _ - as usize - }, - 0usize, - concat!( - "Offset of field: ", - stringify!(libusb_usb_2_0_extension_descriptor), - "::", - stringify!(bLength) - ) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::<libusb_usb_2_0_extension_descriptor>())).bDescriptorType - as *const _ as usize - }, - 1usize, - concat!( - "Offset of field: ", - stringify!(libusb_usb_2_0_extension_descriptor), - "::", - stringify!(bDescriptorType) - ) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::<libusb_usb_2_0_extension_descriptor>())).bDevCapabilityType - as *const _ as usize - }, - 2usize, - concat!( - "Offset of field: ", - stringify!(libusb_usb_2_0_extension_descriptor), - "::", - stringify!(bDevCapabilityType) - ) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::<libusb_usb_2_0_extension_descriptor>())).bmAttributes as *const _ - as usize - }, - 4usize, - concat!( - "Offset of field: ", - stringify!(libusb_usb_2_0_extension_descriptor), - "::", - stringify!(bmAttributes) - ) - ); -} -/// \ingroup libusb_desc -/// A structure representing the SuperSpeed USB Device Capability descriptor -/// This descriptor is documented in section 9.6.2.2 of the USB 3.0 specification. -/// All multiple-byte fields are represented in host-endian format. -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct libusb_ss_usb_device_capability_descriptor { - /// Size of this descriptor (in bytes) - pub bLength: u8, - /// Descriptor type. Will have value - /// \ref libusb_descriptor_type::LIBUSB_DT_DEVICE_CAPABILITY - /// LIBUSB_DT_DEVICE_CAPABILITY in this context. - pub bDescriptorType: u8, - /// Capability type. Will have value - /// \ref libusb_capability_type::LIBUSB_BT_SS_USB_DEVICE_CAPABILITY - /// LIBUSB_BT_SS_USB_DEVICE_CAPABILITY in this context. - pub bDevCapabilityType: u8, - /// Bitmap encoding of supported device level features. - /// A value of one in a bit location indicates a feature is - /// supported; a value of zero indicates it is not supported. - /// See \ref libusb_ss_usb_device_capability_attributes. - pub bmAttributes: u8, - /// Bitmap encoding of the speed supported by this device when - /// operating in SuperSpeed mode. See \ref libusb_supported_speed. - pub wSpeedSupported: u16, - /// The lowest speed at which all the functionality supported - /// by the device is available to the user. For example if the - /// device supports all its functionality when connected at - /// full speed and above then it sets this value to 1. - pub bFunctionalitySupport: u8, - /// U1 Device Exit Latency. - pub bU1DevExitLat: u8, - /// U2 Device Exit Latency. - pub bU2DevExitLat: u16, -} -#[test] -fn bindgen_test_layout_libusb_ss_usb_device_capability_descriptor() { - assert_eq!( - ::std::mem::size_of::<libusb_ss_usb_device_capability_descriptor>(), - 10usize, - concat!( - "Size of: ", - stringify!(libusb_ss_usb_device_capability_descriptor) - ) - ); - assert_eq!( - ::std::mem::align_of::<libusb_ss_usb_device_capability_descriptor>(), - 2usize, - concat!( - "Alignment of ", - stringify!(libusb_ss_usb_device_capability_descriptor) - ) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::<libusb_ss_usb_device_capability_descriptor>())).bLength - as *const _ as usize - }, - 0usize, - concat!( - "Offset of field: ", - stringify!(libusb_ss_usb_device_capability_descriptor), - "::", - stringify!(bLength) - ) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::<libusb_ss_usb_device_capability_descriptor>())).bDescriptorType - as *const _ as usize - }, - 1usize, - concat!( - "Offset of field: ", - stringify!(libusb_ss_usb_device_capability_descriptor), - "::", - stringify!(bDescriptorType) - ) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::<libusb_ss_usb_device_capability_descriptor>())) - .bDevCapabilityType as *const _ as usize - }, - 2usize, - concat!( - "Offset of field: ", - stringify!(libusb_ss_usb_device_capability_descriptor), - "::", - stringify!(bDevCapabilityType) - ) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::<libusb_ss_usb_device_capability_descriptor>())).bmAttributes - as *const _ as usize - }, - 3usize, - concat!( - "Offset of field: ", - stringify!(libusb_ss_usb_device_capability_descriptor), - "::", - stringify!(bmAttributes) - ) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::<libusb_ss_usb_device_capability_descriptor>())).wSpeedSupported - as *const _ as usize - }, - 4usize, - concat!( - "Offset of field: ", - stringify!(libusb_ss_usb_device_capability_descriptor), - "::", - stringify!(wSpeedSupported) - ) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::<libusb_ss_usb_device_capability_descriptor>())) - .bFunctionalitySupport as *const _ as usize - }, - 6usize, - concat!( - "Offset of field: ", - stringify!(libusb_ss_usb_device_capability_descriptor), - "::", - stringify!(bFunctionalitySupport) - ) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::<libusb_ss_usb_device_capability_descriptor>())).bU1DevExitLat - as *const _ as usize - }, - 7usize, - concat!( - "Offset of field: ", - stringify!(libusb_ss_usb_device_capability_descriptor), - "::", - stringify!(bU1DevExitLat) - ) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::<libusb_ss_usb_device_capability_descriptor>())).bU2DevExitLat - as *const _ as usize - }, - 8usize, - concat!( - "Offset of field: ", - stringify!(libusb_ss_usb_device_capability_descriptor), - "::", - stringify!(bU2DevExitLat) - ) - ); -} -/// \ingroup libusb_desc -/// A structure representing the Container ID descriptor. -/// This descriptor is documented in section 9.6.2.3 of the USB 3.0 specification. -/// All multiple-byte fields, except UUIDs, are represented in host-endian format. -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct libusb_container_id_descriptor { - /// Size of this descriptor (in bytes) - pub bLength: u8, - /// Descriptor type. Will have value - /// \ref libusb_descriptor_type::LIBUSB_DT_DEVICE_CAPABILITY - /// LIBUSB_DT_DEVICE_CAPABILITY in this context. - pub bDescriptorType: u8, - /// Capability type. Will have value - /// \ref libusb_capability_type::LIBUSB_BT_CONTAINER_ID - /// LIBUSB_BT_CONTAINER_ID in this context. - pub bDevCapabilityType: u8, - /// Reserved field - pub bReserved: u8, - /// 128 bit UUID - pub ContainerID: [u8; 16usize], -} -#[test] -fn bindgen_test_layout_libusb_container_id_descriptor() { - assert_eq!( - ::std::mem::size_of::<libusb_container_id_descriptor>(), - 20usize, - concat!("Size of: ", stringify!(libusb_container_id_descriptor)) - ); - assert_eq!( - ::std::mem::align_of::<libusb_container_id_descriptor>(), - 1usize, - concat!("Alignment of ", stringify!(libusb_container_id_descriptor)) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::<libusb_container_id_descriptor>())).bLength as *const _ as usize - }, - 0usize, - concat!( - "Offset of field: ", - stringify!(libusb_container_id_descriptor), - "::", - stringify!(bLength) - ) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::<libusb_container_id_descriptor>())).bDescriptorType as *const _ - as usize - }, - 1usize, - concat!( - "Offset of field: ", - stringify!(libusb_container_id_descriptor), - "::", - stringify!(bDescriptorType) - ) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::<libusb_container_id_descriptor>())).bDevCapabilityType - as *const _ as usize - }, - 2usize, - concat!( - "Offset of field: ", - stringify!(libusb_container_id_descriptor), - "::", - stringify!(bDevCapabilityType) - ) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::<libusb_container_id_descriptor>())).bReserved as *const _ - as usize - }, - 3usize, - concat!( - "Offset of field: ", - stringify!(libusb_container_id_descriptor), - "::", - stringify!(bReserved) - ) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::<libusb_container_id_descriptor>())).ContainerID as *const _ - as usize - }, - 4usize, - concat!( - "Offset of field: ", - stringify!(libusb_container_id_descriptor), - "::", - stringify!(ContainerID) - ) - ); -} -/// \ingroup libusb_asyncio -/// Setup packet for control transfers. -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct libusb_control_setup { - /// Request type. Bits 0:4 determine recipient, see - /// \ref libusb_request_recipient. Bits 5:6 determine type, see - /// \ref libusb_request_type. Bit 7 determines data transfer direction, see - /// \ref libusb_endpoint_direction. - pub bmRequestType: u8, - /// Request. If the type bits of bmRequestType are equal to - /// \ref libusb_request_type::LIBUSB_REQUEST_TYPE_STANDARD - /// "LIBUSB_REQUEST_TYPE_STANDARD" then this field refers to - /// \ref libusb_standard_request. For other cases, use of this field is - /// application-specific. - pub bRequest: u8, - /// Value. Varies according to request - pub wValue: u16, - /// Index. Varies according to request, typically used to pass an index - /// or offset - pub wIndex: u16, - /// Number of bytes to transfer - pub wLength: u16, -} -#[test] -fn bindgen_test_layout_libusb_control_setup() { - assert_eq!( - ::std::mem::size_of::<libusb_control_setup>(), - 8usize, - concat!("Size of: ", stringify!(libusb_control_setup)) - ); - assert_eq!( - ::std::mem::align_of::<libusb_control_setup>(), - 2usize, - concat!("Alignment of ", stringify!(libusb_control_setup)) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::<libusb_control_setup>())).bmRequestType as *const _ as usize - }, - 0usize, - concat!( - "Offset of field: ", - stringify!(libusb_control_setup), - "::", - stringify!(bmRequestType) - ) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<libusb_control_setup>())).bRequest as *const _ as usize }, - 1usize, - concat!( - "Offset of field: ", - stringify!(libusb_control_setup), - "::", - stringify!(bRequest) - ) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<libusb_control_setup>())).wValue as *const _ as usize }, - 2usize, - concat!( - "Offset of field: ", - stringify!(libusb_control_setup), - "::", - stringify!(wValue) - ) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<libusb_control_setup>())).wIndex as *const _ as usize }, - 4usize, - concat!( - "Offset of field: ", - stringify!(libusb_control_setup), - "::", - stringify!(wIndex) - ) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<libusb_control_setup>())).wLength as *const _ as usize }, - 6usize, - concat!( - "Offset of field: ", - stringify!(libusb_control_setup), - "::", - stringify!(wLength) - ) - ); -} -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct libusb_context { - _unused: [u8; 0], -} -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct libusb_device { - _unused: [u8; 0], -} -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct libusb_device_handle { - _unused: [u8; 0], -} -/// \ingroup libusb_lib -/// Structure providing the version of the libusb runtime -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct libusb_version { - /// Library major version. - pub major: u16, - /// Library minor version. - pub minor: u16, - /// Library micro version. - pub micro: u16, - /// Library nano version. - pub nano: u16, - /// Library release candidate suffix string, e.g. "-rc4". - pub rc: *const ::std::os::raw::c_char, - /// For ABI compatibility only. - pub describe: *const ::std::os::raw::c_char, -} -#[test] -fn bindgen_test_layout_libusb_version() { - assert_eq!( - ::std::mem::size_of::<libusb_version>(), - 24usize, - concat!("Size of: ", stringify!(libusb_version)) - ); - assert_eq!( - ::std::mem::align_of::<libusb_version>(), - 8usize, - concat!("Alignment of ", stringify!(libusb_version)) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<libusb_version>())).major as *const _ as usize }, - 0usize, - concat!( - "Offset of field: ", - stringify!(libusb_version), - "::", - stringify!(major) - ) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<libusb_version>())).minor as *const _ as usize }, - 2usize, - concat!( - "Offset of field: ", - stringify!(libusb_version), - "::", - stringify!(minor) - ) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<libusb_version>())).micro as *const _ as usize }, - 4usize, - concat!( - "Offset of field: ", - stringify!(libusb_version), - "::", - stringify!(micro) - ) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<libusb_version>())).nano as *const _ as usize }, - 6usize, - concat!( - "Offset of field: ", - stringify!(libusb_version), - "::", - stringify!(nano) - ) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<libusb_version>())).rc as *const _ as usize }, - 8usize, - concat!( - "Offset of field: ", - stringify!(libusb_version), - "::", - stringify!(rc) - ) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<libusb_version>())).describe as *const _ as usize }, - 16usize, - concat!( - "Offset of field: ", - stringify!(libusb_version), - "::", - stringify!(describe) - ) - ); -} -/// The OS doesn't report or know the device speed. -pub const LIBUSB_SPEED_UNKNOWN: libusb_speed = 0; -/// The device is operating at low speed (1.5MBit/s). -pub const LIBUSB_SPEED_LOW: libusb_speed = 1; -/// The device is operating at full speed (12MBit/s). -pub const LIBUSB_SPEED_FULL: libusb_speed = 2; -/// The device is operating at high speed (480MBit/s). -pub const LIBUSB_SPEED_HIGH: libusb_speed = 3; -/// The device is operating at super speed (5000MBit/s). -pub const LIBUSB_SPEED_SUPER: libusb_speed = 4; -/// \ingroup libusb_dev -/// Speed codes. Indicates the speed at which the device is operating. -pub type libusb_speed = u32; -/// Low speed operation supported (1.5MBit/s). -pub const LIBUSB_LOW_SPEED_OPERATION: libusb_supported_speed = 1; -/// Full speed operation supported (12MBit/s). -pub const LIBUSB_FULL_SPEED_OPERATION: libusb_supported_speed = 2; -/// High speed operation supported (480MBit/s). -pub const LIBUSB_HIGH_SPEED_OPERATION: libusb_supported_speed = 4; -/// Superspeed operation supported (5000MBit/s). -pub const LIBUSB_SUPER_SPEED_OPERATION: libusb_supported_speed = 8; -/// \ingroup libusb_dev -/// Supported speeds (wSpeedSupported) bitfield. Indicates what -/// speeds the device supports. -pub type libusb_supported_speed = u32; -/// Supports Link Power Management (LPM) -pub const LIBUSB_BM_LPM_SUPPORT: libusb_usb_2_0_extension_attributes = 2; -/// \ingroup libusb_dev -/// Masks for the bits of the -/// \ref libusb_usb_2_0_extension_descriptor::bmAttributes "bmAttributes" field -/// of the USB 2.0 Extension descriptor. -pub type libusb_usb_2_0_extension_attributes = u32; -/// Supports Latency Tolerance Messages (LTM) -pub const LIBUSB_BM_LTM_SUPPORT: libusb_ss_usb_device_capability_attributes = 2; -/// \ingroup libusb_dev -/// Masks for the bits of the -/// \ref libusb_ss_usb_device_capability_descriptor::bmAttributes "bmAttributes" field -/// field of the SuperSpeed USB Device Capability descriptor. -pub type libusb_ss_usb_device_capability_attributes = u32; -/// Wireless USB device capability -pub const LIBUSB_BT_WIRELESS_USB_DEVICE_CAPABILITY: libusb_bos_type = 1; -/// USB 2.0 extensions -pub const LIBUSB_BT_USB_2_0_EXTENSION: libusb_bos_type = 2; -/// SuperSpeed USB device capability -pub const LIBUSB_BT_SS_USB_DEVICE_CAPABILITY: libusb_bos_type = 3; -/// Container ID type -pub const LIBUSB_BT_CONTAINER_ID: libusb_bos_type = 4; -/// \ingroup libusb_dev -/// USB capability types -pub type libusb_bos_type = u32; -/// Success (no error) -pub const LIBUSB_SUCCESS: libusb_error = 0; -/// Input/output error -pub const LIBUSB_ERROR_IO: libusb_error = -1; -/// Invalid parameter -pub const LIBUSB_ERROR_INVALID_PARAM: libusb_error = -2; -/// Access denied (insufficient permissions) -pub const LIBUSB_ERROR_ACCESS: libusb_error = -3; -/// No such device (it may have been disconnected) -pub const LIBUSB_ERROR_NO_DEVICE: libusb_error = -4; -/// Entity not found -pub const LIBUSB_ERROR_NOT_FOUND: libusb_error = -5; -/// Resource busy -pub const LIBUSB_ERROR_BUSY: libusb_error = -6; -/// Operation timed out -pub const LIBUSB_ERROR_TIMEOUT: libusb_error = -7; -/// Overflow -pub const LIBUSB_ERROR_OVERFLOW: libusb_error = -8; -/// Pipe error -pub const LIBUSB_ERROR_PIPE: libusb_error = -9; -/// System call interrupted (perhaps due to signal) -pub const LIBUSB_ERROR_INTERRUPTED: libusb_error = -10; -/// Insufficient memory -pub const LIBUSB_ERROR_NO_MEM: libusb_error = -11; -/// Operation not supported or unimplemented on this platform -pub const LIBUSB_ERROR_NOT_SUPPORTED: libusb_error = -12; -/// Other error -pub const LIBUSB_ERROR_OTHER: libusb_error = -99; -/// \ingroup libusb_misc -/// Error codes. Most libusb functions return 0 on success or one of these -/// codes on failure. -/// You can call libusb_error_name() to retrieve a string representation of an -/// error code or libusb_strerror() to get an end-user suitable description of -/// an error code. -pub type libusb_error = i32; -/// Transfer completed without error. Note that this does not indicate -/// that the entire amount of requested data was transferred. -pub const LIBUSB_TRANSFER_COMPLETED: libusb_transfer_status = 0; -/// Transfer failed -pub const LIBUSB_TRANSFER_ERROR: libusb_transfer_status = 1; -/// Transfer timed out -pub const LIBUSB_TRANSFER_TIMED_OUT: libusb_transfer_status = 2; -/// Transfer was cancelled -pub const LIBUSB_TRANSFER_CANCELLED: libusb_transfer_status = 3; -/// For bulk/interrupt endpoints: halt condition detected (endpoint -/// stalled). For control endpoints: control request not supported. -pub const LIBUSB_TRANSFER_STALL: libusb_transfer_status = 4; -/// Device was disconnected -pub const LIBUSB_TRANSFER_NO_DEVICE: libusb_transfer_status = 5; -/// Device sent more data than requested -pub const LIBUSB_TRANSFER_OVERFLOW: libusb_transfer_status = 6; -/// \ingroup libusb_asyncio -/// Transfer status codes -pub type libusb_transfer_status = u32; -/// Report short frames as errors -pub const LIBUSB_TRANSFER_SHORT_NOT_OK: libusb_transfer_flags = 1; -/// Automatically free() transfer buffer during libusb_free_transfer(). -/// Note that buffers allocated with libusb_dev_mem_alloc() should not -/// be attempted freed in this way, since free() is not an appropriate -/// way to release such memory. -pub const LIBUSB_TRANSFER_FREE_BUFFER: libusb_transfer_flags = 2; -/// Automatically call libusb_free_transfer() after callback returns. -/// If this flag is set, it is illegal to call libusb_free_transfer() -/// from your transfer callback, as this will result in a double-free -/// when this flag is acted upon. -pub const LIBUSB_TRANSFER_FREE_TRANSFER: libusb_transfer_flags = 4; -/// Terminate transfers that are a multiple of the endpoint's -/// wMaxPacketSize with an extra zero length packet. This is useful -/// when a device protocol mandates that each logical request is -/// terminated by an incomplete packet (i.e. the logical requests are -/// not separated by other means). -/// -/// This flag only affects host-to-device transfers to bulk and interrupt -/// endpoints. In other situations, it is ignored. -/// -/// This flag only affects transfers with a length that is a multiple of -/// the endpoint's wMaxPacketSize. On transfers of other lengths, this -/// flag has no effect. Therefore, if you are working with a device that -/// needs a ZLP whenever the end of the logical request falls on a packet -/// boundary, then it is sensible to set this flag on <em>every</em> -/// transfer (you do not have to worry about only setting it on transfers -/// that end on the boundary). -/// -/// This flag is currently only supported on Linux. -/// On other systems, libusb_submit_transfer() will return -/// LIBUSB_ERROR_NOT_SUPPORTED for every transfer where this flag is set. -/// -/// Available since libusb-1.0.9. -pub const LIBUSB_TRANSFER_ADD_ZERO_PACKET: libusb_transfer_flags = 8; -/// \ingroup libusb_asyncio -/// libusb_transfer.flags values -pub type libusb_transfer_flags = u32; -/// \ingroup libusb_asyncio -/// Isochronous packet descriptor. -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct libusb_iso_packet_descriptor { - /// Length of data to request in this packet - pub length: ::std::os::raw::c_uint, - /// Amount of data that was actually transferred - pub actual_length: ::std::os::raw::c_uint, - /// Status code for this packet - pub status: libusb_transfer_status, -} -#[test] -fn bindgen_test_layout_libusb_iso_packet_descriptor() { - assert_eq!( - ::std::mem::size_of::<libusb_iso_packet_descriptor>(), - 12usize, - concat!("Size of: ", stringify!(libusb_iso_packet_descriptor)) - ); - assert_eq!( - ::std::mem::align_of::<libusb_iso_packet_descriptor>(), - 4usize, - concat!("Alignment of ", stringify!(libusb_iso_packet_descriptor)) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::<libusb_iso_packet_descriptor>())).length as *const _ as usize - }, - 0usize, - concat!( - "Offset of field: ", - stringify!(libusb_iso_packet_descriptor), - "::", - stringify!(length) - ) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::<libusb_iso_packet_descriptor>())).actual_length as *const _ - as usize - }, - 4usize, - concat!( - "Offset of field: ", - stringify!(libusb_iso_packet_descriptor), - "::", - stringify!(actual_length) - ) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::<libusb_iso_packet_descriptor>())).status as *const _ as usize - }, - 8usize, - concat!( - "Offset of field: ", - stringify!(libusb_iso_packet_descriptor), - "::", - stringify!(status) - ) - ); -} -/// \ingroup libusb_asyncio -/// Asynchronous transfer callback function type. When submitting asynchronous -/// transfers, you pass a pointer to a callback function of this type via the -/// \ref libusb_transfer::callback "callback" member of the libusb_transfer -/// structure. libusb will call this function later, when the transfer has -/// completed or failed. See \ref libusb_asyncio for more information. -/// \param transfer The libusb_transfer struct the callback function is being -/// notified about. -pub type libusb_transfer_cb_fn = - ::std::option::Option<unsafe extern "C" fn(transfer: *mut libusb_transfer)>; -/// \ingroup libusb_asyncio -/// The generic USB transfer structure. The user populates this structure and -/// then submits it in order to request a transfer. After the transfer has -/// completed, the library populates the transfer with the results and passes -/// it back to the user. -#[repr(C)] -#[derive(Debug)] -pub struct libusb_transfer { - /// Handle of the device that this transfer will be submitted to - pub dev_handle: *mut libusb_device_handle, - /// A bitwise OR combination of \ref libusb_transfer_flags. - pub flags: u8, - /// Address of the endpoint where this transfer will be sent. - pub endpoint: ::std::os::raw::c_uchar, - /// Type of the endpoint from \ref libusb_transfer_type - pub type_: ::std::os::raw::c_uchar, - /// Timeout for this transfer in millseconds. A value of 0 indicates no - /// timeout. - pub timeout: ::std::os::raw::c_uint, - /// The status of the transfer. Read-only, and only for use within - /// transfer callback function. - /// - /// If this is an isochronous transfer, this field may read COMPLETED even - /// if there were errors in the frames. Use the - /// \ref libusb_iso_packet_descriptor::status "status" field in each packet - /// to determine if errors occurred. - pub status: libusb_transfer_status, - /// Length of the data buffer - pub length: ::std::os::raw::c_int, - /// Actual length of data that was transferred. Read-only, and only for - /// use within transfer callback function. Not valid for isochronous - /// endpoint transfers. - pub actual_length: ::std::os::raw::c_int, - /// Callback function. This will be invoked when the transfer completes, - /// fails, or is cancelled. - pub callback: libusb_transfer_cb_fn, - /// User context data to pass to the callback function. - pub user_data: *mut ::std::os::raw::c_void, - /// Data buffer - pub buffer: *mut ::std::os::raw::c_uchar, - /// Number of isochronous packets. Only used for I/O with isochronous - /// endpoints. - pub num_iso_packets: ::std::os::raw::c_int, - /// Isochronous packet descriptors, for isochronous transfers only. - pub iso_packet_desc: __IncompleteArrayField<libusb_iso_packet_descriptor>, -} -#[test] -fn bindgen_test_layout_libusb_transfer() { - assert_eq!( - ::std::mem::size_of::<libusb_transfer>(), - 64usize, - concat!("Size of: ", stringify!(libusb_transfer)) - ); - assert_eq!( - ::std::mem::align_of::<libusb_transfer>(), - 8usize, - concat!("Alignment of ", stringify!(libusb_transfer)) - ); -} -/// The libusb_has_capability() API is available. -pub const LIBUSB_CAP_HAS_CAPABILITY: libusb_capability = 0; -/// Hotplug support is available on this platform. -pub const LIBUSB_CAP_HAS_HOTPLUG: libusb_capability = 1; -/// The library can access HID devices without requiring user intervention. -/// Note that before being able to actually access an HID device, you may -/// still have to call additional libusb functions such as -/// \ref libusb_detach_kernel_driver(). -pub const LIBUSB_CAP_HAS_HID_ACCESS: libusb_capability = 256; -/// The library supports detaching of the default USB driver, using -/// \ref libusb_detach_kernel_driver(), if one is set by the OS kernel -pub const LIBUSB_CAP_SUPPORTS_DETACH_KERNEL_DRIVER: libusb_capability = 257; -/// \ingroup libusb_misc -/// Capabilities supported by an instance of libusb on the current running -/// platform. Test if the loaded library supports a given capability by calling -/// \ref libusb_has_capability(). -pub type libusb_capability = u32; -pub const LIBUSB_LOG_LEVEL_NONE: libusb_log_level = 0; -pub const LIBUSB_LOG_LEVEL_ERROR: libusb_log_level = 1; -pub const LIBUSB_LOG_LEVEL_WARNING: libusb_log_level = 2; -pub const LIBUSB_LOG_LEVEL_INFO: libusb_log_level = 3; -pub const LIBUSB_LOG_LEVEL_DEBUG: libusb_log_level = 4; -/// \ingroup libusb_lib -/// Log message levels. -/// - LIBUSB_LOG_LEVEL_NONE (0) : no messages ever printed by the library (default) -/// - LIBUSB_LOG_LEVEL_ERROR (1) : error messages are printed to stderr -/// - LIBUSB_LOG_LEVEL_WARNING (2) : warning and error messages are printed to stderr -/// - LIBUSB_LOG_LEVEL_INFO (3) : informational messages are printed to stdout, warning -/// and error messages are printed to stderr -/// - LIBUSB_LOG_LEVEL_DEBUG (4) : debug and informational messages are printed to stdout, -/// warnings and errors to stderr -pub type libusb_log_level = u32; -extern "C" { - pub fn libusb_init(ctx: *mut *mut libusb_context) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn libusb_exit(ctx: *mut libusb_context); -} -extern "C" { - pub fn libusb_wrap_sys_device( - ctx: *mut libusb_context, - fd: __intptr_t, - handle: *mut *mut libusb_device_handle, - ) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn libusb_set_debug(ctx: *mut libusb_context, level: ::std::os::raw::c_int); -} -extern "C" { - pub fn libusb_get_version() -> *const libusb_version; -} -extern "C" { - pub fn libusb_has_capability(capability: u32) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn libusb_error_name(errcode: ::std::os::raw::c_int) -> *const ::std::os::raw::c_char; -} -extern "C" { - pub fn libusb_setlocale(locale: *const ::std::os::raw::c_char) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn libusb_strerror(errcode: libusb_error) -> *const ::std::os::raw::c_char; -} -extern "C" { - pub fn libusb_get_device_list( - ctx: *mut libusb_context, - list: *mut *mut *mut libusb_device, - ) -> isize; -} -extern "C" { - pub fn libusb_free_device_list( - list: *mut *mut libusb_device, - unref_devices: ::std::os::raw::c_int, - ); -} -extern "C" { - pub fn libusb_ref_device(dev: *mut libusb_device) -> *mut libusb_device; -} -extern "C" { - pub fn libusb_unref_device(dev: *mut libusb_device); -} -extern "C" { - pub fn libusb_get_configuration( - dev: *mut libusb_device_handle, - config: *mut ::std::os::raw::c_int, - ) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn libusb_get_device_descriptor( - dev: *mut libusb_device, - desc: *mut libusb_device_descriptor, - ) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn libusb_get_active_config_descriptor( - dev: *mut libusb_device, - config: *mut *mut libusb_config_descriptor, - ) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn libusb_get_config_descriptor( - dev: *mut libusb_device, - config_index: u8, - config: *mut *mut libusb_config_descriptor, - ) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn libusb_get_config_descriptor_by_value( - dev: *mut libusb_device, - bConfigurationValue: u8, - config: *mut *mut libusb_config_descriptor, - ) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn libusb_free_config_descriptor(config: *mut libusb_config_descriptor); -} -extern "C" { - pub fn libusb_get_ss_endpoint_companion_descriptor( - ctx: *mut libusb_context, - endpoint: *const libusb_endpoint_descriptor, - ep_comp: *mut *mut libusb_ss_endpoint_companion_descriptor, - ) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn libusb_free_ss_endpoint_companion_descriptor( - ep_comp: *mut libusb_ss_endpoint_companion_descriptor, - ); -} -extern "C" { - pub fn libusb_get_bos_descriptor( - dev_handle: *mut libusb_device_handle, - bos: *mut *mut libusb_bos_descriptor, - ) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn libusb_free_bos_descriptor(bos: *mut libusb_bos_descriptor); -} -extern "C" { - pub fn libusb_get_usb_2_0_extension_descriptor( - ctx: *mut libusb_context, - dev_cap: *mut libusb_bos_dev_capability_descriptor, - usb_2_0_extension: *mut *mut libusb_usb_2_0_extension_descriptor, - ) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn libusb_free_usb_2_0_extension_descriptor( - usb_2_0_extension: *mut libusb_usb_2_0_extension_descriptor, - ); -} -extern "C" { - pub fn libusb_get_ss_usb_device_capability_descriptor( - ctx: *mut libusb_context, - dev_cap: *mut libusb_bos_dev_capability_descriptor, - ss_usb_device_cap: *mut *mut libusb_ss_usb_device_capability_descriptor, - ) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn libusb_free_ss_usb_device_capability_descriptor( - ss_usb_device_cap: *mut libusb_ss_usb_device_capability_descriptor, - ); -} -extern "C" { - pub fn libusb_get_container_id_descriptor( - ctx: *mut libusb_context, - dev_cap: *mut libusb_bos_dev_capability_descriptor, - container_id: *mut *mut libusb_container_id_descriptor, - ) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn libusb_free_container_id_descriptor(container_id: *mut libusb_container_id_descriptor); -} -extern "C" { - pub fn libusb_get_bus_number(dev: *mut libusb_device) -> u8; -} -extern "C" { - pub fn libusb_get_port_number(dev: *mut libusb_device) -> u8; -} -extern "C" { - pub fn libusb_get_port_numbers( - dev: *mut libusb_device, - port_numbers: *mut u8, - port_numbers_len: ::std::os::raw::c_int, - ) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn libusb_get_port_path( - ctx: *mut libusb_context, - dev: *mut libusb_device, - path: *mut u8, - path_length: u8, - ) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn libusb_get_parent(dev: *mut libusb_device) -> *mut libusb_device; -} -extern "C" { - pub fn libusb_get_device_address(dev: *mut libusb_device) -> u8; -} -extern "C" { - pub fn libusb_get_device_speed(dev: *mut libusb_device) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn libusb_get_max_packet_size( - dev: *mut libusb_device, - endpoint: ::std::os::raw::c_uchar, - ) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn libusb_get_max_iso_packet_size( - dev: *mut libusb_device, - endpoint: ::std::os::raw::c_uchar, - ) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn libusb_open( - dev: *mut libusb_device, - dev_handle: *mut *mut libusb_device_handle, - ) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn libusb_close(dev_handle: *mut libusb_device_handle); -} -extern "C" { - pub fn libusb_get_device(dev_handle: *mut libusb_device_handle) -> *mut libusb_device; -} -extern "C" { - pub fn libusb_set_configuration( - dev_handle: *mut libusb_device_handle, - configuration: ::std::os::raw::c_int, - ) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn libusb_claim_interface( - dev_handle: *mut libusb_device_handle, - interface_number: ::std::os::raw::c_int, - ) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn libusb_release_interface( - dev_handle: *mut libusb_device_handle, - interface_number: ::std::os::raw::c_int, - ) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn libusb_open_device_with_vid_pid( - ctx: *mut libusb_context, - vendor_id: u16, - product_id: u16, - ) -> *mut libusb_device_handle; -} -extern "C" { - pub fn libusb_set_interface_alt_setting( - dev_handle: *mut libusb_device_handle, - interface_number: ::std::os::raw::c_int, - alternate_setting: ::std::os::raw::c_int, - ) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn libusb_clear_halt( - dev_handle: *mut libusb_device_handle, - endpoint: ::std::os::raw::c_uchar, - ) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn libusb_reset_device(dev_handle: *mut libusb_device_handle) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn libusb_alloc_streams( - dev_handle: *mut libusb_device_handle, - num_streams: u32, - endpoints: *mut ::std::os::raw::c_uchar, - num_endpoints: ::std::os::raw::c_int, - ) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn libusb_free_streams( - dev_handle: *mut libusb_device_handle, - endpoints: *mut ::std::os::raw::c_uchar, - num_endpoints: ::std::os::raw::c_int, - ) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn libusb_dev_mem_alloc( - dev_handle: *mut libusb_device_handle, - length: usize, - ) -> *mut ::std::os::raw::c_uchar; -} -extern "C" { - pub fn libusb_dev_mem_free( - dev_handle: *mut libusb_device_handle, - buffer: *mut ::std::os::raw::c_uchar, - length: usize, - ) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn libusb_kernel_driver_active( - dev_handle: *mut libusb_device_handle, - interface_number: ::std::os::raw::c_int, - ) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn libusb_detach_kernel_driver( - dev_handle: *mut libusb_device_handle, - interface_number: ::std::os::raw::c_int, - ) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn libusb_attach_kernel_driver( - dev_handle: *mut libusb_device_handle, - interface_number: ::std::os::raw::c_int, - ) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn libusb_set_auto_detach_kernel_driver( - dev_handle: *mut libusb_device_handle, - enable: ::std::os::raw::c_int, - ) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn libusb_alloc_transfer(iso_packets: ::std::os::raw::c_int) -> *mut libusb_transfer; -} -extern "C" { - pub fn libusb_submit_transfer(transfer: *mut libusb_transfer) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn libusb_cancel_transfer(transfer: *mut libusb_transfer) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn libusb_free_transfer(transfer: *mut libusb_transfer); -} -extern "C" { - pub fn libusb_transfer_set_stream_id(transfer: *mut libusb_transfer, stream_id: u32); -} -extern "C" { - pub fn libusb_transfer_get_stream_id(transfer: *mut libusb_transfer) -> u32; -} -extern "C" { - pub fn libusb_control_transfer( - dev_handle: *mut libusb_device_handle, - request_type: u8, - bRequest: u8, - wValue: u16, - wIndex: u16, - data: *mut ::std::os::raw::c_uchar, - wLength: u16, - timeout: ::std::os::raw::c_uint, - ) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn libusb_bulk_transfer( - dev_handle: *mut libusb_device_handle, - endpoint: ::std::os::raw::c_uchar, - data: *mut ::std::os::raw::c_uchar, - length: ::std::os::raw::c_int, - actual_length: *mut ::std::os::raw::c_int, - timeout: ::std::os::raw::c_uint, - ) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn libusb_interrupt_transfer( - dev_handle: *mut libusb_device_handle, - endpoint: ::std::os::raw::c_uchar, - data: *mut ::std::os::raw::c_uchar, - length: ::std::os::raw::c_int, - actual_length: *mut ::std::os::raw::c_int, - timeout: ::std::os::raw::c_uint, - ) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn libusb_get_string_descriptor_ascii( - dev_handle: *mut libusb_device_handle, - desc_index: u8, - data: *mut ::std::os::raw::c_uchar, - length: ::std::os::raw::c_int, - ) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn libusb_try_lock_events(ctx: *mut libusb_context) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn libusb_lock_events(ctx: *mut libusb_context); -} -extern "C" { - pub fn libusb_unlock_events(ctx: *mut libusb_context); -} -extern "C" { - pub fn libusb_event_handling_ok(ctx: *mut libusb_context) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn libusb_event_handler_active(ctx: *mut libusb_context) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn libusb_interrupt_event_handler(ctx: *mut libusb_context); -} -extern "C" { - pub fn libusb_lock_event_waiters(ctx: *mut libusb_context); -} -extern "C" { - pub fn libusb_unlock_event_waiters(ctx: *mut libusb_context); -} -extern "C" { - pub fn libusb_wait_for_event( - ctx: *mut libusb_context, - tv: *mut timeval, - ) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn libusb_handle_events_timeout( - ctx: *mut libusb_context, - tv: *mut timeval, - ) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn libusb_handle_events_timeout_completed( - ctx: *mut libusb_context, - tv: *mut timeval, - completed: *mut ::std::os::raw::c_int, - ) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn libusb_handle_events(ctx: *mut libusb_context) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn libusb_handle_events_completed( - ctx: *mut libusb_context, - completed: *mut ::std::os::raw::c_int, - ) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn libusb_handle_events_locked( - ctx: *mut libusb_context, - tv: *mut timeval, - ) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn libusb_pollfds_handle_timeouts(ctx: *mut libusb_context) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn libusb_get_next_timeout( - ctx: *mut libusb_context, - tv: *mut timeval, - ) -> ::std::os::raw::c_int; -} -/// \ingroup libusb_poll -/// File descriptor for polling -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct libusb_pollfd { - /// Numeric file descriptor - pub fd: ::std::os::raw::c_int, - /// Event flags to poll for from <poll.h>. POLLIN indicates that you - /// should monitor this file descriptor for becoming ready to read from, - /// and POLLOUT indicates that you should monitor this file descriptor for - /// nonblocking write readiness. - pub events: ::std::os::raw::c_short, -} -#[test] -fn bindgen_test_layout_libusb_pollfd() { - assert_eq!( - ::std::mem::size_of::<libusb_pollfd>(), - 8usize, - concat!("Size of: ", stringify!(libusb_pollfd)) - ); - assert_eq!( - ::std::mem::align_of::<libusb_pollfd>(), - 4usize, - concat!("Alignment of ", stringify!(libusb_pollfd)) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<libusb_pollfd>())).fd as *const _ as usize }, - 0usize, - concat!( - "Offset of field: ", - stringify!(libusb_pollfd), - "::", - stringify!(fd) - ) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<libusb_pollfd>())).events as *const _ as usize }, - 4usize, - concat!( - "Offset of field: ", - stringify!(libusb_pollfd), - "::", - stringify!(events) - ) - ); -} -/// \ingroup libusb_poll -/// Callback function, invoked when a new file descriptor should be added -/// to the set of file descriptors monitored for events. -/// \param fd the new file descriptor -/// \param events events to monitor for, see \ref libusb_pollfd for a -/// description -/// \param user_data User data pointer specified in -/// libusb_set_pollfd_notifiers() call -/// \see libusb_set_pollfd_notifiers() -pub type libusb_pollfd_added_cb = ::std::option::Option< - unsafe extern "C" fn( - fd: ::std::os::raw::c_int, - events: ::std::os::raw::c_short, - user_data: *mut ::std::os::raw::c_void, - ), ->; -/// \ingroup libusb_poll -/// Callback function, invoked when a file descriptor should be removed from -/// the set of file descriptors being monitored for events. After returning -/// from this callback, do not use that file descriptor again. -/// \param fd the file descriptor to stop monitoring -/// \param user_data User data pointer specified in -/// libusb_set_pollfd_notifiers() call -/// \see libusb_set_pollfd_notifiers() -pub type libusb_pollfd_removed_cb = ::std::option::Option< - unsafe extern "C" fn(fd: ::std::os::raw::c_int, user_data: *mut ::std::os::raw::c_void), ->; -extern "C" { - pub fn libusb_get_pollfds(ctx: *mut libusb_context) -> *mut *const libusb_pollfd; -} -extern "C" { - pub fn libusb_free_pollfds(pollfds: *mut *const libusb_pollfd); -} -extern "C" { - pub fn libusb_set_pollfd_notifiers( - ctx: *mut libusb_context, - added_cb: libusb_pollfd_added_cb, - removed_cb: libusb_pollfd_removed_cb, - user_data: *mut ::std::os::raw::c_void, - ); -} -/// \ingroup libusb_hotplug -/// Callback handle. -/// -/// Callbacks handles are generated by libusb_hotplug_register_callback() -/// and can be used to deregister callbacks. Callback handles are unique -/// per libusb_context and it is safe to call libusb_hotplug_deregister_callback() -/// on an already deregisted callback. -/// -/// Since version 1.0.16, \ref LIBUSB_API_VERSION >= 0x01000102 -/// -/// For more information, see \ref libusb_hotplug. -pub type libusb_hotplug_callback_handle = ::std::os::raw::c_int; -/// Default value when not using any flags. -pub const LIBUSB_HOTPLUG_NO_FLAGS: libusb_hotplug_flag = 0; -/// Arm the callback and fire it for all matching currently attached devices. -pub const LIBUSB_HOTPLUG_ENUMERATE: libusb_hotplug_flag = 1; -/// \ingroup libusb_hotplug -/// -/// Since version 1.0.16, \ref LIBUSB_API_VERSION >= 0x01000102 -/// -/// Flags for hotplug events -pub type libusb_hotplug_flag = u32; -/// A device has been plugged in and is ready to use -pub const LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED: libusb_hotplug_event = 1; -/// A device has left and is no longer available. -/// It is the user's responsibility to call libusb_close on any handle associated with a disconnected device. -/// It is safe to call libusb_get_device_descriptor on a device that has left -pub const LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT: libusb_hotplug_event = 2; -/// \ingroup libusb_hotplug -/// -/// Since version 1.0.16, \ref LIBUSB_API_VERSION >= 0x01000102 -/// -/// Hotplug events -pub type libusb_hotplug_event = u32; -/// \ingroup libusb_hotplug -/// Hotplug callback function type. When requesting hotplug event notifications, -/// you pass a pointer to a callback function of this type. -/// -/// This callback may be called by an internal event thread and as such it is -/// recommended the callback do minimal processing before returning. -/// -/// libusb will call this function later, when a matching event had happened on -/// a matching device. See \ref libusb_hotplug for more information. -/// -/// It is safe to call either libusb_hotplug_register_callback() or -/// libusb_hotplug_deregister_callback() from within a callback function. -/// -/// Since version 1.0.16, \ref LIBUSB_API_VERSION >= 0x01000102 -/// -/// \param ctx context of this notification -/// \param device libusb_device this event occurred on -/// \param event event that occurred -/// \param user_data user data provided when this callback was registered -/// \returns bool whether this callback is finished processing events. -/// returning 1 will cause this callback to be deregistered -pub type libusb_hotplug_callback_fn = ::std::option::Option< - unsafe extern "C" fn( - ctx: *mut libusb_context, - device: *mut libusb_device, - event: libusb_hotplug_event, - user_data: *mut ::std::os::raw::c_void, - ) -> ::std::os::raw::c_int, ->; -extern "C" { - /// \ingroup libusb_hotplug - /// Register a hotplug callback function - /// - /// Register a callback with the libusb_context. The callback will fire - /// when a matching event occurs on a matching device. The callback is - /// armed until either it is deregistered with libusb_hotplug_deregister_callback() - /// or the supplied callback returns 1 to indicate it is finished processing events. - /// - /// If the \ref LIBUSB_HOTPLUG_ENUMERATE is passed the callback will be - /// called with a \ref LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED for all devices - /// already plugged into the machine. Note that libusb modifies its internal - /// device list from a separate thread, while calling hotplug callbacks from - /// libusb_handle_events(), so it is possible for a device to already be present - /// on, or removed from, its internal device list, while the hotplug callbacks - /// still need to be dispatched. This means that when using \ref - /// LIBUSB_HOTPLUG_ENUMERATE, your callback may be called twice for the arrival - /// of the same device, once from libusb_hotplug_register_callback() and once - /// from libusb_handle_events(); and/or your callback may be called for the - /// removal of a device for which an arrived call was never made. - /// - /// Since version 1.0.16, \ref LIBUSB_API_VERSION >= 0x01000102 - /// - /// \param[in] ctx context to register this callback with - /// \param[in] events bitwise or of events that will trigger this callback. See \ref - /// libusb_hotplug_event - /// \param[in] flags hotplug callback flags. See \ref libusb_hotplug_flag - /// \param[in] vendor_id the vendor id to match or \ref LIBUSB_HOTPLUG_MATCH_ANY - /// \param[in] product_id the product id to match or \ref LIBUSB_HOTPLUG_MATCH_ANY - /// \param[in] dev_class the device class to match or \ref LIBUSB_HOTPLUG_MATCH_ANY - /// \param[in] cb_fn the function to be invoked on a matching event/device - /// \param[in] user_data user data to pass to the callback function - /// \param[out] callback_handle pointer to store the handle of the allocated callback (can be NULL) - /// \returns LIBUSB_SUCCESS on success LIBUSB_ERROR code on failure - pub fn libusb_hotplug_register_callback( - ctx: *mut libusb_context, - events: libusb_hotplug_event, - flags: libusb_hotplug_flag, - vendor_id: ::std::os::raw::c_int, - product_id: ::std::os::raw::c_int, - dev_class: ::std::os::raw::c_int, - cb_fn: libusb_hotplug_callback_fn, - user_data: *mut ::std::os::raw::c_void, - callback_handle: *mut libusb_hotplug_callback_handle, - ) -> ::std::os::raw::c_int; -} -extern "C" { - /// \ingroup libusb_hotplug - /// Deregisters a hotplug callback. - /// - /// Deregister a callback from a libusb_context. This function is safe to call from within - /// a hotplug callback. - /// - /// Since version 1.0.16, \ref LIBUSB_API_VERSION >= 0x01000102 - /// - /// \param[in] ctx context this callback is registered with - /// \param[in] callback_handle the handle of the callback to deregister - pub fn libusb_hotplug_deregister_callback( - ctx: *mut libusb_context, - callback_handle: libusb_hotplug_callback_handle, - ); -} -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct __locale_data { - pub _address: u8, -} diff --git a/usb_util/src/config_descriptor.rs b/usb_util/src/config_descriptor.rs deleted file mode 100644 index 8aebbac..0000000 --- a/usb_util/src/config_descriptor.rs +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright 2018 The Chromium OS Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -use std::ops::Deref; - -use crate::bindings::{self, libusb_config_descriptor}; -use crate::interface_descriptor::InterfaceDescriptor; - -/// ConfigDescriptor wraps libusb_config_descriptor. -pub struct ConfigDescriptor { - descriptor: *mut libusb_config_descriptor, -} - -impl Drop for ConfigDescriptor { - // Free configuration descriptor. - // Safe because 'self' is intialized with a valid libusb_config_descriptor from libusb - // functions. - fn drop(&mut self) { - unsafe { - bindings::libusb_free_config_descriptor(self.descriptor); - } - } -} - -impl ConfigDescriptor { - /// Build ConfigDescriptor. 'descriptor' should be a valid pointer from - /// libusb_config_descriptor. This function will panic if it's null. - pub unsafe fn new(descriptor: *mut libusb_config_descriptor) -> ConfigDescriptor { - assert!(!descriptor.is_null()); - ConfigDescriptor { descriptor } - } - - /// Get interface by number and alt setting. - pub fn get_interface_descriptor( - &self, - interface_num: u8, - alt_setting: i32, - ) -> Option<InterfaceDescriptor> { - let config_descriptor = self.deref(); - if interface_num >= config_descriptor.bNumInterfaces { - return None; - } - // Safe because interface num is checked. - let interface = unsafe { &*(config_descriptor.interface.offset(interface_num as isize)) }; - - if alt_setting >= interface.num_altsetting { - return None; - } - // Safe because setting num is checked. - unsafe { - Some(InterfaceDescriptor::new( - &*(interface.altsetting.offset(alt_setting as isize)), - )) - } - } -} - -impl Deref for ConfigDescriptor { - type Target = libusb_config_descriptor; - - fn deref(&self) -> &libusb_config_descriptor { - // Safe because 'self.descriptor' is valid. - unsafe { &*(self.descriptor) } - } -} diff --git a/usb_util/src/descriptor.rs b/usb_util/src/descriptor.rs new file mode 100644 index 0000000..cf711d1 --- /dev/null +++ b/usb_util/src/descriptor.rs @@ -0,0 +1,499 @@ +// Copyright 2019 The Chromium OS Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +use crate::types::{self, Descriptor, DescriptorHeader, EndpointDescriptor}; +use crate::{Error, Result}; +use data_model::DataInit; +use std::collections::BTreeMap; +use std::io::{self, Read}; +use std::mem::size_of; +use std::ops::Deref; +use sys_util::warn; + +#[derive(Clone)] +pub struct DeviceDescriptorTree { + inner: types::DeviceDescriptor, + // Map of bConfigurationValue to ConfigDescriptor + config_descriptors: BTreeMap<u8, ConfigDescriptorTree>, +} + +#[derive(Clone)] +pub struct ConfigDescriptorTree { + inner: types::ConfigDescriptor, + // Map of (bInterfaceNumber, bAlternateSetting) to InterfaceDescriptor + interface_descriptors: BTreeMap<(u8, u8), InterfaceDescriptorTree>, +} + +#[derive(Clone)] +pub struct InterfaceDescriptorTree { + inner: types::InterfaceDescriptor, + // Map of bEndpointAddress to EndpointDescriptor + endpoint_descriptors: BTreeMap<u8, EndpointDescriptor>, +} + +impl DeviceDescriptorTree { + pub fn get_config_descriptor(&self, config_value: u8) -> Option<&ConfigDescriptorTree> { + self.config_descriptors.get(&config_value) + } +} + +impl Deref for DeviceDescriptorTree { + type Target = types::DeviceDescriptor; + + fn deref(&self) -> &types::DeviceDescriptor { + &self.inner + } +} + +impl ConfigDescriptorTree { + /// Get interface by number and alt setting. + pub fn get_interface_descriptor( + &self, + interface_num: u8, + alt_setting: u8, + ) -> Option<&InterfaceDescriptorTree> { + self.interface_descriptors + .get(&(interface_num, alt_setting)) + } +} + +impl Deref for ConfigDescriptorTree { + type Target = types::ConfigDescriptor; + + fn deref(&self) -> &types::ConfigDescriptor { + &self.inner + } +} + +impl InterfaceDescriptorTree { + pub fn get_endpoint_descriptor(&self, ep_idx: u8) -> Option<&EndpointDescriptor> { + self.endpoint_descriptors.get(&ep_idx) + } +} + +impl Deref for InterfaceDescriptorTree { + type Target = types::InterfaceDescriptor; + + fn deref(&self) -> &types::InterfaceDescriptor { + &self.inner + } +} + +/// Given a `reader` for a full set of descriptors as provided by the Linux kernel +/// usbdevfs `descriptors` file, parse the descriptors into a tree data structure. +pub fn parse_usbfs_descriptors<R: Read>(mut reader: R) -> Result<DeviceDescriptorTree> { + // Given a structure of length `struct_length`, of which `bytes_consumed` have + // already been read, skip the remainder of the struct. If `bytes_consumed` is + // more than `struct_length`, no additional bytes are skipped. + fn skip<R: Read>(reader: R, bytes_consumed: usize, struct_length: u8) -> io::Result<u64> { + let bytes_to_skip = u64::from(struct_length).saturating_sub(bytes_consumed as u64); + io::copy(&mut reader.take(bytes_to_skip), &mut io::sink()) + } + + // Find the next descriptor of type T and return it. + // Any other descriptors encountered while searching for the expected type are skipped. + fn next_descriptor<R: Read, T: Descriptor + DataInit>(mut reader: R) -> Result<T> { + let desc_type = T::descriptor_type() as u8; + loop { + let hdr = DescriptorHeader::from_reader(&mut reader).map_err(Error::DescriptorRead)?; + if hdr.bDescriptorType == desc_type { + if usize::from(hdr.bLength) < size_of::<DescriptorHeader>() + size_of::<T>() { + return Err(Error::DescriptorParse); + } + + let desc = T::from_reader(&mut reader).map_err(Error::DescriptorRead)?; + + // Skip any extra data beyond the standard descriptor length. + skip( + &mut reader, + size_of::<DescriptorHeader>() + size_of::<T>(), + hdr.bLength, + ) + .map_err(Error::DescriptorRead)?; + return Ok(desc); + } + + // Skip this entire descriptor, since it's not the right type. + skip(&mut reader, size_of::<DescriptorHeader>(), hdr.bLength) + .map_err(Error::DescriptorRead)?; + } + } + + let raw_device_descriptor: types::DeviceDescriptor = next_descriptor(&mut reader)?; + let mut device_descriptor = DeviceDescriptorTree { + inner: raw_device_descriptor, + config_descriptors: BTreeMap::new(), + }; + + for cfg_idx in 0..device_descriptor.bNumConfigurations { + if let Ok(raw_config_descriptor) = + next_descriptor::<_, types::ConfigDescriptor>(&mut reader) + { + let mut config_descriptor = ConfigDescriptorTree { + inner: raw_config_descriptor, + interface_descriptors: BTreeMap::new(), + }; + + for intf_idx in 0..config_descriptor.bNumInterfaces { + if let Ok(raw_interface_descriptor) = + next_descriptor::<_, types::InterfaceDescriptor>(&mut reader) + { + let mut interface_descriptor = InterfaceDescriptorTree { + inner: raw_interface_descriptor, + endpoint_descriptors: BTreeMap::new(), + }; + + for ep_idx in 0..interface_descriptor.bNumEndpoints { + if let Ok(endpoint_descriptor) = + next_descriptor::<_, EndpointDescriptor>(&mut reader) + { + interface_descriptor + .endpoint_descriptors + .insert(ep_idx, endpoint_descriptor); + } else { + warn!("Could not read endpoint descriptor {}", ep_idx); + break; + } + } + + config_descriptor.interface_descriptors.insert( + ( + interface_descriptor.bInterfaceNumber, + interface_descriptor.bAlternateSetting, + ), + interface_descriptor, + ); + } else { + warn!("Could not read interface descriptor {}", intf_idx); + break; + } + } + + device_descriptor + .config_descriptors + .insert(config_descriptor.bConfigurationValue, config_descriptor); + } else { + warn!("Could not read config descriptor {}", cfg_idx); + break; + } + } + + Ok(device_descriptor) +} + +#[cfg(test)] +mod tests { + use super::*; + #[test] + fn parse_descriptors_mass_storage() { + let data: &[u8] = &[ + 0x12, 0x01, 0x00, 0x03, 0x00, 0x00, 0x00, 0x09, 0x81, 0x07, 0x80, 0x55, 0x10, 0x00, + 0x01, 0x02, 0x03, 0x01, 0x09, 0x02, 0x2C, 0x00, 0x01, 0x01, 0x00, 0x80, 0x32, 0x09, + 0x04, 0x00, 0x00, 0x02, 0x08, 0x06, 0x50, 0x00, 0x07, 0x05, 0x81, 0x02, 0x00, 0x04, + 0x00, 0x06, 0x30, 0x0F, 0x00, 0x00, 0x00, 0x07, 0x05, 0x02, 0x02, 0x00, 0x04, 0x00, + 0x06, 0x30, 0x0F, 0x00, 0x00, 0x00, + ]; + + let d = parse_usbfs_descriptors(data).expect("parse_usbfs_descriptors failed"); + + // The seemingly-redundant u16::from() calls avoid borrows of packed fields. + + assert_eq!(u16::from(d.bcdUSB), 0x03_00); + assert_eq!(d.bDeviceClass, 0x00); + assert_eq!(d.bDeviceSubClass, 0x00); + assert_eq!(d.bDeviceProtocol, 0x00); + assert_eq!(d.bMaxPacketSize0, 9); + assert_eq!(u16::from(d.idVendor), 0x0781); + assert_eq!(u16::from(d.idProduct), 0x5580); + assert_eq!(u16::from(d.bcdDevice), 0x00_10); + assert_eq!(d.iManufacturer, 1); + assert_eq!(d.iProduct, 2); + assert_eq!(d.iSerialNumber, 3); + assert_eq!(d.bNumConfigurations, 1); + + let c = d + .get_config_descriptor(1) + .expect("could not get config descriptor 1"); + assert_eq!(u16::from(c.wTotalLength), 44); + assert_eq!(c.bNumInterfaces, 1); + assert_eq!(c.bConfigurationValue, 1); + assert_eq!(c.iConfiguration, 0); + assert_eq!(c.bmAttributes, 0x80); + assert_eq!(c.bMaxPower, 50); + + let i = c + .get_interface_descriptor(0, 0) + .expect("could not get interface descriptor 0 alt setting 0"); + assert_eq!(i.bInterfaceNumber, 0); + assert_eq!(i.bAlternateSetting, 0); + assert_eq!(i.bNumEndpoints, 2); + assert_eq!(i.bInterfaceClass, 0x08); + assert_eq!(i.bInterfaceSubClass, 0x06); + assert_eq!(i.bInterfaceProtocol, 0x50); + assert_eq!(i.iInterface, 0); + + let e = i + .get_endpoint_descriptor(0) + .expect("could not get endpoint 0 descriptor"); + assert_eq!(e.bEndpointAddress, 0x81); + assert_eq!(e.bmAttributes, 0x02); + assert_eq!(u16::from(e.wMaxPacketSize), 0x0400); + assert_eq!(e.bInterval, 0); + + let e = i + .get_endpoint_descriptor(1) + .expect("could not get endpoint 1 descriptor"); + assert_eq!(e.bEndpointAddress, 0x02); + assert_eq!(e.bmAttributes, 0x02); + assert_eq!(u16::from(e.wMaxPacketSize), 0x0400); + assert_eq!(e.bInterval, 0); + } + + #[test] + fn parse_descriptors_servo() { + let data: &[u8] = &[ + 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, 0xd1, 0x18, 0x1b, 0x50, 0x00, 0x01, + 0x01, 0x02, 0x03, 0x01, 0x09, 0x02, 0x7c, 0x00, 0x06, 0x01, 0x04, 0xc0, 0xfa, 0x09, + 0x04, 0x00, 0x00, 0x02, 0xff, 0x50, 0x01, 0x06, 0x07, 0x05, 0x81, 0x02, 0x40, 0x00, + 0x0a, 0x07, 0x05, 0x01, 0x02, 0x40, 0x00, 0x00, 0x09, 0x04, 0x02, 0x00, 0x02, 0xff, + 0x52, 0x01, 0x05, 0x07, 0x05, 0x83, 0x02, 0x40, 0x00, 0x0a, 0x07, 0x05, 0x03, 0x02, + 0x40, 0x00, 0x00, 0x09, 0x04, 0x03, 0x00, 0x02, 0xff, 0x50, 0x01, 0x07, 0x07, 0x05, + 0x84, 0x02, 0x10, 0x00, 0x0a, 0x07, 0x05, 0x04, 0x02, 0x10, 0x00, 0x00, 0x09, 0x04, + 0x04, 0x00, 0x02, 0xff, 0x50, 0x01, 0x08, 0x07, 0x05, 0x85, 0x02, 0x10, 0x00, 0x0a, + 0x07, 0x05, 0x05, 0x02, 0x10, 0x00, 0x00, 0x09, 0x04, 0x05, 0x00, 0x02, 0xff, 0x53, + 0xff, 0x09, 0x07, 0x05, 0x86, 0x02, 0x40, 0x00, 0x0a, 0x07, 0x05, 0x06, 0x02, 0x40, + 0x00, 0x00, + ]; + + // Note: configuration 1 has bNumInterfaces == 6, but it actually only contains 5 + // interface descriptors. This causes us to try to read beyond EOF, which should be + // silently ignored by parse_usbfs_descriptors so that we can use the rest of the + // descriptors. + let d = parse_usbfs_descriptors(data).expect("parse_usbfs_descriptors failed"); + + // The seemingly-redundant u16::from() calls avoid borrows of packed fields. + + assert_eq!(u16::from(d.bcdUSB), 0x02_00); + assert_eq!(d.bDeviceClass, 0x00); + assert_eq!(d.bDeviceSubClass, 0x00); + assert_eq!(d.bDeviceProtocol, 0x00); + assert_eq!(d.bMaxPacketSize0, 64); + assert_eq!(u16::from(d.idVendor), 0x18d1); + assert_eq!(u16::from(d.idProduct), 0x501b); + assert_eq!(u16::from(d.bcdDevice), 0x01_00); + assert_eq!(d.iManufacturer, 1); + assert_eq!(d.iProduct, 2); + assert_eq!(d.iSerialNumber, 3); + assert_eq!(d.bNumConfigurations, 1); + + let c = d + .get_config_descriptor(1) + .expect("could not get config descriptor 1"); + assert_eq!(u16::from(c.wTotalLength), 124); + assert_eq!(c.bNumInterfaces, 6); + assert_eq!(c.bConfigurationValue, 1); + assert_eq!(c.iConfiguration, 4); + assert_eq!(c.bmAttributes, 0xc0); + assert_eq!(c.bMaxPower, 250); + + let i = c + .get_interface_descriptor(0, 0) + .expect("could not get interface descriptor 0 alt setting 0"); + assert_eq!(i.bInterfaceNumber, 0); + assert_eq!(i.bAlternateSetting, 0); + assert_eq!(i.bNumEndpoints, 2); + assert_eq!(i.bInterfaceClass, 0xff); + assert_eq!(i.bInterfaceSubClass, 0x50); + assert_eq!(i.bInterfaceProtocol, 0x01); + assert_eq!(i.iInterface, 6); + + let e = i + .get_endpoint_descriptor(0) + .expect("could not get endpoint 0 descriptor"); + assert_eq!(e.bEndpointAddress, 0x81); + assert_eq!(e.bmAttributes, 0x02); + assert_eq!(u16::from(e.wMaxPacketSize), 0x0040); + assert_eq!(e.bInterval, 10); + + let e = i + .get_endpoint_descriptor(1) + .expect("could not get endpoint 1 descriptor"); + assert_eq!(e.bEndpointAddress, 0x01); + assert_eq!(e.bmAttributes, 0x02); + assert_eq!(u16::from(e.wMaxPacketSize), 0x0040); + assert_eq!(e.bInterval, 0); + + let i = c + .get_interface_descriptor(2, 0) + .expect("could not get interface descriptor 2 alt setting 0"); + assert_eq!(i.bInterfaceNumber, 2); + assert_eq!(i.bAlternateSetting, 0); + assert_eq!(i.bNumEndpoints, 2); + assert_eq!(i.bInterfaceClass, 0xff); + assert_eq!(i.bInterfaceSubClass, 0x52); + assert_eq!(i.bInterfaceProtocol, 0x01); + assert_eq!(i.iInterface, 5); + + let e = i + .get_endpoint_descriptor(0) + .expect("could not get endpoint 0 descriptor"); + assert_eq!(e.bEndpointAddress, 0x83); + assert_eq!(e.bmAttributes, 0x02); + assert_eq!(u16::from(e.wMaxPacketSize), 0x0040); + assert_eq!(e.bInterval, 10); + + let e = i + .get_endpoint_descriptor(1) + .expect("could not get endpoint 1 descriptor"); + assert_eq!(e.bEndpointAddress, 0x03); + assert_eq!(e.bmAttributes, 0x02); + assert_eq!(u16::from(e.wMaxPacketSize), 0x0040); + assert_eq!(e.bInterval, 0); + + let i = c + .get_interface_descriptor(3, 0) + .expect("could not get interface descriptor 3 alt setting 0"); + assert_eq!(i.bInterfaceNumber, 3); + assert_eq!(i.bAlternateSetting, 0); + assert_eq!(i.bNumEndpoints, 2); + assert_eq!(i.bInterfaceClass, 0xff); + assert_eq!(i.bInterfaceSubClass, 0x50); + assert_eq!(i.bInterfaceProtocol, 0x01); + assert_eq!(i.iInterface, 7); + + let e = i + .get_endpoint_descriptor(0) + .expect("could not get endpoint 0 descriptor"); + assert_eq!(e.bEndpointAddress, 0x84); + assert_eq!(e.bmAttributes, 0x02); + assert_eq!(u16::from(e.wMaxPacketSize), 0x0010); + assert_eq!(e.bInterval, 10); + + let e = i + .get_endpoint_descriptor(1) + .expect("could not get endpoint 1 descriptor"); + assert_eq!(e.bEndpointAddress, 0x04); + assert_eq!(e.bmAttributes, 0x02); + assert_eq!(u16::from(e.wMaxPacketSize), 0x0010); + assert_eq!(e.bInterval, 0); + + let i = c + .get_interface_descriptor(4, 0) + .expect("could not get interface descriptor 4 alt setting 0"); + assert_eq!(i.bInterfaceNumber, 4); + assert_eq!(i.bAlternateSetting, 0); + assert_eq!(i.bNumEndpoints, 2); + assert_eq!(i.bInterfaceClass, 0xff); + assert_eq!(i.bInterfaceSubClass, 0x50); + assert_eq!(i.bInterfaceProtocol, 0x01); + assert_eq!(i.iInterface, 8); + + let e = i + .get_endpoint_descriptor(0) + .expect("could not get endpoint 0 descriptor"); + assert_eq!(e.bEndpointAddress, 0x85); + assert_eq!(e.bmAttributes, 0x02); + assert_eq!(u16::from(e.wMaxPacketSize), 0x0010); + assert_eq!(e.bInterval, 10); + + let e = i + .get_endpoint_descriptor(1) + .expect("could not get endpoint 1 descriptor"); + assert_eq!(e.bEndpointAddress, 0x05); + assert_eq!(e.bmAttributes, 0x02); + assert_eq!(u16::from(e.wMaxPacketSize), 0x0010); + assert_eq!(e.bInterval, 0); + + let i = c + .get_interface_descriptor(5, 0) + .expect("could not get interface descriptor 5 alt setting 0"); + assert_eq!(i.bInterfaceNumber, 5); + assert_eq!(i.bAlternateSetting, 0); + assert_eq!(i.bNumEndpoints, 2); + assert_eq!(i.bInterfaceClass, 0xff); + assert_eq!(i.bInterfaceSubClass, 0x53); + assert_eq!(i.bInterfaceProtocol, 0xff); + assert_eq!(i.iInterface, 9); + + let e = i + .get_endpoint_descriptor(0) + .expect("could not get endpoint 0 descriptor"); + assert_eq!(e.bEndpointAddress, 0x86); + assert_eq!(e.bmAttributes, 0x02); + assert_eq!(u16::from(e.wMaxPacketSize), 0x0040); + assert_eq!(e.bInterval, 10); + + let e = i + .get_endpoint_descriptor(1) + .expect("could not get endpoint 1 descriptor"); + assert_eq!(e.bEndpointAddress, 0x06); + assert_eq!(e.bmAttributes, 0x02); + assert_eq!(u16::from(e.wMaxPacketSize), 0x0040); + assert_eq!(e.bInterval, 0); + } + + #[test] + fn parse_descriptors_adb() { + let data: &[u8] = &[ + 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, 0xd1, 0x18, 0xe7, 0x4e, 0x10, 0x03, + 0x01, 0x02, 0x03, 0x01, 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0x80, 0xfa, 0x09, + 0x04, 0x00, 0x00, 0x02, 0xff, 0x42, 0x01, 0x05, 0x07, 0x05, 0x01, 0x02, 0x00, 0x02, + 0x00, 0x07, 0x05, 0x81, 0x02, 0x00, 0x02, 0x00, + ]; + + let d = parse_usbfs_descriptors(data).expect("parse_usbfs_descriptors failed"); + + // The seemingly-redundant u16::from() calls avoid borrows of packed fields. + + assert_eq!(u16::from(d.bcdUSB), 0x02_00); + assert_eq!(d.bDeviceClass, 0x00); + assert_eq!(d.bDeviceSubClass, 0x00); + assert_eq!(d.bDeviceProtocol, 0x00); + assert_eq!(d.bMaxPacketSize0, 64); + assert_eq!(u16::from(d.idVendor), 0x18d1); + assert_eq!(u16::from(d.idProduct), 0x4ee7); + assert_eq!(u16::from(d.bcdDevice), 0x03_10); + assert_eq!(d.iManufacturer, 1); + assert_eq!(d.iProduct, 2); + assert_eq!(d.iSerialNumber, 3); + assert_eq!(d.bNumConfigurations, 1); + + let c = d + .get_config_descriptor(1) + .expect("could not get config descriptor 1"); + assert_eq!(u16::from(c.wTotalLength), 32); + assert_eq!(c.bNumInterfaces, 1); + assert_eq!(c.bConfigurationValue, 1); + assert_eq!(c.iConfiguration, 0); + assert_eq!(c.bmAttributes, 0x80); + assert_eq!(c.bMaxPower, 250); + + let i = c + .get_interface_descriptor(0, 0) + .expect("could not get interface descriptor 0 alt setting 0"); + assert_eq!(i.bInterfaceNumber, 0); + assert_eq!(i.bAlternateSetting, 0); + assert_eq!(i.bNumEndpoints, 2); + assert_eq!(i.bInterfaceClass, 0xff); + assert_eq!(i.bInterfaceSubClass, 0x42); + assert_eq!(i.bInterfaceProtocol, 0x01); + assert_eq!(i.iInterface, 5); + + let e = i + .get_endpoint_descriptor(0) + .expect("could not get endpoint 0 descriptor"); + assert_eq!(e.bEndpointAddress, 0x01); + assert_eq!(e.bmAttributes, 0x02); + assert_eq!(u16::from(e.wMaxPacketSize), 0x200); + assert_eq!(e.bInterval, 0); + + let e = i + .get_endpoint_descriptor(1) + .expect("could not get endpoint 1 descriptor"); + assert_eq!(e.bEndpointAddress, 0x81); + assert_eq!(e.bmAttributes, 0x02); + assert_eq!(u16::from(e.wMaxPacketSize), 0x0200); + assert_eq!(e.bInterval, 0); + } +} diff --git a/usb_util/src/device.rs b/usb_util/src/device.rs new file mode 100644 index 0000000..3fc77e2 --- /dev/null +++ b/usb_util/src/device.rs @@ -0,0 +1,458 @@ +// Copyright 2019 The Chromium OS Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +use crate::{ + control_request_type, descriptor, ConfigDescriptorTree, + ControlRequestDataPhaseTransferDirection, ControlRequestRecipient, ControlRequestType, + DeviceDescriptor, DeviceDescriptorTree, Error, Result, StandardControlRequest, +}; +use libc::{EAGAIN, ENODEV, ENOENT}; +use std::convert::TryInto; +use std::fs::File; +use std::io::{Seek, SeekFrom}; +use std::mem::{size_of, size_of_val}; +use std::os::raw::{c_int, c_uint, c_ulong, c_void}; +use std::sync::Arc; +use sys_util::handle_eintr_errno; + +/// Device represents a USB device. +pub struct Device { + fd: Arc<File>, + device_descriptor_tree: DeviceDescriptorTree, +} + +/// Transfer contains the information necessary to submit a USB request +/// and, once it has been submitted and completed, contains the response. +pub struct Transfer { + // NOTE: This Vec is actually a single URB with a trailing + // variable-length field created by vec_with_array_field(). + urb: Vec<usb_sys::usbdevfs_urb>, + pub buffer: Vec<u8>, + callback: Option<Box<dyn Fn(Transfer) + Send + Sync>>, +} + +/// TransferHandle is a handle that allows cancellation of in-flight transfers +/// between submit_transfer() and get_completed_transfer(). +/// Attempting to cancel a transfer that has already completed is safe and will +/// return an error. +pub struct TransferHandle { + weak_transfer: std::sync::Weak<Transfer>, + fd: std::sync::Weak<File>, +} + +#[derive(PartialEq)] +pub enum TransferStatus { + Completed, + Error, + Cancelled, + NoDevice, +} + +impl Device { + /// Create a new `Device` from a file descriptor. + /// `fd` should be a file in usbdevfs (e.g. `/dev/bus/usb/001/002`). + pub fn new(mut fd: File) -> Result<Self> { + fd.seek(SeekFrom::Start(0)).map_err(Error::DescriptorRead)?; + let device_descriptor_tree = descriptor::parse_usbfs_descriptors(&mut fd)?; + + let device = Device { + fd: Arc::new(fd), + device_descriptor_tree, + }; + Ok(device) + } + + pub fn fd(&self) -> Arc<File> { + self.fd.clone() + } + + unsafe fn ioctl(&self, nr: c_ulong) -> Result<i32> { + let ret = handle_eintr_errno!(sys_util::ioctl(&*self.fd, nr)); + if ret < 0 { + return Err(Error::IoctlFailed(nr, sys_util::Error::last())); + } + Ok(ret) + } + + unsafe fn ioctl_with_ref<T>(&self, nr: c_ulong, arg: &T) -> Result<i32> { + let ret = handle_eintr_errno!(sys_util::ioctl_with_ref(&*self.fd, nr, arg)); + if ret < 0 { + return Err(Error::IoctlFailed(nr, sys_util::Error::last())); + } + Ok(ret) + } + + unsafe fn ioctl_with_mut_ref<T>(&self, nr: c_ulong, arg: &mut T) -> Result<i32> { + let ret = handle_eintr_errno!(sys_util::ioctl_with_mut_ref(&*self.fd, nr, arg)); + if ret < 0 { + return Err(Error::IoctlFailed(nr, sys_util::Error::last())); + } + Ok(ret) + } + + unsafe fn ioctl_with_mut_ptr<T>(&self, nr: c_ulong, arg: *mut T) -> Result<i32> { + let ret = handle_eintr_errno!(sys_util::ioctl_with_mut_ptr(&*self.fd, nr, arg)); + if ret < 0 { + return Err(Error::IoctlFailed(nr, sys_util::Error::last())); + } + Ok(ret) + } + + /// Submit a transfer to the device. + /// The transfer will be processed asynchronously by the device. + /// Call `poll_transfers()` on this device to check for completed transfers. + pub fn submit_transfer(&mut self, transfer: Transfer) -> Result<TransferHandle> { + let mut rc_transfer = Arc::new(transfer); + + // Technically, Arc::from_raw() should only be called on pointers returned + // from Arc::into_raw(). However, we need to stash this value inside the + // Arc<Transfer> itself, so we manually calculate the address that would be + // returned from Arc::into_raw() via Deref and then call Arc::into_raw() + // to forget the Arc without dropping its contents. + // Do not remove the into_raw() call! + let raw_transfer = (&*rc_transfer) as *const Transfer as usize; + match Arc::get_mut(&mut rc_transfer) { + Some(t) => t.urb_mut().usercontext = raw_transfer, + None => { + // This should never happen, since there is only one strong reference + // at this point. + return Err(Error::RcGetMutFailed); + } + } + let _ = Arc::into_raw(rc_transfer.clone()); + + let urb_ptr = rc_transfer.urb.as_ptr() as *mut usb_sys::usbdevfs_urb; + + // Safe because we control the lifetime of the URB via Arc::into_raw() and + // Arc::from_raw() in poll_transfers(). + unsafe { + self.ioctl_with_mut_ptr(usb_sys::USBDEVFS_SUBMITURB(), urb_ptr)?; + } + + let weak_transfer = Arc::downgrade(&rc_transfer); + + Ok(TransferHandle { + weak_transfer, + fd: Arc::downgrade(&self.fd), + }) + } + + /// Check for completed asynchronous transfers submitted via `submit_transfer()`. + /// The callback for each completed transfer will be called. + pub fn poll_transfers(&self) -> Result<()> { + // Reap completed transfers until we get EAGAIN. + loop { + let mut urb_ptr: *mut usb_sys::usbdevfs_urb = std::ptr::null_mut(); + // Safe because we provide a valid urb_ptr to be filled by the kernel. + let result = + unsafe { self.ioctl_with_mut_ref(usb_sys::USBDEVFS_REAPURBNDELAY(), &mut urb_ptr) }; + match result { + Err(Error::IoctlFailed(_nr, e)) => { + if e.errno() == EAGAIN { + // No more completed transfers right now. + break; + } + } + Err(e) => return Err(e), + Ok(_) => {} + } + + if urb_ptr.is_null() { + break; + } + + // Safe because the URB usercontext field is always set to the result of + // Arc::into_raw() in submit_transfer(). + let rc_transfer: Arc<Transfer> = + unsafe { Arc::from_raw((*urb_ptr).usercontext as *const Transfer) }; + + // There should always be exactly one strong reference to rc_transfer, + // so try_unwrap() should never fail. + let mut transfer = Arc::try_unwrap(rc_transfer).map_err(|_| Error::RcUnwrapFailed)?; + + if let Some(cb) = transfer.callback.take() { + cb(transfer); + } + } + + Ok(()) + } + + /// Perform a USB port reset to reinitialize a device. + pub fn reset(&self) -> Result<()> { + // Safe because self.fd is a valid usbdevfs file descriptor. + let result = unsafe { self.ioctl(usb_sys::USBDEVFS_RESET()) }; + + if let Err(Error::IoctlFailed(_nr, errno_err)) = result { + // The device may disappear after a reset if e.g. its firmware changed. + // Treat that as success. + if errno_err.errno() == libc::ENODEV { + return Ok(()); + } + } + + result?; + Ok(()) + } + + /// Claim an interface on this device. + pub fn claim_interface(&self, interface_number: u8) -> Result<()> { + let disconnect_claim = usb_sys::usbdevfs_disconnect_claim { + interface: interface_number.into(), + flags: 0, + driver: [0u8; 256], + }; + // Safe because self.fd is a valid usbdevfs file descriptor and we pass a valid + // pointer to a usbdevs_disconnect_claim structure. + unsafe { + self.ioctl_with_ref(usb_sys::USBDEVFS_DISCONNECT_CLAIM(), &disconnect_claim)?; + } + + Ok(()) + } + + /// Release an interface previously claimed with `claim_interface()`. + pub fn release_interface(&self, interface_number: u8) -> Result<()> { + let ifnum: c_uint = interface_number.into(); + // Safe because self.fd is a valid usbdevfs file descriptor and we pass a valid + // pointer to unsigned int. + unsafe { + self.ioctl_with_ref(usb_sys::USBDEVFS_RELEASEINTERFACE(), &ifnum)?; + } + + Ok(()) + } + + /// Activate an alternate setting for an interface. + pub fn set_interface_alt_setting( + &self, + interface_number: u8, + alternative_setting: u8, + ) -> Result<()> { + let setinterface = usb_sys::usbdevfs_setinterface { + interface: interface_number.into(), + altsetting: alternative_setting.into(), + }; + // Safe because self.fd is a valid usbdevfs file descriptor and we pass a valid + // pointer to a usbdevfs_setinterface structure. + unsafe { + self.ioctl_with_ref(usb_sys::USBDEVFS_SETINTERFACE(), &setinterface)?; + } + Ok(()) + } + + /// Set active configuration for this device. + pub fn set_active_configuration(&mut self, config: u8) -> Result<()> { + let config: c_int = config.into(); + // Safe because self.fd is a valid usbdevfs file descriptor and we pass a valid + // pointer to int. + unsafe { + self.ioctl_with_ref(usb_sys::USBDEVFS_SETCONFIGURATION(), &config)?; + } + + Ok(()) + } + + /// Get the device descriptor of this device. + pub fn get_device_descriptor(&self) -> Result<DeviceDescriptor> { + Ok(*self.device_descriptor_tree) + } + + /// Get active config descriptor of this device. + pub fn get_active_config_descriptor(&self) -> Result<ConfigDescriptorTree> { + let active_config = self.get_active_configuration()?; + match self + .device_descriptor_tree + .get_config_descriptor(active_config) + { + Some(config_descriptor) => Ok(config_descriptor.clone()), + None => Err(Error::NoSuchDescriptor), + } + } + + /// Get bConfigurationValue of the currently active configuration. + pub fn get_active_configuration(&self) -> Result<u8> { + // Send a synchronous control transfer to get the active configuration. + let mut active_config: u8 = 0; + let ctrl_transfer = usb_sys::usbdevfs_ctrltransfer { + bRequestType: control_request_type( + ControlRequestType::Standard, + ControlRequestDataPhaseTransferDirection::DeviceToHost, + ControlRequestRecipient::Device, + ), + bRequest: StandardControlRequest::GetConfiguration as u8, + wValue: 0, + wIndex: 0, + wLength: size_of_val(&active_config) as u16, + timeout: 5000, // milliseconds + data: &mut active_config as *mut u8 as *mut c_void, + }; + // Safe because self.fd is a valid usbdevfs file descriptor and we pass a valid + // pointer to a usbdevfs_ctrltransfer structure. + unsafe { + self.ioctl_with_ref(usb_sys::USBDEVFS_CONTROL(), &ctrl_transfer)?; + } + Ok(active_config) + } + + /// Clear the halt/stall condition for an endpoint. + pub fn clear_halt(&self, ep_addr: u8) -> Result<()> { + let endpoint: c_uint = ep_addr.into(); + // Safe because self.fd is a valid usbdevfs file descriptor and we pass a valid + // pointer to unsigned int. + unsafe { + self.ioctl_with_ref(usb_sys::USBDEVFS_CLEAR_HALT(), &endpoint)?; + } + + Ok(()) + } +} + +// Returns a `Vec<T>` with a size in bytes at least as large as `size_in_bytes`. +fn vec_with_size_in_bytes<T: Default>(size_in_bytes: usize) -> Vec<T> { + let rounded_size = (size_in_bytes + size_of::<T>() - 1) / size_of::<T>(); + let mut v = Vec::with_capacity(rounded_size); + for _ in 0..rounded_size { + v.push(T::default()) + } + v +} + +// This function has been borrowed from kvm - see the doc comment there for details. +fn vec_with_array_field<T: Default, F>(count: usize) -> Vec<T> { + let element_space = count * size_of::<F>(); + let vec_size_bytes = size_of::<T>() + element_space; + vec_with_size_in_bytes(vec_size_bytes) +} + +impl Transfer { + fn urb(&self) -> &usb_sys::usbdevfs_urb { + // self.urb is a Vec created with `vec_with_array_field`; the first entry is + // the URB itself. + &self.urb[0] + } + + fn urb_mut(&mut self) -> &mut usb_sys::usbdevfs_urb { + &mut self.urb[0] + } + + fn new( + transfer_type: u8, + endpoint: u8, + buffer: Vec<u8>, + iso_packets: &[usb_sys::usbdevfs_iso_packet_desc], + ) -> Result<Transfer> { + let mut transfer = Transfer { + urb: vec_with_array_field::<usb_sys::usbdevfs_urb, usb_sys::usbdevfs_iso_packet_desc>( + iso_packets.len(), + ), + buffer, + callback: None, + }; + + transfer.urb_mut().urb_type = transfer_type; + transfer.urb_mut().endpoint = endpoint; + transfer.urb_mut().buffer = transfer.buffer.as_mut_ptr() as *mut c_void; + transfer.urb_mut().buffer_length = transfer + .buffer + .len() + .try_into() + .map_err(Error::InvalidBufferLength)?; + + // Safe because we ensured there is enough space in transfer.urb to hold the number of + // isochronous frames required. + let iso_frame_desc = unsafe { + transfer + .urb_mut() + .iso_frame_desc + .as_mut_slice(iso_packets.len()) + }; + iso_frame_desc.copy_from_slice(iso_packets); + + Ok(transfer) + } + + /// Create a control transfer. + pub fn new_control(buffer: Vec<u8>) -> Result<Transfer> { + let endpoint = 0; + Self::new(usb_sys::USBDEVFS_URB_TYPE_CONTROL, endpoint, buffer, &[]) + } + + /// Create an interrupt transfer. + pub fn new_interrupt(endpoint: u8, buffer: Vec<u8>) -> Result<Transfer> { + Self::new(usb_sys::USBDEVFS_URB_TYPE_INTERRUPT, endpoint, buffer, &[]) + } + + /// Create a bulk transfer. + pub fn new_bulk(endpoint: u8, buffer: Vec<u8>) -> Result<Transfer> { + Self::new(usb_sys::USBDEVFS_URB_TYPE_BULK, endpoint, buffer, &[]) + } + + /// Create an isochronous transfer. + pub fn new_isochronous(endpoint: u8, buffer: Vec<u8>) -> Result<Transfer> { + // TODO(dverkamp): allow user to specify iso descriptors + Self::new(usb_sys::USBDEVFS_URB_TYPE_ISO, endpoint, buffer, &[]) + } + + /// Get the status of a completed transfer. + pub fn status(&self) -> TransferStatus { + let status = self.urb().status; + if status == 0 { + TransferStatus::Completed + } else if status == -ENODEV { + TransferStatus::NoDevice + } else if status == -ENOENT { + TransferStatus::Cancelled + } else { + TransferStatus::Error + } + } + + /// Get the actual amount of data transferred, which may be less than + /// the original length. + pub fn actual_length(&self) -> usize { + self.urb().actual_length as usize + } + + /// Set callback function for transfer completion. + pub fn set_callback<C: 'static + Fn(Transfer) + Send + Sync>(&mut self, cb: C) { + self.callback = Some(Box::new(cb)); + } +} + +impl TransferHandle { + /// Attempt to cancel the transfer associated with this `TransferHandle`. + /// Safe to call even if the transfer has already completed; + /// `Error::TransferAlreadyCompleted` will be returned in this case. + pub fn cancel(self) -> Result<()> { + let rc_transfer = match self.weak_transfer.upgrade() { + None => return Err(Error::TransferAlreadyCompleted), + Some(rc_transfer) => rc_transfer, + }; + + let urb_ptr = rc_transfer.urb.as_ptr() as *mut usb_sys::usbdevfs_urb; + let fd = match self.fd.upgrade() { + None => return Err(Error::NoDevice), + Some(fd) => fd, + }; + + // Safe because fd is a valid usbdevfs file descriptor and we pass a valid + // pointer to a usbdevfs_urb structure. + if unsafe { + handle_eintr_errno!(sys_util::ioctl_with_mut_ptr( + &*fd, + usb_sys::USBDEVFS_DISCARDURB(), + urb_ptr + )) + } < 0 + { + return Err(Error::IoctlFailed( + usb_sys::USBDEVFS_DISCARDURB(), + sys_util::Error::last(), + )); + } + + Ok(()) + } +} diff --git a/usb_util/src/device_handle.rs b/usb_util/src/device_handle.rs deleted file mode 100644 index 17b0f68..0000000 --- a/usb_util/src/device_handle.rs +++ /dev/null @@ -1,161 +0,0 @@ -// Copyright 2018 The Chromium OS Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -use std::os::raw::c_int; -use std::sync::Arc; - -use crate::bindings; -use crate::error::{Error, Result}; -use crate::libusb_context::LibUsbContextInner; -use crate::libusb_device::LibUsbDevice; -use crate::usb_transfer::{TransferCanceller, UsbTransfer, UsbTransferBuffer}; - -/// DeviceHandle wraps libusb_device_handle. -pub struct DeviceHandle { - _context: Arc<LibUsbContextInner>, - handle: *mut bindings::libusb_device_handle, -} - -unsafe impl Send for DeviceHandle {} - -impl Drop for DeviceHandle { - fn drop(&mut self) { - // Safe because self.handle is a valid pointer to libusb_device_handle. - unsafe { - bindings::libusb_close(self.handle); - } - } -} - -impl DeviceHandle { - /// Create a new DeviceHande. 'handle' should be a valid pointer to libusb_device_handle. - pub unsafe fn new( - ctx: Arc<LibUsbContextInner>, - handle: *mut bindings::libusb_device_handle, - ) -> DeviceHandle { - DeviceHandle { - _context: ctx, - handle, - } - } - - /// Get corresponding usb device. - pub fn get_device(&self) -> LibUsbDevice { - // Safe because 'self.handle' is a valid pointer to device handle and libusb_get_device() - // always returns a valid device. - unsafe { - LibUsbDevice::new( - self._context.clone(), - bindings::libusb_get_device(self.handle), - ) - } - } - - /// Reset this usb device. - pub fn reset(&self) -> Result<()> { - // Safe because 'self.handle' is a valid pointer to device handle. - try_libusb!(unsafe { bindings::libusb_reset_device(self.handle) }); - Ok(()) - } - /// Get bConfigurationValue of the currently active configuration. - pub fn get_active_configuration(&self) -> Result<i32> { - let mut config: c_int = 0; - // Safe because 'self.handle' is a valid pointer to device handle and '&mut config' is a - // valid output location. - try_libusb!(unsafe { bindings::libusb_get_configuration(self.handle, &mut config) }); - Ok(config as i32) - } - - /// Set active configuration for a device. - pub fn set_active_configuration(&mut self, config: i32) -> Result<()> { - // Safe because 'self.handle' is a valid pointer to device handle. - try_libusb!(unsafe { bindings::libusb_set_configuration(self.handle, config as c_int) }); - Ok(()) - } - - /// Claim an interface on this deivce handle. - pub fn claim_interface(&self, interface_number: i32) -> Result<()> { - // Safe because 'self.handle' is a valid pointer to device handle. - try_libusb!(unsafe { bindings::libusb_claim_interface(self.handle, interface_number) }); - Ok(()) - } - - /// Release an interface previously claimed with libusb_claim_interface. - pub fn release_interface(&self, interface_number: i32) -> Result<()> { - // Safe because 'self.handle' is a valid pointer to device handle. - try_libusb!(unsafe { bindings::libusb_release_interface(self.handle, interface_number) }); - Ok(()) - } - - /// Perform a USB port reset to reinitialize a device. - pub fn reset_device(&self) -> Result<()> { - // Safe because 'self.handle' is a valid pointer to device handle. - try_libusb!(unsafe { bindings::libusb_reset_device(self.handle) }); - Ok(()) - } - - /// Determine if a kernel driver is active on an interface. - pub fn kernel_driver_active(&self, interface_number: i32) -> Result<bool> { - // Safe because 'self.handle' is a valid pointer to device handle. - let v = try_libusb!(unsafe { - bindings::libusb_kernel_driver_active(self.handle, interface_number) - }); - Ok(v != 0) - } - - /// Detach a kernel driver from an interface. - pub fn detach_kernel_driver(&self, interface_number: i32) -> Result<()> { - // Safe because 'self.handle' is a valid pointer to device handle. - try_libusb!(unsafe { - bindings::libusb_detach_kernel_driver(self.handle, interface_number) - }); - Ok(()) - } - - /// Re-attach an interfae's kernel driver, which was previously detached using - /// detach_kernel_driver. - pub fn attach_kernel_driver(&self, interface_number: i32) -> Result<()> { - // Safe because 'self.handle' is a valid pointer to device handle. - try_libusb!(unsafe { - bindings::libusb_attach_kernel_driver(self.handle, interface_number) - }); - Ok(()) - } - - /// Active an alternate setting for an interface. - pub fn set_interface_alt_setting( - &self, - interface_number: i32, - alternative_setting: i32, - ) -> Result<()> { - // Safe because 'self.handle' is a valid pointer to device handle. - try_libusb!(unsafe { - bindings::libusb_set_interface_alt_setting( - self.handle, - interface_number, - alternative_setting, - ) - }); - Ok(()) - } - - /// Clear the halt/stall condition for an endpoint. - pub fn clear_halt(&self, endpoint: u8) -> Result<()> { - // Safe because 'self.handle' is a valid pointer to device handle. - try_libusb!(unsafe { bindings::libusb_clear_halt(self.handle, endpoint) }); - Ok(()) - } - - /// Libusb asynchronous I/O interface has a 5 step process. It gives lots of - /// flexibility but makes it hard to manage object life cycle and easy to - /// write unsafe code. We wrap this interface to a simple "transfer" and "cancel" - /// interface. Resubmission is not supported and deallocation is handled safely - /// here. - pub fn submit_async_transfer<T: UsbTransferBuffer>( - &self, - transfer: UsbTransfer<T>, - ) -> Result<TransferCanceller> { - unsafe { transfer.submit(self.handle) } - } -} diff --git a/usb_util/src/endpoint_descriptor.rs b/usb_util/src/endpoint_descriptor.rs deleted file mode 100644 index 29eb4ea..0000000 --- a/usb_util/src/endpoint_descriptor.rs +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright 2018 The Chromium OS Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -use std::ops::Deref; - -use crate::bindings::libusb_endpoint_descriptor; -use crate::types::{EndpointDirection, EndpointType}; - -/// EndpointDescriptor wraps libusb_endpoint_descriptor. -pub struct EndpointDescriptor<'a>(&'a libusb_endpoint_descriptor); - -const ENDPOINT_DESCRIPTOR_DIRECTION_MASK: u8 = 1 << 7; -const ENDPOINT_DESCRIPTOR_NUMBER_MASK: u8 = 0xf; -const ENDPOINT_DESCRIPTOR_ATTRIBUTES_TYPE_MASK: u8 = 0x3; - -impl<'a> EndpointDescriptor<'a> { - // Create new endpoint descriptor. - pub fn new(descriptor: &libusb_endpoint_descriptor) -> EndpointDescriptor { - EndpointDescriptor(descriptor) - } - - // Get direction of this endpoint. - pub fn get_direction(&self) -> EndpointDirection { - let direction = self.0.bEndpointAddress & ENDPOINT_DESCRIPTOR_DIRECTION_MASK; - if direction > 0 { - EndpointDirection::DeviceToHost - } else { - EndpointDirection::HostToDevice - } - } - - // Get endpoint number. - pub fn get_endpoint_number(&self) -> u8 { - self.0.bEndpointAddress & ENDPOINT_DESCRIPTOR_NUMBER_MASK - } - - // Get endpoint type. - pub fn get_endpoint_type(&self) -> Option<EndpointType> { - let ep_type = self.0.bmAttributes & ENDPOINT_DESCRIPTOR_ATTRIBUTES_TYPE_MASK; - match ep_type { - 0 => Some(EndpointType::Control), - 1 => Some(EndpointType::Isochronous), - 2 => Some(EndpointType::Bulk), - 3 => Some(EndpointType::Interrupt), - _ => None, - } - } -} - -impl<'a> Deref for EndpointDescriptor<'a> { - type Target = libusb_endpoint_descriptor; - - fn deref(&self) -> &libusb_endpoint_descriptor { - self.0 - } -} diff --git a/usb_util/src/error.rs b/usb_util/src/error.rs index b6dd91e..24d8036 100644 --- a/usb_util/src/error.rs +++ b/usb_util/src/error.rs @@ -1,85 +1,52 @@ -// Copyright 2018 The Chromium OS Authors. All rights reserved. +// Copyright 2019 The Chromium OS Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +use libc::c_ulong; +use remain::sorted; use std; -use std::fmt; +use std::fmt::{self, Display}; +use std::io; +use std::num; -use crate::bindings; - -/// Error type for libusb. +#[sorted] +#[derive(Debug)] pub enum Error { - Success(i32), - IO, - InvalidParam, - Access, + DescriptorParse, + DescriptorRead(io::Error), + FdCloneFailed(io::Error), + InvalidActualLength(num::TryFromIntError), + InvalidBufferLength(num::TryFromIntError), + IoctlFailed(c_ulong, sys_util::Error), NoDevice, - NotFound, - Busy, - Timeout, - Overflow, - Pipe, - Interrupted, - NoMem, - NotSupported, - Other, + NoSuchDescriptor, + RcGetMutFailed, + RcUnwrapFailed, + TransferAlreadyCompleted, } -impl fmt::Debug for Error { +impl Display for Error { + #[remain::check] fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - Error::Success(_v) => write!(f, "Success (no error)"), - Error::IO => write!(f, "Input/output error"), - Error::InvalidParam => write!(f, "Invalid parameter"), - Error::Access => write!(f, "Access denied (insufficient permissions)"), - Error::NoDevice => write!(f, "No such device (it may have been disconnected)"), - Error::NotFound => write!(f, "Entity not found"), - Error::Busy => write!(f, "Resource busy"), - Error::Timeout => write!(f, "Operation timed out"), - Error::Overflow => write!(f, "Overflow"), - Error::Pipe => write!(f, "Pipe error"), - Error::Interrupted => write!(f, "System call interrupted (perhaps due to signal)"), - Error::NoMem => write!(f, "Insufficient memory"), - Error::NotSupported => write!( - f, - "Operation not supported or unimplemented on this platform" - ), - Error::Other => write!(f, "Other error"), - } - } -} + use self::Error::*; -impl From<bindings::libusb_error> for Error { - fn from(e: bindings::libusb_error) -> Self { - match e { - bindings::LIBUSB_ERROR_IO => Error::IO, - bindings::LIBUSB_ERROR_INVALID_PARAM => Error::InvalidParam, - bindings::LIBUSB_ERROR_ACCESS => Error::Access, - bindings::LIBUSB_ERROR_NO_DEVICE => Error::NoDevice, - bindings::LIBUSB_ERROR_NOT_FOUND => Error::NotFound, - bindings::LIBUSB_ERROR_BUSY => Error::Busy, - bindings::LIBUSB_ERROR_TIMEOUT => Error::Timeout, - bindings::LIBUSB_ERROR_OVERFLOW => Error::Overflow, - bindings::LIBUSB_ERROR_PIPE => Error::Pipe, - bindings::LIBUSB_ERROR_INTERRUPTED => Error::Interrupted, - bindings::LIBUSB_ERROR_NO_MEM => Error::NoMem, - bindings::LIBUSB_ERROR_NOT_SUPPORTED => Error::NotSupported, - bindings::LIBUSB_ERROR_OTHER => Error::Other, - // All possible errors are defined above, other values mean success, - // see libusb_get_device_list for example. - _ => Error::Success(e), + #[sorted] + match self { + DescriptorParse => write!(f, "parsing descriptors failed"), + DescriptorRead(e) => write!(f, "reading descriptors from device failed: {}", e), + FdCloneFailed(e) => write!(f, "File::try_clone() failed: {}", e), + InvalidActualLength(e) => write!(f, "invalid actual_length in URB: {}", e), + InvalidBufferLength(e) => write!(f, "invalid transfer buffer length: {}", e), + IoctlFailed(nr, e) => write!(f, "USB ioctl 0x{:x} failed: {}", nr, e), + NoDevice => write!(f, "Device has been removed"), + NoSuchDescriptor => write!(f, "Requested descriptor not found"), + RcGetMutFailed => write!(f, "Rc::get_mut failed"), + RcUnwrapFailed => write!(f, "Rc::try_unwrap failed"), + TransferAlreadyCompleted => write!(f, "attempted to cancel already-completed transfer"), } } } pub type Result<T> = std::result::Result<T, Error>; -#[macro_export] -macro_rules! try_libusb { - ($x:expr) => { - match Error::from($x as i32) { - Error::Success(e) => e, - err => return Err(err), - } - }; -} +impl std::error::Error for Error {} diff --git a/usb_util/src/hotplug.rs b/usb_util/src/hotplug.rs deleted file mode 100644 index e131ab9..0000000 --- a/usb_util/src/hotplug.rs +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright 2019 The Chromium OS Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -use std::os::raw::{c_int, c_void}; -use std::sync::Arc; - -use crate::bindings; -use crate::libusb_context::LibUsbContextInner; -use crate::libusb_device::LibUsbDevice; - -#[derive(PartialEq)] -pub enum HotplugEvent { - DeviceArrived, - DeviceLeft, -} - -impl HotplugEvent { - /// Create a new HotplugEvent from raw libusb_hotplug_event. - pub fn new(event: bindings::libusb_hotplug_event) -> Self { - match event { - bindings::LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED => HotplugEvent::DeviceArrived, - bindings::LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT => HotplugEvent::DeviceLeft, - _ => { - // TODO(jkwang) handle this with option. - // libusb_hotplug_event is a C enum. - panic!("Invaild libusb_hotplug_event"); - } - } - } -} - -pub trait UsbHotplugHandler: Send + Sync + 'static { - fn hotplug_event(&self, device: LibUsbDevice, event: HotplugEvent); -} - -/// UsbHotplugHandlerHolder owns UsbHotplugHandler and LibUsbContext. It will be passed as -/// user_data to libusb_hotplug_register_callback. -pub struct UsbHotplugHandlerHolder { - context: Arc<LibUsbContextInner>, - handler: Box<dyn UsbHotplugHandler>, -} - -impl UsbHotplugHandlerHolder { - /// Create UsbHotplugHandlerHodler from context and handler. - pub fn new<H: UsbHotplugHandler>( - context: Arc<LibUsbContextInner>, - handler: H, - ) -> Box<UsbHotplugHandlerHolder> { - let holder = UsbHotplugHandlerHolder { - context, - handler: Box::new(handler), - }; - Box::new(holder) - } -} - -/// This function is safe when: -/// libusb_device is allocated by libusb -/// user_data points to valid UsbHotPlugHandlerHolder released from Box. -/// -/// Do not invoke this function. It should only be used as a callback for -/// libusb_hotplug_register_callback. -pub unsafe extern "C" fn hotplug_cb( - _: *mut bindings::libusb_context, - device: *mut bindings::libusb_device, - event: bindings::libusb_hotplug_event, - user_data: *mut c_void, -) -> c_int { - // Safe because user_data was casted from holder. - let holder = &*(user_data as *mut UsbHotplugHandlerHolder); - let device = LibUsbDevice::new(holder.context.clone(), device); - let event = HotplugEvent::new(event); - holder.handler.hotplug_event(device, event); - // The handler should always succeed. - bindings::LIBUSB_SUCCESS -} diff --git a/usb_util/src/interface_descriptor.rs b/usb_util/src/interface_descriptor.rs deleted file mode 100644 index a2bf1b2..0000000 --- a/usb_util/src/interface_descriptor.rs +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright 2018 The Chromium OS Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -use std::ops::Deref; - -use crate::bindings::libusb_interface_descriptor; -use crate::endpoint_descriptor::EndpointDescriptor; - -/// InterfaceDescriptor wraps libusb_interface_descriptor. -pub struct InterfaceDescriptor<'a>(&'a libusb_interface_descriptor); - -impl<'a> InterfaceDescriptor<'a> { - /// Create a new Interface descriptor. - pub fn new(descriptor: &'a libusb_interface_descriptor) -> InterfaceDescriptor<'a> { - InterfaceDescriptor(descriptor) - } - - /// Get endpoint descriptor at index. - pub fn endpoint_descriptor(&self, ep_idx: u8) -> Option<EndpointDescriptor> { - if ep_idx >= self.0.bNumEndpoints { - return None; - } - - // Safe because idx is checked. - unsafe { - Some(EndpointDescriptor::new( - &*(self.0.endpoint.offset(ep_idx as isize)), - )) - } - } -} - -impl<'a> Deref for InterfaceDescriptor<'a> { - type Target = libusb_interface_descriptor; - - fn deref(&self) -> &libusb_interface_descriptor { - self.0 - } -} diff --git a/usb_util/src/lib.rs b/usb_util/src/lib.rs index 07af5ad..2574d90 100644 --- a/usb_util/src/lib.rs +++ b/usb_util/src/lib.rs @@ -1,23 +1,18 @@ -// Copyright 2018 The Chromium OS Authors. All rights reserved. +// Copyright 2019 The Chromium OS Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// Generated with bindgen libusb.h -no-prepend-enum-name -o bindings.rs. -#![allow(dead_code)] -#![allow(non_camel_case_types)] -#![allow(non_snake_case)] -#![allow(non_upper_case_globals)] -#[allow(clippy::all)] -mod bindings; +mod descriptor; +mod device; +mod error; +mod types; -#[macro_use] -pub mod error; -pub mod config_descriptor; -pub mod device_handle; -pub mod endpoint_descriptor; -pub mod hotplug; -pub mod interface_descriptor; -pub mod libusb_context; -pub mod libusb_device; -pub mod types; -pub mod usb_transfer; +pub use self::descriptor::{ConfigDescriptorTree, DeviceDescriptorTree, InterfaceDescriptorTree}; +pub use self::device::{Device, Transfer, TransferStatus}; +pub use self::error::{Error, Result}; +pub use self::types::{ + control_request_type, ConfigDescriptor, ControlRequestDataPhaseTransferDirection, + ControlRequestRecipient, ControlRequestType, DeviceDescriptor, EndpointDescriptor, + EndpointDirection, EndpointType, InterfaceDescriptor, StandardControlRequest, UsbRequestSetup, + ENDPOINT_DIRECTION_OFFSET, +}; diff --git a/usb_util/src/libusb_context.rs b/usb_util/src/libusb_context.rs deleted file mode 100644 index 17a77f0..0000000 --- a/usb_util/src/libusb_context.rs +++ /dev/null @@ -1,268 +0,0 @@ -// Copyright 2018 The Chromium OS Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -use std; -#[allow(unused_imports)] -use std::os::raw::{c_long, c_short, c_void}; -use std::os::unix::io::RawFd; -use std::sync::Arc; - -use crate::bindings; -#[cfg(feature = "sandboxed-libusb")] -use crate::device_handle::DeviceHandle; -use crate::error::{Error, Result}; -use crate::hotplug::{hotplug_cb, UsbHotplugHandler, UsbHotplugHandlerHolder}; -use crate::libusb_device::LibUsbDevice; - -use sync::Mutex; - -pub struct LibUsbContextInner { - context: *mut bindings::libusb_context, - pollfd_change_handler: Mutex<Option<Box<PollfdChangeHandlerHolder>>>, -} - -// Safe because libusb_context could be accessed from multiple threads safely. -unsafe impl Send for LibUsbContextInner {} -unsafe impl Sync for LibUsbContextInner {} - -impl LibUsbContextInner { - /// Remove the previous registered notifiers. - pub fn remove_pollfd_notifiers(&self) { - // Safe because 'self.context' is valid. - unsafe { - bindings::libusb_set_pollfd_notifiers(self.context, None, None, std::ptr::null_mut()); - } - } -} - -impl Drop for LibUsbContextInner { - fn drop(&mut self) { - // Avoid pollfd change handler call when libusb_exit is called. - self.remove_pollfd_notifiers(); - // Safe beacuse 'self.context' points to a valid context allocated by libusb_init. - unsafe { - bindings::libusb_exit(self.context); - } - } -} - -/// Wrapper for libusb_context. The libusb libary initialization/deinitialization -/// is managed by this context. -/// See: http://libusb.sourceforge.net/api-1.0/group__libusb__lib.html -#[derive(Clone)] -pub struct LibUsbContext { - inner: Arc<LibUsbContextInner>, -} - -impl LibUsbContext { - /// Create a new LibUsbContext. - pub fn new() -> Result<LibUsbContext> { - let mut ctx: *mut bindings::libusb_context = std::ptr::null_mut(); - // Safe because '&mut ctx' points to a valid memory (on stack). - try_libusb!(unsafe { bindings::libusb_init(&mut ctx) }); - Ok(LibUsbContext { - inner: Arc::new(LibUsbContextInner { - context: ctx, - pollfd_change_handler: Mutex::new(None), - }), - }) - } - - #[cfg(feature = "sandboxed-libusb")] - pub fn handle_from_file(&self, f: std::fs::File) -> Result<DeviceHandle> { - use std::os::unix::io::IntoRawFd; - - let fd = f.into_raw_fd(); - let mut handle: *mut bindings::libusb_device_handle = std::ptr::null_mut(); - // Safe because fd is valid and owned, and '&mut handle' points to valid memory. - try_libusb!(unsafe { - bindings::libusb_wrap_sys_device(self.inner.context, fd as c_long, &mut handle) - }); - unsafe { Ok(DeviceHandle::new(self.inner.clone(), handle)) } - } - - /// Returns a list of USB devices currently attached to the system. - pub fn get_device_iter(&self) -> Result<DeviceIter> { - let mut list: *mut *mut bindings::libusb_device = std::ptr::null_mut(); - // Safe because 'inner.context' points to a valid context and '&mut list' points to a valid - // memory. - try_libusb!(unsafe { bindings::libusb_get_device_list(self.inner.context, &mut list) }); - - Ok(DeviceIter { - context: self.inner.clone(), - list, - index: 0, - }) - } - - /// Check at runtime if the loaded library has a given capability. - pub fn has_capability(&self, cap: u32) -> bool { - // Safe because libusb_init is called before this call happens. - unsafe { bindings::libusb_has_capability(cap) != 0 } - } - - /// Return an iter of poll fds. Those fds that should be polled to handle libusb events. - pub fn get_pollfd_iter(&self) -> PollFdIter { - // Safe because 'inner.context' is inited. - let list: *mut *const bindings::libusb_pollfd = - unsafe { bindings::libusb_get_pollfds(self.inner.context) }; - PollFdIter { list, index: 0 } - } - - /// Handle libusb events in a non block way. - pub fn handle_events_nonblock(&self) { - static mut zero_time: bindings::timeval = bindings::timeval { - tv_sec: 0, - tv_usec: 0, - }; - // Safe because 'inner.context' points to valid context. - unsafe { - bindings::libusb_handle_events_timeout_completed( - self.inner.context, - &mut zero_time as *mut bindings::timeval, - std::ptr::null_mut(), - ); - } - } - - /// Set a handler that could handle pollfd change events. - pub fn set_pollfd_notifiers(&self, handler: Box<dyn LibUsbPollfdChangeHandler>) { - // LibUsbContext is alive when any libusb related function is called. It owns the handler, - // thus the handler memory is always valid when callback is invoked. - let holder = Box::new(PollfdChangeHandlerHolder { handler }); - let raw_holder = Box::into_raw(holder); - unsafe { - bindings::libusb_set_pollfd_notifiers( - self.inner.context, - Some(pollfd_added_cb), - Some(pollfd_removed_cb), - raw_holder as *mut c_void, - ); - } - // Safe because raw_holder is from Boxed pointer. - let holder = unsafe { Box::from_raw(raw_holder) }; - *self.inner.pollfd_change_handler.lock() = Some(holder); - } - - /// Remove the previous registered notifiers. - pub fn remove_pollfd_notifiers(&self) { - self.inner.remove_pollfd_notifiers(); - } - - /// Set a callback that could handle hotplug events. Currently, this function listen to hotplug - /// event of all devices. - pub fn set_hotplug_cb<H: UsbHotplugHandler + Sized>(&self, handler: H) -> Result<()> { - let event = bindings::LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED - | bindings::LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT; - let holder = UsbHotplugHandlerHolder::new(self.inner.clone(), handler); - let raw_holder = Box::into_raw(holder); - // Safe becuase hotpulg cb is a vaild c function and raw_holder points to memory for that - // function argument. - try_libusb!(unsafe { - bindings::libusb_hotplug_register_callback( - self.inner.context, - event, - bindings::LIBUSB_HOTPLUG_NO_FLAGS, - bindings::LIBUSB_HOTPLUG_MATCH_ANY, - bindings::LIBUSB_HOTPLUG_MATCH_ANY, - bindings::LIBUSB_HOTPLUG_MATCH_ANY, - Some(hotplug_cb), - raw_holder as *mut c_void, - std::ptr::null_mut(), - ) - }); - Ok(()) - } -} - -/// Iterator for device list. -pub struct DeviceIter { - context: Arc<LibUsbContextInner>, - list: *mut *mut bindings::libusb_device, - index: isize, -} - -impl Drop for DeviceIter { - fn drop(&mut self) { - // Safe because 'self.list' is inited by a valid pointer from libusb_get_device_list. - unsafe { - bindings::libusb_free_device_list(self.list, 1); - } - } -} - -impl Iterator for DeviceIter { - type Item = LibUsbDevice; - - fn next(&mut self) -> Option<LibUsbDevice> { - // Safe becuase 'self.list' is valid, the list is null terminated. - unsafe { - let current_ptr = self.list.offset(self.index); - if (*current_ptr).is_null() { - return None; - } - self.index += 1; - Some(LibUsbDevice::new(self.context.clone(), *current_ptr)) - } - } -} - -/// Iterator for pollfds. -pub struct PollFdIter { - list: *mut *const bindings::libusb_pollfd, - index: isize, -} - -impl Drop for PollFdIter { - fn drop(&mut self) { - // Safe because 'self.list' points to valid memory of pollfd list. - unsafe { - bindings::libusb_free_pollfds(self.list); - } - } -} - -impl Iterator for PollFdIter { - type Item = bindings::libusb_pollfd; - - fn next(&mut self) -> Option<bindings::libusb_pollfd> { - // Safe because 'self.index' never grow out of the null pointer index. - unsafe { - let current_ptr = self.list.offset(self.index); - if (*current_ptr).is_null() { - return None; - } - - self.index += 1; - // Safe because '*current_ptr' is not null. - Some(**current_ptr) - } - } -} - -/// Trait for handler that handles Pollfd Change events. -pub trait LibUsbPollfdChangeHandler: Send + Sync + 'static { - fn add_poll_fd(&self, fd: RawFd, events: c_short); - fn remove_poll_fd(&self, fd: RawFd); -} - -// This struct owns LibUsbPollfdChangeHandler. We need it because it's not possible to cast void -// pointer to trait pointer. -struct PollfdChangeHandlerHolder { - handler: Box<dyn LibUsbPollfdChangeHandler>, -} - -// This function is safe when user_data points to valid PollfdChangeHandlerHolder. -unsafe extern "C" fn pollfd_added_cb(fd: RawFd, events: c_short, user_data: *mut c_void) { - // Safe because user_data was casted from holder. - let keeper = &*(user_data as *mut PollfdChangeHandlerHolder); - keeper.handler.add_poll_fd(fd, events); -} - -// This function is safe when user_data points to valid PollfdChangeHandlerHolder. -unsafe extern "C" fn pollfd_removed_cb(fd: RawFd, user_data: *mut c_void) { - // Safe because user_data was casted from holder. - let keeper = &*(user_data as *mut PollfdChangeHandlerHolder); - keeper.handler.remove_poll_fd(fd); -} diff --git a/usb_util/src/libusb_device.rs b/usb_util/src/libusb_device.rs deleted file mode 100644 index ad87b46..0000000 --- a/usb_util/src/libusb_device.rs +++ /dev/null @@ -1,108 +0,0 @@ -// Copyright 2018 The Chromium OS Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -use std; -use std::sync::Arc; - -use crate::bindings; -use crate::config_descriptor::ConfigDescriptor; -use crate::device_handle::DeviceHandle; -use crate::error::{Error, Result}; -use crate::libusb_context::LibUsbContextInner; -use crate::types::Speed; - -pub type DeviceDescriptor = bindings::libusb_device_descriptor; - -/// LibUsbDevice wraps libusb_device. -pub struct LibUsbDevice { - _context: Arc<LibUsbContextInner>, - device: *mut bindings::libusb_device, -} - -unsafe impl Send for LibUsbDevice {} - -impl Drop for LibUsbDevice { - fn drop(&mut self) { - // Safe because 'self.device' is a valid pointer and libusb_ref_device is invoked when - // 'self' is built. - unsafe { - bindings::libusb_unref_device(self.device); - } - } -} - -impl LibUsbDevice { - /// Create a new LibUsbDevice. 'device' should be a valid pointer to libusb_device. - pub unsafe fn new( - ctx: Arc<LibUsbContextInner>, - device: *mut bindings::libusb_device, - ) -> LibUsbDevice { - bindings::libusb_ref_device(device); - LibUsbDevice { - _context: ctx, - device, - } - } - - /// Get device descriptor of this device. - pub fn get_device_descriptor(&self) -> Result<DeviceDescriptor> { - // Safe because memory is initialized later. - let mut descriptor: bindings::libusb_device_descriptor = Default::default(); - // Safe because 'self.device' is valid and '&mut descriptor' is valid. - try_libusb!(unsafe { - bindings::libusb_get_device_descriptor(self.device, &mut descriptor) - }); - Ok(descriptor) - } - - /// Get config descriptor at index of idx. - pub fn get_config_descriptor(&self, idx: u8) -> Result<ConfigDescriptor> { - let mut descriptor: *mut bindings::libusb_config_descriptor = std::ptr::null_mut(); - // Safe because 'self.device' is valid and '&mut descriptor' is valid. - try_libusb!(unsafe { - bindings::libusb_get_config_descriptor(self.device, idx, &mut descriptor) - }); - // Safe because descriptor is inited with valid pointer. - Ok(unsafe { ConfigDescriptor::new(descriptor) }) - } - - /// Get active config descriptor of this device. - pub fn get_active_config_descriptor(&self) -> Result<ConfigDescriptor> { - let mut descriptor: *mut bindings::libusb_config_descriptor = std::ptr::null_mut(); - // Safe because 'self.device' is valid and '&mut descriptor' is valid. - try_libusb!(unsafe { - bindings::libusb_get_active_config_descriptor(self.device, &mut descriptor) - }); - // Safe becuase descriptor points to valid memory. - Ok(unsafe { ConfigDescriptor::new(descriptor) }) - } - - /// Get bus number of this device. - pub fn get_bus_number(&self) -> u8 { - // Safe because 'self.device' is valid. - unsafe { bindings::libusb_get_bus_number(self.device) } - } - - /// Get address of this device. - pub fn get_address(&self) -> u8 { - // Safe because 'self.device' is valid. - unsafe { bindings::libusb_get_device_address(self.device) } - } - - /// Get speed of this device. - pub fn get_speed(&self) -> Speed { - // Safe because 'self.device' is valid. - let speed = unsafe { bindings::libusb_get_device_speed(self.device) }; - Speed::from(speed as u32) - } - - /// Get device handle of this device. - pub fn open(&self) -> Result<DeviceHandle> { - let mut handle: *mut bindings::libusb_device_handle = std::ptr::null_mut(); - // Safe because 'self.device' is constructed from libusb device list and handle is on stack. - try_libusb!(unsafe { bindings::libusb_open(self.device, &mut handle) }); - // Safe because handle points to valid memory. - Ok(unsafe { DeviceHandle::new(self._context.clone(), handle) }) - } -} diff --git a/usb_util/src/types.rs b/usb_util/src/types.rs index f40dd6c..d669dcd 100644 --- a/usb_util/src/types.rs +++ b/usb_util/src/types.rs @@ -7,35 +7,159 @@ use data_model::DataInit; use std::mem::size_of; -use crate::bindings; - -/// Speed of usb device. See usb spec for more details. -#[derive(Debug)] -pub enum Speed { - /// The OS doesn't report or know the device speed. - Unknown, - /// The device is operating at low speed (1.5MBit/s). - Low, - /// The device is operating at full speed (12MBit/s). - Full, - /// The device is operating at high speed (480MBit/s). - High, - /// The device is operating at super speed (5000MBit/s). - Super, -} - -impl From<bindings::libusb_speed> for Speed { - fn from(speed: bindings::libusb_speed) -> Speed { - match speed { - bindings::LIBUSB_SPEED_LOW => Speed::Low, - bindings::LIBUSB_SPEED_FULL => Speed::Full, - bindings::LIBUSB_SPEED_HIGH => Speed::High, - bindings::LIBUSB_SPEED_SUPER => Speed::Super, - _ => Speed::Unknown, - } +/// Standard USB descriptor types. +pub enum DescriptorType { + Device = 0x01, + Configuration = 0x02, + Interface = 0x04, + Endpoint = 0x05, +} + +/// Trait describing USB descriptors. +pub trait Descriptor { + /// Get the expected bDescriptorType value for this type of descriptor. + fn descriptor_type() -> DescriptorType; +} + +/// Standard USB descriptor header common to all descriptor types. +#[allow(non_snake_case)] +#[derive(Copy, Clone, Debug, Default)] +#[repr(C, packed)] +pub struct DescriptorHeader { + pub bLength: u8, + pub bDescriptorType: u8, +} + +// Safe because it only has data and has no implicit padding. +unsafe impl DataInit for DescriptorHeader {} + +fn _assert_descriptor_header() { + const_assert!(size_of::<DescriptorHeader>() == 2); +} + +/// Standard USB device descriptor as defined in USB 2.0 chapter 9, +/// not including the standard header. +#[allow(non_snake_case)] +#[derive(Copy, Clone, Debug, Default)] +#[repr(C, packed)] +pub struct DeviceDescriptor { + pub bcdUSB: u16, + pub bDeviceClass: u8, + pub bDeviceSubClass: u8, + pub bDeviceProtocol: u8, + pub bMaxPacketSize0: u8, + pub idVendor: u16, + pub idProduct: u16, + pub bcdDevice: u16, + pub iManufacturer: u8, + pub iProduct: u8, + pub iSerialNumber: u8, + pub bNumConfigurations: u8, +} + +impl Descriptor for DeviceDescriptor { + fn descriptor_type() -> DescriptorType { + DescriptorType::Device + } +} + +// Safe because it only has data and has no implicit padding. +unsafe impl DataInit for DeviceDescriptor {} + +fn _assert_device_descriptor() { + const_assert!(size_of::<DeviceDescriptor>() == 18 - 2); +} + +/// Standard USB configuration descriptor as defined in USB 2.0 chapter 9, +/// not including the standard header. +#[allow(non_snake_case)] +#[derive(Copy, Clone, Debug, Default)] +#[repr(C, packed)] +pub struct ConfigDescriptor { + pub wTotalLength: u16, + pub bNumInterfaces: u8, + pub bConfigurationValue: u8, + pub iConfiguration: u8, + pub bmAttributes: u8, + pub bMaxPower: u8, +} + +impl Descriptor for ConfigDescriptor { + fn descriptor_type() -> DescriptorType { + DescriptorType::Configuration + } +} + +// Safe because it only has data and has no implicit padding. +unsafe impl DataInit for ConfigDescriptor {} + +fn _assert_config_descriptor() { + const_assert!(size_of::<ConfigDescriptor>() == 9 - 2); +} + +impl ConfigDescriptor { + pub fn num_interfaces(&self) -> u8 { + self.bNumInterfaces + } +} + +/// Standard USB interface descriptor as defined in USB 2.0 chapter 9, +/// not including the standard header. +#[allow(non_snake_case)] +#[derive(Copy, Clone, Debug, Default)] +#[repr(C, packed)] +pub struct InterfaceDescriptor { + pub bInterfaceNumber: u8, + pub bAlternateSetting: u8, + pub bNumEndpoints: u8, + pub bInterfaceClass: u8, + pub bInterfaceSubClass: u8, + pub bInterfaceProtocol: u8, + pub iInterface: u8, +} + +impl Descriptor for InterfaceDescriptor { + fn descriptor_type() -> DescriptorType { + DescriptorType::Interface + } +} + +// Safe because it only has data and has no implicit padding. +unsafe impl DataInit for InterfaceDescriptor {} + +fn _assert_interface_descriptor() { + const_assert!(size_of::<InterfaceDescriptor>() == 9 - 2); +} + +/// Standard USB endpoint descriptor as defined in USB 2.0 chapter 9, +/// not including the standard header. +#[allow(non_snake_case)] +#[derive(Copy, Clone, Debug, Default)] +#[repr(C, packed)] +pub struct EndpointDescriptor { + pub bEndpointAddress: u8, + pub bmAttributes: u8, + pub wMaxPacketSize: u16, + pub bInterval: u8, +} + +impl Descriptor for EndpointDescriptor { + fn descriptor_type() -> DescriptorType { + DescriptorType::Endpoint } } +// Safe because it only has data and has no implicit padding. +unsafe impl DataInit for EndpointDescriptor {} + +fn _assert_endpoint_descriptor() { + const_assert!(size_of::<EndpointDescriptor>() == 7 - 2); +} + +const ENDPOINT_DESCRIPTOR_DIRECTION_MASK: u8 = 1 << 7; +const ENDPOINT_DESCRIPTOR_NUMBER_MASK: u8 = 0xf; +const ENDPOINT_DESCRIPTOR_ATTRIBUTES_TYPE_MASK: u8 = 0x3; + /// Endpoint types. #[derive(PartialEq)] pub enum EndpointType { @@ -54,6 +178,35 @@ pub enum EndpointDirection { /// Endpoint direction offset. pub const ENDPOINT_DIRECTION_OFFSET: u8 = 7; +impl EndpointDescriptor { + // Get direction of this endpoint. + pub fn get_direction(&self) -> EndpointDirection { + let direction = self.bEndpointAddress & ENDPOINT_DESCRIPTOR_DIRECTION_MASK; + if direction != 0 { + EndpointDirection::DeviceToHost + } else { + EndpointDirection::HostToDevice + } + } + + // Get endpoint number. + pub fn get_endpoint_number(&self) -> u8 { + self.bEndpointAddress & ENDPOINT_DESCRIPTOR_NUMBER_MASK + } + + // Get endpoint type. + pub fn get_endpoint_type(&self) -> Option<EndpointType> { + let ep_type = self.bmAttributes & ENDPOINT_DESCRIPTOR_ATTRIBUTES_TYPE_MASK; + match ep_type { + 0 => Some(EndpointType::Control), + 1 => Some(EndpointType::Isochronous), + 2 => Some(EndpointType::Bulk), + 3 => Some(EndpointType::Interrupt), + _ => None, + } + } +} + /// Offset of data phase transfer direction. pub const DATA_PHASE_DIRECTION_OFFSET: u8 = 7; /// Bit mask of data phase transfer direction. @@ -118,7 +271,7 @@ pub struct UsbRequestSetup { pub length: u16, // wLength } -fn _assert() { +fn _assert_usb_request_setup() { const_assert!(size_of::<UsbRequestSetup>() == 8); } @@ -194,3 +347,55 @@ impl UsbRequestSetup { } } } + +/// Construct a bmRequestType value for a control request. +pub fn control_request_type( + type_: ControlRequestType, + dir: ControlRequestDataPhaseTransferDirection, + recipient: ControlRequestRecipient, +) -> u8 { + ((type_ as u8) << CONTROL_REQUEST_TYPE_OFFSET) + | ((dir as u8) << DATA_PHASE_DIRECTION_OFFSET) + | (recipient as u8) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn control_request_types() { + assert_eq!( + control_request_type( + ControlRequestType::Standard, + ControlRequestDataPhaseTransferDirection::HostToDevice, + ControlRequestRecipient::Device + ), + 0b0_00_00000 + ); + assert_eq!( + control_request_type( + ControlRequestType::Standard, + ControlRequestDataPhaseTransferDirection::DeviceToHost, + ControlRequestRecipient::Device + ), + 0b1_00_00000 + ); + assert_eq!( + control_request_type( + ControlRequestType::Standard, + ControlRequestDataPhaseTransferDirection::HostToDevice, + ControlRequestRecipient::Interface + ), + 0b0_00_00001 + ); + assert_eq!( + control_request_type( + ControlRequestType::Class, + ControlRequestDataPhaseTransferDirection::HostToDevice, + ControlRequestRecipient::Device + ), + 0b0_01_00000 + ); + } +} diff --git a/usb_util/src/usb_transfer.rs b/usb_util/src/usb_transfer.rs deleted file mode 100644 index e3ca623..0000000 --- a/usb_util/src/usb_transfer.rs +++ /dev/null @@ -1,382 +0,0 @@ -// Copyright 2018 The Chromium OS Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -use std::mem::size_of; -use std::os::raw::c_void; -use std::sync::{Arc, Weak}; - -use crate::bindings::{ - libusb_alloc_transfer, libusb_cancel_transfer, libusb_device_handle, libusb_free_transfer, - libusb_submit_transfer, libusb_transfer, libusb_transfer_status, LIBUSB_TRANSFER_CANCELLED, - LIBUSB_TRANSFER_COMPLETED, LIBUSB_TRANSFER_ERROR, LIBUSB_TRANSFER_NO_DEVICE, - LIBUSB_TRANSFER_OVERFLOW, LIBUSB_TRANSFER_STALL, LIBUSB_TRANSFER_TIMED_OUT, - LIBUSB_TRANSFER_TYPE_BULK, LIBUSB_TRANSFER_TYPE_CONTROL, LIBUSB_TRANSFER_TYPE_INTERRUPT, -}; -use crate::error::{Error, Result}; -use crate::types::UsbRequestSetup; - -/// Status of transfer. -#[derive(PartialEq)] -pub enum TransferStatus { - Completed, - Error, - TimedOut, - Cancelled, - Stall, - NoDevice, - Overflow, -} - -impl From<libusb_transfer_status> for TransferStatus { - fn from(s: libusb_transfer_status) -> Self { - match s { - LIBUSB_TRANSFER_COMPLETED => TransferStatus::Completed, - LIBUSB_TRANSFER_ERROR => TransferStatus::Error, - LIBUSB_TRANSFER_TIMED_OUT => TransferStatus::TimedOut, - LIBUSB_TRANSFER_CANCELLED => TransferStatus::Cancelled, - LIBUSB_TRANSFER_STALL => TransferStatus::Stall, - LIBUSB_TRANSFER_NO_DEVICE => TransferStatus::NoDevice, - LIBUSB_TRANSFER_OVERFLOW => TransferStatus::Overflow, - _ => TransferStatus::Error, - } - } -} - -/// Trait for usb transfer buffer. -pub trait UsbTransferBuffer: Send { - fn as_ptr(&mut self) -> *mut u8; - fn len(&self) -> i32; -} - -/// Default buffer size for control data transfer. -const CONTROL_DATA_BUFFER_SIZE: usize = 1024; - -/// Buffer type for control transfer. The first 8-bytes is a UsbRequestSetup struct. -#[repr(C, packed)] -pub struct ControlTransferBuffer { - pub setup_buffer: UsbRequestSetup, - pub data_buffer: [u8; CONTROL_DATA_BUFFER_SIZE], -} - -impl ControlTransferBuffer { - fn new() -> ControlTransferBuffer { - ControlTransferBuffer { - setup_buffer: UsbRequestSetup { - request_type: 0, - request: 0, - value: 0, - index: 0, - length: 0, - }, - data_buffer: [0; CONTROL_DATA_BUFFER_SIZE], - } - } - - /// Set request setup for this control buffer. - pub fn set_request_setup(&mut self, request_setup: &UsbRequestSetup) { - self.setup_buffer = *request_setup; - } -} - -impl UsbTransferBuffer for ControlTransferBuffer { - fn as_ptr(&mut self) -> *mut u8 { - self as *mut ControlTransferBuffer as *mut u8 - } - - fn len(&self) -> i32 { - if self.setup_buffer.length as usize > CONTROL_DATA_BUFFER_SIZE { - panic!("Setup packet has an oversize length"); - } - self.setup_buffer.length as i32 + size_of::<UsbRequestSetup>() as i32 - } -} - -/// Buffer type for Bulk transfer. -pub struct BulkTransferBuffer { - buffer: Vec<u8>, -} - -impl BulkTransferBuffer { - fn with_size(buffer_size: usize) -> Self { - BulkTransferBuffer { - buffer: vec![0; buffer_size], - } - } - - /// Get mutable interal slice of this buffer. - pub fn as_mut_slice(&mut self) -> &mut [u8] { - &mut self.buffer - } - - /// Get interal slice of this buffer. - pub fn as_slice(&self) -> &[u8] { - &self.buffer - } -} - -impl UsbTransferBuffer for BulkTransferBuffer { - fn as_ptr(&mut self) -> *mut u8 { - if self.buffer.len() == 0 { - // Vec::as_mut_ptr() won't give 0x0 even if len() is 0. - std::ptr::null_mut() - } else { - self.buffer.as_mut_ptr() - } - } - - fn len(&self) -> i32 { - self.buffer.len() as i32 - } -} - -type UsbTransferCompletionCallback<T> = dyn Fn(UsbTransfer<T>) + Send + 'static; - -// This wraps libusb_transfer pointer. -struct LibUsbTransfer { - ptr: *mut libusb_transfer, -} - -impl Drop for LibUsbTransfer { - fn drop(&mut self) { - // Safe because 'self.ptr' is allocated by libusb_alloc_transfer. - unsafe { - libusb_free_transfer(self.ptr); - } - } -} - -// It is safe to invoke libusb functions from multiple threads. -// We cannot modify libusb_transfer safely from multiple threads. All the modifications happens -// in construct (UsbTransfer::new) or consume (UsbTransfer::into_raw), we can consider this thread -// safe. -unsafe impl Send for LibUsbTransfer {} -unsafe impl Sync for LibUsbTransfer {} - -/// TransferCanceller can cancel the transfer. -pub struct TransferCanceller { - transfer: Weak<LibUsbTransfer>, -} - -impl TransferCanceller { - /// Return false if fail to cancel. - pub fn try_cancel(&self) -> bool { - match self.transfer.upgrade() { - Some(t) => { - // Safe because self.transfer has ownership of the raw pointer. - let r = unsafe { libusb_cancel_transfer(t.ptr) }; - if r == 0 { - true - } else { - false - } - } - None => false, - } - } -} - -struct UsbTransferInner<T: UsbTransferBuffer> { - transfer: Arc<LibUsbTransfer>, - callback: Option<Box<UsbTransferCompletionCallback<T>>>, - buffer: T, -} - -/// UsbTransfer owns a LibUsbTransfer, it's buffer and callback. -pub struct UsbTransfer<T: UsbTransferBuffer> { - inner: Box<UsbTransferInner<T>>, -} - -/// Build a control transfer. -pub fn control_transfer(timeout: u32) -> UsbTransfer<ControlTransferBuffer> { - UsbTransfer::<ControlTransferBuffer>::new( - 0, - LIBUSB_TRANSFER_TYPE_CONTROL as u8, - timeout, - ControlTransferBuffer::new(), - ) -} - -/// Build a data transfer. -pub fn bulk_transfer(endpoint: u8, timeout: u32, size: usize) -> UsbTransfer<BulkTransferBuffer> { - UsbTransfer::<BulkTransferBuffer>::new( - endpoint, - LIBUSB_TRANSFER_TYPE_BULK as u8, - timeout, - BulkTransferBuffer::with_size(size), - ) -} - -/// Build a data transfer. -pub fn interrupt_transfer( - endpoint: u8, - timeout: u32, - size: usize, -) -> UsbTransfer<BulkTransferBuffer> { - UsbTransfer::<BulkTransferBuffer>::new( - endpoint, - LIBUSB_TRANSFER_TYPE_INTERRUPT as u8, - timeout, - BulkTransferBuffer::with_size(size), - ) -} - -impl<T: UsbTransferBuffer> UsbTransfer<T> { - fn new(endpoint: u8, type_: u8, timeout: u32, buffer: T) -> Self { - // Safe because alloc is safe. - let transfer: *mut libusb_transfer = unsafe { libusb_alloc_transfer(0) }; - // Just panic on OOM. - assert!(!transfer.is_null()); - let inner = Box::new(UsbTransferInner { - transfer: Arc::new(LibUsbTransfer { ptr: transfer }), - callback: None, - buffer, - }); - // Safe because we inited transfer. - let raw_transfer: &mut libusb_transfer = unsafe { &mut *(inner.transfer.ptr) }; - raw_transfer.endpoint = endpoint; - raw_transfer.type_ = type_; - raw_transfer.timeout = timeout; - raw_transfer.callback = Some(UsbTransfer::<T>::on_transfer_completed); - UsbTransfer { inner } - } - - /// Set callback function for transfer completion. - pub fn set_callback<C: 'static + Fn(UsbTransfer<T>) + Send>(&mut self, cb: C) { - self.inner.callback = Some(Box::new(cb)); - } - - /// Get a reference to the buffer. - pub fn buffer(&self) -> &T { - &self.inner.buffer - } - - /// Get a mutable reference to the buffer. - pub fn buffer_mut(&mut self) -> &mut T { - &mut self.inner.buffer - } - - /// Get actual length of data that was transferred. - pub fn actual_length(&self) -> i32 { - let transfer = self.inner.transfer.ptr; - // Safe because inner.ptr is always allocated by libusb_alloc_transfer. - unsafe { (*transfer).actual_length } - } - - /// Get the transfer status of this transfer. - pub fn status(&self) -> TransferStatus { - let transfer = self.inner.transfer.ptr; - // Safe because inner.ptr is always allocated by libusb_alloc_transfer. - unsafe { TransferStatus::from((*transfer).status) } - } - - /// Submit this transfer to device handle. 'self' is consumed. On success, the memory will be - /// 'leaked' (and stored in user_data) and sent to libusb, when the async operation is done, - /// on_transfer_completed will recreate 'self' and deliver it to callback/free 'self'. On - /// faliure, 'self' is returned with an error. - /// - /// # Safety - /// - /// Assumes libusb_device_handle is an handled opened by libusb, self.inner.transfer.ptr is - /// initialized with correct buffer and length. - pub unsafe fn submit(self, handle: *mut libusb_device_handle) -> Result<TransferCanceller> { - let weak_transfer = Arc::downgrade(&self.inner.transfer); - let transfer = self.into_raw(); - (*transfer).dev_handle = handle; - match Error::from(libusb_submit_transfer(transfer)) { - Error::Success(_e) => Ok(TransferCanceller { - transfer: weak_transfer, - }), - err => { - UsbTransfer::<T>::from_raw(transfer); - Err(err) - } - } - } - - /// Invoke callback when transfer is completed. - /// - /// # Safety - /// - /// Assumes libusb_tranfser is finished. This function is called by libusb, don't call it - /// manually. - unsafe extern "C" fn on_transfer_completed(transfer: *mut libusb_transfer) { - let mut transfer = UsbTransfer::<T>::from_raw(transfer); - // Callback is reset to None. - if let Some(cb) = transfer.inner.callback.take() { - cb(transfer); - } - } - - fn into_raw(mut self) -> *mut libusb_transfer { - let transfer: *mut libusb_transfer = self.inner.transfer.ptr; - // Safe because transfer is allocated by libusb_alloc_transfer. - unsafe { - (*transfer).buffer = self.buffer_mut().as_ptr(); - (*transfer).length = self.buffer_mut().len(); - (*transfer).user_data = Box::into_raw(self.inner) as *mut c_void; - } - transfer - } - - unsafe fn from_raw(transfer: *mut libusb_transfer) -> Self { - UsbTransfer { - inner: Box::<UsbTransferInner<T>>::from_raw( - (*transfer).user_data as *mut UsbTransferInner<T>, - ), - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - use std::sync::Mutex; - - pub fn fake_submit_transfer<T: UsbTransferBuffer>(transfer: UsbTransfer<T>) { - let transfer = transfer.into_raw(); - unsafe { - match (*transfer).callback { - Some(cb) => cb(transfer), - // Although no callback is invoked, we still need on_transfer_completed to - // free memory. - None => panic!("Memory leak!"), - }; - } - } - - #[test] - fn check_control_buffer_size() { - assert_eq!( - size_of::<ControlTransferBuffer>(), - size_of::<UsbRequestSetup>() + CONTROL_DATA_BUFFER_SIZE - ); - } - - #[test] - fn submit_transfer_no_callback_test() { - let t = control_transfer(0); - fake_submit_transfer(t); - let t = bulk_transfer(0, 0, 1); - fake_submit_transfer(t); - } - - struct FakeTransferController { - data: Mutex<u8>, - } - - #[test] - fn submit_transfer_with_callback() { - let c = Arc::new(FakeTransferController { - data: Mutex::new(0), - }); - let c1 = Arc::downgrade(&c); - let mut t = control_transfer(0); - t.set_callback(move |_t| { - let c = c1.upgrade().unwrap(); - *c.data.lock().unwrap() = 3; - }); - fake_submit_transfer(t); - assert_eq!(*c.data.lock().unwrap(), 3); - } -} diff --git a/vm_control/Cargo.toml b/vm_control/Cargo.toml index eb8a078..564aea1 100644 --- a/vm_control/Cargo.toml +++ b/vm_control/Cargo.toml @@ -4,9 +4,6 @@ version = "0.1.0" authors = ["The Chromium OS Authors"] edition = "2018" -[features] -sandboxed-libusb = [] - [dependencies] data_model = { path = "../data_model" } kvm = { path = "../kvm" } |