USB reset fails when using a LimeSDR Mini on FreeBSD

Jan Behrens jbe-mlist at magnetkern.de
Sun Jun 28 09:28:12 UTC 2020


On Sat, 27 Jun 2020 17:36:04 +0200
Jan Behrens <jbe-mlist at magnetkern.de> wrote:

> On Sat, 27 Jun 2020 16:12:45 +0200
> Tomasz CEDRO <tomek at cedro.info> wrote:
> 
> > I guess the FreeBSD's LibUSB implementation should be one-to-one
> > compatible with the GNU LibUSB.

Unless GNU LibUSB behaves wrong, in which case there'd be a good reason
for FreeBSD's LibUSB to behave differently. But not sure if that's the
case.


> > I would try to test and compare it
> > with Linux and MacOS implementation and see the difference:
> > 
> > 1. If the problem exists on FreeBSD, Linux, MacOS. If so/no then if
> > there are different error messages / codes. If there are more verbose
> > codes / messages on systems other than BSD then FreeBSD's
> > implementation may need an update. However, the difference here seems
> > to be the USB stack itself.

As I currently have no Linux installed on my machines, I tested with a
friend how the SoapySDR module for the LimeSDR Mini (SoapyLMS7 from
Lime Suite 20.01.0) behaves on Linux in regard to the
libusb_reset_device() call. This is our result:

We modified  LimeSuite-20.01.0/src/ConnectionFTDI/ConnectionFT601.cpp
in the following way:

At the begin of the file:
#include <unistd.h>
#include <sys/types.h>

And then below:
    fprintf(stderr, "DEBUG: Executing libusb_reset_device() [UID=%i, effective UID=%i]\n", getuid(), geteuid());
    if (libusb_reset_device(dev_handle)!=0)
        return ReportError(-1, "USB reset failed", libusb_strerror(libusb_error(r)));
    fprintf(stderr, "DEBUG: libusb_reset_device() executed successfully.\n");

This resulted in the following output:
$ SoapySDRUtil --make
######################################################
##     Soapy SDR -- the SDR abstraction library     ##
######################################################

Make device 
linux; GNU C++ version 7.3.0; Boost_106501; UHD_003.010.003.000-0-unknown

[INFO] Make connection: 'LimeSDR Mini [USB 2.0] 1D3AC7FE409032'
DEBUG: Executing libusb_reset_device() [UID=1000, effective UID=1000]
DEBUG: libusb_reset_device() executed successfully.
[INFO] Reference clock 40.00 MHz
[INFO] Device name: LimeSDR-Mini
[INFO] Reference: 40 MHz
[INFO] LMS7002M register cache: Disabled
  driver=FT601
  hardware=LimeSDR-Mini
  boardSerialNumber=0x1d3ac7fe409032
  firmwareVersion=6
  gatewareVersion=1.30
  hardwareVersion=1
  protocolVersion=1

Thus libusb_reset_device() returns without an error on GNU/Linux,
despite being executed as user (UID and EUID = 1000).

This proves that on Linux there is no problem in executing the call as
non-root. The problem appears on FreeBSD only.

> > 
> > 2. If that function blocks normal operations on FreeBSD while without
> > it everything works fine, then it may be wrapped around ifdef and
> > simply removed for FreeBSD.

Whether the libusb_reset_device() call is needed or not isn't clear to
me. It *appears* to work without the call, but I'm not sure if there
are side effects or corner cases.

The context of the call is as follows:

[...] libusb_open(devs[i], &dev_handle) [...];
    if(libusb_kernel_driver_active(dev_handle, 1) == 1)   //find out if kernel driver is attached
    {
        lime::debug("Kernel Driver Active");
        if(libusb_detach_kernel_driver(dev_handle, 1) == 0) //detach it
            lime::debug("Kernel Driver Detached!");
    }
    int r = libusb_claim_interface(dev_handle, 0); //claim interface 0 (the first) of device
    if (r < 0)
        return ReportError(-1, "Cannot claim interface - %s", libusb_strerror(libusb_error(r)));

    if ((r = libusb_claim_interface(dev_handle, 1))<0) //claim interface 1 of device
        return ReportError(-1, "Cannot claim interface - %s", libusb_strerror(libusb_error(r)));
    lime::debug("Claimed Interface");
    if (libusb_reset_device(dev_handle)!=0)
        return ReportError(-1, "USB reset failed", libusb_strerror(libusb_error(r)));
    FT_FlushPipe(ctrlRdEp);  //clear ctrl ep rx buffer
    FT_SetStreamPipe(ctrlRdEp,64);
    FT_SetStreamPipe(ctrlWrEp,64);
    isConnected = true;
    return 0;

See:
https://github.com/myriadrf/LimeSuite/blob/1c1c202f9a6ae4bb34068b6f3f576f7f8e74c7f1/src/ConnectionFTDI/ConnectionFT601.cpp#L160


> > 
> > 3. Make sure this is not a bug in the LimeSDR firmware that makes this
> > non-standard behaviour.

As shown above, no problem on Linux.

It might still be wrong to call libusb_reset_device(), but for that we'd
need to understand why it's called and if it's generally a bad practice
to call it as driver that runs as non-root (and if there are
alternatives or if it's just not necessary to do the call).


> > 
> > 4. According to `man usbconfig` reset will perform "Reset the device.
> > This forces the USB stack to reenumerate the bus.". If LimeSDR uses
> > some dynamic USB interfaces configuration and re-organizes itself at
> > runtime then I would observe how the FreeBSD USB stack reacts to that
> > changes. Such reset may not be even necessary by hand (or from libusb)
> > if the OS re-enumerates the bus for you. Maybe on other OS it is
> > important to call that libusb reset to make sure the bus is
> > re-enumerated.
> > 
> > @HPS is the author of the USB stack so he could provide some hints..
> > but without actually seeing the device it can be hard to achieve :-)

For that, it would be helpful to understand when libusb_reset_device()
needs to or should be called, and if it's (supposed to be) the same on
FreeBSD, Linux, and macOS.


> > [...]
> > 
> > Are you sure this is the problem? When run as root does the program
> > works fine? If so, there may be a systctl setting for the stack that
> > may allow user to reset / power-on-off the port (@HPS?)? You may want
> > to take a look at `sysctl -a | grep usb` to search for such sysctl
> > option. Maybe also `man usbconfig` and `man usb`.


Regards,
Jan


More information about the freebsd-usb mailing list