美文网首页
libusb学习笔记(5)

libusb学习笔记(5)

作者: 客昂康 | 来源:发表于2021-12-29 17:49 被阅读0次

    API说明:

    int libusb_get_configuration(libusb_device_handle *dev_handle, int *config);
    获取当前活跃的配置的 bConfigurationValue 值,通过 *config 返回。
    如果设备处于未配置状态,此函数将通过 *config 返回0.
    成功返回0,如果设备已断开连接就返回 LIBUSB_ERROR_NO_DEVICE 。

    int libusb_set_configuration(libusb_device_handle *dev_handle, int configuration);
    使设备指定的配置为活跃的配置。
    操作系统可能已经在设备上设置了活动配置,也可能未设置。
    在 claim 接口和执行其他操作之前,由应用程序确保选择了正确的配置。
    如果在已使用所选配置配置的设备上调用此函数,则此函数将充当轻量级设备重置:
    它将使用当前配置发出 SET_CONFIGURATION 请求,造成大多数usb设备相关的状态被重置
    (altsetting重置为0,endpoint内容清0,开关复位)。
    并非所有后端都支持从用户空间设置配置,通过返回 LIBUSB_ERROR_NOT_SUPPORTED 来表
    示不支持。由于这表明平台正在处理设备配置本身,因此通常可以安全地忽略此错误。
    如果应用程序已 claim 接口,则无法更改或重置配置。建议在 claim 接口之前设置配置。
    或者先调用 libusb_release_interface() 释放接口,不过要先确保 auto_detach_kernel_driver
    为0,不然刚释放又会自动连上相应的驱动程序。
    如果其他应用程序或驱动程序已 claim 接口,则无法更改或重置配置。
    configuration 为 -1 将使设备设置为未配置状态。USB规范规定使用0将设备设置为未配
    置状态,但是实际上存在 bConfigurationValue 为 0 的错误设备。
    应该始终使用此函数,而不是制定自己的 SET_CONFIGURATION 请求。这是因为底层操作系
    统需要知道这些更改何时发生。
    这是一个阻塞函数。
    返回值:
    LIBUSB_ERROR_NOT_FOUND 请求的配置不存在
    LIBUSB_ERROR_BUSY 接口已 claim
    LIBUSB_ERROR_NOT_SUPPORTED 后端不支持设置或更改配置
    LIBUSB_ERROR_NO_DEVICE 设备已断开连接

    int libusb_set_auto_detach_kernel_driver(libusb_device_handle *dev_handle, int enable);
    启用或禁用 libusb 的自动内核驱动程序分离。
    启用此选项后,libusb 将在 claim 接口时自动 detach 接口上的内核驱动程序,并在
    释放 接口时又 attach 该驱动程序。
    默认情况下新打开的设备句柄上禁用自动内核驱动程序分离。
    在不支持 LIBUSB_CAP_SUPPORTS_DETACH_KERNEL_DRIVER 功能的平台上,此函数将返回
    LIBUSB_ERROR_NOT_SUPPORTED,libusb 将继续运行,就像从未调用过此函数一样。
    返回值:
    LIBUSB_SUCCESS 执行成功
    LIBUSB_ERROR_NOT_SUPPORTED 平台不支持

    int libusb_claim_interface(libusb_device_handle *dev_handle, int interface_number);
    声明给定设备句柄上的接口。
    在对其任何端点执行I/O之前,必须声明要使用的接口。
    尝试声明已声明的接口是合法的,在这种情况下,libusb只返回0,不做任何操作。
    如果将 auto_detach_kernel_driver 设置为1,则自动 detach 内核驱动程序。
    接口声明是纯逻辑操作,它不会导致通过总线发送任何请求。
    接口声明用于指示底层操作系统应用程序希望获得接口的所有权。
    这是一个非阻塞函数。
    返回值:
    LIBUSB_SUCCESS 执行成功
    LIBUSB_ERROR_NOT_FOUND 请求的接口不存在
    LIBUSB_ERROR_BUSY 另一个程序或驱动程序已声明该接口
    LIBUSB_ERROR_NO_DEVICE 设备已断开连接

    int libusb_release_interface(libusb_device_handle *dev_handle, int interface_number);
    释放以前使用 libusb_claim_interface() 声明的接口。
    您应该在关闭设备句柄之前释放所有声明的接口。
    如果将 auto_detach_kernel_driver 设置为1,则自动 attach 内核驱动程序。
    将向设备发送 SET_INTERFACE 请求,将接口状态重置为第一个备用设置。
    这是一个阻塞函数。
    返回值:
    LIBUSB_SUCCESS 执行成功
    LIBUSB_ERROR_NOT_FOUND 请求的接口不存在
    LIBUSB_ERROR_NO_DEVICE 设备已断开连接

    int libusb_set_interface_alt_setting(libusb_device_handle *dev_handle, int interface_number, int alternate_setting);
    激活接口的备用设置。
    该接口必须是以前使用 libusb_claim_interface() 声明的。
    应该始终使用此功能,而不是制定自己的 SET_INTERFACE 请求。
    这是因为底层操作系统需要知道这些更改何时发生。
    这是一个阻塞函数。
    返回值:
    LIBUSB_SUCCESS 执行成功
    LIBUSB_ERROR_NOT_FOUND 未声明接口或请求的备用设置不存在
    LIBUSB_ERROR_NO_DEVICE 设备已断开连接

    int libusb_clear_halt(libusb_device_handle *dev_handle, unsigned char endpoint);
    清除端点的停止或暂停状态。
    endpoint 是要清除状态的端点。
    暂停状态的端点在暂停状态停止之前无法接收或传输数据。
    在尝试清除暂停状态之前,应取消所有挂起的传输。
    这是一个阻塞函数。
    返回值:
    LIBUSB_SUCCESS 执行成功
    LIBUSB_ERROR_NOT_FOUND 端点不存在
    LIBUSB_ERROR_NO_DEVICE 设备已断开连接

    int libusb_kernel_driver_active(libusb_device_handle *dev_handle, int interface_number);
    确定接口上的内核驱动程序是否处于活动状态。
    如果内核驱动程序处于活动状态,则无法声明接口,并且libusb将无法执行I/O。
    此功能在Windows上不可用。
    返回值:
    0 无活跃的内核驱动
    1 有活跃的内核驱动
    LIBUSB_ERROR_NO_DEVICE 设备已断开连接
    LIBUSB_ERROR_NOT_SUPPORTED 平台不支持

    int libusb_detach_kernel_driver(libusb_device_handle *dev_handle, int interface_number);
    分离接口上的内核驱动。
    返回值:
    LIBUSB_SUCCESS 执行成功
    LIBUSB_ERROR_NOT_FOUND 无活跃的内核驱动
    LIBUSB_ERROR_INVALID_PARAM 接口不存在
    LIBUSB_ERROR_NO_DEVICE 设备已断开连接
    LIBUSB_ERROR_NOT_SUPPORTED 平台不支持

    int libusb_attach_kernel_driver(libusb_device_handle *dev_handle, int interface_number);
    附上接口上的内核驱动。
    返回值:
    LIBUSB_SUCCESS 执行成功
    LIBUSB_ERROR_NOT_FOUND 无活跃的内核驱动
    LIBUSB_ERROR_INVALID_PARAM 接口不存在
    LIBUSB_ERROR_NO_DEVICE 设备已断开连接
    LIBUSB_ERROR_NOT_SUPPORTED 平台不支持
    LIBUSB_ERROR_BUSY 无法附加驱动程序,因为接口已声明

    代码举例:

    /*
    int libusb_get_configuration(libusb_device_handle *dev_handle, int *config);
        获取当前活跃的配置的 bConfigurationValue 值,通过 *config 返回。
        如果设备处于未配置状态,此函数将通过 *config 返回0.
        成功返回0,如果设备已断开连接就返回 LIBUSB_ERROR_NO_DEVICE 。
    
    int libusb_set_configuration(libusb_device_handle *dev_handle, int configuration);
        使设备指定的配置为活跃的配置。
        操作系统可能已经在设备上设置了活动配置,也可能未设置。
        在 claim 接口和执行其他操作之前,由应用程序确保选择了正确的配置。
        如果在已使用所选配置配置的设备上调用此函数,则此函数将充当轻量级设备重置:
        它将使用当前配置发出 SET_CONFIGURATION 请求,造成大多数usb设备相关的状态被重置
        (altsetting重置为0,endpoint内容清0,开关复位)。
        并非所有后端都支持从用户空间设置配置,通过返回 LIBUSB_ERROR_NOT_SUPPORTED 来表
        示不支持。由于这表明平台正在处理设备配置本身,因此通常可以安全地忽略此错误。
        如果应用程序已 claim 接口,则无法更改或重置配置。建议在 claim 接口之前设置配置。
        或者先调用 libusb_release_interface() 释放接口,不过要先确保 auto_detach_kernel_driver
        为0,不然刚释放又会自动连上相应的驱动程序。
        如果其他应用程序或驱动程序已 claim 接口,则无法更改或重置配置。
        configuration 为 -1 将使设备设置为未配置状态。USB规范规定使用0将设备设置为未配
        置状态,但是实际上存在 bConfigurationValue 为 0 的错误设备。
        应该始终使用此函数,而不是制定自己的 SET_CONFIGURATION 请求。这是因为底层操作系
        统需要知道这些更改何时发生。
        这是一个阻塞函数。
        返回值:
            LIBUSB_ERROR_NOT_FOUND      请求的配置不存在
            LIBUSB_ERROR_BUSY           接口已 claim
            LIBUSB_ERROR_NOT_SUPPORTED  后端不支持设置或更改配置
            LIBUSB_ERROR_NO_DEVICE      设备已断开连接
    
    int libusb_set_auto_detach_kernel_driver(libusb_device_handle *dev_handle, int enable);
        启用或禁用 libusb 的自动内核驱动程序分离。
        启用此选项后,libusb 将在 claim 接口时自动 detach 接口上的内核驱动程序,并在
        释放 接口时又 attach 该驱动程序。
        默认情况下新打开的设备句柄上禁用自动内核驱动程序分离。
        在不支持 LIBUSB_CAP_SUPPORTS_DETACH_KERNEL_DRIVER 功能的平台上,此函数将返回
        LIBUSB_ERROR_NOT_SUPPORTED,libusb 将继续运行,就像从未调用过此函数一样。
        返回值:
            LIBUSB_SUCCESS              执行成功
            LIBUSB_ERROR_NOT_SUPPORTED  平台不支持
    
    int libusb_claim_interface(libusb_device_handle *dev_handle, int interface_number); 
        声明给定设备句柄上的接口。
        在对其任何端点执行I/O之前,必须声明要使用的接口。
        尝试声明已声明的接口是合法的,在这种情况下,libusb只返回0,不做任何操作。
        如果将 auto_detach_kernel_driver 设置为1,则自动 detach 内核驱动程序。
        接口声明是纯逻辑操作,它不会导致通过总线发送任何请求。
        接口声明用于指示底层操作系统应用程序希望获得接口的所有权。
        这是一个非阻塞函数。
        返回值:
            LIBUSB_SUCCESS          执行成功
            LIBUSB_ERROR_NOT_FOUND  请求的接口不存在
            LIBUSB_ERROR_BUSY       另一个程序或驱动程序已声明该接口
            LIBUSB_ERROR_NO_DEVICE  设备已断开连接
    
    int libusb_release_interface(libusb_device_handle *dev_handle, int interface_number);
        释放以前使用 libusb_claim_interface() 声明的接口。
        您应该在关闭设备句柄之前释放所有声明的接口。
        如果将 auto_detach_kernel_driver 设置为1,则自动 attach 内核驱动程序。
        将向设备发送 SET_INTERFACE 请求,将接口状态重置为第一个备用设置。
        这是一个阻塞函数。
        返回值:
            LIBUSB_SUCCESS          执行成功
            LIBUSB_ERROR_NOT_FOUND  请求的接口不存在
            LIBUSB_ERROR_NO_DEVICE  设备已断开连接
    
    int libusb_set_interface_alt_setting(libusb_device_handle *dev_handle, int interface_number, int alternate_setting);    
        激活接口的备用设置。
        该接口必须是以前使用 libusb_claim_interface() 声明的。
        应该始终使用此功能,而不是制定自己的 SET_INTERFACE 请求。
        这是因为底层操作系统需要知道这些更改何时发生。
        这是一个阻塞函数。
        返回值:
            LIBUSB_SUCCESS          执行成功
            LIBUSB_ERROR_NOT_FOUND  未声明接口或请求的备用设置不存在
            LIBUSB_ERROR_NO_DEVICE  设备已断开连接
    
    int libusb_clear_halt(libusb_device_handle *dev_handle, unsigned char endpoint);
        清除端点的停止或暂停状态。
        endpoint 是要清除状态的端点。
        暂停状态的端点在暂停状态停止之前无法接收或传输数据。
        在尝试清除暂停状态之前,应取消所有挂起的传输。
        这是一个阻塞函数。
        返回值:
            LIBUSB_SUCCESS          执行成功
            LIBUSB_ERROR_NOT_FOUND  端点不存在
            LIBUSB_ERROR_NO_DEVICE  设备已断开连接
    
    int libusb_kernel_driver_active(libusb_device_handle *dev_handle, int interface_number);
        确定接口上的内核驱动程序是否处于活动状态。
        如果内核驱动程序处于活动状态,则无法声明接口,并且libusb将无法执行I/O。
        此功能在Windows上不可用。
        返回值:
            0                           无活跃的内核驱动
            1                           有活跃的内核驱动
            LIBUSB_ERROR_NO_DEVICE      设备已断开连接
            LIBUSB_ERROR_NOT_SUPPORTED  平台不支持
    
    int libusb_detach_kernel_driver(libusb_device_handle *dev_handle, int interface_number);
        分离接口上的内核驱动。
        返回值:
            LIBUSB_SUCCESS              执行成功
            LIBUSB_ERROR_NOT_FOUND      无活跃的内核驱动
            LIBUSB_ERROR_INVALID_PARAM  接口不存在
            LIBUSB_ERROR_NO_DEVICE      设备已断开连接
            LIBUSB_ERROR_NOT_SUPPORTED  平台不支持
    
    int libusb_attach_kernel_driver(libusb_device_handle *dev_handle, int interface_number);
        附上接口上的内核驱动。
        返回值:
            LIBUSB_SUCCESS              执行成功
            LIBUSB_ERROR_NOT_FOUND      无活跃的内核驱动
            LIBUSB_ERROR_INVALID_PARAM  接口不存在
            LIBUSB_ERROR_NO_DEVICE      设备已断开连接
            LIBUSB_ERROR_NOT_SUPPORTED  平台不支持
            LIBUSB_ERROR_BUSY           无法附加驱动程序,因为接口已声明
    */
    
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include "libusb.h"
    
    static void dumpdevice(libusb_context *libusbCtx, libusb_device *dev, uint16_t vid, uint16_t pid){
        uint8_t bus = libusb_get_bus_number(dev);
        uint8_t addr = libusb_get_device_address(dev);
        struct libusb_device_descriptor deviceDescriptor;
        memset(&deviceDescriptor, 0, sizeof(struct libusb_device_descriptor));
        libusb_get_device_descriptor(dev, &deviceDescriptor);
        
        printf("/dev/bus/usb/%03u/%03u %04x:%04x usb%u.%u class:%02x\n", 
            bus, addr, 
            deviceDescriptor.idVendor, 
            deviceDescriptor.idProduct, 
            (deviceDescriptor.bcdUSB & 0x0f00) >> 8, 
            (deviceDescriptor.bcdUSB & 0x00f0) >> 4, 
            deviceDescriptor.bDeviceClass
        );
        
        libusb_device_handle *devHandle = NULL;
        libusb_open(dev, &devHandle);
        if(devHandle){
            // 获取当前活跃的配置的 bConfigurationValue 值。
            int activeConfig = 99999;
            int errCode = libusb_get_configuration(devHandle, &activeConfig);
            printf("   libusb_get_configuration()=%d, activeConfig=%d\n", errCode, activeConfig);
            
            if((vid == deviceDescriptor.idVendor) && (pid == deviceDescriptor.idProduct)){
                // 启用内核驱动自动 detach 和自动 attach
                errCode = libusb_set_auto_detach_kernel_driver(devHandle, 1);
                printf("      libusb_set_auto_detach_kernel_driver(1)=%d\n", errCode);
                
                // 声明占用接口0
                errCode = libusb_claim_interface(devHandle, 0);
                printf("      libusb_claim_interface(0)=%d\n", errCode);
                
                // 是否有活跃的内核驱动
                // errCode = libusb_kernel_driver_active(devHandle, 0);
                // printf("      libusb_kernel_driver_active(0)=%d\n", errCode);
                
                // 分离接口上的内核驱动
                // errCode = libusb_detach_kernel_driver(devHandle, 0);
                // printf("      libusb_detach_kernel_driver(0)=%d\n", errCode);
                
                // 附上接口上的内核驱动
                // errCode = libusb_attach_kernel_driver(devHandle, 0);
                // printf("      libusb_attach_kernel_driver(0)=%d\n", errCode);
                
                // 释放对接口0的声明
                errCode = libusb_release_interface(devHandle, 0);
                printf("      libusb_release_interface(0)=%d\n", errCode);
            }
            
            libusb_close(devHandle);
        }
    }
    
    int main(int argc, char* argv[]){
        libusb_context *libusbCtx = NULL;
        int errCode = libusb_init(&libusbCtx);
        if(errCode) return -1;
        
        uint16_t vid = 0;
        uint16_t pid = 0;
        if(argc >= 2){
            sscanf(argv[1], "%04hx:%04hx", &vid, &pid);
            printf("VID:PID = %04x:%04x\n", vid, pid);
        }
        
        // 枚举所有USB设备
        libusb_device **devList = NULL;
        ssize_t count = libusb_get_device_list(libusbCtx, &devList);
        if(count > 0){
            ssize_t i;
            for(i=0; i<count; i++){
                dumpdevice(libusbCtx, devList[i], vid, pid);
            }
            libusb_free_device_list(devList, 1);
            devList = NULL;
        }
        
        libusb_exit(libusbCtx);
        return 0;
    }
    
    INCLUDE=-I/usr/include/libusb-1.0/
    LIBDIR=-L/usr/lib/x86_64-linux-gnu/ -lusb-1.0
    
    all: 
        gcc -o test1.exe test1.c $(INCLUDE) $(LIBDIR) -Wall -O3
        gcc -o test2.exe test2.c $(INCLUDE) $(LIBDIR) -Wall -O3
        gcc -o test3.exe test3.c $(INCLUDE) $(LIBDIR) -Wall -O3
        gcc -o test4.exe test4.c $(INCLUDE) $(LIBDIR) -Wall -O3
        gcc -o test5.exe test5.c $(INCLUDE) $(LIBDIR) -Wall -O3
    

    运行结果:

    test@test-PC:~/TMP/libusb$ ./test5.exe
    /dev/bus/usb/002/001 1d6b:0003 usb3.1 class:09
       libusb_get_configuration()=0, activeConfig=1
    /dev/bus/usb/001/007 1c4f:0002 usb1.1 class:00
       libusb_get_configuration()=0, activeConfig=1
    /dev/bus/usb/001/002 05e3:0610 usb2.1 class:09
       libusb_get_configuration()=0, activeConfig=1
    /dev/bus/usb/001/008 093a:2510 usb2.0 class:00
       libusb_get_configuration()=0, activeConfig=1
    /dev/bus/usb/001/001 1d6b:0002 usb2.0 class:09
       libusb_get_configuration()=0, activeConfig=1
    test@test-PC:~/TMP/libusb$ 
    test@test-PC:~/TMP/libusb$ ./test5.exe 1c4f:0002
    VID:PID = 1c4f:0002
    /dev/bus/usb/002/001 1d6b:0003 usb3.1 class:09
       libusb_get_configuration()=0, activeConfig=1
    /dev/bus/usb/001/007 1c4f:0002 usb1.1 class:00
       libusb_get_configuration()=0, activeConfig=1
          libusb_set_auto_detach_kernel_driver(1)=0
          libusb_claim_interface(0)=0
          libusb_release_interface(0)=0
    /dev/bus/usb/001/002 05e3:0610 usb2.1 class:09
       libusb_get_configuration()=0, activeConfig=1
    /dev/bus/usb/001/008 093a:2510 usb2.0 class:00
       libusb_get_configuration()=0, activeConfig=1
    /dev/bus/usb/001/001 1d6b:0002 usb2.0 class:09
       libusb_get_configuration()=0, activeConfig=1
    test@test-PC:~/TMP/libusb$ 
    

    相关文章

      网友评论

          本文标题:libusb学习笔记(5)

          本文链接:https://www.haomeiwen.com/subject/eftbqrtx.html