一 編寫Linux驅動程序
1.建立Linux驅動骨架
Linux內核在使用驅動時需要裝載與卸載驅動
裝載驅動:建立設備文件、分配內存地址空間等;module_init 函數處理驅動初始化
卸載驅動:刪除設備文件、釋放內存地址空間等;module_exit函數處理退出
包含這兩個函數的兩個宏的C程序文件也可看做是Linux驅動的骨架
2.注冊和注銷設備文件
任何一個Linux驅動都需要有一個設備文件,否則應用程序將無法與驅動程序交互。
建立設備文件:在第一步編寫的處理Linux初始化工作的函數中完成。misc_register函數
刪除設備文件:在第一步編寫的處理Linux退出工作的函數中完成。misc_deregister函數
3.指定與驅動相關的信息
驅動程序是自描述的,驅動程序的作者姓名、使用的開源協議、別名、驅動描述等信息。這些信息都需要在驅動源代碼中指定。
MODULE_AUTHOR、MODULE_LICENSE、MODULE_ALLS、MODULE_DESCRIPION等宏可以指定與驅動相關的信息
4.指定回調函數
一個驅動程序並不一定要指定所有的回調函數,回調函數會通過相關機制進行注冊
5.編寫業務邏輯
具體的業務邏輯與驅動的功能有關,業務邏輯可能由多個函數、多個文件甚至是多個Linux驅動模塊組成
6.編寫Makefile文件
Linux內核源代碼的編譯規則是通過Makefile文件定義的。因此編寫一個新的Linux驅動程序必須有一個Makefile文件
7.編譯Linux驅動程序
可以直接編譯進內核,也可以作為模塊單獨編譯
8.安裝和卸載Linux驅動
若將Linux驅動編譯進內核,只要Linux使用該內核,驅動程序就會自動轉載
若Linux驅動程序以模塊單獨存在,需使用insmod或modprode命令裝載Linux驅動模塊,rmmod命令卸載Linux驅動模塊
二 第一個Linux驅動,以word_count為例
(一)基礎編寫代碼
#mkdir -p /root/drivers/ch06/word_count 建立目錄存放Linux驅動程序
#cd /root/drivers/ch06/word_count
#echo '' > word_count.c 建立驅動源代碼文件
#echo 'obj-m := word_count.o' > Makefile 編寫一個Makefile文件 make命令會吧Linux驅動源代碼目錄中的word_count.c或 word_count.s文件編譯成word_count.o文件
obj-m 表示將Linux驅動作為模塊(.ko文件)編譯,word_count.o會被連接進word_count.ko文件,然后使用insmod或modprode命令裝載word_count.ko
obj-y 表示將Linux驅動編譯進Linux內核,word_count.o會被連接進built-in.o 文件,最終會被連接進內核
Linux系統將內存分為了用戶空間和內核空間,兩者空間的程序不能直接訪問,printk函數運行在內核空間,printf函數運行在用戶空間,因此屬於內核程序的Linux驅動是不能直接訪問printf函數的。
#make -C /usr/src/linux-headers-3.0.0-15-generic M=/root/driver/ch06/word_count 編譯Linux驅動源代碼
# insmod word_count.ko 裝載驅動
# lsmod | grep word_count 查看word_count是否安裝成功
# rmmod word_count 卸載Linux驅動
#dmesg | grep word_count | tail -n 2 查看有Linux驅動輸出的日志信息
(二)加入有關指定的信息的代碼
模塊作者:MODULE_AUTHOR("lining");
模塊描述:MODULE_DESCRPTION("statistics of word count .");
模塊別名:MODULE_ALIAS("word count module.");
開源協議: MODULE_LICENSE("GPL");
#define DEVICE_NAME "wordcount" //定義設備文件名
//描述與設備文件觸發的事件對應的回調函數指針
//owner:設備事件回調幻術應用於哪些驅動模塊,THIS_MODULE表示應用於當前驅動模塊
static struct file_operations dev_fops={.owner = THIS_MODULE};
//描述設備文件的信息
//minor:次設備號 MISC_DYNAMIC_MINOR,:動態生成次設備號 name : 設備文件名稱
//fops : file_operations 結構體變量指針
static struct miscdevice misc={.minor = MISC_DYNAMIC_MINOR, .name=DEVICE_NAME,.fops = &dev_fops};
//初始化Linux驅動
static int word_count_init(void)
{ int ret;
ret = misc_register(&misc);
printk("word_count_init_success\n");
return ret;
}
// 卸載Linux驅動
static void word_count_exit(void)
{ misc_deregister(&misc);
printk("word_inti_exit_success\n");
}
由於內核空間的程序不能直接訪問用戶空間中的數據,因此,需要在word_count_read(從設備文件讀數據)和word_count_write(向設備文件寫數據) 函數中分別使用copy_to_user和copy_from_user函數將數據從內核空間復制到用戶空間或從用戶空間復制到內核空間
(三)裝載與卸載驅動
檢查word_count驅動工作是否完全正常
#dmesg | tail -n 1
#modinfo word_count.ko
檢測Linux驅動模塊的依賴關系
#depmod /root/drivers/ch06/word_count/word_count.ko
調用命令裝載Linux驅動
#modprode word_count
注:insmod 和 modprode 命令都是加載驅動,后者可以檢查驅動模塊的依賴性
三 多種方法測試Linux驅動
(一)使用Ubuntu Linux 測試Linux驅動
需要編寫專門用於測試的程序,例如test_word_count.c
#gcc test_word_count.c -o test_word_count
#test_word_count
#test_word_count "I love you."
輸出結果: String:I love you.
word byte display:0,0,0,3
word count:3
(二)在android模擬器上通過原生C程序測試Linux驅動
#cd ~/kernel/goldfish
#make menuconfig
按照如圖所示進行設置,之后重新編譯Linux內核,成功編譯內核后,android模擬器可以使用性生成的zImage內核文件動態裝載Linux驅動模塊。
兩個條件滿足可以直接運行普通的Linux程序:android模擬器、開發板或手機需要有root權限;可執行文件需要使用交叉編譯器來編譯test_word_count.c文件,建立Android.mk設置編譯參數,並使用make命令進行編譯
#mm 編譯.c文件,在相應目錄下
#adb push ./emulator/test_word_count /data/local 上傳到Android模擬器
執行下面命令測試驅動
#chmod 777 /data/local/test_word_count 設置可執行權限
#/data/local/test_word_count
#/data/local/test_word_count 'a bb ccc ddd eee'
輸出結果:5,表示測試成功
(三)使用Android NDK測試
(四)使用開發板測試
(五)將驅動編譯進Linux內核進行測試
四 在eclipse中開發Linux驅動程序
第一步:建立C工程
第二步:建立C源代碼文件鏈接 New>Source Folder Folder name 輸入 src,導入word_count.c文件
第三步:設置include路徑 單擊菜單項properties,C/C++General > Paths and Symbols ,選中Include的GNU C項,Add添加兩個路徑:/root/kernel/goldfish/include和/root/kernel/goldfish/arch/arm/include
第四步:編譯Linux驅動
測試Linux驅動
第一步:導入test_word_count.c文件
第二步:設置include路徑
第三步:建立Target Make Target > Create ,在Target name 文本框中輸入word_count_eclipse_test,點擊OK
第四步:Build工程 Make Target > Build,選中第三步中建立的文件,然后點擊Build
第五步:運行測試程序 Run As > Local C/C++ Application