PCIE驱动学习 最基本的一个PCIE驱动项目

在GITHUB上搜PCIE驱动找到这个最简单的,也可以编译过的。

https://github.com/ahmedshakill/PCIeDriver

下载下来直接make就可以编译过。

里面只有一个C文件和一个makefile。我分别贴出来:

#include <linux/module.h>
#include <linux/init.h>
#include <linux/pci.h>


// These have to match a physical device attached to a PCIe slot
#define PCITTL32IO_VENDOR_ID 0x8086
#define PCITTL32IO_DEVICE_ID 0x09ab


/* Meta Information */

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Shakil Ahmed");
MODULE_DESCRIPTION("A PCIe LKM");

static struct pci_device_id pcittl32io_ids[]={
    {PCI_DEVICE(PCITTL32IO_VENDOR_ID, PCITTL32IO_DEVICE_ID)},
    { }
};

MODULE_DEVICE_TABLE(pci, pcittl32io_ids);



/* @brief This function is called, when a pci device is registered into the kernel
  *
  *@param dev
  *@param id
  *@return 
*/

static int pcittl32io_probe(struct pci_dev *dev, const struct pci_device_id *id){
    printk("pcittl32io - Now in the probe function");
    return 0;
}

/* @brief This function is called, when a pci device is unregistered from the kernel
  *
  *@param dev
*/
static void pcittl32io_remove(struct pci_dev *dev){
    printk("pcittl32io - Now in the remove function");
}


/*PCI driver struct*/

static struct pci_driver pcittl32io_driver = {
    .name = "pcittl32io",
    .id_table = pcittl32io_ids,
    .probe = pcittl32io_probe,
    .remove = pcittl32io_remove
};


/*This function is called when the module is loaded into the kernel*/
static int __init my_init(void){
    printk("pcittl32io - Registering the PCI device \n");
    return pci_register_driver(&pcittl32io_driver);
}

/*This function is called when the module is removed from the kernel*/

static void __exit my_exit(void){
    printk("pcittl32io - Unregistering the PCI device \n");
    pci_unregister_driver(&pcittl32io_driver);
}

module_init(my_init);
module_exit(my_exit);

obj-m += mymodule.o

all:
	make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules

clean:
	make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean

使用insmod后也可以看到正常加载:

可以基于这个驱动做些练习

以下代码加入了对BAR0和BAR1的映射:

#include <linux/module.h>
#include <linux/init.h>
#include <linux/pci.h>





#include <linux/module.h>
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/pci.h>
#include <linux/interrupt.h>
#include <linux/kdev_t.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/sched.h>
#include <linux/poll.h>
#include <linux/mm.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/serial.h>
#include <linux/serial_core.h>
#include <linux/serial_reg.h>
#include <linux/device.h>
#include <linux/time.h>
#include <linux/pps_kernel.h>
#include <linux/version.h>
#include <linux/slab.h>
#include <asm/page.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <asm/atomic.h>



// These have to match a physical device attached to a PCIe slot
#define PCITTL32IO_VENDOR_ID 0x10EE
#define PCITTL32IO_DEVICE_ID 0x7012

#define DRV_NAME		"pcittl32io"
#define PFX			DRV_NAME ": "

#ifndef PCI_EXP_DEVCTL_READRQ_4096B
#define PCI_EXP_DEVCTL_READRQ_4096B 0x5000


/* Meta Information */

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Shakil Ahmed");
MODULE_DESCRIPTION("A PCIe LKM");

static struct pci_device_id pcittl32io_ids[]={
    {PCI_DEVICE(PCITTL32IO_VENDOR_ID, PCITTL32IO_DEVICE_ID)},
    { }
};


/*

static struct pci_device_id xtrx_pci_table[] = {
	{ PCI_DEVICE(0x10EE, 0xFAE3),
	  .driver_data = 0 },
	{ PCI_DEVICE(0x10EE, 0x7011),
	  .driver_data = 1 },
	{ PCI_DEVICE(0x10EE, 0x7012),
	  .driver_data = 2 },
	{ 0, }
};
*/






MODULE_DEVICE_TABLE(pci, pcittl32io_ids);



/* @brief This function is called, when a pci device is registered into the kernel
  *
  *@param dev
  *@param id
  *@return 
*/

#endif



#define BAR0_WR(a,o,v  )	 iowrite32(cpu_to_be32(v), (void __iomem *)((unsigned long)a + 4*o)) 
#define BAR0_RD(a,o)         be32_to_cpu(ioread32((void __iomem *)((unsigned long)a + 4*o))) 

	void __iomem* bar0_addr;
	void __iomem* bar1_addr;
