如何编写一个简单的Linux驱动(一)——驱动的基本框架

前言linux

  最近在学习Linux驱动,记录下本身学习的历程。git

1.驱动的基本框架程序员

  Linux驱动的基本框架包含两部分,“模块入口、出口的注册”和“模块入口、出口函数的实现”,以下方代码。  github

 1 static int __init shanwuyan_init(void)    //驱动入口函数
 2 {
 3     return 0;
 4 }
 5 
 6 static void __exit shanwuyan_exit(void)    //驱动出口函数
 7 {
 8 
 9 }
10 
11 module_init(shanwuyan_init);    //注册入口函数
12 module_exit(shanwuyan_exit);    //注册出口函数

  其中,module_init()和module_exit()两个函数的做用是注册驱动的入口“shanwuyan_init”和出口“shanwuyan_exit”。加载驱动时会运行入口函数,卸载驱动时会运行出口函数。入口函数的做用是加载驱动时作一些初始化工做,好比注册设备、申请设备号、生成设备节点等等,其返回值为int类型;出口函数的做用是卸载驱动时作一些善后操做,好比注销设备、注销设备号、销毁类等等。shell

2.一个基本驱动的编写bash

  本文的主要目的是让读者了解驱动的基本框架,咱们先不实现注册设备、申请设备号、注销设备等复杂的工做。框架

  为了让驱动的加载和卸载工做更直观地为程序员所观察,咱们能够在入口函数和出口函数中添加打印语句,这样每次加载和卸载驱动的时候,程序员都能在终端观察到相应的信息,以下方代码。  函数

 1 static int __init shanwuyan_init(void)    //驱动入口函数
 2 {
 3     printk(KERN_EMERG "shanwuyan_init\r\n");
 4     return 0;
 5 }
 6 
 7 static void __exit shanwuyan_exit(void)    //驱动出口函数
 8 {
 9     printk(KERN_EMERG "shanwuyan_exit\r\n");
10 }

  “printk”函数是什么?说到打印,有C语言基础的读者首先想到的可能就是“printf”函数,可是“printf”只能在应用层面工做,而设备驱动是工做在内核态下的,因此“printf”不能在设备驱动中工做。在内核态下的打印函数是“printk”函数。KERN_EMERG是打印优先级,这里采用了最高优先级。学习

  再加上头文件以及注册用的函数,能够获得一个相对完整的代码。    spa

 1 /* 源代码文件名为:shanwuyan.c */
 2 #include <linux/module.h>
 3 #include <linux/kernel.h>
 4 #include <linux/init.h>
 5 #include <linux/fs.h>
 6 #include <linux/uaccess.h>
 7 
 8 static int __init shanwuyan_init(void)    //驱动入口函数
 9 {
10     printk(KERN_EMERG "shanwuyan_init\r\n");
11     return 0;
12 }
13 
14 static void __exit shanwuyan_exit(void)    //驱动出口函数
15 {
16     printk(KERN_EMERG "shanwuyan_exit\r\n");
17 }
18 
19 module_init(shanwuyan_init);    //注册入口函数
20 module_exit(shanwuyan_exit);    //注册出口函数

  该设备驱动实现的功能是:加载驱动时打印字符串“shanwuyan_init”,卸载驱动时打印字符串“shanwuyan_exit”。

3.Makefile文件的编写

  Makefile文件没什么可说的,代码以下(记得匹配本身的内核目录)。  

 1 #!/bin/bash
 2 
 3 obj-m += shanwuyan.o    #此处要和你的驱动源文件同名
 4 
 5 KDIR := /home/topeet/Android/iTop4412_Kernel_3.0    #这里是你的内核目录
 6 
 7 PWD ?= $(shell pwd)
 8 
 9 all:
10     make -C $(KDIR) M=$(PWD) modules    #make操做
11 
12 clean:
13     make -C $(KDIR) M=$(PWD) clean    #make clean操做

4.应用

  编译,并加载生成的“shanwuyan.ko”文件,加载驱动和卸载驱动的命令以下。  

1 insmod shanwuyan.ko #加载驱动
2 rmmod shanwuyan.ko #卸载驱动,若是该命令不起做用,请用下方的命令
3 rmmod shanwuyan    #卸载驱动

  进入到驱动文件所在的路径下,并在命令行输入加载驱动的命令“insmod shanwuyan.ko”,能够看到驱动入口函数打印出来的字符串信息“shanwuyan_init”。

  可是终端还打印了两行警告信息“shanwuyan: module license 'unspecified' taints kernel”和“Disabling lock debugging due to kernel”,这是由于咱们没有在代码中加入赞成开源协议,因此终端打印该信息。须要注意的是,该警告信息只有在系统启动后第一次加载驱动时才会打印,卸载掉以后,若是不重启系统,再加载驱动时就不会再打印这两行警告信息了。

  打开源文件,加入GPL开源协议,一个完整的基本驱动框架就完成了,所有代码以下。

 1 /* 源代码文件名为:shanwuyan.c */
 2 #include <linux/module.h>
 3 #include <linux/kernel.h>
 4 #include <linux/init.h>
 5 #include <linux/fs.h>
 6 #include <linux/uaccess.h>
 7 
 8 static int __init shanwuyan_init(void)    //驱动入口函数
 9 {
10     printk(KERN_EMERG "shanwuyan_init\r\n");
11     return 0;
12 }
13 
14 static void __exit shanwuyan_exit(void)    //驱动出口函数
15 {
16     printk(KERN_EMERG "shanwuyan_exit\r\n");
17 }
18 
19 module_init(shanwuyan_init);    //注册入口函数
20 module_exit(shanwuyan_exit);    //注册出口函数
21 
22 MODULE_LICENSE("GPL");    //赞成GPL开源协议,就不会打印警告信息了
23 MODULE_AUTHOR("shanwuyan");    //还能够再添加上做者名称

  再次编译,重启系统,并加载驱动,此次不会再打印警告信息了,只打印了咱们在入口函数中写的字符串,以下图。

  使用“rmmod shanwuyan”命令卸载驱动,出现错误,以下图。  

  这是咱们须要建立文件夹“/lib/modules”,建立后再次卸载驱动,又出现了错误,以下图。

  咱们按照错误信息,建立文件夹“/lib/modules/3.0.15”(根据内核版本的不一样而不一样),再次卸载驱动,成功,打印出来咱们想要的字符串信息“shanwuyan_exit”。

 

  本文的所有代码在这里

相关文章
相关标签/搜索