设备驱动模型-device、driver、bus(2/2)

吃可爱长大的小学妹 提交于 2019-12-30 01:22:42

目录

一. 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()匹配函数。
 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!