20145302張薇 20145308劉昊陽 《資訊保安系統設計基礎》實驗四:外設驅動裝置設計

20145302張薇發表於2016-11-26

20145302張薇 20145308劉昊陽 《資訊保安系統設計基礎》實驗四:外設驅動裝置設計 實驗報告

北京電子科技學院(BESTI)

實 驗 報 告

課程: 資訊保安系統設計基礎 班級:1453

學號姓名:(按貢獻大小排名)20145302張薇 20145308劉昊陽

成績: 指導教師:婁嘉鵬老師 實驗日期:2016.11.24

實驗密級:無 預習程度:已預習 實驗時間:10:10—12:30

儀器組次: 必修/選修:必修 實驗序號:4

實驗名稱: 外設驅動裝置設計

實驗目的與要求

  1. 掌握實時系統應用和驅動程式的編寫
  2. 選擇某個介面電路

實驗儀器

名稱 型號 數量
arm UP-TECH 1
PC機 XP 1

實驗內容與步驟
1.閱讀和理解原始碼
(1)功能

  • demo_read,demo_write 函式完成驅動的讀寫介面功能,do_write 函式實現將使用者寫入的資料逆序排列,通過讀取函式讀取轉換後的資料。這裡只是演示介面的實現過程和核心驅動對使用者的資料的處理。

(2)原始碼框架


#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);

(3)註釋

  • 將驅動對映為標準介面
  • 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 的模組必須包 含標頭檔案

2.編譯驅動模組及測試程式

  • 上面介紹了在 Makefile 中有兩種編譯方法,可以在本機上使用 gcc 也可以使用交叉編譯器進行編譯,這裡我們只介紹用交叉編譯器進行編譯的結果。

  • 注意:如果編譯的時候出現問題,可能是在/usr/src 下沒有建立一個 linux 連線,可以使用下面的命令:


[root@zxt 01_demo]# cd /usr/src/
[root@zxt src]# ln –sf   linux-2.4.20-8  linux
[root@zxt src]# ls
debug  linux  linux-2.4  linux-2.4.20-8  redha
  • ln指令的用法是連線,使用格式是ln [options] source dist,這裡我們用到的sf引數的含義是:

-f:連結時先將與dist同檔名的檔案刪除

-s:進行軟連結。(軟連結,又稱符號連結,這個檔案包含了另一個檔案的路徑名,特點是可以連結不同檔案系統的檔案,甚至可以連結不存在的檔案。)

3.測試驅動程式
(1)建立裝置節點


如果使用 gcc 編譯的話,需要通過下面的命令來建立裝置節點,如果使用交叉編譯器的話,不需要建立裝置節點。

#mknod /dev/demo c 254 0

(2)插入驅動模組demo.o


可以用 lsmod 命令來檢視模組是否已經被插入,在不使用該模組的時候還可以用 rmmod 命令來將模組解除安裝。

    [root@zxt 01_demo]# insmod demo.o
    Warning: loading demo.o will taint the kernel: no license
    See http://www.tux.org/lkml/#export-tainted for information about tainted modules
    Module demo loaded, with warnings

(3)使用測試程式進行測試

  • 成功後會出現下面的結果:

[root@zxt 01_demo]# ./test_demo
write 32 bytes data to /dev/demo
0:   0   1   2   3
1:   4   5   6   7
2:   8   9   10  11
3:   12  13  14  15
4:   16  17  18  19
5:   20  21  22  23
6:   24  25  26  27
7:   28  29  30  31
*****************************************************
Read 32 bytes data from /dev/demo
0:   31  30  29  28
1:   27  26  25  24
2:   23  22  21  11
3:   12  13  14  15
4:   16  17  18  19
5:   20  10   9   8
6:   7    6   5   4
7:   3    2   1   0
*****************************************************
  • 如果模組沒有成功插入的話,會出現下面的情況:
[root@zxt 01_demo]# ./test_demo
####DEMO  device open fail####  

(4)測試讀過程

在驅動模組成功插入後,會在/dev 下面建立一個叫做 demo 的裝置檔案,我們也可以使用 cat 命令來直接呼叫 read 函式,來測試讀過程。
[root@zxt demo]# cat /dev/demo/0
device open success!
實驗中遇到的問題
1.需要修改makefile

  • makefile中兩行巨集變數定義用於使用armv4l-unknown-linux-gcc編譯器編譯驅動:

#KERNELDIR = /arm2410cl/ kernel/linux-2.4.18-2410cl/
#CROSS_COMPILE= armv4l-unknown-linux-
  • 由於makefile檔案中KERNEL_PATH設定和真實環境有點不同,修改makefile檔案中的路徑就好了。

  • 修改為:


KERNELDIR = /usr/src/linux
#KERNELDIR = /arm2410cl/ kernel/linux-2.4.18-2410cl/
INCLUDEDIR = $(KERNELDIR)/include
#CROSS_COMPILE=armv41-unknown-linux-

相關文章