1. 程式人生 > >淺談裝置驅動的作用與本質,有無作業系統Linux裝置驅動的區別

淺談裝置驅動的作用與本質,有無作業系統Linux裝置驅動的區別

 

一、驅動的作用

任何一個計算機系統的執行都是系統中軟硬體協作的結果,沒有硬體的軟體是空中樓閣,而沒有軟體的硬體則只是一堆廢鐵。硬體是底層基礎,是所有軟體得以執行的平臺,程式碼最終會落實為硬體上的組合邏輯與時序邏輯;軟體則實現了具體應用,它按照各種不同的業務需求而設計,滿足了使用者的需求。硬體較固定,軟體則很靈活,可以適應各種複雜多變的應用。可以說,計算機系統的軟硬體互相成就了對方。

但是,軟硬體之間同樣存在著悖論,那就是軟體和硬體不應該互相滲透到對方的領地。為了儘可能快速地完成設計,應用軟體工程師不想也不必關心硬體,而硬體工程師也難有足夠的閒暇和能力來顧及軟體。例如,應用軟體工程師在呼叫套接字傳送和接收資料包

的時候,他不必關心網絡卡上的中斷、暫存器、儲存空間、I/O埠、片選以及其他任何硬體詞彙;在使用printf()函式輸出資訊的時候,他不用知道底層究竟是怎樣把相應的資訊輸出到螢幕或串列埠。

也就是說,應用軟體工程師需要看到一個沒有硬體的純粹的軟體世界,硬體必須被透明地呈現給他們。誰來實現硬體對應用軟體工程師的隱形?這個艱鉅的任務就落在了驅動工程師的頭上。

對裝置驅動最通俗的解釋就是“驅使硬體裝置行動” 。裝置驅動與底層硬體直接打交道,按照硬體裝置的具體工作方式讀寫裝置暫存器,完成裝置的輪詢、中斷處理、DMA通訊,進行實體記憶體向虛擬記憶體的對映,最終使通訊裝置能夠收發資料,使顯示裝置能夠顯示文字和畫面,使儲存裝置能夠記錄檔案和資料。

由此可見,裝置驅動充當了硬體和應用軟體之間的紐帶,它使得應用軟體只需要呼叫系統軟體的應用程式設計介面(API)就可讓硬體去完成要求的工作。在系統中沒有作業系統的情況下,工程師可以根據硬體裝置的特點自行定義介面,如對串列埠定義SerialSend()、SerialRecv();對 LED 定義LightOn()、LightOff();以及對 Flash 定義FlashWrite()、FlashRead()等。而在有作業系統的情況下,裝置驅動的架構則由相應的作業系統定義,驅動工程師必須按照相應的架構設計裝置驅動,這樣,裝置驅動才能良好地整合到作業系統的核心中。

驅動程式溝通著硬體和應用軟體,而驅動工程師則溝通著硬體工程師和應用軟體工程師。隨著通訊、電子行業的迅速發展,全世界每天都會有大量的新晶片被生產,大量的新電路板被設計,因此,也會有大量裝置驅動需要開發。這些裝置驅動,或執行在簡單的單任務環境中,或執行在 VxWorks、Linux、Windows等多工作業系統環境中,發揮著不可替代的作用。

二、有無作業系統的區別

1)無作業系統(即裸機)時的裝置驅動

並不是任何一個計算機系統都一定要執行作業系統,在許多情況下作業系統是不要的。對於功能比較單一、控制並不複雜的系統,如公交車刷卡機、電冰箱、微波、簡單的手機和小靈通等,並不需要多工排程、檔案系統、記憶體管理等複雜功能,單任務架構完全可以很好地支援它們的工作。一個無限迴圈中夾雜對裝置中斷的檢測或者對裝置的輪詢是這種系統中軟體的典型架構。裸機的實現就有點類似微控制器(MCU)了,儘管微控制器的暫存器沒有那麼的多,如果會裸機驅動,我想,應該能勝任微控制器的工作了,呵呵。

