ioctl函式實用性總結(適用初學者)

2021-09-26 04:59:30 字數 3767 閱讀 8319

ioctl函式實用性總結(適用初學者)。

1 ioctl為什麼會出現

(1)雖然在檔案操作結構體"struct file_operations"中有很多對應的裝置操作函式,但是有些命令是實在找不到對應的操作函式。如cd-rom的驅動,想要乙個彈出光碟機的操作,這種操作並不是所有的字元裝置都需要的,所以檔案操作結構體也不會有對應的函式操作。

(2)大部分驅動除了需要具備讀寫裝置的能力之外,還需要具備對硬體控制的能力,使用者程式所作的只是通過命令碼告訴驅動程式它想做什麼,至於怎麼解釋這些命令和怎麼實現這些命令,這都是驅動程式要做的事情。

(3)編寫應用的程式猿要做的事只需要通過驅動開發者在驅動相關的.**件中提供的命令碼,命令碼用文字進行了說明,因為有些驅動是加密的,裡面包含了ioctl的操作,不會給你看原始碼,但是會提供**件裡面包含了該驅動所有命令碼的解釋與操作結果說明,這樣一來你只要理解命令碼即可,應用程式設計師可快速開發上手。

總結:出於這樣的原因,ioctl就有它的用處了————一些沒辦法歸類的函式就統一放在ioctl這個函式操作中,通過指定的命令來實現對應的操作。所以,ioctl函式裡面都實現了多個的對硬體的操作步驟,將他們綜合起來完成乙個任務,而不是單一的某個write/read操作,通過應用層傳入的命令來呼叫相應的操作。

2 ioctl函式原型

2.1在應用程式中,使用ioctl系統呼叫來控制裝置,原型如下

intioctl(intfd,unsignedlongcmd,...);

fd:檔案描述符

cmd:控制命令

...:可選引數:插入*argp,具體內容依賴於cmd

2.2在驅動程式中,使用ioctl用來操作硬體,原型如下

int(*ioctl)(structinode*inode,structfile*filp,unsignedintcmd,unsignedlongarg);

inode與filp兩個指標對應於應用程式傳遞的檔案描述符fd,這和傳遞open方法的引數一樣。

cmd由使用者空間直接不經修改的傳遞給驅動程式

arg可選。

總結:當我們把驅動載入到核心的時候,驅動會呼叫核心的註冊函式,將驅動的file_operations註冊,這個時候,我們通過應用層開啟該驅動的裝置檔案fd,呼叫ioctl時,會自動掛接到指定驅動中的ioctl函式,完成指定的硬體操作。

3 ioctl函式幾個重要引數

3.1 cmd為什麼會變得如此複雜

(1)所謂的複雜命令無非也是乙個32bit的整數,比如用乙個最簡單的方式定義乙個命令也是可以的

#define test_clear 155

如上但核心開發人員發現這樣有點不對勁。如果有兩個不同的裝置,但它們的ioctl的cmd卻一樣的

#define test_open 155

當程式**量,功能,模組太大時,哪天應用開發者沒有注意,在操作某乙個功能時,本來要開啟a裝置,操作a硬體,不小心寫錯了**開啟了b裝置,並且呼叫ioctl,這樣就完蛋了。因為這個檔案裡面同樣有cmd對應實現,你就無故的影響了b驅動的正常使用,為了防止這樣的事情發生,核心對cmd又有了新的定義,規定了cmd都應該不一樣。

使用複雜cmd後**:

#define test_magic 'x' //定義幻數

#define test_max_nr 3 //定義命令的最大序數

#define test_clear _io(test_magic, 1)

#define test_offset _io(test_magic, 2)

#define test_kbuf _io(test_magic, 3)

3.2 cmd的組成

前言:在驅動程式中實現的ioctl函式體內,實際上是有乙個switch 結構,每乙個case對應乙個命令碼,做出一些相應的操作。怎麼實現這些操作,這是每乙個程式設計師自己的事情,因為裝置都是特定的。關鍵在於怎麼樣組織命令碼,因為在ioctl中命令碼是唯一聯絡使用者程式命令和驅動程式支援的途徑。

在linux核心中是這樣定義乙個命令碼的:

| 裝置型別 | 序 列 號 | 方 向 | 資料 尺寸 |

| 8 bit | 8 bit |2 bit | 8~14 bit |

