Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

libusb: error [submit_bulk_transfer] submiturb failed error -1 errno=2 - What am I doing wrong with LibUSB?

Tags:

Ok, I'm probably doing something dumb, but I can't get libusb to let me transfer data to my device for the life of me.

Code:

#include <iostream>
#include <iomanip>

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <signal.h>

#include <libusb-1.0/libusb.h>


#define EP_DATA_IN  0x83
#define EP_DATA_OUT 0x02
#define DEVICE_CONFIGURATION 0


int main(int argc, char **argv)
{

    int rc;
    libusb_context *ctx = NULL;
    libusb_device_handle *dev_handle;

    int actual = 0;
    unsigned char *data = new unsigned char[4];
    data[0]='a';data[1]='b';data[2]='c';data[3]='d';

    rc = libusb_init(&ctx);
    if(rc < 0) {
        std::cout << "Init Error " << rc << std::endl;
        return 1;
    }

    libusb_set_debug(ctx, 6);


    dev_handle = libusb_open_device_with_vid_pid(ctx, 0x03eb, 0x2423);
    if (!dev_handle) {
        fprintf(stderr, "Error finding USB device\n");
        return 2;
    }

    if(libusb_kernel_driver_active(dev_handle, DEVICE_CONFIGURATION) == 1) {
        std::cout << "Kernel Driver Active" << std::endl;
        if(libusb_detach_kernel_driver(dev_handle, DEVICE_CONFIGURATION) == 0)
            std::cout << "Kernel Driver Detached!" << std::endl;
    }

    rc = libusb_claim_interface(dev_handle, DEVICE_CONFIGURATION);
    if(rc != 0) {
        std::cout << "Cannot Claim Interface" << std::endl;
        return 3;
    }

    std::cout << "Data->" << data << "<-" << std::endl;
    std::cout << "Writing Data..." << std::endl;

    std::cout << "Trying endpoint " << EP_DATA_OUT << "." << std::endl;
    rc = libusb_bulk_transfer(dev_handle, EP_DATA_OUT, data, sizeof(data), &actual, 100);

    if(rc == 0 && actual == 4)
    {
        std::cout << "Writing Successful!" << std::endl;
    }
    else
    {
        std::cout << "Write Error! Rc: " << rc << " Actual transfered bytes: " << actual << "." << std::endl;
        std::cout << "Error code means: " << libusb_error_name(rc) << std::endl;
    }


    rc = libusb_release_interface(dev_handle, 0);
    if(rc!=0) {
        std::cout << "Cannot Release Interface" << std::endl;
        return 1;
    }

    if (dev_handle)
        libusb_close(dev_handle);

    libusb_exit(ctx);

    return 0;
}

Device in question:

pi@testpi:~$ sudo lsusb -d 03eb: -v

Bus 001 Device 004: ID 03eb:2423 Atmel Corp.
Device Descriptor:
  bLength                18
  bDescriptorType         1
  bcdUSB               2.00
  bDeviceClass            0 (Defined at Interface level)
  bDeviceSubClass         0
  bDeviceProtocol         0
  bMaxPacketSize0        64
  idVendor           0x03eb Atmel Corp.
  idProduct          0x2423
  bcdDevice            1.00
  iManufacturer           1 ATMEL ASF
  iProduct                2 Vendor Class Example
  iSerial                 0
  bNumConfigurations      1
  Configuration Descriptor:
    bLength                 9
    bDescriptorType         2
    wTotalLength           69
    bNumInterfaces          1
    bConfigurationValue     1
    iConfiguration          0
    bmAttributes         0xc0
      Self Powered
    MaxPower              100mA
    Interface Descriptor:
      bLength                 9
      bDescriptorType         4
      bInterfaceNumber        0
      bAlternateSetting       0
      bNumEndpoints           0
      bInterfaceClass       255 Vendor Specific Class
      bInterfaceSubClass    255 Vendor Specific Subclass
      bInterfaceProtocol    255 Vendor Specific Protocol
      iInterface              0
    Interface Descriptor:
      bLength                 9
      bDescriptorType         4
      bInterfaceNumber        0
      bAlternateSetting       1
      bNumEndpoints           6
      bInterfaceClass       255 Vendor Specific Class
      bInterfaceSubClass    255 Vendor Specific Subclass
      bInterfaceProtocol    255 Vendor Specific Protocol
      iInterface              0
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x81  EP 1 IN
        bmAttributes            3
          Transfer Type            Interrupt
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0040  1x 64 bytes
        bInterval               1
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x02  EP 2 OUT
        bmAttributes            3
          Transfer Type            Interrupt
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0040  1x 64 bytes
        bInterval               1
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x83  EP 3 IN
        bmAttributes            2
          Transfer Type            Bulk
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0040  1x 64 bytes
        bInterval               0
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x04  EP 4 OUT
        bmAttributes            2
          Transfer Type            Bulk
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0040  1x 64 bytes
        bInterval               0
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x85  EP 5 IN
        bmAttributes            1
          Transfer Type            Isochronous
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0100  1x 256 bytes
        bInterval               1
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x06  EP 6 OUT
        bmAttributes            1
          Transfer Type            Isochronous
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0100  1x 256 bytes
        bInterval               1
