Linux 裝置驅動框架

2021-07-09 08:04:41 字數 3181 閱讀 1328

1)驅動框架

linux將所有外部裝置看成是一類特殊檔案,稱之為「裝置檔案」,如果說系統呼叫是linux核心和應用程式之間的介面,那麼裝置驅動程式則可以看成是linux核心與外部裝置之間的介面。裝置驅動程式向應用程式遮蔽了硬體在實現上的細節,使得應用程式可以像操作普通檔案一樣來操作外部裝置。在應用程式看來,硬體裝置只是乙個裝置檔案,應用程式可以象操作普通檔案一樣對硬體裝置進行操作,如open ()、close ()、read ()、write () 等。

linux主要將裝置分為三類:字元裝置和塊裝置和網路裝置。字元裝置是指裝置傳送和接收資料以字元的形式進行,而且也不支援隨機訪問;而塊裝置則是利用一塊系統記憶體作為緩衝區,以整個資料緩衝區的形式進行,塊裝置主要是針對磁碟等慢速裝置設計的,其目的是避免耗費過多的cpu時間來等待操作的完成。

每個裝置檔案對應有兩個裝置號:乙個是主裝置號,標識該裝置的種類,也標識了該裝置所使用的驅動程式;另乙個是次裝置號,標識使用同一裝置驅動程式的不同硬體裝置。裝置檔案的主裝置號必須與裝置驅動程式在登入該裝置時申請的主裝置號一致,否則使用者程序將無法訪問到裝置驅動程式。

linux下的裝置驅動程式可以按照兩種方式進行編譯,一種是直接靜態編譯成核心的一部分,另一種則是編譯成可以動態載入的模組。如果編譯進核心的話,會增加核心的大小,還要改動核心的原始檔,而且不能動態地解除安裝,不利於除錯,所有推薦使用模組方式。從本質上來講,模組也是核心的一部分,它不同於普通的應用程式,不能呼叫位於使用者態下的c或者c++庫函式,而只能呼叫linux核心提供的函式,在/proc/allksyms中可以檢視到核心提供的所有函式。

裝置驅動程式結構

了解裝置驅動程式的基本結構(或者稱為框架),對開發人員而言是非常重要的,linux的裝置驅動程式大致可以分為如下幾個部分:驅動程式的註冊與登出、裝置的開啟與釋放、裝置的讀寫操作、裝置的控制操作、裝置的中斷和輪詢處理。

a,驅動程式的註冊與登出 

向系統增加乙個驅動程式意味著要賦予它乙個主裝置號,這可以通過在驅動程式的初始化過程中呼叫register_chrdev( )或者register_blkdev( )來完成。而在關閉字元裝置或者塊裝置時,則需要通過呼叫unregister_chrdev( )或unregister_blkdev( )從核心中登出裝置,同時釋放占用的主裝置號。

b,裝置的開啟與釋放 

開啟裝置是通過呼叫file_operations結構中的函式open( )來完成的,它是驅動程式用來為今後的操作完成初始化準備工作的。在大部分驅動程式中,open( )通常需要完成下列工作: 檢查裝置相關錯誤,如裝置尚未準備好等。如果是第一次開啟,則初始化硬體裝置。識別次裝置號,如果有必要則更新讀寫操作的當前位置指標f_ops。分配和填寫要放在file->private_data裡的資料結構。使用計數增1。 

釋放裝置是通過呼叫file_operations結構中的函式release( )來完成的,這個裝置方法有時也被稱為close( ),它的作用正好與open( )相反,通常要完成下列工作:使用計數減1。釋放在file->private_data中分配的記憶體。如果使用計算為0,則關閉裝置。 

c,裝置的讀寫操作 

