小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

設備模型(總線、設備、驅動程序和類)

 WUCANADA 2012-06-10


Linux設備驅動程序學習(13)

-Linux設備模型(總線、設備、驅動程序和類)


文章的例子和實驗使用《LDD3》所配的lddbus模塊(稍作修改)。

提示:在學習這部分內容是一定要分析所有介紹的源代碼,知道他們與上一部分內容(kobject、kset、attribute等等)的關系,最好要分析一個實際的“flatform device”設備,不然會只學到表象,到后面會不知所云的。

總線

總線是處理器和一個或多個設備之間的通道,在設備模型中, 所有的設備都通過總線相連, 甚至是內部的虛擬"platform"總線。總線可以相互插入。設備模型展示了總線和它們所控制的設備之間的實際連接。
在 Linux 設備模型中, 總線由 bus_type 結構表示, 定義在 <linux/device.h>

struct bus_type {
    const char        * name;/*總線類型名稱*/
    struct module        * owner;/*指向模塊的指針(如果有), 此模塊負責操作這個總線*/

    struct kset        subsys;/*與該總線相關的子系統(tǒng)*/
    struct kset        drivers;/*總線驅動程序的kset*/
    struct kset        devices;/* 掛在該總線的所有設備的kset*/

    struct klist        klist_devices;/*與該總線相關的驅動程序鏈表*/
    struct klist        klist_drivers;/*掛接在該總線的設備鏈表*/

    struct blocking_notifier_head bus_notifier;

    struct bus_attribute    * bus_attrs; /*總線屬性*/
    struct device_attribute * dev_attrs; /*設備屬性,指向為每個加入總線的設備建立的默認屬性鏈表*/
    struct driver_attribute * drv_attrs; /*驅動程序屬性*/
    struct bus_attribute drivers_autoprobe_attr;/*驅動自動探測屬性*/
    struct bus_attribute drivers_probe_attr;/*驅動探測屬性*/

    int        (*match)(struct device * dev, struct device_driver * drv);
    int        (*uevent)(struct device *dev, char **envp,
                 int num_envp, char *buffer, int buffer_size);
    int        (*probe)(struct device * dev);
    int        (*remove)(struct device * dev);
    void        (*shutdown)(struct device * dev);

    int (*suspend)(struct device * dev, pm_message_t state);
    int (*suspend_late)(struct device * dev, pm_message_t state);
    int (*resume_early)(struct device * dev);
    nt (*resume)(struct device * dev);
/*處理熱插拔、電源管理、探測和移除等事件的方法*/
    unsigned int drivers_autoprobe:1;
};


在更新的內核里,這個結構體變得更簡潔了,隱藏了無需驅動編程人員知道的一些成員:

 

/*in Linux 2.6.26.5*/

struct bus_type {
    const char        *name;
    struct bus_attribute    *bus_attrs;
    struct device_attribute    *dev_attrs;
    struct driver_attribute    *drv_attrs;

    int (*match)(struct device *dev, struct device_driver *drv);
    int (*uevent)(struct device *dev, struct kobj_uevent_env *env);
    int (*probe)(struct device *dev);
    int (*remove)(struct device *dev);
    void (*shutdown)(struct device *dev);

    int (*suspend)(struct device *dev, pm_message_t state);
    int (*suspend_late)(struct device *dev, pm_message_t state);
    int (*resume_early)(struct device *dev);
    int (*resume)(struct device *dev);

    struct bus_type_private *p;
};

struct bus_type_private {
    struct kset subsys;
    struct kset *drivers_kset;
    struct kset *devices_kset;
    struct klist klist_devices;
    struct klist klist_drivers;
    struct blocking_notifier_head bus_notifier;
    unsigned int drivers_autoprobe:1;
    struct bus_type *bus;
};

總線的注冊和刪除

總線的主要注冊步驟:

(1)申明和初始化 bus_type 結構體。只有很少的 bus_type 成員需要初始化,大部分都由設備模型核心控制。但必須為總線指定名字及一些必要的方法。例如:

struct bus_type ldd_bus_type = {
    .name = "ldd",
    .match = ldd_match,
    .uevent = ldd_uevent,
};

(2)調用bus_register函數(shù)注冊總線。

