前言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」。
本文的所有代碼在這裏。