Linux驱动开发实战之PCIE驱动(一)

以下是针对Linux下PCI设备驱动开发的详细步骤指南及示例代码,适合刚入门的小白逐步学习和实践:


一、开发环境准备

  1. 安装开发工具
    sudo apt install build-essential linux-headers-$(uname -r)
    
  2. 创建项目目录
    mkdir pci_driver && cd pci_driver
    

二、编写最简单的PCI驱动框架

1. 创建驱动源码文件 my_pci_driver.c
#include <linux/module.h>
#include <linux/pci.h>/* 定义驱动支持的PCI设备ID列表 */
static const struct pci_device_id my_pci_ids[] = {{ PCI_DEVICE(0x1234, 0x5678) }, // 替换为你的设备厂商ID和设备ID{ 0, }  // 结束标记
};
MODULE_DEVICE_TABLE(pci, my_pci_ids);/* PCI设备探测函数(当系统发现匹配设备时调用) */
static int my_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{printk(KERN_INFO "My PCI Driver: Device detected!\n");return 0; // 返回0表示成功
}/* PCI设备移除函数(驱动卸载或设备拔出时调用) */
static void my_pci_remove(struct pci_dev *pdev)
{printk(KERN_INFO "My PCI Driver: Device removed.\n");
}/* 定义PCI驱动结构体 */
static struct pci_driver my_pci_driver = {.name     = "my_pci_driver",   // 驱动名称.id_table = my_pci_ids,        // 支持的设备ID表.probe    = my_pci_probe,      // 探测函数.remove   = my_pci_remove,     // 移除函数
};/* 模块加载函数 */
static int __init my_pci_init(void)
{return pci_register_driver(&my_pci_driver);
}/* 模块卸载函数 */
static void __exit my_pci_exit(void)
{pci_unregister_driver(&my_pci_driver);
}module_init(my_pci_init);
module_exit(my_pci_exit);MODULE_LICENSE("GPL");
MODULE_AUTHOR("Your Name");
MODULE_DESCRIPTION("Simple PCI Driver Example");
2. 创建Makefile
obj-m += my_pci_driver.oall:make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modulesclean:make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean

三、获取设备厂商ID与设备ID

  1. 查找PCI设备信息

    lspci -nn  # 显示所有PCI设备,例如:# 01:00.0 Ethernet controller [0200]: Intel Corporation Device [8086:1533]
    
    • 8086是厂商ID(Vendor ID)
    • 1533是设备ID(Device ID)
  2. 修改代码中的PCI_DEVICE宏

    { PCI_DEVICE(0x8086, 0x1533) }, // 替换为你的设备ID
    

四、编译与加载驱动

  1. 编译驱动

    make  # 生成my_pci_driver.ko文件
    
  2. 加载驱动

    sudo insmod my_pci_driver.ko
    
  3. 查看日志

    dmesg | tail  # 应显示"Device detected!"
    
  4. 卸载驱动

    sudo rmmod my_pci_driver
    dmesg | tail  # 显示"Device removed."
    

五、进阶功能实现

1. 启用PCI设备与映射内存
static int my_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{int ret;void __iomem *regs;// 启用PCI设备ret = pci_enable_device(pdev);if (ret) {printk(KERN_ERR "Failed to enable PCI device\n");return ret;}// 请求内存区域(假设使用BAR0)ret = pci_request_regions(pdev, "my_pci_driver");if (ret) {printk(KERN_ERR "Failed to request regions\n");goto err_disable;}// 映射BAR0到内核虚拟地址regs = pci_ioremap_bar(pdev, 0);if (!regs) {printk(KERN_ERR "Failed to map BAR0\n");ret = -ENOMEM;goto err_release;}// 示例:读取第一个寄存器(假设32位)u32 value = ioread32(regs);printk(KERN_INFO "Register value: 0x%x\n", value);// 保存映射地址到设备私有数据pci_set_drvdata(pdev, regs);return 0;err_release:pci_release_regions(pdev);
err_disable:pci_disable_device(pdev);return ret;
}static void my_pci_remove(struct pci_dev *pdev)
{void __iomem *regs = pci_get_drvdata(pdev);iounmap(regs);pci_release_regions(pdev);pci_disable_device(pdev);
}
2. 处理中断
#include <linux/interrupt.h>static irqreturn_t my_pci_interrupt(int irq, void *dev_id)
{struct pci_dev *pdev = dev_id;void __iomem *regs = pci_get_drvdata(pdev);// 读取中断状态寄存器u32 status = ioread32(regs + 0x10);if (status & 0x1) {printk(KERN_INFO "Interrupt occurred!\n");// 清除中断标志iowrite32(status & 0x1, regs + 0x10);return IRQ_HANDLED;}return IRQ_NONE;
}// 在probe函数中添加:
ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_LEGACY);
if (ret < 0) {printk(KERN_ERR "Failed to allocate IRQ\n");goto err_unmap;
}ret = request_irq(pci_irq_vector(pdev, 0), my_pci_interrupt,IRQF_SHARED, "my_pci_irq", pdev);
if (ret) {printk(KERN_ERR "Failed to request IRQ\n");goto err_irq;
}// 在remove函数中添加:
free_irq(pci_irq_vector(pdev, 0), pdev);
pci_free_irq_vectors(pdev);

