無論是vc還是vb,還是c#,還是jsp php等等語言,在學習他們之前總是先來乙個hello world的例子,這個好像成了我們程式入門的必經之路。所以在驅動程式的學習上,也離不開這個步驟。但是驅動程式的開發是執行在核心空間的,而應用程式 是執行在使用者空間的,所以驅動程式的開發盒除錯和應用程式的開發都有很大的區別。對於這個hello world的程式我也化了不少時間才搞清楚。
驅動程式作為系統核心的一部分,它工作在核心態,而應用程式工作在使用者態。也就是說,不能直接通過指標,把使用者空間的資料位址傳遞給核心(因為mmu對映 的位址根本不一樣)。要想在應用程式和驅動程式之間傳遞資料(指標),就需要經過轉換。把使用者態「看到」的空間位址轉換成核心態可訪問的位址。
linux系統提供了一系列方便的函式實現這種轉換,如get_user、put_user、copy_from_user、copy_to_user等,它們自己負責訪問許可權的檢查,使用時,不需要關係更多的問題。
linux核心把驅動程式劃分為3種型別:字元裝置、塊裝置和網路裝置。字元裝置和塊裝置可以像檔案一樣被訪問。它們的主要區別不在於能否seek,而是 在於系統對於這兩種型別裝置的管理方式。應用程式對於字元裝置的每乙個i/o操作,都會直接傳遞給系統核心對應的驅動程式;而應用程式對於塊裝置的操作, 要經過系統的緩衝區管理,間接傳遞給驅動程式處理。塊裝置的這種管理方式是為儲存提供優化的;而字元裝置的管理方式是為操作提供優化的。
至 於網路裝置,它在linux系統中是一模擬較特殊的裝置它不像字元裝置或塊裝置那樣通過對應的裝置檔案節點去訪問,核心也不再通過read和write等 呼叫去訪問網路裝置。linux的網路系統主要是基於bsd unix的套接字機制,在系統和驅動程式之間有專門的資料結構進行資料傳輸,系統支援對資料傳送和資料接收快取,提供流量控制機制,提供更多的協議支援。
在linux系統中,驅動程式都做成模組的形式,也就是module。簡單的說,乙個模組提供乙個功能,這些模組是可以按照需要隨時裝入核心空間和從核心空間解除安裝的。因此,核心模組是為了給核心動態增減功能而設計的,並不僅僅是限於驅動程式。
因為核心模組需要載入到核心空間,所以其程式的編寫與一般應用程式不同,在裡面再也找不到類似main()這樣的入口函式,下面對應函式相應的源**hello.c,分析乙個驅動模組的寫法。
#ifndef __kernel__
#define __kernel__
#endif
#ifndef module
#define module
#endif
#include //所有模組都需要的標頭檔案
#include
#include
#include // init和exit相關巨集
module_license('gpl');
int text_init(void)
void text_cleanup(void)
module_init(text_init); //註冊載入時執行的函式
module_exit(text_cleanup); //註冊解除安裝時執行的函式
乙個linux核心模組需包含模組初始化和模組解除安裝函式,前者在insmod的時候執行,後者在rmmod的時候執行。初始化與解除安裝函式必須在巨集module_init和module_exit使用前定義,否則會出現編譯錯誤。
程式中的module_license('gpl')用於宣告模組的許可證。
編譯:gcc -c -i /usr/src/linux-2.4/include/ hello.c
執行:insmod hello.o
終端上會顯示:
localhost kernel:hello world!
同時在/proc/modules裡面會看到相應的裝置資訊:
more /proc/modules
你會看到(或許後面的數值不一樣):
hello 844 0 (unused)
.......
解除安裝驅動程式:
rmmod hello
你將會在終端上面看到:
localhost kernel:goodbye world!
模組程式設計需要注意:
1.在gcc編譯選項中增加-c
2.在gcc編譯選項中定義兩個巨集:-dmodule -d__kerenl__
或直接在原始檔中定義這兩個巨集:
#define module
#define __kernel__
3.在原始檔中包括module.h檔案:
#i nclude
4.假定你現在執行的核心的原始碼目錄絕對路徑是mykernelsrcpath,在gcc編譯時增加選項:
-i $mykernelsrcpath/include (如-i /usr/src/linux/include)
5.某些時候用insmod -f能夠成功載入,但需謹慎使用。
6.如果看不到用printk列印的資訊,可以用dmesg命令看。
7.列印訊息受級別的限制,訊息級別可以通過printk設定,如:
printk('something'); /* 其中0 /proc/sys/kernel/printk
關於核心模組初始化(載入)函式
當使用者輸入命令「insmod 模組檔名」(或者其他方式)載入核心模組時,系統會檢測此模組能否被載入,如果能被載入,核心呼叫模組的初始化函式。在linux 2.4中,核心模組的初始化函式名為init_module()。但如果驅動程式需要編譯進核心,則初始化函式不能與核心的其他部分(包括其他核心模組) 的函式同名。這樣,如果程式可能編譯到核心中時就比較麻煩。不過在這個標頭檔案中定義了巨集module_init(),用來遮蔽兩者的差別,事實上,使用這 個巨集可以使驅動程式向上相容linux 2.6,而相容linux 2.0也比較方便。
關於核心模組清除(解除安裝)函式
當使用者輸入命令「rmmod 模組檔名」(或者其他方式)解除安裝核心模組時,此時,系統會檢測此模組是否能被解除安裝,核心將呼叫模組清除函式。在linux 2.4中,清除函式的函式名稱為cleanup_module()。但如果驅動程式需要編譯進核心,則初始化函式不能與核心的其他部分(包括其他核心模 塊)的函式同名。這樣,如果程式可能編譯到核心中時就比較麻煩。不過在這個標頭檔案中定義了巨集module_exit(),用來遮蔽兩者的差別。
linux 核心 驅動
首先 1.建立裝置 分配cdev結構體 if globalmem major 手動分配 ret register chrdev region devno,1,globalmem else globalmem 提供給上層使用 2 建立核心裝置 struct globalmem dev globalme...
乙個簡單的linux核心驅動
一,核心結構簡單概述 上層程式操作裝置驅動簡單概述 在使用者空間使用相關的c庫,比如open函式會造成乙個中斷,系統會去呼叫sys call函式 系統呼叫 然後會去呼叫相關的sys open函式,在核心空間的時候會去驅動鏈表裡面查詢對應的外設驅動,我們編寫完驅動程式,載入到核心,核心會去呼叫相關的驅...
新增linux核心驅動
1.將核心驅動.ko放入 lib modules 3.2.0 23 generic kernel drivers 目錄下 2.執行depmod a來解決依賴 掃瞄driver下的驅動依賴關係 命令執行完成後,會自動生成modules.dep 和modules.alias。dep為依賴關係。3.更新當...