【Linux C/C++编写】libusb库处理-获取USB设备信息

前言

        USB设备比较常见,lisusb是开源的USB操作库,多个平台都可用(python也封装有libusb模块),以下分享linux下的USB消息获取。

关联博文

https://blog.csdn.net/liangyuna8787/article/details/153978124?spm=1001.2014.3001.5502https://blog.csdn.net/liangyuna8787/article/details/153978124?spm=1001.2014.3001.5502 之前分享了在Linux下,响应插入/拔插USB设备事件,但推送的信息不够详细,以下通过libusb库获取详细的信息。

获取USB设备信息

函数名称

所属类别

功能描述

返回值说明

使用场景

libusb_init()

库初始化

初始化 libusb 库,创建上下文

0 成功,<0 错误码

程序启动时初始化 USB 库

libusb_exit()

库清理

清理 libusb 资源,关闭上下文

程序退出时清理资源

libusb_open_device_with_vid_pid()

设备操作

通过 VID/PID 打开指定设备

设备句柄或 NULL

根据厂商ID和产品ID打开特定设备

libusb_get_device()

设备信息

从设备句柄获取设备对象

对应的设备对象

获取设备基本信息时需要

libusb_get_device_descriptor()

设备描述符

获取设备描述符信息

0 成功,<0 错误码

读取设备的基本信息(VID/PID等)

libusb_close()

设备操作

关闭 USB 设备句柄

设备使用完毕后释放资源

libusb_get_device_list()

设备枚举

获取系统中所有 USB 设备列表

设备数量或错误码

枚举所有连接的 USB 设备

libusb_free_device_list()

资源释放

释放设备列表占用的内存

设备列表使用完毕后清理内存

libusb_open()

设备操作

打开指定的 USB 设备

0 成功,<0 错误码

打开特定设备进行通信

libusb_get_string_descriptor_ascii()

字符串操作

获取字符串描述符(ASCII格式)

实际读取长度或错误码

读取设备名称、厂商信息等字符串

libusb_get_bus_number()

拓扑信息

获取设备所在的总线号

总线编号

设备定位和识别

libusb_get_device_address()

拓扑信息

获取设备在总线上的地址

设备地址

设备定位和识别

libusb_get_config_descriptor()

配置描述符

获取设备的配置描述符

0 成功,<0 错误码

读取设备的接口和端点配置信息

libusb_free_config_descriptor()

资源释放

释放配置描述符内存

配置描述符使用完毕后清理内存

下面提供打包为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

输出如下:

posted @ 2026-01-25 13:27  clnchanpin  阅读(5)  评论(0)    收藏  举报