libusb hotplug-逻辑仅在第一次且仅在连接了硬件时才有效

时间:2018-09-09 18:21:21

标签: c++ libusb

代码跟随,以及程序输出。

我做了以下重现此问题的测试代码。这是对led板的测试(我写点东西,板上使led发光)。该问题并非特定于此硬件,我在其他硬件上具有相同的行为。实际的代码是分层的并且更好,但是表现出相同的行为。

情况1: 我连接了硬件并启动程序,它显示了提供的输出。仅在我事先连接硬件的情况下,它才会执行应该执行的操作。后续的拆装操作在设备上失败(例如,没有LED指示灯)。

情况2: 如果我启动程序并随后连接硬件,也会发生同样的情况。在这种情况下,它永远不会起作用。

我不是从根本上了解一些东西。情况1在第一次“运行”时如何没有附加内核驱动程序,而在随后的“运行”中却有一个内核驱动程序呢?我已经尝试过(很多)注释掉有关内核驱动程序的代码,将命令序列移到不可用...

请问我的错误在哪里?如果可能的话,请解释一下,因为我迷路了...

#include <stdlib.h>
#include <stdio.h>
#include <thread>
#include <iostream>

#include "libusb-1.0/libusb.h"

class test {
public:
    int done = 0;
    int rc = 0;

    test() {
        init();
    }

    virtual ~test() {
        shutdown();
    }

private:
    const static uint8_t umRequestType = 0x21;
    const static uint8_t umRequest = 9;
    const static uint16_t umValue = 0x0200;
    const static unsigned int umTimeout = 2000;
    const static int interface = 0; //test board's interface

    libusb_device_handle *handle = NULL;

    int init() {
        libusb_hotplug_callback_handle hp[2];
        int product_id, vendor_id, class_id;
        int rc;

        vendor_id = 0xd209;
        product_id = 0x1401;
        class_id = LIBUSB_HOTPLUG_MATCH_ANY;

        rc = libusb_init(NULL);
        if (rc < 0) {
            printf("failed to initialise libusb: %s\n", libusb_error_name(rc));
        }

        if (!libusb_has_capability(LIBUSB_CAP_HAS_HOTPLUG)) {
            printf("Hotplug capabilites are not supported on this platform\n");
            libusb_exit(NULL);
        }

        rc = libusb_hotplug_register_callback(NULL, LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED, LIBUSB_HOTPLUG_ENUMERATE, vendor_id,
                                              product_id, class_id, static_hotplug_callback, this, &hp[0]);
        if (LIBUSB_SUCCESS != rc) {
            fprintf(stderr, "Error registering callback 0\n");
            libusb_exit(NULL);
        }

        rc = libusb_hotplug_register_callback(NULL, LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT, LIBUSB_HOTPLUG_ENUMERATE, vendor_id,
                                              product_id, class_id, static_hotplug_callback_detach, this, &hp[1]);
        if (LIBUSB_SUCCESS != rc) {
            fprintf(stderr, "Error registering callback 1\n");
            libusb_exit(NULL);
        }
    }

    void shutdown() {
        if (handle) {
            libusb_close(handle);
        }
        libusb_exit(NULL);
    }

    static int LIBUSB_CALL static_hotplug_callback(libusb_context *ctx, libusb_device *dev, libusb_hotplug_event event, void *user_data) {
        return reinterpret_cast<test *>(user_data)->hotplug_callback(ctx, dev, event, user_data);
    }

