天天看點

【驅動】linux裝置驅動·掃盲

linux裝置驅動

   Linux系統把裝置驅動分成字元裝置、塊裝置和網絡裝置三種類型。

核心為裝置驅動提供了注冊和管理的接口,裝置驅動還可以使用核心提供的其他功能以及通路核心資源。

PCI局部總線

   早期的計算機有衆多總線标準。從最初的8位總線到16位總線,到目前主流的32位總線,不同廠商都制定了自己的總線标準。不同的總線裝置給裝置驅動的設計帶了麻煩,直到後來PCI局部總線出台這種局面才得到緩解,并且逐漸成為事實上的标準。

   PCI是英文Peripheral Component Interconnect的縮寫,中文意思是外設部件互連标準。

   PCI局部總線标準最早由英特爾公司為制定,最初主要應用在PC機。目前已經被越來越多的嵌入式系統已經其他類型的計算機系統使用。

   設計PCI的原因是由于之前的總線有許多的缺點,歸納總結為以下幾點:

總線速度過慢。

總線位址配置設定方法複雜。

總線資源共享效率低。

   PCI總線采用軟體配置位址和其它總線資訊的方法,避免了手工配置裝置在總線位址帶來的麻煩,此外,PCI還支援通過橋的方式擴充總線的處理能力。

Linux裝置驅動基本概念

   在Linux系統中,所有的資源都是作為檔案管理的,裝置驅動也不例外,裝置驅動通常是作為一類特殊的檔案存放在/dev目錄下。

   這裡僅列出了一部分檔案,裝置檔案屬性最開始的一個字元c表示該裝置檔案關聯的是一個字元裝置;b表示關聯的是一個塊裝置。在檔案清單的中間部分有兩個數字,第一個數字稱做主裝置号,第二個數字稱做次裝置号。

在核心中使用主裝置号辨別一個裝置,次裝置号提供給裝置驅動使用。

   在打工一個裝置的時候,核心會根據裝置的主裝置号得到裝置驅動,并且把次裝置傳遞給驅動。linux核心為所有裝置都配置設定了主裝置号,在編寫驅動程式之前需要參考核心代碼Documentation/devices.txt檔案,確定使用的裝置号沒有被占用。

在使用一個裝置之前,需要使用linux提供的mknod指令建立裝置檔案。mknod指令格式如下

   其中,NAME是裝置檔案名稱;TYPE是裝置類型,c代碼字元裝置,b代表塊裝置;MAJOR是主裝置号,MINOR是次裝置号。OPTION是選項,-m參數用于指定裝置檔案通路權限。

   linux核心按照外部裝置工作特點把裝置分成了字元裝置、塊裝置和網絡裝置3種基本類型。

在編寫裝置驅動的時候,需要使用核心提供的裝置驅動接口,向核心提供具體裝置的操作方法。

字元裝置

   字元裝置是Linux系統最簡單的一類裝置。

應用程式可以像操作普通檔案一樣操作字元裝置。常見的序列槽、數據機都是字元裝置。

   編寫字元裝置驅動需要使用核心提供的register_chardev()函數注冊一個字元裝置驅動。

   函數定義如下:

   fops是指向函數指針數組的結構指針,驅動程式的入口函數都包括在這個指針内部。    

該函數的傳回值如果小于0表示注冊裝置驅動失敗,如果設定major為0,表示由核心動态配置設定主裝置号,函數的傳回值是主裝置号。    

   當使用register_chardve()函數成功注冊一個字元裝置後,會在/proc/devices檔案中顯示出裝置資訊

   删除了一些,其中Character devices是字元裝置驅動清單,Block devices是塊裝置驅動清單,數字代表主裝置驅動,後面是裝置驅動名稱。

   與注冊驅動相反,核心提供了unregister_chardev()函數解除安裝裝置驅動or

   核心會比較裝置驅動名稱與裝置号是否相同,如果不同函數傳回-EINVAL。錯誤地解除安裝裝置驅動會帶來嚴重後果,是以在解除安裝驅動的時候應該對函數傳回值做判斷。

   在register_chardev()函數中有一個fops參數,該參數指向一個file_operation結構,該結構包含了驅動上的所有操作。随着核心功能的不斷增加,file_operations結構的定義也越來越複雜。

   大部分驅動都沒有提供所有的函數,對于字元裝置來說,常用的函數如下

【驅動】linux裝置驅動·掃盲

塊裝置

   與字元裝置相比,塊裝置要複雜的多。

   最主要的差别是塊裝置帶有緩沖,字元裝置沒有。

塊裝置傳輸資料隻能以塊作為機關讀寫,字元裝置是以位元組作為最小讀寫機關的。塊裝置對于I/O請求有對應的緩沖區,可以選擇響應的順序,如采用特定的排程政策等;字元裝置隻能順序通路。

   此外,塊裝置提供了随機通路的能力,而字元裝置之順序讀取資料。

   塊裝置提供了一個類似字元裝置的通路函數結構block_device_operations,定義如下

   其中,open、release、ioctl等函數的功能與字元裝置相同。

塊裝置提供了幾個特有的函數成員:

media_change()函數用來檢查媒體是否改變,主要用于檢查可移動裝置;

revalidate_disk()函數響應實體媒體的改變請求;

getgen()函數用于向系統彙報驅動器資訊。

網絡裝置

   在Linux核心中,網絡裝置是一類特殊的裝置,是以被單獨設計為一種類型的驅動。

   與其他裝置不同的是,網絡裝置不是通過裝置檔案通路的,在/dev目錄下不會看到任何網絡裝置。是以,網絡裝置的操作不是通過檔案操作實作的。

   Linux核心為了抽象網絡裝置界面,為其定義了一個接口用于屏蔽網絡環境下各種網絡裝置的差别。核心對所有網絡裝置的通路都通過這個抽象的接口,接口對上層網絡協定提供相同的操作方法。

繼續閱讀