1. 程式人生 > >字元裝置的核心抽象

字元裝置的核心抽象

Linux核心中處處體現面向物件的設計思想,為了統一形形色色的裝置,Linux系統將裝置分為三類:字元裝置、塊裝置、網路裝置。並將其分別抽象為struct cdev,struct block_device,struct net_devce三個物件,具體的裝置都可以包含著三種物件從而繼承和三種物件屬性和操作,並通過各自的物件新增到相應的驅動模型中,從而進行統一的管理和操作。
顧名思義,字元裝置驅動程式管理的是核心物件是字元裝置。從字元裝置的設計框架角度出發,核心為字元裝置抽象出了一個具體的資料結構struct cdev,定義如下:

#include <linux/cdev.h>
struct cdev { struct kobject kobj; struct module *owner; const struct file_operations *ops; struct list_head list; dev_t dev; unsigned int count; };

各成員描述如下:
struct kobject kobj
內嵌的核心物件,通過它將裝置統一加入到“Linux裝置驅動模型”中管理(如物件的引用計數、電源管理、熱插拔、生命週期、與使用者通訊等)。
struct module *owner
字元裝置驅動程式所在的核心模組物件的指標。
const struct file_operations *ops
檔案操作,是字元裝置驅動中非常重要的資料結構,在應用程式通過檔案系統(VFS)呼叫到裝置裝置驅動程式中實現的檔案操作類函式過程中,ops起著橋樑紐帶作用,VFS與檔案系統及裝置檔案之間的介面是file_operations結構體成員函式,這個結構體包含了對檔案進行開啟、關閉、讀寫、控制等一系列成員函式。
struct list_head list
用於將系統中的字元裝置形成連結串列(這是個核心連結串列的一個連結因子,可以再核心很多結構體中看到這種結構的身影)。
dev_t dev
字元裝置的裝置號,有主裝置和次裝置號構成。
unsigned int count
屬於同一主裝置好的次裝置號的個數,用於表示裝置驅動程式控制的實際同類裝置的數量。

以下是具體裝置與cdev的關係:
這裡寫圖片描述

我們知道了具體的字元裝置可以通過cdev來管理字元裝置,那麼我們如何能夠在驅動中通過cdev來找到我們具體的裝置呢?C語言中沒有面向物件語言的繼承的語法,但是我們可以通過結構體的包含來實現繼承,例如一個字元裝置adc_dev 結構體如下(這個一個能夠進行ad採集裝置):

struct adc_dev {
    unsigned int __iomem *adccon;
    unsigned int __iomem *adcdat;
    unsigned int __iomem *clrint;
    unsigned int __iomem *adcmux;

    unsigned
int adcval; struct completion completion; atomic_t available; unsigned int irq; struct cdev cdev; };

可以看到,這個裝置結構體中包含著操作此裝置的記憶體資訊、中斷資訊等,其中就嵌入了cdev結構體,然後通過字元裝置的驅動框架就可以將此設備註冊進Linux系統。
一般在驅動中我們很容易就能知道cdev指標的值,那麼我們可以通過cdev來找到裝置結構體adc_dev,核心提供瞭如下的巨集介面:

#define container_of(ptr, type, member) ({          \
    const typeof(((type *)0)->member) * __mptr = (ptr); \
    (type *)((char *)__mptr - offsetof(type, member)); })

此介面的具體實現在這不在贅述,詳見核心連結串列相關文章。
現在我們來使用此介面獲得我們的裝置結構體:
int adc_open(struct inode *inode,struct file *filep)
{
struct adc_dev adc_devp;
adc_devp = container_of(inode->i_cdev, struct cdev, cdev);

return 0;
}

非常簡單是不是,其中container_of介面的ptr是內嵌的cdev的記憶體地址,type為資料型別此處為struct cdev,member為內嵌的成員名此處為cdev。
由於Linux系統要管理成百上千中裝置,所以這種抽象非常重要且有必要,它提取並抽象了裝置的共性,為上層提供統一介面,使得管理和操作裝置變的容易。