libusb: error [submit_bulk_transfer] submiturb failed error -1 errno=2 - 我对 LibUSB 做错了什么?

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

好吧,我可能在做一些愚蠢的事情,但我无法让 libusb 让我终生将数据传输到我的设备。

代码:

#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;
}

有问题的设备:

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

以及当我 运行 针对设备的代码时得到的结果:

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

据我所知,我做的一切都是正确的。 libusb_claim_interface returns 好的,由于我使用的是自定义 VID/PID 组合,因此设备上没有附加预先存在的驱动程序,并且 EP_DATA_OUT 是输出端点(方向位为 0,但未描述 "out" 相对于谁)。出于愤怒,我还尝试了所有其他可能的端点(0-16、0-16 | 1 << 7),所有这些端点都出现了完全相同的错误。

我是不是遗漏了什么愚蠢的东西?我是否必须安装内核模块或其他东西才能让 libusb 与我一起玩得开心?我正在使用 libusb-1.0.

libusb 调试消息的错误是 error -1 errno=2。其中 errno=2 对应于 ERNOENT,但是我能找到的关于它的一些东西以及 libusb 并没有对实际发生的事情得出一个像样的结论。

代码已构建 g++ -std=c++11 -Wall -lrt -lusb-1.0 main.cpp -o main.bin,尽管我使用 C++ 的事实 可能 与问题无关,因为我没有使用其中之一C++ libusb 包装器。

好的,所以我想出了问题。

基本上,显然,出于~原因~,我设备的端点连接到配置 0,备用设置 1

我不确定如何,或者是否有可能从 lsusb 的输出中确定这一点,但我有一些脚本用于针对 PyUSB 编写的不同设备,所以我仔细研究了一下,它告诉我:

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

关键是 INTERFACE 0: 下没有端点,但 INTERFACE 0, 1: 下有 个端点。这足以继续弄清楚 INTERFACE 0 有不止一个版本,并且很容易弄清楚我需要调用 libusb_set_interface_alt_setting() 到 select正确的备用配置东西。

基本上,我最后添加了

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

在我的 C(++) 代码中调用 libusb_claim_interface() 之后,我现在可以写入设备。