在Linux下,lspci可以枚举所有PCI设备。它是通过读取PCI配置空间(PCI Configuration Space)信息来实现PCI设备的枚举的。这里,我通过两种方式来简单的模拟一下lspci的功能。一种是通过PCI总线的CF8和CFC端口来枚举(参考PCI总线规范);另一种是利用proc filesystem。

方法一:这种方法需要对端口进行操作,在Linux下,普通应用程序没有权限读写I/O 端口,需要通过iopl或ioperm来提升权限,我的代码里面使用iopl。

/*

* Enum all pci device via the PCI config register(CF8 and CFC).

*/

#include

#include

#include

#include

#define PCI_MAX_BUS 255 /* 8 bits (0 ~ 255) */

#define PCI_MAX_DEV 31 /* 5 bits (0 ~ 31) */

#define PCI_MAX_FUN 7 /* 3 bits (0 ~ 7) */

#define CONFIG_ADDRESS 0xCF8

#define CONFIG_DATA 0xCFC

#define PCICFG_REG_VID 0x00 /* Vendor id, 2 bytes */

#define PCICFG_REG_DID 0x02 /* Device id, 2 bytes */

#define PCICFG_REG_CMD 0x04 /* Command register, 2 bytes */

#define PCICFG_REG_STAT 0x06 /* Status register, 2 bytes */

#define PCICFG_REG_RID 0x08 /* Revision id, 1 byte */

void list_pci_devices()

{

unsigned int bus, dev, fun;

unsigned int addr, data;

//printf("BB:DD:FF VID:DID\n");

for (bus = 0; bus <= PCI_MAX_BUS; bus++) {

for (dev = 0; dev <= PCI_MAX_DEV; dev++) {

for (fun = 0; fun <= PCI_MAX_FUN; fun++) {

addr = 0x80000000L | (bus<<16) | (dev<<11) | (fun<<8);

outl(addr, CONFIG_ADDRESS);

data = inl(CONFIG_DATA);

/* Identify vendor ID */

if ((data != 0xFFFFFFFF) && (data != 0)) {

printf("%02X:%02X:%02X ", bus, dev, fun);

printf("%04X:%04X", data&0xFFFF, data>>16);

addr = 0x80000000L | (bus<<16) | (dev<<11) | (fun<<8) | PCICFG_REG_RID;

outl(addr, CONFIG_ADDRESS);

data = inl(CONFIG_DATA);

if (data&0xFF) {

printf(" (rev %02X)\n", data&0xFF);

} else {

printf("\n");

}

}

} end func

} // end device

} // end bus

}

int main()

{

int ret;

/* Enable r/w permission of all 65536 ports */

ret = iopl(3);

if (ret < 0) {

perror("iopl set error");

return 1;

}

list_pci_devices();

/* Disable r/w permission of all 65536 ports */

ret = iopl(0);

if (ret < 0) {

perror("iopl set error");

return 1;

}

return 0;

}

方法二:这种方法需不需要对端口进行操作,而是利用Linux procfs来实现对PCI 配置空间的访问。

/*

* Enum all pci device via /proc/bus/pci/.

*/

#include

#include

#include

#include

#include

#include

#define PCI_MAX_BUS 255 /* 8 bits (0 ~ 255) */

#define PCI_MAX_DEV 31 /* 5 bits (0 ~ 31) */

#define PCI_MAX_FUN 7 /* 3 bits (0 ~ 7) */

/*

* PCI Configuration Header offsets

*/

#define PCICFG_REG_VID 0x00 /* Vendor id, 2 bytes */

#define PCICFG_REG_DID 0x02 /* Device id, 2 bytes */

#define PCICFG_REG_CMD 0x04 /* Command register, 2 bytes */

#define PCICFG_REG_STAT 0x06 /* Status register, 2 bytes */

#define PCICFG_REG_RID 0x08 /* Revision id, 1 byte */

#define PCICFG_REG_PROG_INTF 0x09 /* Programming interface code, 1 byte */

#define PCICFG_REG_SUBCLASS 0x0A /* Sub-class code, 1 byte */

#define PCICFG_REG_BASCLASS 0x0B /* Base class code, 1 byte */

#define PCICFG_REG_CACHE_LINESZ 0x0C /* Cache line size, 1 byte */

#define PCICFG_REG_LATENCY_TIMER 0x0D /* Latency timer, 1 byte */

#define PCICFG_REG_HEADER_TYPE 0x0E /* Header type, 1 byte */

#define PCICFG_REG_BIST 0x0F /* Builtin self test, 1 byte */

#define PCICFG_REG_BAR0 0x10 /* Base addr register 0, 4 bytes */

#define PCICFG_REG_BAR1 0x14 /* Base addr register 1, 4 bytes */

#define PCICFG_REG_BAR2 0x18 /* Base addr register 2, 4 bytes */

