diff options
| -rw-r--r-- | host/lib/transport/libusb1_zero_copy.cpp | 183 | 
1 files changed, 104 insertions, 79 deletions
| diff --git a/host/lib/transport/libusb1_zero_copy.cpp b/host/lib/transport/libusb1_zero_copy.cpp index 4469991b8..edbeb5673 100644 --- a/host/lib/transport/libusb1_zero_copy.cpp +++ b/host/lib/transport/libusb1_zero_copy.cpp @@ -64,16 +64,12 @@ private:      size_t _transfer_size;      size_t _num_transfers; -    /* -     * Transfer state lists (free, pending, or completed) -     */ +    // Transfer state lists (transfers are free, pending, or completed)      std::list<libusb_transfer *>  _free_list;      std::list<libusb_transfer *>  _pending_list;      std::list<libusb_transfer *>  _completed_list; -    /* -     * Calls for processing asynchronous I/O  -     */ +    // Calls for processing asynchronous I/O       libusb_transfer *allocate_transfer(int buff_len);      bool cancel(libusb_transfer *lut);      bool cancel_all(); @@ -81,9 +77,7 @@ private:      bool reap_pending_list_timeout();      bool reap_completed_list(); -    /* -     * Transfer state manipulators  -     */ +    // Transfer state manipulators       void free_list_add(libusb_transfer *lut);      void pending_list_add(libusb_transfer *lut);      void completed_list_add(libusb_transfer *lut); @@ -91,9 +85,7 @@ private:      libusb_transfer *completed_list_get();      bool pending_list_remove(libusb_transfer *lut); -    /* -     * Misc -     */ +    // Debug use      void print_transfer_status(libusb_transfer *lut);  public: @@ -103,25 +95,18 @@ public:      ~usb_endpoint(); -    /* -     * Accessors  -     */ +    // Accessors       int get_endpoint() const { return _endpoint; }      bool get_direction() const { return _input; }      libusb_device_handle *get_dev_handle() const { return _dev_handle; }      libusb_context *get_ctx() const { return _ctx; } -    /* -     * Exposed interface for submitting / retrieving transfer buffers -     * used in zero-copy interface -     */ +    // Exposed interface for submitting / retrieving transfer buffers      bool submit(libusb_transfer *lut);      libusb_transfer *get_completed_transfer();      libusb_transfer *get_free_transfer(); -    /* -     * Callback use only -     */ +    //Callback use only      void callback_handle_transfer(libusb_transfer *lut);  }; @@ -130,6 +115,10 @@ public:   * Callback function called when submitted transfers complete.   * The endpoint upon which the transfer is part of is recovered   * and the transfer moved from pending to completed state. + * Callbacks occur during the reaping calls where libusb_handle_events() + * is used. The callback only modifies the transfer state by moving + * it from the pending to completed status list. + * \param lut pointer to libusb_transfer   */  static void callback(libusb_transfer *lut)  { @@ -140,6 +129,7 @@ static void callback(libusb_transfer *lut)  /*   * Accessor call to allow list access from callback space + * \param pointer to libusb_transfer   */  void usb_endpoint::callback_handle_transfer(libusb_transfer *lut)  { @@ -154,9 +144,9 @@ void usb_endpoint::callback_handle_transfer(libusb_transfer *lut)  /*   * Constructor - * - * Allocate libusb transfers. For IN endpoints, submit the transfers - * so that they're ready to return when data is available.  + * Allocate libusb transfers and mark as free.  For IN endpoints, + * submit the transfers so that they're ready to return when + * data is available.    */  usb_endpoint::usb_endpoint(libusb_device_handle *dev_handle,                            libusb_context *ctx, int endpoint, bool input, @@ -177,6 +167,10 @@ usb_endpoint::usb_endpoint(libusb_device_handle *dev_handle,  /*   * Destructor + * Make sure all the memory is freed. Cancel any pending transfers. + * When all completed transfers are moved to the free list, release + * the transfers. Libusb will deallocate the data buffer held by + * each transfer.   */  usb_endpoint::~usb_endpoint()  { @@ -200,9 +194,10 @@ usb_endpoint::~usb_endpoint()  /*   * Allocate a libusb transfer  - * - * The allocated transfer is continuously reused and should be freed at - * shutdown. + * The allocated transfer - and buffer it contains - is repeatedly + * submitted, reaped, and reused and should not be freed until shutdown. + * \param buff_len size of the individual buffer held by each transfer + * \return pointer to an allocated libusb_transfer   */  libusb_transfer *usb_endpoint::allocate_transfer(int buff_len)  { @@ -226,8 +221,9 @@ libusb_transfer *usb_endpoint::allocate_transfer(int buff_len)  /*   * Asynchonous transfer submission - * - * Submit and mark transfer as pending. + * Submit a libusb transfer to libusb add pending status + * \param lut pointer to libusb_transfer + * \return true on success or false on error    */  bool usb_endpoint::submit(libusb_transfer *lut)  { @@ -244,9 +240,9 @@ bool usb_endpoint::submit(libusb_transfer *lut)  /*   * Cancel a pending transfer  - *   * Search the pending list for the transfer and cancel if found. - * Returns true on success. False otherwise or on error.  + * \param lut pointer to libusb_transfer to cancel + * \return true on success or false if transfer is not found   *   * Note: success only indicates submission of cancelation request.   * Sucessful cancelation is not known until the callback occurs. @@ -266,6 +262,7 @@ bool usb_endpoint::cancel(libusb_transfer *lut)  /*   * Cancel all pending transfers  + * \return bool true if cancelation request is submitted   *   * Note: success only indicates submission of cancelation request.   * Sucessful cancelation is not known until the callback occurs. @@ -287,11 +284,10 @@ bool usb_endpoint::cancel_all()  /*   * Reap completed transfers - *    * return true if at least one transfer was reaped, false otherwise.  - *   * Check completed transfers for errors and mark as free. This is a   * blocking call.  + * \return bool true if a libusb transfer is reaped, false otherwise   */  bool usb_endpoint::reap_completed_list()  { @@ -313,12 +309,8 @@ bool usb_endpoint::reap_completed_list()  /* - * Print completed transfer status error(s)  - *  - * return true if at least one transfer was reaped, false otherwise.  - * - * Check completed transfers for errors and mark as free. This is a - * blocking call.  + * Print status errors of a completed transfer + * \param lut pointer to an libusb_transfer   */  void usb_endpoint::print_transfer_status(libusb_transfer *lut)  { @@ -359,13 +351,11 @@ void usb_endpoint::print_transfer_status(libusb_transfer *lut)  /* - * Reap pending transfers  - * - * Return true if at least one transfer was reaped, false otherwise. This is - * a blocking call. - * - * Reaping submitted transfers is handled by libusb and the assigned callback - * function. Block until at least one transfer is reaped. + * Reap pending transfers without timeout  + * This is a blocking call. Reaping submitted transfers is + * handled by libusb and the assigned callback function. + * Block until at least one transfer is reaped. + * \return true true if a transfer was reaped or false otherwise   */  bool usb_endpoint::reap_pending_list()  { @@ -382,12 +372,11 @@ bool usb_endpoint::reap_pending_list()  /*   * Reap pending transfers with timeout  - * - * Return true if at least one transfer was reaped, false otherwise. This call - * blocks until a transfer is reaped or timeout. - * - * Reaping submitted transfers is handled by libusb and the assigned callback - * function. Block until at least one transfer is reaped or timeout occurs. + * This call blocks until a transfer is reaped or timeout. + * Reaping submitted transfers is handled by libusb and the + * assigned callback function. Block until at least one + * transfer is reaped or timeout occurs. + * \return true if a transfer was reaped or false otherwise   */  bool usb_endpoint::reap_pending_list_timeout()  { @@ -414,7 +403,9 @@ bool usb_endpoint::reap_pending_list_timeout()  /* - * Returns a free transfer with empty data bufer for OUT requests  + * Get a free transfer + * The transfer has an empty data bufer for OUT requests  + * \return pointer to a libusb_transfer   */  libusb_transfer *usb_endpoint::get_free_transfer()  { @@ -428,7 +419,9 @@ libusb_transfer *usb_endpoint::get_free_transfer()  /* - * Returns a transfer containing data for IN requests + * Get a completed transfer  + * The transfer has a full data buffer for IN requests + * \return pointer to libusb_transfer   */  libusb_transfer *usb_endpoint::get_completed_transfer()  { @@ -461,7 +454,6 @@ void usb_endpoint::completed_list_add(libusb_transfer *lut)  /*   * Free and completed lists don't have ordered content  - *   * Pop transfers from the front as needed   */  libusb_transfer *usb_endpoint::free_list_get() @@ -481,7 +473,6 @@ libusb_transfer *usb_endpoint::free_list_get()  /*   * Free and completed lists don't have ordered content  - *   * Pop transfers from the front as needed   */  libusb_transfer *usb_endpoint::completed_list_get() @@ -501,7 +492,6 @@ libusb_transfer *usb_endpoint::completed_list_get()  /*   * Search and remove transfer from pending list - *   * Assuming that the callbacks occur in order, the front element   * should yield the correct transfer. If not, then something else   * is going on. If no transfers match, then something went wrong. @@ -522,6 +512,13 @@ bool usb_endpoint::pending_list_remove(libusb_transfer *lut)  /***********************************************************************   * Managed buffers    **********************************************************************/ +/* + * Libusb managed receive buffer + * Construct a recv buffer from a libusb transfer. The memory held by + * the libusb transfer is exposed through the managed buffer interface. + * Upon destruction, the transfer and buffer are resubmitted to the + * endpoint for further use.  + */  class libusb_managed_recv_buffer_impl : public managed_recv_buffer {  public:      libusb_managed_recv_buffer_impl(libusb_transfer *lut, @@ -549,7 +546,15 @@ private:      const boost::asio::const_buffer _buff;  }; - +/* + * Libusb managed send buffer + * Construct a send buffer from a libusb transfer. The memory held by + * the libusb transfer is exposed through the managed buffer interface. + * Committing the buffer will set the data length and submit the buffer + * to the endpoint. Submitting a buffer multiple times or destroying + * the buffer before committing is an error. For the latter, the transfer + * is returned to the endpoint with no data for reuse. + */  class libusb_managed_send_buffer_impl : public managed_send_buffer {  public:      libusb_managed_send_buffer_impl(libusb_transfer *lut, @@ -613,9 +618,7 @@ private:      usb_endpoint          *_rx_ep;      usb_endpoint          *_tx_ep; -    /* -     * Libusb handles -     */ +    // Maintain libusb values      libusb_context       *_rx_ctx;      libusb_context       *_tx_ctx;      libusb_device_handle *_rx_dev_handle; @@ -628,9 +631,6 @@ private:  public:      typedef boost::shared_ptr<libusb_zero_copy_impl> sptr; -    /* -     * Structors -     */      libusb_zero_copy_impl(usb_device_handle::sptr handle,                            unsigned int rx_endpoint,                            unsigned int tx_endpoint, @@ -646,7 +646,11 @@ public:      size_t get_num_send_frames(void) const { return _num_frames; }  }; - +/* + * Constructor + * Initializes libusb, opens devices, and sets up interfaces for I/O. + * Finally, creates endpoints for asynchronous I/O.  + */  libusb_zero_copy_impl::libusb_zero_copy_impl(usb_device_handle::sptr handle,                                               unsigned int rx_endpoint,                                               unsigned int tx_endpoint, @@ -656,30 +660,39 @@ libusb_zero_copy_impl::libusb_zero_copy_impl(usb_device_handle::sptr handle,     _recv_buff_size(block_size), _send_buff_size(block_size),     _num_frames(buff_size / block_size)  { +    // Initialize libusb with separate contexts to allow +    // thread safe operation of transmit and receive       libusb::init(&_rx_ctx, libusb_debug_level);      libusb::init(&_tx_ctx, libusb_debug_level);      UHD_ASSERT_THROW((_rx_ctx != NULL) && (_tx_ctx != NULL)); +    // Find and open the libusb_device corresponding to the +    // given handle and return the libusb_device_handle +    // that can be used for I/O purposes.      _rx_dev_handle = libusb::open_device(_rx_ctx, handle);      _tx_dev_handle = libusb::open_device(_tx_ctx, handle); +    // Open USB interfaces for tx/rx using magic values. +    // IN interface:      2 +    // OUT interface:     1 +    // Control interface: 0      libusb::open_interface(_rx_dev_handle, 2);      libusb::open_interface(_tx_dev_handle, 1); -    _rx_ep = new usb_endpoint(_rx_dev_handle, -                              _rx_ctx, -                              rx_endpoint, -                              true, -                              _recv_buff_size, -                              _num_frames);  - -    _tx_ep = new usb_endpoint(_tx_dev_handle, -                              _tx_ctx, -                              tx_endpoint, -                              false, -                              _send_buff_size, -                              _num_frames); +    _rx_ep = new usb_endpoint(_rx_dev_handle,  // libusb device_handle +                              _rx_ctx,         // libusb context +                              rx_endpoint,     // USB endpoint number +                              true,            // IN endpoint +                              _recv_buff_size, // buffer size per transfer  +                              _num_frames);    // number of libusb transfers + +    _tx_ep = new usb_endpoint(_tx_dev_handle,  // libusb device_handle +                              _tx_ctx,         // libusb context +                              tx_endpoint,     // USB endpoint number +                              false,           // OUT endpoint +                              _send_buff_size, // buffer size per transfer +                              _num_frames);    // number of libusb transfers  } @@ -696,6 +709,12 @@ libusb_zero_copy_impl::~libusb_zero_copy_impl()  } +/* + * Construct a managed receive buffer from a completed libusb transfer + * (happy with buffer full of data) obtained from the receive endpoint. + * Return empty pointer if no transfer is available (timeout or error). + * \return pointer to a managed receive buffer  + */  managed_recv_buffer::sptr libusb_zero_copy_impl::get_recv_buff()  {      libusb_transfer *lut = _rx_ep->get_completed_transfer(); @@ -710,6 +729,12 @@ managed_recv_buffer::sptr libusb_zero_copy_impl::get_recv_buff()  } +/* + * Construct a managed send buffer from a free libusb transfer (with + * empty buffer). Return empty pointer of no transfer is available + * (timeout or error). + * \return pointer to a managed send buffer  + */  managed_send_buffer::sptr libusb_zero_copy_impl::get_send_buff()  {      libusb_transfer *lut = _tx_ep->get_free_transfer(); | 
