20145216 20145330 《資訊保安系統設計基礎》 實驗四 模組方式驅動實驗

20145330孫文馨發表於2016-11-19

20145216 20145330 《資訊保安系統設計基礎》 實驗四 模組方式驅動實驗

實驗報告封面

20145216 20145330 《資訊保安系統設計基礎》 實驗四 模組方式驅動實驗
20145216 20145330 《資訊保安系統設計基礎》 實驗四 模組方式驅動實驗

實驗步驟

1、閱讀和理解原始碼
進入/arm2410cl/exp/drivers/01_demo,使用vi 編輯器或其他編輯器閱讀理解原始碼。
20145216 20145330 《資訊保安系統設計基礎》 實驗四 模組方式驅動實驗

2、實驗開始前配置環境變數
20145216 20145330 《資訊保安系統設計基礎》 實驗四 模組方式驅動實驗

3、編譯驅動模組及測試程式上面介紹了在 Makefile 中有兩種編譯方法,可以在本機上使用gcc 也可以使用交叉編譯器進行編譯,這裡我們只介紹用交叉編譯器進行編譯的結果。
20145216 20145330 《資訊保安系統設計基礎》 實驗四 模組方式驅動實驗

4、測試驅動程式如果使用 gcc 編譯的話,需要通過下面的命令來建立裝置節點,如果使用交叉編譯器的話,不需要建立裝置節點。

20145216 20145330 《資訊保安系統設計基礎》 實驗四 模組方式驅動實驗

首先要插入驅動模組demo.o,然後可以用lsmod 命令來檢視模組是否已經被插入,在不使用該模組的時候還可以用rmmod 命令來將模組解除安裝。

20145216 20145330 《資訊保安系統設計基礎》 實驗四 模組方式驅動實驗

根據上述命令輸入:
20145216 20145330 《資訊保安系統設計基礎》 實驗四 模組方式驅動實驗

下面使用測試程式來進行測試:./test_demo

直接執行出現請求開啟失敗的提示,經過多次探索問題解決執行成功
20145216 20145330 《資訊保安系統設計基礎》 實驗四 模組方式驅動實驗

20145216 20145330 《資訊保安系統設計基礎》 實驗四 模組方式驅動實驗

問題與解決

1、問題:忘記配置環境變數,需要將實驗一armv4l資料夾要考到bc中
20145216 20145330 《資訊保安系統設計基礎》 實驗四 模組方式驅動實驗

  • 解決方法:將armv4l資料夾拷貝到bc中再次輸入相關命令
    20145216 20145330 《資訊保安系統設計基礎》 實驗四 模組方式驅動實驗

輸入命令./install.sb
20145216 20145330 《資訊保安系統設計基礎》 實驗四 模組方式驅動實驗

2、問題:交叉編譯器進行編譯第一次輸入命令出現錯誤
20145216 20145330 《資訊保安系統設計基礎》 實驗四 模組方式驅動實驗

  • 解決方法:
    20145216 20145330 《資訊保安系統設計基礎》 實驗四 模組方式驅動實驗

輸入命令後問題解決
20145216 20145330 《資訊保安系統設計基礎》 實驗四 模組方式驅動實驗

3、問題:在使用測試程式進行測試時,多次出現device open failed提示
20145216 20145330 《資訊保安系統設計基礎》 實驗四 模組方式驅動實驗

  • 解決方法:懷疑是前面某一步驟漏輸入或者命令輸錯,依次再次輸入排除問題,再次輸入insmod demo.o,發現外掛已存在於是再次執行,依然失敗,排除外掛插入因素
  • 輸入命令#mknod /dev/demo c 254 0 ,建立裝置節點(因為第一次編譯時根據指導書指示沒有操作此步驟),進行執行發現成功。

20145216 20145330 《資訊保安系統設計基礎》 實驗四 模組方式驅動實驗

