歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux編程 >> Linux編程

【Linux 驅動】第二章 構造和運行模塊

設置測試系統開發環境及Hello World入門模塊在前面中已經講到,請參考:http://www.linuxidc.com/Linux/2012-04/58409.htm

一,核心模塊與應用程序的對比

        應用程序:小規模及中規模程序,從頭到尾執行單個任務。

        核心模塊:預先注冊自己,以便服務於將來的某個請求。然後他的初始化函數就立即結束。

        退出時候,應用程序可以不釋放自己申請的資源,而模塊在退出之前必須仔細撤銷初始化函數所做的一切。

二,用戶空間和內核空間

        模塊運行在內核空間,應用程序運行在內核空間。

        每當應用程序執行系統調用或者被硬件中斷掛起時,Unix將執行模式從用戶空間切換到內核空間。

        應用程序在虛擬內存中布局,並具有一塊很大的棧空間(保存函數調用歷史以及當前活動函數中的自動變量)。內核具有非常小的棧,所以我們自己的函數必須和整個內核空間調用鏈一同共享這個棧。

       【注意】在內核API中看到有兩個下劃線_ _的函數名:接口的底層組件

三,初始化和關閉

         static  int  _ _init  initialization_function(void)

          {

                /*初始化代碼*/

                 return <int>;


           }

         module_init(initialization_function); //說明內核初始化位置,沒有這個函數,則初始化函數無法調用


【注意】_ _init    _ _initdata表明函數只在初始化期間使用,模塊裝載完成後不再使用。

 


    static  void  _ _init  cleanup_function(void)//沒有返回值

 

 

    清除函數 類似 module_exit(cleanup_function)

四,初始化過程中的錯誤處理

         1)時刻銘記,注冊可能會失敗,因此模塊代碼要始終檢查返回值。

         2)當注冊時,有些模塊注冊失敗,則需要自行撤銷已注冊的設施。否則內核處於一種不穩定狀態。唯一有效的解決辦法:重新引導系統

         3)使用goto

                int  _ _my_init_function(void)

               {

                    int err;

                    err=regeister_this(ptr1,"skull");

                    if(err)  goto fail_this;

                    err=regeister_that(ptr2,"skull");

                    if(err)  goto fail_that;

                   err=regeister_those(ptr3,"skull");
                    if(err)  goto fail_those;

 


                     return 0;//成功

                


                   fail_this:return err;

                   fail_those:unregeister_those(ptr3,"skull");


                   fail_that:unregeister_that(ptr3,"skull");

                 }

           4)初始化函數還在運行時,內核就完全可能會調用我們的模塊。所以我們應在用來支持某個設施的所有內部初始化完成之前,不要注冊任何設施。


五,模塊參數支持很多類型;
    1)基本類型:
        bool   :布爾類型
        invbool:顛倒了值的bool類型;
        charp  :字符指針類型,內存為用戶提供的字符串分配;
        int    :整型
        long   :長整型
        short  :短整型
        uint   :無符號整型
        ulong  :無符號長整型
        ushort :無符號短整型

     定義模塊參數的方法:
           module_param(name, type, perm);
     其中,name:表示參數的名字;
          type:表示參數的類型;
          perm:表示參數的訪問權限;

   2)數組類型:用逗號間隔的列表提供的值;
      聲明一個數組參數:
           module_param_array(name, type, num, perm);
      其中,name:表示數組的名字;
           type:表示參數的類型;
           num :表示數組中元素數量;
           perm:表示參數的訪問權限;
   3)參數的訪問權限
       modlue_param和module_param_array中的perm用於設定該參數的訪問權限;
       perm表示該參數在sysfs文件系統中所對應的文件節點的屬性;你用該使用<linux/stat.h>中定義的權限值;這個值控制誰可以存取這些模塊參數在sysfs文件系統中的表示;當perm為0時,表示此參數不存在sysfs文件系統下對應的文件節點;否則,模塊被加載後,在/sys/module/目錄下將會出現以此模塊名命名的目錄,帶有給定的權限;
比如:
#define S_IRWXU 00700
#define S_IRUSR 00400
#define S_IWUSR 00200
#define S_IXUSR 00100
#define S_IRWXG 00070
#define S_IRGRP 00040
#define S_IWGRP 00020
#define S_IXGRP 00010
#define S_IRWXO 00007
#define S_IROTH 00004
#define S_IWOTH 00002
#define S_IXOTH 00001
注意:如果一個參數被sysfs修改了,那麼你的模塊看到的參數值也被修改了,但是你的模塊不會收到任何通知;你應當不要使模塊參數可寫,除非你准備好檢測這個改變並因而作出反應;

六,在用戶空間編寫驅動程序

        用戶空間驅動程序的優點:
            1)可以和整個C庫鏈接
            2)驅動程序不用借助外部程序(對於復雜的外設,常常需要和驅動一起發行用戶提供策略的應用程序)就可以完成許多非常規的任務。
            3)在驅動中可以使用浮點數,在某些特殊的硬件中,可能需要使用浮點數,而linux內核並不提供浮點數的支持。如果能在用戶態實現驅動,就可以輕松解決這一問題
           4) 驅動的問題不會導致整個系統掛起,有過驅動開發經驗的人一定會對調試深有感觸,一些錯誤常常導致整個系統掛起。而用戶態的驅動在調試上就要方便很多。
           5) 用戶內存可以換出
           6)設計良好的驅動仍然可以支持對設備的並發訪問
           7)可以給出封閉源碼的驅動程序,不必采用GPL,更為靈活


      用戶空間驅動的最常見例子是X-server,很多USB設備的驅動也可以放到用戶空間。目前,很多人嘗試在用戶態為PCI設備提供驅動

     用戶空間驅動的缺點:
         1)中斷在用戶空間不可用,最新的UIO接口已經解決了這一問題
         2)響應時間較慢
         3)只能支持字符設備,無法支持塊設備和網絡設備
         4)可靠性較低,很多驅動都是閉源的,我們沒法通過閱讀代碼解決問題
         5)有些硬件廠商只提供和某些linux開發版(常常早就過時了)相匹配的用戶空間驅動

相關閱讀:

【Linux 驅動】第一章 設備驅動程序簡介  http://www.linuxidc.com/Linux/2012-04/58410.htm

【Linux 驅動】驅動開發第一步----開發環境搭配  http://www.linuxidc.com/Linux/2012-04/58409.htm

Copyright © Linux教程網 All Rights Reserved