Linux驅動編程 step-by-step (一)

轉載於:

http://blog.csdn.net/jshazk1989/article/details/6908472

驅動程序的作用:

簡單來說 驅動程序就是使計算機與設備通信的特殊的代碼,在作單片機時候(無OS)我們自己定義接口及自定義的結構來操作相關硬件,而在有OS的模式下我們操作的硬件是去實現對應的接口(這些接口是已定義好的,我們需要實現這些接口)而無需自己定義接口,這樣既能正確的控制設備。又能很好的維護(如果需要升級驅動,上邊的應用程序不需要改變)

編寫驅動考慮的因素

  1. 提供給用戶更多的選項
  2. 保持用戶操作的簡單性
  3. 編寫驅動的時間

驅動分類:

  1. 字符設備:能夠像字節流(類似文件)一樣被訪問的設備(至少實現open, close, read ,write等功能)
  2. 快設備:    用戶空間接口與字符設備相同, 內部實與字符設備完全不同(可以被隨即訪問,一般在類UNIX系統中快設備的讀取每次只能讀一整塊在linux可以操作任意字節)
  3. 網絡設備:網絡通路通過網絡設備形成,能夠與主機交換數據的設備

內核功能劃分:

  1. 進程管理(PM):進程的創建與撤銷,在單個或者多個CPU上實現多進程的抽象
  2. 內存管理(MM):管理內存分配及回收的策略
  3. 文件系統(FS/VFS): Linux 非常依賴於文件系統,內核在沒有結構的硬件系統上構造結文件系統,而文件抽象在整個系統中會廣泛使用,Linux支持多種文件系統類型
  4. 設備控制:驅動程序,操控硬件以及相應總線設備
  5. 網絡(NET): 在網絡接口於應用程序之間傳輸數據。

好了 理論行得東西介紹的差不多了,下邊說點有用的,內核的驅動可以做成模塊在需要的時候裝載,在不需要的時候卸載
我們在編寫用戶程序的時候總喜歡從編寫hello world 寫起 , 在內核驅動模塊也是一樣,下邊是一個hello_world的一個模塊

  1. //hello_world.c   
  2. #include <linux/init.h>   
  3. #include <linux/module.h>  
  4. MODULE_LICENSE("GPL");   
  5.   
  6. static int hello_init(void)   
  7. {   
  8.     printk(KERN_ALERT "hello module\n");   
  9.     return 0;   
  10. }   
  11.   
  12. static void hello_exit(void)   
  13. {   
  14.     printk(KERN_ALERT "hello module exit\n");   
  15. }   
  16.   
  17. module_init(hello_init);   
  18. module_exit(hello_exit);  

以及對應的Makefile

  1. ifneq ($(KERNELRELEASE),)   
  2. # call from kernel build system   
  3. obj-m   := hello_world.o   
  4. #if we need more than one source code to build the module  
  5. #we should use the variable below:  example: modules-objs := file1.o file2.o  
  6. modules-objs :=   
  7.   
  8. else  
  9. #kernel PTAH   
  10. KERNELDIR ?= /lib/modules/$(shell uname -r)/build   
  11. PWD       := $(shell pwd)   
  12.   
  13. modules:   
  14.     $(MAKE) -C $(KERNELDIR) M=$(PWD) modules   
  15.   
  16. endif   
  17.   
  18. clean:   
  19.     rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions  

有幾點與用戶空間程序不同的地方

  1. 模塊程序沒有main函數(那麼程序入口在哪裏?)
  2. 打印函數使用的printk 而不是用戶空間的printf 而且使用方式不一樣
  3. 模塊的編譯不是通常的方式
  4. 頭文件不是常見的那些頭文件
  5. 以及編譯之後不會產生可執行文件,而是 .ko 文件
    ...

模塊沒有main函數,在裝載模塊 insmod 時會調用module_init註冊的函數 此處爲hello_init
在模塊卸載remod時 會調用module_exit註冊的函數 此處爲hello_exit
在module_init 註冊的函數主要是進行初始化,分配內存, 註冊設備等
而module_exit中註冊的函數與之相反, 設備註銷, 釋放內存等
具體的編譯模塊的Makefile我在另一篇文章中有說到 此處不再贅述
內核的打印函數使用printk去打印信息, printk不支持浮點類型, 在printk中可以加入信息級別有7中

  1. #define KERN_EMERG    "<0>"    /* system is unusable */  
  2. #define KERN_ALERT    "<1>"    /* action must be taken immediately */  
  3. #define KERN_CRIT     "<2>"    /* critical conditions */  
  4. #define KERN_ERR      "<3>"    /* error conditions */  
  5. #define KERN_WARNING  "<4>"    /* warning conditions */  
  6. #define KERN_NOTICE   "<5>"    /* normal but significant */  
  7. #define KERN_INFO     "<6>"    /* informational */  
  8. #define KERN_DEBUG    "<7>"    /* debug-level messages */  

對應與不同的錯誤等級 選擇不懂的option, 並做不同的處理, 小於一定等級的信息會直接打印到終端(非X-window下的終端),可以使用dmesg來查看全部的打印信息
編譯內核的頭文件是在/lib/modules/$(shell uname -r)/build/include下得,而不是用戶模式下得/usr/include
編譯後不會生產可執行文件,會生成一個.ko的文件
使用insmod xxx.ko去裝載模塊
使用lsmod去查看已裝載的模塊
使用rmmod xxx 去卸載相應模塊(卸載是不帶.ko)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章