理解原始碼

  • 原始碼

    #define DEVICE_NAME  "demo"
    static ssize_t demo_write(struct file *filp,const char * buffer, size_t count)
    { 
        char drv_buf[];
        copy_from_user(drv_buf , buffer, count);
        …
    }
    static ssize_t demo_read(struct file *filp,char *buffer,size_t count,loff_t *ppos)
    {
    char drv_buf[];
    copy_to_user(buffer, drv_buf,count);
    ….
    }
    static int demo_ioctl(struct inode *inode, struct file *file,unsigned int cmd, unsigned long arg)
    {
    }
    static int demo_open(struct inode *inode, struct file *file)
    {
    }
    static int demo_release(struct inode *inode, struct file *filp)
    {
        MOD_DEC_USE_COUNT;
        DPRINTK("device release\n");
        return 0;
    }
    static struct file_operations demo_fops = {
        owner:  THIS_MODULE,
        write:demo_write, 
        read: demo_read, 
        ioctl: demo_ioctl,
        open: demo_open,
        release:demo_release,
    };
    #ifdef CONFIG_DEVFS_FS
    static devfs_handle_t devfs_demo_dir, devfs_demoraw;
    #endif
    static int __init demo_init(void)
    {
        int result;
        #ifdef CONFIG_DEVFS_FS
        devfs_demo_dir = devfs_mk_dir(NULL, "demo", NULL);
        devfs_demoraw = devfs_register(devfs_demo_dir, "0", DEVFS_FL_DEFAULT,
        demo_Major, demo_MINOR, S_IFCHR | S_IRUSR | S_IWUSR,&demo_fops, NULL);
        #else
        SET_MODULE_OWNER(&demo_fops);
        result = register_chrdev(demo_Major, "scullc", &demo_fops);
        if (result < 0) return result;
        if (demo_Major == 0) demo_Major = result; /* dynamic */
        #endif
        printk(DEVICE_NAME " initialized\n");
        return 0;
    }
    static void __exit demo_exit(void)
    {
        unregister_chrdev(demo_major, "demo");
        kfree(demo_devices);
        printk(DEVICE_NAME " unloaded\n");
    }
    module_init(demo_init);
    module_exit(demo_exit);

註釋

  • 將驅動對映為標準介面

    • static struct file_operations demo_fops = {…}完成了將驅動函式對映為標準介面。
    • 驅動向核心註冊

    • devfs_registe()和 register_chrdev()函式完成將驅動向核心註冊。
  • Open方法

Open 方法提供給驅動程式初始化裝置的能力,從而為以後的裝置操作做好準備,此外open操作一般還會遞增使用計數,用以防止檔案關閉前模組被解除安裝出核心。

- 遞增使用計數
- 檢查特定裝置錯誤。
- 如果裝置是首次開啟,則對其進行初始化。
- 識別次裝置號,如有必要修改 f_op 指標。
- 分配並填寫 filp->private_data 中的資料。
  • Release 方法

與 open 方法相反,release 方法應完成如下功能:

- 釋放由 open 分配的 filp->private_data 中的所有內容
- 在最後一次關閉操作時關閉裝置
- 使用計數減一
  • Read 和 和 Write 方法

ssize_t demo_write(struct file filp,const char buffer, size_t count,loff_t *ppos)

ssize_t demo_read(struct file filp, char buffer, size_t count, loff_t *ppos)
read 方法完成將資料從核心拷貝到應用程式空間,write 方法相反,將資料從應用程式空間拷貝到核心。對於者兩個方法,引數 filp 是檔案指標,count 是請求傳輸資料的長度,buffer 是使用者空間的資料緩衝區,ppos 是檔案中進行操作的偏移量,型別為 64 位數。由於使用者空間和核心空間的記憶體對映方式完全不同,所以不能使用象 memcpy 之類的函式,必須使用如下函式:

unsigned long copy_to_user (void to,const void from,unsigned long count);

unsigned long copy_from_user(void to,const void from,unsigned long count);

  • ioctl方法

ioctl 方法主要用於對裝置進行讀寫之外的其他控制,比如配置裝置、進入或退出某種
操作模式,這些操作一般都無法通過 read/write 檔案操作來完成。

  • 編寫中斷處理函式的注意事項:

中斷處理程式與普通C程式碼沒有太大不同,不同的是中斷處理程式在中斷期間執行,它有如下限制:

不能向使用者空間傳送或接受資料
不能執行有睡眠操作的函式
不能呼叫排程函式

  • 使用/proc檔案系統

/proc 檔案系統是由程式建立的檔案系統,核心利用它向外輸出資訊。/proc 目錄下的
每一個檔案都被繫結到一個核心函式,這個函式在此檔案被讀取時,動態地生成檔案的內
容。

大多數情況下 proc 目錄下的檔案是隻讀的。使用/proc 的模組必須包 含
標頭檔案

實驗感想與體會

這次實驗我們耗費了整整兩個課時,在閱讀實驗指導書後本來覺得步驟不是很多應該能很快完成。沒想到遇到各種細小的問題,並不是一帆風順的。做實驗的魅力就在於要不斷的嘗試與探索,在這個過程中操作更加熟練知識條理更加清晰,我們這次採用了新的排除法發現查錯效率高了不少,今後會繼續努力的。

隊友連結:http://www.cnblogs.com/sjy519/p/6083253.html

相關文章