libusb hotplug - логика работает только 1 раз и только если подключено оборудование - PullRequest
0 голосов
/ 09 сентября 2018

Код следует так же, как и вывод программы.

Я сделал следующий тестовый код, который воспроизводит проблему.Это тест на светодиодной доске (я что-то пишу, на плате горит светодиод).Проблема не относится к этому оборудованию, у меня такое же поведение на другом оборудовании.Фактический код является многоуровневым и лучше, но демонстрирует то же поведение.

Ситуация 1: я подключаю аппаратное обеспечение и запускаю программу, и она показывает поставленный вывод.Он делает то, что должен делать только один раз и только если я предварительно подключаю оборудование.Последующие операции отсоединения-присоединения завершаются неудачно на устройстве (например, без светодиода).

ситуация 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
...