1. 程式人生 > >Ioctl使用及與unlocked_ioctl區別

Ioctl使用及與unlocked_ioctl區別

1. Ioctl 用來做什麼?

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

1.1 使用者使用方法
         在使用者空間,使用ioctl 系統呼叫來控制裝置,原型如下:
         int ioctl(int fd,unsigned long cmd,...)
         原型中的點表示這是一個可選的引數,存在與否依賴於控制命令(第2 個引數)是否涉及到與裝置的資料互動。

1.2 驅動ioctl方法
        ioctl 驅動方法有和使用者空間版本不同的原型:
        int (*ioctl)(struct inode *inode,struct file *filp,unsigned int cmd,unsigned long arg)
        cmd引數從使用者空間傳下來,可選的引數arg 以一個unsigned long 的形式傳遞,不管它是一個整數或一個指標。如果cmd命令不涉及資料傳輸,則第3 個引數arg的值無任何意義。

2. Ioctl實現
2.1 實現Ioctl方法的步驟:
      1)  定義命令
      2.)  實現命令

2.2 定義命令
        在編寫ioctl程式碼之前,首先需要定義命令。為了防止對錯誤的裝置使用正確的命令,命令號應該在系統範圍內是唯一的。ioctl 命令編碼被劃分為幾個位段,include/asm/ioctl.h中定義了這些位欄位:型別(幻數),序號,傳送方向,引數的大小。Documentation/ioctl-number.txt檔案中羅列了在核心中已經使用了的幻數。
        定義ioctl 命令的正確方法是使用4 個位段, 這個列表中介紹的符號定義在<linux/ioctl.h>中:
1) Type
     幻數(型別): 表明哪個裝置的命令,在參考了ioctlnumber.txt之後選出,8 位寬。
2)  Number
      序號,表明裝置命令中的第幾個,8 位寬
3) Direction
     資料傳送的方向,可能的值是_IOC_NONE(沒有資料傳輸),_IOC_READ, _IOC_WRITE。資料傳送是從應用程式的觀點來看待的,_IOC_READ 意思是從裝置讀。
4) Size
使用者資料的大小。(13/14位寬,視處理器而定)

核心提供了下列巨集來幫助定義命令:
1)  _IO(type,nr)
    沒有引數的命令
2)  _IOR(type,nr,datatype)
    從驅動中讀資料
3)  _IOW(type,nr,datatype)
   寫資料到驅動
4) _IOWR(type,nr,datatype)
   雙向傳送,type 和number 成員作為引數被傳遞。

定義命令(範例)
#define MEM_IOC_MAGIC ‘m’ //定義幻數
#define MEM_IOCSET
_IOW(MEM_IOC_MAGIC, 0, int)
#define MEM_IOCGQSET
_IOR(MEM_IOC_MAGIC, 1, int)

2.3 Ioctl函式實現
        定義好了命令,下一步就是要實現Ioctl函數了,Ioctl函式的實現包括如下3個技術環節:
       1)  返回值
       2) 引數使用
       3) 命令操作

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

2.3..2 Ioctl函式實現(引數)
         如何使用Ioctl中的引數?
         如果是一個整數,可以直接使用。如果是指標,我們必須確保這個使用者地址是有效的,因此使用前需進行正確的檢查。

2.3.3 Ioctl函式實現(引數檢查)
        不需要檢測:
        1) copy_from_user

        2) copy_to_user
        3) get_user
        4) put_user
        需要檢測:
       1) __get_user
       2) __put_user

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

        第一個引數是VERIFY_READ 或者VERIFY_WRITE,用來表明是讀使用者記憶體還是寫使用者記憶體。addr 引數是要操作的使用者記憶體地址,size 是操作的長度。如果ioctl 需要從使用者空間讀一個整數,那麼size引數等於sizeof(int)。access_ok 返回一個布林值: 1 是成功(存取沒問題)和0 是失敗(存取有問題),如果該函式返回失敗, 則Ioctl應當返回–EFAULT 。

2.3 Ioctl與unlocked_ioctl的區別

使用ioctl的函式宣告為:(int *ioctl)(struct inode *inodep, struct file *filp, unsigned int cmd, unsigned long arg)

使用unlock_ioctl的函式宣告:(int *ioctl)(struct file *filp, unsigned int cmd, unsigned long arg)

不然會導致傳入的cmd改變