PCIE-MSI中断LINUX驱动-imt_driv.c
2025-07-16
0
0
#include <linux/io.h>
#include <linux/types.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kthread.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/err.h>
#include <linux/delay.h>
#include <linux/poll.h>
#include "imt_drv.h"
/***************************************************************
全局变量定义
****************************************************************/
imt_test_pci_dev_s g_imt_pci_dev;
static void imt_tasklet_handler (unsigned long data)
{
printk("Enter imt tasklet\n");
enable_irq(pci_irq_vector(g_imt_pci_dev.pci_dev, 0));
}
DECLARE_TASKLET(imt_test_handler, imt_tasklet_handler, 0);
static irqreturn_t imt_irq_handle(int irq, void* dev_id)
{
printk("imt_irq_handle %d\n", irq);
disable_irq(irq);
tasklet_schedule(&imt_test_handler);
return IRQ_HANDLED;
}
static int imt_test_open(struct inode *inode, struct file *filp)
{
filp->private_data = &g_imt_pci_dev;
return 0;
}
static int imt_test_release(struct inode *inode, struct file *filp)
{
return 0;
}
static struct file_operations imt_test_fops = {
.open = imt_test_open,
.release = imt_test_release,
.owner = THIS_MODULE,
};
unsigned int imt_test_irq_num = 0;
/**
* @brief 初始化设备
*
* @param pci_dev
* @param pci_id
* @return int
*/
static int imt_test_probe(struct pci_dev *pci_dev, const struct pci_device_id *pci_id)
{
int ret;
int i;
int msi_num;
int irq_num;
imt_test_pci_dev_s *privdata;
printk("imt enter probe\n");
memset(&g_imt_pci_dev, 0, sizeof(imt_test_pci_dev_s));
privdata = &g_imt_pci_dev;
if(pci_enable_device(pci_dev)) {
printk(KERN_ERR "%s:cannot enable device\n", pci_name(pci_dev));
return -ENODEV;
}
/* 对PCI区进行标记,标记该区域已经分配出去*/
ret = pci_request_regions(pci_dev, IMT_TEST_DEV_NAME);
if(ret) {
printk("pci_request_regions failed ret:%d\n", ret);
return ret;
}
pci_set_master(pci_dev);
pci_set_drvdata(pci_dev, privdata);
g_imt_pci_dev.pci_dev = pci_dev;
ret = alloc_chrdev_region(&g_imt_pci_dev.dev_num, 0, 1, IMT_TEST_DEV_NAME);
cdev_init(&privdata->cdev, &imt_test_fops);
cdev_add(&privdata->cdev, privdata->dev_num, 1);
privdata->cdev_class = class_create(THIS_MODULE, IMT_TEST_DEV_NAME);
device_create(privdata->cdev_class, NULL, privdata->dev_num, pci_dev, IMT_TEST_DEV_NAME);
msi_num = pci_alloc_irq_vectors(pci_dev, 1, 32, PCI_IRQ_MSI);
printk("pci_alloc_irq_vectors return %d\n", msi_num);
if (msi_num == 32) {
irq_num = pci_irq_vector(pci_dev, 0);
for (i = 0; i < 32; i++) {
if ((ret = devm_request_irq(&pci_dev->dev, irq_num + i, imt_irq_handle, 0,"imt_msi", pci_dev)) < 0){
printk("Cannot request irq %d, ret=%d\n", irq_num, ret);
return -1;
} else {
printk("request irq %d, ret=%d success\n", irq_num, ret);
}
}
} else {
printk("Error: pci_alloc_irq_vectors alloc 32 irqs failed. msi_num:%d\n", msi_num);
return -1;
}
printk("imt_test_probe end successful\n");
return 0;
}
static void imt_test_remove(struct pci_dev *pci_dev)
{
unsigned int i;
printk("imt_test_remove enter\n");
device_destroy(g_imt_pci_dev.cdev_class, g_imt_pci_dev.dev_num);
class_destroy(g_imt_pci_dev.cdev_class);
unregister_chrdev_region(g_imt_pci_dev.dev_num, 1);
for (i = 0; i < 32; i++) {
devm_free_irq(&pci_dev->dev, pci_irq_vector(pci_dev, i), pci_dev);
}
iounmap((void*)g_imt_pci_dev.ioaddr);
pci_release_regions(pci_dev);
pci_set_drvdata(pci_dev, NULL);
pci_disable_device(pci_dev);
printk("imt_test_remove end\n");
}
static struct pci_device_id imt_test_tbl[] = {
{IMT_TEST_VENDOR_ID, IMT_TEST_DEVICE_ID_0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
{ 0,}
};
MODULE_DEVICE_TABLE(pci, imt_test_tbl);
static struct pci_driver imt_test_driver = {
.name = IMT_MODULE_NAME, ///< 驱动的名字,一般是一个宏定义
.id_table = imt_test_tbl, ///< 包含了相关物理PCI设备的基本信息,vendorID,deviceID
.probe = imt_test_probe, ///< 用于发现PCI设备
.remove = imt_test_remove,
};
static int __init imt_test_init_module(void)
{
return pci_register_driver(&imt_test_driver);
}
static void __exit imt_test_cleanup_module(void)
{
pci_unregister_driver(&imt_test_driver);
}
module_init(imt_test_init_module);
module_exit(imt_test_cleanup_module);
MODULE_LICENSE("GPL");