int bus_register(struct bus_type * bus)

調用可能失敗, 所以必須始終檢查返回值。若成功,新的總線子系統(tǒng)將被添加進系統(tǒng),并可在 sysfs 的 /sys/bus 下看到。之后可以向總線添加設備。
例如:

ret = bus_register(&ldd_bus_type);
if (ret)
 return ret;

 
當必須從系統(tǒng)中刪除一個總線時, 調用:

void bus_unregister(struct bus_type *bus);

總線方法

在 bus_type 結構中定義了許多方法,它們允許總線核心作為設備核心和單獨的驅動程序之間提供服務的中介,主要介紹以下兩個方法:

int (*match)(struct device * dev, struct device_driver * drv);
/*當一個新設備或者驅動被添加到這個總線時,這個方法會被調用一次或多次,若指定的驅動程序能夠處理指定的設備,則返回非零值。必須在總線層使用這個函數(shù), 因為那里存在正確的邏輯,核心內核不知道如何為每個總線類型匹配設備和驅動程序*/

int (*uevent)(struct device *dev, char **envp, int num_envp, char *buffer, int buffer_size);
/*在為用戶空間產(chǎn)生熱插拔事件之前,這個方法允許總線添加環(huán)境變量(參數(shù)和 kset 的uevent方法相同)*/

lddbus的match和uevent方法:

static int ldd_match(struct device *dev, struct device_driver *driver)
{
 return !strncmp(dev->bus_id, driver->name, strlen(driver->name));
}/*僅簡單比較驅動和設備的名字*/
/*當涉及實際硬件時, match 函數(shù)常常對設備提供的硬件 ID 和驅動所支持的 ID 做比較*/

static int ldd_uevent(struct device *dev, char **envp, int num_envp, char *buffer, int buffer_size)
{
 envp[0] = buffer;
 if (snprintf(buffer, buffer_size, "LDDBUS_VERSION=%s",
 Version) >= buffer_size)
 return -ENOMEM;
 envp[1] = NULL;
 return 0;
}/*在環(huán)境變量中加入 lddbus 源碼的當前版本號*/

對設備和驅動的迭代

若要編寫總線層代碼, 可能不得不對所有已經(jīng)注冊到總線的設備或驅動進行一些操作,這可能需要仔細研究嵌入到 bus_type 結構中的其他數(shù)據(jù)結構, 但最好使用內核提供的輔助函數(shù):

int bus_for_each_dev(struct bus_type *bus, struct device *start, void *data, int (*fn)(struct device *, void *));
int bus_for_each_drv(struct bus_type *bus, struct device_driver *start, void *data, int (*fn)(struct device_driver *, void *));

/* 這兩個函數(shù)迭代總線上的每個設備或驅動程序, 將關聯(lián)的 device 或 device_driver 傳遞給 fn, 同時傳遞 data 值。若 start 為 NULL, 則從第一個設備開始; 否則從 start 之后的第一個設備開始。若 fn 返回非零值, 迭代停止并且那個值從 bus_for_each_dev 或bus_for_each_drv 返回。*/

總線屬性

幾乎 Linux 設備模型中的每一層都提供添加屬性的函數(shù), 總線層也不例外。bus_attribute 類型定義在 <linux/device.h> 如下:

struct bus_attribute {
    struct attribute    attr;
    ssize_t (*show)(struct bus_type *, char * buf);
    ssize_t (*store)(struct bus_type *, const char * buf, size_t count);
};


可以看出struct bus_attribute 和struct attribute 很相似,其實大部分在 kobject 級上的設備模型層都是以這種方式工作。

內核提供了一個宏在編譯時創(chuàng)建和初始化 bus_attribute 結構:

BUS_ATTR(_name,_mode,_show,_store)/*這個宏聲明一個結構, 將 bus_attr_ 作為給定 _name 的前綴來創(chuàng)建總線的真正名稱*/

/*總線的屬性必須顯式調用 bus_create_file 來創(chuàng)建:*/
int bus_create_file(struct bus_type *bus, struct bus_attribute *attr);

/*刪除總線的屬性調用:*/
void bus_remove_file(struct bus_type *bus, struct bus_attribute *attr);