Device Status:     0x0001
  Self Powered

And what I get when I run the code against the device:

pi@testpi:~/BatLogger/Interface/libusb_test$ ./make.sh
libusb: debug [libusb_get_device_list]
libusb: debug [libusb_get_device_descriptor]
libusb: debug [libusb_open] open 1.4
libusb: debug [usbi_add_pollfd] add fd 11 events 4
libusb: debug [libusb_kernel_driver_active] interface 0
libusb: debug [libusb_claim_interface] interface 0
Data->abcd<-
Writing Data...
Trying endpoint 2.
libusb: debug [add_to_flying_list] arm timerfd for timeout in 100ms (first in line)
libusb: debug [submit_bulk_transfer] need 1 urbs for new transfer with length 4
libusb: error [submit_bulk_transfer] submiturb failed error -1 errno=2
libusb: debug [submit_bulk_transfer] first URB failed, easy peasy
libusb: debug [disarm_timerfd]
Write Error! Rc: -1 Actual transfered bytes: 0.
Error code means: LIBUSB_ERROR_IO
libusb: debug [libusb_release_interface] interface 0
libusb: debug [libusb_close]
libusb: debug [usbi_remove_pollfd] remove fd 11
libusb: debug [libusb_exit]
libusb: debug [libusb_exit] destroying default context

As far as I know, I'm doing everything correctly. libusb_claim_interface returns OK, there isn't a pre-existing driver attached to the device since I'm using a custom VID/PID combo, and EP_DATA_OUT is a output endpoint (direction bit is 0, though to whom "out" is with respect to isn't described). Out of irritation, I've also tried every other possible endpoint (0-16, 0-16 | 1 << 7), with the exact same error for all of them.

Is there something silly I'm missing? Do I have to install a kernel module or something to make libusb play nice with me? I'm using libusb-1.0.

The error from the libusb debug message is error -1 errno=2. where errno=2 corresponds to ERNOENT, but the few things I could find about that together with libusb didn't have a decent conclusion about what's actually going on.

Code is built g++ -std=c++11 -Wall -lrt -lusb-1.0 main.cpp -o main.bin, though the fact that I'm using C++ is probably not relevant to the issue, since I'm not using one of the C++ libusb wrappers.

like image 601
Fake Name Avatar asked May 22 '17 22:05

Fake Name


1 Answers

Ok, so I figured out the issue.

Basically, apparently, for ~reasons~, the endpoints for my device are attached to configuration 0, alternate setting 1.

I'm not sure how, or if it's even possible to determine this from the output of lsusb, but I had a bit of scripting that I had used for a different device written against PyUSB, so I had a poke around with that, and it told me:

