学了那么多程序语言,总是有一个Hello world开头,不禁感叹Hello world的强大。呵呵,废话少说,咋们的故事当然要从这个Hello world开始。

先查看自己OS使用的内核版本
[dongliang@dongliang:~]$ uname -r
2.6.22-14-generic /* 这是我显示的结果 */

如果安装系统时,自动安装了源码。在 /usr/src 目录下有对应的使用的版本目录。例如下(我是自己下的)
[root@localhost :/usr/src]# ls
linux-headers-2.6.22-14
linux-headers-2.6.22-14-generic
linux-source-2.6.22 /*这个就是解压后的源码目录 */
linux-source-2.6.22.tar.bz2 /* 这是我下的源码 包 */

如果没有源码。(一般ubuntu 都没有吧)
查看一下可一下载的源码包(切记不要使用超级用户使用此命令否则……会提示没有此命令)
root@localhost :/usr/src# apt-cache search linux-source
linux-source - Linux kernel source with Ubuntu patches
xen-source-2.6.16 - Linux kernel source for version 2.6.17 with Ubuntu patches
linux-source-2.6.22 - Linux kernel source for version 2.6.22 with Ubuntu patches
root@localhost :/usr/src#

我选择了 linux-source-2.6.22 - Linux kernel source for version 2.6.22 with Ubuntu patches 这个~
然后 install 之

root@localhost # sudo apt-get install linux-source-2.6.22

下载完成后,在/usr/src下,文件名为:linux-source-2.6.22.tar.bz2,是一个压缩包,解压缩既可以得到整个内核的源代码:

注意 已经切换到超级用户模式

root@localhost:/usr/src# tar -jxvf linux-source-2.6.20.tar.bz2

解压后生成一个新的目录/usr/src/linux-source-2.6.22,所有的源代码都在该目录下。

进入该目录

开始配置内核 选择最快的原版的配置(默认)方式 (我是如此)

root@localhost:/usr/src/linux-source-2.6.22# make menuconfig

当然你也可以使用 自己喜欢的配置方式 如 menuconfig , xconfig(必须有GTK环境吧)。反正不用剪裁什么,所以不管那种方式能配置它就行了。

完成后,开始make 吧 这儿比较久 一般有1一个小时吧。(保证空间足够 我编译完成后 使用了1.8G) 我分区时分给/目录30G的空间,我没遇到这问题。倒是我朋友遇到了。

root@localhost:/usr/src/linux-source-2.6.22$ make

root@localhost:/usr/src/linux-source-2.6.22$ make bzImage

当然,第一个make也可以不执行,直接make bzImage。执行结束后,可以看到在当前目录下生成了一个新的文件: vmlinux, 其属性为-rwxr-xr-x。

然后 :

root@localhost:/usr/src/linux-source-2.6.22# make modules /* 编译 模块 */

root@localhost:/usr/src/linux-source-2.6.22# make modules_install /* 安装 模块 */

执行结束之后,会在/lib/modules下生成新的目录/lib/modules/2.6.22-14-generic/
。 在随后的编译模块文件时,要用到这个路径下的build目录。至此,内核编译完成。可以重启一下系统。

至此 内核树就建立啦 原来不是很难.....

(1)linux开源当然少不了源代码的贡献,请看下边(至于什么是开源,悲剧的我现在也没整明白):

#include <linux/init.h>  //所有模块代码中都包含一下两个头文件
#include <linux/module.h>
MODULE_LICENSE("Dual BSD/GPL"); //所有模块代码都应该指定所使用的许可证 static int hello_init(void)
{
printk(KERN_ALERT "Hello,world\n");
return 0;
} static void hello_exit(void)
{
printk(KERN_ALERT "Goodbye,Cruel world\n"); } module_init(hello_init);
module_exit(hello_exit);

看到这里我们明白了,驱动程序说白了就是提供函数接口给用户空间的程序调用。在c语言中都有main()入口,那设备驱动程序的入口在哪儿呢?你猜对了,就是module_init(),它的参数是一个函数指针,告诉说咋们的入口在hello_init()。明白这层意思,module_exit()就不用多说了吧..

(2)连源码都给你了,也就不吝啬一个makefile了如下:

ifneq ($(KERNELRELEASE),)
obj-m := hello.o #设置模块名字
else
KERNELDIR :=/lib/modules/$(shell uname -r)/build #将目录改为内核所在目录
PWD := $(shell pwd)
all:
$(MAKE) -C $(KERNELDIR) SUBDIRS=$(PWD) modules
endif
clean:
rm -f *.o *.ko *.mod.c .hello*

