200 likes | 338 Views
嵌入式系統與實習 ( 驅動程式結構 ). 組員: 4970E079 劉明哲 4970E081 陳俊宇 4970E005 吳明勳. 目錄. 1 、驅動程式介紹 2 、 Linux 設備驅動程式分類 3 、驅動程式的結構 4 、主、從設備號 5 、驅動程式基本框架 6 、重要結構體. 1 、驅動程式介紹. 驅動程式負責將應用程式如讀、寫等操作正確無誤的傳遞給相關的硬體,並使硬體能夠做出正確反應的程式。驅動程式像一個黑盒子,它隱藏了硬體的工作細節,應用程式只需要通過一組標準化的介面實現對硬體的操作。. 2 、 Linux 設備驅動程式分類.
E N D
嵌入式系統與實習 (驅動程式結構) 組員:4970E079 劉明哲 4970E081 陳俊宇 4970E005 吳明勳
目錄 1、驅動程式介紹 2、Linux 設備驅動程式分類 3、驅動程式的結構 4、主、從設備號 5、驅動程式基本框架 6、重要結構體
1、驅動程式介紹 驅動程式負責將應用程式如讀、寫等操作正確無誤的傳遞給相關的硬體,並使硬體能夠做出正確反應的程式。驅動程式像一個黑盒子,它隱藏了硬體的工作細節,應用程式只需要通過一組標準化的介面實現對硬體的操作。
2、Linux 設備驅動程式分類 • Linux 設備驅動程式在 Linux 的核心程式碼中佔有很大的比例,程式碼的長度日益增加,主要是驅動程式的增加。雖然 Linux 核心的不斷升級,但驅動程式的結構還是相對穩定。 • Linux 系統的設備分為字元設備(char device),區塊設備(block device)和網路設備(network device)三種。字元設備是指在存取時沒有緩衝的設備,而區塊設備的讀寫都有緩衝來支援,並且區塊設備必須能夠隨機存取(random access)。典型的字元設備包括滑鼠,鍵盤,串列埠等。區塊設備主要包括硬碟軟碟設備,CD-ROM 等。 • 網路設備在 Linux 裡做專門的處理。Linux 的網路系統主要是基於 BSD unix 的 socket機制。在系統和驅動程式之間定義有專用的資料結構(sk_buff)進行資料傳遞。系統有支援對發送資料和接收資料的緩衝,提供流量控制機制,提供對多協定的支援。
3、驅動程式的結構 • 驅動程式的結構如圖1. 所示,應用程式經過系統調用,進入核心層,核心要控制硬體需要通過驅動程式實現,驅動程式相當於核心與硬體之間的“系統調用"。
核心模組 • 核心模組是Linux 核心的重要組成要素,核心模組能在Linux 系統啟動之後能夠動態進行裝載和卸載,因此不需對核心進行重新編譯或重啟系統就可將核心的一部分替換掉,Linux 核心的所有設備驅動,檔案系統,網路協定等可做成模組的形式來提供。在所有的模組中需記錄編譯的核心版本資訊,並與當前執行的核心版本一致。即,模組具有版本依賴性,如果不一樣就會出錯,當然可以在模組程式中的include<linux/module.h>之前通過巨集定義#define__NO_VERSION__表明不定義模組的版本資訊。 • 核心模組程式與一般應用程式之間主要不同之處是,模組程式沒有main()函數,模組程式在裝載時調用init_module(void)函數新增到核心中,在卸載時調用 void cleanup_module( )函數從核心中卸載。另外一個應用程式從頭到尾只執行一個任務,但一個模組可以把回應未來請求的事務登記到核心中,然後等待系統調用,核心模組程式結構如圖2. 所示。
4、主.從設備號 • 應用程式通過設備檔案系統(devfs)的名字(或節點)存取硬體設備,所有的設備節點在/dev 目錄下。利用 mknod 命令產生設備檔案系統的節點,但只有超級使用者才能產生設備文。Mknod 命令必須要有設備名和設備類型,主設備號(Major Number),次設備號(MinorNumber)等 3 個參數。主設備號用於核心區分設備驅動程式,次設備號用於設備驅動程式區分設備。 • 一個設備驅動程式可能控制多個設備。新的設備驅動程式要有新的主設備號。在核心程式碼的 Documentation /devices.txt 中定義了所有設備的主設備號。在建立設備的時候不要與常用的設備衝突。 • 下面/dev/hda1 是設備名,b 表示 block 設備(c 表示字元設備)。127 是主設備號, 1 是次設備號。次設備號可以是 0 – 255 之間的值,限制為 8bit。 [root@localhost]$ mknod /dev/hda1 b 127 1 [root@localhost]$ ls –al /dev/hda1 [root@localhost]$ brw-rw---- 1 root disk 3 1 Mar
5、驅動程式基本框架 • 如果採用模組方式編寫設備驅動程式時,通常至少要實現設備初始化模組、設備打開模組、資料讀寫與控制模組、中斷處理模組(有的驅動程式沒有)、設備釋放模組和、設備卸載模組等幾個部分。下面給出一個典型的設備驅動程式的基本框架。,從中不難體會到這幾個關鍵部分是如何組織起來的。
/* 打開設備模組 */ static int xxx_open(struct inode *inode, struct file *file) { /*…………*/ } /* 讀設備模組 */ static int xxx_read(struct inode *inode, struct file *file) { /*…………*/ } /* 寫設備模組 */ static int xxx_write(struct inode *inode, struct file *file) { /*…………*/ } /* 控制設備模組 */ static int xxx_ioctl(struct inode *inode, struct file *file) { /*…………*/ } /* 中斷處理模組 */ static void xxx_interrupt(int irq, void *dev_id, struct pt_regs *regs) { /* ... */ }
/* 設備檔操作介面 */ static struct file_operations xxx_fops = { read:xxx_read,/* 讀設備操作*/ write: xxx_write, /* 寫設備操作*/ ioctl: xxx_ioctl, /* 控制設備操作*/ open: xxx_open, /* 打開設備操作*/ release: xxx_release /* 釋放設備操作*/ /* ... */ }; static int __init xxx_init_module (void) { /* ... */ } static void __exit demo_cleanup_module (void) { pci_unregister_driver(&demo_pci_driver); } /* 載入驅動程式模組入口 */ module_init(xxx_init_module); /* 卸載驅動程式模組入口 */ module_exit(xxx_cleanup_module);
6、重要結構體 • 打開的設備在核心內部由 file 結構標識,核心使用 file_operation 結構存取驅動程式函數。file_operation 結構是一個定義在<linux/fs.h>中的函數指標陣列。每個檔案都與它自己的函數集相關聯。這個結構中的每一個欄位都必須指向驅動程式中實現特定操作的函數。結構如下,詳細內容可查閱相關檔案。
struct file_operations { struct module *owner; loff_t (*llseek) (struct file *, loff_t, int); ssize_t (*read) (struct file *, char *, size_t, loff_t *); ssize_t (*write) (struct file *, const char *, size_t, loff_t *); int (*readdir) (struct file *, void *, filldir_t); unsigned int (*poll) (struct file *, struct poll_table_struct *); int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long); int (*mmap) (struct file *, struct vm_area_struct *); int (*open) (struct inode *, struct file *); int (*flush) (struct file *); int (*release) (struct inode *, struct file *); int (*fsync) (struct file *, struct dentry *, int datasync); int (*fasync) (int, struct file *, int); int (*lock) (struct file *, int, struct file_lock *); ssize_t (*readv) (struct file *, const struct iovec *, unsigned long, loff_t *); ssize_t (*writev) (struct file *, const struct iovec *, unsigned long, loff_t *); ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int); unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long); };
File 結構 • File 結構代表一個打開的檔案。它在 open 時被核心建立,並傳遞給在該檔案上進行操作的所有函數,直到最後的 close 函數。在檔案的所有實例都被關閉之後,核心會釋放這個資料結構。結構在/linux/fs.h 定義,詳細內容查閱相關檔案。
struct file { struct list_head struct dentry struct vfsmount struct file_operations atomic_t unsigned int mode_t loff_t unsigned long struct fown_struct unsigned int int unsigned long void struct kiobuf long f_list; *f_dentry; *f_vfsmnt; *f_op; f_count; f_flags; f_mode; f_pos; f_reada, f_ramax, f_raend, f_ralen, f_rawin; f_owner; f_uid, f_gid; f_error; f_version; *private_data; *f_iobuf; f_iobuf_lock; /* needed for tty driver, and maybe others */ /* preallocated helper kiobuf to speedup O_DIRECT */ }; 驅動程式中常用的函數 int xxx_open(struct inode *inode, struct file *filp); int xxx_release(struct inode *inode, struc file *filp); ssize_t xxx_read(struct file *filp, char *buff,size_t count, loff_t *offp); ssize_t xxx_write(struct file *filp, const char *buff, size_t count , loff_t *offp);
實驗內容 1、dri_arh 模組載入實驗 • 編寫實驗程式 • #include <linux/string.h> • #include <linux/module.h> • #include <linux/fs.h> • #include <linux/init.h> • #include <linux/types.h> • #include <linux/fs.h> • static int __init dri_arch_init_module(void) • { • printk("This is a simple driver-module!\r\n"); • return 0; • } • static void __exit dri_arch_cleanup_module(void) • { • printk("Goodbye driver-module!\r\n"); • } • module_init(dri_arch_init_module); • module_exit(dri_arch_cleanup_module);
編譯 make 使用 Makefile檔 CC =/opt/xscalev1/bin/arm-linux-gcc INCLUDEDIR = /root/xsbase/Xsbase270_Linux_F/Kernel/linux-2.4.21-emdoor/include CFLAGS = -D__KERNEL__ -DMODULE -Wall -O2 CFLAGS += -I.. -I$(INCLUDEDIR) DEBUG = TARGET = dri_arch OBJS = $(TARGET).o SRC = dri_arch.c All: dri_arch.o dri_arch.o: dri_arch.c $(CC) $(CFLAGS) $(DEBUG) -c -o dri_arch.o dri_arch.c clean : rm -rf *.o
下載目標程式到目標板,具體的操作參考使用手冊相關部分掛載目標程式,下載目標程式到目標板,具體的操作參考使用手冊相關部分掛載目標程式, 並查看輸出調試資訊, 本次相關操作均要求到下載的當前目錄(含 dri_arch.o) $insmod dri_arch.o (掛載 dri_arch) $lsmod (查看當前已掛載模組,會看到 dri_arch) $dmesg (查看模組輸出資訊:This is a simple driver-module!) $rmmod dri_arch (卸載 dri_arch) $lsmod (查看當前已掛載模組,不再看到 dri_arch) $dmesg (查看模組輸出資訊:Goodbye driver-module!)