PCIE-MSI中断LINUX驱动-imt_driv.c
			 2025-07-16
			  9
			 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");
 PCIE-MIS/MSIX中断
			PCIE-MIS/MSIX中断
			




