01 像学任何编程语言一样,先从hello world开始

从第二章构造和运行模块开始,因为第一章我已经了解。
先贴第一个简单模块:
  1 #include <linux/init.h>
  2 #include <linux/module.h>                               //所有模块必须包含这两个头文件
  3
  4 MODULE_LICENSE("Dual BSD/GPL");                //许可证,另可以添加MODULE_AUTHOR MODULE_DESCRIPTION 等。具体规范化,可参考各发行的驱动源码。
  5
  6 static int hello_init(void)
  7 {
  8         printk(KERN_ALERT "hello world\n");
  9         return 0;
 10 }
 11 static void hello_exit(void)
 12 {
 13         printk(KERN_ALERT "Goodbye, cruel world\n");
 14 }
 15
 16 module_init(hello_init);
 17 module_exit(hello_exit);
重点关注编译和装载 Makefile
  1 obj-m:=hello.o
  2 #KERNELDIR:=/home/hya/linux-3.2/                                                                                              
  3 KERNELDIR:=/lib/modules/$(shell uname -r)/build/
  4
  5 hello:
  6         make -C $(KERNELDIR) M=`pwd`
  7 clean:
  8         rm -rf *.mod.c *.o *.ko modules.order Module.symvers
  9
模块的安装需要基于特定的内核平台,Makefile要找正确的KERNELDIR路径进行编译,KERNELDIR路径下的内核源码必须正确配置和构造了内核树。
首先我通过第二行指定内核路径,并且在该目录下正确 make menuconfig 、make。
在当前Ubuntu平台上无法insmod,报错如下:(注,insmod 必须是超级用户权限)  版本依赖问题
如果要在Makefile中同时编译多个module:
如果你写成 obj-m:=1.o
                  obj-m:=2.o
                  obj-m:=3.o
这样只会编译3.o,而忽略前面的两个;正确的做法应该是:
   1 obj-m:=01_reg_chrdev.o                                                                                                            
  2 obj-m +=02_reg_cdev.o
  3 obj-m +=03_scull_dev.o
(多看、多做、多想)

理解:
1、模块的初始化和关闭:
初始化:我所理解的初始化时相当于应用程序的main函数;
固定格式:
static int __init init_fun(void)
{
    /*初始化代码*/
}
module_init(inti_fun);
__init:对内核来讲,是一种暗示,表明该函数仅在初始化期间使用,在模块被装载之后,模块装载器就会将初始化函数扔掉,将该函数占用的内存释放出来。
关闭:模块rmmod时调用,注销接口,并向系统返回所有资源。
固定格式:
static void __exit cleanup_fun(void)
{
    /* 清除代码*/
}
module_exit(cleanup_fun);
如果一个模块未定义清除函数,则内核不允许卸载该模块。
2、 错误处理:
在内核注册设施时,要时间铭记注册可能会失败。模块初始化出现错误后,必须自行注销已注册的设施。如果由于某种原因未能撤销已注册的设备,内核会处于一种不稳定的状态。这就用到了goto语句,驱动似乎很喜欢使用goto,进行回退。以后代码看多了,慢慢就理解了。
3、模块参数:
sudo insmod hello_param.ko howmany=2 whom="Mom"  注意必须添加 “变量=”
源码:
  6 static char *whom = "world";
  7 static int howmany = 1;
  8
  9 module_param(howmany, int, S_IRUGO | S_IWUSR);
 10 module_param(whom, charp, S_IRUGO | S_IWUSR);
。。。
 16         printk(KERN_INFO "hello %d %s\n", howmany, whom);
。。。
暂时了解,相信以后实际使用还需仔细琢磨。
4、本章还简单介绍了一线内容:
核心模块和应用程序的对比,比如printk不支持浮点数等;
用户空间和内核空间的区别;
内核中的并发;当前进程task_struct;
内核符号表:EXPORT_SYMBOL(name);
模块装载竞争;
在用户空间编写驱动程序。
这些内容可能涉及到对于操作系统和Linux内核的理解,渐渐深入吧。

猜你喜欢

转载自blog.csdn.net/aysa_bear/article/details/51555645