一,環境搭建步驟
1)下載Linux源碼
1> ~#apt-cache search linux-source
出現:linux-source - Linux kernel source with Ubuntu patches
linux-source-3.0.0 - Linux kernel source for version 3.0.0 with Ubuntu patches
2>~#apt-get install linux-source-3.0.0
下載完成後,在/usr/src/下會出現一個linux-source-3.0.0.tar.bz2。解壓: tar jxvf linux-source-3.0.0.tar.bz2
3>然後在Linux內核源碼目錄/usr/src/linux-source-2.6.32目錄下面用老的方法配置好Linux內核:
~#make oldconfig
4>編譯內核:~#make //大概需要一個小時
5>編譯模塊:~#make modules
6>安裝模塊:~#make modules_install
以上步驟完成後,會在/lib/modules 目錄下生成一個文件夾3.0.0-12-generic
二,hello.c
三,Makefile
hello.c hello.ko hello.mod.o Makefile modules.order
hello.c~ hello.mod.c hello.o Makefile~ Module.symvers
1>裝載目標模塊:~#insmod ./hello.ko
~#lsmod //查看目前安裝的驅動模塊,有hello
2>模塊裝載觸發hello.c的init()方法,輸出hello world,如果沒有的話,是因為其將輸出放到/var/log/syslog中去了。打開便可以看見你的結果!
卸載目標模塊命令是:~#rmmod ./hello.ko
總結:從此我們邁出了Linux驅動開發的第一步
代碼深度解析:
1)查找文件位置:
我的文件位置在:/usr/src/linux-source-3.0.0/include/linux/module.h //其余的位置也有好多,但是這個文件位置才是正解
/usr/src/linux-source-3.0.0/include/linux/in.h
2)另外,如果你的模塊需要用到參數傳遞,那麼你可能就要聲明moduleparam.h這個頭文件了。
3)模塊裡常包含一些描述性聲明,如:
MODULE_聲明可以寫在模塊的任何地方(但必須在函數外面),但是慣例是寫在模塊最後。MODULE_LICENSE("GPL"); // "GPL" 是指明了 這是GNU General Public License的任意版本
// “GPL v2” 是指明 這僅聲明為GPL的第二版本
// "GPL and addtional"
// "Dual BSD/GPL"
// "Dual MPL/GPL"
// "Proprietary" 私有的
// 除非你的模塊顯式地聲明一個開源版本,否則內核會默認你這是一個私有的模塊(Proprietary)。
MODULE_AUTHOR // 聲明作者
MODULE_DESCRIPTION // 對這個模塊作一個簡單的描述,這個描述是"human-readable"的
MODULE_VERSION // 這個模塊的版本
MODULE_ALIAS // 這個模塊的別名
MODULE_DEVICE_TABLE // 告訴用戶空間這個模塊支持什麼樣的設備
4)
Linux KERN_ALERT 什麼意思消息打印級別:
fmt----消息級別:
#define KERN_EMERG "<0>"
#define KERN_ALERT "<1>"
#define KERN_CRIT "<2>"
#define KERN_ERR "<3>"
#define KERN_WARNING "<4>"
#define KERN_NOTICE "<5>"
#define KERN_INFO "<6>"
#define KERN_DEBUG "<7>"
不同級別使用不同字符串表示,數字越小,級別越高。
printk輸出跟輸出的日志級別有關系,當輸出日志級別比控制台的級別高時,就會顯示在控制台上,當比控制台低時,則會記錄在/var/log/message中.但是當系統同時運行了klogd和syslogd時,都追加到/var/log/message.在/proc/sys/kernel/printk文件中,前兩個整數為當前的日志級別和默認的日志級別(默認的日志級別即為printk的輸出級別).
注意:
需要開啟klogd和syslogd服務才能正常輸出。通過klogd可以改變系統消息輸出級別。
linux0.11為什麼在內核態使用printk()函數,而在用戶態使用printf()函數?
(1) 答:printk()函數是直接使用了向終端寫函數tty_write()。而printf()函數是調用write()系統調用函數向標准輸出設備寫。所以在用戶態(如進程0)不能夠直接使用printk()函數,而在內核態由於他已是特權級,所以無需系統調用來改變特權級,因而能夠直接使用printk()函數。
printk是內核輸出,在終端是看不見的。
你可以看一下系統日志。/var/log/message。
或者使用dmesg命令看一下
不管你可能怎麼想,printk()並不是設計用來同用戶交互的,雖然我們在 hello-1就是出於這樣的目的使用它!它實際上是為內核提供日志功能, 記錄內核信息或用來給出警告。因此,每個printk() 聲明都會帶一個優先級,就像你看到的<1>和KERN_ALERT 那樣。內核總共定義了八個優先級的宏, 所以你不必使用晦澀的數字代碼,並且你可以從文件linux/kernel.h查看這些宏和它們的意義。如果你 不指明優先級,默認的優先級DEFAULT_MESSAGE_LOGLEVEL將被采用。
閱讀一下這些優先級的宏。頭文件同時也描述了每個優先級的意義。在實際中, 使用宏而不要使用數字,就像<4>。總是使用宏,就像 KERN_WARNING。
當優先級低於int console_loglevel,信息將直接打印在你的終端上。如果同時 syslogd和klogd都在運行,信息也同時添加在文件 /var/log/messages,而不管是否顯示在控制台上與否。我們使用像 KERN_ALERT這樣的高優先級,來確保printk()將信息輸出到 控制台而不是只是添加到日志文件中。 當你編寫真正的實用的模塊時,你應該針對可能遇到的情況使用合 適的優先級。
相關閱讀:
【Linux 驅動】第一章 設備驅動程序簡介 http://www.linuxidc.com/Linux/2012-04/58410.htm
【Linux 驅動】第二章 構造和運行模塊 http://www.linuxidc.com/Linux/2012-04/58411.htm