Linux 设备驱动

news2024/11/27 4:27:01

驱动编译要用到kernel的Makefile文件 — — 也就是源码树的编译系统。因此,源码需要被配置和编译,以ubuntu自带的源码为例:

编译外部模块(.ko)的编译命令是:

make -C M=mak**eCpathtokernelsrc>M=PWD

也就是进入到kernel目录,利用kbuild系统来编译驱动文件。obj-m 告诉编译系统需要编译成一个module(.ko),foo.o表明需要源文件是foo.c或者foo.S,如果驱动模块包含多个文件(如: foo_main.c, foo_common.c),写法如下:

kbuild将编译$(foo-y)列出的所有文件,合并产生 foo.ko

在编译期间,模块的Makefile会被kbuild多次读取,因此建议使用$(KERNELRELEASE)来区分Makefile的使用阶段,优化后的Makefile如下:

第一次运行make的时侯,$(KERNELRELEASE) 为空,因此,Makefile的 ‘else’ 内容首先被读取,然后,执行 *‘make -C …..’*, 执行过程中,会回读Makefile文件,这次, ‘ifneq’ 条件满足,两次走不同的路径,编译系统配置不同的变量参数。

如果,不使用 $(KERNELRELEASE) 区分的话,每次编译系统都会设置所有的变量和规则,可能会与kernel的Makefile变量或者规则冲突,因此,建议在(KERNELRELEASE)为空的情况下,配置driver专用的变量和规则,除了使用(KERNELRELEASE)为空的情况下,配置drive**r专用的变量和规则,除了使用(KERNELRELEASE)外,kernel还提供了一些其它的做法,
更多的kernel 编译系统信息,请参考kernel源码下的 “Documentation/kbuild/”

驱动模块运行相关命令

  • insmod foo.ko —— 加载driver 到kernel去运行。

  • rmmod foo —— 从kernel 移除driver.

  • lsmod —— 查看当前kernel 运行的模块。

字符设备

字符设备驱动实际上就是实现一个文件接口,让设备文件可以像一个普通文件那样来访问,这样应用程序就可以使用libc库的’文件IO API(open/write/read/close 系列函数)‘ 来访问驱动程序,与驱动交换数据,因此,它的核心就是实现文件系统的接口 -- 文件操作。

程序入口

宏内核与微内核的一个最大区别就是驱动程序的运行空间。微内核系统,驱动程序作为一个应用程序,运行在用户空间,它的入口就是应用程序的‘main’函数。 Linux作为一个宏内核系统,它的驱动程序与内核是一体的,运行在内核空间,它的入口是 ‘module_init’,‘module_exit’则是对应的退出函数,它们一定是成对出现的。

foo_init 执行了最基本的字符设备操作:使用 cdev_add 添加一个 ‘cdev’到字符设备列表(其实是一个map结构), 这样就把foo这个字符设备托付给kernel进行管理了,当应用程序操作相应的设备文件时,kernel能调度到foo驱动程序。

foo_exit 一定要使用 cdev_del 从列表里面删除设备,不然,当kernel从列表里面查找到 cdev时,返回的将是“过时”的指针,使用它来 callback相应操作时,就会出现空指针异常,导致kernel会挂掉。切记!foo_init 和 foo_exit 一定要成对使用,执行相反的操作。

bug 实例:

  1. foo_exit 不执行 cdev_del 函数。

  2. insmod foo.ko -- OK。

  3. 应用程序对设备文件读写 -- OK。

  4. rmmod foo -- OK。

  5. insmod foo.ko -- OK。

  6. 应用程序对设备文件读写 -- core dump。

rmmod foo’时,会调用 foo_exit,但是,程序员忘了执行 cdev_del 函数,导致 foo.cdev 的指针没有被删除而变成了一个空指针,它仍然在字符设备列表里面。 当第二次插入foo.ko后, 读写该设备时,Kernel找的是旧的 foo.cdev 空指针,用它调用相应的文件操作时,就发生了空指针的 core dump 错误。

文件操作

setup_dev: 注册当前的设备的文件操作函数,当应用程序操作设备文件时,调用到对应的驱动函数。与用户空间交换数据,copy_from/to_user,这两个函数返回0表示函数执行成功。

  • copy_from_user: 把用户写入的数据copy驱动数据buf保存起来。

  • copy_to_user: copy驱动数据buf到 用户读取数据的buf。

应用程序与字符驱动的交互流程

  1. 创建设备文件 -- sudo mknod /dev/foodev c 500 0

  2. 修改设备文件权限 -- sudo chmod 766 /dev/foodev

  3. 应用程序使用open函数打开设备文件。

  4. kernel根据文件类型(字符设备文件)找到字符设备列表,并根据设备号(Major, Minor),找到对应的设备驱动模块。

  5. 调用设备驱动的open函数 foo_open 。

  6. 应用程序调用 read/write函数来读写设备文件。

  7. 驱动调用 foo_read/write并使用copy_from/to_user来交换数据。