#define PCICFG_REG_BAR3 0x1C /* Base addr register 3, 4 bytes */

#define PCICFG_REG_BAR4 0x20 /* Base addr register 4, 4 bytes */

#define PCICFG_REG_BAR5 0x24 /* Base addr register 5, 4 bytes */

#define PCICFG_REG_CIS 0x28 /* Cardbus CIS Pointer */

#define PCICFG_REG_SVID 0x2C /* Subsystem Vendor ID, 2 bytes */

#define PCICFG_REG_SDID 0x2E /* Subsystem ID, 2 bytes */

#define PCICFG_REG_ROMBAR 0x30 /* ROM base register, 4 bytes */

#define PCICFG_REG_CAPPTR 0x34 /* Capabilities pointer, 1 byte */

#define PCICFG_REG_INT_LINE 0x3C /* Interrupt line, 1 byte */

#define PCICFG_REG_INT_PIN 0x3D /* Interrupt pin, 1 byte */

#define PCICFG_REG_MIN_GNT 0x3E /* Minimum grant, 1 byte */

#define PCICFG_REG_MAX_LAT 0x3F /* Maximum lat, 1 byte */

void list_pci_devices()

{

unsigned int bus, dev, fun;

//printf("BB:DD:FF VID:DID(RID)\n");

for (bus = 0; bus <= PCI_MAX_BUS; bus++) {

for (dev = 0; dev <= PCI_MAX_DEV; dev++) {

for (fun = 0; fun <= PCI_MAX_FUN; fun++) {

char proc_name[64];

int cfg_handle;

uint32_t data;

uint16_t vid, did;

uint8_t rid;

snprintf(proc_name, sizeof(proc_name),

"/proc/bus/pci/%02x/%02x.%x", bus, dev, fun);

cfg_handle = open(proc_name, O_RDWR);

if (cfg_handle <= 0)

continue;

lseek(cfg_handle, PCICFG_REG_VID, SEEK_SET);

read(cfg_handle, &data, sizeof(data));

/* Identify vendor ID */

if ((data != 0xFFFFFFFF) && (data != 0)) {

lseek(cfg_handle, PCICFG_REG_RID, SEEK_SET);

read(cfg_handle, &rid, sizeof(rid));

vid = data&0xFFFF;

did = data>>16;

printf("%02X:%02X:%02X", bus, dev, fun);

if (rid > 0) {

printf(" %04X:%04X (rev %02X)\n", vid, did, rid);

} else {

printf(" %04X:%04X\n", vid, did);

}

}

} // end func

} // end device

} // end bus

}

int main(int argc, char **argv)

{

list_pci_devices();

return 0;

}

这两种方法各有优缺点,第一种方法方便移植到其他OS,第二种就只适用于Linux。但是,第一种方法需要对I/O port进行直接操作。第二种就不需要。

注意:执行这两段代码时,需要超级用户(root) 权限。

补充:今天在枚举 Westmere-EP Processor(Intel Xeon Processor 5500 Series(Nehalem-EP))的 IMC(Integrated Memory Controller)时发现一个问题。lspci无法枚举到IMC设备。Westmere-EP 是 Intel 新的处理器架构。和以往的CPU不一样,它把Memory Controller集成到了CPU里面。IMC控制器被映射到了PCI总线上,Bus Number 是0xFE~0xFF,procfs(/proc/bus/pci/)下没有这几个设备。但是,通过 CF8/CFC 端口可以枚举到这些设备。

3. 这段代码是在驱动中可以用来查找特定的pci device,并且返回一个pci_dev的结构体变量。通过这样一个struct变量,内核提供的接口函数可以直接套用,如pci_read_config_word(),pci_write_config_word()等。

void list_pci_device()

{

struct pci_dev *dev;

struct pci_bus *bus,*childbus;

list_for_each_entry(bus, &pci_root_buses, node) {//globle pci_root_buses in pci.h

list_for_each_entry(dev, &bus->devices, bus_list) {// for bus 0

printk("%02X:%02X:%02X %04X:%04X\n",dev->bus->number,dev->devfn >> 3, dev->devfn & 0x07,dev->vendor,dev->device);

}

list_for_each_entry(childbus, &bus->children,node) { // for bus 1,2,3,...

list_for_each_entry(dev, &childbus->devices, bus_list) {

printk("%02X:%02X:%02X %04X:%04X\n",dev->bus->number,dev->devfn >> 3, dev->devfn & 0x07,dev->vendor,dev->device);

}

}

}

}