1)幻數:說得再好聽的名字也只不過是個0~0xff的數,佔8bit(_ioc_typebits)。這個數是用來區分不同的驅動的,像裝置號申請的時候一樣,核心有乙個文件給出一些推薦的或者已經被使用的幻數。

2)序數:用這個數來給自己的命令編號,佔8bit(_ioc_nrbits),我的程式從1開始排序。

3)資料傳輸方向:佔2bit(_ioc_dirbits)。如果涉及到要傳參,核心要求描述一下傳輸的方向,傳輸的方向是以應用層的角度來描述的。

總結:這樣一來,乙個命令就變成了乙個整數形式的命令碼。但是命令碼非常的不直觀,所以kernel中提供了一些巨集,這些巨集可根據便於理解的字串生成命令碼,或者是從命令碼得到一些使用者可以理解的字串以標明這個命令對應的裝置型別、裝置序列號、資料傳送方向和資料傳輸尺寸。

如下://nr為序號,命令最大個數,datatype為資料型別,如int

_io(type,nr)//沒有引數的命令

_ior(type,nr,datatype)//從驅動中讀資料

_iow(type,nr,datatype)//寫資料到驅動

_iowr(type,nr,datatype)//雙向傳送

定義命令例子:

#definemem_ioc_magic'm'//定義型別

#definemem_iocset_iow(mem_ioc_magic,0,int)

#definemem_iocgqset_ior(mem_ioc_magic,1,int)

cmd最後達到的目的:既然這麼費勁定義了命令,當然要檢驗命令是否有效,所有我們在驅動中就可以新增驗證**,判斷命令是否為該驅動的命令

if(_ioc_type(cmd) != test_magic) return - einval;

if(_ioc_nr(cmd) > test_max_nr) return - einval;

3.3 ioctl中的arg之傳參

前言: 應用層的ioctl的第三個引數是"...",這個跟printf的"..."可不一樣,printf中是意味這你可以傳任意個數的引數,而ioctl最多也只能傳乙個,"..."的意思是讓核心不要檢查這個引數的型別。也就是說,從使用者層可以傳入任何引數,只要你傳入的個數是1.

一般會有兩種的傳參方法:

3.3.1 整數,那可是省力又省心,直接使用就可以了。

如下**:作為運算引數

應用層 ioctl(fd, test_offset, 10);

驅動層switch(cmd){

case test_offset:

filp->f_pos += (int)arg;

3.3.2指標,通過指標的就傳什麼型別都可以了,當然用起來就比較煩。

(1)考慮到引數不可能永遠只是乙個正數這麼簡單,如果要傳多一點的東西,譬如是結構體,那就得用上指標了。

(2)一講到從應用程式傳來的指標,就得想起我**的傳入了非法指標的例子。所以,驅動程式中任何與應用層打交道的指標,都得先檢驗指標的安全性。

**如下:因為指標是從使用者程式傳來,所以必須檢查安全性

驅動** if(copy_from_user(&val, (struct ioctl_data *)arg, sizeof(struct ioctl_data))){

ret = - efault;

goto ret;

應用** struct ioctl_data my_data= {

.size = 10,

.buf = "123456789"

ioctl(fd, test_kbuf, &my_data);

ioctl函式實用性總結(適用初學者)

1 雖然在檔案操作結構體 struct file operations 中有很多對應的裝置操作函式,但是有些命令是實在找不到對應的操作函式。如cd rom的驅動,想要乙個彈出光碟機的操作,這種操作並不是所有的字元裝置都需要的,所以檔案操作結構體也不會有對應的函式操作。2 大部分驅動除了需要具備讀寫裝...

python實用性 6個實用性強的python庫

在程式設計時,小挫折可能與大難題一樣令人痛苦。沒人希望在費勁心思之後,只是做到彈出訊息視窗或是快速寫入資料庫。因此,程式設計師都會喜歡那些能夠快速處理這些問題,同時長遠來看也很健壯的解決方案。1.pyglet 是什麼 pyglet是乙個純python語言編寫的跨平台框架,用於開發多 和視窗特效應用,...

什麼是實用性測試?

什麼是實用性測試?陳能技 2007 9 4 實用性測試,也叫實用主義測試,強調運用實用的測試方法和技術,快速高效地幫助測試人員完成測試工作,從而保證軟體質量。有鑑於各種各樣的測試理論和測試工具 測試方法都過於理論化,有些甚至已經不適合現在的軟體專案過程。為此提出實用性測試概念,倡導實用的測試技術和方...