例如創(chuàng)建一個包含源碼版本號簡單屬性文件方法如下:

static ssize_t show_bus_version(struct bus_type *bus, char *buf)
{
 return snprintf(buf, PAGE_SIZE, "%s\n", Version);
}

static BUS_ATTR(version, S_IRUGO, show_bus_version, NULL);

/*在模塊加載時創(chuàng)建屬性文件:*/
if (bus_create_file(&ldd_bus_type, &bus_attr_version))
 printk(KERN_NOTICE "Unable to create version attribute\n");

/*這個調用創(chuàng)建一個包含 lddbus 代碼的版本號的屬性文件(/sys/bus/ldd/version)*/


設備

在最底層, Linux 系統(tǒng)中的每個設備由一個 struct device 代表:

struct device {
    struct klist        klist_children;
    struct klist_node    knode_parent;   /* node in sibling list */
    struct klist_node    knode_driver;
    struct klist_node    knode_bus;
    struct device        *parent;/* 設備的 "父" 設備,該設備所屬的設備,通常一個父設備是某種總線或者主控制器. 如果 parent 是 NULL, 則該設備是頂層設備,較少見 */

    struct kobject kobj;/*代表該設備并將其連接到結構體系中的 kobject; 注意:作為通用的規(guī)則, device->kobj->parent 應等于 device->parent->kobj*/
    char    bus_id[BUS_ID_SIZE];/*在總線上唯一標識該設備的字符串;例如: PCI 設備使用標準的 PCI ID 格式, 包含:域, 總線, 設備, 和功能號.*/
    struct device_type    *type;
    unsigned        is_registered:1;
    unsigned        uevent_suppress:1;
    struct device_attribute uevent_attr;
    struct device_attribute *devt_attr;

    struct semaphore    sem;  /* semaphore to synchronize calls to its driver. */
    struct bus_type    * bus;     /*標識該設備連接在何種類型的總線上*/
    struct device_driver *driver;    /*管理該設備的驅動程序*/
    void        *driver_data;    /*該設備驅動使用的私有數(shù)據(jù)成員*/
    void        *platform_data;    /* Platform specific data, device core doesn't touch it */
    struct dev_pm_info    power;

#ifdef CONFIG_NUMA
    int        numa_node;   /* NUMA node this device is close to */
#endif
    u64        *dma_mask;    /* dma mask (if dma'able device) */
    u64        coherent_dma_mask;
/* Like dma_mask, but for
                     alloc_coherent mappings as
                     not all hardware supports
                     64 bit addresses for consistent
                     allocations such descriptors. */


    struct list_head    dma_pools;    /* dma pools (if dma'ble) */

    struct dma_coherent_mem    *dma_mem; /* internal for coherent mem override */
    /* arch specific additions */
    struct dev_archdata    archdata;

    spinlock_t        devres_lock;
    struct list_head    devres_head;

    /* class_device migration path */
    struct list_head    node;
    struct class        *class;
    dev_t          devt;       /* dev_t, creates the sysfs "dev" */
    struct attribute_group    **groups;    /* optional groups */

    void    (*release)(struct device * dev);/*當這個設備的最后引用被刪除時,內核調用該方法; 它從被嵌入的 kobject 的 release 方法中調用。所有注冊到核心的設備結構必須有一個 release 方法, 否則內核將打印錯誤信息*/
};
/*在注冊 struct device 前,最少要設置parent, bus_id, bus, 和 release 成員*/

設備注冊

設備的注冊和注銷函數(shù)為:

int device_register(struct device *dev);
void device_unregister(struct device *dev);

一個實際的總線也是一個設備,所以必須單獨注冊,以下為 lddbus 在編譯時注冊它的虛擬總線設備源碼:

static void ldd_bus_release(struct device *dev)
{
 printk(KERN_DEBUG "lddbus release\n");
}

struct device ldd_bus = {
 .bus_id = "ldd0",
 .release = ldd_bus_release

}; /*這是頂層總線,parent 和 bus 成員為 NULL*/

/*作為第一個(并且唯一)總線, 它的名字為 ldd0,這個總線設備的注冊代碼如下:*/
ret = device_register(&ldd_bus);
if (ret)
 printk(KERN_NOTICE "Unable to register ldd0\n");
