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