编写PCIE驱动实现设备配置空间读取
查看电脑下挂了哪些PCIE设备
https://blog.youkuaiyun.com/miss_lazygoat/article/details/47664813
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/io.h>
#define MAX_BUS 256
#define MAX_DEV 32
#define MAX_FUN 8
#define BASE_ADDR 0x80000000
#define CONFIG_ADDR 0xcf8
#define CONFIG_DATA 0xCFC
typedef unsigned int WORD;
int main(){
WORD bus,dev,fun;
WORD addr,data;
int ret = 0;
printf("bus#\tdev#\tfun#\tdata#\t\n");
ret = iopl(3); // 设置权限
if (ret < 0){
perror("iopl set 3 fail:");
return -1;
}
for(bus = 0;bus < MAX_BUS;bus++){
for(dev = 0;dev < MAX_DEV;dev++){
for(fun = 0;fun < MAX_FUN;fun++){
addr = BASE_ADDR|(bus<<16)|(dev<<11)|(fun<<8);//合成PCIE ID路由地址
outl(addr,CONFIG_ADDR);
data = inl(CONFIG_DATA);
if((data != 0xffffffff)&&(data != 0)){
printf("%2x\t%2x\t%2x\t%8x\t\n",bus,dev,fun,data);
}
}
}
}
ret = iopl(0);
if(ret < 0){
perror("iopl set 0 fail:");
return -1;
}
}
输出如下:
bus# dev# fun# data#
0 0 0 1548086
0 1 0 1518086
0 2 0 1668086
0 14 0 1e318086
0 16 0 1e3a8086
0 1a 0 1e2d8086
0 1b 0 1e208086
0 1c 0 1e108086
0 1c 1 1e128086
0 1c 2 1e148086
0 1c 3 1e168086
0 1d 0 1e268086
0 1f 0 1e578086
0 1f 2 1e018086
0 1f 3 1e228086
0 1f 5 1e098086
1 0 0 de310de
1 0 1 bea10de
2 0 0 522910ec
3 0 0 472714e4
得到的Vender ID再查看其对照表
venderid对照表
https://blog.youkuaiyun.com/vdoublev/article/details/102832655
在网上没有查到对应的deviceID对照表,所以只能从厂家知道大概是啥设备

驱动程序
用的是上图的18号Nvidia做示例
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/slab.h>
#include <linux/pci.h>
#define VENDER_ID 0x10de //Nvidia corporation
#define DEVICE_ID 0xDE3 //unkown device
#define PCI_DEV_NAME "pci_dev_silly"
struct cdev g_pci_cdev;
dev_t g_pci_tdev;
dev_t g_devno;
int g_pci_major = 0;
int g_pci_minor = 0;
struct class *g_pci_class;
struct device *g_dev;
struct pci_bus bus_num;
unsigned int devfn = 0;
struct pci_dev *g_pci_get_dev_num = NULL;
int open_dev(struct inode *inode, struct file *filp)
{
printk("this is ysp open\n");
return 0;
}
struct file_operations pci_fops = {
.owner = THIS_MODULE,
.open = open_dev,
};
static int __init pci_driver_init (void)
{
int ret;
unsigned int data;
g_devno = MKDEV(g_pci_major, g_pci_minor);
printk("silly1 major is %d,minor is %d\n",g_pci_major,g_pci_minor);
printk("silly1 g_pci_tdev is %d\n",g_pci_tdev);
if (g_pci_major)
ret= register_chrdev_region(g_pci_tdev, 1, PCI_DEV_NAME);
else
{
ret = alloc_chrdev_region(&g_pci_tdev, 0, 1, PCI_DEV_NAME);
g_pci_major = MAJOR(g_pci_tdev);
}
printk("silly2 major is %d,minor is %d\n",g_pci_major,g_pci_minor);
printk("silly2 g_pci_tdev is %d\n",g_pci_tdev);
if (ret) {
printk("%s alloc_chrdev_region failed!\n",__func__);
goto alloc_chrdev_err;
}
cdev_init(&(g_pci_cdev), &pci_fops);
g_pci_cdev.owner = THIS_MODULE;
ret = cdev_add(&(g_pci_cdev), g_pci_tdev, 1);
if (ret) {
printk("%s cdev_add failed!\n",__func__);
goto cdev_add_err;
}
g_pci_class =class_create(THIS_MODULE,"hello_char_class");
if(IS_ERR(g_pci_class))
{
ret = PTR_ERR(g_pci_class);
printk("%s class_create failed!\n",__func__);
goto class_err;
}
g_dev = device_create(g_pci_class,NULL,g_pci_tdev,NULL,"pci_dev%d",0);
if (IS_ERR(g_dev)) {
ret = PTR_ERR(g_dev);
printk("%s device_create failed!\n",__func__);
goto device_err;
}
//如果pci没有建链,这里需要物理建链才能get device。建链的操作还不会。
g_pci_get_dev_num = pci_get_device(VENDER_ID,DEVICE_ID,g_pci_get_dev_num);
if(g_pci_get_dev_num != NULL){
printk("get pci device success\n");
ret = pci_enable_device(g_pci_get_dev_num);
printk("enable device ret = %d\n",ret);
//ret = pci_bus_read_config_dword(&bus_num,devfn,0,&data);
ret = pci_read_config_dword(g_pci_get_dev_num,0,&data);
printk("ret = %d,data = 0x%x\n",ret,data);
}
else{
printk("get pci device err\n");
}
printk("pcie module initialization\n");
return 0;
device_err:
device_destroy(g_pci_class, g_pci_tdev);
class_err:
cdev_del(g_pci_tdev);
cdev_add_err:
unregister_chrdev_region(g_pci_tdev, 1);
alloc_chrdev_err:
//kfree(my_hello_dev);
return ret;
}
static void __exit pci_driver_exit (void)
{
cdev_del (&(g_pci_cdev));
unregister_chrdev_region (g_pci_tdev,1);
device_destroy(g_pci_class, g_pci_tdev); //delete device node under /dev//必须先删除设备,再删除class类
class_destroy(g_pci_class); //delete class created by us
//kfree(my_hello_dev);
printk (KERN_INFO "char driver cleaned up\n");
return 0;
}
module_init (pci_driver_init);
module_exit (pci_driver_exit);
MODULE_LICENSE ("GPL");
insmod后,采用dmesg看到执行结果如下,可以看到读出来的data正是{deviceid,venderid}
这里只是采用id路由访问配置空间。用IO访问还不会。
IO访问看别人示例里将pci的phy addr与CPU内存地址mmap起来后,直接往对应的内存写值读值。他那里有个init的函数我没有,所以看不到,不知道那里面是否有将设备配置成DMA访问
本文介绍了一种通过编写驱动程序来实现对PCIE设备配置空间读取的方法,并展示了如何利用该方法获取连接到系统的PCIE设备信息。
6454

被折叠的 条评论
为什么被折叠?