/*一旦調用完成, 新總線會在 sysfs 中 /sys/devices 下顯示,任何掛到這個總線的設備會在 /sys/devices/ldd0 下顯示*/

設備屬性

sysfs 中的設備入口可有屬性,相關的結構是:

/* interface for exporting device attributes 這個結構體和《LDD3》中的不同,已經(jīng)被更新過了,請?zhí)貏e注意!*/
struct device_attribute {
    struct attribute attr;
    ssize_t (*show)(struct device *dev, struct device_attribute *attr,char *buf);
    ssize_t (*store)(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
};

/*設備屬性結構可在編譯時建立, 使用以下宏:*/
DEVICE_ATTR(_name,_mode,_show,_store);
/*這個宏聲明一個結構, 將 dev_attr_ 作為給定 _name 的前綴來命名設備屬性

/*屬性文件的實際處理使用以下函數(shù):*/

 int device_create_file(struct device *device,    struct device_attribute * entry);
 void device_remove_file(struct device * dev, struct device_attribute * attr);

設備結構的嵌入

device 結構包含設備模型核心用來模擬系統(tǒng)的信息。但大部分子系統(tǒng)記錄了關于它們又擁有的設備的額外信息,所以很少單純用 device 結構代表設備,而是,通常將其嵌入一個設備的高層表示中。底層驅動幾乎不知道 struct device。

lddbus 驅動創(chuàng)建了它自己的 device 類型,并期望每個設備驅動使用這個類型來注冊它們的設備:

struct ldd_device {
 char *name;
 struct ldd_driver *driver;
 struct device dev;
};
#define to_ldd_device(dev) container_of(dev, struct ldd_device, dev);

lddbus 導出的注冊和注銷接口如下:

/*
 * LDD devices.
 */


/*
 * For now, no references to LDDbus devices go out which are not
 * tracked via the module reference count, so we use a no-op
 * release function.
 */

static void ldd_dev_release(struct device *dev)
{ }

int register_ldd_device(struct ldd_device *ldddev)
{
    ldddev->dev.bus = &ldd_bus_type;
    ldddev->dev.parent = &ldd_bus;
    ldddev->dev.release = ldd_dev_release;
    strncpy(ldddev->dev.bus_id, ldddev->name, BUS_ID_SIZE);
    return device_register(&ldddev->dev);
}
EXPORT_SYMBOL(register_ldd_device);

void unregister_ldd_device(struct ldd_device *ldddev)
{
    device_unregister(&ldddev->dev);
}
EXPORT_SYMBOL(unregister_ldd_device);


 sculld 驅動添加一個自己的屬性到它的設備入口,稱為 dev, 僅包含關聯(lián)的設備號,源碼如下:

static ssize_t sculld_show_dev(struct device *ddev,struct device_attribute *attr, char *buf)
{
 struct sculld_dev *dev = ddev->driver_data;
 return print_dev_t(buf, dev->cdev.dev);
}

static DEVICE_ATTR(dev, S_IRUGO, sculld_show_dev, NULL);

/*接著, 在初始化時間, 設備被注冊, 并且 dev 屬性通過下面的函數(shù)被創(chuàng)建:*/
static void sculld_register_dev(struct sculld_dev *dev, int index)
{
 sprintf(dev->devname, "sculld%d", index);
 dev->ldev.name = dev->devname;
 dev->ldev.driver = &sculld_driver;
 dev->ldev.dev.driver_data = dev;
 register_ldd_device(&dev->ldev);
 if (device_create_file(&dev->ldev.dev, &dev_attr_dev))
    printk( "Unable to create dev attribute ! \n");
} /*注意:程序使用 driver_data 成員來存儲指向我們自己的內部的設備結構的指針。請檢查
device_create_file的返回值,否則編譯時會有警告。*/


設備驅動程序

設備模型跟蹤所有系統(tǒng)已知的驅動,主要目的是使驅動程序核心能協(xié)調驅動和新設備之間的關系。一旦驅動在系統(tǒng)中是已知的對象就可能完成大量的工作。驅動程序的結構體 device_driver 定義如下:

/*定義在<linux/device.h>*/
struct device_driver {
    const char        * name;/*驅動程序的名字( 在 sysfs 中出現(xiàn) )*/
    struct bus_type        * bus;/*驅動程序所操作的總線類型*/

