設備驅動模型-device、driver、bus(2/2)

目錄

一. device設備描述

1.1 內核結構

1.1.1 設備 struct device

1.1.2 設備屬性 struct device_attribute

1.2 相關操作接口

1.2.1 設備操作接口

1.2.2 設備屬性操作接口

二. driver設備驅動描述

2.1 內核結構

2.1.1 struct device_driver驅動數據結構

2.1.2 struct driver_attribute 設備屬性

2.2 相關操作接口

2.2.1 驅動操作接口

2.2.2 驅動屬性操作接口

三. 設備、驅動配對之bus總線---實例

3.1 device實例

3.2 driver實例

3.3 bus實例


一. device設備描述

1.1 內核結構

1.1.1 設備 struct device

struct device {
    struct device        *parent;
    
    /*設備私有數據*/
    struct device_private    *p;

    struct kobject kobj;

    /*設備名*/
    const char        *init_name; /* initial name of the device */
    
    /*設備類型*/
    const struct device_type *type;

    struct mutex        mutex;    /* mutex to synchronize calls to
                     * its driver.
                     */
    
    /* 設備所在總線 */
    struct bus_type    *bus;        /* type of bus device is on */
    
    /*管理該設備的驅動*/
    struct device_driver *driver;    /* which driver has allocated this
                       device */

    /*板級支持包提供*/
    void        *platform_data;    /* Platform specific data, device
                       core doesn't touch it */
                       
    /*該設備驅動使用的私有數據成員 */
    void        *driver_data;    /* Driver data, set and get with
                       dev_set/get_drvdata */
    struct dev_pm_info    power;
    struct dev_pm_domain    *pm_domain;

#ifdef CONFIG_PINCTRL
    struct dev_pin_info    *pins;
#endif

#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. */
    unsigned long    dma_pfn_offset;

    struct device_dma_parameters *dma_parms;

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

    struct dma_coherent_mem    *dma_mem; /* internal for coherent mem
                         override */
#ifdef CONFIG_DMA_CMA
    struct cma *cma_area;        /* contiguous memory area for dma
                       allocations */
#endif
    struct removed_region *removed_mem;
    /* arch specific additions */
    struct dev_archdata    archdata;

    /*設備樹 系統啓動時解析dtb得到*/
    struct device_node    *of_node; /* associated device tree node */
    struct acpi_dev_node    acpi_node; /* associated ACPI device node */
    
    /*主次設備號 12:20  (主:次)*/
    dev_t            devt;    /* dev_t, creates the sysfs "dev" */
    
    u32            id;    /* device instance */

    spinlock_t        devres_lock;
    struct list_head    devres_head;

    struct klist_node    knode_class;
    struct class        *class;
    const struct attribute_group **groups;    /* optional groups */
    
    /*釋放device空間的*/
    void    (*release)(struct device *dev);
    
    struct iommu_group    *iommu_group;

    bool            offline_disabled:1;
    bool            offline:1;
};

/*設備相關結構體*/
struct device_type {
    const char *name;
    /*屬性文件*/
    const struct attribute_group **groups;
    /*當設備insmod時, uevent會通過bus type(kset)發送時間到用戶層。*/
    int (*uevent)(struct device *dev, struct kobj_uevent_env *env);
    char *(*devnode)(struct device *dev, umode_t *mode,
             kuid_t *uid, kgid_t *gid);
    
    void (*release)(struct device *dev);
    
    /*電源管理相關*/
    const struct dev_pm_ops *pm;
};

struct device_private {
    struct klist klist_children;
    struct klist_node knode_parent;
    struct klist_node knode_driver;
    struct klist_node knode_bus;
    struct list_head deferred_probe;
    /*反向指向自己device*/
    struct device *device;
};

1.1.2 設備屬性 struct device_attribute

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);
};

 

1.2 相關操作接口

注:一條總線也是個設備,也必須按設備註冊。

1.2.1 設備操作接口

/*1. 註冊設備*/
extern int __must_check device_register(struct device *dev);

/*2. 註銷設備*/
extern void device_unregister(struct device *dev);

extern int __must_check device_add(struct device *dev);
extern void device_del(struct device *dev);

/*遍歷bus type下所有device*/
extern int device_for_each_child(struct device *dev, void *data,
             int (*fn)(struct device *dev, void *data));
             