千万不要说不懂makefile,大千世界,连地图都不懂,也不知道咋混的。这里要说的是 $(MAKE) 这里一定是大写MAKE,我开始小写,怎么都过不去,郁闷啊..

$(MAKE) -C $(KERNELDIR) SUBDIRS = $(PWD) modules这句啥意思?就是说首先改变目录到-C选项指定的目录(即内核源代码目录),其中保存了内核的顶层makefile文件。SUBDIRS=选项让该makefile在构造modules目标返回之前到模块源代码目录。然后,modules目标指向obj-m变量设定的模块。(其实,这样的写Makefile命令还是有些烦人,可有啥办法呢,谁让咱们是笨鸟,聪明的方法?有,那要见下篇介绍-----聪明的makefile,嘿嘿)。

(3)好了,该有的都有了,不该有的咋一点也不贪。下面make一番:

[root@localhost~]# make
make -C /lib/modules/2.6.29.4-167.fc11.i686.PAE/build SUBDIRS=/root/device modules
make[1]: Entering directory `/usr/src/kernels/2.6.29.4-167.fc11.i686.PAE'
  Building modules, stage 2.
  MODPOST 1 modules
  CC      /root/device/hello.mod.o
  LD [M]  /root/device/hello.ko
make[1]: Leaving directory `/usr/src/kernels/2.6.29.4-167.fc11.i686.PAE'

这是生成了hello.ko模块(如果没有,是有八九就是makefile有问题,还说会写,露了原形吧),接下来可以看结果了

首先再打开一个终端B(刚才make的那个不要关了,叫它A吧),像这样
[root@localhost~]# tail -f /var/log/messages 

然后在A终端输入
[root@localhost~]# insmod ./hello.ko  哈哈在B终端是不是看到了localhost kernel:hello,world

然后在A终端输入
[root@localhost ~]# rmmod hello 哈哈在B终端是不是看到了localhost kernel:Goodbye,Cruel world

查看加载模块
[root@localhost ~]# lsmod
Module Size Used by
hello 2560 0
已经加载上咯~~

那程序的输出在那呢?书中说明 如果不出现在终端 则会写进 syslog 文件中
dongliang@dongliang:~/linux_驱动开发$ cat /var/log/syslog | grep world
Mar 16 12:14:53 shana kernel: [ 5937.529297] Hello, world
Mar 16 12:16:05 shana kernel: [ 6009.439036] Goodbye, cruel world

至此,一个最简单的helloworld的设备驱动演示程序就完成了,是不是挺好玩,关键是挺兴奋,这才是关键。哈哈

当工人就得劳动;当军人就的准备打仗(不然某些人老是欺负咋们了不是),所以嘛,当程序员,就一定要在最后来个说明注意什么的,烦躁啊..

那就说明吧:
(1) 这个helloworld,我建议在fedora 下实现,在centos或redhat或那些我没试过的,是有些问题的。    这主要是要在某些系统下是不支持模块的,这就要重新编译内核,选上“Enable loadable module        support”,这样才可以。你偏要忘北走,我也不能用个绳子套着你喝水是吧,不管了,反正我今天关心的helloworld完成了,这难道就是传说中的责任分工,那个?呵呵,等着,我改天一定不上。
(2) 在编写makefile时,所有的换行后的空格都是tab键,而不是space(空格键)。
(3) 本例程的文件保存为 hello.c  ,不然编译不通过。

学习心得:
(1)驱动模块运行在内核空间,运行时不能依赖于任何函数库和模块连接,所以在写驱动时所调用的函数只能是作为内核一部分的函数。
(2)驱动模块和应用程序的一个重要不同是:应用程序退出时可不管资源释放或者其他的清除工作,但模块的退出函数必须仔细撤销初始化函数所作的一切,否则,在系统重新引导之前某些东西就会残留在系统中。
(3)处理器的多种工作模式(级别)其实就是为了操作系统的用户空间和内核空间设计的。在Unix类的操作系统中只用到了两个级别:最高和最低级别。
(4)要十分注意驱动程序的并发处理。
(5)内核API中具有双下划线(_ _)的函数,通常是接口的底层组件,应慎用。
(6)内核代码不能实现浮点书运算。

