【我所认知的BIOS】->PCI enumerate

本文详细介绍了PCI bridge的工作原理,包括PCI总线的Type0和Type1访问方式,以及PCI枚举过程中bus number的分配规则。在枚举过程中,遵循所有位于PCI-PCI bridge后的总线必须在secondary bus number和subordinate bus number之间的原则。通过具体的步骤阐述了PCI bus number的初始化过程,为理解PCI系统提供了清晰的指导。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

PCI enumerate

By Lightseed   

10/06/2010 

 

这篇文章本是很久以前写的,最近感觉比较懒惰今天才贴出来。近两年开始EFI越来越流行了,可以说逐渐有颠覆legacy bios的趋势。处于对知识的渴望和追求我也最近对EFI有了一些简单的了解,我打算在后续的文章中做一个关于EFI的专题,基于EDK来写blog应该不错。毕竟它是开源的嘛,如果以AMI的EFI来写文章我估计可能会涉及到商业机密的问题。希望能像网上那个《linux的那些事儿》那样做成一个一个的小专题。也希望如果有兴趣的朋友或者BIOSER能够和我联系,咱们一起研究哈。期待您的加入。。。先说说我的打算,PCI,IDE等这些比较重要的东西都各自做一个小专题。至于其他的嘛暂时还没想到。形式以code为例子直接加注或者说明。

   

另外之前有关于ACPI的文章,但是看了看,真的觉得没啥好说的,都是架构上的一些东西。估计要说的话,肯能也就要结合到实际的代码,我再斟酌斟酌用什么形式来表达出来会比较好。

1PCI bridge的工作原理

PCI的架构中,引入了PCI bridge的概念来扩展使用更多的PCI设备。其他的基本东西就不多讲了,开门见山先分析在PCI bridge处理总线上访问的原理。

1.1PCI总线的两种方式

PCI总线上有两种访问方式,分别是Type0Type1。且bridge会通过比对自己的secondary bus numbersubordinate bus number后做出后续的反应是type0还是type1的配置。

1.2详细说说type1

当总线上CPU发出了一个访问PCI的动作,(假设说CPU用的是type0的方式,经过bridge1后被其配置成了type1)那么PCI bridge会去做比对,这时就出现了三种情况:

①如果此总线序号不在bridgesecondary bus numbersubordinate bus number之间则忽略掉它。

②如果此总线序号与bridgesecondary bus number相同则将其转换成类型0 配置命令。

③如果此总线序号位于bridgesecondary bus numbersubordinate bus number之间则将它不作改变的传递到二级总线接口中。

总之就是通过这中方式找到PCI总线上的对应的PCI设备,然后访问之~

2PCI 在枚举过程

2.1PCIbus number必须遵循的一个规则

在我们当前的主板上面PCI to PCI bridge是基本上都会有的,整个PCI系统要能够正确地被解析访问到,PCIbus number必须遵循一个规则:

All PCI buses located behind a PCI-PCI bridge must reside between the seondary bus number and the subordinate bus number.

有了这个规则,那么不管是BIOS还是linux在分配PCI bus numbe

