一、访问PCI 配置空间
PCI 有 3 种独立地址空间:PCI/IO 空间、PCI 内存地址空间和 PCI 配置空间。
PCI 配置空间(共为256字节),布局如下:
内核为访问配置空间提供了函数接口:
pci_read_config_byte/word/dword(struct pci_dev *pdev, int offset, int *value);
pci_write_config_byte/word/dword(struct pci_dev *pdev, int offset, int *value);
二、PCI 的 I/O 和内存空间
获取 I/O 或内存资源
pci_resource_start(struct pci_dev *dev, int bar); /*Bar值的范围为0-5*/ // 该函数返回六个 PCI I/O 区域之一的第一个地址(内存地址或 I/O 端口编号)。
pci_resource_end(struct pci_dev *dev, int bar) /* Bar值的范围为0-5*/ // 该函数返回第 bar 个 I/O 区域的后一个地址。注意这是最后一个可用的地址,而不是该区域之后的第一个地址。
pci_resource_flags(struct pci_dev *dev, int bar) /* Bar值的范围为0-5*/ // 该函数返回资源关联的标志。资源标志用来定义单个资源的某些特性。对与 PCI I/O 区域关联的 PCI 资源,
// 该信息从基地址寄存器中获得,但对其它与 PCI 设备无关的资源,它可能来自任何地方。
申请/释放I/O或内存资源
int pci_request_regions(struct pci_dev *pdev, const char *res_name);
void pci_release_regions(struct pci_dev *pdev);
获取/设置驱动私有数据
void *pci_get_drvdata(struct pci_dev *pdev);
void pci_set_drvdata((struct pci_dev *pdev, void *data);
使能/禁止 PCI 设备
int pci_enable_device(struct pci_dev *pdev);
int pci_disable_device(struct pci_dev *pdev);
设置主总线为 DMA 模式
void pci_set_master(struct pci_dev *pdev);
寻找指定总线指定槽位的 PCI 设备
struct pci_dev *pci_find_slot (unsigned int bus,unsigned int devfn);
设置 PCI 能量管理状态
int pci_set_power_state(struct pci_dev *pdev, pci_power_t state);
在设备的能力中表中找出指定能力
int pci_find_capability(struct pci_dev *pdev, int cap);
启用设备内存写无效事务
int pci_set_mwi(struct pci_dev *pdev);
禁用设备内存写无效事务:
void pci_clear_mwi(struct pci_dev *pdev);
三、判断 pci 设备是否存在
一般来说,linux 访问pci设备,只能在pci设备驱动的 probe 里得到关键的 struct pci_dev * pdev;偶尔遇到点急事,想走个后门,靠 pci_get_device 能在任意位置根据厂商和设备id得到这个 pdev。
函数接口
// vendor:厂商ID; device:设备ID.
struct pci_dev *pci_get_device(unsigned int vendor, unsigned int device,
struct pci_dev *from)
{
return pci_get_subsys(vendor, device, PCI_ANY_ID, PCI_ANY_ID, from);
}
使用示例
struct pci_dev *pdev_check = NULL;
pdev_check = pci_get_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101,
NULL);
if(pdev_check == NULL){
printk("pci_get_device find error\n ");
} else {
printk("---bar %d:start %x length %x flags %x \n", i, pci_resource_start(pdev_check, i), pci_resource_len(pdev_check, i), pci_resource_flags(pdev_check, i));
}