常见问题

Q: 读写设备文件时,write或者 read函数返回0,不能读写数据 ?
A: 这类设备文件读写失败问题,很有可能是权限问题,确认下文件读写权限,其次是数据是否符合驱动的要求。

块设备

块设备指的是存储设备,块设备驱动就是存储驱动如:HD,SSD。Linux 用 Block 子系统对它们进行管理,把应用层的IO读写请求,转变为Request ,传给相应的会设备驱动。驱动流程比较简单:

register_blkdev → alloc_disk → 处理request

Q: 文件系统与Block子系统的关系?
A: Block子系统主要是提供最底层的数据读写,也就是raw io,文件系统使用它进行IO操作。

注册

注册块设备(主设备号)

注册设备(MAJOR,MINOR)

添加磁盘

这个磁盘会出现在 /dev 目录下面, 本例是 /dev/frd0,用户可以对设备文件进行格式化,分区等磁盘相关的操作。如: ‘mkfs.ext2 /dev/frd0’, ‘mount /dev/frd0 /mnt’。

初始化请求队列

处理设备请求

kernel 提供了一些宏来帮助遍历请求列表。对请求的处理策略,就是Block驱动最核心最精华的部分,开发者得根据设备的物理特性来提高访问效率,解决并发拥堵等问题。
*fr_queue_rq()* -- ‘**请求队列’**处理函数,在初始化请求队列时设置,Loop处理每个请求:

*fr_transfer()* -- 物理设备读写数据,根据请求的上下文内容(context),进行底层数据传输,这里就是最底层的IO通讯了,驱动根据物理设备的接口协议来进行数据的读写。

块设备驱动测试

执行上面命令后,frd_data_r 和 frd_data_w的内容应该是一样的。

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

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

相关文章

oracle经典习题(一)

oracle经典习题(一) 1.显示与BLAKE在同一部门工作的雇员的姓名、工作和入职日期&#xff0c;但是BLAKE不包含在内 1.1 示例sql语句 SELECT ename,job,hiredate FROM emp WHERE deptno(SELECT deptno FROM emp WHERE enameBLAKE) AND ename <> BLAKE1.2 运行截图 2.显示…

vpp hash源码分析

概述 vpp的hash结构分为hash头、桶&#xff08;_hash_create或hash_resize申请&#xff09;和桶下元素&#xff08;clib_mem_realloc申请&#xff09;&#xff0c;总共3个部分组成。 根据元素key的hash值不同&#xff0c;分配到不同的桶下&#xff0c;与其他hash表原理相同。 …

Python利用pandas处理Excel数据的应用

最近迷上了高效处理数据的pandas&#xff0c;其实这个是用来做数据分析的&#xff0c;如果你是做大数据分析和测试的&#xff0c;那么这个是非常的有用的&#xff01;&#xff01;但是其实我们平时在做自动化测试的时候&#xff0c;如果涉及到数据的读取和存储&#xff0c;那么…

二叉树5:二叉树层序遍历

学会二叉树的层序遍历&#xff0c;可以一口气打完以下十题&#xff1a; 强烈建议大家和我一样&#xff0c;先看一下第一道题&#xff0c;大家可以去看看卡哥的哔站视频&#xff0c;理解透。然后后面的九道题自己先动手做一下&#xff0c;别急着看答案&#xff0c;真心不难&…

Git流程规范

开发新功能 1、从master拉一个功能分支&#xff0c;取名为某个版本下的某个产品功能 4.3/精确发券 2、当功能开发好了&#xff0c;合并分支到dev进行联调 3、如果是俩个关联性的分支&#xff0c;应该把分支合并到另外一个分支&#xff0c;在合并到dev分支中。如图。feature3…

【学习笔记01】vue的了解和指令

一、什么是 Vue&#xff1f; Vue (发音为 /vjuː/&#xff0c;类似 view) 是一款用于构建用户界面的JavaScript框架。它基于标准 HTML、CSS 和 JavaScript 构建&#xff0c;并提供了一套声明式的、组件化的编程模型&#xff0c;帮助你高效地开发用户界面。 二、Vue的两个核心功…

Day831.局部变量为什么是线程安全的 -Java 并发编程实战

局部变量为什么是线程安全的 Hi&#xff0c;我是阿昌&#xff0c;今天学习记录的是关于局部变量为什么是线程安全的。 一遍一遍重复再重复地讲到&#xff0c;多个线程同时访问共享变量的时候&#xff0c;会导致并发问题。 那在 Java 语言里&#xff0c;是不是所有变量都是共…

【java设计】:全民飞机大战小游戏制作

文章目录 前言 一、全民飞机大战 二、计划安排 三、源码图和类图展示

CTF Android逆向 -- KGB Messenger APK文件结构介绍,破解账户与密码,静态分析,修改并构建APK,逆向算法,APK文件签名