一步一步实现Linux设备驱动的Helloworld模块的更多相关文章

  1. linux设备驱动归纳总结(十二):简单的数码相框【转】

    本文转载自:http://blog.chinaunix.net/uid-25014876-id-116926.html linux设备驱动归纳总结(十二):简单的数码相框 xxxxxxxxxxxxxx ...

  2. linux设备驱动归纳总结(十一):写个简单的看门狗驱动【转】

    本文转载自:http://blog.chinaunix.net/uid-25014876-id-112879.html linux设备驱动归纳总结(十一):写个简单的看门狗驱动 xxxxxxxxxxx ...

  3. linux设备驱动归纳总结(十):1.udev&misc【转】

    本文转载自:http://blog.chinaunix.net/uid-25014876-id-111839.html linux设备驱动归纳总结(十):1.udev&misc xxxxxxx ...

  4. linux设备驱动归纳总结(六):3.中断的上半部和下半部——tasklet【转】

    本文转载自:http://blog.chinaunix.net/uid-25014876-id-100005.html linux设备驱动归纳总结(六):3.中断的上半部和下半部——tasklet x ...

  5. linux设备驱动归纳总结(六):2.分享中断号【转】

    本文转载自:http://blog.chinaunix.net/uid-25014876-id-90837.html xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ...

  6. linux设备驱动归纳总结(六):1.中断的实现【转】

    本文转载自:http://blog.chinaunix.net/uid-25014876-id-90740.html linux设备驱动归纳总结(六):1.中断的实现 xxxxxxxxxxxxxxxx ...

  7. linux设备驱动归纳总结(五):4.写个简单的LED驱动【转】

    本文转载自:http://blog.chinaunix.net/uid-25014876-id-84693.html linux设备驱动归纳总结(五):4.写个简单的LED驱动 xxxxxxxxxxx ...

  8. linux设备驱动归纳总结(五):3.操作硬件——IO静态映射【转】

    本文转载自:http://blog.chinaunix.net/uid-25014876-id-83299.html linux设备驱动归纳总结(五):3.操作硬件——IO静态映射 xxxxxxxxx ...

  9. linux设备驱动归纳总结(四):5.多处理器下的竞态和并发【转】

    本文转载自:http://blog.chinaunix.net/uid-25014876-id-67673.html linux设备驱动归纳总结(四):5.多处理器下的竞态和并发 xxxxxxxxxx ...

随机推荐

  1. 【LeetCode】11. Container With Most Water

    题目: Given n non-negative integers a1, a2, ..., an, where each represents a point at coordinate (i, a ...

  2. js日期的写法,获取girdviw的行数、提示信息、验证数量信息

    //制订日期(js日期的写法) var myDate = new Date(); var theDate = myDate.toLocaleDateString();  //获取今天的日期 //获取控 ...

  3. 进制格式转换 c#

    Console.WriteLine());//即17是十六进制位 得到的结果是23 得到十进制数 将字符串转换成二进制 public static string mdFiveGet(string md ...

  4. 通过fileupload上传文件超出大小

    配置文件 . web.config中添加如下内容: <configuration> <system.web> <httpRuntime maxRequestLength= ...

  5. eclipse+maven+jetty环境下修改了文件需要重启才能修改成功

    遇到这种情况,需要在类库文件夹中修改配置文件(C:\.m2\repository\org\mortbay\jetty\jetty\6.1.22) 在以上路径下添加如下路径的压缩文件中的两个文件即可 路 ...

  6. sass sublime text 2 gulp ionic

    sass 安装1.全局安装 sass 我的Mac 所以不用再安装Ruby ,直接在终端输入 gem install sass 然后在终端中输入 sass -v 出现 Sass 3.4.8 (selec ...

  7. CSS 三角形绘制方法

    #triangle-up {    width: 0;    height: 0;    border-left: 50px solid transparent;    border-right: 5 ...

  8. nc命令学习

    监测端口是否存在 nc -z 127.0.0.1 9100 扫描端口 nc -z -v 127.0.0.1 8000 9999 发送http nc www.baidu.com 80 GET / HTT ...

  9. com.google.inject.CreationException: Guice creation errors

    错误的原因:xml文件中方法名重复或错误

  10. Java学生管理系统项目案例

    这是一个不错的Java学生管理系统项目案例,希望能够帮到大家的学习吧. 分代码如下 package com.student.util; import java.sql.Connection; impo ...