    struct kobject        kobj;/*內嵌的kobject對象*/
    struct klist        klist_devices;/*當前驅動程序能操作的設備鏈表*/
    struct klist_node    knode_bus;

    struct module        * owner;
    const char         * mod_name;    /* used for built-in modules */
    struct module_kobject    * mkobj;

    int    (*probe)    (struct device * dev);/*查詢一個特定設備是否存在及驅動是否可以使用它的函數(shù)*/
    int    (*remove)    (struct device * dev);/*將設備從系統(tǒng)中刪除*/
    void    (*shutdown)    (struct device * dev);/*關閉設備*/
    int    (*suspend)    (struct device * dev, pm_message_t state);
    int    (*resume)    (struct device * dev);
};

/*注冊device_driver 結構的函數(shù)是:*/
int driver_register(struct device_driver *drv);
void driver_unregister(struct device_driver *drv);

/*driver的屬性結構在:*/
struct driver_attribute {
 struct attribute attr;
 ssize_t (*show)(struct device_driver *drv, char *buf);
 ssize_t (*store)(struct device_driver *drv, const char *buf, size_t count);
};
DRIVER_ATTR(_name,_mode,_show,_store)

/*屬性文件創(chuàng)建的方法:*/
int driver_create_file(struct device_driver * drv, struct driver_attribute * attr);
void driver_remove_file(struct device_driver * drv, struct driver_attribute * attr);

/*bus_type 結構含有一個成員( drv_attrs ) 指向一組為屬于該總線的所有設備創(chuàng)建的默認屬性*/


在更新的內核里,這個結構體變得更簡潔了,隱藏了無需驅動編程人員知道的一些成員:

/*in Linux 2.6.26.5*/

struct device_driver {
    const char        *name;
    struct bus_type        *bus;

    struct module        *owner;
    const char         *mod_name;    /* used for built-in modules */

    int (*probe) (struct device *dev);
    int (*remove) (struct device *dev);
    void (*shutdown) (struct device *dev);
    int (*suspend) (struct device *dev, pm_message_t state);
    int (*resume) (struct device *dev);
    struct attribute_group **groups;

