【Linux C/C++编写】libusb库处理-获取USB设备信息
前言
USB设备比较常见,lisusb是开源的USB操作库,多个平台都可用(python也封装有libusb模块),以下分享linux下的USB消息获取。
关联博文
https://blog.csdn.net/liangyuna8787/article/details/153978124?spm=1001.2014.3001.5502
https://blog.csdn.net/liangyuna8787/article/details/153978124?spm=1001.2014.3001.5502 之前分享了在Linux下,响应插入/拔插USB设备事件,但推送的信息不够详细,以下通过libusb库获取详细的信息。
获取USB设备信息
函数名称 | 所属类别 | 功能描述 | 返回值说明 | 使用场景 |
|---|---|---|---|---|
| 库初始化 | 初始化 libusb 库,创建上下文 | 0 成功,<0 错误码 | 程序启动时初始化 USB 库 |
| 库清理 | 清理 libusb 资源,关闭上下文 | 无 | 程序退出时清理资源 |
| 设备操作 | 通过 VID/PID 打开指定设备 | 设备句柄或 NULL | 根据厂商ID和产品ID打开特定设备 |
| 设备信息 | 从设备句柄获取设备对象 | 对应的设备对象 | 获取设备基本信息时需要 |
| 设备描述符 | 获取设备描述符信息 | 0 成功,<0 错误码 | 读取设备的基本信息(VID/PID等) |
| 设备操作 | 关闭 USB 设备句柄 | 无 | 设备使用完毕后释放资源 |
| 设备枚举 | 获取系统中所有 USB 设备列表 | 设备数量或错误码 | 枚举所有连接的 USB 设备 |
| 资源释放 | 释放设备列表占用的内存 | 无 | 设备列表使用完毕后清理内存 |
| 设备操作 | 打开指定的 USB 设备 | 0 成功,<0 错误码 | 打开特定设备进行通信 |
| 字符串操作 | 获取字符串描述符(ASCII格式) | 实际读取长度或错误码 | 读取设备名称、厂商信息等字符串 |
| 拓扑信息 | 获取设备所在的总线号 | 总线编号 | 设备定位和识别 |
| 拓扑信息 | 获取设备在总线上的地址 | 设备地址 | 设备定位和识别 |
| 配置描述符 | 获取设备的配置描述符 | 0 成功,<0 错误码 | 读取设备的接口和端点配置信息 |
| 资源释放 | 释放配置描述符内存 | 无 | 配置描述符使用完毕后清理内存 |
下面提供打包为so动态库的源码,动态库提供了两个核心功能:通过vidpid获取USB设备信息和获取区别USB设备信息
//USBDeviceInfo.h
#ifndef USB_DEVICE_INFO_H
#define USB_DEVICE_INFO_H
#include
#include
#include
#include
#ifdef __cplusplus
extern "C" {
#endif
//USB设备信息结构体
typedef struct UsbMsg {
uint16_t vid; //厂商ID
uint16_t pid; //产品ID
uint8_t Bus; //总线号
uint8_t Device; //设备地址
std::set subclass_set; //设备子类集合
std::string name; //设备名称
uint16_t Version; //USB版本
} stUsbMsg;
void* create_usb_device_info();
void destroy_usb_device_info(void* obj);
bool usb_device_info_initialize(void* obj);
void usb_device_info_cleanup(void* obj);
stUsbMsg usb_device_info_get_device_info(void* obj, uint16_t vendorId, uint16_t productId);
void usb_device_info_get_all_devices(void* obj, stUsbMsg** devices, size_t* count);
void free_usb_devices_array(stUsbMsg* devices, size_t count);
const char* usb_device_info_get_class_name(void* obj, uint8_t class_code);
#ifdef __cplusplus
}
#endif
#endif //USB_DEVICE_INFO_H
// USBDeviceInfo.cpp
#include "USBDeviceInfo.h"
#include
#include
#include
#include
#include
// USB设备信息实现类
class USBDeviceInfoImpl {
public:
// 构造函数:初始化上下文为nullptr
USBDeviceInfoImpl() : context(nullptr) {}
// 析构函数:自动清理资源
~USBDeviceInfoImpl() {
cleanup();
}
// 根据设备类代码获取设备类名称
const std::string get_device_class_name(uint8_t class_code) {
switch (class_code) {
case 0x00: return "接口定义类"; // 设备类在接口描述符中定义
case 0x01: return "音频设备"; // 音频设备类
case 0x02: return "通信设备"; // 通信设备类(CDC)
case 0x03: return "HID设备"; // 人机接口设备
case 0x05: return "物理设备"; // 物理设备类
case 0x06: return "图像设备"; // 图像设备类(如摄像头)
case 0x07: return "打印机"; // 打印机设备类
case 0x08: return "大容量存储设备"; // 大容量存储设备(U盘、移动硬盘)
case 0x09: return "集线器"; // USB集线器
case 0x0A: return "CDC数据设备"; // CDC数据设备
case 0x0B: return "智能卡设备"; // 智能卡读卡器
case 0x0D: return "内容安全设备"; // 内容安全设备
case 0x0E: return "视频设备"; // 视频设备类
case 0x0F: return "个人医疗设备"; // 个人医疗设备
case 0x10: return "音频/视频设备"; // 音频视频设备类
case 0xDC: return "诊断设备"; // 诊断设备类
case 0xE0: return "无线控制器"; // 无线控制器(蓝牙、WiFi等)
case 0xEF: return "杂项设备"; // 杂项设备类
case 0xFE: return "特定应用设备"; // 特定应用设备
case 0xFF: return "厂商自定义设备"; // 厂商自定义设备类
default: return "未知设备类"; // 未知的设备类代码
}
}
// 初始化libusb库
bool initialize() {
// 初始化libusb上下文
int result = libusb_init(&context);
if (result != 0) {
std::cerr << "初始化libusb失败: " << libusb_error_name(result) << std::endl;
return false;
}
return true;
}
// 清理libusb资源
void cleanup() {
if (context) {
libusb_exit(context); // 释放libusb上下文
context = nullptr; // 重置指针为空
}
}
// 根据VID和PID获取特定设备信息
stUsbMsg getDeviceInfo(uint16_t vendorId, uint16_t productId) {
stUsbMsg result; // 创建返回结果结构体
// 通过VID和PID打开设备
libusb_device_handle* deviceHandle = libusb_open_device_with_vid_pid(context, vendorId, productId);
if (!deviceHandle) {
return result; // 打开失败返回空结果
}
// 获取设备对象
libusb_device* device = libusb_get_device(deviceHandle);
libusb_device_descriptor descriptor;
// 获取设备描述符
int ret = libusb_get_device_descriptor(device, &descriptor);
if (ret == 0) {
// 成功获取描述符,格式化设备信息
result = formatDeviceInfo(deviceHandle, descriptor, device);
}
// 关闭设备句柄
libusb_close(deviceHandle);
return result;
}
// 获取系统中所有USB设备信息
std::vector getAllDevices() {
std::vector devices; // 设备信息列表
libusb_device** deviceList; // 设备列表指针
// 获取USB设备列表
ssize_t count = libusb_get_device_list(context, &deviceList);
if (count < 0) {
return devices; // 获取失败返回空列表
}
// 遍历所有设备
for (ssize_t i = 0; i < count; ++i) {
libusb_device_descriptor desc;
// 获取设备描述符
if (libusb_get_device_descriptor(deviceList[i], &desc) == 0) {
libusb_device_handle* handle;
// 打开设备以获取更多信息
if (libusb_open(deviceList[i], &handle) == 0) {
// 格式化设备信息并添加到列表
devices.push_back(formatDeviceInfo(handle, desc, deviceList[i]));
libusb_close(handle); // 关闭设备句柄
}
}
}
// 释放设备列表内存
libusb_free_device_list(deviceList, 1);
return devices;
}
private:
libusb_context* context; // libusb上下文指针
// 将16位数值转换为16进制字符串(4位宽度)
std::string toHex(uint16_t value) {
std::stringstream ss;
ss << std::hex << std::setw(4) << std::setfill('0') << value;
return ss.str();
}
// 获取字符串描述符
std::string getStringDescriptor(libusb_device_handle* handle, uint8_t index) {
if (index == 0) return ""; // 索引为0表示无字符串描述符
unsigned char buffer[256]; // 字符串缓冲区
// 获取ASCII格式的字符串描述符
int length = libusb_get_string_descriptor_ascii(handle, index, buffer, sizeof(buffer));
if (length > 0) {
// 成功获取字符串,转换为std::string
return std::string(reinterpret_cast(buffer), length);
}
return ""; // 获取失败返回空字符串
}
// 格式化设备信息为stUsbMsg结构
stUsbMsg formatDeviceInfo(libusb_device_handle* handle, const libusb_device_descriptor& desc, libusb_device* dev) {
std::set subclass_set; // 子类集合(去重)
subclass_set.clear();
stUsbMsg result; // 返回结果结构体
// 获取总线号和设备地址
result.Bus = libusb_get_bus_number(dev);
result.Device = libusb_get_device_address(dev);
// 获取USB版本、厂商ID、产品ID
result.Version = desc.bcdUSB;
result.vid = desc.idVendor;
result.pid = desc.idProduct;
// 尝试获取设备名称(按优先级:制造商→产品→序列号)
std::string usbname = getStringDescriptor(handle, desc.iManufacturer);
if(usbname == "") usbname = getStringDescriptor(handle, desc.iProduct);
if(usbname == "") usbname = getStringDescriptor(handle, desc.iSerialNumber);
result.name = usbname;
// 获取配置描述符以分析接口信息
libusb_config_descriptor* config;
int ret = libusb_get_config_descriptor(dev, 0, &config); // 获取第一个配置
if (ret == 0 && config) {
// 遍历所有接口
for (int i = 0; i < config->bNumInterfaces; i++) {
const libusb_interface* interface = &config->interface[i];
// 遍历接口的所有备用设置
for (int j = 0; j < interface->num_altsetting; j++) {
const libusb_interface_descriptor* iface_desc = &interface->altsetting[j];
uint8_t subclass = iface_desc->bInterfaceClass; // 获取接口类代码
subclass_set.insert(subclass); // 添加到集合(自动去重)
}
}
// 释放配置描述符内存
libusb_free_config_descriptor(config);
}
// 设置子类集合
result.subclass_set = subclass_set;
return result;
}
};
// C风格接口实现(用于C语言或其他语言调用)
extern "C" {
// 创建USB设备信息对象
void* create_usb_device_info() {
return new USBDeviceInfoImpl(); // 返回新创建的对象指针
}
// 销毁USB设备信息对象
void destroy_usb_device_info(void* obj) {
delete static_cast(obj); // 删除对象并释放内存
}
// 初始化USB设备信息库
bool usb_device_info_initialize(void* obj) {
return static_cast(obj)->initialize();
}
// 清理USB设备信息库资源
void usb_device_info_cleanup(void* obj) {
static_cast(obj)->cleanup();
}
// 根据VID和PID获取特定设备信息
stUsbMsg usb_device_info_get_device_info(void* obj, uint16_t vendorId, uint16_t productId) {
return static_cast(obj)->getDeviceInfo(vendorId, productId);
}
// 获取所有USB设备信息(返回数组形式)
void usb_device_info_get_all_devices(void* obj, stUsbMsg** devices, size_t* count) {
// 获取设备列表vector
std::vector devList = static_cast(obj)->getAllDevices();
*count = devList.size(); // 设置设备数量
// 动态分配数组内存
*devices = new stUsbMsg[*count];
// 将vector内容复制到数组
for (size_t i = 0; i < *count; ++i) {
(*devices)[i] = devList[i];
}
}
// 释放USB设备信息数组内存
void free_usb_devices_array(stUsbMsg* devices, size_t count) {
delete[] devices; // 释放动态分配的数组
}
// 根据设备类代码获取类名称(C字符串形式)
const char* usb_device_info_get_class_name(void* obj, uint8_t class_code) {
static std::string result; // 静态变量保证返回的C字符串有效
result = static_cast(obj)->get_device_class_name(class_code);
return result.c_str(); // 返回C风格字符串
}
} // extern "C"
makefile文件内容如下:
DEBUG_FLAGS= -fPIC -g -D__MUTEX
LIB_FLAGS=
SO_OBJ=libusbDevinfo.so
CC=g++
$(SO_OBJ):USBDeviceInfo.cpp
$(CC) -shared -o $(SO_OBJ) USBDeviceInfo.cpp $(DEBUG_FLAGS) $(LIB_FLAGS)
.PHONEY:clean
clean:
rm *.so *.o $(SO_OBJ) -f
执行make之后,生成动态库libusbDevinfo.so,下面是引用libusbDevinfo.so的示例代码:
//main.cpp
#include "USBDeviceInfo.h"
#include
#include
#include
void show_device_info(const stUsbMsg& device) {
std::cout << "┌─ USB设备信息" << std::endl;
std::cout << "├─ 厂商ID: 0x" << std::hex << std::setw(4) << std::setfill('0') << device.vid << std::endl;
std::cout << "├─ 产品ID: 0x" << std::hex << std::setw(4) << std::setfill('0') << device.pid << std::endl;
std::cout << "├─ 总线号: " << std::dec << static_cast(device.Bus) << std::endl;
std::cout << "├─ 设备地址: " << static_cast(device.Device) << std::endl;
//显示USB版本
uint16_t usbVersion = device.Version;
uint8_t majorVersion = (usbVersion >> 8) & 0xFF;
uint8_t minorVersion = usbVersion & 0xFF;
std::cout << "├─ USB版本: " << static_cast(majorVersion) << "." << static_cast(minorVersion) << std::endl;
std::cout << "├─ 设备名称: " << (device.name.empty() ? "未知" : device.name) << std::endl;
std::cout << "└─ 设备类型: ";
for (const auto& subclass : device.subclass_set) {
std::cout << "0x" << std::hex << std::setw(2) << std::setfill('0') << static_cast(subclass) << " ";
std::cout << std::endl << std::endl;
}
}
int main() {
std::cout << "=== USB设备信息动态库测试 ===" << std::endl;
//创建USB设备信息对象
void* usbInfo = create_usb_device_info();
if (!usbInfo) {
std::cerr << "创建USB设备信息对象失败" << std::endl;
return 1;
}
//初始化
if (!usb_device_info_initialize(usbInfo)) {
std::cerr << "初始化libusb失败" << std::endl;
destroy_usb_device_info(usbInfo);
return 1;
}
std::cout << "\n1. 查询特定设备测试" << std::endl;
std::cout << "----------------------------------------" << std::endl;
//测试查询特定设备
uint16_t targetVid = 0x0BDA; //Realtek
uint16_t targetPid = 0x5161; //示例设备
stUsbMsg device = usb_device_info_get_device_info(usbInfo, targetVid, targetPid);
show_device_info(device);
std::cout << "2. 枚举所有USB设备测试" << std::endl;
std::cout << "----------------------------------------" << std::endl;
//测试枚举所有设备
stUsbMsg* devices = nullptr;
size_t deviceCount = 0;
usb_device_info_get_all_devices(usbInfo, &devices, &deviceCount);
std::cout << "发现 " << deviceCount << " 个USB设备" << std::endl;
for (size_t i = 0; i < deviceCount; ++i) {
std::cout << "设备 " << (i + 1) << ":" << std::endl;
show_device_info(devices[i]);
}
//释放设备数组
free_usb_devices_array(devices, deviceCount);
std::cout << "3. 设备类名称查询测试" << std::endl;
std::cout << "----------------------------------------" << std::endl;
//测试设备类名称查询
uint8_t testClasses[] = {0x03, 0x08, 0x09, 0xFF};
for (auto classCode : testClasses) {
const char* className = usb_device_info_get_class_name(usbInfo, classCode);
std::cout << "设备类 0x" << std::hex << std::setw(2) << std::setfill('0') << static_cast(classCode);
std::cout << ": " << className << std::endl;
}
//清理资源
usb_device_info_cleanup(usbInfo);
destroy_usb_device_info(usbInfo);
std::cout << "=== 测试完成 ===" << std::endl;
return 0;
}
使用以下命令行进行编译:
g++ -o main main.cpp -L. -lusbDevinfo -lusb-1.0
输出如下:

浙公网安备 33010602011771号