一、魔數(shù)使用意義 在驅(qū)動(dòng)程序里, ioctl() 函數(shù)上傳送的變量 cmd 是應(yīng)用程序用于區(qū)別設(shè)備驅(qū)動(dòng)程序請(qǐng)求處理內(nèi)容的值。cmd除了可區(qū)別數(shù)字外,還包含有助于處理的幾種相應(yīng)信息。 cmd的大小為 32位,共分 4 個(gè)域:bit31~bit30 2位為 “區(qū)別讀寫” 區(qū),作用是區(qū)分是讀取命令還是寫入命令。bit29~bit16 14位為 "數(shù)據(jù)大小" 區(qū),表示 ioctl() 中的 arg 變量傳送的內(nèi)存大小。bit15~bit08 8位為 “魔數(shù)"(也稱為"幻數(shù)")區(qū),這個(gè)值用以與其它設(shè)備驅(qū)動(dòng)程序的 ioctl 命令進(jìn)行區(qū)別。bit07~bit00 8位為 "基數(shù)"("命令序號(hào)")區(qū),是區(qū)分命令的命令順序序號(hào)。 二、linux內(nèi)核驅(qū)動(dòng)中_IO,_IOR,_IOW,_IOWR宏的用法與解析 在驅(qū)動(dòng)程序里, ioctl() 函數(shù)上傳送的變量 cmd 是應(yīng)用程序用于區(qū)別設(shè)備驅(qū)動(dòng)程序請(qǐng)求處理內(nèi)容的值。cmd除了可區(qū)別數(shù)字外,還包含有助于處理的幾種相應(yīng)信息。 cmd的大小為 32位,共分 4 個(gè)域: bit31~bit30 2位為 “區(qū)別讀寫” 區(qū),作用是區(qū)分是讀取命令還是寫入命令。 bit29~bit15 14位為 "數(shù)據(jù)大小" 區(qū),表示 ioctl() 中的 arg 變量傳送的內(nèi)存大小。 bit20~bit08 8位為 “魔數(shù)"(也稱為"幻數(shù)")區(qū),這個(gè)值用以與其它設(shè)備驅(qū)動(dòng)程序的 ioctl 命令進(jìn)行區(qū)別。 bit07~bit00 8位為 "區(qū)別序號(hào)" 區(qū),是區(qū)分命令的命令順序序號(hào)。 像 命令碼中的 “區(qū)分讀寫區(qū)” 里的值可能是 _IOC_NONE (0值)表示無數(shù)據(jù)傳輸,_IOC_READ (讀), _IOC_WRI TE (寫) , _IOC_READ|_IOC_WRITE (雙向)。 內(nèi)核定義了 _IO() , _IOR() , IOW() 和 _IOWR() 這 4 個(gè)宏來輔助生成上面的 cmd 。下面分析 _IO() 的實(shí)現(xiàn),其它的類似: 在 asm-generic/ioctl.h 里可以看到 _IO() 的定義: #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() 的最后結(jié)果由 _IOC() 中的 4 個(gè)參數(shù)移位組合而成。 再看 _IOC_DI RS HIT 的定義: #define _IOC_DIRSHIFT (_IOC_SIZESHIFT+_IOC_SIZEBITS) _IOC_SIZESHIFT 的定義: #define _IOC_SIZESHIFT (_IOC_TYPESHIFT+_IOC_TYPEBITS) _IOC_TYPESHIF 的定義: #define _IOC_TYPESHIFT (_IOC_NRSHIFT+_IOC_NRBITS) _IOC_NRSHIFT 的定義: #define _IOC_NRSHIFT 0 _IOC_NRBITS 的定義: #define _IOC_NRBITS 8 _IOC_TYPEBITS 的定義: #define _IOC_TYPEBITS 8 由上面的定義,往上推得到: 引 用 _IOC_TYPESHIFT = 8 _IOC_SIZESHIFT = 16 _IOC_DIRSHIFT = 30 所以,(dir) << _IOC_DIRSHIFT) 表是 dir 往左移 30 位,即移到 bit31~bit30 兩位上,得到方向(讀寫)的屬性; (size) << _IOC_SIZESHIFT) 位左移 16 位得到“數(shù)據(jù)大小”區(qū); (type) << _IOC_TYPESHIFT) 左 移 8位得到"魔數(shù)區(qū)" ; (nr) << _IOC_NRSHIFT) 左移 0 位( bit7~bit0) 。 這樣,就得到了 _IO() 的宏值。 這幾個(gè)宏的使用格式為: _IO (魔數(shù), 基數(shù)); _IOR (魔數(shù), 基數(shù), 變量型) _IOW (魔數(shù), 基數(shù), 變量型) _IOWR (魔數(shù), 基數(shù),變量型 ) 魔數(shù) (magic number) 魔數(shù)范圍為 0~255 。通常,用英文 字符 "A" ~ "Z" 或者 "a" ~ "z" 來表示。設(shè)備驅(qū)動(dòng)程序從傳遞進(jìn)來的命令獲取魔數(shù),然后與自身處理的魔數(shù)想比較,如果相同則處理,不同則不處理。魔數(shù)是拒絕誤使用的初步輔助狀態(tài)。設(shè)備驅(qū)動(dòng) 程序可以通過 _IOC_TYPE (cmd) 來獲取魔數(shù)。不同的設(shè)備驅(qū)動(dòng)程序最好設(shè)置不同的魔數(shù),但并不是要求絕對(duì),也是可以使用其他設(shè)備驅(qū)動(dòng)程序已用過的魔數(shù)。 基(序列號(hào))數(shù) 基數(shù)用于區(qū)別各種命令。通常,從 0開始遞增,相同設(shè)備驅(qū)動(dòng)程序上可以重復(fù)使用該值。例如,讀取和寫入命令中使用了相同的基數(shù),設(shè)備驅(qū)動(dòng)程序也能分辨出來,原因在于設(shè)備驅(qū)動(dòng)程序區(qū)分命令時(shí) 使用 switch ,且直接使用命令變量 cmd值。創(chuàng)建命令的宏生成的值由多個(gè)域組合而成,所以即使是相同的基數(shù),也會(huì)判斷為不同的命令。設(shè)備驅(qū)動(dòng)程序想要從命令中獲取該基數(shù),就使用下面的宏: _IOC_NR (cmd) 通常,switch 中的 case 值使用的是命令的本身。 變量型 變量型使用 arg 變量指定傳送的數(shù)據(jù)大小,但是不直接代入輸入,而是代入變量或者是變量的類型,原因是在使用宏創(chuàng)建命令,已經(jīng)包含了 sizeof() 編譯命令。比如 _IOR() 宏的定義是: 引用 #define _IOR(type,nr,size) _IOC(_IOC_READ,(type),(nr),(_IOC_TYPECHECK(size))) 而 _IOC_TYPECHECK() 的定義正是: 引用 #define _IOC_TYPECHECK(t) (sizeof(t)) 設(shè)備驅(qū)動(dòng)程序想要從傳送的命令獲取相應(yīng)的值,就要使用下列宏函數(shù): _IOC_SIZE(cmd) _IO 宏 該宏函數(shù)沒有可傳送的變量,只是用于傳送命令。例如如下約定: 引用 #define TEST_DRV_RESET _IO ('Q', 0) 此時(shí),省略由應(yīng)用程序傳送的 arg 變量或者代入 0 。在應(yīng)用程序中使用該宏時(shí),比如: ioctl (dev, TEST_DEV_RESET, 0) 或者 ioctl (dev, TEST_DRV_RESET) 。 這是因?yàn)樽兞康挠行б蛩厥强勺円蛩?。只作為命令使用時(shí),沒有必要判 斷出設(shè)備上數(shù)據(jù)的輸出或輸入。因此,設(shè)備驅(qū)動(dòng)程序沒有必要執(zhí)行設(shè)備文件大開選項(xiàng)的相關(guān)處理。 _IOR 宏 該函數(shù)用 于創(chuàng)建從設(shè)備讀取數(shù)據(jù)的命令,例如可如下約定: 引用 #define TEST_DEV_READ _IRQ('Q', 1, int) 這說明應(yīng)用程序從設(shè)備讀取數(shù)據(jù)的大小為 int 。下面宏用于判斷傳送到設(shè)備驅(qū)動(dòng)程序的 cmd 命令的讀寫狀態(tài): _IOC_DIR (cmd) 運(yùn)行該宏時(shí),返回值的類型 如下: _IOC_NONE : 無屬性 _IOC_READ : 可讀屬性 _IOC_WRITE : 可寫屬性 _IOC_READ | _IOC_WRITE : 可讀,可寫屬性 使用該命令時(shí),應(yīng)用程序的 ioctl() 的 arg 變量值指定設(shè)備驅(qū)動(dòng)程序上讀取數(shù)據(jù)時(shí)的緩存(結(jié)構(gòu)體)地址。 _IOW 宏 用于創(chuàng)建設(shè) 備上寫入數(shù)據(jù)的命令,其余內(nèi)容與 _IOR 相同。通常,使用該命令時(shí),ioctl() 的 arg 變量值指定設(shè)備驅(qū)動(dòng)程序上寫入數(shù)據(jù)時(shí)的緩存(結(jié)構(gòu)體)地址。 _IOWR 宏 用于創(chuàng)建設(shè)備上讀寫數(shù)據(jù)的命令。其余內(nèi) 容與 _IOR 相同。通常,使用該命令時(shí),ioctl() 的 arg 變量值指定設(shè)備驅(qū)動(dòng)程序上寫入或讀取數(shù)據(jù)時(shí)的緩存 (結(jié)構(gòu)體) 地址。 _IOR() , _IOW(), IORW() 的定義: #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))) |
|