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.cpp91
1 files changed, 55 insertions, 36 deletions
diff --git a/host/lib/transport/libusb1_zero_copy.cpp b/host/lib/transport/libusb1_zero_copy.cpp
index 3e67264cd..3532dc4aa 100644
--- a/host/lib/transport/libusb1_zero_copy.cpp
+++ b/host/lib/transport/libusb1_zero_copy.cpp
@@ -1,5 +1,5 @@
//
-// Copyright 2010-2011 Ettus Research LLC
+// Copyright 2010-2013 Ettus Research LLC
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@@ -21,6 +21,7 @@
#include <uhd/utils/msg.hpp>
#include <uhd/exception.hpp>
#include <boost/foreach.hpp>
+#include <boost/make_shared.hpp>
#include <boost/thread/thread.hpp>
#include <list>
@@ -35,6 +36,12 @@ static const size_t DEFAULT_XFER_SIZE = 32*512; //bytes
#define LIBUSB_CALL
#endif /*LIBUSB_CALL*/
+//! libusb_handle_events_timeout_completed is only in newer API
+#ifndef HAVE_LIBUSB_HANDLE_EVENTS_TIMEOUT_COMPLETED
+ #define libusb_handle_events_timeout_completed(ctx, tx, completed)\
+ libusb_handle_events_timeout(ctx, tx)
+#endif
+
/*!
* All libusb callback functions should be marked with the LIBUSB_CALL macro
* to ensure that they are compiled with the same calling convention as libusb.
@@ -42,7 +49,8 @@ static const size_t DEFAULT_XFER_SIZE = 32*512; //bytes
//! helper function: handles all async callbacks
static void LIBUSB_CALL libusb_async_cb(libusb_transfer *lut){
- *(static_cast<bool *>(lut->user_data)) = true;
+ int *completed = (int *)lut->user_data;
+ *completed = 1;
}
/*!
@@ -60,14 +68,24 @@ static void LIBUSB_CALL libusb_async_cb(libusb_transfer *lut){
* \param completed a reference to the completed flag
* \return true for completion, false for timeout
*/
-UHD_INLINE bool wait_for_completion(libusb_context *ctx, const double timeout, bool &completed){
+UHD_INLINE bool wait_for_completion(libusb_context *ctx, const double timeout, int &completed){
+ //already completed by a previous call?
+ if (completed) return true;
+
+ //perform a non-blocking event handle
+ timeval tv;
+ tv.tv_sec = 0;
+ tv.tv_usec = 0;
+ libusb_handle_events_timeout_completed(ctx, &tv, &completed);
+ if (completed) return true;
+
+ //finish the rest with a timeout loop
const boost::system_time timeout_time = boost::get_system_time() + boost::posix_time::microseconds(long(timeout*1000000));
-
while (not completed and (boost::get_system_time() < timeout_time)){
timeval tv;
tv.tv_sec = 0;
tv.tv_usec = 10000; /*10ms*/
- libusb_handle_events_timeout(ctx, &tv);
+ libusb_handle_events_timeout_completed(ctx, &tv, &completed);
}
return completed;
@@ -82,34 +100,27 @@ class libusb_zero_copy_mrb : public managed_recv_buffer{
public:
libusb_zero_copy_mrb(libusb_transfer *lut, const size_t frame_size):
_ctx(libusb::session::get_global_session()->get_context()),
- _lut(lut), _expired(false), _frame_size(frame_size) { /* NOP */ }
+ _lut(lut), _frame_size(frame_size) { /* NOP */ }
void release(void){
- if (_expired) return;
- completed = false;
+ completed = 0;
_lut->length = _frame_size; //always reset length
UHD_ASSERT_THROW(libusb_submit_transfer(_lut) == 0);
- _expired = true;
}
sptr get_new(const double timeout, size_t &index){
if (wait_for_completion(_ctx, timeout, completed)){
index++;
- _expired = false;
- return make_managed_buffer(this);
+ return make(this, _lut->buffer, _lut->actual_length);
}
return managed_recv_buffer::sptr();
}
- bool completed;
+ int completed;
private:
- const void *get_buff(void) const{return _lut->buffer;}
- size_t get_size(void) const{return _lut->actual_length;}
-
libusb_context *_ctx;
libusb_transfer *_lut;
- bool _expired;
const size_t _frame_size;
};
@@ -122,35 +133,27 @@ class libusb_zero_copy_msb : public managed_send_buffer{
public:
libusb_zero_copy_msb(libusb_transfer *lut, const size_t frame_size):
_ctx(libusb::session::get_global_session()->get_context()),
- _lut(lut), _expired(false), _frame_size(frame_size) { /* NOP */ }
-
- void commit(size_t len){
- if (_expired) return;
- completed = false;
- _lut->length = len;
- if (len == 0) libusb_async_cb(_lut);
- else UHD_ASSERT_THROW(libusb_submit_transfer(_lut) == 0);
- _expired = true;
+ _lut(lut), _frame_size(frame_size) { completed = true; }
+
+ void release(void){
+ completed = 0;
+ _lut->length = size();
+ UHD_ASSERT_THROW(libusb_submit_transfer(_lut) == 0);
}
sptr get_new(const double timeout, size_t &index){
if (wait_for_completion(_ctx, timeout, completed)){
index++;
- _expired = false;
- return make_managed_buffer(this);
+ return make(this, _lut->buffer, _frame_size);
}
return managed_send_buffer::sptr();
}
- bool completed;
+ int completed;
private:
- void *get_buff(void) const{return _lut->buffer;}
- size_t get_size(void) const{return _frame_size;}
-
libusb_context *_ctx;
libusb_transfer *_lut;
- bool _expired;
const size_t _frame_size;
};
@@ -181,13 +184,30 @@ public:
_handle->claim_interface(recv_interface);
_handle->claim_interface(send_interface);
+ //flush the buffers out of the recv endpoint
+ //limit the flushing to at most one second
+ for (size_t i = 0; i < 100; i++)
+ {
+ unsigned char buff[512];
+ int transfered = 0;
+ const int status = libusb_bulk_transfer(
+ _handle->get(), // dev_handle
+ (recv_endpoint & 0x7f) | 0x80, // endpoint
+ static_cast<unsigned char *>(buff),
+ sizeof(buff),
+ &transfered, //bytes xfered
+ 10 //timeout ms
+ );
+ if (status == LIBUSB_ERROR_TIMEOUT) break;
+ }
+
//allocate libusb transfer structs and managed receive buffers
for (size_t i = 0; i < get_num_recv_frames(); i++){
libusb_transfer *lut = libusb_alloc_transfer(0);
UHD_ASSERT_THROW(lut != NULL);
- _mrb_pool.push_back(boost::shared_ptr<libusb_zero_copy_mrb>(new libusb_zero_copy_mrb(lut, this->get_recv_frame_size())));
+ _mrb_pool.push_back(boost::make_shared<libusb_zero_copy_mrb>(lut, this->get_recv_frame_size()));
libusb_fill_bulk_transfer(
lut, // transfer
@@ -210,7 +230,7 @@ public:
libusb_transfer *lut = libusb_alloc_transfer(0);
UHD_ASSERT_THROW(lut != NULL);
- _msb_pool.push_back(boost::shared_ptr<libusb_zero_copy_msb>(new libusb_zero_copy_msb(lut, this->get_send_frame_size())));
+ _msb_pool.push_back(boost::make_shared<libusb_zero_copy_msb>(lut, this->get_send_frame_size()));
libusb_fill_bulk_transfer(
lut, // transfer
@@ -224,7 +244,6 @@ public:
);
_all_luts.push_back(lut);
- _msb_pool.back()->commit(0);
}
}
@@ -237,7 +256,7 @@ public:
}
//process all transfers until timeout occurs
- bool completed = false;
+ int completed = 0;
wait_for_completion(ctx, 0.01, completed);
//free all transfers