歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux編程 >> Linux編程 >> 【Linux 驅動】驅動開發第一步----開發環境搭配

【Linux 驅動】驅動開發第一步----開發環境搭配

日期:2017/3/1 10:24:47   编辑:Linux編程

一,環境搭建步驟

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

  1. #include <linux/init.h>
  2. #include <linux/module.h>
  3. MODULE_LICENSE("Dual BSD/GPL");
  4. static int hello_init(void)
  5. {
  6. printk(KERN_ALERT "Hello, world\n"); //printk 跟printf 類似,只是printk運行在內核態
  7. return 0;
  8. }
  9. static void hello_exit(void)
  10. {
  11. printk(KERN_ALERT "Goodbye, cruel world\n");
  12. }
  13. module_init(hello_init);
  14. module_exit(hello_exit);

三,Makefile

  1. ifneq ($(KERNELRELEASE),)
  2. obj-m :=hello.o
  3. else
  4. KERNELDIR ?= /lib/modules/$(shell uname -r)/build
  5. PWD := $(shell pwd)
  6. default:
  7. $(MAKE) -C $(KERNELDIR) M=$(PWD) modules
  8. endif
四,~#make //生成文件如下

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)查找文件位置:

  1. #include <linux/init.h>//這個頭文件包含了你的模塊初始化與清除的函數
  2. #include <linux/module.h>//包含了許多符號與函數的定義,這些符號與函數多與加載模塊有關
find / -name module.h

我的文件位置在:/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_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 // 告訴用戶空間這個模塊支持什麼樣的設備


MODULE_聲明可以寫在模塊的任何地方(但必須在函數外面),但是慣例是寫在模塊最後。

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

Copyright © Linux教程網 All Rights Reserved