• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2018 The Chromium OS Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 use std::os::raw::c_int;
6 use std::sync::Arc;
7 
8 use crate::bindings;
9 use crate::error::{Error, Result};
10 use crate::libusb_context::LibUsbContextInner;
11 use crate::usb_transfer::{UsbTransfer, UsbTransferBuffer};
12 
13 /// DeviceHandle wraps libusb_device_handle.
14 pub struct DeviceHandle {
15     _context: Arc<LibUsbContextInner>,
16     handle: *mut bindings::libusb_device_handle,
17 }
18 
19 unsafe impl Send for DeviceHandle {}
20 
21 impl Drop for DeviceHandle {
drop(&mut self)22     fn drop(&mut self) {
23         // Safe because self.handle is a valid pointer to libusb_device_handle.
24         unsafe {
25             bindings::libusb_close(self.handle);
26         }
27     }
28 }
29 
30 impl DeviceHandle {
31     /// Create a new DeviceHande. 'handle' should be a valid pointer to libusb_device_handle.
new( ctx: Arc<LibUsbContextInner>, handle: *mut bindings::libusb_device_handle, ) -> DeviceHandle32     pub unsafe fn new(
33         ctx: Arc<LibUsbContextInner>,
34         handle: *mut bindings::libusb_device_handle,
35     ) -> DeviceHandle {
36         DeviceHandle {
37             _context: ctx,
38             handle,
39         }
40     }
41 
42     /// Reset this usb device.
reset(&self) -> Result<()>43     pub fn reset(&self) -> Result<()> {
44         // Safe because 'self.handle' is a valid pointer to device handle.
45         try_libusb!(unsafe { bindings::libusb_reset_device(self.handle) });
46         Ok(())
47     }
48     /// Get bConfigurationValue of the currently active configuration.
get_active_configuration(&self) -> Result<i32>49     pub fn get_active_configuration(&self) -> Result<i32> {
50         let mut config: c_int = 0;
51         // Safe because 'self.handle' is a valid pointer to device handle and '&mut config' is a
52         // valid output location.
53         try_libusb!(unsafe { bindings::libusb_get_configuration(self.handle, &mut config) });
54         Ok(config as i32)
55     }
56 
57     /// Set active configuration for a device.
set_active_configuration(&mut self, config: i32) -> Result<()>58     pub fn set_active_configuration(&mut self, config: i32) -> Result<()> {
59         // Safe because 'self.handle' is a valid pointer to device handle.
60         try_libusb!(unsafe { bindings::libusb_set_configuration(self.handle, config as c_int) });
61         Ok(())
62     }
63 
64     /// Claim an interface on this deivce handle.
claim_interface(&self, interface_number: i32) -> Result<()>65     pub fn claim_interface(&self, interface_number: i32) -> Result<()> {
66         // Safe because 'self.handle' is a valid pointer to device handle.
67         try_libusb!(unsafe { bindings::libusb_claim_interface(self.handle, interface_number) });
68         Ok(())
69     }
70 
71     /// Release an interface previously claimed with libusb_claim_interface.
release_interface(&self, interface_number: i32) -> Result<()>72     pub fn release_interface(&self, interface_number: i32) -> Result<()> {
73         // Safe because 'self.handle' is a valid pointer to device handle.
74         try_libusb!(unsafe { bindings::libusb_release_interface(self.handle, interface_number) });
75         Ok(())
76     }
77 
78     /// Perform a USB port reset to reinitialize a device.
reset_device(&self) -> Result<()>79     pub fn reset_device(&self) -> Result<()> {
80         // Safe because 'self.handle' is a valid pointer to device handle.
81         try_libusb!(unsafe { bindings::libusb_reset_device(self.handle) });
82         Ok(())
83     }
84 
85     /// Determine if a kernel driver is active on an interface.
kernel_driver_active(&self, interface_number: i32) -> Result<bool>86     pub fn kernel_driver_active(&self, interface_number: i32) -> Result<bool> {
87         // Safe because 'self.handle' is a valid pointer to device handle.
88         let v = try_libusb!(unsafe {
89             bindings::libusb_kernel_driver_active(self.handle, interface_number)
90         });
91         Ok(v != 0)
92     }
93 
94     /// Detach a kernel driver from an interface.
detach_kernel_driver(&self, interface_number: i32) -> Result<()>95     pub fn detach_kernel_driver(&self, interface_number: i32) -> Result<()> {
96         // Safe because 'self.handle' is a valid pointer to device handle.
97         try_libusb!(unsafe {
98             bindings::libusb_detach_kernel_driver(self.handle, interface_number)
99         });
100         Ok(())
101     }
102 
103     /// Re-attach an interfae's kernel driver, which was previously detached using
104     /// detach_kernel_driver.
attach_kernel_driver(&self, interface_number: i32) -> Result<()>105     pub fn attach_kernel_driver(&self, interface_number: i32) -> Result<()> {
106         // Safe because 'self.handle' is a valid pointer to device handle.
107         try_libusb!(unsafe {
108             bindings::libusb_attach_kernel_driver(self.handle, interface_number)
109         });
110         Ok(())
111     }
112 
113     /// Active an alternate setting for an interface.
set_interface_alt_setting( &self, interface_number: i32, alternative_setting: i32, ) -> Result<()>114     pub fn set_interface_alt_setting(
115         &self,
116         interface_number: i32,
117         alternative_setting: i32,
118     ) -> Result<()> {
119         // Safe because 'self.handle' is a valid pointer to device handle.
120         try_libusb!(unsafe {
121             bindings::libusb_set_interface_alt_setting(
122                 self.handle,
123                 interface_number,
124                 alternative_setting,
125             )
126         });
127         Ok(())
128     }
129 
130     /// Clear the halt/stall condition for an endpoint.
clear_halt(&self, endpoint: u8) -> Result<()>131     pub fn clear_halt(&self, endpoint: u8) -> Result<()> {
132         // Safe because 'self.handle' is a valid pointer to device handle.
133         try_libusb!(unsafe { bindings::libusb_clear_halt(self.handle, endpoint) });
134         Ok(())
135     }
136 
137     /// Libusb asynchronous I/O interface has a 5 step process. It gives lots of
138     /// flexibility but makes it hard to manage object life cycle and easy to
139     /// write unsafe code. We wrap this interface to a simple "transfer" and "cancel"
140     /// interface. Resubmission is not supported and deallocation is handled safely
141     /// here.
submit_async_transfer<T: UsbTransferBuffer>( &self, transfer: UsbTransfer<T>, ) -> Result<()>142     pub fn submit_async_transfer<T: UsbTransferBuffer>(
143         &self,
144         transfer: UsbTransfer<T>,
145     ) -> Result<()> {
146         unsafe { transfer.submit(self.handle) }
147     }
148 }
149