    int hotplug_callback(libusb_context *ctx, libusb_device *dev, libusb_hotplug_event event, void *user_data) {
        struct libusb_device_descriptor desc;

        (void) ctx;
        (void) dev;
        (void) event;
        (void) user_data;

        rc = libusb_get_device_descriptor(dev, &desc);
        if (LIBUSB_SUCCESS != rc) {
            fprintf(stderr, "Error getting device descriptor\n");
        }

        printf("Device attached: %04x:%04x\n", desc.idVendor, desc.idProduct);

        rc = libusb_open(dev, &handle);
        if (LIBUSB_SUCCESS != rc) {
            fprintf(stderr, "Error opening device\n");
        }

        rc = libusb_kernel_driver_active(handle, interface);
        printf("libusb_kernel_driver_active returned %d\n",rc);
        if (rc == 1) { //find out if kernel driver is attached
            printf("A kernel driver is active\n");
            rc = libusb_detach_kernel_driver(handle, interface);
            if (rc != LIBUSB_SUCCESS) {
                printf("libusb_detach_kernel_driver() failed: %s - %d\n",libusb_error_name(rc),libusb_strerror((libusb_error) rc));
                return false;
            } else {
                printf("detached kernel driver\n");
            }
        }

        rc = libusb_set_configuration(handle, 1);
        printf("libusb_set_configuration returned %d\n",rc);

        if (handle) {
            rc = libusb_set_auto_detach_kernel_driver(handle, 1);
            if (rc != LIBUSB_SUCCESS) {
                printf("libusb_set_auto_detach_kernel_driver() failed: %s - %d\n",libusb_error_name(rc),libusb_strerror((libusb_error) rc) );
             } else {
                printf("libusb_set_auto_detach_kernel_driver() has been set\n");
            }
        }

        rc = libusb_claim_interface(handle, interface);
        if (rc != LIBUSB_SUCCESS) {
            printf("libusb_claim_interface() failed: %s - %d\n",libusb_error_name(rc),libusb_strerror((libusb_error) rc));
            return false;
        }

        //get the bConfigurationValue
        int config = 0;
        rc = libusb_get_configuration(handle, &config);
        std::cout << "libusb_get_configuration returned " << rc << "\n";
        std::cout << "config value is " << config << "\n";

        if (handle) {
            std::array<unsigned char, 2> data{0x00, 0xff};
            auto byteCount = libusb_control_transfer(handle, umRequestType, umRequest, umValue, interface, &data[0], data.size(), umTimeout);
            printf("#bytes written to board: %d\n", data.size());
            libusb_close(handle);
            handle = NULL;
        }

        done++;

        return 0;
    }

    static int LIBUSB_CALL static_hotplug_callback_detach(libusb_context *ctx, libusb_device *dev, libusb_hotplug_event event, void *user_data) {
        return reinterpret_cast<test *>(user_data)->hotplug_callback_detach(ctx, dev, event, user_data);
    }

    int hotplug_callback_detach(libusb_context *ctx, libusb_device *dev, libusb_hotplug_event event, void *user_data) {
        (void) ctx;
        (void) dev;
        (void) event;
        (void) user_data;

        printf("Device detached\n");

        if (handle) {
            libusb_close(handle);
            handle = NULL;
        }

        done++;

        return 0;
    }

};


int main(int argc, char *argv[]) {
    std::unique_ptr<test> testClass1 = std::make_unique<test>();

    while (testClass1->done < 5) {
        printf("#evens: %d\n",testClass1->done);
        if (libusb_handle_events_completed(nullptr, nullptr) != LIBUSB_SUCCESS)
            printf("libusb_handle_events() failed: %s\n", libusb_error_name(testClass1->rc));
        std::this_thread::sleep_for(std::chrono::microseconds(1000000));
    }
    //the end
}

程序输出情况1:

/home/****/CLionProjects/usbdebugpoc/cmake-build-debug/usbdebugpoc
Device attached: d209:1401    
libusb_kernel_driver_active returned 0
libusb_set_configuration returned 0
libusb_set_auto_detach_kernel_driver() has been set
libusb_get_configuration returned 0
config value is 1
#bytes written to board: 2
#evens: 1
Device detached
#evens: 2
Device attached: d209:1401
libusb_kernel_driver_active returned 1
A kernel driver is active
detached kernel driver
libusb_set_configuration returned 0
libusb_set_auto_detach_kernel_driver() has been set
libusb_get_configuration returned 0
config value is 1
#bytes written to board: 2
#evens: 3
Device detached
#evens: 4
Device attached: d209:1401
libusb_kernel_driver_active returned 1
A kernel driver is active
detached kernel driver
libusb_set_configuration returned 0
libusb_set_auto_detach_kernel_driver() has been set
libusb_get_configuration returned 0
config value is 1
#bytes written to board: 2

Process finished with exit code 0

0 个答案:

没有答案