diff options
Diffstat (limited to 'host/lib')
-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(); |