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

简介: Linux源码阅读笔记20-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);


相关文章
|
7月前
|
安全 Linux 网络安全
Nipper 3.9.0 for Windows & Linux - 网络设备漏洞评估
Nipper 3.9.0 for Windows & Linux - 网络设备漏洞评估
208 0
Nipper 3.9.0 for Windows & Linux - 网络设备漏洞评估
|
8月前
|
数据采集 编解码 运维
一文讲完说懂 WowKey -- WowKey 是一款 Linux 类设备的命令行(CLT)运维工具
WowKey 是一款面向 Linux 类设备的命令行运维工具,支持自动登录、批量执行及标准化维护,适用于企业、团队或个人管理多台设备,显著提升运维效率与质量。
|
9月前
|
监控 Linux 开发者
理解Linux操作系统内核中物理设备驱动(phy driver)的功能。
综合来看,物理设备驱动在Linux系统中的作用是至关重要的,它通过与硬件设备的紧密配合,为上层应用提供稳定可靠的通信基础设施。开发一款优秀的物理设备驱动需要开发者具备深厚的硬件知识、熟练的编程技能以及对Linux内核架构的深入理解,以确保驱动程序能在不同的硬件平台和网络条件下都能提供最优的性能。
493 0
|
11月前
|
运维 监控 中间件
Linux运维笔记 - 如何使用WGCLOUD监控交换机的流量
WGCLOUD是一款开源免费的通用主机监控工具,安装使用都非常简单,它可以监控主机、服务器的cpu、内存、磁盘、流量等数据,也可以监控数据库、中间件、网络设备
|
11月前
|
安全 Ubuntu Linux
Nipper 3.8.0 for Windows & Linux - 网络设备漏洞评估
Nipper 3.8.0 for Windows & Linux - 网络设备漏洞评估
475 0
Nipper 3.8.0 for Windows & Linux - 网络设备漏洞评估
|
运维 安全 Linux
试试Linux设备命令行运维工具——Wowkey
WowKey 是一款专为 Linux 设备设计的命令行运维工具,提供自动化、批量化、标准化、简单化的运维解决方案。它简单易用、高效集成且无依赖,仅需 WIS 指令剧本文件、APT 账号密码文件和 wowkey 命令即可操作。通过分离鉴权内容与执行内容,WowKey 让运维人员专注于决策,摆脱繁琐的交互与执行细节工作,大幅提升运维效率与质量。无论是健康检查、数据采集还是配置更新,WowKey 都能助您轻松应对大规模设备运维挑战。立即从官方资源了解更多信息:https://atsight.top/training。
|
数据采集 运维 安全
Linux设备命令行运维工具WowKey问答
WowKey 是一款用于 Linux 设备运维的工具,可通过命令行手动或自动执行指令剧本,实现批量、标准化操作,如健康检查、数据采集、配置更新等。它简单易用,只需编写 WIS 指令剧本和 APT 帐号密码表文件,学习成本极低。支持不同流派的 Linux 系统,如 RHEL、Debian、SUSE 等,只要使用通用 Shell 命令即可通吃Linux设备。
|
监控 Shell Linux
Android调试终极指南:ADB安装+多设备连接+ANR日志抓取全流程解析,覆盖环境变量配置/多设备调试/ANR日志分析全流程,附Win/Mac/Linux三平台解决方案
ADB(Android Debug Bridge)是安卓开发中的重要工具,用于连接电脑与安卓设备,实现文件传输、应用管理、日志抓取等功能。本文介绍了 ADB 的基本概念、安装配置及常用命令。包括:1) 基本命令如 `adb version` 和 `adb devices`;2) 权限操作如 `adb root` 和 `adb shell`;3) APK 操作如安装、卸载应用;4) 文件传输如 `adb push` 和 `adb pull`;5) 日志记录如 `adb logcat`;6) 系统信息获取如屏幕截图和录屏。通过这些功能,用户可高效调试和管理安卓设备。
|
Linux API 开发工具
FFmpeg开发笔记(五十九)Linux编译ijkplayer的Android平台so库
ijkplayer是由B站研发的移动端播放器,基于FFmpeg 3.4,支持Android和iOS。其源码托管于GitHub,截至2024年9月15日,获得了3.24万星标和0.81万分支,尽管已停止更新6年。本文档介绍了如何在Linux环境下编译ijkplayer的so库,以便在较新的开发环境中使用。首先需安装编译工具并调整/tmp分区大小,接着下载并安装Android SDK和NDK,最后下载ijkplayer源码并编译。详细步骤包括环境准备、工具安装及库编译等。更多FFmpeg开发知识可参考相关书籍。
785 0
FFmpeg开发笔记(五十九)Linux编译ijkplayer的Android平台so库
|
Linux 开发工具 数据安全/隐私保护