Merged features/inband -r4812:5218 into trunk. This group of changes
[debian/gnuradio] / usrp / host / lib / fusb_linux.cc
diff --git a/usrp/host/lib/fusb_linux.cc b/usrp/host/lib/fusb_linux.cc
deleted file mode 100644 (file)
index 1eaba4e..0000000
+++ /dev/null
@@ -1,686 +0,0 @@
-/* -*- c++ -*- */
-/*
- * Copyright 2003 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_linux.h>
-#include <usb.h>               // libusb header
-#include <stdexcept>
-#ifdef HAVE_LINUX_COMPILER_H
-#include <linux/compiler.h>
-#endif
-#include <linux/usbdevice_fs.h>        // interface to kernel portion of user mode usb driver
-#include <sys/ioctl.h>
-#include <assert.h>
-#include <string.h>
-#include <algorithm>
-#include <errno.h>
-#include <string.h>
-
-#define MINIMIZE_TX_BUFFERING 1                // must be defined to 0 or 1
-
-
-static const int MAX_BLOCK_SIZE = fusb_sysconfig::max_block_size();            // hard limit
-static const int DEFAULT_BLOCK_SIZE = MAX_BLOCK_SIZE;
-static const int DEFAULT_BUFFER_SIZE = 4 * (1L << 20);                         // 4 MB / endpoint
-
-
-// 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);
-}
-
-inline static void
-urb_set_ephandle (usbdevfs_urb *urb, fusb_ephandle_linux *handle)
-{
-  urb->usercontext = handle;
-}
-
-inline static fusb_ephandle_linux *
-urb_get_ephandle (usbdevfs_urb *urb)
-{
-  return (fusb_ephandle_linux *) urb->usercontext;
-}
-
-// ------------------------------------------------------------------------
-//                USB request block (urb) allocation
-// ------------------------------------------------------------------------
-
-static usbdevfs_urb *
-alloc_urb (fusb_ephandle_linux *self, int buffer_length, int endpoint,
-          bool input_p, unsigned char *write_buffer)
-{
-  usbdevfs_urb *urb = new usbdevfs_urb;
-  memset (urb, 0, sizeof (*urb));
-
-  urb->buffer_length = buffer_length;
-
-  // We allocate dedicated memory only for input buffers.
-  // For output buffers we reuse the same buffer (the kernel 
-  // copies the data at submital time)
-
-  if (input_p)
-    urb->buffer = new unsigned char [buffer_length];
-  else
-    urb->buffer = write_buffer;
-
-  // init common values
-
-  urb->type = USBDEVFS_URB_TYPE_BULK;
-  urb->endpoint = (endpoint & 0x7f) | (input_p ? 0x80 : 0);
-
-  // USBDEVFS_URB_QUEUE_BULK goes away in linux 2.5, but is needed if
-  // we are using a 2.4 usb-uhci host controller driver.  This is
-  // unlikely since we're almost always going to be plugged into a
-  // high speed host controller (ehci)
-#if 0 && defined (USBDEVFS_URB_QUEUE_BULK)
-  urb->flags = USBDEVFS_URB_QUEUE_BULK;
-#endif
-
-  urb->signr = 0;
-  urb_set_ephandle (urb, self);
-
-  return urb;
-}
-
-static void
-free_urb (usbdevfs_urb *urb)
-{
-  // if this was an input urb, free the buffer
-  if (urb->endpoint & 0x80)
-    delete [] ((unsigned char *) urb->buffer);
-
-  delete urb;
-}
-
-// ------------------------------------------------------------------------
-//                             device handle
-// ------------------------------------------------------------------------
-
-fusb_devhandle_linux::fusb_devhandle_linux (usb_dev_handle *udh)
-  : fusb_devhandle (udh)
-{
-  // that's all
-}
-
-fusb_devhandle_linux::~fusb_devhandle_linux ()
-{
-  // if there are any pending requests, cancel them and free the urbs.
-  
-  std::list<usbdevfs_urb*>::reverse_iterator it;
-
-  for (it = d_pending_rqsts.rbegin (); it != d_pending_rqsts.rend (); it++){
-    _cancel_urb (*it);
-    free_urb (*it);
-  }
-}
-
-fusb_ephandle *
-fusb_devhandle_linux::make_ephandle (int endpoint, bool input_p,
-                                    int block_size, int nblocks)
-{
-  return new fusb_ephandle_linux (this, endpoint, input_p,
-                                 block_size, nblocks);
-}
-
-
-// Attempt to cancel all transactions associated with eph.
-
-void
-fusb_devhandle_linux::_cancel_pending_rqsts (fusb_ephandle_linux *eph)
-{
-  std::list<usbdevfs_urb*>::reverse_iterator it;
-
-  for (it = d_pending_rqsts.rbegin (); it != d_pending_rqsts.rend (); it++){
-    if (urb_get_ephandle (*it) == eph)
-      _cancel_urb (*it);
-  }
-}
-
-void 
-fusb_devhandle_linux::pending_add (usbdevfs_urb *urb)
-{
-  d_pending_rqsts.push_back (urb);
-}
-
-usbdevfs_urb *
-fusb_devhandle_linux::pending_get ()
-{
-  if (d_pending_rqsts.empty ())
-    return 0;
-
-  usbdevfs_urb *urb = d_pending_rqsts.front ();
-  d_pending_rqsts.pop_front ();
-  return urb;
-}
-
-bool
-fusb_devhandle_linux::pending_remove (usbdevfs_urb *urb)
-{
-  std::list<usbdevfs_urb*>::iterator   result = find (d_pending_rqsts.begin (),
-                                                      d_pending_rqsts.end (),
-                                                      urb);
-  if (result == d_pending_rqsts.end ()){
-    fprintf (stderr, "fusb::pending_remove: failed to find urb in pending_rqsts: %p\n", urb);
-    return false;
-  }
-  d_pending_rqsts.erase (result);
-  return true;
-}
-
-/*
- * Submit the urb to the kernel.
- * iff successful, the urb will be placed on the devhandle's pending list.
- */
-bool
-fusb_devhandle_linux::_submit_urb (usbdevfs_urb *urb)
-{
-  int  ret;
-
-  ret = ioctl (fd_from_usb_dev_handle (d_udh), USBDEVFS_SUBMITURB, urb);
-  if (ret < 0){
-    perror ("fusb::_submit_urb");
-    return false;
-  }
-  
-  pending_add (urb);
-  return true;
-}
-
-/*
- * Attempt to cancel the in pending or in-progress urb transaction.
- * Return true iff transaction was sucessfully cancelled.
- *
- * Failure to cancel should not be considered a problem.  This frequently
- * occurs if the transaction has already completed in the kernel but hasn't
- * yet been reaped by the user mode code.
- *
- * urbs which were cancelled have their status field set to -ENOENT when
- * they are reaped.
- */
-bool
-fusb_devhandle_linux::_cancel_urb (usbdevfs_urb *urb)
-{
-  int ret = ioctl (fd_from_usb_dev_handle (d_udh), USBDEVFS_DISCARDURB, urb);
-  if (ret < 0){
-    // perror ("fusb::_cancel_urb");
-    return false;
-  }
-  return true;
-}
-
-/*
- * Check with the kernel and see if any of our outstanding requests
- * have completed.  For each completed transaction, remove it from the
- * devhandle's pending list and append it to the completed list for
- * the corresponding endpoint.
- *
- * If any transactions are reaped return true.
- *
- * If ok_to_block_p is true, then this will block until at least one
- * transaction completes.
- */
-bool
-fusb_devhandle_linux::_reap (bool ok_to_block_p)
-{
-  int          ret;
-  int          nreaped = 0;
-  usbdevfs_urb *urb = 0;
-
-  int  fd = fd_from_usb_dev_handle (d_udh);
-  
-  // try to reap as many as possible without blocking...
-
-  while ((ret = ioctl (fd, USBDEVFS_REAPURBNDELAY, &urb)) == 0){
-    if (urb->status != 0 && urb->status != -ENOENT){
-      fprintf (stderr, "_reap: usb->status = %d, actual_length = %5d\n",
-              urb->status, urb->actual_length);
-    }
-    pending_remove (urb);
-    urb_get_ephandle (urb)->completed_list_add (urb);
-    nreaped++;
-  }
-
-  if (nreaped > 0)             // if we got any, return w/o blocking
-    return true;
-
-  if (!ok_to_block_p)
-    return false;
-  
-  ret = ioctl (fd, USBDEVFS_REAPURB, &urb);
-  if (ret < 0){
-    perror ("fusb::_reap");
-    return false;
-  }
-
-  pending_remove (urb);
-  urb_get_ephandle (urb)->completed_list_add (urb);
-  return true;
-}
-
-void
-fusb_devhandle_linux::_wait_for_completion ()
-{
-  while (!d_pending_rqsts.empty ())
-    _reap (true);
-}
-\f// ------------------------------------------------------------------------
-//                          end point handle
-// ------------------------------------------------------------------------
-
-fusb_ephandle_linux::fusb_ephandle_linux (fusb_devhandle_linux *devhandle,
-                                         int endpoint,
-                                         bool input_p,
-                                         int block_size, int nblocks)
-  : fusb_ephandle (endpoint, input_p, block_size, nblocks),
-    d_devhandle (devhandle), 
-    d_write_work_in_progress (0), d_write_buffer (0),
-    d_read_work_in_progress (0), d_read_buffer (0), d_read_buffer_end (0)
-{
-
-  if (d_block_size < 0 || d_block_size > MAX_BLOCK_SIZE)
-    throw std::out_of_range ("fusb_ephandle_linux: block_size");
-
-  if (d_nblocks < 0)
-    throw std::out_of_range ("fusb_ephandle_linux: nblocks");
-
-  if (d_block_size == 0)
-    d_block_size = DEFAULT_BLOCK_SIZE;
-
-  if (d_nblocks == 0)
-    d_nblocks = std::max (1, DEFAULT_BUFFER_SIZE / d_block_size);
-
-  if (!d_input_p)
-    if (!MINIMIZE_TX_BUFFERING)
-      d_write_buffer = new unsigned char [d_block_size];
-
-  if (0)
-    fprintf(stderr, "fusb_ephandle_linux::ctor: d_block_size = %d  d_nblocks = %d\n",
-           d_block_size, d_nblocks);
-
-  // allocate urbs
-
-  for (int i = 0; i < d_nblocks; i++)
-    d_free_list.push_back (alloc_urb (this, d_block_size, d_endpoint,
-                                     d_input_p, d_write_buffer));
-}
-
-fusb_ephandle_linux::~fusb_ephandle_linux ()
-{
-  stop ();
-
-  usbdevfs_urb *urb;
-
-  while ((urb = free_list_get ()) != 0)
-    free_urb (urb);
-
-  while ((urb = completed_list_get ()) != 0)
-    free_urb (urb);
-
-  if (d_write_work_in_progress)
-    free_urb (d_write_work_in_progress);
-
-  delete [] d_write_buffer;
-
-  if (d_read_work_in_progress)
-    free_urb (d_read_work_in_progress);
-}
-
-// ----------------------------------------------------------------
-
-bool
-fusb_ephandle_linux::start ()
-{
-  if (d_started)
-    return true;               // already running
-
-  d_started = true;
-
-  if (d_input_p){              // fire off all the reads
-    usbdevfs_urb *urb;
-
-    int nerrors = 0;
-    while ((urb = free_list_get ()) != 0 && nerrors < d_nblocks){
-      if (!submit_urb (urb))
-       nerrors++;
-    }
-  }
-
-  return true;
-}
-
-//
-// kill all i/o in progress.
-// kill any completed but unprocessed transactions.
-//
-bool
-fusb_ephandle_linux::stop ()
-{
-  if (!d_started)
-    return true;
-  
-  d_devhandle->_cancel_pending_rqsts (this);
-  d_devhandle->_reap (false);
-
-
-  usbdevfs_urb *urb;
-  while ((urb = completed_list_get ()) != 0)
-    free_list_add (urb);
-
-  if (d_write_work_in_progress){
-    free_list_add (d_write_work_in_progress);
-    d_write_work_in_progress = 0;
-  }
-
-  if (d_read_work_in_progress){
-    free_list_add (d_read_work_in_progress);
-    d_read_work_in_progress = 0;
-    d_read_buffer = 0;
-    d_read_buffer_end = 0;
-  }
-
-  if (d_free_list.size () != (unsigned) d_nblocks)
-    fprintf (stderr, "d_free_list.size () = %d, d_nblocks = %d\n",
-            d_free_list.size (), d_nblocks);
-    
-  assert (d_free_list.size () == (unsigned) d_nblocks);
-
-  d_started = false;
-  return true;
-}
-
-// ----------------------------------------------------------------
-//                     routines for writing 
-// ----------------------------------------------------------------
-
-#if (MINIMIZE_TX_BUFFERING)
-
-int 
-fusb_ephandle_linux::write(const void *buffer, int nbytes)
-{
-  if (!d_started)
-    return -1;
-  
-  if (d_input_p)
-    return -1;
-
-  assert(nbytes % 512 == 0);
-
-  unsigned char *src = (unsigned char *) buffer;
-
-  int n = 0;
-  while (n < nbytes){
-
-    usbdevfs_urb *urb = get_write_work_in_progress();
-    assert(urb->actual_length == 0);
-    int m = std::min(nbytes - n, MAX_BLOCK_SIZE);
-    urb->buffer = src;
-    urb->buffer_length = m;
-
-    n += m;
-    src += m;
-
-    if (!submit_urb(urb))
-      return -1;
-
-    d_write_work_in_progress = 0;
-  }
-
-  return n;
-}
-
-#else
-
-int 
-fusb_ephandle_linux::write (const void *buffer, int nbytes)
-{
-  if (!d_started)
-    return -1;
-  
-  if (d_input_p)
-    return -1;
-
-  unsigned char *src = (unsigned char *) buffer;
-
-  int n = 0;
-  while (n < nbytes){
-
-    usbdevfs_urb *urb = get_write_work_in_progress ();
-    unsigned char *dst = (unsigned char *) urb->buffer;
-    int m = std::min (nbytes - n, urb->buffer_length - urb->actual_length);
-
-    memcpy (&dst[urb->actual_length], &src[n], m);
-    urb->actual_length += m;
-    n += m;
-
-    if (urb->actual_length == urb->buffer_length){
-      if (!submit_urb (urb))
-       return -1;
-      d_write_work_in_progress = 0;
-    }
-  }
-
-  return n;
-}
-
-#endif
-
-usbdevfs_urb *
-fusb_ephandle_linux::get_write_work_in_progress ()
-{
-  // if we've already got some work in progress, return it
-
-  if (d_write_work_in_progress)
-    return d_write_work_in_progress;
-
-  while (1){
-
-    reap_complete_writes ();
-
-    usbdevfs_urb *urb = free_list_get ();
-
-    if (urb != 0){
-      assert (urb->actual_length == 0);
-      d_write_work_in_progress = urb;
-      return urb;
-    }
-
-    // The free list is empty.  Tell the device handle to reap.
-    // Anything it reaps for us will end up on our completed list.
-
-    d_devhandle->_reap (true);
-  }
-}
-
-void
-fusb_ephandle_linux::reap_complete_writes ()
-{
-  // take a look at the completed_list and xfer to free list after
-  // checking for errors.
-
-  usbdevfs_urb *urb;
-  
-  while ((urb = completed_list_get ()) != 0){
-
-    // Check for any errors or short writes that were reported in the urb.
-    // The kernel sets status, actual_length and error_count.
-    // error_count is only used for ISO xfers.
-    // status is 0 if successful, else is an errno kind of thing
-
-    if (urb->status != 0){
-      fprintf (stderr, "fusb: (status %d) %s\n", urb->status, strerror (-urb->status));
-    }
-    else if (urb->actual_length != urb->buffer_length){
-      fprintf (stderr, "fusb: short write xfer: %d != %d\n",
-              urb->actual_length, urb->buffer_length);
-    }
-
-    free_list_add (urb);
-  }
-}
-
-void
-fusb_ephandle_linux::wait_for_completion ()
-{
-  d_devhandle->_wait_for_completion ();
-}
-
-// ----------------------------------------------------------------
-//                    routines for reading
-// ----------------------------------------------------------------
-
-int
-fusb_ephandle_linux::read (void *buffer, int nbytes)
-{
-  if (!d_started)
-    return -1;
-  
-  if (!d_input_p)
-    return -1;
-
-  unsigned char *dst = (unsigned char *) buffer;
-
-  int n = 0;
-  while (n < nbytes){
-
-    if (d_read_buffer >= d_read_buffer_end)
-      if (!reload_read_buffer ())
-       return -1;
-
-    int m = std::min (nbytes - n, (int) (d_read_buffer_end - d_read_buffer));
-
-    memcpy (&dst[n], d_read_buffer, m);
-    d_read_buffer += m;
-    n += m;
-  }
-
-  return n;
-}
-
-bool
-fusb_ephandle_linux::reload_read_buffer ()
-{
-  assert (d_read_buffer >= d_read_buffer_end);
-
-  usbdevfs_urb *urb;
-
-  if (d_read_work_in_progress){
-    // We're done with this urb.  Fire off a read to refill it.
-    urb = d_read_work_in_progress;
-    d_read_work_in_progress = 0;
-    d_read_buffer = 0;
-    d_read_buffer_end = 0;
-    urb->actual_length = 0;
-    if (!submit_urb (urb))
-      return false;
-  }
-
-  while (1){
-
-    while ((urb = completed_list_get ()) == 0)
-      d_devhandle->_reap (true);
-
-    // check result of completed read
-
-    if (urb->status != 0){
-      // We've got a problem.
-      // Report the problem and resubmit.
-      fprintf (stderr, "fusb: (rd status %d) %s\n", urb->status, strerror (-urb->status));
-      urb->actual_length = 0;
-      if (!submit_urb (urb))
-       return false;
-
-      continue;
-    }
-
-    // we've got a happy urb, full of data...
-
-    d_read_work_in_progress = urb;
-    d_read_buffer = (unsigned char *) urb->buffer;
-    d_read_buffer_end = d_read_buffer + urb->actual_length;
-
-    return true;
-  }
-}
-
-// ----------------------------------------------------------------
-
-void
-fusb_ephandle_linux::free_list_add (usbdevfs_urb *urb)
-{
-  assert (urb_get_ephandle (urb) == this);
-  urb->actual_length = 0;
-  d_free_list.push_back (urb);
-}
-
-usbdevfs_urb *
-fusb_ephandle_linux::free_list_get ()
-{
-  if (d_free_list.empty ())
-    return 0;
-
-  usbdevfs_urb *urb = d_free_list.front ();
-  d_free_list.pop_front ();
-  return urb;
-}
-
-void
-fusb_ephandle_linux::completed_list_add (usbdevfs_urb *urb)
-{
-  assert (urb_get_ephandle (urb) == this);
-  d_completed_list.push_back (urb);
-}
-
-usbdevfs_urb *
-fusb_ephandle_linux::completed_list_get ()
-{
-  if (d_completed_list.empty ())
-    return 0;
-
-  usbdevfs_urb *urb = d_completed_list.front ();
-  d_completed_list.pop_front ();
-  return urb;
-}
-
-/*
- * Submit the urb.  If successful the urb ends up on the devhandle's
- * pending list, otherwise, it's back on our free list.
- */
-bool
-fusb_ephandle_linux::submit_urb (usbdevfs_urb *urb)
-{
-  if (!d_devhandle->_submit_urb (urb)){    // FIXME record the problem somewhere
-    fprintf (stderr, "_submit_urb failed\n");
-    free_list_add (urb);
-    return false;
-  }
-  return true;
-}