aboutsummaryrefslogtreecommitdiffstats
path: root/host/lib/transport/libusb1_zero_copy.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'host/lib/transport/libusb1_zero_copy.cpp')
-rw-r--r--host/lib/transport/libusb1_zero_copy.cpp183
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();