前言 一次练习Android逆向的记录&#xff0c;写得很详细&#xff0c;有什么没有理解的地方可以私信 csdn不让我加外链&#xff0c;所以将链接前面的#号去掉即可 题目&#xff1a; ht#tps://github.com/tlamb96/kgb_messenger在这个挑战中&#xff0c;一共有三个flag&#x…

UE4 Pak打包、挂载、加载

首先&#xff0c;必须得明确的一点就是如果想要加载Pak内资源&#xff0c;那么这些资源必须是经过Cook的。如果打包的是未Cook的资源&#xff0c;那么即使Pak挂载成功&#xff0c;也不可能会成功加载Pak内资源。 不知道怎么生成Cook资源&#xff0c;可以看我前一篇 ​​​​​…

持之以恒,方得始终|海联捷讯的六年数字化历程

企业数字化已经成为了企业家与管理者的共识。如何实现数字化转型&#xff0c;从认知到战略&#xff0c;上至组织文化&#xff0c;下至每个组织成员的行为&#xff0c;都需要做出改变——它本质上是一种创新的企业管理模式和运营机制&#xff0c;重要性不言而喻。而降本增效也是…

学习->C++篇十七:C++的类型转换和IO流

目录 一.类型转换 1.C语言中的类型转换 2.C中的类型转换 二.IO流 1. C语言的输入与输出 2. 流是什么 3. stringstream 一.类型转换 1.C语言中的类型转换 &#xff08;1&#xff09;隐式类型转换&#xff0c;编译阶段自动进行&#xff0c;不能转换就编译报错。&#xff…

TCP/IP四层协议

七层模型层数太多记不住&#xff0c;四层模型 应用层&#xff0c;传输层&#xff0c;网络层&#xff0c;网络接口层的名字必须记得滚瓜烂熟。&#xff08;重点也是tcp/ip四层模型&#xff09; 四层模型&#xff1a; 1.应用层&#xff1a; 两台终端设备上的应用程序 应该遵守…

三面美团 Java 岗,HR 现场直接发 offer,他是横着走出来的

前情提要 这是一个发生在我朋友身上的真实事情&#xff1a; 这里就叫他程序员 Y 吧。 程序员 Y 工作不到两年&#xff0c;周末在朋友圈发了个喜报&#xff0c;准备入职美团。 之后&#xff0c;我就带着祝福跟 Y 聊了许久&#xff0c;聊天的内容就是具体了解一下他面试的过程…

技术分享之IntelliJ plugin

资料 https://zhaojian.blog.csdn.net/article/details/127882946 Plugin Configuration File https://plugins.jetbrains.com/docs/intellij/plugin-configuration-file.html 今天分享的主要内容: 了解插件能够做什么 如何开发一个插件 阅读两个常用的插件源码 intellij的窗…

15.Django大型电商项目之创建模型与sql表反向生成模型

1.用户模块模型类创建 1.1 创建用户的子应用 python .\manage.py startapp userapp在settings中挂载子应用 创建子应用urls.py 在主应用中加入子应用的urls.py 1.2 创建表 如何在直接导入sql文件形成表&#xff0c;这里就直接在navicate中把sql文件拖进去点击开始即可 这里…

大数据技术系列:图解大数据平台开发

导言 在前面的文章《「大数据技术体系」学习实践导览》中&#xff0c;概要式的梳理了大数据平台的业务目标&#xff0c;大数据平台的架构框架&#xff0c;大数据平台中常用的技术及工具&#xff0c;数据治理四方面的内容&#xff0c;算是对自身所了解大数据知识体系的抛砖引玉…

第十四届蓝桥杯集训——JavaC组第十二篇——while循环(循环四要素)

第十四届蓝桥杯集训——JavaC组第十二篇——while循环(循环四要素) 前言 百度解析&#xff1a;以环形、回路或轨道运行;沿曲折的路线运行;特指运行一周而回到原处,再转。或说反复地连续做某事。 那么&#xff0c;在程序中依然是连续重复的按照一定的规则去执行某事。 程序计数器…

如何把视频分屏?教你轻松学会视频分屏

分屏视频该怎么操作&#xff1f;不知道大家有没有看到过这样一个视频&#xff0c;就是一个视频里有两个或者有更多个画面&#xff0c;我们在观看的时候可以同时看好几个画面。其实这就是分屏视频&#xff0c;在一个页面中加入多个画面。这样的视频是不是既好玩又炫酷呢&#xf…

尚硅谷Promise笔记

文章目录一、Promise介绍与基本使用1-1.初体验之promise封装ajax请求1-2.Promise对象状态属性PromiseState的值有三个1-3.Promise对象状态属性PromiseResults二、Promise API2-1.Promise构造函数Promise(excutor){}2-2.Promise.prototype.then 方式&#xff1a;(onResolved,onR…