六、调试技巧

  1. 查看驱动日志

    dmesg -w  # 实时监控内核日志
    
  2. 检查设备是否被识别

    lspci -v -s 01:00.0  # 替换为你的设备地址
    
  3. 查看驱动加载状态

    lsmod | grep my_pci_driver
    

七、注意事项

  1. 内核版本兼容性:确保头文件路径正确(/lib/modules/$(uname -r)/build)。
  2. 内存安全:使用ioread32/iowrite32访问寄存器,避免直接指针操作。
  3. 错误处理:所有内核函数调用必须检查返回值!
  4. 测试环境:建议在虚拟机或专用开发板测试,避免主机崩溃。

通过以上步骤,可以逐步构建一个完整的PCI设备驱动。实际开发中需根据具体硬件手册调整寄存器操作和中断处理逻辑。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/72578.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【 <二> 丹方改良:Spring 时代的 JavaWeb】之 Spring Boot 的自动配置:约定优于配置的设计美学

<前文回顾> 点击此处查看 合集 https://blog.csdn.net/foyodesigner/category_12907601.html?fromshareblogcolumn&sharetypeblogcolumn&sharerId12907601&sharereferPC&sharesourceFoyoDesigner&sharefromfrom_link <今日更新> 一、Spring…

SourceTree的安装与使用

SourceTree的安装与使用 一、前言 作为可视化Git管理工具&#xff0c;SourceTree可以避免我们使用命令进行常规的代码拉取&#xff0c;更新&#xff0c;合并等操作。 鼠标点点就可以完成代码管理的工作。所以强烈推荐可视化的工具。不过SourceTree还是有点bug&#xff0c;比…

JMeter 性能测试

Jmeter 用户手册 名词解释&#xff1a; RPS&#xff1a;每秒请求数-每秒向服务器发送多少请求数&#xff08;一个场景&#xff0c;系统面临多大的压力&#xff09; TPS&#xff1a;每秒事务数-每秒能够处理多少请求/事务数性能评价标准&#xff08;其中的一个核心指标&#x…

Go语言的负载均衡

Go语言的负载均衡 引言 在互联网快速发展的今天&#xff0c;服务器的压力越来越大。随着用户的增加&#xff0c;单一服务器很难满足所有请求&#xff0c;导致延迟增加&#xff0c;服务质量下降。负载均衡&#xff0c;作为一种重要的技术手段&#xff0c;能够有效地分散用户请…

【Mac 从 0 到 1 保姆级配置教程 09】09. 快速配置终端复用工具 tmux 和 oh-my-tmux

文章目录 1. 前言2. 安装 tmux3. 配置 tmux4. 安装 oh-my-tmux5. 最后6. 参考资料7. 系列教程 Mac 从 0 到 1 保姆级配置教程目录&#xff0c;点击即可跳转对应文章&#xff1a; 【Mac 从 0 到 1 保姆级配置教程 00】 - 教程说明 【Mac 从 0 到 1 保姆级配置教程 01】 - 安装无…

【每日学点HarmonyOS Next知识】屏幕参数、半模态相关、三集联动、只显示部分卡面,自定义绘制

1、HarmonyOS 需要 获取屏幕 xdpi 与 ydpi 数据&#xff1f; 可以通过display.getDefaultDisplaySync参考链接&#xff1a;https://developer.huawei.com/consumer/cn/doc/harmonyos-references-V5/js-apis-display-V5 ohos.display (屏幕属性) &#xff1a;屏幕属性提供管理…

Java 大视界 -- 基于 Java 的大数据机器学习模型的迁移学习应用与实践(129)

&#x1f496;亲爱的朋友们&#xff0c;热烈欢迎来到 青云交的博客&#xff01;能与诸位在此相逢&#xff0c;我倍感荣幸。在这飞速更迭的时代&#xff0c;我们都渴望一方心灵净土&#xff0c;而 我的博客 正是这样温暖的所在。这里为你呈上趣味与实用兼具的知识&#xff0c;也…

通义万相 2.1 与蓝耘智算平台的深度协同,挖掘 AIGC 无限潜力并释放巨大未来价值

我的个人主页 我的专栏&#xff1a; 人工智能领域、java-数据结构、Javase、C语言&#xff0c;希望能帮助到大家&#xff01;&#xff01;&#xff01; 点赞&#x1f44d;收藏❤ 引言&#xff1a;AIGC 浪潮下的新机遇 在当今数字化飞速发展的时代&#xff0c;人工智能生成内容&…

