diff options
Diffstat (limited to 'usrp/host/lib')
-rw-r--r-- | usrp/host/lib/Makefile.am | 11 | ||||
-rw-r--r-- | usrp/host/lib/fusb.h | 5 | ||||
-rw-r--r-- | usrp/host/lib/fusb_ra_wb.cc | 258 | ||||
-rw-r--r-- | usrp/host/lib/fusb_ra_wb.h | 84 | ||||
-rw-r--r-- | usrp/host/lib/fusb_sysconfig_darwin.cc | 7 | ||||
-rw-r--r-- | usrp/host/lib/fusb_sysconfig_generic.cc | 6 | ||||
-rw-r--r-- | usrp/host/lib/fusb_sysconfig_linux.cc | 6 | ||||
-rw-r--r-- | usrp/host/lib/fusb_sysconfig_ra_wb.cc | 47 | ||||
-rw-r--r-- | usrp/host/lib/fusb_sysconfig_win32.cc | 6 | ||||
-rw-r--r-- | usrp/host/lib/usrp_basic.cc | 3 |
10 files changed, 430 insertions, 3 deletions
diff --git a/usrp/host/lib/Makefile.am b/usrp/host/lib/Makefile.am index c34827c43..f7dad8463 100644 --- a/usrp/host/lib/Makefile.am +++ b/usrp/host/lib/Makefile.am @@ -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 diff --git a/usrp/host/lib/fusb.h b/usrp/host/lib/fusb.h index 2c0cb3ffd..da1b7c0ad 100644 --- a/usrp/host/lib/fusb.h +++ b/usrp/host/lib/fusb.h @@ -123,6 +123,11 @@ public: */ static int max_block_size (); + /*! + * \brief returns the default buffer size + */ + static int default_buffer_size (); + }; #endif /* _FUSB_H_ */ diff --git a/usrp/host/lib/fusb_ra_wb.cc b/usrp/host/lib/fusb_ra_wb.cc new file mode 100644 index 000000000..c95f4afbe --- /dev/null +++ b/usrp/host/lib/fusb_ra_wb.cc @@ -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); + } +} diff --git a/usrp/host/lib/fusb_ra_wb.h b/usrp/host/lib/fusb_ra_wb.h new file mode 100644 index 000000000..09bf8ee65 --- /dev/null +++ b/usrp/host/lib/fusb_ra_wb.h @@ -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_ */ + diff --git a/usrp/host/lib/fusb_sysconfig_darwin.cc b/usrp/host/lib/fusb_sysconfig_darwin.cc index 4ea7ef8bd..f66c298db 100644 --- a/usrp/host/lib/fusb_sysconfig_darwin.cc +++ b/usrp/host/lib/fusb_sysconfig_darwin.cc @@ -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; +} + diff --git a/usrp/host/lib/fusb_sysconfig_generic.cc b/usrp/host/lib/fusb_sysconfig_generic.cc index fb50910c6..d336cb946 100644 --- a/usrp/host/lib/fusb_sysconfig_generic.cc +++ b/usrp/host/lib/fusb_sysconfig_generic.cc @@ -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; +} diff --git a/usrp/host/lib/fusb_sysconfig_linux.cc b/usrp/host/lib/fusb_sysconfig_linux.cc index 85cbf3f30..468fa9f82 100644 --- a/usrp/host/lib/fusb_sysconfig_linux.cc +++ b/usrp/host/lib/fusb_sysconfig_linux.cc @@ -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; +} diff --git a/usrp/host/lib/fusb_sysconfig_ra_wb.cc b/usrp/host/lib/fusb_sysconfig_ra_wb.cc new file mode 100644 index 000000000..68eecedc5 --- /dev/null +++ b/usrp/host/lib/fusb_sysconfig_ra_wb.cc @@ -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; +} diff --git a/usrp/host/lib/fusb_sysconfig_win32.cc b/usrp/host/lib/fusb_sysconfig_win32.cc index b1f2447c4..282e77ac4 100644 --- a/usrp/host/lib/fusb_sysconfig_win32.cc +++ b/usrp/host/lib/fusb_sysconfig_win32.cc @@ -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; +} diff --git a/usrp/host/lib/usrp_basic.cc b/usrp/host/lib/usrp_basic.cc index baecb666f..2eef14727 100644 --- a/usrp/host/lib/usrp_basic.cc +++ b/usrp/host/lib/usrp_basic.cc @@ -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; |