libusb学习笔记(5)

2021-12-29  本文已影响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$ 
上一篇下一篇

猜你喜欢

热点阅读