Revision 55da3154 host/lib/transport/libusb1_zero_copy.cpp
| b/host/lib/transport/libusb1_zero_copy.cpp | ||
|---|---|---|
| 64 | 64 |
size_t _transfer_size; |
| 65 | 65 |
size_t _num_transfers; |
| 66 | 66 |
|
| 67 |
/* |
|
| 68 |
* Transfer state lists (free, pending, or completed) |
|
| 69 |
*/ |
|
| 67 |
// Transfer state lists (transfers are free, pending, or completed) |
|
| 70 | 68 |
std::list<libusb_transfer *> _free_list; |
| 71 | 69 |
std::list<libusb_transfer *> _pending_list; |
| 72 | 70 |
std::list<libusb_transfer *> _completed_list; |
| 73 | 71 |
|
| 74 |
/* |
|
| 75 |
* Calls for processing asynchronous I/O |
|
| 76 |
*/ |
|
| 72 |
// Calls for processing asynchronous I/O |
|
| 77 | 73 |
libusb_transfer *allocate_transfer(int buff_len); |
| 78 | 74 |
bool cancel(libusb_transfer *lut); |
| 79 | 75 |
bool cancel_all(); |
| ... | ... | |
| 81 | 77 |
bool reap_pending_list_timeout(); |
| 82 | 78 |
bool reap_completed_list(); |
| 83 | 79 |
|
| 84 |
/* |
|
| 85 |
* Transfer state manipulators |
|
| 86 |
*/ |
|
| 80 |
// Transfer state manipulators |
|
| 87 | 81 |
void free_list_add(libusb_transfer *lut); |
| 88 | 82 |
void pending_list_add(libusb_transfer *lut); |
| 89 | 83 |
void completed_list_add(libusb_transfer *lut); |
| ... | ... | |
| 91 | 85 |
libusb_transfer *completed_list_get(); |
| 92 | 86 |
bool pending_list_remove(libusb_transfer *lut); |
| 93 | 87 |
|
| 94 |
/* |
|
| 95 |
* Misc |
|
| 96 |
*/ |
|
| 88 |
// Debug use |
|
| 97 | 89 |
void print_transfer_status(libusb_transfer *lut); |
| 98 | 90 |
|
| 99 | 91 |
public: |
| ... | ... | |
| 103 | 95 |
|
| 104 | 96 |
~usb_endpoint(); |
| 105 | 97 |
|
| 106 |
/* |
|
| 107 |
* Accessors |
|
| 108 |
*/ |
|
| 98 |
// Accessors |
|
| 109 | 99 |
int get_endpoint() const { return _endpoint; }
|
| 110 | 100 |
bool get_direction() const { return _input; }
|
| 111 | 101 |
libusb_device_handle *get_dev_handle() const { return _dev_handle; }
|
| 112 | 102 |
libusb_context *get_ctx() const { return _ctx; }
|
| 113 | 103 |
|
| 114 |
/* |
|
| 115 |
* Exposed interface for submitting / retrieving transfer buffers |
|
| 116 |
* used in zero-copy interface |
|
| 117 |
*/ |
|
| 104 |
// Exposed interface for submitting / retrieving transfer buffers |
|
| 118 | 105 |
bool submit(libusb_transfer *lut); |
| 119 | 106 |
libusb_transfer *get_completed_transfer(); |
| 120 | 107 |
libusb_transfer *get_free_transfer(); |
| 121 | 108 |
|
| 122 |
/* |
|
| 123 |
* Callback use only |
|
| 124 |
*/ |
|
| 109 |
//Callback use only |
|
| 125 | 110 |
void callback_handle_transfer(libusb_transfer *lut); |
| 126 | 111 |
}; |
| 127 | 112 |
|
| ... | ... | |
| 130 | 115 |
* Callback function called when submitted transfers complete. |
| 131 | 116 |
* The endpoint upon which the transfer is part of is recovered |
| 132 | 117 |
* and the transfer moved from pending to completed state. |
| 118 |
* Callbacks occur during the reaping calls where libusb_handle_events() |
|
| 119 |
* is used. The callback only modifies the transfer state by moving |
|
| 120 |
* it from the pending to completed status list. |
|
| 121 |
* \param lut pointer to libusb_transfer |
|
| 133 | 122 |
*/ |
| 134 | 123 |
static void callback(libusb_transfer *lut) |
| 135 | 124 |
{
|
| ... | ... | |
| 140 | 129 |
|
| 141 | 130 |
/* |
| 142 | 131 |
* Accessor call to allow list access from callback space |
| 132 |
* \param pointer to libusb_transfer |
|
| 143 | 133 |
*/ |
| 144 | 134 |
void usb_endpoint::callback_handle_transfer(libusb_transfer *lut) |
| 145 | 135 |
{
|
| ... | ... | |
| 154 | 144 |
|
| 155 | 145 |
/* |
| 156 | 146 |
* Constructor |
| 157 |
* |
|
| 158 |
* Allocate libusb transfers. For IN endpoints, submit the transfers
|
|
| 159 |
* so that they're ready to return when data is available.
|
|
| 147 |
* Allocate libusb transfers and mark as free. For IN endpoints,
|
|
| 148 |
* submit the transfers so that they're ready to return when
|
|
| 149 |
* data is available. |
|
| 160 | 150 |
*/ |
| 161 | 151 |
usb_endpoint::usb_endpoint(libusb_device_handle *dev_handle, |
| 162 | 152 |
libusb_context *ctx, int endpoint, bool input, |
| ... | ... | |
| 177 | 167 |
|
| 178 | 168 |
/* |
| 179 | 169 |
* Destructor |
| 170 |
* Make sure all the memory is freed. Cancel any pending transfers. |
|
| 171 |
* When all completed transfers are moved to the free list, release |
|
| 172 |
* the transfers. Libusb will deallocate the data buffer held by |
|
| 173 |
* each transfer. |
|
| 180 | 174 |
*/ |
| 181 | 175 |
usb_endpoint::~usb_endpoint() |
| 182 | 176 |
{
|
| ... | ... | |
| 200 | 194 |
|
| 201 | 195 |
/* |
| 202 | 196 |
* Allocate a libusb transfer |
| 203 |
* |
|
| 204 |
* The allocated transfer is continuously reused and should be freed at |
|
| 205 |
* shutdown. |
|
| 197 |
* The allocated transfer - and buffer it contains - is repeatedly |
|
| 198 |
* submitted, reaped, and reused and should not be freed until shutdown. |
|
| 199 |
* \param buff_len size of the individual buffer held by each transfer |
|
| 200 |
* \return pointer to an allocated libusb_transfer |
|
| 206 | 201 |
*/ |
| 207 | 202 |
libusb_transfer *usb_endpoint::allocate_transfer(int buff_len) |
| 208 | 203 |
{
|
| ... | ... | |
| 226 | 221 |
|
| 227 | 222 |
/* |
| 228 | 223 |
* Asynchonous transfer submission |
| 229 |
* |
|
| 230 |
* Submit and mark transfer as pending. |
|
| 224 |
* Submit a libusb transfer to libusb add pending status |
|
| 225 |
* \param lut pointer to libusb_transfer |
|
| 226 |
* \return true on success or false on error |
|
| 231 | 227 |
*/ |
| 232 | 228 |
bool usb_endpoint::submit(libusb_transfer *lut) |
| 233 | 229 |
{
|
| ... | ... | |
| 244 | 240 |
|
| 245 | 241 |
/* |
| 246 | 242 |
* Cancel a pending transfer |
| 247 |
* |
|
| 248 | 243 |
* Search the pending list for the transfer and cancel if found. |
| 249 |
* Returns true on success. False otherwise or on error. |
|
| 244 |
* \param lut pointer to libusb_transfer to cancel |
|
| 245 |
* \return true on success or false if transfer is not found |
|
| 250 | 246 |
* |
| 251 | 247 |
* Note: success only indicates submission of cancelation request. |
| 252 | 248 |
* Sucessful cancelation is not known until the callback occurs. |
| ... | ... | |
| 266 | 262 |
|
| 267 | 263 |
/* |
| 268 | 264 |
* Cancel all pending transfers |
| 265 |
* \return bool true if cancelation request is submitted |
|
| 269 | 266 |
* |
| 270 | 267 |
* Note: success only indicates submission of cancelation request. |
| 271 | 268 |
* Sucessful cancelation is not known until the callback occurs. |
| ... | ... | |
| 287 | 284 |
|
| 288 | 285 |
/* |
| 289 | 286 |
* Reap completed transfers |
| 290 |
* |
|
| 291 | 287 |
* return true if at least one transfer was reaped, false otherwise. |
| 292 |
* |
|
| 293 | 288 |
* Check completed transfers for errors and mark as free. This is a |
| 294 | 289 |
* blocking call. |
| 290 |
* \return bool true if a libusb transfer is reaped, false otherwise |
|
| 295 | 291 |
*/ |
| 296 | 292 |
bool usb_endpoint::reap_completed_list() |
| 297 | 293 |
{
|
| ... | ... | |
| 313 | 309 |
|
| 314 | 310 |
|
| 315 | 311 |
/* |
| 316 |
* Print completed transfer status error(s) |
|
| 317 |
* |
|
| 318 |
* return true if at least one transfer was reaped, false otherwise. |
|
| 319 |
* |
|
| 320 |
* Check completed transfers for errors and mark as free. This is a |
|
| 321 |
* blocking call. |
|
| 312 |
* Print status errors of a completed transfer |
|
| 313 |
* \param lut pointer to an libusb_transfer |
|
| 322 | 314 |
*/ |
| 323 | 315 |
void usb_endpoint::print_transfer_status(libusb_transfer *lut) |
| 324 | 316 |
{
|
| ... | ... | |
| 359 | 351 |
|
| 360 | 352 |
|
| 361 | 353 |
/* |
| 362 |
* Reap pending transfers |
|
| 363 |
* |
|
| 364 |
* Return true if at least one transfer was reaped, false otherwise. This is |
|
| 365 |
* a blocking call. |
|
| 366 |
* |
|
| 367 |
* Reaping submitted transfers is handled by libusb and the assigned callback |
|
| 368 |
* function. Block until at least one transfer is reaped. |
|
| 354 |
* Reap pending transfers without timeout |
|
| 355 |
* This is a blocking call. Reaping submitted transfers is |
|
| 356 |
* handled by libusb and the assigned callback function. |
|
| 357 |
* Block until at least one transfer is reaped. |
|
| 358 |
* \return true true if a transfer was reaped or false otherwise |
|
| 369 | 359 |
*/ |
| 370 | 360 |
bool usb_endpoint::reap_pending_list() |
| 371 | 361 |
{
|
| ... | ... | |
| 382 | 372 |
|
| 383 | 373 |
/* |
| 384 | 374 |
* Reap pending transfers with timeout |
| 385 |
* |
|
| 386 |
* Return true if at least one transfer was reaped, false otherwise. This call |
|
| 387 |
* blocks until a transfer is reaped or timeout. |
|
| 388 |
* |
|
| 389 |
* Reaping submitted transfers is handled by libusb and the assigned callback |
|
| 390 |
* function. Block until at least one transfer is reaped or timeout occurs. |
|
| 375 |
* This call blocks until a transfer is reaped or timeout. |
|
| 376 |
* Reaping submitted transfers is handled by libusb and the |
|
| 377 |
* assigned callback function. Block until at least one |
|
| 378 |
* transfer is reaped or timeout occurs. |
|
| 379 |
* \return true if a transfer was reaped or false otherwise |
|
| 391 | 380 |
*/ |
| 392 | 381 |
bool usb_endpoint::reap_pending_list_timeout() |
| 393 | 382 |
{
|
| ... | ... | |
| 414 | 403 |
|
| 415 | 404 |
|
| 416 | 405 |
/* |
| 417 |
* Returns a free transfer with empty data bufer for OUT requests |
|
| 406 |
* Get a free transfer |
|
| 407 |
* The transfer has an empty data bufer for OUT requests |
|
| 408 |
* \return pointer to a libusb_transfer |
|
| 418 | 409 |
*/ |
| 419 | 410 |
libusb_transfer *usb_endpoint::get_free_transfer() |
| 420 | 411 |
{
|
| ... | ... | |
| 428 | 419 |
|
| 429 | 420 |
|
| 430 | 421 |
/* |
| 431 |
* Returns a transfer containing data for IN requests |
|
| 422 |
* Get a completed transfer |
|
| 423 |
* The transfer has a full data buffer for IN requests |
|
| 424 |
* \return pointer to libusb_transfer |
|
| 432 | 425 |
*/ |
| 433 | 426 |
libusb_transfer *usb_endpoint::get_completed_transfer() |
| 434 | 427 |
{
|
| ... | ... | |
| 461 | 454 |
|
| 462 | 455 |
/* |
| 463 | 456 |
* Free and completed lists don't have ordered content |
| 464 |
* |
|
| 465 | 457 |
* Pop transfers from the front as needed |
| 466 | 458 |
*/ |
| 467 | 459 |
libusb_transfer *usb_endpoint::free_list_get() |
| ... | ... | |
| 481 | 473 |
|
| 482 | 474 |
/* |
| 483 | 475 |
* Free and completed lists don't have ordered content |
| 484 |
* |
|
| 485 | 476 |
* Pop transfers from the front as needed |
| 486 | 477 |
*/ |
| 487 | 478 |
libusb_transfer *usb_endpoint::completed_list_get() |
| ... | ... | |
| 501 | 492 |
|
| 502 | 493 |
/* |
| 503 | 494 |
* Search and remove transfer from pending list |
| 504 |
* |
|
| 505 | 495 |
* Assuming that the callbacks occur in order, the front element |
| 506 | 496 |
* should yield the correct transfer. If not, then something else |
| 507 | 497 |
* is going on. If no transfers match, then something went wrong. |
| ... | ... | |
| 522 | 512 |
/*********************************************************************** |
| 523 | 513 |
* Managed buffers |
| 524 | 514 |
**********************************************************************/ |
| 515 |
/* |
|
| 516 |
* Libusb managed receive buffer |
|
| 517 |
* Construct a recv buffer from a libusb transfer. The memory held by |
|
| 518 |
* the libusb transfer is exposed through the managed buffer interface. |
|
| 519 |
* Upon destruction, the transfer and buffer are resubmitted to the |
|
| 520 |
* endpoint for further use. |
|
| 521 |
*/ |
|
| 525 | 522 |
class libusb_managed_recv_buffer_impl : public managed_recv_buffer {
|
| 526 | 523 |
public: |
| 527 | 524 |
libusb_managed_recv_buffer_impl(libusb_transfer *lut, |
| ... | ... | |
| 549 | 546 |
const boost::asio::const_buffer _buff; |
| 550 | 547 |
}; |
| 551 | 548 |
|
| 552 |
|
|
| 549 |
/* |
|
| 550 |
* Libusb managed send buffer |
|
| 551 |
* Construct a send buffer from a libusb transfer. The memory held by |
|
| 552 |
* the libusb transfer is exposed through the managed buffer interface. |
|
| 553 |
* Committing the buffer will set the data length and submit the buffer |
|
| 554 |
* to the endpoint. Submitting a buffer multiple times or destroying |
|
| 555 |
* the buffer before committing is an error. For the latter, the transfer |
|
| 556 |
* is returned to the endpoint with no data for reuse. |
|
| 557 |
*/ |
|
| 553 | 558 |
class libusb_managed_send_buffer_impl : public managed_send_buffer {
|
| 554 | 559 |
public: |
| 555 | 560 |
libusb_managed_send_buffer_impl(libusb_transfer *lut, |
| ... | ... | |
| 613 | 618 |
usb_endpoint *_rx_ep; |
| 614 | 619 |
usb_endpoint *_tx_ep; |
| 615 | 620 |
|
| 616 |
/* |
|
| 617 |
* Libusb handles |
|
| 618 |
*/ |
|
| 621 |
// Maintain libusb values |
|
| 619 | 622 |
libusb_context *_rx_ctx; |
| 620 | 623 |
libusb_context *_tx_ctx; |
| 621 | 624 |
libusb_device_handle *_rx_dev_handle; |
| ... | ... | |
| 628 | 631 |
public: |
| 629 | 632 |
typedef boost::shared_ptr<libusb_zero_copy_impl> sptr; |
| 630 | 633 |
|
| 631 |
/* |
|
| 632 |
* Structors |
|
| 633 |
*/ |
|
| 634 | 634 |
libusb_zero_copy_impl(usb_device_handle::sptr handle, |
| 635 | 635 |
unsigned int rx_endpoint, |
| 636 | 636 |
unsigned int tx_endpoint, |
| ... | ... | |
| 646 | 646 |
size_t get_num_send_frames(void) const { return _num_frames; }
|
| 647 | 647 |
}; |
| 648 | 648 |
|
| 649 |
|
|
| 649 |
/* |
|
| 650 |
* Constructor |
|
| 651 |
* Initializes libusb, opens devices, and sets up interfaces for I/O. |
|
| 652 |
* Finally, creates endpoints for asynchronous I/O. |
|
| 653 |
*/ |
|
| 650 | 654 |
libusb_zero_copy_impl::libusb_zero_copy_impl(usb_device_handle::sptr handle, |
| 651 | 655 |
unsigned int rx_endpoint, |
| 652 | 656 |
unsigned int tx_endpoint, |
| ... | ... | |
| 656 | 660 |
_recv_buff_size(block_size), _send_buff_size(block_size), |
| 657 | 661 |
_num_frames(buff_size / block_size) |
| 658 | 662 |
{
|
| 663 |
// Initialize libusb with separate contexts to allow |
|
| 664 |
// thread safe operation of transmit and receive |
|
| 659 | 665 |
libusb::init(&_rx_ctx, libusb_debug_level); |
| 660 | 666 |
libusb::init(&_tx_ctx, libusb_debug_level); |
| 661 | 667 |
|
| 662 | 668 |
UHD_ASSERT_THROW((_rx_ctx != NULL) && (_tx_ctx != NULL)); |
| 663 | 669 |
|
| 670 |
// Find and open the libusb_device corresponding to the |
|
| 671 |
// given handle and return the libusb_device_handle |
|
| 672 |
// that can be used for I/O purposes. |
|
| 664 | 673 |
_rx_dev_handle = libusb::open_device(_rx_ctx, handle); |
| 665 | 674 |
_tx_dev_handle = libusb::open_device(_tx_ctx, handle); |
| 666 | 675 |
|
| 676 |
// Open USB interfaces for tx/rx using magic values. |
|
| 677 |
// IN interface: 2 |
|
| 678 |
// OUT interface: 1 |
|
| 679 |
// Control interface: 0 |
|
| 667 | 680 |
libusb::open_interface(_rx_dev_handle, 2); |
| 668 | 681 |
libusb::open_interface(_tx_dev_handle, 1); |
| 669 | 682 |
|
| 670 |
_rx_ep = new usb_endpoint(_rx_dev_handle, |
|
| 671 |
_rx_ctx, |
|
| 672 |
rx_endpoint, |
|
| 673 |
true, |
|
| 674 |
_recv_buff_size, |
|
| 675 |
_num_frames); |
|
| 676 |
|
|
| 677 |
_tx_ep = new usb_endpoint(_tx_dev_handle, |
|
| 678 |
_tx_ctx, |
|
| 679 |
tx_endpoint, |
|
| 680 |
false, |
|
| 681 |
_send_buff_size, |
|
| 682 |
_num_frames); |
|
| 683 |
_rx_ep = new usb_endpoint(_rx_dev_handle, // libusb device_handle
|
|
| 684 |
_rx_ctx, // libusb context
|
|
| 685 |
rx_endpoint, // USB endpoint number
|
|
| 686 |
true, // IN endpoint
|
|
| 687 |
_recv_buff_size, // buffer size per transfer
|
|
| 688 |
_num_frames); // number of libusb transfers
|
|
| 689 |
|
|
| 690 |
_tx_ep = new usb_endpoint(_tx_dev_handle, // libusb device_handle
|
|
| 691 |
_tx_ctx, // libusb context
|
|
| 692 |
tx_endpoint, // USB endpoint number
|
|
| 693 |
false, // OUT endpoint
|
|
| 694 |
_send_buff_size, // buffer size per transfer
|
|
| 695 |
_num_frames); // number of libusb transfers
|
|
| 683 | 696 |
} |
| 684 | 697 |
|
| 685 | 698 |
|
| ... | ... | |
| 696 | 709 |
} |
| 697 | 710 |
|
| 698 | 711 |
|
| 712 |
/* |
|
| 713 |
* Construct a managed receive buffer from a completed libusb transfer |
|
| 714 |
* (happy with buffer full of data) obtained from the receive endpoint. |
|
| 715 |
* Return empty pointer if no transfer is available (timeout or error). |
|
| 716 |
* \return pointer to a managed receive buffer |
|
| 717 |
*/ |
|
| 699 | 718 |
managed_recv_buffer::sptr libusb_zero_copy_impl::get_recv_buff() |
| 700 | 719 |
{
|
| 701 | 720 |
libusb_transfer *lut = _rx_ep->get_completed_transfer(); |
| ... | ... | |
| 710 | 729 |
} |
| 711 | 730 |
|
| 712 | 731 |
|
| 732 |
/* |
|
| 733 |
* Construct a managed send buffer from a free libusb transfer (with |
|
| 734 |
* empty buffer). Return empty pointer of no transfer is available |
|
| 735 |
* (timeout or error). |
|
| 736 |
* \return pointer to a managed send buffer |
|
| 737 |
*/ |
|
| 713 | 738 |
managed_send_buffer::sptr libusb_zero_copy_impl::get_send_buff() |
| 714 | 739 |
{
|
| 715 | 740 |
libusb_transfer *lut = _tx_ep->get_free_transfer(); |
Also available in: Unified diff