linux驅動 ioctl函式解析

2021-10-08 16:35:14 字數 4492 閱讀 1446

乙個字元裝置驅動會實現常規的開啟、關閉、讀、寫等功能,但是在一些細分的情景下,如果需要擴充套件新功能,通常以增設ioctl()命令的方式實現,其作用類似於「拾遺補漏」。在檔案i/o中,ioctl扮演著重要角色,本文將以驅動開發為側重點,從使用者空間到核心空間縱向分析ioctl函式。

在man手冊中描述ioctl函式的作用是:操作特殊檔案的底層裝置引數。

long

(*unlocked_ioctl)

(struct file *

,unsigned

int,

unsigned

long);

long

(*compat_ioctl)

(struct file *

,unsigned

int,

unsigned

long

);

在驅動程式中,ioctl()函式上傳送的變數cmd是應用程式用於區別裝置驅動程式請求處理內容的值,cmd除了可區別數字外,還包含有助於處理的幾種相應資訊。cmd的大小為32位,共分為4個域

在asm-generic/ioctl.h裡有如下定義

#define _io(type,nr) _ioc(_ioc_none,(type),(nr),0)

再看__ioc()的定義:

#define _ioc(dir,type,nr,size) \

(((dir) << _ioc_dirshift) | \

((type) << _ioc_typeshift) | \

((nr) << _ioc_nrshift) | \

((size) << _ioc_sizeshift))

可見,__io()的最後結果由__ioc()中的4個引數移位組合而成。

#define _ioc_dirshift	(_ioc_sizeshift+_ioc_sizebits)

#define _ioc_sizeshift (_ioc_typeshift+_ioc_typebits)

#define _ioc_sizebits 14

#define _ioc_typeshift (_ioc_nrshift+_ioc_nrbits)

#define _ioc_typebits 8

#define _ioc_nrshift 0

#define _ioc_nrbits 8

所以可以得到

_ioc_dirshift = _ioc_sizeshift + 14 = (_ioc_typeshift+_ioc_typebits) + 14

= (_ioc_nrshift+_ioc_nrbits + 8) +14

= 0 + 8 + 8 +14

= 30

_ioc_typeshift = (_ioc_nrshift+_ioc_nrbits) = 0 + 8 = 8

_ioc_nrshift = 0

_ioc_sizeshift = (_ioc_typeshift+_ioc_typebits) = (_ioc_nrshift+_ioc_nrbits) + 8

= 0 + 8 + 8

= 16

所以,(dir) << _ioc_dirshift表示dir左移30位,得到bit31 ~ bit30兩位上,得到方向(讀寫)的屬性

(size) << _ioc_sizeshift) 位左移 16 位得到「資料大小」區;

(type) << _ioc_typeshift) 左移 8位得到"魔數區" ;

(nr) << _ioc_nrshift) 左移 0 位( bit7~bit0)

在asm-generic/ioctl.h中還有如下巨集定義

//構造無引數的命令編號

#define _io(type,nr) _ioc(_ioc_none,(type),(nr),0)

//構造從驅動程式中讀取資料命令編號

#define _ior(type,nr,size) _ioc(_ioc_read,(type),(nr),(_ioc_typecheck(size)))

//構造從驅動程式中寫入資料

#define _iow(type,nr,size) _ioc(_ioc_write,(type),(nr),(_ioc_typecheck(size)))

//用於雙向傳輸

#define _iowr(type,nr,size) _ioc(_ioc_read|_ioc_write,(type),(nr),(_ioc_typecheck(size)))

dir(direction),ioctl命令訪問模式(資料傳輸方向),佔據2bit,可以為_ioc_none、_ioc_read、_ioc_write _ioc_read | _ioc_write,分別指示了四種訪問模式:無資料、讀資料、寫資料、讀寫資料

type(device type),裝置型別,佔據8bit,在一些文獻中翻譯為「幻數」或者「魔數」,可以為任意char型字元,例如『a』、『b』、『c』等等,其主要作用是使ioctl命令有唯一的裝置標識;

tips:documentions/ioctl-number.txt記錄了在核心中已經使用的「魔數」字元,為避免衝突,在自定義ioctl命令之前應該先查閱該文件

nr(number),命令編號/序數,佔據8bit,可以為任意unsigned char型資料,取值範圍0~255,如果定義了多個ioctl命令,通常從0開始編號遞增;

size,涉及到ioctl第三個引數arg,佔據13bit或者14bit(體系相關,arm架構一般為14位),指定了arg的資料型別及長度,如果在驅動的ioctl實現中不檢查,通常可以忽略該引數。

核心空間

#define close_cmd       (_io(0xef,0x1))     

/*關閉定時器*/

#define open_cmd (_io(0xef,0x2))

/*開啟定時器*/

#define setperiod_cmd (_io(0xef,0x3))

/*設定定時器週期命令*/..

....

static

long

timer_unlocked_ioctl

(struct file *filp,

unsigned

int cmd,

unsigned

long arg)

return0;

}//裝置操作函式

static

struct file_operations timer_fops =

;

使用者空間

#include

"stdio.h"

#include

"unistd.h"

#include

"sys/types.h"

#include

"sys/stat.h"

#include

"fcntl.h"

#include

"stdlib.h"

#include

"string.h"

#include

"linux/ioctl.h"

/* 命令值 */

#define close_cmd (_io(0xef, 0x1))

/* 關閉定時器 */

#define open_cmd (_io(0xef, 0x2))

/* 開啟定時器 */

#define setperiod_cmd (_io(0xef, 0x3))

/* 設定定時器週期命令 */

intmain

(int argc,

char

*ar**)

filename = ar**[1]

; fd =

open

(filename,o_rdwr);if

(fd <0)

while(1

)if(cmd ==1)

/* 關閉 led 燈 */

cmd = close_cmd;

else

if(cmd ==2)

/* 開啟 led 燈 */

cmd = open_cmd;

else

if(cmd ==3)

}ioctl

(fd, cmd, arg)

;/* 控制定時器的開啟和關閉 */

}close

(fd)

;}

linux驅動中的ioctl函式

我這裡說的ioctl函式是在驅動程式裡的,因為我不知道還有沒有別的場合用到了ioctl,所以就規定了我們討論的範圍。為什麼要寫篇文章呢,是因為我前一陣子被ioctl給搞混 了,這幾天才弄明白它,於是在這裡清理一下頭腦。一 什麼是ioctl。ioctl是裝置驅動程式中對裝置的i o通道進行管理的函式。...

linux驅動 ioctl介面

核心中對底層裝置操作完全可以通過read write介面來實現,在linux 2.2之前都是沒有ioctl介面的,2.4以後才引入ioctl介面。典故 據說 以前在操作軟盤時,需要彈出光碟時命令為eject,可以通過write寫這個字串來傳輸這個指令,但是此時,如果要往軟盤中寫入 eject 字串時...

linux如何通過ioctl呼叫驅動的

ioctl作用 應用層的ioctl函式傳入的cmd和arg引數會直接傳入驅動層的ioctl介面,在對應驅動檔案裡會對相應的命令進行操作 對於傳遞的ioctl命令有一定的規範,具體可以參考 include asm ioctl.h,documentation ioctl number.txt 這兩個檔案...