Smart210学习记录-------linux内核模块
Linux 驱动工程师需要牢固地掌握 Linux 内核的编译方法以为嵌入式系统构建可运行的
Linux 操作系统映像。在编译 LDD6410 的内核时,需要配置内核,可以使用下面命令中的
一个:
#make config(基于文本的最为传统的配置界面,不推荐使用)
#make menuconfig(基于文本菜单的配置界面)
#make xconfig(要求 QT 被安装)
#make gconfig(要求 GTK+被安装)
在配置Linux 2.6内核所使用的make config、make menuconfig、make xconfig和make gconfig
这 4 种方式中,最值得推荐的是 make menuconfig,它不依赖于 QT 或 GTK+,且非常直观,对
LDD6410 的 Linux 2.6.28 内核运行 make menuconfig
内核配置包含的项目相当多,arch/arm/configs/ldd6410lcd_defconfig 文件包含了 LDD6410 的
默认配置,因此,只需要运行 make ldd6410lcd_defconfig 就可以为 LDD6410 开发板配置内核。
编译内核和模块的方法是:
make zImage
make modules
执行完上述命令后,在源代码的根目录下会得到未压缩的内核映像 vmlinux 和内核符号表文
件 System.map,在 arch/arm/boot/目录会得到压缩的内核映像 zImage,在内核各对应目录得到选中
的内核模块。
Linux 2.6 内核的配置系统由以下 3 个部分组成。
! Makefile:分布在 Linux 内核源代码中的 Makefile,定义 Linux 内核的编译规则。
! 配置文件(Kconfig):给用户提供配置选择的功能。
! 配置工具:包括配置命令解释器(对配置脚本中使用的配置命令进行解释)和配置用户
界面(提供基于字符界面和图形界面)。这些配置工具都是使用脚本语言,如 Tcl/TK、
Perl 等编写。
Kconfig Makfile
在 Linux 内核中增加程序需要完成以下 3 项工作。
! 将编写的源代码拷入 Linux 内核源代码的相应目录。
! 在目录的 Kconfig 文件中增加关于新源代码对应项目的编译配置选项。
! 在目录的 Makefile 文件中增加对新源代码的编译条目。
一个 Linux 内核模块主要由如下几个部分组成。
(1)模块加载函数(一般需要) 。
当通过 insmod 或 modprobe 命令加载内核模块时,模块的加载函数会自动被内核执行,完成
本模块的相关初始化工作。
(2)模块卸载函数(一般需要) 。
当通过 rmmod 命令卸载某模块时,模块的卸载函数会自动被内核执行,完成与模块卸载函数
相反的功能。
(3)模块许可证声明(必须) 。
许可证(LICENSE)声明描述内核模块的许可权限,如果不声明 LICENSE,模块被加载时,
将收到内核被污染 (kernel tainted)的警告。
在Linux 2.6内核中,可接受的LICENSE包括“GPL” 、 “GPL v2” 、 “GPL and additional rights” 、
“Dual BSD/GPL” 、 “Dual MPL/GPL”和“Proprietary” 。
大多数情况下,内核模块应遵循 GPL 兼容许可权。Linux 2.6 内核模块最常见的是以
MODULE_LICENSE( "Dual BSD/GPL" )语句声明模块采用 BSD/GPL 双 LICENSE。
(4)模块参数(可选) 。
模块参数是模块被加载的时候可以被传递给它的值,它本身对应模块内部的全局变量。
(5)模块导出符号(可选) 。
内核模块可以导出符号(symbol,对应于函数或变量),这样其他模块可以使用本模块中的变
量或函数。
(6)模块作者等信息声明(可选) 。
**********************************************************************************************
模块加载函数
Linux 内核模块加载函数一般以_ _init 标识声明,典型的模块加载函数的形式如代码清单
static int __init initialization_function(void)
{
...
}
module_init(initialization_function);
模块加载函数必须以“module_init(函数名)”的形式被指定。它返回整型值,若初始化成功,
应返回 0。而在初始化失败时,应该返回错误编码。在 Linux 内核里,错误编码是一个负值,在
<linux/errno.h>中定义,包含-ENODEV、-ENOMEM 之类的符号值。总是返回相应的错误编码是
种非常好的习惯,因为只有这样,用户程序才可以利用 perror 等方法把它们转换成有意义的错误
信息字符串。
在 Linux 2.6 内核中,可以使用 request_module(const char *fmt, …)函数加载内核模块,驱动开
发人员可以通过调用
request_module(module_name);
或
request_module("char-major-%d-%d", MAJOR(dev), MINOR(dev));
这种灵活的方式加载其他内核模块。
在 Linux 中,所有标识为_ _init 的函数在连接的时候都放在.init.text 这个区段内,此外,所有
的_ _init 函数在区段.initcall.init 中还保存了一份函数指针,在初始化时内核会通过这些函数指针
调用这些_ _init 函数,并在初始化完成后,释放 init 区段(包括.init.text、.initcall.init 等)。
**********************************************************************************************
**********************************************************************************************
模块卸载函数
Linux 内核模块加载函数一般以_ _exit 标识声明,典型的模块卸载函数的形式如代码清单
static void __exit cleanup_function(void)
{
...
}
module_exit(cleanup_function);
模块卸载函数在模块卸载的时候执行,不返回任何值,必须以“module_exit(函数名)”的形
式来指定。
通常来说,模块卸载函数要完成与模块加载函数相反的功能,如下所示。
! 若模块加载函数注册了 XXX,则模块卸载函数应该注销 XXX。
! 若模块加载函数动态申请了内存,则模块卸载函数应释放该内存。
! 若模块加载函数申请了硬件资源(中断、DMA 通道、I/O 端口和 I/O 内存等)的占用,
则模块卸载函数应释放这些硬件资源。
! 若模块加载函数开启了硬件,则卸载函数中一般要关闭之。
和_ _init一样,_ _exit也可以使对应函数在运行完成后自动回收内存。实际上,_ _init和_ _exit
都是宏,其定义分别为:
#define _ _init _ _attribute_ _ ((_ _section_ _ (".init.text")))
和
#ifdef MODULE
#define _ _exit _ _attribute_ _ ((_ _section_ _(".exit.text")))
#else
#define _ _exit _ _attribute_used_ _attribute_ _ ((_ _section_ _(".exit.text")))
#endif
数据也可以被定义为_ _initdata 和_ _exitdata,这两个宏分别为:
#define _ _initdata _ _attribute_ _ ((_ _section_ _ (".init.data")))
和
#define _ _exitdata _ _attribute_ _ ((_ _section_ _(".exit.data")))
**********************************************************************************************
模块参数
我们可以用“module_param(参数名,参数类型,参数读/写权限)”为模块定义一个参数,例如下
列代码定义了 1 个整型参数和 1 个字符指针参数:
static char* pr = "hello world";
static int num = 5;
module_param(pr, charp, S_IRUGO);
module_param(num, int, S_IRUGO);
在装载内核模块时,用户可以向模块传递参数,形式为“insmode(或 modprobe)模块名 参
数名=参数值” ,如果不传递,参数将使用模块内定义的缺省值。
参数类型可以是byte、short、ushort、int、uint、long、ulong、charp(字符指针)、bool或invbool
(布尔的反),在模块被编译时会将 module_param 中声明的类型与变量定义的类型进行比较,判断
是否一致。
模块被加载后,在/sys/module/目录下将出现以此模块名命名的目录。当“参数读/写权限”为 0
时,表示此参数不存在 sysfs 文件系统下对应的文件节点,如果此模块存在“参数读/写权限”不为 0
的命令行参数,在此模块的目录下还将出现parameters目录,包含一系列以参数名命名的文件节点,
这些文件的权限值就是传入module_param()的“参数读/写权限” ,而文件的内容为参数的值。
除此之外,模块也可以拥有参数数组,形式为“module_param_array(数组名,数组类型,数组长,参数
读/写权限)” 。从2.6.0~2.6.10版本,需将数组长变量名赋给“数组长” ,从2.6.10 版本开始,需将数组
长变量的指针赋给“数组长” ,当不需要保存实际输入的数组元素个数时,可以设置“数组长”为NULL。
运行 insmod 或 modprobe 命令时,应使用逗号分隔输入的数组元素。
**********************************************************************************************
导出符号
Linux 2.6的“/proc/kallsyms”文件对应着内核符号表,它记录了符号以及符号所在的内存地址。
模块可以使用如下宏导出符号到内核符号表:
EXPORT_SYMBOL(符号名);
EXPORT_SYMBOL_GPL(符号名);
导出的符号将可以被其他模块使用,使用前声明一下即可
**********************************************************************************************
模块声明与描述
在 Linux 内核模块中,我们可以用 MODULE_AUTHOR、MODULE_DESCRIPTION、
MODULE_VERSION、MODULE_DEVICE_TABLE、MODULE_ALIAS 分别声明模块的作者、描
述、版本、设备表和别名,例如:
MODULE_AUTHOR(author);
MODULE_DESCRIPTION(description);
MODULE_VERSION(version_string);
MODULE_DEVICE_TABLE(table_info);
MODULE_ALIAS(alternate_name);
http://weibo.com/21cnbao
**********************************************************************************************
模块的使用计数
try_module_get ()与 module_put()的引入与使用与Linux 2.6内核下的设备模型密切相关。Linux
2.6 内核为不同类型的设备定义了 struct module *owner 域,用来指向管理此设备的模块。当开始
使用某个设备时,内核使用 try_module_get(dev->owner)去增加管理此设备的 owner 模块的使用计
数;当不再使用此设备时,内核使用 module_put(dev->owner)减少对管理此设备的 owner 模块的
使用计数。这样,当设备在使用时,管理此设备的模块将不能被卸载。只有当设备不再被使用时,
模块才允许被卸载。
在 Linux 2.6 内核下,对于设备驱动工程师而言,很少需要亲自调用 try_module_get()与
module_put(),因为此时开发人员所写的驱动通常为支持某具体设备的owner模块,对此设备owner
模块的计数管理由内核里更底层的代码如总线驱动或是此类设备共用的核心模块来实现,从而简
化了设备驱动开发。
详情请看Linucx设备驱动开发
Smart210学习记录-------linux内核模块的更多相关文章
- Smart210学习记录-----Linux i2c驱动
一:Linux i2c子系统简介: 1.Linux 的 I2C 体系结构分为 3 个组成部分: (1) I2C 核心. I2C 核心提供了 I2C 总线驱动和设备驱动的注册.注销方法,I2C 通信方法 ...
- Smart210学习记录------linux串口驱动
转自:http://blog.chinaunix.net/xmlrpc.php?r=blog/article&uid=27025492&id=327609 一.核心数据结构 串口驱动有 ...
- Smart210学习记录-----linux定时器
1.内核定时器: Linux 内核所提供的用于操作定时器的数据结构和函数如下: (1) timer_list 在 Linux 内核中,timer_list 结构体的一个实例对应一个定时器 1 stru ...
- Smart210学习记录-------linux驱动中断
Linux中断 Linux 的中断处理分为两个半部,顶半部处理紧急的硬件操作,底半部处理不紧急的耗时操作.tasklet 和工作队列都是调度中断底半部的良好机制,tasklet 基于软中断实现.内核定 ...
- Smart210学习记录-------Linux设备驱动结构
cdev结构体 1 struct cdev { 2 struct kobject kobj; /* 内嵌的 kobject 对象 */ 3 struct module *owner; /*所属模块*/ ...
- Smart210学习记录----beep linux字符设备驱动
今天搞定了beep linux字符设备驱动,心里还是很开心的,哈哈...但在完成的过程中却遇到了一个非常棘手的问题,花费了我大量的时间,,,, 还是把问题描述一下吧,好像这个问题很普遍的,网上许多解决 ...
- Smart210学习记录------块设备
转自:http://bbs.chinaunix.net/thread-2017377-1-1.html 本章的目的用尽可能最简单的方法写出一个能用的块设备驱动.所谓的能用,是指我们可以对这个驱动生成的 ...
- Smart210学习记录-----SD/MMC/SDIO驱动
转自:http://jingpin.jikexueyuan.com/article/23369.html http://blog.csdn.net/evilcode/article/details/7 ...
- Smart210学习记录-------内存初始化
买了Smart210的板子,开始学习中,,,,, 今天看了重定位DRAM ,然而内存需要初始化,早上信心满满的我到现在崩溃的我....也不知遭受了什么样的蹂躏 ,,还是记下一点学到的知识吧.. 数据手 ...
随机推荐
- backbonejs中的模型篇(二)
一:模型标识符 每个模型都有一个用作唯一标识符的ID属性,以便在不同模型间进行区分.通过id属性我们可以直接访问模型对象当中用于标识符存放的属性,默认属性名为id,但也可以通过设置idAttribut ...
- redhat enterprixe 5.0 NFS服务配置与管理
一.了解NFS Samba 是主要用于实现Linux和Windows操作系统之间文件共享的协议,而NFS则是实现UNIX和Linux操作系统之间文件共享的协议. NFS可以把网络上远程的文件挂载到本机 ...
- ASP.NET MVC 上传大文件时404
前一段时间会员的上传组件改用FLASH的swfupload来上传,既能很友好的显示上传进度,又能完全满足大文件的上传. 后来服务器升级到windows 2008,改为IIS7后,上传文件一旦超过30M ...
- 使用OpenGL ES绘制3D图形
如果应用定义的顶点不在同一个平面上,并且使用三角形把合适的顶点连接起来,就可以绘制出3D图形了. 使用OpenGL ES绘制3D图形的方法与绘制2D图形的步骤大致相同,只是绘制3D图形需要定义更多的 ...
- Linux 中 10 个有用的命令行补全例子
在 Linux 系统中,当你输入一个命令,再按两次 TAB 键,就会列出所有以你输入字符开头的可用命令.这并不新鲜,可能你已经知道了.这个功能被称作命令行补全bash completion.默认情况下 ...
- [Js]缓冲运动
一.运动框架 1.在开始运动时,关闭已有定时器(否则会不断有新的定时器执行) 2.把运动和停止隔开(if/else) 二.缓冲运动 逐渐变慢,最后停止(距离越远速度越大) 速度=(目标值-当前值)/缩 ...
- 微软WTL模板库完整版安装(VS2010+windows7X64位环境下)分享
一:简介 想必大家对于微软的MFC应该都比较熟悉.但是WTL可能很多人比较陌生吧.下面我就简单的说说这个库. 首先对这个库的做个简单的介绍吧. WTL 是 Windows Template Libra ...
- 滑雪(dp好题)
题目描述:贝西去科罗拉多州去滑雪,不过还她不太会玩,只是个能力为 1 的渣渣.贝西从 0 时刻进入滑雪场,一到 T 时刻就必须离开.滑雪场里有 N 条斜坡,第 i 条斜坡滑行一次需要 Di 分钟,要求 ...
- 走进AngularJs(七) 过滤器(filter) - 吕大豹
时间 2013-12-15 16:22:00 博客园-原创精华区 原文 http://www.cnblogs.com/lvdabao/p/3475426.html 主题 AngularJS 过滤器 ...
- 戴文的Linux内核专题:08内核配置(5)
转自Linux中国 Linux内核拥有许多可以配置的特性,接下来我们还有许多要配置. 下一个可以配置的特性是x86的随机数生成器(x86 architectural random number gen ...