1. file_operations結構體的概述
linux驅動程式中最重要的涉及3個重要的核心資料結構,分別為file_operations,file和inode。在linux中inode結構用於表示檔案,而file結構則表示開啟的檔案的描述,因為對於單個檔案而言可能會有許多個表示開啟的檔案的描述符,因而就可能會的對應有多個file結構,但是都指向單個inode結構。
在系統內部,i/o裝置的訪問操作通過特定的的入口來進行,而這組特定的入口由驅動程式來提供的。通常這組裝置驅動的介面是由結構體file_operations向系統說明的,結構體file_operations是定義在include/linux/fs.h中的。
structfile_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 *, structpoll_table_struct *);
int (*ioctl) (struct inode *, struct file*, unsigned int, unsigned long);
int (*mmap) (struct file *, structvm_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, structfile_lock *);
ssize_t (*readv) (struct file *, conststruct iovec *, unsigned long, loff_t *);
ssize_t (*writev) (struct file *, conststruct iovec *, unsigned long, loff_t *);
ssize_t (*sendpage) (struct file *, structpage *, int, size_t, loff_t *, int);
詳細分析結構體中比較重要的幾個方法:
struct module *owner;
它是乙個指向擁有這個結構的模組的指標.這個成員用來在它的操作還在被使用時阻止模組被解除安裝。
loff_t (*llseek) (struct file *, loff_t, int);
llseek方法用作改變檔案中的當前讀/寫位置, 並且新位置作為(正的)返回值。指標引數filp為進行讀取資訊的目標檔案結構體指標; loff_t 引數是乙個"long offset", 並且就算在 32位平台上也至少 64 位寬. 錯誤由乙個負返回值指示。
ssize_t (*read) (struct file * filp, char * , size_t,loff_t * );
這個函式用來從裝置中獲取資料. 在這個位置的乙個空指標導致 read 系統呼叫以 -einval("invalid argument") 失敗.乙個非負返回值代表了成功讀取的位元組數( 返回值是乙個"signed size" 型別, 常常是目標平台本地的整數型別)。
ssize_t (*write) (struct file*, const char * ,size_t,loff_t *);
傳送資料給裝置. 如果 null,-einval 返回給呼叫 write 系統呼叫的程式. 如果非負, 返回值代表成功寫的位元組數.
(注:這個操作和上面的對檔案進行讀的操作均為阻塞操作)
int (*readdir) (struct file * ,void *, filldir_t);
對於裝置檔案這個成員應當為 null; 它用來讀取目錄, 並且僅對檔案系統有用。
int (*ioctl) (struct inode*, struct file*, unsignedint, unsigned long );
ioctl 系統呼叫提供了發出裝置特定命令的方法(例如格式化軟盤的乙個磁軌, 這不是讀也不是寫). 另外, 幾個 ioctl 命令被核心識別而不必引用 fops 表.如果裝置不提供 ioctl 方法, 對於任何未事先定義的請求(-enotty,"裝置無這樣的ioctl"), 系統呼叫返回乙個錯誤.
int (*open) (struct inode * inode , struct file * filp) ;
這常常是對裝置檔案進行的第乙個操作, 不要求驅動宣告乙個對應的方法. 如果這個項是 null, 裝置開啟一直成功, 但是你的驅動不會得到通知。與open()函式對應的是release()函式。
int (*release) (struct inode *, struct file *);
release ()函式當最後乙個開啟裝置的使用者程序執行close()系統呼叫的時候,核心將呼叫驅動程式release()函式:
void release(struct inode inode,struct file*file),release函式的主要任務是清理未結束的輸入輸出操作,釋放資源,使用者自定義排他標誌的復位等。在檔案結構被釋放時引用這個操作. 如同 open, release 可以為 null.
2.驅動編寫的框架
裝置驅動程式的主體一般是寫好了的。嵌入式開發人員要把驅動程式嵌入核心。驅動程式可以按照兩種方式編譯。一種是編譯進kernel,另一種是編譯成模組(modules),如果編譯進核心的話,會增加核心的大小,還要改動核心的原始檔,而且不能動態的解除安裝,不利於除錯,所以推薦使用模組方式,也可以理解為靜態載入與動態載入的方式。
在這裡可大致將驅動編寫分為以下幾個部分:
u 驅動程式的註冊和登出;
u 裝置的開啟和釋放;
u 裝置的讀寫操作;
u 裝置的控制操作;
u 裝置的中斷和輪詢處理。
3.模組的概念
模組:核心本身是很龐大的乙個結構,需要的元件很多。編譯核心時,使用者 可以把所有的**編譯進核心,但是這樣會引起兩個問題:一是核心過大;二是 當需要新增或者刪除核心時,需要重新再編譯核心,而重新編譯核心是乙個是否花費時間的工作,所以有了核心模組的概念。 模組並不編譯到核心中,編譯後存放在指定的目錄,當需要使用時動態載入。
Linux裝置驅動程式 字元裝置驅動程式設計
linux對裝置的操作與對檔案的操作是一樣的,可以看到乙個裝置所對應的檔案。我們平時用的read write等函式也可以用於裝置檔案。字元裝置 以字元為單位 按照順利操作 沒有快取區,故不支援隨機讀寫 例外 幀快取裝置,如顯示卡,是可以隨機訪問的 裝置號由主裝置號與次裝置號組成。主裝置號標識裝置對應...
字元裝置驅動 架構分析
好長時間沒怎麼看書了,最近把字元裝置驅動部分又複習了一下,寫個筆記.char device driver 相關資料結構 struct cdev struct kobj map probes 255 struct mutex lock static struct char device struct ...
Linux裝置驅動程式設計例項
linux系統中,裝置驅動程式是作業系統核心的重要組成部分,在 與硬體裝置之間 建立了標準的抽象介面。通過這個介面,使用者可以像處理普通檔案一樣,對硬體設 備進行開啟 open 關閉 close 讀寫 read write 等操作。通過分析和設計設 備驅動程式,可以深入理解linux系統和進行系統開...