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;
6 use std::os::raw::{c_short, c_void};
7 use std::os::unix::io::RawFd;
8 use std::sync::Arc;
9
10 use crate::bindings;
11 use crate::error::{Error, Result};
12 use crate::hotplug::{hotplug_cb, UsbHotplugHandler, UsbHotplugHandlerHolder};
13 use crate::libusb_device::LibUsbDevice;
14
15 use sync::Mutex;
16
17 pub struct LibUsbContextInner {
18 context: *mut bindings::libusb_context,
19 pollfd_change_handler: Mutex<Option<Box<PollfdChangeHandlerHolder>>>,
20 }
21
22 // Safe because libusb_context could be accessed from multiple threads safely.
23 unsafe impl Send for LibUsbContextInner {}
24 unsafe impl Sync for LibUsbContextInner {}
25
26 impl LibUsbContextInner {
27 /// Remove the previous registered notifiers.
remove_pollfd_notifiers(&self)28 pub fn remove_pollfd_notifiers(&self) {
29 // Safe because 'self.context' is valid.
30 unsafe {
31 bindings::libusb_set_pollfd_notifiers(self.context, None, None, std::ptr::null_mut());
32 }
33 }
34 }
35
36 impl Drop for LibUsbContextInner {
drop(&mut self)37 fn drop(&mut self) {
38 // Avoid pollfd change handler call when libusb_exit is called.
39 self.remove_pollfd_notifiers();
40 // Safe beacuse 'self.context' points to a valid context allocated by libusb_init.
41 unsafe {
42 bindings::libusb_exit(self.context);
43 }
44 }
45 }
46
47 /// Wrapper for libusb_context. The libusb libary initialization/deinitialization
48 /// is managed by this context.
49 /// See: http://libusb.sourceforge.net/api-1.0/group__libusb__lib.html
50 #[derive(Clone)]
51 pub struct LibUsbContext {
52 inner: Arc<LibUsbContextInner>,
53 }
54
55 impl LibUsbContext {
56 /// Create a new LibUsbContext.
new() -> Result<LibUsbContext>57 pub fn new() -> Result<LibUsbContext> {
58 let mut ctx: *mut bindings::libusb_context = std::ptr::null_mut();
59 // Safe because '&mut ctx' points to a valid memory (on stack).
60 try_libusb!(unsafe { bindings::libusb_init(&mut ctx) });
61 Ok(LibUsbContext {
62 inner: Arc::new(LibUsbContextInner {
63 context: ctx,
64 pollfd_change_handler: Mutex::new(None),
65 }),
66 })
67 }
68
69 /// Create a new jailed LibUsbContext.
70 #[cfg(feature = "sandboxed-libusb")]
new_jailed() -> Result<LibUsbContext>71 pub fn new_jailed() -> Result<LibUsbContext> {
72 let mut ctx: *mut bindings::libusb_context = std::ptr::null_mut();
73 // Safe because '&mut ctx' points to a valid memory (on stack).
74 try_libusb!(unsafe { bindings::libusb_init_jailed(&mut ctx) });
75 Ok(LibUsbContext {
76 inner: Arc::new(LibUsbContextInner {
77 context: ctx,
78 pollfd_change_handler: Mutex::new(None),
79 }),
80 })
81 }
82
83 /// Build device from File.
84 #[cfg(feature = "sandboxed-libusb")]
get_device_from_fd(&self, fd: std::fs::File) -> Result<LibUsbDevice>85 pub fn get_device_from_fd(&self, fd: std::fs::File) -> Result<LibUsbDevice> {
86 use std::os::unix::io::IntoRawFd;
87
88 let fd = fd.into_raw_fd();
89 let mut device: *mut bindings::libusb_device = std::ptr::null_mut();
90 // Safe because fd is valid and owned, and '&mut device' points to valid memory.
91 try_libusb!(unsafe {
92 bindings::libusb_get_device_from_fd(self.inner.context, fd, &mut device)
93 });
94 unsafe { Ok(LibUsbDevice::new(self.inner.clone(), device)) }
95 }
96
97 /// Returns a list of USB devices currently attached to the system.
get_device_iter(&self) -> Result<DeviceIter>98 pub fn get_device_iter(&self) -> Result<DeviceIter> {
99 let mut list: *mut *mut bindings::libusb_device = std::ptr::null_mut();
100 // Safe because 'inner.context' points to a valid context and '&mut list' points to a valid
101 // memory.
102 try_libusb!(unsafe { bindings::libusb_get_device_list(self.inner.context, &mut list) });
103
104 Ok(DeviceIter {
105 context: self.inner.clone(),
106 list,
107 index: 0,
108 })
109 }
110
111 /// Check at runtime if the loaded library has a given capability.
has_capability(&self, cap: u32) -> bool112 pub fn has_capability(&self, cap: u32) -> bool {
113 // Safe because libusb_init is called before this call happens.
114 unsafe { bindings::libusb_has_capability(cap) != 0 }
115 }
116
117 /// Return an iter of poll fds. Those fds that should be polled to handle libusb events.
get_pollfd_iter(&self) -> PollFdIter118 pub fn get_pollfd_iter(&self) -> PollFdIter {
119 // Safe because 'inner.context' is inited.
120 let list: *mut *const bindings::libusb_pollfd =
121 unsafe { bindings::libusb_get_pollfds(self.inner.context) };
122 PollFdIter { list, index: 0 }
123 }
124
125 /// Handle libusb events in a non block way.
handle_events_nonblock(&self)126 pub fn handle_events_nonblock(&self) {
127 static mut zero_time: bindings::timeval = bindings::timeval {
128 tv_sec: 0,
129 tv_usec: 0,
130 };
131 // Safe because 'inner.context' points to valid context.
132 unsafe {
133 bindings::libusb_handle_events_timeout_completed(
134 self.inner.context,
135 &mut zero_time as *mut bindings::timeval,
136 std::ptr::null_mut(),
137 );
138 }
139 }
140
141 /// Set a handler that could handle pollfd change events.
set_pollfd_notifiers(&self, handler: Box<dyn LibUsbPollfdChangeHandler>)142 pub fn set_pollfd_notifiers(&self, handler: Box<dyn LibUsbPollfdChangeHandler>) {
143 // LibUsbContext is alive when any libusb related function is called. It owns the handler,
144 // thus the handler memory is always valid when callback is invoked.
145 let holder = Box::new(PollfdChangeHandlerHolder { handler });
146 let raw_holder = Box::into_raw(holder);
147 unsafe {
148 bindings::libusb_set_pollfd_notifiers(
149 self.inner.context,
150 Some(pollfd_added_cb),
151 Some(pollfd_removed_cb),
152 raw_holder as *mut c_void,
153 );
154 }
155 // Safe because raw_holder is from Boxed pointer.
156 let holder = unsafe { Box::from_raw(raw_holder) };
157 *self.inner.pollfd_change_handler.lock() = Some(holder);
158 }
159
160 /// Remove the previous registered notifiers.
remove_pollfd_notifiers(&self)161 pub fn remove_pollfd_notifiers(&self) {
162 self.inner.remove_pollfd_notifiers();
163 }
164
165 /// Set a callback that could handle hotplug events. Currently, this function listen to hotplug
166 /// event of all devices.
set_hotplug_cb<H: UsbHotplugHandler + Sized>(&self, handler: H) -> Result<()>167 pub fn set_hotplug_cb<H: UsbHotplugHandler + Sized>(&self, handler: H) -> Result<()> {
168 let event = bindings::LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED
169 | bindings::LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT;
170 let holder = UsbHotplugHandlerHolder::new(self.inner.clone(), handler);
171 let raw_holder = Box::into_raw(holder);
172 // Safe becuase hotpulg cb is a vaild c function and raw_holder points to memory for that
173 // function argument.
174 try_libusb!(unsafe {
175 bindings::libusb_hotplug_register_callback(
176 self.inner.context,
177 event,
178 bindings::LIBUSB_HOTPLUG_NO_FLAGS,
179 bindings::LIBUSB_HOTPLUG_MATCH_ANY,
180 bindings::LIBUSB_HOTPLUG_MATCH_ANY,
181 bindings::LIBUSB_HOTPLUG_MATCH_ANY,
182 Some(hotplug_cb),
183 raw_holder as *mut c_void,
184 std::ptr::null_mut(),
185 )
186 });
187 Ok(())
188 }
189 }
190
191 /// Iterator for device list.
192 pub struct DeviceIter {
193 context: Arc<LibUsbContextInner>,
194 list: *mut *mut bindings::libusb_device,
195 index: isize,
196 }
197
198 impl Drop for DeviceIter {
drop(&mut self)199 fn drop(&mut self) {
200 // Safe because 'self.list' is inited by a valid pointer from libusb_get_device_list.
201 unsafe {
202 bindings::libusb_free_device_list(self.list, 1);
203 }
204 }
205 }
206
207 impl Iterator for DeviceIter {
208 type Item = LibUsbDevice;
209
next(&mut self) -> Option<LibUsbDevice>210 fn next(&mut self) -> Option<LibUsbDevice> {
211 // Safe becuase 'self.list' is valid, the list is null terminated.
212 unsafe {
213 let current_ptr = self.list.offset(self.index);
214 if (*current_ptr).is_null() {
215 return None;
216 }
217 self.index += 1;
218 Some(LibUsbDevice::new(self.context.clone(), *current_ptr))
219 }
220 }
221 }
222
223 /// Iterator for pollfds.
224 pub struct PollFdIter {
225 list: *mut *const bindings::libusb_pollfd,
226 index: isize,
227 }
228
229 impl Drop for PollFdIter {
drop(&mut self)230 fn drop(&mut self) {
231 // Safe because 'self.list' points to valid memory of pollfd list.
232 unsafe {
233 bindings::libusb_free_pollfds(self.list);
234 }
235 }
236 }
237
238 impl Iterator for PollFdIter {
239 type Item = bindings::libusb_pollfd;
240
next(&mut self) -> Option<bindings::libusb_pollfd>241 fn next(&mut self) -> Option<bindings::libusb_pollfd> {
242 // Safe because 'self.index' never grow out of the null pointer index.
243 unsafe {
244 let current_ptr = self.list.offset(self.index);
245 if (*current_ptr).is_null() {
246 return None;
247 }
248
249 self.index += 1;
250 // Safe because '*current_ptr' is not null.
251 Some(**current_ptr)
252 }
253 }
254 }
255
256 /// Trait for handler that handles Pollfd Change events.
257 pub trait LibUsbPollfdChangeHandler: Send + Sync + 'static {
add_poll_fd(&self, fd: RawFd, events: c_short)258 fn add_poll_fd(&self, fd: RawFd, events: c_short);
remove_poll_fd(&self, fd: RawFd)259 fn remove_poll_fd(&self, fd: RawFd);
260 }
261
262 // This struct owns LibUsbPollfdChangeHandler. We need it because it's not possible to cast void
263 // pointer to trait pointer.
264 struct PollfdChangeHandlerHolder {
265 handler: Box<dyn LibUsbPollfdChangeHandler>,
266 }
267
268 // This function is safe when user_data points to valid PollfdChangeHandlerHolder.
pollfd_added_cb(fd: RawFd, events: c_short, user_data: *mut c_void)269 unsafe extern "C" fn pollfd_added_cb(fd: RawFd, events: c_short, user_data: *mut c_void) {
270 // Safe because user_data was casted from holder.
271 let keeper = &*(user_data as *mut PollfdChangeHandlerHolder);
272 keeper.handler.add_poll_fd(fd, events);
273 }
274
275 // This function is safe when user_data points to valid PollfdChangeHandlerHolder.
pollfd_removed_cb(fd: RawFd, user_data: *mut c_void)276 unsafe extern "C" fn pollfd_removed_cb(fd: RawFd, user_data: *mut c_void) {
277 // Safe because user_data was casted from holder.
278 let keeper = &*(user_data as *mut PollfdChangeHandlerHolder);
279 keeper.handler.remove_poll_fd(fd);
280 }
281