字元裝置的讀寫操作相對比較簡單,直接使用函式read( )和write( )就可以了。但如果是塊裝置的話,則需要呼叫函式block_read( )和block_write( )來進行資料讀寫,這兩個函式將向裝置請求表中增加讀寫請求,以便linux核心可以對請求順序進行優化。由於是對記憶體緩衝區而不是直接對裝置進行操作的,因此能很大程度上加快讀寫速度。如果記憶體緩衝區中沒有所要讀入的資料,或者需要執行寫操作將資料寫入裝置,那麼就要執行真正的資料傳輸,這是通過呼叫資料結構blk_dev_struct中的函式request_fn( )來完成的。

d,裝置的控制操作 

除了讀寫操作外,應用程式有時還需要對裝置進行控制,這可以通過裝置驅動程式中的函式ioctl( )來完成。ioctl( )的用法與具體裝置密切關聯,因此需要根據裝置的實際情況進行具體分析。

e,裝置的中斷和輪詢處理

對於不支援中斷的硬體裝置,讀寫時需要輪流查詢裝置狀態,以便決定是否繼續進行資料傳輸。如果裝置支援中斷,則可以按中斷方式進行操作。

(2)字元裝置和雜項裝置

首先了解下雜項裝置(misc device),雜項裝置也是在嵌入式系統中用得比較多的一種裝置驅動。在linux 核心的include/linux目錄下有miscdevice.h檔案,要把自己定義的misc device從裝置定義在這裡。其實是因為這些字元裝置不符合預先確定的字元裝置範疇,所有這些裝置採用主編號10 ,一起歸於misc device,其實misc_register就是用主標號10呼叫register_chrdev()的(需要注意的是,當註冊的從裝置號是misc_dynamic_minor,要求的是系統自動分配從裝置號),對應的反註冊函式是misc_deregister。也就是說,misc裝置其實也就是特殊的字元裝置。 

再來看字元裝置,下面我們來假設乙個非常簡單的虛擬字元裝置:這個裝置的名字叫做"gobalvar"。驅動程式是核心的一部分,因此我們需要給其新增模組初始化函式,該函式用來完成對所控裝置的初始化工作,我們用module_init( global_var)申明,並呼叫register_chrdev() 函式註冊字元裝置(老式的字元裝置註冊方式):

static int __init gobalvar_init(void)

else

}其中,register_chrdev函式中的引數major_num為主裝置號,"gobalvar"為裝置名,gobalvar_fops為包含基本函式入口點的結構體,型別為file_operations。當gobalvar模組被載入時,gobalvar_init被執行,它將呼叫核心函式register_chrdev,把驅動程式的基本入口點指標存放在核心的字元裝置位址表中,在使用者程序對該裝置執行系統呼叫時提供入口位址。

與模組初始化函式對應的就是模組解除安裝函式,需要呼叫register_chrdev()的"反函式" unregister_chrdev():

static void __exit gobalvar_exit(void)

隨著核心不斷增加新的功能,file_operations結構體已逐漸變得越來越大,但是大多數的驅動程式只是利用了其中的一部分。對於字元裝置來說,要提供的主要入口有:open ()、release ()、read ()、write ()、ioctl ()、llseek()、poll()等。使用register_chrdev(led_major,device_name,&dev_fops)註冊字元裝置驅動程式時,如果有多個裝置使用該函式註冊驅動程式,led_major不能相同,否則幾個裝置都無法註冊。

linux 字元裝置驅動框架

linux 字元裝置驅動是3種型別中最簡單的一種,其實就是實現 file operations 中的函式,基本實現框架如下 1,需要包含的標頭檔案 include include include include include 2.定義及實現 file operations 中的函式,file op...

Linux雜項裝置驅動框架

首先是標頭檔案定義 include include include include 以下是一些file operations中提供的一些函式,這些函式用於給應用層提供介面,以此來調動裝置。static int filename open struct inode my indoe,struct fi...

Linux字元裝置驅動框架總結

對於linux而言,一切皆檔案,在linux系統下,所有檔案都可以像文字檔案一樣open read write,那麼對於linux裝置驅動而言,比如現在有乙個點燈的驅動程式,它的裝置節點是 dev 當應用程式執行open read write的時候,是如何呼叫到驅動程式裡的open read wri...