linux设备驱动--HelloWorld
最近正在学习设备驱动开发,因此打算写一个系列博客,即是对自己学习的一个总结,也是对自己的一个督促,有不对,不足,需要改正的地方还望大家指出,而且希望结识志同道合的朋友一起学习技术,共同进步。
作者:liufei_learning(转载请注明出处)
email:flying0216@foxmail.com
IT学习交流群:160855096
开发环境:Win7(主机) + VisualBox + ubuntu10.10(虚拟机) + TQ2440开发板(2.6.30.4内核)
功能:
1.ubuntu下helloworld模块的实现
2.TQ2440下helloworld模块的实现
目录: 1.源码
2.实现步骤
Ubuntu下helloworld模块的实现
遇到的问题及解决方案
TQ2440下helloworld模块的实现
遇到的问题及解决方案
3.分析
1)__init__exit
2)module_init() 与 module_exit()
3)MODULE_LICENSE
4)Makefile解析
5)printk()解析
源码:
Makefile
实现步骤:
ubuntu下helloworld模块的实现
1.建立hello.c Makefile文件
Makefile文件注意红色部分,2.6.35-22-generic改为本机的
ifneq($(KERNELRELEASE),)
obj-m :=hello.o
else
KDIR:= /lib/modules/2.6.35-22-generic/build
2.进入所在目录执行
make命令
3.加载模块insmod hello.ko
4.查看以安装模块 lsmod
实验结果:
5.卸载模块rmmod
遇到的问题:
printk无法打印,这是因为printk无法再图形界面下显示在ubuntu里使用printk函数打印的信息被写到/var/log/syslog里,
使用dmesg-c 也可查看
实验结果:
TQ2440下helloworld模块的实现
1.在内核源码 drivers/char/下建立一个
fly_hello.c文件(内容同上)
2.修改同目录下Kconfig
在menu "Character devices"后添加
config FLY_HELLO
tristate"TQ2440 Hello Driver"
dependson ARCH_S3C2440
---help---
TQ2440 Hello Driver
3.修改同目录下Makefile文件
obj-y+= mem.o random.o tty_io.o n_tty.o tty_ioctl.o tty_ldisc.o tty_buffer.otty_port.o后添加
obj-$(CONFIG_FLY_HELLO)+=fly_hello.o
4.配置内核make menuconfig
DeviceDrivers--->
Character device---->
<M>TQ2440 Hello Driver
5.makeSUBDIR=drivers/char/ modules
6.复制drivers/char/下的fly_hello.ko开发板/lib/modules/2.6.30.4-EmbedSky下
7.insmod rmmod
结果截图:
遇到的问题:
卸载的时候出现rmmod: chdir(/lib/modules): No such file or directory错误
现在的内核模块在插入卸载时都会要转到/lib/modules/内核版本号/这个目录里。所以只要建立这个目录并且把要使用的模块.ko文件复制到这个目录就行了。
分析:
一.__init __exit
这些宏被用来标记一些函数或者初始化数据(不适用于未初始化数据)作为初始化函数。此功能仅仅被用在初始化阶段,内核以此作为线索在使用后释放内存资源
用法:
static void __initinitme(int x, int y)
{
extern int z; z = x * y;
}
extern intinitialize_foobar_device(int, int, int) __init;
static intinit_variable __initdata = 0;
static const char
宏__init的使用会在初始化完成后丢弃该函数并收回所占内存,如果该模块被编译进内核,而不是动态加载。
宏__initdata同__init类似,只不过对变量有效。
宏__exit将忽略“清理收尾”的函数如果该模块被编译进内核。同宏__init一样,对动态加载模块是无效的。这很容易理解。编译进内核的模块是没有清理收尾工作的,而动态加载的却需要自己完成这些工作。
这些宏在头文件linux/init.h定义,用来释放内核占用的内存。 当你在启动时看到这样的Freeingunused kernel memory: 236k freed内核输出,上面的 那些正是内核所释放的。
二.module_init()与module_exit()
module_init():驱动的入口点,在内核启动或动态加载模块时被调用
module_exit():驱动的结束点,动态卸载模块时被调用,如果被静态链接在内核,则module_exit()没有效果
三.MODULE_LICENSE
宏MODULE_DESCRIPTION()用来描述模块的用途。
宏MODULE_AUTHOR()用来声明模块的作者。
宏MODULE_SUPPORTED_DEVICE()声明模块支持的设备….
四.Makefile解析
KERNELRELEASE是在内核源码的顶层Makefile中定义的一个变量,在第一次读取执行此Makefile时,KERNELRELEASE没有被定义,所以make将读取执行else之后的内容,如果make的目标是clean,直接执行clean操作,然后结束。当make的目标为all时,-C
$(KDIR)指明跳转到内核源码目录下读取那里的Makefile;M=$(PWD)表明然后返回到当前目录继续读入、执行当前的Makefile。当从内核源码目录返回时,KERNELRELEASE已被定义,kbuild也被启动去解析kbuild语法的语句,make将继续读取else之前的内容。else之前的内容为kbuild语法的语句,指明模块源码中各文件的依赖关系,以及要生成的目标模块名。
五.printk()
内核通过printk() 输出的信息具有日志级别,日志级别是通过在 printk() 输出的字符串前加一个带尖括号的整数来控制的,如printk("<6>Hello, world!/n");。内核中共提供了八种不同的日志级别,在
linux/kernel.h中有相应的宏对应。
#defineKERN_EMERG "<0>" /* systemis unusable */
#defineKERN_ALERT "<1>" /* actionmust be taken immediately */
#defineKERN_CRIT "<2>" /*critical conditions */
#defineKERN_ERR "<3>"/* error conditions */
#defineKERN_WARNING "<4>" /* warningconditions */
#defineKERN_NOTICE "<5>" /* normal butsignificant */
#defineKERN_INFO "<6>" /*informational */
#defineKERN_DEBUG "<7>" /*debug-level messages */
所以 printk()可以这样用:printk(KERN_INFO "Hello, world!/n");。
未指定日志级别的 printk()采用的默认级别是 DEFAULT_MESSAGE_LOGLEVEL,这个宏在 kernel/printk.c 中被定义为整数4,即对应KERN_WARNING。
在/proc/sys/kernel/printk 会显示4个数值(可由 echo修改),分别表示当前控制台日志级别、未明确指定日志级别的默认消息日志级别、最小(最高)允许设置的控制台日志级别、引导时默认的日志级别。当 printk()中的消息日志级别小于当前控制台日志级别时,printk 的信息(要有/n符)就会在控制台上显示。但无论当前控制台日志级别是何值,通过
/proc/kmsg(或使用dmesg)总能查看。另外如果配置好并运行了 syslogd 或 klogd,没有在控制台上显示的 printk 的信息也会追加到 /var/log/syslog 中。
分享到:
相关推荐
”模块示例,帮助初学者入门Linux驱动程序开发。 首先,我们需要理解Linux设备驱动程序的分类。在Linux中,设备可以分为字符设备、块设备和网络设备等。字符设备通常用于传输顺序数据,如串口;块设备则支持随机...
"Linux驱动开发之旅(一)--helloworld"是一个针对初学者的教程,旨在帮助新手理解驱动开发的基本步骤和关键点。在这个教程中,我们将创建一个简单的字符设备驱动,它的主要功能就是向用户空间输出"Hello, World!...
在Linux驱动程序中,"Hello World"通常是一个非常简单的字符设备驱动,它会在设备节点上输出一条欢迎信息。这个驱动的核心部分通常包括以下内容: 1. **驱动注册**:在内核中注册设备驱动,定义设备号(major和...
本篇文章将通过一个简单的"Linux设备驱动Hello World"示例,来帮助初学者理解驱动程序的基本结构和编写方式。 首先,我们要知道驱动程序的主要任务是为硬件提供一个抽象层,它处理硬件特定的操作,同时提供标准的...
此外,还讨论了Linux驱动的安全问题,如防止驱动程序漏洞被利用造成系统安全风险。版本编号和版权条款也是驱动开发中不可忽视的部分,它们涉及到代码的管理和合规性。最后,作者鼓励读者加入内核开发社团,以获得更...
·Linux设备驱动程序学习(0)-Hello, world!模块 ·Linux设备驱动程序学习(2)-调试技术 ·Linux设备驱动程序学习(3)-并发和竞态 ·Linux设备驱动程序学习(4)-高级字符驱动程序操作[(1)ioctl and llseek...
申嵌入门篇2 编写第一个嵌入式Linux应用程序-HelloWorld.lxe
本文档是最基本的Linux设备驱动程序hello world的技术文档,hello world很简单,但如果没有高手指导,或者你的开发板提供的资料做得不够好,那是足够让你花上一个星期也不一定能够搞出来的。本文档是针对Linux设备...
Linux设备驱动程序的一个示例是HelloWorld模块。这个模块展示了内核驱动模块的基本结构,包括模块的初始化函数和退出函数。模块代码通常包含两个重要的头文件:linux/init.h和linux/module.h,这两个头文件分别提供...
Linux驱动开发之编写第一个内核模块--Hello World源码, 亲测OK,对应文章链接: https://dingdong.blog.csdn.net/article/details/106329048
通过"modules_helloworld"项目,开发者可以学习到如何从零开始编写Linux驱动模块,理解内核与设备之间的交互机制,为更复杂的驱动开发打下基础。参考提供的教程链接,可以获取更具体的步骤和示例代码,进一步加深对...
嵌入式 linux 底层helloworld 驱动程序
Linux 字符设备驱动程序...Linux 字符设备驱动程序学习笔记中还介绍了驱动程序的分类、字符设备驱动程序的设计、驱动程序的安装方式、设备文件的概念等知识点,为读者提供了系统的 Linux 字符设备驱动程序学习资源。
Ubuntu下驱动开发HelloWorld