【Linux Device Driver】—(3.1)—ioctl——原理
阿新 • • 發佈:2019-02-12
大部分驅動除了需要具備讀寫裝置能力外,還需要具備對硬體控制的能力,例如:要求裝置報告錯誤資訊改變模特率,這些操作常常通過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。