Linux核心驅動(六):1、裝置控制—ioctl

來源:互聯網
上載者:User

一、ioctl   的功能

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

二、ioctl  使用方法

       1、在使用者空間,使用  ioctl  系統調用來控制裝置,函數原型如下:

              int  ioctl (  int fd, unsigned long cmd, 【...】 );

              註:參數列表中的 省略符號“...”,表示一個可選的參數,這些參數的存在與否依賴於控制命令(第2個參數 cmd)。

       2、驅動方法中的  ioctl  (ioctl  驅動方法有和使用者空間版本不同的原型):

              int  ( * ioctl) ( struct inode * inode, struct file * filp, unsigned int cmd, unsigned long arg);

              參數:

                        == inode:記錄一些裝置號等資訊

                        ==filp:對應一個開啟的檔案,其中記錄了一些諸如檔案的讀寫位置等資訊

                       ==cmd:這個參數從使用者空間傳下來,

                       ==arg:可選的參數, 不管它是一個整數或一個指標, arg  都以一個unsigned long 的形式傳遞。如果第3個參數cmd命令不涉及資料轉送,則第3個參數arg的值毫無意義。

三、實現  ioctl  方法:(步驟)

        1、定義命令

              (1)從實質上講,一個命令就是一個32位的整數。為了防止對錯誤的裝置使用正確的命令,命令號應該在系統範圍內是唯一的。

              (2)ioctl  命令編碼被劃分為4個位段,(在  include / asm / ioctl.h  中定義了這些位欄位),他們分別是:

                         a、類型(幻數)   b、序號   c、傳送方向  d、參數的大小

               (3)定義命令的正確方法是使用4個位段,這個列表中介紹的符號定義在  <linux / ioctl.h>

                       ==  Type (幻數:類型)

                                       表明那個裝置的命令,在參考了ioctl-number.txt之後選出,8位寬。

                              eg:

                                    我們給每一個裝置指定一個類型(幻數)假如說我們指定了某裝置的幻數為3,那麼所有Type段的值為3的命令都是給這個裝置服務的

                       ==Number(序號)

                                           一個裝置有多個控制命令,這個欄位的值用來表明,當前命令是所有裝置控制命令中的第幾個命令,8位寬

                       ==Direction(資料傳送的方向)

                                              涉及資料轉送的命令需要指明資料傳送的方向(比如設定傳輸速率),資料傳送的方向是從應用程式的觀點來看待的,可能的值有:

                                              --- _IOC_NONE:沒有資料轉送

                                              --- _IOC_READ:從裝置讀

                                              --- _IOC_WRITE  :向裝置寫                                 

                       ==Size(使用者資料的大小)

                                    13/14 位寬,視處理器而定

               (4)核心提供了下列宏來協助定義命令:

                         ==  _IO ( type , nr )  ,  用於構造沒有參數的命令

                                由於沒有參數,所以這個命令的 Direction (等於_IOC_NONE)和 Size(等於0) 就都明確了,不需要再設定。

                                所以使用這個宏,並傳入命令的type欄位和nr欄位的值,它就會幫你構造並返回一個沒有參數的命令

                         ==  _IOR(type , nr , datatype),從驅動中讀資料

                                這裡不需要直接提供size的大小,這個宏會根據你提供的參數類型datatype,自動的計算資料size的大小

                         ==  _IOW ( type, nr , datatype ),寫資料到驅動

                         ==  _IOWR ( type, nr , datatype ),雙向傳送,type 和 number 成員作為參數被傳遞

                         eg:

                              

#define MEM_IOC_MAGIC 'm'  //定義幻數,由於幻數是一個8位寬的,所以其實就是一個char類型變數,我們當然可以用一個字元對他進行賦值#define  MEM_IOCSET  _IOW(MEM_IOC_MAGIC, 0 , int);   //定義一個命令MEM_IOCSET,用於向裝置中寫資料#define MEM_IOCGQSET _IOR(MEM_IOC_MAGIC,1,int)  //向裝置中讀資料

        2、實現命令(ioctl 函數的實現包括如下 3個技術環節:a、傳回值  b、參數設定  c、命令操作)

              (1)ioctl  函數的實現 主體是一個 switch 語句,switch的 參數是cmd。當命令號不能匹配任何一個命令時,返回 -EINVAL(error invalid 非法參數,注意前面有一個負號)

              (2)如何使用 ioctl 函數中的第4個參數arg(從使用者空間傳下來的)?如果是一個整數,可以直接使用。如果是指標,我們必須確保這個使用者地址是有效,因此使用前需要進行正確的檢查。

                      ==通過以下的函數使用此指標不需要進行檢測(因為在這些函數內部已經實現了檢測)(4個):

                            --- copy_from_user

                            --- copy_to_user

                            --- get_user                           

                            --- put_user

                       ==通過以下的函數使用此指標需要進行檢測(2個):

                            ---  __get_user

                            ---  __put_user

                       == 怎麼樣對這個指標進行檢測?

                              使用 int access_ok ( int type, const void *addr,unsigned long size ); 函數

                              參數:

                               --- type:可以使用的值是VERIFY_READ 或者  VERIFY_WRITE ,用來表明讀使用者記憶體還是寫使用者記憶體

                               ---addr:指明要操作的使用者記憶體位址

                               ---size:操作的長度,eg:如果需要從使用者空間讀一個整數,那麼size參數等於sizeof(int)

                              傳回值:

                                    access_ok返回一個布爾值:1是成功(存取沒問題),0是失敗(存取有問題)。如果該函數返回失敗,則ioctl 應當返回  -EFAULT

                              eg:

if( _IOC_DIR(cmd) & _IOC_READ)     err = access_oc(VERIFY_WRITE,(void __user*)arg,_IOC_SIZE(cmd));//為什麼_IOC_READ 對應 VERIFY_WRITE?因為IOC_READ表示從裝置中讀取資料然後傳到使用者空間,所以這個資料最終要留向使用者空間,即寫進使用者空間,寫到使用者空間這個arg指標所指向的地區。所以這裡我們要驗證的是寫else if( _IOC_DIR(cmd) & _IOC_WRITE)     err = access_ok(VERIFY_WRITE,(void __user*)arg,_IOC_SIZE(cmd));if(err)    return -EFAULT;

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.