Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/windows/16.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在Windows中获取PCI区域大小?_C_Windows_Size_Regions_Pci - Fatal编程技术网

如何在Windows中获取PCI区域大小?

如何在Windows中获取PCI区域大小?,c,windows,size,regions,pci,C,Windows,Size,Regions,Pci,我需要扫描我的PCI总线,并从特定供应商处获取特定设备的信息。 我的目标是找到AMD图形卡的PCI区域大小,以便将该卡的PCI内存映射到用户空间,以便进行i2c传输并查看来自各种传感器的信息 为了扫描PCI总线,我大约在一年前下载并编译了适用于Windows x64的pciutils 3.1.7。它应该使用DirectIO 这是我的密码 int scan_pci_bus() { struct pci_access *pci; struct pci_dev *dev; in

我需要扫描我的PCI总线,并从特定供应商处获取特定设备的信息。 我的目标是找到AMD图形卡的PCI区域大小,以便将该卡的PCI内存映射到用户空间,以便进行i2c传输并查看来自各种传感器的信息

为了扫描PCI总线,我大约在一年前下载并编译了适用于Windows x64的pciutils 3.1.7。它应该使用DirectIO

这是我的密码

int scan_pci_bus()
{
    struct pci_access *pci;
    struct pci_dev *dev;
    int i;

    pci = pci_alloc();
    pci_init(pci);

    pci_scan_bus(pci);

    for(dev = pci->devices; dev; dev = dev->next) 
    {
        pci_fill_info(dev, PCI_FILL_IDENT | PCI_FILL_CLASS | PCI_FILL_IRQ | PCI_FILL_BASES | PCI_FILL_ROM_BASE | PCI_FILL_SIZES | PCI_FILL_PHYS_SLOT);
        if(dev->vendor_id == 0x1002 && dev->device_id == 0x6899)
        {
            //Vendor is AMD, Device ID is a AMD HD5850 GPU
            for(i = 0; i < 6; i++) 
            {
                printf("Region Size %d %x ID %x\n", dev->size[i], dev->base_addr[i], dev->device_id);
            }
        }
    }


    pci_cleanup(pci);

    return 0;
}
int-scan\u-pci\u总线()
{
结构pci_访问*pci;
结构pci_dev*dev;
int i;
pci=pci_alloc();
pci_init(pci);
pci_扫描_总线(pci);
用于(dev=pci->devices;dev;dev=dev->next)
{
pci_填充信息(开发,pci_填充标识| pci_填充等级| pci_填充IRQ | pci_填充基础| pci_填充ROM|基础| pci_填充尺寸| pci_填充物理插槽);
如果(开发人员->供应商标识==0x1002&&dev->设备标识==0x6899)
{
//供应商是AMD,设备ID是AMD HD5850 GPU
对于(i=0;i<6;i++)
{
printf(“区域大小%d%x ID%x\n”,开发->大小[i],开发->基本地址[i],开发->设备ID);
}
}
}
pci_清理(pci);
返回0;
}
正如您在printf行中看到的,我尝试打印一些数据,我成功地打印了
device\u id
base\u addr
,但是
size
应该包含此设备的PCI区域大小始终为0。我希望循环中至少有一个循环显示大于0的大小

我的代码基于使用相同代码的Linux应用程序,尽管它使用Linux附带的pci.h头(pciutils显然具有相同的API)。 显然,Windows(在我的例子中是Windows 7 x64)没有显示此信息,或者至少没有暴露于PCIUTIL

你建议我如何获得这些信息?如果有PCIUTILsforWindows的替代品并提供此信息,我很乐意获得它们的链接


编辑:我仍然没有找到解决方案。如果有任何解决方案可以解决我的问题,并且也适用于32位Windows,我们将不胜感激。

这是一个非常复杂的问题。PCI设备使用
基址寄存器
让BIOS和操作系统决定其内存区域的位置。每个PCI设备都可以指定所需的几个内存或IO区域,并让BIOS/OS决定将其放置在何处。更复杂的是,只有一个寄存器同时用于指定大小和地址。这是怎么回事

当卡首次通电时,它的32位地址寄存器将包含类似0xFFFF0000的内容。任何二进制1表示“操作系统可以改变这一点”,任何二进制0表示“必须保持零”。因此,这告诉操作系统,前16位中的任何一位都可以设置为操作系统想要的任何值,但下16位必须保持为零。这也意味着该内存区域占用16位地址空间,即64k。因此,内存区域必须与其大小对齐。如果一张卡需要64K的地址空间,操作系统只能将其放在64K倍数的内存地址上。当操作系统决定要在何处定位该卡的64K内存空间时,它会将其写回该寄存器,覆盖其中的初始0xFFFF0000

换句话说,卡告诉操作系统它需要内存的大小/对齐方式,然后操作系统用内存地址覆盖相同的寄存器/变量。完成后,如果不重置地址,就无法从寄存器中恢复大小

这意味着没有便携的方式来询问卡片的区域有多大,你只能问它区域在哪里

那么为什么这在Linux中可以工作呢?因为它要求内核提供这些信息。内核有一个API来提供这些东西,与lspci的工作方式相同。我不是Windows专家,但我不知道应用程序有什么方法可以向Windows内核询问这些信息。可能有一个API以某种方式来实现这一点,或者您可能需要编写一些在内核端运行的东西来将这些信息传递给您。如果查看libpci源代码,对于windows,它将调用pci_fill_info()的“通用”版本,返回:

return flags & ~PCI_FILL_SIZES;
这基本上意味着“我会退回你要的所有东西,但是尺寸。”

但无论如何,这可能并不重要。如果您只是想读/写I2C寄存器,那么它们通常(总是?)位于控制/配置区域的前4K。您可能只需要映射4K(一页),而忽略可能还有更多的事实。另外,请注意,您可能需要采取额外的步骤来阻止此卡的真实驱动程序在运行时读/写。如果你用手敲打I2C总线,而驱动程序试图同时敲打I2C总线,很可能会造成总线混乱

也可能有一种现有的方法要求radeon驱动程序为您执行I2C请求,这可能会避免所有这些


(还要注意的是,我正在简化和润色很多关于条形图工作原理的细节,包括64位地址、I/O空间等,如果您想了解更多,请阅读PCI文档)

嗯,whamma给出了一个非常好的答案[但是]有一点他错了,那就是区域大小。区域大小很容易找到,这里我将展示两种方法,第一种是通过从栏的地址破译,第二种是通过Windows用户界面

假设E2000000是基址寄存器的地址。如果我们将其转换为二进制,我们得到: 111000100000000000000000000000

现在这里总共有32位,如果你必须的话,你可以数一数。现在,如果您不熟悉位在 一个条被布置出来,看这里->,特别是“基址寄存器”,更具体地说 显示“内存空间条布局”的图像。现在让我们开始从右端到左端读取位并使用 链接i po中的图像