mirror of https://gerrit.osmocom.org/libusrp
Merged -r3596:3600 of eb/ra_wb into trunk. This contains the
BSD read-ahead/write-behind fast usb support. git-svn-id: http://gnuradio.org/svn/gnuradio/trunk@3601 221aa14e-8319-0410-a670-987f0aec2ac5
This commit is contained in:
parent
7a0001d24a
commit
e57ba270ce
|
@ -64,6 +64,10 @@ linux_CODE = \
|
|||
fusb_linux.cc \
|
||||
fusb_sysconfig_linux.cc
|
||||
|
||||
ra_wb_CODE = \
|
||||
fusb_ra_wb.cc \
|
||||
fusb_sysconfig_ra_wb.cc
|
||||
|
||||
|
||||
#
|
||||
# include each <foo>_CODE entry here...
|
||||
|
@ -72,7 +76,8 @@ EXTRA_libusrp_la_SOURCES = \
|
|||
$(generic_CODE) \
|
||||
$(darwin_CODE) \
|
||||
$(win32_CODE) \
|
||||
$(linux_CODE)
|
||||
$(linux_CODE) \
|
||||
$(ra_wb_CODE)
|
||||
|
||||
|
||||
# work around automake deficiency
|
||||
|
@ -103,6 +108,10 @@ if FUSB_TECH_linux
|
|||
libusrp_la_SOURCES = $(libusrp_la_common_SOURCES) $(linux_CODE)
|
||||
endif
|
||||
|
||||
if FUSB_TECH_ra_wb
|
||||
libusrp_la_SOURCES = $(libusrp_la_common_SOURCES) $(ra_wb_CODE)
|
||||
endif
|
||||
|
||||
|
||||
libusrp_la_LDFLAGS = $(NO_UNDEFINED) -version-info 0:0:0
|
||||
libusrp_la_LIBADD = $(USB_LIBS) ../misc/libmisc.la
|
||||
|
|
|
@ -123,6 +123,11 @@ public:
|
|||
*/
|
||||
static int max_block_size ();
|
||||
|
||||
/*!
|
||||
* \brief returns the default buffer size
|
||||
*/
|
||||
static int default_buffer_size ();
|
||||
|
||||
};
|
||||
|
||||
#endif /* _FUSB_H_ */
|
||||
|
|
|
@ -0,0 +1,258 @@
|
|||
/* -*- c++ -*- */
|
||||
/*
|
||||
* Copyright 2003,2006 Free Software Foundation, Inc.
|
||||
*
|
||||
* This file is part of GNU Radio
|
||||
*
|
||||
* GNU Radio is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* GNU Radio is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with GNU Radio; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <fusb_ra_wb.h>
|
||||
#include <usb.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <sys/event.h>
|
||||
#include <dev/usb/usb.h>
|
||||
|
||||
static const int USB_TIMEOUT = 1000; // in milliseconds
|
||||
|
||||
// the following comment and function is from fusb_linux.cc
|
||||
#if 0
|
||||
// Totally evil and fragile extraction of file descriptor from
|
||||
// guts of libusb. They don't install usbi.h, which is what we'd need
|
||||
// to do this nicely.
|
||||
//
|
||||
// FIXME if everything breaks someday in the future, look here...
|
||||
|
||||
static int
|
||||
fd_from_usb_dev_handle (usb_dev_handle *udh)
|
||||
{
|
||||
return *((int *) udh);
|
||||
}
|
||||
#endif
|
||||
|
||||
// the control endpoint doesn't actually do us any good so here is a
|
||||
// new "fragile extraction"
|
||||
static int
|
||||
ep_fd_from_usb_dev_handle (usb_dev_handle *udh, int endpoint)
|
||||
{
|
||||
struct usb_dev_handle_kludge2 { // see also usrp_prims.cc
|
||||
int fd;
|
||||
struct usb_bus *bus;
|
||||
struct usb_device *device;
|
||||
int config;
|
||||
int interface;
|
||||
int altsetting;
|
||||
void *impl_info;
|
||||
};
|
||||
struct bsd_usb_dev_handle_info_kludge {
|
||||
int ep_fd[USB_MAX_ENDPOINTS];
|
||||
};
|
||||
struct bsd_usb_dev_handle_info_kludge *info
|
||||
= (struct bsd_usb_dev_handle_info_kludge *)
|
||||
((struct usb_dev_handle_kludge2 *)udh)->impl_info;
|
||||
return info->ep_fd[UE_GET_ADDR(endpoint)];
|
||||
}
|
||||
|
||||
|
||||
fusb_devhandle_ra_wb::fusb_devhandle_ra_wb (usb_dev_handle *udh)
|
||||
: fusb_devhandle (udh)
|
||||
{
|
||||
// that's it
|
||||
}
|
||||
|
||||
fusb_devhandle_ra_wb::~fusb_devhandle_ra_wb ()
|
||||
{
|
||||
// nop
|
||||
}
|
||||
|
||||
fusb_ephandle *
|
||||
fusb_devhandle_ra_wb::make_ephandle (int endpoint, bool input_p,
|
||||
int block_size, int nblocks)
|
||||
{
|
||||
return new fusb_ephandle_ra_wb (this, endpoint, input_p,
|
||||
block_size, nblocks);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
|
||||
fusb_ephandle_ra_wb::fusb_ephandle_ra_wb (fusb_devhandle_ra_wb *dh,
|
||||
int endpoint, bool input_p,
|
||||
int block_size, int nblocks)
|
||||
: fusb_ephandle (endpoint, input_p, block_size, nblocks),
|
||||
d_devhandle (dh), d_ra_wb_on (false)
|
||||
{
|
||||
// that's it
|
||||
}
|
||||
|
||||
fusb_ephandle_ra_wb::~fusb_ephandle_ra_wb ()
|
||||
{
|
||||
// nop
|
||||
}
|
||||
|
||||
bool
|
||||
fusb_ephandle_ra_wb::start ()
|
||||
{
|
||||
d_started = true;
|
||||
|
||||
char buf = '\0';
|
||||
int fd;
|
||||
|
||||
// this is to cause libusb to open the endpoint
|
||||
if (!d_input_p) {
|
||||
write(&buf, 0);
|
||||
fd = ep_fd_from_usb_dev_handle (d_devhandle->get_usb_dev_handle(),
|
||||
d_endpoint);
|
||||
}
|
||||
else {
|
||||
read(&buf, 0);
|
||||
fd = ep_fd_from_usb_dev_handle (d_devhandle->get_usb_dev_handle(),
|
||||
d_endpoint|USB_ENDPOINT_IN);
|
||||
}
|
||||
|
||||
// enable read ahead/write behind
|
||||
int ret;
|
||||
struct usb_bulk_ra_wb_opt opts;
|
||||
int enable = 1;
|
||||
|
||||
opts.ra_wb_buffer_size = d_block_size*d_nblocks;
|
||||
opts.ra_wb_request_size = d_block_size;
|
||||
// fprintf (stderr, "setting buffer size to %d, request size to %d\n",
|
||||
// opts.ra_wb_buffer_size, opts.ra_wb_request_size);
|
||||
if (!d_input_p) {
|
||||
ret = ioctl (fd, USB_SET_BULK_WB_OPT, &opts);
|
||||
if (ret < 0)
|
||||
fprintf (stderr, "USB_SET_BULK_WB_OPT: %s\n", strerror(errno));
|
||||
else {
|
||||
ret = ioctl (fd, USB_SET_BULK_WB, &enable);
|
||||
if (ret < 0)
|
||||
fprintf (stderr, "USB_SET_BULK_WB: %s\n", strerror(errno));
|
||||
else
|
||||
d_ra_wb_on = true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
ret = ioctl (fd, USB_SET_BULK_RA_OPT, &opts);
|
||||
if (ret < 0)
|
||||
fprintf (stderr, "USB_SET_BULK_RA_OPT: %s\n", strerror(errno));
|
||||
else {
|
||||
ret = ioctl (fd, USB_SET_BULK_RA, &enable);
|
||||
if (ret < 0)
|
||||
fprintf (stderr, "USB_SET_BULK_RA: %s\n", strerror(errno));
|
||||
else
|
||||
d_ra_wb_on = true;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
fusb_ephandle_ra_wb::stop ()
|
||||
{
|
||||
int fd;
|
||||
int ret;
|
||||
int enable = 0;
|
||||
if (d_ra_wb_on) {
|
||||
if (!d_input_p) {
|
||||
fd = ep_fd_from_usb_dev_handle (d_devhandle->get_usb_dev_handle(),
|
||||
d_endpoint);
|
||||
ret = ioctl (fd, USB_SET_BULK_WB, &enable);
|
||||
if (ret < 0)
|
||||
fprintf (stderr, "USB_SET_BULK_WB: %s\n", strerror(errno));
|
||||
else
|
||||
d_ra_wb_on = false;
|
||||
}
|
||||
else {
|
||||
fd = ep_fd_from_usb_dev_handle (d_devhandle->get_usb_dev_handle(),
|
||||
d_endpoint|USB_ENDPOINT_IN);
|
||||
ret = ioctl (fd, USB_SET_BULK_RA, &enable);
|
||||
if (ret < 0)
|
||||
fprintf (stderr, "USB_SET_BULK_RA: %s\n", strerror(errno));
|
||||
else
|
||||
d_ra_wb_on = false;
|
||||
}
|
||||
}
|
||||
|
||||
d_started = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
int
|
||||
fusb_ephandle_ra_wb::write (const void *buffer, int nbytes)
|
||||
{
|
||||
if (!d_started)
|
||||
return -1;
|
||||
|
||||
if (d_input_p)
|
||||
return -1;
|
||||
|
||||
return usb_bulk_write (d_devhandle->get_usb_dev_handle (),
|
||||
d_endpoint, (char *) buffer, nbytes, USB_TIMEOUT);
|
||||
}
|
||||
|
||||
int
|
||||
fusb_ephandle_ra_wb::read (void *buffer, int nbytes)
|
||||
{
|
||||
if (!d_started)
|
||||
return -1;
|
||||
|
||||
if (!d_input_p)
|
||||
return -1;
|
||||
|
||||
return usb_bulk_read (d_devhandle->get_usb_dev_handle (),
|
||||
d_endpoint|USB_ENDPOINT_IN, (char *) buffer, nbytes,
|
||||
USB_TIMEOUT);
|
||||
}
|
||||
|
||||
void
|
||||
fusb_ephandle_ra_wb::wait_for_completion ()
|
||||
{
|
||||
// as the driver is implemented this only makes sense for write
|
||||
if (d_ra_wb_on && !d_input_p) {
|
||||
int fd = ep_fd_from_usb_dev_handle (d_devhandle->get_usb_dev_handle(),
|
||||
d_endpoint);
|
||||
int kq = kqueue();
|
||||
if (kq < 0)
|
||||
return;
|
||||
struct kevent evt;
|
||||
int nevents;
|
||||
EV_SET (&evt, fd, EVFILT_WRITE, EV_ADD | EV_ENABLE, 0, 0, 0/*NULL*/);
|
||||
nevents = kevent (kq, &evt, 1, &evt, 1, NULL);
|
||||
if (nevents < 1) {
|
||||
close(kq);
|
||||
return;
|
||||
}
|
||||
while (!(evt.flags & EV_ERROR) && evt.data < (d_block_size*d_nblocks)) {
|
||||
// it's a busy loop, but that's all I can do at the moment
|
||||
nevents = kevent (kq, NULL, 0, &evt, 1, NULL);
|
||||
// let's see if this improves the test_usrp_standard_tx throughput &
|
||||
// "CPU usage" by looping less frequently
|
||||
struct timeval timeout;
|
||||
timeout.tv_sec = 0;
|
||||
timeout.tv_usec = 1000; // 1 ms
|
||||
select (0, NULL, NULL, NULL, &timeout);
|
||||
}
|
||||
close (kq);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,84 @@
|
|||
/* -*- c++ -*- */
|
||||
/*
|
||||
* Copyright 2003,2006 Free Software Foundation, Inc.
|
||||
*
|
||||
* This file is part of GNU Radio
|
||||
*
|
||||
* GNU Radio is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* GNU Radio is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with GNU Radio; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef _FUSB_RA_WB_H_
|
||||
#define _FUSB_RA_WB_H_
|
||||
|
||||
#include <fusb.h>
|
||||
|
||||
/*!
|
||||
* \brief generic implementation of fusb_devhandle using only libusb
|
||||
*/
|
||||
class fusb_devhandle_ra_wb : public fusb_devhandle
|
||||
{
|
||||
public:
|
||||
// CREATORS
|
||||
fusb_devhandle_ra_wb (usb_dev_handle *udh);
|
||||
virtual ~fusb_devhandle_ra_wb ();
|
||||
|
||||
// MANIPULATORS
|
||||
virtual fusb_ephandle *make_ephandle (int endpoint, bool input_p,
|
||||
int block_size = 0, int nblocks = 0);
|
||||
};
|
||||
|
||||
|
||||
/*!
|
||||
* \brief generic implementation of fusb_ephandle using only libusb
|
||||
*/
|
||||
class fusb_ephandle_ra_wb : public fusb_ephandle
|
||||
{
|
||||
private:
|
||||
fusb_devhandle_ra_wb *d_devhandle;
|
||||
bool d_ra_wb_on;
|
||||
|
||||
public:
|
||||
// CREATORS
|
||||
fusb_ephandle_ra_wb (fusb_devhandle_ra_wb *dh, int endpoint, bool input_p,
|
||||
int block_size = 0, int nblocks = 0);
|
||||
virtual ~fusb_ephandle_ra_wb ();
|
||||
|
||||
// MANIPULATORS
|
||||
|
||||
virtual bool start (); //!< begin streaming i/o
|
||||
virtual bool stop (); //!< stop streaming i/o
|
||||
|
||||
/*!
|
||||
* \returns \p nbytes if write was successfully enqueued, else -1.
|
||||
* Will block if no free buffers available.
|
||||
*/
|
||||
virtual int write (const void *buffer, int nbytes);
|
||||
|
||||
/*!
|
||||
* \returns number of bytes read or -1 if error.
|
||||
* number of bytes read will be <= nbytes.
|
||||
* Will block if no input available.
|
||||
*/
|
||||
virtual int read (void *buffer, int nbytes);
|
||||
|
||||
/*
|
||||
* block until all outstanding writes have completed
|
||||
*/
|
||||
virtual void wait_for_completion ();
|
||||
};
|
||||
|
||||
#endif /* _FUSB_RA_WB_H_ */
|
||||
|
|
@ -24,6 +24,7 @@
|
|||
#include <fusb_darwin.h>
|
||||
|
||||
static const int MAX_BLOCK_SIZE = 32 * 1024; // hard limit
|
||||
static const int FUSB_BUFFER_SIZE = 2 * (1L << 20); // 2 MB (was 8 MB)
|
||||
|
||||
fusb_devhandle *
|
||||
fusb_sysconfig::make_devhandle (usb_dev_handle *udh)
|
||||
|
@ -35,3 +36,9 @@ int fusb_sysconfig::max_block_size ()
|
|||
{
|
||||
return MAX_BLOCK_SIZE;
|
||||
}
|
||||
|
||||
int fusb_sysconfig::default_buffer_size ()
|
||||
{
|
||||
return FUSB_BUFFER_SIZE;
|
||||
}
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include <fusb_generic.h>
|
||||
|
||||
static const int MAX_BLOCK_SIZE = 16 * 1024; // hard limit
|
||||
static const int FUSB_BUFFER_SIZE = 2 * (1L << 20); // 2 MB (was 8 MB)
|
||||
|
||||
fusb_devhandle *
|
||||
fusb_sysconfig::make_devhandle (usb_dev_handle *udh)
|
||||
|
@ -35,3 +36,8 @@ int fusb_sysconfig::max_block_size ()
|
|||
{
|
||||
return MAX_BLOCK_SIZE;
|
||||
}
|
||||
|
||||
int fusb_sysconfig::default_buffer_size ()
|
||||
{
|
||||
return FUSB_BUFFER_SIZE;
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include <fusb_linux.h>
|
||||
|
||||
static const int MAX_BLOCK_SIZE = 16 * 1024; // hard limit
|
||||
static const int FUSB_BUFFER_SIZE = 2 * (1L << 20); // 2 MB (was 8 MB)
|
||||
|
||||
fusb_devhandle *
|
||||
fusb_sysconfig::make_devhandle (usb_dev_handle *udh)
|
||||
|
@ -35,3 +36,8 @@ int fusb_sysconfig::max_block_size ()
|
|||
{
|
||||
return MAX_BLOCK_SIZE;
|
||||
}
|
||||
|
||||
int fusb_sysconfig::default_buffer_size ()
|
||||
{
|
||||
return FUSB_BUFFER_SIZE;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
/* -*- c++ -*- */
|
||||
/*
|
||||
* Copyright 2003,2006 Free Software Foundation, Inc.
|
||||
*
|
||||
* This file is part of GNU Radio
|
||||
*
|
||||
* GNU Radio is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* GNU Radio is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with GNU Radio; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include <fusb.h>
|
||||
#include <fusb_ra_wb.h>
|
||||
|
||||
//static const int MAX_BLOCK_SIZE = 16 * 1024; // hard limit
|
||||
// there's no hard limit, even before making any changes to the driver
|
||||
// 64k is empirically a pretty good number
|
||||
static const int MAX_BLOCK_SIZE = 64 * 1024;
|
||||
// there is a limit of 1 MB in the driver for the buffer size
|
||||
static const int FUSB_BUFFER_SIZE = 256 * (1L << 10); // 256 kB
|
||||
|
||||
fusb_devhandle *
|
||||
fusb_sysconfig::make_devhandle (usb_dev_handle *udh)
|
||||
{
|
||||
return new fusb_devhandle_ra_wb (udh);
|
||||
}
|
||||
|
||||
int fusb_sysconfig::max_block_size ()
|
||||
{
|
||||
return MAX_BLOCK_SIZE;
|
||||
}
|
||||
|
||||
int fusb_sysconfig::default_buffer_size ()
|
||||
{
|
||||
return FUSB_BUFFER_SIZE;
|
||||
}
|
|
@ -24,6 +24,7 @@
|
|||
#include <fusb_win32.h>
|
||||
|
||||
static const int MAX_BLOCK_SIZE = 64 * 1024; // Windows kernel hard limit
|
||||
static const int FUSB_BUFFER_SIZE = 2 * (1L << 20); // 2 MB (was 8 MB)
|
||||
|
||||
fusb_devhandle *
|
||||
fusb_sysconfig::make_devhandle (usb_dev_handle *udh)
|
||||
|
@ -35,3 +36,8 @@ int fusb_sysconfig::max_block_size ()
|
|||
{
|
||||
return MAX_BLOCK_SIZE;
|
||||
}
|
||||
|
||||
int fusb_sysconfig::default_buffer_size ()
|
||||
{
|
||||
return FUSB_BUFFER_SIZE;
|
||||
}
|
||||
|
|
|
@ -42,8 +42,7 @@ using namespace ad9862;
|
|||
// These set the buffer size used for each end point using the fast
|
||||
// usb interface. The kernel ends up locking down this much memory.
|
||||
|
||||
static const int FUSB_BUFFER_SIZE = 2 * (1L << 20); // 2 MB (was 8 MB)
|
||||
//static const int FUSB_BUFFER_SIZE = 256 * (1L << 10); // 256 kB
|
||||
static const int FUSB_BUFFER_SIZE = fusb_sysconfig::default_buffer_size();
|
||||
static const int FUSB_BLOCK_SIZE = fusb_sysconfig::max_block_size();
|
||||
static const int FUSB_NBLOCKS = FUSB_BUFFER_SIZE / FUSB_BLOCK_SIZE;
|
||||
|
||||
|
|
Loading…
Reference in New Issue