static int pcittl32io_probe(struct pci_dev *pdev, const struct pci_device_id *id){
    printk("pcittl32io - Now in the probe function");

    int err ;

	err = pci_enable_device(pdev);
	if (err) {
		dev_err(&pdev->dev, "Cannot enable PCI device, "
			"aborting.\n");
		return err;
	}

	printk(KERN_INFO PFX "liwei:  pcittl32io_probe   [%d] \n",  __LINE__ );

	/* Reconfigure MaxReadReq to 4KB */
	pcie_capability_clear_and_set_word(pdev, PCI_EXP_DEVCTL,
					   PCI_EXP_DEVCTL_READRQ, PCI_EXP_DEVCTL_READRQ_4096B);

	pci_set_master(pdev);

	if (pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32))) {
		dev_err(&pdev->dev,"No suitable consistent DMA available.\n");
		goto err_disable_pdev;
	} 
 
	/*
	 * Check for BARs.  We expect 0: 4KB
	 */    
	if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM) ||
		pci_resource_len(pdev, 0) < 1 << 10) {
		dev_err(&pdev->dev, "Missing UL BAR, aborting.\n");
		err = -ENODEV;
		goto err_disable_pdev;
	} //获取bar0 
    
    	err = pci_request_regions(pdev, DRV_NAME);
	if (err) {
		dev_err(&pdev->dev, "Cannot obtain PCI resources, "
			"aborting.\n");
		goto err_disable_pdev;
	}//开始获取资源

	bar0_addr = pci_iomap(pdev, 0,  1 << 12);
	if (!bar0_addr) {
		dev_err(&pdev->dev, "Failed to map BAR 0.\n");
		goto err_free_res;
	}

	bar1_addr = pci_iomap(pdev, 1,  1 << 16);
	if (!bar0_addr) {
		dev_err(&pdev->dev, "Failed to map BAR 1.\n");
		goto err_unmap0;
	}

int i , r ;
///for(i=0;i<100;++i)    BAR0_WR( bar0_addr , i , i   ) ;   
for(i=0;i<16;++i)   {
     BAR0_WR( bar0_addr , i , i   ) ;   
     r = BAR0_RD( bar0_addr ,  i  ) ;    //  BAR0_WR( bar0_addr , i , i   ) ; 
    printk(KERN_INFO PFX "read%d = %08d \n" ,  i , r );
}

	 printk(KERN_INFO PFX "liwei:  bar0  bar1 now ready   [%d] \n",  __LINE__ );
   


  
return 0 ;

err_unmap1:
	pci_iounmap(pdev, bar1_addr);
err_unmap0:
	pci_iounmap(pdev, bar0_addr);
err_free_res:
	pci_release_regions(pdev);

err_disable_pdev:
	pci_clear_master(pdev); /* Nobody seems to do this */

	pci_disable_device(pdev);
	pci_set_drvdata(pdev, NULL);
	return err;

    
 
}

/* @brief This function is called, when a pci device is unregistered from the kernel
  *
  *@param dev
*/
static void pcittl32io_remove(struct pci_dev *pdev){
    printk("pcittl32io - Now in the remove function");





//	struct xtrx_dev* xtrxdev = pci_get_drvdata(pdev);
	
	printk(KERN_INFO PFX "liwei:   pcittl32io_remove  [%d] \n",  __LINE__ );
	 /printk(KERN_INFO PFX "Removing device %s\n", pci_name(pdev));

	/* Disable interrupts */
	//xtrx_writel(xtrxdev, GP_PORT_WR_INT_PCIE, (1U << INT_PCIE_I_FLAG));
	/* Clear pending interrupts */
	//xtrx_readl(xtrxdev, GP_PORT_RD_INTERRUPTS);

	//cdev_del(&xtrxdev->cdev);
	//device_destroy(xtrx_class, MKDEV(MAJOR(dev_first), MINOR(xtrxdev->devno)));




//err_unmap1:
	pci_iounmap(pdev, bar1_addr);
//err_unmap0:
	pci_iounmap(pdev, bar0_addr);
//err_free_res:
	pci_release_regions(pdev);

//err_disable_pdev:
	pci_clear_master(pdev); /* Nobody seems to do this */

	pci_disable_device(pdev);
	pci_set_drvdata(pdev, NULL);
  

}


/*PCI driver struct*/

static struct pci_driver pcittl32io_driver = {
    .name = "pcittl32io",
    .id_table = pcittl32io_ids,
    .probe = pcittl32io_probe,
    .remove = pcittl32io_remove
};


/*This function is called when the module is loaded into the kernel*/
static int __init my_init(void){
    printk("pcittl32io - Registering the PCI device \n");
    return pci_register_driver(&pcittl32io_driver);
}

/*This function is called when the module is removed from the kernel*/

static void __exit my_exit(void){
    printk("pcittl32io - Unregistering the PCI device \n");
    pci_unregister_driver(&pcittl32io_driver);
}

module_init(my_init);
module_exit(my_exit);
vivado 项目以及linux驱动打包文件如下:


链接:https://pan.baidu.com/s/1zpBpLLttvSIBMPxnCmAgAQ 
提取码:1asm 

vivado版本是2019.1 在XC7A35T的XTRX硬件上运行通过。 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值