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::mem::size_of;
6 use std::os::raw::c_void;
7 use std::sync::{Arc, Weak};
8
9 use crate::bindings::{
10 libusb_alloc_transfer, libusb_cancel_transfer, libusb_device_handle, libusb_free_transfer,
11 libusb_submit_transfer, libusb_transfer, libusb_transfer_status, LIBUSB_TRANSFER_CANCELLED,
12 LIBUSB_TRANSFER_COMPLETED, LIBUSB_TRANSFER_ERROR, LIBUSB_TRANSFER_NO_DEVICE,
13 LIBUSB_TRANSFER_OVERFLOW, LIBUSB_TRANSFER_STALL, LIBUSB_TRANSFER_TIMED_OUT,
14 LIBUSB_TRANSFER_TYPE_BULK, LIBUSB_TRANSFER_TYPE_CONTROL, LIBUSB_TRANSFER_TYPE_INTERRUPT,
15 };
16 use crate::error::{Error, Result};
17 use crate::types::UsbRequestSetup;
18
19 /// Status of transfer.
20 #[derive(PartialEq)]
21 pub enum TransferStatus {
22 Completed,
23 Error,
24 TimedOut,
25 Cancelled,
26 Stall,
27 NoDevice,
28 Overflow,
29 }
30
31 impl From<libusb_transfer_status> for TransferStatus {
from(s: libusb_transfer_status) -> Self32 fn from(s: libusb_transfer_status) -> Self {
33 match s {
34 LIBUSB_TRANSFER_COMPLETED => TransferStatus::Completed,
35 LIBUSB_TRANSFER_ERROR => TransferStatus::Error,
36 LIBUSB_TRANSFER_TIMED_OUT => TransferStatus::TimedOut,
37 LIBUSB_TRANSFER_CANCELLED => TransferStatus::Cancelled,
38 LIBUSB_TRANSFER_STALL => TransferStatus::Stall,
39 LIBUSB_TRANSFER_NO_DEVICE => TransferStatus::NoDevice,
40 LIBUSB_TRANSFER_OVERFLOW => TransferStatus::Overflow,
41 _ => TransferStatus::Error,
42 }
43 }
44 }
45
46 /// Trait for usb transfer buffer.
47 pub trait UsbTransferBuffer: Send {
as_ptr(&mut self) -> *mut u848 fn as_ptr(&mut self) -> *mut u8;
len(&self) -> i3249 fn len(&self) -> i32;
50 }
51
52 /// Default buffer size for control data transfer.
53 const CONTROL_DATA_BUFFER_SIZE: usize = 1024;
54
55 /// Buffer type for control transfer. The first 8-bytes is a UsbRequestSetup struct.
56 #[repr(C, packed)]
57 pub struct ControlTransferBuffer {
58 pub setup_buffer: UsbRequestSetup,
59 pub data_buffer: [u8; CONTROL_DATA_BUFFER_SIZE],
60 }
61
62 impl ControlTransferBuffer {
new() -> ControlTransferBuffer63 fn new() -> ControlTransferBuffer {
64 ControlTransferBuffer {
65 setup_buffer: UsbRequestSetup {
66 request_type: 0,
67 request: 0,
68 value: 0,
69 index: 0,
70 length: 0,
71 },
72 data_buffer: [0; CONTROL_DATA_BUFFER_SIZE],
73 }
74 }
75
76 /// Set request setup for this control buffer.
set_request_setup(&mut self, request_setup: &UsbRequestSetup)77 pub fn set_request_setup(&mut self, request_setup: &UsbRequestSetup) {
78 self.setup_buffer = *request_setup;
79 }
80 }
81
82 impl UsbTransferBuffer for ControlTransferBuffer {
as_ptr(&mut self) -> *mut u883 fn as_ptr(&mut self) -> *mut u8 {
84 self as *mut ControlTransferBuffer as *mut u8
85 }
86
len(&self) -> i3287 fn len(&self) -> i32 {
88 if self.setup_buffer.length as usize > CONTROL_DATA_BUFFER_SIZE {
89 panic!("Setup packet has an oversize length");
90 }
91 self.setup_buffer.length as i32 + size_of::<UsbRequestSetup>() as i32
92 }
93 }
94
95 /// Buffer type for Bulk transfer.
96 pub struct BulkTransferBuffer {
97 buffer: Vec<u8>,
98 }
99
100 impl BulkTransferBuffer {
with_size(buffer_size: usize) -> Self101 fn with_size(buffer_size: usize) -> Self {
102 BulkTransferBuffer {
103 buffer: vec![0; buffer_size],
104 }
105 }
106
107 /// Get mutable interal slice of this buffer.
as_mut_slice(&mut self) -> &mut [u8]108 pub fn as_mut_slice(&mut self) -> &mut [u8] {
109 &mut self.buffer
110 }
111
112 /// Get interal slice of this buffer.
as_slice(&self) -> &[u8]113 pub fn as_slice(&self) -> &[u8] {
114 &self.buffer
115 }
116 }
117
118 impl UsbTransferBuffer for BulkTransferBuffer {
as_ptr(&mut self) -> *mut u8119 fn as_ptr(&mut self) -> *mut u8 {
120 if self.buffer.len() == 0 {
121 // Vec::as_mut_ptr() won't give 0x0 even if len() is 0.
122 std::ptr::null_mut()
123 } else {
124 self.buffer.as_mut_ptr()
125 }
126 }
127
len(&self) -> i32128 fn len(&self) -> i32 {
129 self.buffer.len() as i32
130 }
131 }
132
133 type UsbTransferCompletionCallback<T> = dyn Fn(UsbTransfer<T>) + Send + 'static;
134
135 // This wraps libusb_transfer pointer.
136 struct LibUsbTransfer {
137 ptr: *mut libusb_transfer,
138 }
139
140 impl Drop for LibUsbTransfer {
drop(&mut self)141 fn drop(&mut self) {
142 // Safe because 'self.ptr' is allocated by libusb_alloc_transfer.
143 unsafe {
144 libusb_free_transfer(self.ptr);
145 }
146 }
147 }
148
149 // It is safe to invoke libusb functions from multiple threads.
150 // We cannot modify libusb_transfer safely from multiple threads. All the modifications happens
151 // in construct (UsbTransfer::new) or consume (UsbTransfer::into_raw), we can consider this thread
152 // safe.
153 unsafe impl Send for LibUsbTransfer {}
154 unsafe impl Sync for LibUsbTransfer {}
155
156 /// TransferCanceller can cancel the transfer.
157 pub struct TransferCanceller {
158 transfer: Weak<LibUsbTransfer>,
159 }
160
161 impl TransferCanceller {
162 /// Return false if fail to cancel.
try_cancel(&self) -> bool163 pub fn try_cancel(&self) -> bool {
164 match self.transfer.upgrade() {
165 Some(t) => {
166 // Safe because self.transfer has ownership of the raw pointer.
167 let r = unsafe { libusb_cancel_transfer(t.ptr) };
168 if r == 0 {
169 true
170 } else {
171 false
172 }
173 }
174 None => false,
175 }
176 }
177 }
178
179 struct UsbTransferInner<T: UsbTransferBuffer> {
180 transfer: Arc<LibUsbTransfer>,
181 callback: Option<Box<UsbTransferCompletionCallback<T>>>,
182 buffer: T,
183 }
184
185 /// UsbTransfer owns a LibUsbTransfer, it's buffer and callback.
186 pub struct UsbTransfer<T: UsbTransferBuffer> {
187 inner: Box<UsbTransferInner<T>>,
188 }
189
190 /// Build a control transfer.
control_transfer(timeout: u32) -> UsbTransfer<ControlTransferBuffer>191 pub fn control_transfer(timeout: u32) -> UsbTransfer<ControlTransferBuffer> {
192 UsbTransfer::<ControlTransferBuffer>::new(
193 0,
194 LIBUSB_TRANSFER_TYPE_CONTROL as u8,
195 timeout,
196 ControlTransferBuffer::new(),
197 )
198 }
199
200 /// Build a data transfer.
bulk_transfer(endpoint: u8, timeout: u32, size: usize) -> UsbTransfer<BulkTransferBuffer>201 pub fn bulk_transfer(endpoint: u8, timeout: u32, size: usize) -> UsbTransfer<BulkTransferBuffer> {
202 UsbTransfer::<BulkTransferBuffer>::new(
203 endpoint,
204 LIBUSB_TRANSFER_TYPE_BULK as u8,
205 timeout,
206 BulkTransferBuffer::with_size(size),
207 )
208 }
209
210 /// Build a data transfer.
interrupt_transfer( endpoint: u8, timeout: u32, size: usize, ) -> UsbTransfer<BulkTransferBuffer>211 pub fn interrupt_transfer(
212 endpoint: u8,
213 timeout: u32,
214 size: usize,
215 ) -> UsbTransfer<BulkTransferBuffer> {
216 UsbTransfer::<BulkTransferBuffer>::new(
217 endpoint,
218 LIBUSB_TRANSFER_TYPE_INTERRUPT as u8,
219 timeout,
220 BulkTransferBuffer::with_size(size),
221 )
222 }
223
224 impl<T: UsbTransferBuffer> UsbTransfer<T> {
new(endpoint: u8, type_: u8, timeout: u32, buffer: T) -> Self225 fn new(endpoint: u8, type_: u8, timeout: u32, buffer: T) -> Self {
226 // Safe because alloc is safe.
227 let transfer: *mut libusb_transfer = unsafe { libusb_alloc_transfer(0) };
228 // Just panic on OOM.
229 assert!(!transfer.is_null());
230 let inner = Box::new(UsbTransferInner {
231 transfer: Arc::new(LibUsbTransfer { ptr: transfer }),
232 callback: None,
233 buffer,
234 });
235 // Safe because we inited transfer.
236 let raw_transfer: &mut libusb_transfer = unsafe { &mut *(inner.transfer.ptr) };
237 raw_transfer.endpoint = endpoint;
238 raw_transfer.type_ = type_;
239 raw_transfer.timeout = timeout;
240 raw_transfer.callback = Some(UsbTransfer::<T>::on_transfer_completed);
241 UsbTransfer { inner }
242 }
243
244 /// Get canceller of this transfer.
get_canceller(&self) -> TransferCanceller245 pub fn get_canceller(&self) -> TransferCanceller {
246 let weak_transfer = Arc::downgrade(&self.inner.transfer);
247 TransferCanceller {
248 transfer: weak_transfer,
249 }
250 }
251
252 /// Set callback function for transfer completion.
set_callback<C: 'static + Fn(UsbTransfer<T>) + Send>(&mut self, cb: C)253 pub fn set_callback<C: 'static + Fn(UsbTransfer<T>) + Send>(&mut self, cb: C) {
254 self.inner.callback = Some(Box::new(cb));
255 }
256
257 /// Get a reference to the buffer.
buffer(&self) -> &T258 pub fn buffer(&self) -> &T {
259 &self.inner.buffer
260 }
261
262 /// Get a mutable reference to the buffer.
buffer_mut(&mut self) -> &mut T263 pub fn buffer_mut(&mut self) -> &mut T {
264 &mut self.inner.buffer
265 }
266
267 /// Get actual length of data that was transferred.
actual_length(&self) -> i32268 pub fn actual_length(&self) -> i32 {
269 let transfer = self.inner.transfer.ptr;
270 // Safe because inner.ptr is always allocated by libusb_alloc_transfer.
271 unsafe { (*transfer).actual_length }
272 }
273
274 /// Get the transfer status of this transfer.
status(&self) -> TransferStatus275 pub fn status(&self) -> TransferStatus {
276 let transfer = self.inner.transfer.ptr;
277 // Safe because inner.ptr is always allocated by libusb_alloc_transfer.
278 unsafe { TransferStatus::from((*transfer).status) }
279 }
280
281 /// Submit this transfer to device handle. 'self' is consumed. On success, the memory will be
282 /// 'leaked' (and stored in user_data) and sent to libusb, when the async operation is done,
283 /// on_transfer_completed will recreate 'self' and deliver it to callback/free 'self'. On
284 /// faliure, 'self' is returned with an error.
285 ///
286 /// # Safety
287 ///
288 /// Assumes libusb_device_handle is an handled opened by libusb, self.inner.transfer.ptr is
289 /// initialized with correct buffer and length.
submit(self, handle: *mut libusb_device_handle) -> Result<()>290 pub unsafe fn submit(self, handle: *mut libusb_device_handle) -> Result<()> {
291 let transfer = self.into_raw();
292 (*transfer).dev_handle = handle;
293 match Error::from(libusb_submit_transfer(transfer)) {
294 Error::Success(_e) => Ok(()),
295 err => {
296 UsbTransfer::<T>::from_raw(transfer);
297 Err(err)
298 }
299 }
300 }
301
302 /// Invoke callback when transfer is completed.
303 ///
304 /// # Safety
305 ///
306 /// Assumes libusb_tranfser is finished. This function is called by libusb, don't call it
307 /// manually.
on_transfer_completed(transfer: *mut libusb_transfer)308 unsafe extern "C" fn on_transfer_completed(transfer: *mut libusb_transfer) {
309 let mut transfer = UsbTransfer::<T>::from_raw(transfer);
310 // Callback is reset to None.
311 if let Some(cb) = transfer.inner.callback.take() {
312 cb(transfer);
313 }
314 }
315
into_raw(mut self) -> *mut libusb_transfer316 fn into_raw(mut self) -> *mut libusb_transfer {
317 let transfer: *mut libusb_transfer = self.inner.transfer.ptr;
318 // Safe because transfer is allocated by libusb_alloc_transfer.
319 unsafe {
320 (*transfer).buffer = self.buffer_mut().as_ptr();
321 (*transfer).length = self.buffer_mut().len();
322 (*transfer).user_data = Box::into_raw(self.inner) as *mut c_void;
323 }
324 transfer
325 }
326
from_raw(transfer: *mut libusb_transfer) -> Self327 unsafe fn from_raw(transfer: *mut libusb_transfer) -> Self {
328 UsbTransfer {
329 inner: Box::<UsbTransferInner<T>>::from_raw(
330 (*transfer).user_data as *mut UsbTransferInner<T>,
331 ),
332 }
333 }
334 }
335
336 #[cfg(test)]
337 mod tests {
338 use super::*;
339 use std::sync::Mutex;
340
fake_submit_transfer<T: UsbTransferBuffer>(transfer: UsbTransfer<T>)341 pub fn fake_submit_transfer<T: UsbTransferBuffer>(transfer: UsbTransfer<T>) {
342 let transfer = transfer.into_raw();
343 unsafe {
344 match (*transfer).callback {
345 Some(cb) => cb(transfer),
346 // Although no callback is invoked, we still need on_transfer_completed to
347 // free memory.
348 None => panic!("Memory leak!"),
349 };
350 }
351 }
352
353 #[test]
check_control_buffer_size()354 fn check_control_buffer_size() {
355 assert_eq!(
356 size_of::<ControlTransferBuffer>(),
357 size_of::<UsbRequestSetup>() + CONTROL_DATA_BUFFER_SIZE
358 );
359 }
360
361 #[test]
submit_transfer_no_callback_test()362 fn submit_transfer_no_callback_test() {
363 let t = control_transfer(0);
364 fake_submit_transfer(t);
365 let t = bulk_transfer(0, 0, 1);
366 fake_submit_transfer(t);
367 }
368
369 struct FakeTransferController {
370 data: Mutex<u8>,
371 }
372
373 #[test]
submit_transfer_with_callback()374 fn submit_transfer_with_callback() {
375 let c = Arc::new(FakeTransferController {
376 data: Mutex::new(0),
377 });
378 let c1 = Arc::downgrade(&c);
379 let mut t = control_transfer(0);
380 t.set_callback(move |_t| {
381 let c = c1.upgrade().unwrap();
382 *c.data.lock().unwrap() = 3;
383 });
384 fake_submit_transfer(t);
385 assert_eq!(*c.data.lock().unwrap(), 3);
386 }
387 }
388