1. 程式人生 > >【Linux Device Driver】—(3.1)—ioctl——原理

【Linux Device Driver】—(3.1)—ioctl——原理

大部分驅動除了需要具備讀寫裝置能力外,還需要具備對硬體控制的能力,例如:要求裝置報告錯誤資訊改變模特率,這些操作常常通過ioctl方法來實現!

這裡的東西看上去的卻挺多,但是還是依照此次的原則,只是對自己知識的一個複習,所以也就懶得貼那麼多的文字。

1、ioctl方法

使用者空間:

int ioctl(int fd, unsigned long cmd, ...);

原型中的省略號表示這是一個可選的引數,存在與否依賴於控制命令(第2個引數)是否涉及到與裝置的資料互動。

核心:

#include <linus/fs.h>

// 不使用BLK(大核心鎖),降使用此種函式指標代替ioctl
long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);

// 相容64位系統,將使用此函式指標代替
long (*compat_ioctl) (struct file *, unsigned int, unsigned long);

這裡如果cmd命令不涉及資料傳輸,被驅動操作接收到的arg值是無定義的。

2、ioctl函式定義命令

ioctl命令編碼被劃分為幾個段,include/asm/ioctl.h中定義了這些欄位:型別(幻數),基數,傳送方向,引數大小等。Documentation/ioctl-number.txt檔案中羅列了再核心中已經使用的幻數。

#include <linus/ioctl.h>

/* used to create numbers */
#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)))

/* used to decode ioctl numbers.. */
#define _IOC_DIR(nr)		(((nr) >> _IOC_DIRSHIFT) & _IOC_DIRMASK)
#define _IOC_TYPE(nr)		(((nr) >> _IOC_TYPESHIFT) & _IOC_TYPEMASK)
#define _IOC_NR(nr)		(((nr) >> _IOC_NRSHIFT) & _IOC_NRMASK)
#define _IOC_SIZE(nr)		(((nr) >> _IOC_SIZESHIFT) & _IOC_SIZEMASK)


2、ioctl函式定義命令3、ioctl函式的實現

(3.1)返回值

ioctl函式的實現通常是根據命令執行的一個switch語句。但是當命令不能匹配任何一個裝置所支援的命令時,通常返回-EINVAL(“非法引數”)。

(3.2)引數使用

如果是一個整數,可以直接使用。如果是指標,我們必須確保這個使用者地址是有效的,因此使用前必須要做正確性檢查(當然也有不需要檢測的,就是前面沒有“__”的核心空間和使用者空間互動函式)。

int access_ok(int type, const void *addr, unsigned long size)

其中第一個引數是VERIFY_READ或者是VERIFY_WRITE,用來表明讀使用者記憶體還是寫使用者記憶體(千萬記住和讀寫函式對調的!),addr引數是要操作的使用者記憶體地址,size是操作的長度。

access_ok返回一個布林值:1表示成功和0表示失敗(儲存有問題),如果該函式返回失敗,則ioctl應當返回-EFAULT。