Linux驅動介紹和實例快速入門
一、驅動簡介
Linux的驅動在本質上就是一種軟件程序,上層軟件可以在不了解硬件特性的情況下,通過驅動提供的接口,和計算機硬件進行通信。
系統調用是內核和應用程序之間的接口,而驅動程序是內核和硬件之間的接口。它為應用程序屏蔽了硬件的細節,故對應用程序而言,硬件設備只是一個設備文件,應用程序可以像操作普通文件一樣對硬件設備進行操作。
Linux驅動程序只是內核的一部分,管理著系統的設備控制器和相應的設備。驅動程序,英文名為"Device Driver",全稱“設備驅動程序”,是一種可以使計算機和設備通信的特殊程序,相當于硬件的接口,操作系統只有通過這個接口才能控制硬件設備的工作。它主要完成以下幾個功能:
- 對設備初始化和釋放
- 傳送數據到硬盤和從硬件讀取數據
- 檢測和處理設備出現的錯誤
二、驅動分類
計算機系統的硬件由CPU、存儲器、和外設組成。驅動針對的對象都是存儲器和外設。Linux將外設和存儲器分為三個基礎大類:塊設備驅動,字符設備驅動和網絡設備驅動。
2.1、字符設備驅動
字符設備是指那些必須以串行順序訪問的設備,字符設備的I/O操作沒有通過緩存。字符設備的操作是以字節為基礎的,但一次只能執行一個字節的操作。典型的如LCD、串口、LED、蜂鳴器、觸摸屏等等。
2.2、塊設備驅動
塊設備是相對于字符設備定義的,可以以任意順序進行訪問,以塊為單位進行操作。塊設備驅動的讀寫都有緩存來支持,且塊設備必須能夠隨機存取。設備的塊大小是設備本身設計時定義好的,軟件是不能去更改的,不同設備的塊大小可以不一樣。常見的塊設備都是存儲類設備,如:硬盤、NandFlash、iNand、SD等等。
2.3、網絡設備驅動
網絡設備驅動是專為網卡設計的驅動模型,面向數據包的接收和發送而設計的,它并不應對于文件系統的節點。即不對應于/dev目錄下的設備文件,應用程序最終用套間字socket完成與網絡設備的接口。
除網絡設備外,字符設備和塊設備都被映射到Linux文件系統的文件和目錄,通過文件系統的系統調用接口open(),write(),read(),close()等即可訪問字符設備和塊設備。塊設備比字符設備復雜,在它上面會首先建立一個磁盤/Flash文件系統,如FAT、EXT3、TAFFS、TFFS等,FAT、EXT3、TAFFS、TFF規范了文件和目錄在存儲介質上的組織。
三、驅動的編譯和加載
Linux設備驅動屬于內核的一部分,Linux內核的一個模塊可以以兩種方式被編譯和加載
3.1、編譯方式
內部編譯:將驅動程序源碼放在內核源碼目錄中進行編譯。
外部編譯:將驅動程序源碼放在內核源碼目錄外進行編譯。
3.2、加載方式
靜態加載:編譯進uImage中,系統啟動時直接加載。
動態加載:編譯.ko文件,動態加載驅動模塊。
3.3、編譯器
x86等架構使用gcc即可,arm嵌入式設備需要使用相關交叉編譯工具鏈。
下面是內核模塊的例子:
分析上述程序,發現一個Linux內核模塊需包含模塊初始化和模塊卸載函數,前者在insmod的時候運行,后者在rmmod的時候運行。初始化與卸載函數必須在宏module_init和module_exit使用前定義,否則會出現編譯錯誤。
初始化與卸載函數必須在宏module_init和module_exit使用前定義,否則會出現編譯錯誤。程序中的:
- MODULE_LICENSE(“GPL”)用于聲明模塊的許可證。
- MODULE_AUTHOR:說明作者信息.。
- MODULE_DESCRIPTION:對本驅動的描述。
如果要將其直接編譯入Linux內核,則需要將源代碼文件拷貝入Linux內核源代碼的相應路徑里,并修改Makefile。
模塊初始化函數的任務是為以后調用模塊的函數做準備,好像是模塊說,:" 我在這里, 這是我能做的”。
模塊的退出函數( 例子里是 hello_exit )就在模塊被卸載時調用.,它好像告訴內核, "我不 再在那里了, 不要要求我做任何事了”。
這種編程的方法類似于事件驅動的編程, 但是雖然不是所有的應用程序都是事件驅動的, 每個內核模塊都是。另外一個主要的不同, 在事件驅動的應用程序和內核代碼之間, 是退出函數: 一個終止的應用程序可以在釋放資源方面 懶惰, 或者完全不做清理工作, 但是模塊的退出函數必須小心恢復每個由初始化函數建立的東西, 否則會保留一些東西直到系統重啟。
編寫Makerfile文件來進行編譯:
3.4、驅動加載、卸載及debug