Linux的驱动机制及实现
1 Linux驱动与模块 1.1 Linux的模块 驱动程序为了与外设硬件进行交互,必须调用Linux内核提供的内存管理、文件系统等 多种功能函数。而用户态的程序只能通过系统调用来使用有限的内核功能,因此驱动程序在 linux系统中被安排在内核态运行,也即可以访问所有的内核功能。 但是为了把内核通用功能与这些驱动程序区分开来,Linux 通常要求驱动程序作为一个 模块(module)在内核空间运行,并且由内核进行管理。当然,实际上模块并非只能用来编写 驱动程序,模块可以作为任何一个独立的功能块,操作内核函数并通过特定接口向应用程序 提供服务。 1.2 模块的编写要求 模块的代码中,必须加入以下头文件,才能正确地引用模块机制的若干函数: #include <linux/module.h> #include<linux/init.h> 当然,如果编写的模块是驱动程序,则还需要加入与驱动程序相关的内存管理、设备注 册、中断管理等头文件。 模块与通常的应用程序不同,并没有一个main函数,而是一些相互作用的函数的集合。 当然,这些集合中必须有一个首先调用的初始化函数,以及一个退出函数。 初始化函数:在模块加载时被调用,负责申请并初始化模块运行时必须的数据结构,此 后这些结构有可能在模块存续期间一直存在。 退出函数:在模块卸载时被调用,卸载后模块内任何数据结构都不该继续存在,因此退 出函数必须仔细的把模块运行带来的所有数据结构释放掉,否则将会造成内存泄露。 为了使内核知道模块中初始化函数和退出函数的函数名,必须用以下两个宏来定义: module_init(s3c_ts_init); module_exit(s3c_ts_exit); 上例中s3c_ts_init被定义为模块的初始化函数,s3c_ts_exit被定 ### Linux的驱动机制及其实现 #### 1. Linux驱动与模块 ##### 1.1 Linux的模块 在Linux系统中,驱动程序扮演着连接硬件设备与操作系统的关键角色。为了与外设硬件进行有效的交互,驱动程序需要调用Linux内核提供的各种功能,如内存管理、文件系统操作等。然而,用户态程序只能通过系统调用来访问内核的一小部分功能,因此驱动程序在Linux系统中被安排在内核态运行,这意味着它们可以直接访问所有内核提供的功能。 尽管如此,为了区分内核的通用功能和特定于设备的驱动程序,Linux采用了一种模块化的架构。具体来说,驱动程序通常作为一个**模块(module)**在内核空间中运行,并由内核进行管理和调度。模块不仅限于驱动程序,还可以是任何独立的功能块,它们可以通过特定的接口操作内核函数并向应用程序提供服务。 ##### 1.2 模块的编写要求 为了编写一个Linux模块,开发人员需要遵循一定的规则和要求。模块的代码中必须包含以下头文件,以便能够正确引用模块机制所需的函数: ```c #include <linux/module.h> #include <linux/init.h> ``` 如果编写的模块是驱动程序,则还应该包含与驱动程序相关的其他头文件,如内存管理、设备注册、中断管理等。 与传统的应用程序不同,Linux模块没有`main`函数。相反,它们是由一组相互作用的函数组成,其中必须包括一个初始化函数和一个退出函数。初始化函数在模块加载时被调用,负责申请并初始化模块运行时必需的数据结构。这些数据结构可能会在整个模块生命周期中持续存在。退出函数则在模块卸载时被调用,它负责释放模块运行期间创建的所有资源,避免内存泄漏等问题的发生。 为了告知内核初始化函数和退出函数的名称,开发人员需要使用如下两个宏: ```c module_init(s3c_ts_init); module_exit(s3c_ts_exit); ``` 这里的`s3c_ts_init`和`s3c_ts_exit`分别是初始化函数和退出函数的名称。 ##### 1.3 模块的编译 Linux模块可以根据需求以不同的方式进行编译。模块可以被包含在内核中,也可以作为外部模块存在于内核之外。 - **包含在内核中的模块**:当Linux启动时,这些模块会被自动初始化(即调用其初始化函数)。这种方式的优点是可以减少系统启动时间,但会增加内核的大小。 - **外部模块**:这些模块可以在内核启动之后通过外部命令(如`insmod`)动态加载到内核中。这种方式更为灵活,允许按需加载模块,但也意味着增加了系统的初始化时间。 对于外部模块的编译,通常会使用一个简单的Makefile文件,如下所示: ```makefile obj-m := module.o module-objs := file1.o file2.o make -C ~/kernel-2.6 M='pwd' modules ``` 这段Makefile指示了如何编译名为`module.o`的模块,该模块由`file1.c`和`file2.c`两个源文件编译而来。`make -C ~/kernel-2.6 M='pwd' modules`这一命令指定了内核源代码的位置。 在嵌入式平台上,通常会将驱动模块作为内核内部模块编译,以生成单一的镜像文件。这通常通过`make menuconfig`等工具完成,配置工具会根据选项生成一系列`CONFIG_`变量,用于指定模块的编译类型(内部模块或外部模块)。 #### 1.4 内部驱动模块的加载 对于编译到Linux内核内部的驱动模块,在Linux启动过程中会自动加载这些模块。本节将详细介绍Linux何时以及如何加载这些内部驱动模块。 ##### 1.4.1 `module_init`的定义 要了解模块何时被加载,就需要理解`module_init`的定义。在`/include/linux/init.h`文件中,有如下的声明: ```c #define __define_initcall(level,fn,id) \ static initcall_t __initcall_##fn##id __used \ __attribute__((__section__(.initcall##level##"_"##id))) ``` 这段宏定义了如何声明初始化函数。`initcall_t`是一个函数指针类型,指向一个无参数且返回void类型的函数。`__section__`宏用于控制函数在目标文件中的位置,确保它们能够在内核启动时按照正确的顺序被调用。 通过上述介绍,我们可以了解到Linux模块的基本概念、编写要求以及编译和加载的过程。这些知识对于理解Linux操作系统的工作原理以及开发高效的驱动程序至关重要。
剩余53页未读,继续阅读
- voidnull2012-12-30大爱非扫描版的东西,清晰
- fengwei19892013-06-03大爱非扫描版的东西,清晰.
- dzqjys2013-05-16很不错,很清晰
- 粉丝: 0
- 资源: 1
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
最新资源
- “农贸互联”:农产品线上销售系统的开发与应用
- 基于web的音乐网站源码(java毕业设计完整源码+LW).zip
- 基于扰动观测器的伺服系统摩擦补偿Matlab仿真 1.模型简介 模型为基于扰动观测器的摩擦补偿仿真,仿真基于永磁同步电机速度、电流双闭环控制结构开发,双环均采用PI控制,PI参数已经调好 仿真
- 基于保信息学科平台系统设计与实现源码(java毕业设计完整源码+LW).zip
- openjdk8u432-ga
- 采用遗传算法来完成自动组卷功能的前后端分离的在线测试练习系统 基于若依框架进行二次开发 功能:用户管理,练习关系,测试管理,题库管理,数据统计,权限控制 自动组卷:使用遗传算法来完成该
- 年终总结,包含今年的参与的项目,工作内容,遇到的问题,建议,来年计划等
- 通用verilog串口控制器: 1.无奇偶校验,通过高低温等实验稳定运行,可靠性强,方便移植 2.提供整体工程,仿真,提供
- 基于深度学习的股票价格预测和量化策略研究python源码+文档说明+报告PPT(高分项目)
- “宠物服务智能化”:宠物服务平台的开发指南
- 基于深度学习的股票价格预测和量化策略研究python源码+文档说明+报告PPT
- 小谢稳定v4-1.zip
- 79e09efba17ad6cb50253b529448c863.jpg
- 证件照处理的Python脚本
- 一个简单的图像加密和解密脚本
- 基于稀疏梯度场的非局部图像去噪算法及其在图像增强中的应用