摘要
:
編寫裝置驅動是乙個具有挑戰性和冒險性的工作。當裝置通過init_mo
dule函式登記時,裝置的資源應當被分 配。乙個主要的裝置資源是i/o埠。作為動態連線的驅動程式,開發者應當小心將未被使用的i/o埠分配 給這些裝置。 首先驅動程式應偵測這些埠是否被使用或釋放。然後再為裝置申請獲取埠。當驅動模組被 從核心中移出時,埠應該被釋放。這篇文章討論了linux裝置驅動的安全埠分配的複雜性。 介紹
裝置驅動開發者乙個主要關心的問題是裝置的資源分配。這些資源包括i/o埠,記憶體和中斷。這篇文章試**釋i/o子系統的基本原理和資源分配的重要性,主要是i/o埠的資源處理。同時還將闡明如何偵測,申請和釋放裝置的埠位址。
基本的硬體元素,如埠,匯流排和裝置控制器,構成了大量的不同的i/o裝置。裝置驅動向i/o子系統提供了 乙個通用的裝置訪問介面,這非常類似於系統呼叫(systmem call)在應用程式和作業系統之間提供的標準界 面。現在有很多種型別的裝置附屬在電腦上,舉例說來有: 儲存裝置,如磁碟,磁帶,光碟機和軟碟機; 人機交 互裝置,如鍵盤,滑鼠和螢幕; 傳輸裝置,如網絡卡和數據機。不論這些不同裝置的數目巨大,我們只需要理解一些基本的概念,即裝置如何載入以及軟體如何控制硬體。
基本概念
裝置由兩部分組成,乙個是被稱裝置為控制器的電器部分,另乙個是機械部分。控制器通過系統匯流排載入到 電腦上。典型的方式是,一組互不衝突的暫存器組被賦予到各個控制器。i/o埠包含4組暫存器,即狀態寄 存器,控制暫存器,資料輸入暫存器,資料輸出暫存器。狀態暫存器擁有可以被主機讀取的(狀態)位,用來 指示當前命令是否執行完畢,或者位元組是否可以被讀出或寫入,以及任何錯誤提示。控制暫存器則被主機寫操作以啟動一條命令或者改變裝置的(工作)模式。資料輸入暫存器用於獲取輸入而資料輸出暫存器則向主機傳送結果。
所以,處理器和裝置之間的基本介面是控制和狀態暫存器。當處理器執行程式並且遇到與裝置相關的指令 時,它通過向相應的裝置傳送一條命令來執行該指令。控制器執行所要求的動作並設定狀態暫存器的特定位,然後進入等待。處理器有責任檢查裝置的狀態直到發現操作完成。例如並口驅動程式(印表機使用的)一般會 輪詢印表機以知道印表機是否準備好。如果印表機沒有準備好,驅動程式會睡眠一段時間(處理器此時會做其他有用的工作),該過程將重複直到印表機準備好。這種輪詢的機制能夠改進系統的效能。另外一種方式則是 系統進行不必要的"死等"(unnecessarily waiting)而不做任何有用的工作。
暫存器擁有在i/o空間明確定義的位址範圍。通常這些位址在啟動時被分配,使用一組在配置檔案中定義的引數。各個裝置的位址範圍可能被預分配,如果裝置是靜態載入的。這意味核心包含了已存在裝置的驅動 程式,以分配的i/o埠能被存放在proc目錄下。你可以在系統使用這些裝置時,通過執行「cat /proc/ioports」 命令同步的檢查其所使用的位址範圍。第一列輸出顯示了埠的範圍而第二列則是擁用這些埠的裝置。一 些作業系統具備在執行時動態載入裝置驅動模組的特性。所以任何新的裝置都能通過動態載入模組在系統執行時載入到系統中,並且能夠被控制和訪問。
裝置驅動的概念是非常抽象的並且處於一台計算上所執行軟體的最低層。由於直接到裝置的硬體特性的限 制。每個裝置驅動都只管理一種單一型別的裝置。這些型別可能是字元型,快裝置型或網路型。如果乙個應用程式向裝置提出(操作)要求。核心會聯絡到對應的裝置驅動,裝置驅動接著向特定的裝置發出命令。裝置驅 動是乙個函式集合:包含了許多呼叫入口,類似於open,close,read,write,ioctl,llseek 等。當你插入你的模組時,init_module ( ) 函式會被呼叫,而模組被移出時,cleanup_module ( ) 函式會被呼叫。裝置是在 裝置驅動的init_module ( ) 例程中被登記的。
當裝置在 init_module ( ) 中登記時,裝置的資源如i/o埠,記憶體和中斷號也在這個函式被分配,這也 是驅動程式能夠正確操作裝置的需要。如果你分配了任何錯誤的記憶體位址,系統會顯示錯誤資訊segmentation fault。 而對於i/o埠,系統不會給出任何類似wrong i/o port的資訊,但是指派任何現有裝置已使用的端 口將會造成系統崩潰。當你移出模組時,裝置應當被登出,更確切的說,主(裝置)號和資源將在cleanup_module ( ) 函 數中被釋放
裝置驅動最頻繁的工作時讀寫io埠。所以你的驅動應當是確信完美的,被裝置使用的埠位址是獨佔的。任何其他裝置都不會使用這段位址範圍。為了確認這點,首先驅動應當查明這段位址是否在使用,當驅動發現 這段位址未被使用時,可以申請核心為裝置分配這段位址。
安全埠分配
現在我們來看看如何通過系統函式來完成資源分配和資源釋放。下面的例項 是在linux 2。4核心上進行實驗的,以下的所有實現僅適用於linux作業系統和某些擴充套件的unix變種。
首先偵測可用的埠(位址)範圍,通過下面的函式
int check_region (unsigned long start
, unsigned long len);
函式返回0表示埠位址可用,返回小於零或負的錯誤編碼( -ebusy or -einval) 表示已在使用中。函式接受2個引數: start 是 連續區域(或i/o埠範圍)的起始值,而len是區域內的埠數目。
當埠可用時,應該將它分配給裝置,通過request_region 函式。
struct resource *request_region (unsigned long start
, unsigned long len, char *name);
頭兩個引數和我們前面看到的一樣,字元指標變數name是要分配埠位址的裝置名稱。函式返回指向resource結構的指標。resource結構用來描述資源的範圍,定義於。結構的格式定義如下
struct resource ;
當模組從核心移出時,埠應當被釋放以便為其它裝置使用,為此我們在 cleanup_module ( )中 使用release_region ( ) 函式。 函式的語法如下
void release_region ( unsigned long start
, unsigned long len);
兩個引數的解釋和前面一致。 以上的3個函式實際上是巨集定義,定義於。
裝置埠分配的驅動**例子
下面的程式說明了動態載入裝置的埠分配與**
#include 。h。>
#include 。h。>
struct file_operations fops;
unsigned long start
, len;
int init_module (void)
else
return 0;
}
void cleanup_module (void)
printk (" your device is unregistered/n");
}
為了避免混淆,例子**中去掉了錯誤檢查和和主(裝置)號的動態分配。 當埠分配成功時,我們可以在proc目錄中檢查:
$cat /proc/ioports
驅動程式的核心i/o埠函式選擇
linux
支援不同位寬的埠函式,用於i/o埠的讀寫。埠可以是8位,16位或32位。linux的內 核標頭檔案定義了訪問i/o埠的內聯(inline)函式,用於讀取(inx)或寫入(outx) 8位,16位以及32位埠。這些函式是
__u8 inb (unsigned int port);
void outb (__u8 data
, unsigned int port);
__u16 inw (unsigned int port);
void outw(__u16 data, unsigned int port);
__u32 inl (unsigned int prot);
void outl (__u32 data, unsigned int port);
這些函式的串版本(string versions)能讓你在單位時間內更有效的傳輸乙個以上的資料,通過以下函式
void insb(unsigned int port
, void *addr, unsigned long count);
void outsb(unsigned int port, void *addr, unsigned long count);
addr
是被傳入或傳出的記憶體單元位址,count是被傳輸單元的數量。 data 則是被讀取或 寫入到"port"埠的資料。
void insw(unsigned int port
, void *addr, unsigned long count);
void outsw(unsigned int port, void *addr, unsigned long count);
向16位埠讀寫16位資料
void insl(unsigned int port
, void *addr, unsigned long count);
void outsl(unsigned int port, void *addr, unsigned long count);
向32位埠讀寫32位資料
驅動 linux裝置驅動 字元裝置驅動開發
preface 前面對linux裝置驅動的相應知識點進行了總結,現在進入實踐階段!linux 裝置驅動入門篇 linux 裝置驅動掃盲篇 fedora下的字元裝置驅動開發 開發乙個基本的字元裝置驅動 在linux核心驅動中,字元裝置是最基本的裝置驅動。字元裝置包括了裝置最基本的操作,如開啟裝置 關閉...
Linux裝置驅動
一.簡介 作業系統是通過各種驅動程式來駕馭硬體裝置,它為使用者遮蔽了各種各樣的裝置,驅動硬體是作業系統最基本的功能,並且提供統一的操作方式。正如我們檢視螢幕上的文件時,不用去管到底使用nvidia晶元,還是ati晶元的顯示卡,只需知道輸入命令後,需要的文字就顯示在螢幕上。硬體驅動程式是作業系統最基本...
linux裝置驅動
1 flash的程式設計原理都是只能將1寫為0,而不能將0寫為1。所以在flash程式設計之前,必須將對應的塊擦除,而擦除的過程就是把所有位都寫為1的過程,塊內的所有位元組變為0xff。2 nand flash與nor flash相比容量大 低 nand flash中每個塊的最大擦寫次數是100萬次...