extern struct device *device_find_child(struct device *dev, void *data,
                int (*match)(struct device *dev, void *data));
extern int device_rename(struct device *dev, const char *new_name);
extern int device_move(struct device *dev, struct device *new_parent,
               enum dpm_order dpm_order);
extern const char *device_get_devnode(struct device *dev,
                      umode_t *mode, kuid_t *uid, kgid_t *gid,
                      const char **tmp);

/*引用計數*/              
extern struct device *get_device(struct device *dev);
extern void put_device(struct device *dev);

/*獲取私有成員(屬性)*/
void *dev_get_drvdata(const struct device *dev)
void dev_set_drvdata(struct device *dev, void *data)


1.2.2 設備屬性操作接口

/*1. 創建屬性*/
extern int device_create_file(struct device *device,
                  const struct device_attribute *entry);

/*2. 刪除屬性*/
extern void device_remove_file(struct device *dev,
                   const struct device_attribute *attr);

二. driver設備驅動描述

2.1 內核結構

2.1.1 struct device_driver驅動數據結構

struct device_driver {
    /*驅動程序的名字( 體現在 sysfs 中 )*/
    const char        *name;

    /*驅動程序所在的總線*/
    struct bus_type        *bus;

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

    bool suppress_bind_attrs;    /* disables bind/unbind via sysfs */

    const struct of_device_id    *of_match_table;
    const struct acpi_device_id    *acpi_match_table;

    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);
    const struct attribute_group **groups;

    const struct dev_pm_ops *pm;

    struct driver_private *p;
};


2.1.2 struct driver_attribute 設備屬性

/* sysfs interface for exporting driver attributes */
struct driver_attribute {
    struct attribute attr;
    ssize_t (*show)(struct device_driver *driver, char *buf);
    ssize_t (*store)(struct device_driver *driver, const char *buf,
             size_t count);
};

 

2.2 相關操作接口

2.2.1 驅動操作接口

/*1. 註冊驅動*/
extern int __must_check driver_register(struct device_driver *drv);

/*2. 註銷驅動*/
extern void driver_unregister(struct device_driver *drv);

2.2.2 驅動屬性操作接口

/*1. 創建屬性*/
extern int __must_check driver_create_file(struct device_driver *driver,
                    const struct driver_attribute *attr);

/*2. 刪除屬性*/
extern void driver_remove_file(struct device_driver *driver,
                   const struct driver_attribute *attr);

三. 設備、驅動配對之bus總線---實例

3.1 device實例

#include <linux/device.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/string.h>

extern struct device my_bus;
extern struct bus_type my_bus_type;

static void my_dev_release(struct device *dev)
{
    
}

struct device my_dev = {
    .bus = &my_bus_type,
    .parent = &my_bus,
    .release = my_dev_release,
};


static ssize_t mydev_show(struct device *dev, char *buf)
{
    return sprintf(buf, "%s\n", "This is my device!");
}
static DEVICE_ATTR(dev, S_IRUGO, mydev_show, NULL);


static int __init my_device_init(void)
{
    int ret = 0;
        
    /*初始化設備*/
    dev_set_name(&my_dev, "my_dev");
        
    /*註冊設備*/
    device_register(&my_dev);
        
    /*創建屬性文件*/
    device_create_file(&my_dev, &dev_attr_dev);
    
    return ret;    

}

static void __exit my_device_exit(void)
{
    device_unregister(&my_dev);
}


module_init(my_device_init);
module_exit(my_device_exit);
MODULE_AUTHOR("vec");
MODULE_LICENSE("Dual BSD/GPL");


Makefile

ifneq ($(KERNELRELEASE),)
    obj-m := device.o
else
    PWD  := $(shell pwd)

KDIR := /lib/modules/$(shell uname -r)/build

#解決:no symbol version 問題
KBUILD_EXTRA_SYMBOLS+=/home/vec/test_file/bus_test/bus/Module.symvers
export KBUILD_EXTRA_SYMBOLS

all:
    $(MAKE) -C $(KDIR) M=$(PWD) modules

clean:
    rm -rf .*.cmd *.o *.mod.c *.ko .tmp_versions modules.order Module.symvers
endif

3.2 driver實例

