乙個字元裝置驅動會實現常規的開啟、關閉、讀、寫等功能,但是在一些細分的情景下,如果需要擴充套件新功能,通常以增設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 這兩個檔案...