【BERT和GPT的区别】

BERT采用完形填空&#xff08;Masked Language Modeling, MLM&#xff09;与GPT采用自回归生成&#xff08;Autoregressive Generation&#xff09;的差异&#xff0c;本质源于两者对语言建模的不同哲学导向与技术目标的根本分歧。这种选择不仅塑造了模型的架构特性&#xff0c…

Java实体类转JSON时如何避免null值变成“null“?

在Java开发中&#xff0c;实体类与JSON的转换是一个非常常见的需求。今天&#xff0c;我们要聊聊一个特别的重要但又常常被忽视的问题&#xff1a;当我们将Java实体类转换为JSON格式时&#xff0c;如何处理那些null值&#xff0c;避免它们在JSON中出现为字符串“null”呢&#…

五大基础算法——枚举算法

枚举算法 是一种通过遍历所有可能的解来寻找问题答案的算法思想。它通常用于解决那些解空间有限且可以直接列举所有可能情况的问题。以下是枚举算法的核心概念、适用场景、实现方法及经典例题&#xff1a; 一、核心概念 解空间 所有可能的解的集合。 遍历 通过循环或递归逐一检…

C语言高级学习之变量和内存分布

一.变量和内存分布 1.课程要求 2.技术层次 3.C语言标准 1.3.1 K&R C 起初&#xff0c;C语言没有官方标准。1978年由美国电话电报公司(AT&T&#xff09;贝尔实验室正式发表了C语言。布莱恩柯林汉&#xff08;Brian Kernighan&#xff09; 和 丹尼斯里奇&#xff08;D…

【004】deepseek本地化部署后,python的调用方式_#py

python调用本地deepseek 1 本地化部署deepseek2 python调用方式 1 本地化部署deepseek 已经有很多大佬们说了不少部署本地化部署deepseek的工作了&#xff0c;我就不过多重复了。 先安装Ollama软件&#xff0c;再通过Ollama获取deepseek的模型文件&#xff0c;大家根据电脑的配…

蓝桥杯学习-12递归

12递归 1.概述 2.几个递归模板 (1)求阶乘 int f(int n){ if(n 1) return 1; return f(n-1) * n; }(2)斐波拉契序列 int f(int n){ if(n 1 || n 2) return n; return f(n - 1) f(n - 2); }例题一-蓝桥5194 int f(int n){if(n 0) return 1;if(n % 2 0) return f(n / 2)…

Python----数据可视化(Pyecharts三:绘图二:涟漪散点图,K线图,漏斗图,雷达图,词云图,地图,柱状图折线图组合,时间线轮廓图)

1、涟漪特效散点图 from pyecharts.globals import SymbolType from pyecharts.charts import EffectScatter from pyecharts.faker import Faker from pyecharts import options as opts from pyecharts.globals import ThemeType # 绘制图表 es (EffectScatter(init_optsop…

自然语言处理预训练模型的研究综述

&#x1f4d5;参考&#xff1a;&#xff1a;2020-11-02,https://kns.cnki.net/kcms/detail/11.2127.tp.20201030.1952.017.html 主要是这篇文章的自己摘了点笔记。 预训练模型的深度学目标是如何使预训练好的模型处于良好的初始状态&#xff0c;在下游任务中达到更好的性能表现…

ES6(1) 简介与基础概念

1. ES6 简介 ES6&#xff08;ECMAScript 6&#xff09;是 JavaScript 的一个重要版本&#xff0c;它在 ES5 的基础上进行了扩展和优化。ES6 主要应用于现代 Web 开发&#xff0c;提高了 JavaScript 的编程效率和可读性。 2. ES6 与 JavaScript 的关系 JavaScript 是一种基于 E…

HTML深度解读

## 引言 HTML&#xff08;HyperText Markup Language&#xff09;是构建网页的基础语言。自1991年由Tim Berners-Lee发明以来&#xff0c;HTML已经经历了多次版本更新&#xff0c;从HTML 1.0到HTML5&#xff0c;每一次更新都带来了新的特性和功能。本文将深入探讨HTML的核心概…

一次Linux下 .net 调试经历

背景&#xff1a; Xt160Api, 之前在windows下用.net调用&#xff0c;没有任何问题。 但是移植到Linux去后&#xff0c;.net程序 调用 init(config_path) 总是报错 /root/test 找不到 traderApi.ini (/root/test 是程序目录) 然后退出程序 解决过程: 于是考虑是不是参数传错了&…

iOS底层原理系列01-iOS系统架构概览-从硬件到应用层

1. 系统层级结构 iOS系统架构采用分层设计模式&#xff0c;自底向上可分为五个主要层级&#xff0c;每层都有其特定的功能职责和技术组件。这种层级化结构不仅使系统更加模块化&#xff0c;同时也提供了清晰的技术抽象和隔离机制。 1.1 Darwin层&#xff1a;XNU内核、BSD、驱动…