#include <linux/device.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/string.h>

extern struct bus_type my_bus_type;

static int my_probe(struct device *dev)
{
    printk("Driver found device which my driver can handle!\n");
    return 0;
}

static int my_remove(struct device *dev)
{
    printk("Driver found device unpluged!\n");
    return 0;
}

struct device_driver my_driver = {
    .name = "my_dev",
    .bus = &my_bus_type,
    .probe = my_probe,
    .remove    = my_remove,
};


static ssize_t mydriver_show(struct device_driver *driver, char *buf)
{
    return sprintf(buf, "%s\n", "This is my driver!");
}
static DRIVER_ATTR(drv, S_IRUGO, mydriver_show, NULL);


static int __init my_driver_init(void)
{
    int ret = 0;
        
    /*註冊驅動*/
    driver_register(&my_driver);
        
    /*創建屬性文件*/
    driver_create_file(&my_driver, &driver_attr_drv);
    
    return ret;    

}

static void my_driver_exit(void)
{
    driver_unregister(&my_driver);
}

module_init(my_driver_init);
module_exit(my_driver_exit);
MODULE_AUTHOR("vec");
MODULE_LICENSE("Dual BSD/GPL");


Makefile
 

ifneq ($(KERNELRELEASE),)
    obj-m := driver.o
else
    PWD  := $(shell pwd)

KDIR := /lib/modules/$(shell uname -r)/build
KBUILD_EXTRA_SYMBOLS=/home/vec/test_file/bus_test/bus/Module.symvers
export KBUILD_EXTRA_SYMBOLS

all:
    $(MAKE) -C $(KDIR) M=$(PWD) modules

clean:
    rm -rf .*.cmd *.o *.mod.c *.ko .tmp_versions modules.order Module.symvers
endif

3.3 bus實例

#include <linux/device.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/string.h>

static char *version = "Revision: 2.0";

static int my_match(struct device *dev, struct device_driver *driver)
{
    printk(KERN_DEBUG "func: %s: device name: %s: driver name: %s \n", __func__, dev_name(dev), driver->name);
    return !strncmp(dev_name(dev), driver->name, strlen(driver->name));
}

static void my_bus_release(struct device *dev)
{
    printk(KERN_DEBUG "func: %s \n", __func__);
}
    
struct device my_bus = {
    .init_name   = "my_bus0",
    .release  = my_bus_release
};
//EXPORT_SYMBOL(my_bus);
EXPORT_SYMBOL_GPL(my_bus);

struct bus_type my_bus_type = {
    .name = "my_bus",
    .match = my_match,
};
//EXPORT_SYMBOL(my_bus_type);
EXPORT_SYMBOL_GPL(my_bus_type);

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);


static int __init my_bus_init(void)
{
    int ret;
        
    /*註冊總線*/
    ret = bus_register(&my_bus_type);
    if (ret)
        return ret;
        
    /*創建屬性文件*/    
    if (bus_create_file(&my_bus_type, &bus_attr_version))
        printk(KERN_NOTICE "Fail to create version attribute!\n");
    
    /*註冊總線設備*/
    ret = device_register(&my_bus);
    if (ret)
        printk(KERN_NOTICE "Fail to register device:my_bus!\n");
        
    return ret;
}

static void my_bus_exit(void)
{
    device_unregister(&my_bus);
    bus_unregister(&my_bus_type);
}

module_init(my_bus_init);
module_exit(my_bus_exit);
MODULE_AUTHOR("vec");
MODULE_LICENSE("Dual BSD/GPL");


Makefile
 

ifneq ($(KERNELRELEASE),)
    obj-m := bus.o
else
    PWD  := $(shell pwd)
KDIR := /lib/modules/$(shell uname -r)/build

all:
    $(MAKE) -C $(KDIR) M=$(PWD) modules

clean:
    rm -rf .*.cmd *.o *.mod.c *.ko .tmp_versions modules.order Module.symvers
endif


  1 . 先insmod bus.ko,然後在insmod device.ko和driver.ko。
  2 . 由於bus總線初始化時的device和driver都爲空,所以只insmod device.ko或driver.ko ,均不打印bus 的my_match()匹配函數。
 

發佈了97 篇原創文章 · 獲贊 52 · 訪問量 19萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章