libusb设备描述符解析实战:从struct libusb_device_descriptor到接口配置
引言:USB设备识别的痛点与解决方案
你是否曾在开发USB设备应用时,面对复杂的设备描述符结构感到困惑?是否在解析USB设备信息时,因不了解描述符层级关系而无从下手?本文将系统讲解libusb中设备描述符的解析方法,从基础的设备描述符(struct libusb_device_descriptor)到复杂的接口配置,帮助你全面掌握USB设备信息的获取与解析技巧。
读完本文,你将能够:
- 理解USB描述符的层级结构及各字段含义
- 掌握使用libusb获取设备描述符的方法
- 解析配置描述符、接口描述符和端点描述符
- 处理设备字符串描述符,获取厂商、产品等信息
- 编写实用的USB设备枚举工具
USB描述符层级结构概述
USB设备描述符采用层级结构组织,从设备到配置,再到接口和端点,形成一个清晰的树形结构。libusb通过一系列结构体来表示这些描述符,主要包括:
USB描述符类型与关系
USB设备描述符体系包含以下主要类型,它们之间形成层级关系:
- 设备描述符(Device Descriptor):最高层级,描述设备的整体信息
- 配置描述符(Configuration Descriptor):描述设备的配置信息,一个设备可以有多个配置
- 接口描述符(Interface Descriptor):描述设备的功能接口,一个配置可以包含多个接口
- 端点描述符(Endpoint Descriptor):描述接口的通信端点,一个接口可以有多个端点
- 字符串描述符(String Descriptor):描述设备的文本信息,如厂商名称、产品名称等
设备描述符(struct libusb_device_descriptor)详解
设备描述符是USB设备的顶层描述符,包含了设备的基本信息。在libusb中,设备描述符由struct libusb_device_descriptor结构体表示。
结构体定义与字段说明
struct libusb_device_descriptor {
uint8_t bLength; // 描述符长度(字节)
uint8_t bDescriptorType; // 描述符类型(LIBUSB_DT_DEVICE)
uint16_t bcdUSB; // USB规范版本号(BCD码)
uint8_t bDeviceClass; // 设备类代码
uint8_t bDeviceSubClass; // 设备子类代码
uint8_t bDeviceProtocol; // 设备协议代码
uint8_t bMaxPacketSize0; // 端点0最大数据包大小
uint16_t idVendor; // 厂商ID
uint16_t idProduct; // 产品ID
uint16_t bcdDevice; // 设备版本号(BCD码)
uint8_t iManufacturer; // 厂商字符串描述符索引
uint8_t iProduct; // 产品字符串描述符索引
uint8_t iSerialNumber; // 序列号字符串描述符索引
uint8_t bNumConfigurations; // 配置数量
};
重要字段解析
| 字段名 | 长度 | 说明 | 示例值 |
|---|---|---|---|
| bLength | 1字节 | 描述符长度,固定为18字节 | 0x12 |
| bDescriptorType | 1字节 | 描述符类型,设备描述符固定为0x01 | LIBUSB_DT_DEVICE |
| bcdUSB | 2字节 | USB规范版本号,BCD码 | 0x0200表示USB 2.0 |
| bDeviceClass | 1字节 | 设备类代码 | 0x00表示每个接口独立指定类 |
| idVendor | 2字节 | 厂商ID,由USB-IF分配 | 0x0483(STMicroelectronics) |
| idProduct | 2字节 | 产品ID,由厂商分配 | 0x5740(STM32 USB设备) |
| bNumConfigurations | 1字节 | 设备支持的配置数量 | 0x01表示1个配置 |
获取设备描述符的方法
使用libusb获取设备描述符的基本步骤:
// 初始化libusb上下文
libusb_init(NULL);
// 获取设备列表
libusb_device **devs;
ssize_t cnt = libusb_get_device_list(NULL, &devs);
// 遍历设备列表
for (ssize_t i = 0; i < cnt; i++) {
libusb_device *dev = devs[i];
// 获取设备描述符
struct libusb_device_descriptor desc;
int r = libusb_get_device_descriptor(dev, &desc);
if (r < 0) {
fprintf(stderr, "获取设备描述符失败: %d\n", r);
continue;
}
// 解析设备描述符信息
printf("厂商ID: 0x%04x, 产品ID: 0x%04x\n", desc.idVendor, desc.idProduct);
// ... 解析其他字段
}
// 释放设备列表
libusb_free_device_list(devs, 1);
// 退出libusb
libusb_exit(NULL);
配置描述符(struct libusb_config_descriptor)解析
配置描述符描述了USB设备的一个特定配置,包括该配置下的接口数量、电源需求等信息。一个USB设备可以有多个配置,但同一时间只能激活一个配置。
结构体定义与字段说明
struct libusb_config_descriptor {
uint8_t bLength; // 描述符长度
uint8_t bDescriptorType; // 描述符类型(LIBUSB_DT_CONFIG)
uint16_t wTotalLength; // 配置描述符总长度(包括接口和端点描述符)
uint8_t bNumInterfaces; // 接口数量
uint8_t bConfigurationValue; // 配置值(用于选择此配置)
uint8_t iConfiguration; // 配置字符串描述符索引
uint8_t bmAttributes; // 配置特性
uint8_t MaxPower; // 最大功耗(单位:2mA)
// 接口数组,长度由bNumInterfaces决定
const struct libusb_interface *interface;
// 额外描述符
const unsigned char *extra;
int extra_length;
};
配置特性(bmAttributes)解析
配置特性字段bmAttributes是一个8位标志,用于描述配置的电源管理特性:
| 位 | 说明 |
|---|---|
| D7 | 必须为1,表示总线供电 |
| D6 | 1表示自供电,0表示总线供电 |
| D5 | 1表示远程唤醒,0表示不支持远程唤醒 |
| D4-D0 | 保留,必须为0 |
最大功耗(MaxPower)计算
MaxPower字段表示设备在该配置下的最大功耗,单位为2mA。例如:
- MaxPower = 0x32(50)表示最大功耗为50 × 2mA = 100mA
- MaxPower = 0xFA(250)表示最大功耗为250 × 2mA = 500mA(USB 2.0设备的最大允许功耗)
获取配置描述符的方法
// 假设已经获取了设备列表和设备描述符
libusb_device *dev = devs[i];
struct libusb_device_descriptor desc;
libusb_get_device_descriptor(dev, &desc);
// 打开设备
libusb_device_handle *handle;
int r = libusb_open(dev, &handle);
if (r < 0) {
fprintf(stderr, "打开设备失败: %d\n", r);
continue;
}
// 获取配置描述符
struct libusb_config_descriptor *config;
r = libusb_get_config_descriptor(dev, 0, &config); // 获取第一个配置
if (r < 0) {
fprintf(stderr, "获取配置描述符失败: %d\n", r);
libusb_close(handle);
continue;
}
// 解析配置描述符信息
printf("配置数量: %d, 接口数量: %d\n", desc.bNumConfigurations, config->bNumInterfaces);
printf("最大功耗: %dmA\n", config->MaxPower * 2);
// 释放配置描述符
libusb_free_config_descriptor(config);
// 关闭设备
libusb_close(handle);
接口描述符与端点描述符详解
接口描述符(struct libusb_interface_descriptor)
接口描述符描述了USB设备配置中的一个功能接口。一个配置可以包含多个接口,每个接口代表设备的一个独立功能。
struct libusb_interface_descriptor {
uint8_t bLength; // 描述符长度
uint8_t bDescriptorType; // 描述符类型(LIBUSB_DT_INTERFACE)
uint8_t bInterfaceNumber; // 接口号
uint8_t bAlternateSetting; // 备用设置号
uint8_t bNumEndpoints; // 端点数(不包括端点0)
uint8_t bInterfaceClass; // 接口类代码
uint8_t bInterfaceSubClass; // 接口子类代码
uint8_t bInterfaceProtocol; // 接口协议代码
uint8_t iInterface; // 接口字符串描述符索引
// 端点数组,长度由bNumEndpoints决定
const struct libusb_endpoint_descriptor *endpoint;
// 额外描述符
const unsigned char *extra;
int extra_length;
};
接口类代码(bInterfaceClass)是识别接口功能的重要依据,常见值包括:
| 类代码 | 说明 |
|---|---|
| 0x00 | 接口类由端点或接口描述符指定 |
| 0x01 | 音频类 |
| 0x02 | 通信类 |
| 0x03 | 人机接口设备类(HID) |
| 0x06 | 图像类(如扫描仪) |
| 0x07 | 打印机类 |
| 0x08 | 大容量存储类 |
| 0x09 | 集线器类 |
| 0x0A | CDC数据类 |
| 0xFF | 厂商特定类 |
端点描述符(struct libusb_endpoint_descriptor)
端点描述符描述了接口的通信端点,包括端点地址、传输类型、最大数据包大小等信息。
struct libusb_endpoint_descriptor {
uint8_t bLength; // 描述符长度
uint8_t bDescriptorType; // 描述符类型(LIBUSB_DT_ENDPOINT)
uint8_t bEndpointAddress; // 端点地址
uint8_t bmAttributes; // 端点属性
uint16_t wMaxPacketSize; // 最大数据包大小
uint8_t bInterval; // 轮询间隔(单位:ms)
uint8_t bRefresh; // 音频设备专用:刷新速率
uint8_t bSynchAddress; // 音频设备专用:同步端点地址
// 额外描述符
const unsigned char *extra;
int extra_length;
};
端点地址(bEndpointAddress)解析
端点地址是一个8位字段,格式如下:
- 位7:方向,0=输出端点(主机到设备),1=输入端点(设备到主机)
- 位6-4:保留
- 位3-0:端点号(0-15)
示例:
- 0x01:端点1,输出端点
- 0x81:端点1,输入端点
端点属性(bmAttributes)解析
端点属性字段描述了端点的传输类型和特性:
- 位1-0:传输类型
- 00:控制传输(Control)
- 01:等时传输(Isochronous)
- 10:批量传输(Bulk)
- 11:中断传输(Interrupt)
- 位3-2:同步类型(仅用于等时传输)
- 位5-4:用法类型(仅用于等时传输)
- 位7-6:保留
最大数据包大小(wMaxPacketSize)
对于高速(High-Speed)端点,此字段的高两位表示每微帧(125us)可以传输的事务数:
- 低10位:每事务的最大字节数
- 高2位:事务数减1(00=1事务,01=2事务,10=3事务)
示例:0x0200表示每微帧2个事务,每个事务最大256字节,总容量为512字节/微帧。
字符串描述符解析
字符串描述符包含了设备的文本信息,如厂商名称、产品名称和序列号等,以UTF-16LE编码表示。
常见的字符串描述符类型
| 索引 | 描述 |
|---|---|
| iManufacturer | 厂商名称字符串索引 |
| iProduct | 产品名称字符串索引 |
| iSerialNumber | 序列号字符串索引 |
| iConfiguration | 配置名称字符串索引 |
| iInterface | 接口名称字符串索引 |
获取字符串描述符的方法
// 假设已经打开设备,获取了设备句柄handle
char manufacturer[256], product[256], serial[256];
// 获取厂商名称
if (desc.iManufacturer) {
int r = libusb_get_string_descriptor_ascii(handle, desc.iManufacturer,
(unsigned char*)manufacturer, sizeof(manufacturer));
if (r > 0) {
printf("厂商: %s\n", manufacturer);
}
}
// 获取产品名称
if (desc.iProduct) {
int r = libusb_get_string_descriptor_ascii(handle, desc.iProduct,
(unsigned char*)product, sizeof(product));
if (r > 0) {
printf("产品: %s\n", product);
}
}
// 获取序列号
if (desc.iSerialNumber) {
int r = libusb_get_string_descriptor_ascii(handle, desc.iSerialNumber,
(unsigned char*)serial, sizeof(serial));
if (r > 0) {
printf("序列号: %s\n", serial);
}
}
实战:USB设备枚举与描述符解析工具
下面我们将综合运用前面所学知识,编写一个完整的USB设备枚举与描述符解析工具,该工具能够:
- 列出系统中的所有USB设备
- 显示设备描述符信息
- 解析配置、接口和端点描述符
- 获取并显示字符串描述符
完整代码实现
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <libusb.h>
// USB设备类代码到名称的映射
const char* usb_class_to_string(uint8_t class_code) {
switch (class_code) {
case 0x00: return "设备定义的类";
case 0x01: return "音频类";
case 0x02: return "通信类";
case 0x03: return "人机接口设备类(HID)";
case 0x05: return "物理类";
case 0x06: return "图像类";
case 0x07: return "打印机类";
case 0x08: return "大容量存储类";
case 0x09: return "集线器类";
case 0x0A: return "CDC数据类";
case 0x0B: return "智能卡类";
case 0x0D: return "内容安全类";
case 0x0E: return "视频类";
case 0x0F: return "个人医疗类";
case 0xDC: return "诊断设备类";
case 0xE0: return "无线控制器类";
case 0xEF: return "杂项类";
case 0xFE: return "应用类";
case 0xFF: return "厂商特定类";
default: return "未知类";
}
}
// USB传输类型到名称的映射
const char* transfer_type_to_string(uint8_t attributes) {
switch (attributes & 0x03) {
case 0x00: return "控制传输";
case 0x01: return "等时传输";
case 0x02: return "批量传输";
case 0x03: return "中断传输";
default: return "未知传输类型";
}
}
// 打印设备描述符信息
void print_device_descriptor(struct libusb_device_descriptor *desc) {
printf("===== 设备描述符信息 =====\n");
printf("USB版本: %d.%d\n", (desc->bcdUSB >> 8), (desc->bcdUSB & 0xFF));
printf("设备类: 0x%02X (%s)\n", desc->bDeviceClass, usb_class_to_string(desc->bDeviceClass));
printf("子类: 0x%02X, 协议: 0x%02X\n", desc->bDeviceSubClass, desc->bDeviceProtocol);
printf("端点0最大数据包大小: %d bytes\n", desc->bMaxPacketSize0);
printf("厂商ID: 0x%04X, 产品ID: 0x%04X\n", desc->idVendor, desc->idProduct);
printf("设备版本: %d.%d\n", (desc->bcdDevice >> 8), (desc->bcdDevice & 0xFF));
printf("配置数量: %d\n", desc->bNumConfigurations);
printf("==========================\n");
}
// 打印配置描述符信息
void print_config_descriptor(struct libusb_config_descriptor *config) {
printf("\n===== 配置描述符信息 (配置值: %d) =====\n", config->bConfigurationValue);
printf("总长度: %d bytes\n", config->wTotalLength);
printf("接口数量: %d\n", config->bNumInterfaces);
// 解析配置特性
printf("配置特性: 0x%02X\n", config->bmAttributes);
printf(" - 自供电: %s\n", (config->bmAttributes & 0x40) ? "是" : "否");
printf(" - 远程唤醒: %s\n", (config->bmAttributes & 0x20) ? "是" : "否");
// 计算最大功耗
printf("最大功耗: %dmA\n", config->MaxPower * 2);
printf("=======================================\n");
}
// 打印接口和端点描述符信息
void print_interface_descriptors(struct libusb_config_descriptor *config) {
for (int i = 0; i < config->bNumInterfaces; i++) {
const struct libusb_interface *interface = &config->interface[i];
for (int j = 0; j < interface->num_altsetting; j++) {
const struct libusb_interface_descriptor *if_desc = &interface->altsetting[j];
printf("\n===== 接口描述符信息 (接口号: %d, 备用设置: %d) =====\n",
if_desc->bInterfaceNumber, if_desc->bAlternateSetting);
printf("接口类: 0x%02X (%s)\n", if_desc->bInterfaceClass, usb_class_to_string(if_desc->bInterfaceClass));
printf("子类: 0x%02X, 协议: 0x%02X\n", if_desc->bInterfaceSubClass, if_desc->bInterfaceProtocol);
printf("端点数: %d\n", if_desc->bNumEndpoints);
printf("===============================================\n");
// 打印端点信息
for (int k = 0; k < if_desc->bNumEndpoints; k++) {
const struct libusb_endpoint_descriptor *ep_desc = &if_desc->endpoint[k];
printf("\n--- 端点描述符 %d ---\n", k+1);
printf("端点地址: 0x%02X\n", ep_desc->bEndpointAddress);
printf(" - 方向: %s\n", (ep_desc->bEndpointAddress & 0x80) ? "输入(设备到主机)" : "输出(主机到设备)");
printf(" - 端点号: %d\n", (ep_desc->bEndpointAddress & 0x0F));
printf("传输类型: %s\n", transfer_type_to_string(ep_desc->bmAttributes));
// 对于等时传输,解析同步类型和用法类型
if ((ep_desc->bmAttributes & 0x03) == 0x01) {
uint8_t sync_type = (ep_desc->bmAttributes >> 2) & 0x03;
uint8_t usage_type = (ep_desc->bmAttributes >> 4) & 0x03;
printf("同步类型: ");
switch (sync_type) {
case 0: printf("无同步"); break;
case 1: printf("异步"); break;
case 2: printf("自适应"); break;
case 3: printf("同步"); break;
default: printf("未知");
}
printf("\n");
printf("用法类型: ");
switch (usage_type) {
case 0: printf("数据端点"); break;
case 1: printf("反馈端点"); break;
case 2: printf("隐式反馈数据端点"); break;
default: printf("未知");
}
printf("\n");
}
// 解析最大数据包大小
printf("最大数据包大小: %d bytes\n", ep_desc->wMaxPacketSize & 0x07FF);
// 对于高速端点,显示每微帧的事务数
if ((ep_desc->wMaxPacketSize & 0x0800) && ((ep_desc->bmAttributes & 0x03) == 0x02)) {
int transactions = ((ep_desc->wMaxPacketSize >> 11) & 0x03) + 1;
printf("每微帧事务数: %d\n", transactions);
}
printf("轮询间隔: %dms\n", ep_desc->bInterval);
printf("-------------------------\n");
}
}
}
}
// 获取并打印字符串描述符
void print_string_descriptors(libusb_device_handle *handle, struct libusb_device_descriptor *desc) {
char buffer[256];
printf("\n===== 字符串描述符信息 =====\n");
// 获取厂商名称
if (desc->iManufacturer) {
int r = libusb_get_string_descriptor_ascii(handle, desc->iManufacturer,
(unsigned char*)buffer, sizeof(buffer));
if (r > 0) {
printf("厂商名称: %s\n", buffer);
} else {
printf("厂商名称: 无法获取\n");
}
} else {
printf("厂商名称: 未提供\n");
}
// 获取产品名称
if (desc->iProduct) {
int r = libusb_get_string_descriptor_ascii(handle, desc->iProduct,
(unsigned char*)buffer, sizeof(buffer));
if (r > 0) {
printf("产品名称: %s\n", buffer);
} else {
printf("产品名称: 无法获取\n");
}
} else {
printf("产品名称: 未提供\n");
}
// 获取序列号
if (desc->iSerialNumber) {
int r = libusb_get_string_descriptor_ascii(handle, desc->iSerialNumber,
(unsigned char*)buffer, sizeof(buffer));
if (r > 0) {
printf("序列号: %s\n", buffer);
} else {
printf("序列号: 无法获取\n");
}
} else {
printf("序列号: 未提供\n");
}
printf("===========================\n");
}
// 枚举并解析USB设备
void enumerate_usb_devices() {
libusb_device **devs;
ssize_t cnt;
// 初始化libusb
int r = libusb_init(NULL);
if (r < 0) {
fprintf(stderr, "libusb初始化失败: %d\n", r);
return;
}
// 获取设备列表
cnt = libusb_get_device_list(NULL, &devs);
if (cnt < 0) {
fprintf(stderr, "获取设备列表失败: %zd\n", cnt);
libusb_exit(NULL);
return;
}
printf("找到 %zd 个USB设备:\n\n", cnt);
// 遍历设备列表
for (ssize_t i = 0; i < cnt; i++) {
libusb_device *dev = devs[i];
struct libusb_device_descriptor desc;
libusb_device_handle *handle = NULL;
// 获取设备描述符
r = libusb_get_device_descriptor(dev, &desc);
if (r < 0) {
fprintf(stderr, "获取设备描述符失败: %d\n", r);
continue;
}
// 打印设备基本信息
printf("=============================================\n");
printf("设备 %zd: 总线 %d, 地址 %d\n", i+1,
libusb_get_bus_number(dev), libusb_get_device_address(dev));
printf("厂商ID: 0x%04X, 产品ID: 0x%04X\n", desc.idVendor, desc.idProduct);
printf("=============================================\n");
// 打印设备描述符详细信息
print_device_descriptor(&desc);
// 打开设备以获取更多信息
r = libusb_open(dev, &handle);
if (r == 0) {
// 获取并打印字符串描述符
print_string_descriptors(handle, &desc);
// 获取并打印配置描述符
for (int j = 0; j < desc.bNumConfigurations; j++) {
struct libusb_config_descriptor *config;
r = libusb_get_config_descriptor(dev, j, &config);
if (r < 0) {
fprintf(stderr, "获取配置描述符 %d 失败: %d\n", j, r);
continue;
}
print_config_descriptor(config);
print_interface_descriptors(config);
// 释放配置描述符
libusb_free_config_descriptor(config);
}
// 关闭设备
libusb_close(handle);
} else {
printf("\n无法打开设备,可能需要root权限或适当的驱动程序\n");
printf("错误代码: %d\n", r);
}
printf("\n-------------------------------------------------\n\n");
}
// 释放设备列表
libusb_free_device_list(devs, 1);
// 退出libusb
libusb_exit(NULL);
}
int main(int argc, char *argv[]) {
enumerate_usb_devices();
return 0;
}
代码解析与使用说明
上述代码实现了一个完整的USB设备枚举与描述符解析工具,主要功能包括:
- 设备枚举:使用
libusb_get_device_list()获取系统中的USB设备列表 - 设备描述符解析:通过
libusb_get_device_descriptor()获取设备基本信息 - 配置描述符解析:通过
libusb_get_config_descriptor()获取设备配置信息 - 接口和端点解析:遍历配置中的接口和端点描述符
- 字符串描述符解析:使用
libusb_get_string_descriptor_ascii()获取文本信息
编译命令:
gcc -o usb_descriptor_parser usb_descriptor_parser.c -lusb-1.0
使用方法:
# 需要root权限以访问所有设备
sudo ./usb_descriptor_parser
高级应用:基于描述符的设备筛选与配置
在实际应用中,我们通常需要根据设备描述符信息筛选特定设备或配置设备。以下是一些常见的高级应用场景。
根据厂商ID和产品ID筛选设备
// 筛选特定厂商和产品的设备
libusb_device *find_device_by_vid_pid(uint16_t vid, uint16_t pid) {
libusb_device **devs;
ssize_t cnt;
libusb_device *found = NULL;
cnt = libusb_get_device_list(NULL, &devs);
if (cnt < 0) return NULL;
for (ssize_t i = 0; i < cnt; i++) {
libusb_device *dev = devs[i];
struct libusb_device_descriptor desc;
if (libusb_get_device_descriptor(dev, &desc) < 0)
continue;
if (desc.idVendor == vid && desc.idProduct == pid) {
found = dev;
break;
}
}
// 如果找到了设备,增加引用计数,否则释放设备列表
if (found)
libusb_ref_device(found);
else
libusb_free_device_list(devs, 1);
return found;
}
配置设备接口和备用设置
// 配置设备接口和备用设置
int configure_device_interface(libusb_device_handle *handle, int interface_num, int alt_setting) {
// 首先分离内核驱动(如果存在)
int r = libusb_kernel_driver_active(handle, interface_num);
if (r == 1) {
r = libusb_detach_kernel_driver(handle, interface_num);
if (r < 0 && r != LIBUSB_ERROR_NOT_SUPPORTED) {
fprintf(stderr, "分离内核驱动失败: %d\n", r);
return r;
}
}
// 声明接口
r = libusb_claim_interface(handle, interface_num);
if (r < 0) {
fprintf(stderr, "声明接口失败: %d\n", r);
return r;
}
// 设置备用设置
if (alt_setting > 0) {
r = libusb_set_interface_alt_setting(handle, interface_num, alt_setting);
if (r < 0) {
fprintf(stderr, "设置备用设置失败: %d\n", r);
libusb_release_interface(handle, interface_num);
return r;
}
}
return 0;
}
常见问题与解决方案
权限问题
问题:无法打开设备,错误代码为LIBUSB_ERROR_ACCESS(-3) 解决方案:
- 使用root权限运行程序
- 创建udev规则文件(/etc/udev/rules.d/99-usb-device.rules),添加设备权限:
SUBSYSTEM=="usb", ATTR{idVendor}=="0483", ATTR{idProduct}=="5740", MODE="0666" - 重新加载udev规则:
sudo udevadm control --reload-rules && sudo udevadm trigger
内核驱动冲突
问题:设备被内核驱动占用,无法访问端点 解决方案:
- 使用
libusb_kernel_driver_active()检查驱动是否激活 - 使用
libusb_detach_kernel_driver()分离内核驱动 - 操作完成后使用
libusb_attach_kernel_driver()重新附加驱动
描述符解析错误
问题:获取描述符失败或解析结果异常 解决方案:
- 检查libusb版本是否支持设备的USB规范版本
- 验证设备是否正常工作,尝试更换USB端口或线缆
- 使用
libusb_get_string_descriptor()替代ASCII版本,处理非ASCII字符
总结与展望
本文详细介绍了libusb中设备描述符的层级结构和解析方法,从设备描述符到配置、接口和端点描述符,全面覆盖了USB设备信息的获取与解析技巧。通过实际代码示例,展示了如何使用libusb库函数来枚举设备、获取描述符和解析设备信息。
掌握USB描述符解析是开发USB设备应用的基础,后续可以进一步学习:
- USB控制传输:使用控制端点与设备进行配置和管理交互
- 批量/中断传输:实现设备与主机之间的高速数据传输
- 异步I/O操作:提高USB数据传输的效率和响应性
- 热插拔检测:实时监测USB设备的连接和断开事件
通过深入理解USB描述符和libusb库的使用,你将能够开发出功能强大的USB设备应用程序,满足各种USB设备的通信需求。
参考资料
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



