首页 > 系统相关 >Linux源码阅读笔记20-PCI设备驱动详解

Linux源码阅读笔记20-PCI设备驱动详解

时间:2024-08-08 23:25:58浏览次数:16  
标签:20 irq dev pci printk 源码 Mcard PCI

PCI基础

  1. PCI总线为高性能局部总线,主要解决外部设备之间以及外部设备与主机之间高速数据传输。在数字图形、图像等处理,以及告诉实时数据采集与处理等队数据传输速率要求高的应用中,采用PCI总线进行数据传输。
  2. PCI规范能够实现32位并行数据传输,工作频率为33MHz或66MHz,最大吞吐率为266MB/s。PCI-E是目前PCI系列最具代表性的一种,与并行PCI总线区别在于它采用串行传输数据模式,最大支持32个串行连接。每个传输方向上吞吐率为250MB/s,方向上总传输速率达8GB/s。
  3. 串行通讯比并行通讯速度快,成本低。比如PCIe64位总线,133MHz,吞吐率1GB/s,内存于台式机和服务器,比PCI宽,但是能插入PCI卡。
  4. PCI总线特点
    • 具有隐含的中央仲裁系统。
    • 具有与处理器和存储器自诩痛完全并行操作的能力。
    • 提供地址和数据的奇偶校验,完全的多总线主控能力。

PCI数据结构

  1. 连接CPU和PCI系统对应的数据结构类型pci_host_bridge

  1. 描述PCI总线对应的数据结构类型pci_bus

  1. 用于指向PCI读写操作函数集的结构体类型pci_ops

  1. 专门用于描述总线的物理插槽的结构体类型pci_slot

  1. PCI设备结构体类型pci_dev

  1. PCI驱动程序结构体类型pci_driver

  1. PCI卡标识结构类型pci_driver_i

PCI驱动实例

/* PCI设备驱动编程,必须包括两个核心重要的头文件 */
#include <linux/module.h>
#include <linux/pci.h>

/* 用户自定义结构体类型,作用于中断服务函数里面 */
struct pci_Card 
{
   resource_size_t io;
   long range, flags;
   void __iomem *ioaddr;
   int irq;
};


static struct pci_device_id ids[] = 
{
    { 
        PCI_DEVICE(PCI_VENDOR_ID_INTEL,
        0x100f)
    },

    { 
        PCI_DEVICE(PCI_VENDOR_ID_INTEL, 
        PCI_DEVICE_ID_INTEL_80332_0) 
    },

    {0,}
};


MODULE_DEVICE_TABLE(pci, ids);


void skel_get_configs(struct pci_dev *dev) 
{

    uint8_t revisionId;
    uint16_t vendorId, deviceId;
    uint32_t classId;

    pci_read_config_word(dev, PCI_VENDOR_ID, &vendorId);
    printk("vendorID = %x", vendorId);

    pci_read_config_word(dev, PCI_DEVICE_ID, &deviceId);
    printk("deviceID = %x", deviceId);

    pci_read_config_byte(dev, PCI_REVISION_ID, &revisionId);
    printk("revisionID = %x",revisionId);

    pci_read_config_dword(dev, PCI_CLASS_REVISION, &classId);
    printk("classID = %x",classId);
}


static irqreturn_t pci_Mcard_interrupt(int irq, void *dev_id) 
{
   struct pci_Card *pci_Mcard = (struct pci_Card *)dev_id;

   printk("irq = %d, pci_Mcard_irq = %d\n", irq, pci_Mcard->irq);
   return IRQ_HANDLED;
}


static int probe(struct pci_dev *dev, const struct pci_device_id *id) 
{
    int retval = 0;
    struct pci_Card *pci_Mcard;
    printk("probe func\n"); 
    
    /* 设备使能 */
    if(pci_enable_device(dev)) {
        printk (KERN_ERR "IO Error.\n");
        return -EIO;
    }

    pci_Mcard = kmalloc(sizeof(struct pci_Card),GFP_KERNEL);
    if(!pci_Mcard) {
        printk("In %s,kmalloc err!",__func__);
        return -ENOMEM;
    }

    /* 设备中断号 */
    pci_Mcard->irq = dev->irq;
    if(pci_Mcard->irq < 0) {
        printk("IRQ is %d, it's invalid!\n",pci_Mcard->irq);
        goto out_pci_Mcard;
    }

    /*获取io内存相关信息*/
    pci_Mcard->io = pci_resource_start(dev, 0);
    pci_Mcard->range = pci_resource_end(dev, 0) - pci_Mcard->io + 1;
    pci_Mcard->flags = pci_resource_flags(dev,0);
    printk("start %llx %lx %lx\n",pci_Mcard->io, pci_Mcard->range, pci_Mcard->flags);
    printk("PCI base addr 0 is io%s.\n",(pci_Mcard->flags & IORESOURCE_MEM)? "mem":"port");

    /*防止地址访问冲突,所以这里先申请*/
    retval = pci_request_regions(dev,"pci_module");
    if(retval) {
        printk("PCI request regions err!\n");
        goto out_pci_Mcard;
    }

    /*再进行映射*/
    pci_Mcard->ioaddr = pci_ioremap_bar(dev, 0);
    if(!pci_Mcard->ioaddr) {
      printk("ioremap err!\n");
      retval = -ENOMEM;
      goto out_regions;
    }

    /*申请中断IRQ并设定中断服务子函数*/
    retval = request_irq(pci_Mcard->irq, pci_Mcard_interrupt, IRQF_SHARED, "pci_module", pci_Mcard);
    if(retval) {
      printk (KERN_ERR "Can't get assigned IRQ %d.\n",pci_Mcard->irq);
      goto out_iounmap;
    }

    pci_set_drvdata(dev, pci_Mcard);
    skel_get_configs(dev);
    return 0;

out_iounmap:
    iounmap(pci_Mcard->ioaddr);
out_regions:
    pci_release_regions(dev);
out_pci_Mcard:
    kfree(pci_Mcard);
    return retval;
}