    struct driver_private *p;
};


struct driver_private {
    struct kobject kobj;
    struct klist klist_devices;
    struct klist_node knode_bus;
    struct module_kobject *mkobj;
    struct device_driver *driver;
};
#define to_driver(obj) container_of(obj, struct driver_private, kobj)


驅動程序結構的嵌入

對大多數(shù)驅動程序核心結構, device_driver 結構通常被嵌入到一個更高層的、總線相關的結構中。

以lddbus 子系統(tǒng)為例,它定義了ldd_driver 結構:

struct ldd_driver {
 char *version;
 struct module *module;
 struct device_driver driver;
 struct driver_attribute version_attr;
};
#define to_ldd_driver(drv) container_of(drv, struct ldd_driver, driver);

lddbus總線中相關的驅動注冊和注銷函數(shù)是:

/*
 * Crude driver interface.
 */

static ssize_t show_version(struct device_driver *driver, char *buf)
{
    struct ldd_driver *ldriver = to_ldd_driver(driver);
    sprintf(buf, "%s\n", ldriver->version);
    return strlen(buf);
}

int register_ldd_driver(struct ldd_driver *driver)
{
 int ret;
 driver->driver.bus = &ldd_bus_type;
 ret = driver_register(&driver->driver);/*注冊底層的 device_driver 結構到核心*/
 if (ret)
 return ret;
 driver->version_attr.attr.name = "version";/* driver_attribute 結構必須手工填充*/
 driver->version_attr.attr.owner = driver->module;/* 注意:設定 version 屬性的擁有者為驅動模塊, 不是 lddbus 模塊!因為 show_version 函數(shù)是使用驅動模塊所創(chuàng)建的 ldd_driver 結構,若 ldd_driver 結構在一個用戶空間進程試圖讀取版本號時已經(jīng)注銷,就會出錯*/
 driver->version_attr.attr.mode = S_IRUGO;
 driver->version_attr.show = show_version;
 driver->version_attr.store = NULL;
 return driver_create_file(&driver->driver, &driver->version_attr);/*建立版本屬性,因為這個屬性在運行時被創(chuàng)建,所以不能使用 DRIVER_ATTR 宏*/
}

void unregister_ldd_driver(struct ldd_driver *driver)
{
    driver_unregister(&driver->driver);
}
EXPORT_SYMBOL(register_ldd_driver);
EXPORT_SYMBOL(unregister_ldd_driver);

在sculld 中創(chuàng)建的 ldd_driver 結構如下:

/* Device model stuff */
static struct ldd_driver sculld_driver = {
    .version = "$Revision: 1.21 $",
    .module = THIS_MODULE,
    .driver = {
        .name = "sculld",
    },
};/*只要一個簡單的 register_ldd_driver 調用就可添加它到系統(tǒng)中。一旦完成初始化, 驅動信息可在 sysfs 中顯示*/


類 子系統(tǒng)

類是一個設備的高層視圖, 它抽象出了底層的實現(xiàn)細節(jié),從而允許用戶空間使用設備所提供的功能, 而不用關心設備是如何連接和工作的。類成員通常由上層代碼所控制, 而無需驅動的明確支持。但有些情況下驅動也需要直接處理類。

幾乎所有的類都顯示在 /sys/class 目錄中。出于歷史的原因,有一個例外:塊設備顯示在 /sys/block目錄中。在許多情況, 類子系統(tǒng)是向用戶空間導出信息的最好方法。當類子系統(tǒng)創(chuàng)建一個類時, 它將完全擁有這個類,根本不用擔心哪個模塊擁有那些屬性,而且信息的表示也比較友好。

為了管理類,驅動程序核心導出了一些接口,其目的之一是提供包含設備號的屬性以便自動創(chuàng)建設備節(jié)點,所以udev的使用離不開類。 類函數(shù)和結構與設備模型的其他部分遵循相同的模式,所以真正嶄新的概念是很少的。

注意:class_simple 是老接口,在2.6.13中已被刪除,這里不再研究。

管理類的接口

類由 struct class 的結構體來定義:

/*
 * device classes
 */

struct class {
    const char        * name;/*每個類需要一個唯一的名字, 它將顯示在 /sys/class 中*/
    struct module        * owner;

    struct kset        subsys;
    struct list_head    children;
    struct list_head    devices;
    struct list_head    interfaces;
    struct kset        class_dirs;
    struct semaphore    sem;    /* locks both the children and interfaces lists */

    struct class_attribute        * class_attrs;/* 指向類屬性的指針(以NULL結尾) */
    struct class_device_attribute    * class_dev_attrs;/* 指向類中每個設備的一組默認屬性的指針 */
    struct device_attribute        * dev_attrs;

    int    (*uevent)(struct class_device *dev, char **envp,
             int num_envp, char *buffer, int buffer_size);/* 類熱插拔產(chǎn)生時添加環(huán)境變量的函數(shù) */
    int    (*dev_uevent)(struct device *dev, char **envp, int num_envp,
                char *buffer, int buffer_size);/* 類中的設備熱插拔時添加環(huán)境變量的函數(shù) */

    void    (*release)(struct class_device *dev);/* 把設備從類中刪除的函數(shù) */
    void    (*class_release)(struct class *class);/* 刪除類本身的函數(shù) */
    void    (*dev_release)(struct device *dev);

    int    (*suspend)(struct device *, pm_message_t state);
    int    (*resume)(struct device *);
};


/*類注冊函數(shù):*/
int class_register(struct class *cls);
void class_unregister(struct class *cls);

/*類屬性的接口:*/
struct class_attribute {
 struct attribute attr;
 ssize_t (*show)(struct class *cls, char *buf);
 ssize_t (*store)(struct class *cls, const char *buf, size_t count);
};
CLASS_ATTR(_name,_mode,_show,_store);
int class_create_file(struct class *cls, const struct class_attribute *attr);
void class_remove_file(struct class *cls, const struct class_attribute *attr);


在更新的內核里,這個結構體變得簡潔了,刪除了一些成員:

/*in Linux 2.6.26.5*/

/*
 * device classes
 */

struct class {
    const char        *name;
    struct module        *owner;

