驱动学习1:第一个驱动入门

Linux驱动程序,首先应该知道它是linux的内核模块。

Linux内核模块是使得复杂而庞大的linux内核条理清晰、可裁剪、高兼容性的重要特性。

Linux内核模块的特点:

1,  模块本身不被编译进内核镜像,能够控制内核的大小。

2,  模块可以在需要的时候中被动态加载,一旦加载完成就和内核其它部分完全一样。

下面便是linux内核模块的helloworld程序,结构十分固定。

(1) 模块加载函数

当通过insmod或者modprobe命令加载内核模块时,模块的加载函数会自动执行,完成本模块的相关初始化工作

(2) 模块卸载函数

当通过rmmod命令卸载内核模块时,模块的卸载函数会自动执行,完成本模块的卸载功能

(3) 模块许可证声明

如果不声明LICENSE,模块被加载时,将收到内核被污染(Kernel Tainted)的警告。

(4) 模块参数(可选)

模块参数是模块被加载的时候可以传递给它的值,它本身对应模块内部的全部变量

(5) 模块导出符号(可选)

内核模块可以导出的符号(symbol,对应函数或变量),若导出,则其他模块可以使用本模块中的变量或函数

(6) 模块作者等信息声明(可选)

这个驱动并不具有任何控制硬件的行为,只是为了展示linux驱动的通用结构。这几乎是所有驱动程序的通用模版,如led的驱动程序,只需要在hello_ioctl函数中根据不同的传入参数操作gpio寄存器即可。(应用层没有操作硬件的权限,而内核中具有所有权限。驱动程序的作用就是高效的、封装的、有限的向应用层提供服务)

代码:

 1 /*  
 2 hello.c - The simplest kernel module.
 3 */
 4 #include <linux/kernel.h>
 5 #include <linux/init.h>
 6 #include <linux/module.h>
 7 #include <linux/slab.h>
 8 #include <linux/io.h>
 9 #include <linux/interrupt.h>
10 
11 #include <linux/of_address.h>
12 #include <linux/of_device.h>
13 #include <linux/of_platform.h>
14 
15 /* Standard module information */
16 MODULE_LICENSE("GPL");
17 MODULE_AUTHOR("pp.");
18 MODULE_DESCRIPTION("hello module template ");
19 
20 #define DRIVER_NAME "hello"
21 
22 unsigned myint = 0xdeadbeef;
23 char *mystr = "default";
24 
25 module_param(myint, int, S_IRUGO);
26 module_param(mystr, charp, S_IRUGO);
27 
28 static int __init hello_init(void)
29 {
30     printk(KERN_INFO "Hello module world.\n");
31     printk(KERN_INFO "Module parameters were (0x%08x) and \"%s\"\n", myint,mystr);
32 
33     return 0;
34 }
35 
36 
37 static void __exit hello_exit(void)
38 {
39     printk(KERN_ALERT "Goodbye module world.\n");
40 }
41 
42 module_init(hello_init);
43 module_exit(hello_exit);

编译后生成.ko文件,移植到开发板linux下测试

默认情况下

root@plnx_arm:/mnt# insmod hello.ko 
Hello module world.
Module parameters were (0xdeadbeef) and "default"
root@plnx_arm:/mnt# lsmod          
    Tainted: G  
hello 817 0 - Live 0xbf004000 (O)
root@plnx_arm:/mnt# rmmod hello    
Goodbye module world.

传入参数时:

root@plnx_arm:/mnt# insmod hello.ko myint=123  mystr="pp"
Hello module world.
Module parameters were (0x0000007b) and "pp"
root@plnx_arm:/mnt# rmmod hello
Goodbye module world.

通过其他的查询命令可以看到内核的输出:

root@plnx_arm:/mnt# ls /sys/module/hello/parameters/
myint  mystr
root@plnx_arm:/mnt# tail -n 2 /var/log/messages 
Jun  4 09:56:33 plnx_arm user.info kernel: Hello module world.
Jun  4 09:56:33 plnx_arm user.info kernel: Module parameters were (0x0000007b) and "pp"

在Linux下可以通过两种方式加载驱动程序:静态加载和动态加载。

静态加载就是把驱动程序直接编译进内核,系统启动后可以直接调用。静态加载的缺点是调试起来比较麻烦,每次修改一个地方都要重新编译和下载内核,效率较低。若采用静态加载的驱动较多,会导致内核容量很大,浪费存储空间。

动态加载利用了Linux的module特性,可以在系统启动后用insmod命令添加模块(.ko),在不需要的时候用rmmod命令卸载模块,采用这种动态加载的方式便于驱动程序的调试,同时可以针对产品的功能需求,进行内核的裁剪,将不需要的驱动去除,大大减小了内核的存储容量。

在台式机上,一般采用动态加载的方式;在嵌入式产品里,可以先采用动态加载的方式进行调试,调试成功后再编译进内核。

 

猜你喜欢

转载自www.cnblogs.com/shuqingstudy/p/9149598.html