linux查看pci设备枚举,Linux 枚举PCI设备相关推荐

  1. linux查看内存的生产商,linux下查看CPU.内存型号.pci 转自《Ivan-blog》

    cat /proc/cpuinfo | grep 'physical id' physical id : 0 physical id : 0 physical id : 0 physical id : ...

  2. linux查看usb驱动版本号,linux查看硬件信息及驱动设备相关整理

    该楼层疑似违规已被系统折叠 隐藏此楼查看此楼 联系我登录 首页 业界新闻 技术文章 资源分享 微语 linux查看硬件信息及驱动设备相关整理[转] 蓝猫 发布于:2014-5-30 17:48 分类: ...

  3. linux下查看系统硬件,Linux 查看系统硬件信息 Linux 查看系统硬件信息(实例详解)...

    linux查看系统的硬件信息,并不像windows那么直观,这里我罗列了查看系统信息的实用命令,并作了分类,实例解说.html cpu lscpu命令,查看的是cpu的统计信息.linux blue@ ...

  4. linux查看远程服务器端口,linux下查看本机和远程服务器的端口是否连通的方法...

    linux下查看本机和远程服务器的端口是否连通的方法 如下所示: 1.ssh -v -p [端口号] [用户名]@[IP地址] 2.curl [IP地址]:[端口号] 以上这篇linux下查看本机和远 ...

  5. linux查看文件写进程,Linux下如何知道文件被那个进程写

    晚上朔海同学问:一个文件正在被进程写 我想查看这个进程 文件一直在增大 找不到谁在写 使用lsof也没找到 这个问题挺有普遍性的,解决方法应该很多,这里我给大家提个比较直观的方法. linux下每个文 ...

  6. linux查看程序的快捷键,linux操作系统的快捷键及命令讲解

    GNU是为Linux提供免费软件支持的工具;红帽与乌邦图都是Linux的一个版本. Linux登入时登入名为root的是最高级别 Linux系统中的文件夹: /:根目标 bin:二进制可执行文件 li ...

  7. linux查看显示器名称命令,linux 查看显示器信息Linux下查看硬件信息命令大全

    /proc 虚拟的目录,是系统内存的映射.可直接访问这个目录来获取系统信息.其中也包含下面的信息: 主机CPU信息:cpuinfo 主机DMA通道信息:dma 文件系统信息:filesystems 主 ...

  8. linux查看磁盘权限设置,Linux 磁盘管理

    磁盘管理 Linux思想一切皆文件: open(),read(),write(),close() I/O 设备地址 设备类型: 块设备:block,存取单位"块",磁盘 (随机访问 ...

  9. linux查看网卡pcie插槽,Linux下查看PCI-E插槽信息的方法

    原文: http://blog.chinaunix.net/uid-1829236-id-3188434.html ========================================== ...

  10. linux查看cpu个数命令,Linux怎么查看物理CPU个数

    在linux中我们对于硬件的查看只能通过命令的方式来获得了不能直接查看到了,下面学习阿拉小编给各位整理了一些Linux查看物理CPU个数.核数.逻辑CPU个数的命令供各位学习. Linux怎么查看物理 ...

最新文章

  1. Nervos Report (2018年12月)
  2. 30个免费网页图标字体以及使用方法
  3. JS格式化JSON串显示在表格中
  4. SpringBoot简单集成Redis,实现简单查询
  5. 计算机视觉:卷积神经网络基础
  6. Display Skin
  7. hibernate的映射关系配置及对会话工厂的初始化。以及struts2写实例查询
  8. android 开机自动启动应用,以及如何放置系统应用(system/app)中
  9. 可以悬浮在屏幕的搜题软件_悬浮窗搜题app下载-悬浮窗搜题预约 安卓版v1.0.0-PC6安卓网...
  10. 德国Taufenbach激光打标机电源维修RFE020详解
  11. nuxt使用videojs播放flv格式视频
  12. 洛谷P3376 【模板】网络最大流{Dinic算法}
  13. 强烈推荐的程序员键盘--红轴手感好按键压力小写代码更轻松
  14. java实现APP版本比对工具类
  15. 如何有效提高生产车间的生产效率呢?
  16. 我的开车心得-送给马路新人 【转】
  17. easyAR的使用教程
  18. SSH框架总结,超详细
  19. R语言--ELM极限学习机(elmNNRcpp包)
  20. 详解BigDecimal及其加减乘除运算

热门文章

  1. 油品调和计算软件_燃料油品的调合及计算方法及航空汽油的调合
  2. KICAD——手动生成嘉立创可识别的BOM和POS文件
  3. 合取范式可满足性问题:CDCL(Conflict-Driven Clause Learning)算法详解
  4. Delphi 金额转大写
  5. 王者荣耀英雄战力 最低战区查询
  6. 【光学】基于matlab相互垂直的光波叠加仿真【含Matlab源码 2071期】
  7. 用大数据文本挖掘来看“共享单车”的行业现状及走势
  8. C# 将word/ppt文档转换为Pdf的三种方法
  9. FaShop-开源拖拽式小程序搭建平台
  10. 黑苹果16g内存够用吗_刚脱坑黑苹果,给想装黑苹果的几个建议