如何編寫一個簡單的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」。

 

  本文的所有代碼在這裏

相關文章
相關標籤/搜索