1. 程式人生 > >字符設備驅動之結構體

字符設備驅動之結構體

廣泛 情況 ref ger 重要 目錄 AR fop https

https://blog.csdn.net/tigerjibo/article/details/6412469
大部分驅動程序操作都涉及到三個重要的內核數據結構,分別是file_operations、file和inode,它們定義在<linux/fs.h>

1、file_operations:是一個函數指針的集合
1>應用程序和VFS之間的接口是系統調用,而VFS與磁盤文件系統以及普通設備之間的接口是file_operations結構體成員函數。file_operations結構體中成員函數是字符設備驅動與內核的接口,是用戶空間對linux進行系統調用的最終落實者,這個結構體包含對文件打開,關閉,讀寫,控制的一系列成員函數

2>由於字符設備的上層沒有磁盤文件系統,所以字符設備的file_operations成員函數就直接由設備驅動提供了,file_operations正是字符設備驅動的核心
3>對於塊設備而言,ext2,fat,jffs2等文件系統中會實現對VFS的file_operations成員函數,設備驅動層看不到file_operations的存在。磁盤文件系統和設備驅動會將磁盤上的文件的訪問最終轉換成對磁盤上柱面和扇區的訪問
4>file_operations的成員:

static const struct file_operations XXX_fops =
{
.owner = THIS_MODULE,

.llseek = XXX_llseek,
.open = XXX _open,
.read = XXX _read,
.write = XXX _write,
.ioctl = XXX _ioctl,
.release = XXX _release,
};

1>struct module owner:第一個file_operations成員根本不是一個操作,它是一個指向擁有這個結構的模塊的指針。這個成員用來在他的操作還在被使用時阻止模型被卸載。幾乎所有程序中,它被簡單初始化為THIS_MODULE,一個<linux/module.h>中定義的宏
2> loff_t (

llseek) (struct file *, loff_t, int);
文件定位函數,合法時返回文件的當前位置,不合法返回-EINVAL
第一個參數為file指針
第二個為請求偏移量
第三個為文件定位的起始地址:一般為0或1,0表示文件開頭,1表示當前位置

3> ssize_t (read) (struct file , char __user , size_t, loff_t );讀函數,利用copy_to_user()函數讓內核讀取用戶空間的數據,並返回訪問的字節數
4> ssize_t (write) (struct file , const char __user , size_t, loff_t );寫函數利用copy_from_user()函數讓用戶向文件寫入數據,並返回寫入的字節數
5> int (ioctl) (struct inode , struct file , unsigned int, unsigned long);執行I/O控制命令
6> int (
open) (struct inode , struct file );打開文件
7>int (release) (struct inode , struct file *);關閉文件

  1. struct file:文件結構體
    1>文件結構體代表一個打開的文件(設備對應於設備文件),系統中每個打開的文件在內核空間都有一個關聯的struct file。它由內核在打開文件時創建,並傳遞給在文件上進行操作的任何函數。在文件的所有實例都關閉之後,內核釋放這個數據結構
    2>字符設備驅動用到的變量,文件讀寫模型mode,標識f_flags都是設備關系的內容,而私有數據指針private_data在設備驅動中被廣泛使用,大多數被用於指向設備驅動自定義的設備結構體
    3>struct file

struct file {
940 /
941
fu_list becomes invalid after file_free is called and queued via
942 * fu_rcuhead for RCU freeing
943 /
951 const struct file_operations
f_op;
957 unsigned int f_flags;
958 fmode_t f_mode;
959 loff_t f_pos;
960 struct fown_struct f_owner;
969 void *private_data;
970
979};

