1use rusb::ffi::{self, constants::*};
2
3use std::convert::TryInto;
4use std::ptr::NonNull;
5
6use std::sync::atomic::{AtomicBool, Ordering};
7
8mod error;
9mod pool;
10
11use error::{Error, Result};
12
13pub use pool::TransferPool;
14
15struct Transfer {
16 ptr: NonNull<ffi::libusb_transfer>,
17 buffer: Vec<u8>,
18}
19
20impl Transfer {
21 unsafe fn bulk(
23 device: *mut ffi::libusb_device_handle,
24 endpoint: u8,
25 mut buffer: Vec<u8>,
26 ) -> Self {
27 let ptr =
31 NonNull::new(ffi::libusb_alloc_transfer(0)).expect("Could not allocate transfer!");
32
33 let user_data = Box::into_raw(Box::new(AtomicBool::new(false))).cast::<libc::c_void>();
34
35 let length = if endpoint & ffi::constants::LIBUSB_ENDPOINT_DIR_MASK
36 == ffi::constants::LIBUSB_ENDPOINT_OUT
37 {
38 buffer.len()
40 } else {
41 buffer.capacity()
43 }
44 .try_into()
45 .unwrap();
46
47 ffi::libusb_fill_bulk_transfer(
48 ptr.as_ptr(),
49 device,
50 endpoint,
51 buffer.as_mut_ptr(),
52 length,
53 Self::transfer_cb,
54 user_data,
55 0,
56 );
57
58 Self { ptr, buffer }
59 }
60
61 unsafe fn control(
63 device: *mut ffi::libusb_device_handle,
64
65 request_type: u8,
66 request: u8,
67 value: u16,
68 index: u16,
69 data: &[u8],
70 ) -> Self {
71 let mut buf = Vec::with_capacity(data.len() + LIBUSB_CONTROL_SETUP_SIZE);
72
73 let length = data.len() as u16;
74
75 ffi::libusb_fill_control_setup(
76 buf.as_mut_ptr() as *mut u8,
77 request_type,
78 request,
79 value,
80 index,
81 length,
82 );
83 Self::control_raw(device, buf)
84 }
85
86 unsafe fn control_raw(device: *mut ffi::libusb_device_handle, mut buffer: Vec<u8>) -> Self {
88 let ptr =
92 NonNull::new(ffi::libusb_alloc_transfer(0)).expect("Could not allocate transfer!");
93
94 let user_data = Box::into_raw(Box::new(AtomicBool::new(false))).cast::<libc::c_void>();
95
96 ffi::libusb_fill_control_transfer(
97 ptr.as_ptr(),
98 device,
99 buffer.as_mut_ptr(),
100 Self::transfer_cb,
101 user_data,
102 0,
103 );
104
105 Self { ptr, buffer }
106 }
107
108 unsafe fn interrupt(
110 device: *mut ffi::libusb_device_handle,
111 endpoint: u8,
112 mut buffer: Vec<u8>,
113 ) -> Self {
114 let ptr =
118 NonNull::new(ffi::libusb_alloc_transfer(0)).expect("Could not allocate transfer!");
119
120 let user_data = Box::into_raw(Box::new(AtomicBool::new(false))).cast::<libc::c_void>();
121
122 let length = if endpoint & ffi::constants::LIBUSB_ENDPOINT_DIR_MASK
123 == ffi::constants::LIBUSB_ENDPOINT_OUT
124 {
125 buffer.len()
127 } else {
128 buffer.capacity()
130 }
131 .try_into()
132 .unwrap();
133
134 ffi::libusb_fill_interrupt_transfer(
135 ptr.as_ptr(),
136 device,
137 endpoint,
138 buffer.as_mut_ptr(),
139 length,
140 Self::transfer_cb,
141 user_data,
142 0,
143 );
144
145 Self { ptr, buffer }
146 }
147
148 unsafe fn iso(
150 device: *mut ffi::libusb_device_handle,
151 endpoint: u8,
152 mut buffer: Vec<u8>,
153 iso_packets: i32,
154 ) -> Self {
155 let ptr = NonNull::new(ffi::libusb_alloc_transfer(iso_packets))
158 .expect("Could not allocate transfer!");
159
160 let user_data = Box::into_raw(Box::new(AtomicBool::new(false))).cast::<libc::c_void>();
161
162 let length = if endpoint & ffi::constants::LIBUSB_ENDPOINT_DIR_MASK
163 == ffi::constants::LIBUSB_ENDPOINT_OUT
164 {
165 buffer.len()
167 } else {
168 buffer.capacity()
170 }
171 .try_into()
172 .unwrap();
173
174 ffi::libusb_fill_iso_transfer(
175 ptr.as_ptr(),
176 device,
177 endpoint,
178 buffer.as_mut_ptr(),
179 length,
180 iso_packets,
181 Self::transfer_cb,
182 user_data,
183 0,
184 );
185 ffi::libusb_set_iso_packet_lengths(ptr.as_ptr(), (length / iso_packets) as u32);
186
187 Self { ptr, buffer }
188 }
189 extern "system" fn transfer_cb(transfer: *mut ffi::libusb_transfer) {
192 let completed = unsafe {
198 let transfer = &mut *transfer;
199 &*transfer.user_data.cast::<AtomicBool>()
200 };
201 completed.store(true, Ordering::SeqCst);
202 }
203
204 fn transfer(&self) -> &ffi::libusb_transfer {
205 unsafe { self.ptr.as_ref() }
207 }
208
209 fn completed_flag(&self) -> &AtomicBool {
210 unsafe { &*self.transfer().user_data.cast::<AtomicBool>() }
212 }
213
214 fn swap_buffer(&mut self, new_buf: Vec<u8>) -> Vec<u8> {
216 let transfer_struct = unsafe { self.ptr.as_mut() };
217
218 let data = std::mem::replace(&mut self.buffer, new_buf);
219
220 transfer_struct.actual_length = 0; transfer_struct.buffer = self.buffer.as_mut_ptr();
223 transfer_struct.length = self.buffer.capacity() as i32;
224
225 data
226 }
227
228 fn submit(&mut self) -> Result<()> {
230 self.completed_flag().store(false, Ordering::SeqCst);
231 let errno = unsafe { ffi::libusb_submit_transfer(self.ptr.as_ptr()) };
232
233 match errno {
234 0 => Ok(()),
235 LIBUSB_ERROR_NO_DEVICE => Err(Error::Disconnected),
236 LIBUSB_ERROR_BUSY => {
237 unreachable!("We shouldn't be calling submit on transfers already submitted!")
238 }
239 LIBUSB_ERROR_NOT_SUPPORTED => Err(Error::Other("Transfer not supported")),
240 LIBUSB_ERROR_INVALID_PARAM => {
241 Err(Error::Other("Transfer size bigger than OS supports"))
242 }
243 _ => Err(Error::Errno("Error while submitting transfer: ", errno)),
244 }
245 }
246
247 fn cancel(&mut self) {
248 unsafe {
249 ffi::libusb_cancel_transfer(self.ptr.as_ptr());
250 }
251 }
252
253 fn handle_completed(&mut self) -> Result<Vec<u8>> {
254 assert!(self.completed_flag().load(Ordering::Relaxed));
255 let err = match self.transfer().status {
256 LIBUSB_TRANSFER_COMPLETED => {
257 debug_assert!(self.transfer().length >= self.transfer().actual_length);
258 unsafe {
259 self.buffer.set_len(self.transfer().actual_length as usize);
260 }
261 let data = self.swap_buffer(Vec::new());
262 return Ok(data);
263 }
264 LIBUSB_TRANSFER_CANCELLED => Error::Cancelled,
265 LIBUSB_TRANSFER_ERROR => Error::Other("Error occurred during transfer execution"),
266 LIBUSB_TRANSFER_TIMED_OUT => {
267 unreachable!("We are using timeout=0 which means no timeout")
268 }
269 LIBUSB_TRANSFER_STALL => Error::Stall,
270 LIBUSB_TRANSFER_NO_DEVICE => Error::Disconnected,
271 LIBUSB_TRANSFER_OVERFLOW => Error::Overflow,
272 _ => panic!("Found an unexpected error value for transfer status"),
273 };
274 Err(err)
275 }
276}
277
278impl Drop for Transfer {
280 fn drop(&mut self) {
281 unsafe {
282 drop(Box::from_raw(self.transfer().user_data));
283 ffi::libusb_free_transfer(self.ptr.as_ptr());
284 }
285 }
286}