| 30 |
30 |
|
| 31 |
31 |
const int libusb_timeout = 0;
|
| 32 |
32 |
|
|
33 |
static const size_t DEFAULT_NUM_XFERS = 16; //num xfers
|
|
34 |
static const size_t DEFAULT_XFER_SIZE = 32*512; //bytes
|
|
35 |
|
| 33 |
36 |
/***********************************************************************
|
| 34 |
37 |
* Helper functions
|
| 35 |
38 |
***********************************************************************/
|
| ... | ... | |
| 56 |
59 |
* create a bidirectional interface. It is a zero copy implementation
|
| 57 |
60 |
* with respect to libusb, however, each send and recv requires a copy
|
| 58 |
61 |
* operation from kernel to userspace; this is due to the usbfs
|
| 59 |
|
* interface provided by the kernel.
|
|
62 |
* interface provided by the kernel.
|
| 60 |
63 |
**********************************************************************/
|
| 61 |
64 |
class usb_endpoint {
|
| 62 |
65 |
public:
|
| ... | ... | |
| 107 |
110 |
//! a list of shared arrays for the transfer buffers
|
| 108 |
111 |
std::vector<boost::shared_array<boost::uint8_t> > _buffers;
|
| 109 |
112 |
|
| 110 |
|
// Calls for processing asynchronous I/O
|
|
113 |
// Calls for processing asynchronous I/O
|
| 111 |
114 |
libusb_transfer *allocate_transfer(int buff_len);
|
| 112 |
115 |
void print_transfer_status(libusb_transfer *lut);
|
| 113 |
116 |
};
|
| ... | ... | |
| 142 |
145 |
* Constructor
|
| 143 |
146 |
* Allocate libusb transfers and mark as free. For IN endpoints,
|
| 144 |
147 |
* submit the transfers so that they're ready to return when
|
| 145 |
|
* data is available.
|
|
148 |
* data is available.
|
| 146 |
149 |
*/
|
| 147 |
150 |
usb_endpoint::usb_endpoint(
|
| 148 |
151 |
libusb::device_handle::sptr handle,
|
| ... | ... | |
| 194 |
197 |
|
| 195 |
198 |
|
| 196 |
199 |
/*
|
| 197 |
|
* Allocate a libusb transfer
|
|
200 |
* Allocate a libusb transfer
|
| 198 |
201 |
* The allocated transfer - and buffer it contains - is repeatedly
|
| 199 |
202 |
* submitted, reaped, and reused and should not be freed until shutdown.
|
| 200 |
203 |
* \param buff_len size of the individual buffer held by each transfer
|
| ... | ... | |
| 225 |
228 |
* Asynchonous transfer submission
|
| 226 |
229 |
* Submit a libusb transfer to libusb add pending status
|
| 227 |
230 |
* \param lut pointer to libusb_transfer
|
| 228 |
|
* \return true on success or false on error
|
|
231 |
* \return true on success or false on error
|
| 229 |
232 |
*/
|
| 230 |
233 |
void usb_endpoint::submit(libusb_transfer *lut){
|
| 231 |
234 |
UHD_ASSERT_THROW(libusb_submit_transfer(lut) == 0);
|
| ... | ... | |
| 281 |
284 |
}
|
| 282 |
285 |
|
| 283 |
286 |
/***********************************************************************
|
| 284 |
|
* Managed buffers
|
|
287 |
* Managed buffers
|
| 285 |
288 |
**********************************************************************/
|
| 286 |
289 |
/*
|
| 287 |
290 |
* Libusb managed receive buffer
|
| 288 |
291 |
* Construct a recv buffer from a libusb transfer. The memory held by
|
| 289 |
292 |
* the libusb transfer is exposed through the managed buffer interface.
|
| 290 |
293 |
* Upon destruction, the transfer and buffer are resubmitted to the
|
| 291 |
|
* endpoint for further use.
|
|
294 |
* endpoint for further use.
|
| 292 |
295 |
*/
|
| 293 |
296 |
class libusb_managed_recv_buffer_impl : public managed_recv_buffer {
|
| 294 |
297 |
public:
|
| ... | ... | |
| 307 |
310 |
private:
|
| 308 |
311 |
const boost::asio::const_buffer &get() const
|
| 309 |
312 |
{
|
| 310 |
|
return _buff;
|
|
313 |
return _buff;
|
| 311 |
314 |
}
|
| 312 |
315 |
|
| 313 |
316 |
libusb_transfer *_lut;
|
| ... | ... | |
| 327 |
330 |
class libusb_managed_send_buffer_impl : public managed_send_buffer {
|
| 328 |
331 |
public:
|
| 329 |
332 |
libusb_managed_send_buffer_impl(libusb_transfer *lut,
|
| 330 |
|
usb_endpoint::sptr endpoint,
|
| 331 |
|
size_t buff_size)
|
| 332 |
|
: _buff(lut->buffer, buff_size), _committed(false)
|
|
333 |
usb_endpoint::sptr endpoint)
|
|
334 |
: _buff(lut->buffer, lut->length), _committed(false)
|
| 333 |
335 |
{
|
| 334 |
336 |
_lut = lut;
|
| 335 |
337 |
_endpoint = endpoint;
|
| ... | ... | |
| 349 |
351 |
std::cerr << "UHD: send buffer already committed" << std::endl;
|
| 350 |
352 |
return 0;
|
| 351 |
353 |
}
|
| 352 |
|
|
|
354 |
|
| 353 |
355 |
UHD_ASSERT_THROW(num_bytes <= boost::asio::buffer_size(_buff));
|
| 354 |
356 |
|
| 355 |
357 |
_lut->length = num_bytes;
|
| ... | ... | |
| 369 |
371 |
private:
|
| 370 |
372 |
const boost::asio::mutable_buffer &get() const
|
| 371 |
373 |
{
|
| 372 |
|
return _buff;
|
|
374 |
return _buff;
|
| 373 |
375 |
}
|
| 374 |
376 |
|
| 375 |
377 |
libusb_transfer *_lut;
|
| ... | ... | |
| 385 |
387 |
class libusb_zero_copy_impl : public usb_zero_copy
|
| 386 |
388 |
{
|
| 387 |
389 |
private:
|
| 388 |
|
usb_endpoint::sptr _rx_ep, _tx_ep;
|
| 389 |
|
|
| 390 |
390 |
libusb::device_handle::sptr _handle;
|
| 391 |
|
|
| 392 |
|
size_t _recv_buff_size;
|
| 393 |
|
size_t _send_buff_size;
|
| 394 |
|
size_t _num_frames;
|
|
391 |
size_t _recv_num_frames, _send_num_frames;
|
|
392 |
usb_endpoint::sptr _recv_ep, _send_ep;
|
| 395 |
393 |
|
| 396 |
394 |
public:
|
| 397 |
395 |
typedef boost::shared_ptr<libusb_zero_copy_impl> sptr;
|
| 398 |
396 |
|
| 399 |
|
libusb_zero_copy_impl(libusb::device_handle::sptr handle,
|
| 400 |
|
unsigned int rx_endpoint,
|
| 401 |
|
unsigned int tx_endpoint,
|
| 402 |
|
size_t recv_buff_size,
|
| 403 |
|
size_t send_buff_size);
|
|
397 |
libusb_zero_copy_impl(
|
|
398 |
libusb::device_handle::sptr handle,
|
|
399 |
unsigned int recv_endpoint, unsigned int send_endpoint,
|
|
400 |
size_t recv_xfer_size, size_t recv_num_xfers,
|
|
401 |
size_t send_xfer_size, size_t send_num_xfers
|
|
402 |
);
|
| 404 |
403 |
|
| 405 |
404 |
managed_recv_buffer::sptr get_recv_buff(void);
|
| 406 |
405 |
managed_send_buffer::sptr get_send_buff(void);
|
| 407 |
406 |
|
| 408 |
|
size_t get_num_recv_frames(void) const { return _num_frames; }
|
| 409 |
|
size_t get_num_send_frames(void) const { return _num_frames; }
|
|
407 |
size_t get_num_recv_frames(void) const { return _recv_num_frames; }
|
|
408 |
size_t get_num_send_frames(void) const { return _send_num_frames; }
|
| 410 |
409 |
};
|
| 411 |
410 |
|
| 412 |
411 |
/*
|
| 413 |
412 |
* Constructor
|
| 414 |
413 |
* Initializes libusb, opens devices, and sets up interfaces for I/O.
|
| 415 |
|
* Finally, creates endpoints for asynchronous I/O.
|
|
414 |
* Finally, creates endpoints for asynchronous I/O.
|
| 416 |
415 |
*/
|
| 417 |
|
libusb_zero_copy_impl::libusb_zero_copy_impl(libusb::device_handle::sptr handle,
|
| 418 |
|
unsigned int rx_endpoint,
|
| 419 |
|
unsigned int tx_endpoint,
|
| 420 |
|
size_t buff_size,
|
| 421 |
|
size_t block_size)
|
| 422 |
|
: _handle(handle),
|
| 423 |
|
_recv_buff_size(block_size), _send_buff_size(block_size),
|
| 424 |
|
_num_frames(buff_size / block_size)
|
| 425 |
|
{
|
| 426 |
|
_handle->claim_interface(2 /*in interface*/);
|
|
416 |
libusb_zero_copy_impl::libusb_zero_copy_impl(
|
|
417 |
libusb::device_handle::sptr handle,
|
|
418 |
unsigned int recv_endpoint, unsigned int send_endpoint,
|
|
419 |
size_t recv_xfer_size, size_t recv_num_xfers,
|
|
420 |
size_t send_xfer_size, size_t send_num_xfers
|
|
421 |
){
|
|
422 |
_handle = handle;
|
|
423 |
|
|
424 |
//if the sizes are left at 0 (automatic) -> use the defaults
|
|
425 |
if (recv_xfer_size == 0) recv_xfer_size = DEFAULT_XFER_SIZE;
|
|
426 |
if (recv_num_xfers == 0) recv_num_xfers = DEFAULT_NUM_XFERS;
|
|
427 |
if (send_xfer_size == 0) send_xfer_size = DEFAULT_XFER_SIZE;
|
|
428 |
if (send_num_xfers == 0) send_num_xfers = DEFAULT_NUM_XFERS;
|
|
429 |
|
|
430 |
//sanity check the transfer sizes
|
|
431 |
UHD_ASSERT_THROW(recv_xfer_size % 512 == 0);
|
|
432 |
UHD_ASSERT_THROW(send_xfer_size % 512 == 0);
|
|
433 |
|
|
434 |
//store the num xfers for the num frames count
|
|
435 |
_recv_num_frames = recv_num_xfers;
|
|
436 |
_send_num_frames = send_num_xfers;
|
|
437 |
|
|
438 |
_handle->claim_interface(2 /*in interface*/);
|
| 427 |
439 |
_handle->claim_interface(1 /*out interface*/);
|
| 428 |
440 |
|
| 429 |
|
_rx_ep = usb_endpoint::sptr(new usb_endpoint(
|
|
441 |
_recv_ep = usb_endpoint::sptr(new usb_endpoint(
|
| 430 |
442 |
_handle, // libusb device_handle
|
| 431 |
|
rx_endpoint, // USB endpoint number
|
|
443 |
recv_endpoint, // USB endpoint number
|
| 432 |
444 |
true, // IN endpoint
|
| 433 |
|
_recv_buff_size, // buffer size per transfer
|
| 434 |
|
_num_frames // number of libusb transfers
|
|
445 |
recv_xfer_size, // buffer size per transfer
|
|
446 |
recv_num_xfers // number of libusb transfers
|
| 435 |
447 |
));
|
| 436 |
448 |
|
| 437 |
|
_tx_ep = usb_endpoint::sptr(new usb_endpoint(
|
|
449 |
_send_ep = usb_endpoint::sptr(new usb_endpoint(
|
| 438 |
450 |
_handle, // libusb device_handle
|
| 439 |
|
tx_endpoint, // USB endpoint number
|
|
451 |
send_endpoint, // USB endpoint number
|
| 440 |
452 |
false, // OUT endpoint
|
| 441 |
|
_send_buff_size, // buffer size per transfer
|
| 442 |
|
_num_frames // number of libusb transfers
|
|
453 |
send_xfer_size, // buffer size per transfer
|
|
454 |
send_num_xfers // number of libusb transfers
|
| 443 |
455 |
));
|
| 444 |
456 |
}
|
| 445 |
457 |
|
| ... | ... | |
| 447 |
459 |
* Construct a managed receive buffer from a completed libusb transfer
|
| 448 |
460 |
* (happy with buffer full of data) obtained from the receive endpoint.
|
| 449 |
461 |
* Return empty pointer if no transfer is available (timeout or error).
|
| 450 |
|
* \return pointer to a managed receive buffer
|
|
462 |
* \return pointer to a managed receive buffer
|
| 451 |
463 |
*/
|
| 452 |
464 |
managed_recv_buffer::sptr libusb_zero_copy_impl::get_recv_buff(void){
|
| 453 |
|
libusb_transfer *lut = _rx_ep->get_lut_with_wait(/* TODO timeout API */);
|
|
465 |
libusb_transfer *lut = _recv_ep->get_lut_with_wait(/* TODO timeout API */);
|
| 454 |
466 |
if (lut == NULL) {
|
| 455 |
467 |
return managed_recv_buffer::sptr();
|
| 456 |
468 |
}
|
| 457 |
469 |
else {
|
| 458 |
470 |
return managed_recv_buffer::sptr(
|
| 459 |
471 |
new libusb_managed_recv_buffer_impl(lut,
|
| 460 |
|
_rx_ep));
|
|
472 |
_recv_ep));
|
| 461 |
473 |
}
|
| 462 |
474 |
}
|
| 463 |
475 |
|
| ... | ... | |
| 466 |
478 |
* Construct a managed send buffer from a free libusb transfer (with
|
| 467 |
479 |
* empty buffer). Return empty pointer of no transfer is available
|
| 468 |
480 |
* (timeout or error).
|
| 469 |
|
* \return pointer to a managed send buffer
|
|
481 |
* \return pointer to a managed send buffer
|
| 470 |
482 |
*/
|
| 471 |
483 |
managed_send_buffer::sptr libusb_zero_copy_impl::get_send_buff(void){
|
| 472 |
|
libusb_transfer *lut = _tx_ep->get_lut_with_wait(/* TODO timeout API */);
|
|
484 |
libusb_transfer *lut = _send_ep->get_lut_with_wait(/* TODO timeout API */);
|
| 473 |
485 |
if (lut == NULL) {
|
| 474 |
486 |
return managed_send_buffer::sptr();
|
| 475 |
487 |
}
|
| 476 |
488 |
else {
|
| 477 |
489 |
return managed_send_buffer::sptr(
|
| 478 |
490 |
new libusb_managed_send_buffer_impl(lut,
|
| 479 |
|
_tx_ep,
|
| 480 |
|
_send_buff_size));
|
|
491 |
_send_ep));
|
| 481 |
492 |
}
|
| 482 |
493 |
}
|
| 483 |
494 |
|
| 484 |
|
|
| 485 |
495 |
/***********************************************************************
|
| 486 |
496 |
* USB zero_copy make functions
|
| 487 |
497 |
**********************************************************************/
|
| 488 |
|
usb_zero_copy::sptr usb_zero_copy::make(usb_device_handle::sptr handle,
|
| 489 |
|
unsigned int rx_endpoint,
|
| 490 |
|
unsigned int tx_endpoint,
|
| 491 |
|
size_t buff_size,
|
| 492 |
|
size_t block_size)
|
| 493 |
|
|
| 494 |
|
{
|
|
498 |
usb_zero_copy::sptr usb_zero_copy::make(
|
|
499 |
usb_device_handle::sptr handle,
|
|
500 |
unsigned int recv_endpoint, unsigned int send_endpoint,
|
|
501 |
size_t recv_xfer_size, size_t recv_num_xfers,
|
|
502 |
size_t send_xfer_size, size_t send_num_xfers
|
|
503 |
){
|
| 495 |
504 |
libusb::device_handle::sptr dev_handle(libusb::device_handle::get_cached_handle(
|
| 496 |
505 |
boost::static_pointer_cast<libusb::special_handle>(handle)->get_device()
|
| 497 |
506 |
));
|
| 498 |
|
return sptr(new libusb_zero_copy_impl(dev_handle,
|
| 499 |
|
rx_endpoint,
|
| 500 |
|
tx_endpoint,
|
| 501 |
|
buff_size,
|
| 502 |
|
block_size));
|
|
507 |
return sptr(new libusb_zero_copy_impl(
|
|
508 |
dev_handle,
|
|
509 |
recv_endpoint, send_endpoint,
|
|
510 |
recv_xfer_size, recv_num_xfers,
|
|
511 |
send_xfer_size, send_num_xfers
|
|
512 |
));
|
| 503 |
513 |
}
|