Linux设备驱动学习笔记

 

这次的主要内容:
1.linux设备驱动程序的作用
2.内核模块和用户空间程序的区别
3.Hello world程序.
4.Makefile文件
5.编译,加载内核模块
6.Other tips
7.好书和网站

1.linux设备驱动程序的作用
简单的说,驱动程序告诉了我们可以提供了那些能力,但是没有告诉我们怎么使用这些能力。按照《linux设备驱动程序》上的说法,前一部分叫做”机制”,后面的叫作”策略”。linux设备驱动程序完成来自上层软件的抽象调用,让上层不用去关心底层到底怎么实现。比如说音频设备驱动,提供了一个接口 playsound().那么上层只要去调用这个接口,就可以发音,而不必关心到底怎么让音频设备发音。

2.内核模块和用户空间的应用程序的区别
内核模块工作在内核态,应用程序工作在用户态。这个概念是操作系统理论的基础,不了解的,罚抄一编《操作系统》… 不同于应用程序是从头到尾处理一个任务,内核模块只是注册下自己,以便服务将来的请求。模块初始化的任务是为了将来调用模块的函数作准备,就好像是说”我在这里, 这是我能做的”。当模块退出时,就好像是在说,”我不在这里了,不要请我作任何事了”。
内核模块和应用程序的区别还有,内核模块在卸载的时候必须小心翼翼的将初始化时生成的资源给还原。虽然感觉很麻烦,但是无独有偶,这也方便了我们测试程序,不用为了修改模块后再调试而必须重启。
在用户空间写程序时,可以调用并非自己写的函数,比如printf,但是在内核中,因为没有库链接到内核中,所以绝大部分不能调用普通的头文件,当然有例外。在内核中大部分的头文件都定义在了include/linux和include/asm中。
还有一点是,如果用户空间的程序出错了,没啥事,但是内核模块出错了,至少会终结当前的进程,极有可能导致系统崩溃。

3.hello world程序
理论暂且放一遍…看代码.一个超级入门的程序,hello world.c。

#include 
#include 
 
static int __init hello_init(void){
	printk(KERN_ALERT "hello world
");
	return 0;
}
 
static void __exit hello_exit(void){
	printk(KERN_ALERT "byebye,hello world
");
}
 
module_init(hello_init);
module_exit(hello_exit);

这个模块很简单,只有四个部分。
我们先看最后两行。module_init和module_exit是两个宏,用来声明模块初始时调用的函数和卸载时调用的函数。参数就是对应的函数名。
然后看初始化函数hello_init。函数声明为static并不是必须的。一般来说,这个设备的函数并不需要被其他的内核模块访问,声明为static就可以了。然后是__init,和__exit一样是个标志,告诉内核这些函数或者结构体只是在初始化或者退出的时候用下,其他的时候不用。hello_init和hello_exit中只用到了一个printk函数,类似printf,不过在输出时,需要先输出消息的级别,比如KERN_ALERT。
到此,一个非常简单的hello world就完成了。下面编译。

4.Makefile文件
在编译之前讲Makefile是必须的,因为如果没有makefile的话每次编译将会非常痛苦。至于Makefile,不讲太多,给一个简单的linux2.6下的模板吧.

ifneq ($(KERNELRELEASE),)
	obj-m := helloworld.o
 
else
	KERNELDIR :=/lib/modules/$(shell uname -r)/build
	PWD := $(shell pwd)
 
default:
	$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
 
install:
	$(shell sudo insmod ./helloworld.ko)
endif

内核模块的makefile和一般C/c++程序的makefile有点不一样,因为使用了kbuild。想了解makefile和kbuild的可以看linux的Documention。

5.编译,加载内核模块
将makefile写好后,就可以在终端下切换到当前目录,然后make就好了。当前前提是你有的include的文件和kernel sources tree.在/usr/src/linux-2.6*下有源代码。在/usr/include/linux下有init.h和module.h。
make成功后,目录下应该生成了一个helloworld.ko,这是2.6的内核模块的后缀。之后是加载到运行的内核中。sudo make install桌这手动输入sudo insmod ./helloworld.ko也可以。还有一种加载内核模块的命令是modprobe,这个比insmod更强大,可以自动搜索依赖。
加载成功后,我们可以用lsmod来查看当前内核中的模块,或者cat /proc/modules,都可以。而如果想看到helloworld模块加载时输出的信息,在ubuntu 下可以去/var/log/kern.log文件中查看,或者使用dmesg命令。dmesg | tail -10. 如果想卸载模块,可以用rmmod命令。sudo rmmod helloworld。

6.other tips
Ubuntu linux的内核模块是放在/lib/modules/2.6*/kernel下的。
查看某条命令的用法可以用man command.
如果想查看某个模块的信息,可以用modinfo modname。

7.好的书籍和网站
想系统的学习的话,还是需要看书的,遇到问题了,可以到论坛上求助,当然现google一下还是很有必要的。
好的书籍:
《linux内核设计与实现》比较基础,个人感觉适合初学者
《linux设备驱动》如果需要作某个驱动的话,可以参考。
《linux内核*》找本介绍linux源代码的书看下,对自己理解设备驱动模型等非常有帮助。
好的论坛:
http://www.linuxforum.net
http://kerneltrap.org/
好的工具也很必要,工欲善其事,必先利其器嘛。
如果在win下的话,用source insight,很强大。linux下的话有source navigator。不过熟悉vim的可以用vim+ctags(我也在学),或者专门作源代码分析的lxr, 。这个lxr是可以架设在本机上的,在ubuntu中文论坛上可以搜到。

书或者网站或者工具,没必要急着全部熟悉,照准一个,先看完,用好,等自己了解了一些后,再去看更需要的书吧。

http://www.boluor.com/note-of-linux-device-driver.html

你可能感兴趣的:(linux,杂文)