ioctl命令詳解 相關(guān)資料請(qǐng)參照:ioctl-number.txt、linux/ioctl.h 功能: 大部分驅(qū)動(dòng)除了需要具備讀寫設(shè)備的能力外,還需要具備對(duì)硬件控制的能力。例如,要求設(shè)備報(bào)告錯(cuò)誤信息,改變波特率,這些操作常常通過ioctl方法來實(shí)現(xiàn)。 用戶使用方法: 在用戶空間,使用ioctl系統(tǒng)調(diào)用來控制設(shè)備,原型如下: int ioctl(int fd,unsigned long cmd,...); 原型中的點(diǎn)表示這是一個(gè)可選的參數(shù),存在與否依賴于控制命令(第二個(gè)參數(shù))是否涉及到與設(shè)備的數(shù)據(jù)交互。 驅(qū)動(dòng)ioctl方法: ioctl驅(qū)動(dòng)方法有和用戶空間版本不同的原型: int (*ioctl)(struct inode *inode,struct file *filp,unsigned int cmd,unsigned long arg) cmd參數(shù)從用戶空間傳下來,可選的參數(shù) arg以一個(gè)unsigned long 的形式傳遞,不管它是一個(gè)整數(shù)或一個(gè)指針。如果cmd命令不涉及數(shù)據(jù)傳輸,則第3個(gè)參數(shù)arg的值無任何意義。從linux-2.6.36把,已經(jīng)由unlocked_ioctl替代原來的ioctl。其中驅(qū)動(dòng)的變化就是函數(shù)參數(shù)去掉inode參數(shù),其它應(yīng)該沒有變化。int ioctl(int fd,unsigned long cmd,...)。 ioctl實(shí)現(xiàn) 如何實(shí)現(xiàn)ioctl方法? 1.定義命令 2.實(shí)現(xiàn)命令 定義命令 在編寫ioctl代碼之前,首先需要定義命令。為了防止對(duì)錯(cuò)誤的設(shè)備使用正確的命令,命令號(hào)應(yīng)該在系統(tǒng)范圍內(nèi)是唯一的中定義。ioctl命令編碼被劃分為幾個(gè)位段,include/asm/ioctl.h定義了這些位字段:類型(幻數(shù)),序號(hào),傳送方向,參數(shù)的大小。 Documentation/ioctl-number.txt文件中羅列了在內(nèi)核中已經(jīng)使用了的幻數(shù)。 定義命令 定義ioctl命令的正確方法是使用4 個(gè)位段,這個(gè)列表中介紹的符號(hào)定義在<linux/ioctl.h>中: Type 幻數(shù)(類型):表明哪個(gè)設(shè)備的命令,在參考了ioctl-number.txt之后選出,8位寬。 Number 序號(hào),表明設(shè)備命令中的第幾個(gè),8位寬。 Direction 數(shù)據(jù)傳送的方向,可能的值是 _IOC_NONE(沒有數(shù)據(jù)傳輸) _IOC_READ _IOC_WRITE 數(shù)據(jù)傳送是從應(yīng)用程序的觀點(diǎn)來看待的,_IOC_READ意思是從設(shè)備讀。 size 用戶數(shù)據(jù)的大小。(13/14位寬,視處理器而定) 內(nèi)核提供了下列宏來幫助定義命令: _IO(type,nr); 沒有 參數(shù)的命令 _IOR(type,nr,datatype) 從驅(qū)動(dòng)中讀取數(shù)據(jù) _IOW(type,nr,datatype) 寫數(shù)據(jù)到驅(qū)動(dòng) _IOWR(type,nr,datatype) 雙向傳送,type和number成員作為參數(shù)被傳遞。 列子(example) #define MEM_IOC_MAGIC 'm' //定義幻數(shù) #define MEM_IOCSET _IOW(MEM_IOC_MAGIC,0,int) #define MEM_IOCGQSET _IOR(MEM_IOC_MAGIC,1,int) ioctl函數(shù)實(shí)現(xiàn) 定義好了命令,下一步就是要實(shí)現(xiàn)ioctl函數(shù)了,ioctl函數(shù)的實(shí)現(xiàn)包括如下3個(gè)技術(shù)環(huán)節(jié): 1.返回值 2. 參數(shù)使用 3.命令操作 ioctl函數(shù)實(shí)現(xiàn)(返回值) ioctl函數(shù)的實(shí)現(xiàn)通常是根據(jù)命令執(zhí)行的一個(gè) switch語(yǔ)句。但是,當(dāng)命令號(hào)不能匹配任何一個(gè)設(shè)備所支持的命令時(shí), 通常返回-EINVAL("非法參數(shù)") ioctl函數(shù)實(shí)現(xiàn)(參數(shù)) 如何使用ioctl中的參數(shù)? 如果是一個(gè)整數(shù),可以直接使用。如果是指針,我們必須確保這個(gè)用戶地址是有效的,因此使用前需進(jìn)行正確的檢查。 ioctl函數(shù)實(shí)現(xiàn)(參數(shù)檢查) 不需要檢測(cè): copy_from_user copy_to_user get_user put_user 需要檢測(cè): __get_user __put_user 參數(shù)檢查函數(shù): int access_ok(int type,const void *addr,unsigned long size); type:VERIFY_READ或者VERIFY_WRITE,用來表明是讀用戶內(nèi)存還是寫用戶內(nèi)存。 addr:要操作的用戶內(nèi)存地址 size:操作的長(zhǎng)度,如果ioctl需要從用戶空間讀一個(gè)整數(shù),那么size參數(shù)等于sizeof(int)。 access_ok返回一個(gè)布爾值:1是成功(存取沒問題)和0是失敗(存取有問題),如果該函數(shù)返回失敗,則ioctl應(yīng)當(dāng)返回-EFAULT。 ioctl 函數(shù)實(shí)現(xiàn)(參數(shù)檢查) if(_IOC_DIR(cmd) & _IOC_READ) err = !access_ok(VERIFY_WRITE,(void __user *)arg,_IOC_SIZE(cmd)); //為什么_IOC_READ對(duì)應(yīng)VERIFY_WRITE?? else if(_IOC_DIR(cmd) & _IOC_WRITE) err = !access_ok(VERIFY_READ,(void _user)*arg,_IOC_SEIZE(cmd)); if(err) return -EFAULT; ioctl函數(shù)實(shí)現(xiàn)(命令操作) switch(cmd) { case MEM_IOCSQUANTUM: retval = _get_user(scull_quantum,(int *)arg); break; case MEM_IOCGQUANTUM: retval = _put_user(scull_quantum,(int *)arg); break; default: return -EINVAL; } |
|