/* 移除PCI设备 */
static void remove(struct pci_dev *dev) 
{
   struct pci_Card *pci_Mcard = pci_get_drvdata(dev);
   free_irq (pci_Mcard->irq, pci_Mcard);
   iounmap(pci_Mcard->ioaddr);
   pci_release_regions(dev);
   kfree(pci_Mcard);
   pci_disable_device(dev);
   printk("remove pci device ok\n");
}

/* 结构体成员变量填充 */
static struct pci_driver pci_driver = 
{
    .name = "pci_module",
    .id_table = ids,
    .probe = probe,
    .remove = remove,
};

/* 模块入口函数 */
static int __init pci_module_init(void) 
{
    printk("PCI module entry function\n");

    return pci_register_driver(&pci_driver);
}

/* 模块退出函数 */
static void __exit pci_module_exit(void) 
{
    printk("PCI module exit function.\n");

    // PCI驱动被卸载时,需要调用pci_unregister_driver
    pci_unregister_driver(&pci_driver);
}

MODULE_LICENSE("GPL");

module_init(pci_module_init);
module_exit(pci_module_exit);



标签:20,irq,dev,pci,printk,源码,Mcard,PCI
From: https://blog.csdn.net/H520xcodenodev/article/details/141038824

相关文章

  • Java毕业设计 基于Springboot+Vue的公司单位高校党建系统(源码+lw+部署文档+讲解等)
    文末获取资源,收藏关注不迷路文章目录前言主要使用技术研究内容核心代码文章目录前言随着经济的发展,人员交流来往的频繁,党员管理更加需要一套信息系统以提高信息管理的快捷及准确性。智慧党建系统是高校党委组织工作不可缺少的一部分,各功能齐全、简单有用的智慧党建......
  • 2024最新ai视频代码
    importcv2#加载预训练模型(例如YOLOv3)net=cv2.dnn.readNet("yolov3.weights","yolov3.cfg")#加载COCO数据集类别标签withopen("coco.names","r")asf:classes=[line.strip()forlineinf.readlines()]#配置模型的输入和输出layer_na......
  • 河南萌新联赛2024第(四)场
    题目链接:河南萌新联赛2024第(四)场:河南理工大学_ACM/NOI/CSP/CCPC/ICPC算法编程高难度练习赛_牛客竞赛OJ1.小雷的神奇电脑同或概念:•如果两个输入位相同,则输出为1•如果两个输入位不同,则输出为0 所以可以发现规律,最大同或一定出现在相邻两个数(二进制下位相同多),同时利......
  • 2024牛客多校第七场
    K贪心地先凑出前后端后,中间的部分是本质不同的子序列个数然后枚举可以重叠的部分,如果可以重叠肯定是回文后缀有不少细节,比如空串,重叠部分要求后面的能取到#include<cstdio>#include<iostream>#defineintlonglong#defineULLunsignedlonglongusingnamespacestd;......
  • JAVA+SQL办公自动化系统(毕设+实现+源码+数据库)
    摘  要极光办公自动化系统是针对南开创元信息技术有限公司开发的,专门用于企业内部员工信息交流的软件,其开发过程主要包括前端应用程序的开发和后端数据库的建立两个方面。对于前者要求应用程序功能完备操作简单,对于后者要求建立起数据一致性、完整性和安全性好的数据库......
  • 2024牛客多校第八场
    E观察到s(m)<=108,所以r是可以枚举的但是枚举完后再开根号,时间复杂度为O(T*r*sqrt(n))≈O(100*100*1e6)赛时还想了一种自认为更优的做法。考虑枚举i,枚举完i就能得到r,判断是否满足条件(当然,就像分解质因数那样,n/i也要判断)然后直接这么写会出点小问题,比如11=10*1+1,i=1时11%1=0在......
  • win7一键修复所有dll缺失详细方法,7个dll修复方法深度解析(2024)
    dll文件是一种包含函数和其他关键信息的文件,供Windows应用程序使用。虽然大多数普通用户对.dll文件的具体工作原理并不熟悉,但这些文件对于系统应用来说是至关重要的。通常情况下,人们在遇到因DLL文件缺失或损坏而导致的错误时,才会接触到它们。对于非专业用户来说,理解这些错......
  • 会话管理Cookie和Session(源码级讲解、超详细)
    文章目录1.会话管理概述1.1为什么需要会话管理1.1.2会话管理实现的手段2Cookie2.1Cookie概述2.2Cookie的使用2.3Cookie的时效性2.4Cookie的提交路径3.Session3.1HttpSession概述3.2HttpSession的使用3.3HttpSession时效性1.会话管理概述1.1为什么......
  • 基于YOLOv10深度学习的交通信号灯检测识别系统【python源码+Pyqt5界面+数据集+训练代
    《博主简介》小伙伴们好,我是阿旭。专注于人工智能、AIGC、python、计算机视觉相关分享研究。✌更多学习资源,可关注公-仲-hao:【阿旭算法与机器学习】,共同学习交流~......
  • [lnsyoj2073/luogu5911]PRZ
    题意给定由\(n\)个二元组\((t,w)\)组成的集合\(S\)和常数\(W\),需要将\(S\)分为任意多个非空子集\(sub_1,sub_2,\cdots,sub_k\),求:\[\min\{\sum_{i=1}^k\max_{j\insub_i}\{t_j\}(\sum_{j\insub_i}w_j\leW)\}\]sol数据范围较小,显然状态压缩DP。状态比较好想,\(f_......