在這樣的系統中,雖然不存在作業系統,但是裝置驅動是必須存在的。一般情況下,對每一種裝置驅動都會定義為一個軟體模組,包含.h檔案和.c檔案,前者定義該裝置驅動的資料結構並宣告外部函式,後者進行裝置驅動的具體實現。書中例舉了一個串列埠驅動serial.c serial.h,主要是配置GPIO,串列埠控制暫存器,以及串列埠的收發(讀寫)暫存器,而這幾個配置都是自定義函式實現的,比如串列埠的寫(發)SerialSend 函式等。

其他模組需要使用這個裝置的時候,只需要包含裝置驅動的標頭檔案 serial.h,然後呼叫其中的外部介面函式即可。如我們要從串列埠上傳送字串“Hello World”,使用函式SerialSend( " Hello World ",11)即可。

由此可見,在沒有作業系統的情況下,裝置驅動的介面被直接提交給了應用軟體工程師, 應用軟體沒有跨越任何層次就直接訪問了裝置驅動的介面。 裝置驅動包含的介面函式也與硬體的功能直接吻合, 沒有任何附加功能。

有的工程師把單任務系統設計成裝置驅動和具體的應用軟體模組處於同一層次(即應用程式也在比如serial.c中實現),這顯然是不合理的,不符合軟體設計中高內聚低耦合的要求。

另一種不合理的設計是直接在應用中操作硬體的暫存器(單獨一個main.c,所有功能都在一個函式中實現,不採用其他任何介面/函式),而不單獨設計驅動模組,這種設計意味著系統中不存在或未能充分利用可被重用的驅動程式碼。

2)有作業系統時的裝置驅動

無作業系統時的裝置驅動中的裝置驅動直接執行在硬體之上,不與任何作業系統關聯。當系統中包含作業系統後,裝置驅動會變得怎樣?

首先,無作業系統時裝置驅動的硬體操作工作仍然是必不可少的, 沒有這一部分,裝置驅動不可能與硬體打交道。

其次,我們還需要將裝置驅動融入核心。為了實現這種融合,必須在所有的裝置驅動中設計面向作業系統核心的介面,這樣的介面由作業系統規定,對一類裝置而言結構一致,獨立於具體的裝置。

由此可見,當系統中存在作業系統的時候,裝置驅動變成了連線硬體和核心的橋樑。作業系統的存在勢必要求裝置驅動附加更多的程式碼和功能(以我看,主要是提供了很多結構),把單一的“驅使硬體裝置行動”變成了作業系統內與硬體互動的模組,它對外呈現為作業系統的API,不再給應用軟體工程師直接提供介面。有了作業系統之後,裝置驅動反而變得複雜,那要作業系統幹什麼?

首先,一個複雜的軟體系統需要處理多個併發的任務,沒有作業系統,想完成多工併發是很困難的。

其次,作業系統給我們提供記憶體管理機制。一個典型的例子是,對於多數含 MMU的處理器而言,Windows、Linux 等作業系統可以讓每個程序都獨立地訪問 4GB的記憶體空間。

上述優點似乎並沒有體現在裝置驅動身上,作業系統的存在給裝置驅動究竟帶來了什麼好處呢?

簡而言之,作業系統通過給裝置驅動製造麻煩來達到給上層應用提供便利的目的。如果裝置驅動都按照作業系統給出的獨立於裝置的介面而設計,應用程式將可使用統一的系統呼叫介面來訪問各種裝置。對於類UNIX的VxWorks、Linux等作業系統而言,應用程式通過write()、read()等函式讀寫檔案就可以訪問各種字元裝置和塊裝置,而不用管裝置的具體型別和工作方式,是非常方便的。

不管有無作業系統,不管是SerialSend,或者write,訪問裝置都需要對暫存器進行讀寫操作,比如串列埠,在dev目錄下有個ttys0結點,我們可以通過ioctl函式對其進行讀寫操作,當然,write、read更為直接咯。而上層的應用可以對這些函式進行封裝,定義不同的介面,從而實現更多的功能