    struct kset        subsys;
    struct list_head    devices;
    struct list_head    interfaces;
    struct kset        class_dirs;
    struct semaphore    sem; /* locks children, devices, interfaces */
    struct class_attribute        *class_attrs;
    struct device_attribute        *dev_attrs;

    int (*dev_uevent)(struct device *dev, struct kobj_uevent_env *env);

    void (*class_release)(struct class *class);
    void (*dev_release)(struct device *dev);

    int (*suspend)(struct device *dev, pm_message_t state);
    int (*resume)(struct device *dev);
};

類設備(在新內核中已被刪除)

類存在的真正目的是給作為類成員的各個設備提供一個容器,成員由 struct class_device 來表示:

struct class_device {
    
struct list_head    node;/*for internal use by the driver core only*/
    
struct kobject        kobj;/*for internal use by the driver core only*/
    
struct class        * class;    /* 指向該設備所屬的類,必須*/
    dev_t            devt
;        /* dev_t, creates the sysfs "dev" ,for internal use by the driver core only*/
    
struct class_device_attribute *devt_attr;/*for internal use by the driver core only*/
    
struct class_device_attribute uevent_attr;
    
struct device        * dev;        /* 指向此設備相關的 device 結構體,可選。若不為NULL,應是一個從類入口到/sys/devices 下相應入口的符號連接,以便用戶空間查找設備入口*/
    
void            * class_data;    /* 私有數(shù)據(jù)指針 */
    
struct class_device    *parent;    /* parent of this child device, if there is one */
    
struct attribute_group ** groups;    /* optional groups */

    
void    (*release)(struct class_device *dev);
    
int    (*uevent)(struct class_device *dev, char **envp,
            
int num_envp, char *buffer, int buffer_size);
    
char    class_id[BUS_ID_SIZE];    /* 此類中的唯一的名字 */
};

/*類設備注冊函數(shù):*/
int class_device_register(struct class_device *cd);
void class_device_unregister(struct class_device *cd);

/*重命名一個已經(jīng)注冊的類設備入口:*/
int class_device_rename(struct class_device *cd, char *new_name);

/*類設備入口屬性:*/
struct class_device_attribute {
 
struct attribute attr;
 ssize_t
(*show)(struct class_device *cls, char *buf);
 ssize_t
(*store)(struct class_device *cls, const char *buf,
 
size_t count);
};

CLASS_DEVICE_ATTR
(_name, _mode, _show, _store);

/*創(chuàng)建和刪除除struct class中設備默認屬性外的屬性*/
int class_device_create_file(struct class_device *cls, const struct class_device_attribute *attr);
void class_device_remove_file(struct class_device *cls, const struct class_device_attribute *attr);

類接口

類子系統(tǒng)有一個 Linux 設備模型的其他部分找不到的附加概念,稱為“接口”, 可將它理解為一種設備加入或離開類時獲得信息的觸發(fā)機制,結構體如下:

struct class_interface {
    struct list_head    node;
    struct class        *class;/* 指向該接口所屬的類*/

    int (*add) (struct class_device *, struct class_interface *);

/*當一個類設備被加入到在 class_interface 結構中指定的類時, 將調用接口的 add 函數(shù),進行一些設備需要的額外設置,通常是添加更多屬性或其他的一些工作*/
    void (*remove)    (struct class_device *, struct class_interface *);/*一個接口的功能是簡單明了的. 當設備從類中刪除, 將調用remove 方法來進行必要的清理*/
    int (*add_dev)     (struct device *, struct class_interface *);
    void (*remove_dev) (struct device *, struct class_interface *);
};

/*注冊或注銷接口的函數(shù):*/
int class_interface_register(struct class_interface *class_intf);
void class_interface_unregister(struct class_interface *class_intf);
/*一個類可注冊多個接口*/


    本站是提供個人知識管理的網(wǎng)絡存儲空間,所有內容均由用戶發(fā)布,不代表本站觀點。請注意甄別內容中的聯(lián)系方式、誘導購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權內容,請點擊一鍵舉報。
    轉藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多