bool TaskThread::InitHid() { qDebug() << __FUNCTION__ << "_ID:" << QThread::currentThreadId(); // 初始化 HID 库 res = hid_init(); if (res < 0) { qDebug() << "HID library initialization failed."; return false; } // 获取设备列表 devs = hid_enumerate(0x0, 0x0); // 0x0 表示获取所有设备 if (!devs) { qDebug() << "No HID devices found."; hid_exit(); return false; } // 遍历设备列表 cur_dev = devs; while (cur_dev) { qDebug() << "Device found:"; qDebug() << " Vendor ID: " << cur_dev->vendor_id; qDebug() << " Product ID: " << cur_dev->product_id; qDebug() << " Interface ID: " << cur_dev->interface_number; qDebug() << " Serial Number: " << QString::fromWCharArray(cur_dev->serial_number); qDebug() << " Manufacturer String: " << QString::fromWCharArray(cur_dev->manufacturer_string); qDebug() << " Product String: " << QString::fromWCharArray(cur_dev->product_string); // 根据条件选择设备 if (cur_dev->vendor_id == 0x00C9 && cur_dev->product_id == 0x2766 && cur_dev->interface_number == 1) { // 替换为您的设备的 VID 和 PID qDebug() << "Found target device."; // 打开设备 if (cur_dev->interface_number == 1) { qDebug() << "Found target device 02."; handle = hid_open(cur_dev->vendor_id, cur_dev->product_id, cur_dev->serial_number); hid_set_nonblocking(handle, 1); if (!handle) { qDebug() << "Unable to open device."; hid_free_enumeration(devs); hid_exit(); return false; } emit sig_SendFeedBack(QString(" 找到对应USB设备,并且打开 ").toUtf8()); m_IsModel = ReadData_Model; } qDebug() << "读取数据."; } cur_dev = cur_dev->next; } // 打开指定的 HID 设备(使用设备的 VID 和 PID) // handle = hid_open(0x00C9, 0x2766, nullptr); /
最新发布
03-08
<think>好的,我现在需要帮用户解决关于使用libhidapi初始化和枚举HID设备的代码实现和优化问题。首先,我得回忆一下hidapi的基本用法。用户提到的函数有hid_init、hid_enumerate和hid_open,这些都是hidapi的核心函数。 首先,hid_init负责初始化库,这是必须的第一步。用户可能没有正确调用它,导致后续函数失败。然后,hid_enumerate用来枚举设备,需要指定厂商ID和产品ID,如果设为0的话可能匹配所有设备,但用户可能想具体指定。返回的设备列表需要正确遍历,每个节点包含设备信息,比如路径、厂商ID等。这里需要注意内存管理,使用完后必须释放枚举结果,否则会有内存泄漏。 接下来是hid_open,需要设备路径来打开设备。用户可能遇到的问题是无法打开设备,这时候需要检查路径是否正确,或者是否有权限问题。在Windows下可能需要管理员权限,或者驱动是否正确安装。另外,引用[1]提到SetupAPI.lib的依赖,这可能导致链接错误,需要确保库正确添加。 优化方面,可以考虑重用枚举结果,避免频繁枚举,或者缓存设备信息。另外,错误处理需要加强,比如检查每个函数的返回值,并输出有意义的错误信息。引用[3]中的关闭函数示例提醒我要正确释放资源,避免资源泄漏。 用户的问题可能还涉及跨平台兼容性,hidapi虽然支持多平台,但不同系统的实现可能有差异,比如WindowsLinux的设备路径格式不同。代码中需要处理这些差异,或者使用条件编译。 此外,引用[2]提到设备类的匹配,用户可能在枚举时希望过滤特定类型的设备,比如HID类。这可以通过检查枚举结果中的class类型来实现,或者在枚举时指定参数,但hidapi的枚举函数是否支持直接过滤?可能需要查阅文档确认。 在代码结构上,建议将初始化和枚举逻辑封装成函数,提高复用性。同时,使用智能指针或RAII管理资源,自动释放枚举列表和设备句柄,避免手动管理带来的错误。 常见问题排查方面,权限问题在Linux下常见,需要udev规则或者以root权限运行。Windows下可能需要安装WinUSB驱动,或者使用Zadig工具替换驱动。还有,设备被其他进程占用时无法打开,需要确保独占访问或释放其他占用。 总结下来,我需要提供一个清晰的代码示例,包含初始化、枚举、打开设备的步骤,强调错误处理和资源释放。优化点包括封装函数、资源管理、缓存和错误日志。同时,提醒用户注意平台差异和依赖库的链接。</think>### 分步解答:HID设备初始化和枚举的C++实现与优化 #### 一、基础代码实现 1. **初始化hidapi库** ```cpp #include <hidapi.h> // 初始化库(必须最先调用) if (hid_init() != 0) { std::cerr << "HIDAPI初始化失败" << std::endl; return -1; } ``` 注意:`hid_init()`在所有hidapi函数前调用[^1] 2. **枚举HID设备** ```cpp // 枚举所有HID设备(VID=0x1234, PID=0x5678) hid_device_info* devices = hid_enumerate(0x1234, 0x5678); hid_device_info* current = devices; while (current) { std::cout << "发现设备: " << "VID:" << std::hex << current->vendor_id << " PID:" << current->product_id << " 路径:" << current->path << std::endl; current = current->next; } ``` 参数设为0时匹配所有设备[^2] 3. **打开设备并通信** ```cpp hid_device* handle = hid_open_path(devices->path); if (!handle) { std::cerr << "设备打开失败,错误码: " << hid_error(nullptr) << std::endl; } // 发送数据示例 unsigned char buf[64] = {0}; buf[0] = 0x01; // HID报告ID hid_write(handle, buf, sizeof(buf)); ``` #### 二、关键优化策略 1. **资源管理优化** ```cpp // 使用RAII封装设备句柄 class HIDWrapper { public: HIDWrapper(const char* path) : handle(hid_open_path(path)) {} ~HIDWrapper() { if(handle) hid_close(handle); } // 添加其他成员函数... private: hid_device* handle; }; ``` 2. **错误处理强化** ```cpp void CheckHIDError(hid_device* dev) { const wchar_t* err = hid_error(dev); if (err) { std::wcerr << L"HID错误: " << err << std::endl; } } ``` 3. **枚举缓存优化** ```cpp // 缓存设备信息避免重复枚举 static std::vector<DeviceInfo> cached_devices; void UpdateDeviceCache() { hid_device_info* devices = hid_enumerate(0, 0); // 将设备信息转换为结构体缓存... hid_free_enumeration(devices); } ``` #### 三、常见问题排查 1. **设备无法打开** - 检查设备路径是否正确(不同平台路径格式不同) - Windows需安装WinUSB驱动 - Linux需要配置udev规则: ```bash # /etc/udev/rules.d/99-hid.rules SUBSYSTEM=="usb", MODE="0666" ``` 2. **未定义符号错误** ```makefile # 在编译命令中添加链接库 LDFLAGS += -lhidapi-hidraw -ludev # Linux LDFLAGS += -lhidapi -lsetupapi # Windows ``` 3. **跨平台兼容处理** ```cpp #if defined(_WIN32) #define HID_PATH_PREFIX "\\\\?\\hid#" #else #define HID_PATH_PREFIX "/dev/hidraw" #endif ``` #### 四、引用说明 : Windows环境下需要正确配置SetupAPI.lib库并处理设备驱动兼容性问题 [^2]: 可通过指定设备类(如LIBUSB_CLASS_HID)过滤设备类型 [^3]: 必须确保hid_close和hid_free_enumeration的成对调用 [^4]: 接口设置内存管理需要关注缓存生命周期
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值