1> fmode_t f_mode:通過宏 FMODE_READ 和 FMODE_WRITE.確定文件是可讀/可寫/可讀寫。你可能想在你的open或者ioctl函數中檢查這個成員的讀寫許可,但是你不需要檢查讀寫許可,因為內核在調用你的方法之前檢查。當文件還沒有為那種存取而打開時讀或者寫的企圖被拒絕,驅動甚至不知道這個情況。
2>unsigned int f_flags:這些是文件標誌, 例如 O_RDONLY, O_NONBLOCK, 和 O_SYNC. 驅動應當檢查 O_NONBLOCK 標誌來看是否是請求非阻塞操作;其他標誌很少使用. 所有的標誌在頭文件 <linux/fcntl.h> 中定義.
3> void private_data:open系統調用設置這個指針為Null,在為驅動調用open之前,你可以自由使用這個成員或者忽略它;你可以使用這個成員來指向分配的數據,但是接著你必須記住在內核銷毀文件結構之前,在release方法中釋放那個內存。private_data是一個有用的資源,在系統調用間保留狀態信息。
4> loff_t f_pos:當前讀寫位置。loft_t在所有平臺都是64位(ggc術語是long long)。驅動可以讀這個值,如果它需要知道文件中的當前位置,但是正常地不應該改變它; 讀和寫應當使用它們作為最後參數而收到的指針來更新一個位置, 代替直接作用於 filp->f_pos. 這個規則的一個例外是在 llseek 方法中, 它的目的就是改變文件位置.
5> struct file_operations
f_op: 和文件關聯的操作. 內核安排指針作為它的 open 實現的一部分, 接著讀取它當它需要分派任何的操作時. filp->f_op 中的值從不由內核保存為後面的引用; 這意味著你可改變你的文件關聯的文件操作, 在你返回調用者之後新方法會起作用. 例如, 關聯到主編號 1 (/dev/null, /dev/zero, 等等)的 open 代碼根據打開的次編號來替代 filp->f_op 中的操作. 這個做法允許實現幾種行為, 在同一個主編號下而不必在每個系統調用中引入開銷. 替換文件操作的能力是面向對象編程的"方法重載"的內核對等體

4>驅動程序中經常會使用如下類似的代碼來檢測用戶打開文件的讀寫方式。

if (flie->f_mode & FMODE_WRITE)//用戶要求可寫
{

}
4>用下面的代碼判斷以阻塞還是非阻塞方式打開設備文件
if (file->f_flags & O_NONBLOCK)//非阻塞
{

}
else //阻塞
{

}

3.struct inode 結構

虛擬文件系統中的每個文件都關聯到一個inode,用於管理文件的屬性(包含文件訪問權限,屬主,組,大小,生成時間,訪問時間,最後修改時間等信息,它是Linux管理文件系統的最基本單位,也是文件系統連接任何子目錄,文件的橋梁)

struct inode {
741 /* RCU path lookup touches following: /
742 umode_t i_mode;
766 dev_t i_rdev;
786 struct list_head i_devices;
787 union {
788 struct pipe_inode_info
i_pipe;
789 struct block_device i_bdev;
790 struct cdev
i_cdev;
791 };
812 void i_private; / fs or device private pointer /
};
1>i_mode:為唯一地標示與一個設備文件關聯的設備,內核在i_mode中存儲了文件類型(面向塊/字符)
2>i_rdev:存儲了主從設備號。主從設備號在內核中合並為一種變量類型dev_t
3>i_fop:是一組函數指針的集合,包括許多文件操作如打開/讀取/寫入等,這些由虛擬文件系統使用來處理塊設備。
4>內核會根據inode標示塊設備還是字符設備,來使用i_bdev或者i_cdev指向更多具體的信息。對於代表設備文件的節點,這個成員包含實際的設備編號
5>struct cdev
i_dev:struct cdev是內核的內部結構,代表字符設備;這個成員包含一個指針,指向這個結構, 當節點指的是一個字符設備文件時.

4.cdev結構體

在linux中使用cdev結構體描述字符設備,cdev結構體定義:

12struct cdev {
13 struct kobject kobj;
14 struct module owner;
15 const struct file_operations
ops;
16 struct list_head list;
17 dev_t dev;
18 unsigned int count;
19};
1>kobj是一個嵌入在該結構中的內核對象。它用於該數據結構的一般管理(是一個重要的數據結構,後在後面對其進行詳細的介紹)
2>owner指向提供驅動程序的模塊
3>ops是一組文件操作,實現了與硬件通信的具體操作

字符設備驅動之結構體