linux驱动学习

本文介绍了一种通过编写驱动程序来实现对PCIE设备配置空间读取的方法,并展示了如何利用该方法获取连接到系统的PCIE设备信息。

编写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访问

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值