1 pi@testpi:~/BatLogger/Interface/libusb_test$ sudo python3 test.py
INFO:Main.Gui:Device: DEVICE ID 03eb:2423 on Bus 001 Address 004 =================
 bLength                :   0x12 (18 bytes)
 bDescriptorType        :    0x1 Device
 bcdUSB                 :  0x200 USB 2.0
 bDeviceClass           :    0x0 Specified at interface
 bDeviceSubClass        :    0x0
 bDeviceProtocol        :    0x0
 bMaxPacketSize0        :   0x40 (64 bytes)
 idVendor               : 0x03eb
 idProduct              : 0x2423
 bcdDevice              :  0x100 Device 1.0
 iManufacturer          :    0x1 ATMEL ASF
 iProduct               :    0x2 Vendor Class Example
 iSerialNumber          :    0x0
 bNumConfigurations     :    0x1
  CONFIGURATION 1: 100 mA ==================================
   bLength              :    0x9 (9 bytes)
   bDescriptorType      :    0x2 Configuration
   wTotalLength         :   0x45 (69 bytes)
   bNumInterfaces       :    0x1
   bConfigurationValue  :    0x1
   iConfiguration       :    0x0
   bmAttributes         :   0xc0 Self Powered
   bMaxPower            :   0x32 (100 mA)
    INTERFACE 0: Vendor Specific ===========================
     bLength            :    0x9 (9 bytes)
     bDescriptorType    :    0x4 Interface
     bInterfaceNumber   :    0x0
     bAlternateSetting  :    0x0
     bNumEndpoints      :    0x0
     bInterfaceClass    :   0xff Vendor Specific
     bInterfaceSubClass :   0xff
     bInterfaceProtocol :   0xff
     iInterface         :    0x0
    INTERFACE 0, 1: Vendor Specific ========================
     bLength            :    0x9 (9 bytes)
     bDescriptorType    :    0x4 Interface
     bInterfaceNumber   :    0x0
     bAlternateSetting  :    0x1
     bNumEndpoints      :    0x6
     bInterfaceClass    :   0xff Vendor Specific
     bInterfaceSubClass :   0xff
     bInterfaceProtocol :   0xff
     iInterface         :    0x0
      ENDPOINT 0x81: Interrupt IN ==========================
       bLength          :    0x7 (7 bytes)
       bDescriptorType  :    0x5 Endpoint
       bEndpointAddress :   0x81 IN
       bmAttributes     :    0x3 Interrupt
       wMaxPacketSize   :   0x40 (64 bytes)
       bInterval        :    0x1
      ENDPOINT 0x2: Interrupt OUT ==========================
       bLength          :    0x7 (7 bytes)
       bDescriptorType  :    0x5 Endpoint
       bEndpointAddress :    0x2 OUT
       bmAttributes     :    0x3 Interrupt
       wMaxPacketSize   :   0x40 (64 bytes)
       bInterval        :    0x1
      ENDPOINT 0x83: Bulk IN ===============================
       bLength          :    0x7 (7 bytes)
       bDescriptorType  :    0x5 Endpoint
       bEndpointAddress :   0x83 IN
       bmAttributes     :    0x2 Bulk
       wMaxPacketSize   :   0x40 (64 bytes)
       bInterval        :    0x0
      ENDPOINT 0x4: Bulk OUT ===============================
       bLength          :    0x7 (7 bytes)
       bDescriptorType  :    0x5 Endpoint
       bEndpointAddress :    0x4 OUT
       bmAttributes     :    0x2 Bulk
       wMaxPacketSize   :   0x40 (64 bytes)
       bInterval        :    0x0
      ENDPOINT 0x85: Isochronous IN ========================
       bLength          :    0x7 (7 bytes)
       bDescriptorType  :    0x5 Endpoint
       bEndpointAddress :   0x85 IN
       bmAttributes     :    0x1 Isochronous
       wMaxPacketSize   :  0x100 (256 bytes)
       bInterval        :    0x1
      ENDPOINT 0x6: Isochronous OUT ========================
       bLength          :    0x7 (7 bytes)
       bDescriptorType  :    0x5 Endpoint
       bEndpointAddress :    0x6 OUT
       bmAttributes     :    0x1 Isochronous
       wMaxPacketSize   :  0x100 (256 bytes)
       bInterval        :    0x1

The critical thing being that there are no endpoints under INTERFACE 0:, but there are endpoints under INTERFACE 0, 1:. This was enough to go on to figure out that there were more then one version of INTERFACE 0, and with that, it was pretty easy to figure out I needed to call libusb_set_interface_alt_setting() to select the right alternate configuration thingie.

Basically, I wound up adding

rc = libusb_set_interface_alt_setting(dev_handle, DEVICE_CONFIGURATION, 1);
if(rc != 0) {
    std::cout << "Cannot configure alternate setting" << std::endl;
    return 3;
}

after the libusb_claim_interface() call in my C(++) code, and I can now write to the device.

like image 182
Fake Name Avatar answered Oct 27 '22 09:10

Fake Name