pci_read_config_dword函数实现
时间: 2023-11-06 14:10:39 浏览: 451
pci_read_config_dword函数是一个用于读取PCI设备配置空间中指定寄存器的函数,其实现可以参考以下代码:
```
uint32_t pci_read_config_dword(uint8_t bus, uint8_t slot, uint8_t func, uint8_t offset)
{
// 计算配置空间地址
uint32_t address = (uint32_t)((bus << 16) | (slot << 11) |
(func << 8) | (offset & 0xfc) | ((uint32_t)0x80000000));
// 发送配置空间地址到PCI总线
outl(PCI_CONFIG_ADDRESS, address);
// 从PCI总线读取指定寄存器的值
return inl(PCI_CONFIG_DATA);
}
```
其中,outl和inl函数用于向PCI总线发送数据和从PCI总线接收数据。PCI配置空间中每个寄存器都有一个唯一的地址,因此我们可以通过计算得到指定寄存器的地址,然后将该地址发送到PCI总线,最后从PCI总线读取相应寄存器的值即可。
相关问题
IOCTL_READ_PCI_CONFIG 和 IOCTL_WRITE_PCI_CONFIG 的实现
IOCTL_READ_PCI_CONFIG 和 IOCTL_WRITE_PCI_CONFIG 是用于读写PCI设备配置空间的Windows I/O控制码。
以下是它们的实现示例:
```c
// 读取PCI设备配置空间
BOOL ReadPCIConfig(HANDLE hDevice, DWORD dwBus, DWORD dwSlot, DWORD dwFunction, LPVOID lpBuffer, DWORD dwBytesToRead) {
// 构造PCI配置空间的地址
DWORD dwAddress = 0x80000000 | (dwBus << 16) | (dwSlot << 11) | (dwFunction << 8);
// 构造输入缓冲区
PCI_CONFIG_INPUT input = {0};
input.dwAddress = dwAddress;
input.dwBytesToRead = dwBytesToRead;
// 构造输出缓冲区
PCI_CONFIG_OUTPUT output = {0};
// 发送IOCTL请求
DWORD dwBytesReturned = 0;
BOOL bSuccess = DeviceIoControl(hDevice, IOCTL_READ_PCI_CONFIG, &input, sizeof(input), &output, sizeof(output), &dwBytesReturned, NULL);
// 将结果拷贝到输出缓冲区
if (bSuccess) {
memcpy(lpBuffer, output.bResult, dwBytesToRead);
}
return bSuccess;
}
// 写入PCI设备配置空间
BOOL WritePCIConfig(HANDLE hDevice, DWORD dwBus, DWORD dwSlot, DWORD dwFunction, LPCVOID lpBuffer, DWORD dwBytesToWrite) {
// 构造PCI配置空间的地址
DWORD dwAddress = 0x80000000 | (dwBus << 16) | (dwSlot << 11) | (dwFunction << 8);
// 构造输入缓冲区
PCI_CONFIG_INPUT input = {0};
input.dwAddress = dwAddress;
input.dwBytesToWrite = dwBytesToWrite;
memcpy(input.bData, lpBuffer, dwBytesToWrite);
// 发送IOCTL请求
DWORD dwBytesReturned = 0;
BOOL bSuccess = DeviceIoControl(hDevice, IOCTL_WRITE_PCI_CONFIG, &input, sizeof(input), NULL, 0, &dwBytesReturned, NULL);
return bSuccess;
}
```
这里的 `PCI_CONFIG_INPUT` 和 `PCI_CONFIG_OUTPUT` 是自定义的结构体,定义如下:
```c
typedef struct _PCI_CONFIG_INPUT {
DWORD dwAddress; // PCI配置空间的地址
DWORD dwBytesToRead; // 要读取的字节数
DWORD dwBytesToWrite; // 要写入的字节数
BYTE bData[256]; // 数据缓冲区
} PCI_CONFIG_INPUT, *PPCI_CONFIG_INPUT;
typedef struct _PCI_CONFIG_OUTPUT {
BYTE bResult[256]; // 数据缓冲区
} PCI_CONFIG_OUTPUT, *PPCI_CONFIG_OUTPUT;
```
在实际使用中,需要先打开一个PCI设备的句柄,然后通过该句柄调用 `ReadPCIConfig` 和 `WritePCIConfig` 函数进行读写操作。其中,`dwBus`、`dwSlot` 和 `dwFunction` 分别表示PCI设备的总线号、插槽号和功能号,`lpBuffer` 表示数据缓冲区的指针,`dwBytesToRead` 和 `dwBytesToWrite` 分别表示要读取和写入的字节数。
中文注释此函数,static int agp_ali_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { struct agp_device_ids *devs = ali_agp_device_ids; struct agp_bridge_data *bridge; u8 hidden_1621_id, cap_ptr; int j; cap_ptr = pci_find_capability(pdev, PCI_CAP_ID_AGP); if (!cap_ptr) return -ENODEV; /* probe for known chipsets */ for (j = 0; devs[j].chipset_name; j++) { if (pdev->device == devs[j].device_id) goto found; } dev_err(&pdev->dev, "unsupported ALi chipset [%04x/%04x])\n", pdev->vendor, pdev->device); return -ENODEV; found: bridge = agp_alloc_bridge(); if (!bridge) return -ENOMEM; bridge->dev = pdev; bridge->capndx = cap_ptr; switch (pdev->device) { case PCI_DEVICE_ID_AL_M1541: bridge->driver = &ali_m1541_bridge; break; case PCI_DEVICE_ID_AL_M1621: pci_read_config_byte(pdev, 0xFB, &hidden_1621_id); switch (hidden_1621_id) { case 0x31: devs[j].chipset_name = "M1631"; break; case 0x32: devs[j].chipset_name = "M1632"; break; case 0x41: devs[j].chipset_name = "M1641"; break; case 0x43: devs[j].chipset_name = "M1621"; break; case 0x47: devs[j].chipset_name = "M1647"; break; case 0x51: devs[j].chipset_name = "M1651"; break; default: break; } fallthrough; default: bridge->driver = &ali_generic_bridge; } dev_info(&pdev->dev, "ALi %s chipset\n", devs[j].chipset_name); /* Fill in the mode register */ pci_read_config_dword(pdev, bridge->capndx+PCI_AGP_STATUS, &bridge->mode); pci_set_drvdata(pdev, bridge); return agp_add_bridge(bridge); }
这是一个用于探测 PCI 设备的函数,使用静态修饰符标识只在当前文件中可见。函数名为 agp_ali_probe,接收两个参数,分别是一个指向 pci_dev 结构体的指针 pdev 和一个指向 pci_device_id 结构体的指针 ent。
函数首先定义了一个指向 agp_device_ids 结构体的指针变量 devs,其初始化值为 ali_agp_device_ids。接下来定义了一个指向 agp_bridge_data 结构体的指针变量 bridge 和两个整型变量 hidden_1621_id 和 cap_ptr。
函数通过调用 pci_find_capability 函数查找是否存在 PCI_CAP_ID_AGP 的能力,如果不存在则返回错误码 ENODEV。
然后,函数通过遍历 ali_agp_device_ids 数组,查找是否有匹配的设备 ID,如果找到了则跳转到 found 标签处,否则打印一个错误信息并返回 ENODEV 错误码。
如果找到了匹配的设备 ID,则调用 agp_alloc_bridge 函数分配一个 agp_bridge_data 结构体的内存空间,并将指针赋值给 bridge 变量。如果分配内存失败则返回 ENOMEM 错误码。
接下来,函数根据不同的设备 ID 设置不同的桥驱动,如果是 AL_M1541 设备,则使用 ali_m1541_bridge 驱动,如果是 AL_M1621 设备,则需要读取隐藏的 0xFB 寄存器,根据其值设置不同的芯片组名称,然后使用 ali_generic_bridge 驱动。最后,函数输出一个信息,表示探测到了 ALi 芯片组。
最后,函数通过调用 pci_read_config_dword 函数读取 PCI_AGP_STATUS 寄存器的值,并将其赋值给 bridge->mode 变量,然后通过调用 pci_set_drvdata 函数将 bridge 指针作为私有数据存储到设备的数据结构中。最后,函数通过调用 agp_add_bridge 函数将 bridge 添加到全局 agp_bridge_list 链表中,并返回操作结果。
阅读全文