ioctl命令編號分析

        在編寫ioctl代碼之前,需要選擇對應不同命令的編號。爲了防止對錯誤的設備使用正確的命令,命令號應該在系統範圍內唯一,這種錯誤匹配並不是不會發生,程序可能發現自己正在試圖對FIFOaudio等這類非串行設備輸入流修改波特率,如果每一個ioctl命令都是唯一的,應用程序進行這種操作時就會得到一個EINVAL錯誤,而不是無意間成功地完成了意想不到的操作。

        要按Linux內核的約定方法爲驅動程序選擇ioctl編號,應該首先看看include/asm/ioctl.hDoucumention/ioctl-number.txt這兩個文件。頭文件定義了要使用的位字段:類型(幻數)、序數、傳送方向以及參數大小等。ioctl-number.txt文件中羅列了內核所使用的幻數,選擇自己的幻數要避免和內核衝突。以下是對include/asm/ioctl.h中定義的宏的註釋:

#define         _IOC_NRBITS          8                               //序數(number)字段的字位寬度,8bits

#define         _IOC_TYPEBITS      8                               //幻數(type)字段的字位寬度,8bits

#define         _IOC_SIZEBITS       14                              //大小(size)字段的字位寬度,14bits

#define         _IOC_DIRBITS         2                               //方向(direction)字段的字位寬度,2bits

 

#define         _IOC_NRMASK        ((1 << _IOC_NRBITS)-1)    //序數字段的掩碼,0x000000FF

#define         _IOC_TYPEMASK   ((1 << _IOC_TYPEBITS)-1)  //幻數字段的掩碼,0x000000FF

#define         _IOC_SIZEMASK     ((1 << _IOC_SIZEBITS)-1)   //大小字段的掩碼,0x00003FFF

#define         _IOC_DIRMASK      ((1 << _IOC_DIRBITS)-1)    //方向字段的掩碼,0x00000003

 

#define        _IOC_NRSHIFT       0                                                         //序數字段在整個字段中的位移,0

#define        _IOC_TYPESHIFT   (_IOC_NRSHIFT+_IOC_NRBITS)         //幻數字段的位移,8

#define        _IOC_SIZESHIFT    (_IOC_TYPESHIFT+_IOC_TYPEBITS)  //大小字段的位移,16

#define        _IOC_DIRSHIFT      (_IOC_SIZESHIFT+_IOC_SIZEBITS)    //方向字段的位移,30

 

/*

 * Direction bits.

 */

#define _IOC_NONE     0U     //沒有數據傳輸

#define _IOC_WRITE   1U     //向設備寫入數據,驅動程序必須從用戶空間讀入數據

#define _IOC_READ     2U     //從設備中讀取數據,驅動程序必須向用戶空間寫入數據

 

 

/*

*_IOC 宏將dirtypenrsize四個參數組合成一個cmd參數,如下圖:

*

*/

 

#define _IOC(dir,type,nr,size) /

       (((dir)  << _IOC_DIRSHIFT) | /

        ((type) << _IOC_TYPESHIFT) | /

        ((nr)   << _IOC_NRSHIFT) | /

        ((size) << _IOC_SIZESHIFT))

 

/*

* used to create numbers 

*/

//構造無參數的命令編號

#define _IO(type,nr)             _IOC(_IOC_NONE,(type),(nr),0) 

//構造從驅動程序中讀取數據的命令編號

 

#define _IOR(type,nr,size)     _IOC(_IOC_READ,(type),(nr),sizeof(size)) 

//用於向驅動程序寫入數據命令

#define _IOW(type,nr,size)    _IOC(_IOC_WRITE,(type),(nr),sizeof(size))

//用於雙向傳輸

#define _IOWR(type,nr,size) _IOC(_IOC_READ|_IOC_WRITE,(type),(nr),sizeof(size))

 

/* 

*used to decode ioctl numbers..

 */

//從命令參數中解析出數據方向,即寫進還是讀出

#define _IOC_DIR(nr)          (((nr) >> _IOC_DIRSHIFT) & _IOC_DIRMASK)

//從命令參數中解析出幻數type

#define _IOC_TYPE(nr)              (((nr) >> _IOC_TYPESHIFT) & _IOC_TYPEMASK)

//從命令參數中解析出序數number

#define _IOC_NR(nr)           (((nr) >> _IOC_NRSHIFT) & _IOC_NRMASK)

//從命令參數中解析出用戶數據大小

#define _IOC_SIZE(nr)         (((nr) >> _IOC_SIZESHIFT) & _IOC_SIZEMASK)

 

/* ...and for the drivers/sound files... */

 

#define IOC_IN            (_IOC_WRITE << _IOC_DIRSHIFT)

#define IOC_OUT         (_IOC_READ << _IOC_DIRSHIFT)

#define IOC_INOUT     ((_IOC_WRITE|_IOC_READ) << _IOC_DIRSHIFT)

#define IOCSIZE_MASK      (_IOC_SIZEMASK << _IOC_SIZESHIFT)

#define IOCSIZE_SHIFT      (_IOC_SIZESHIFT)

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章