• 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::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