您的位置 首页 FPGA

驱动之路-设备模型之上层模型

驱动之路-设备模型之上层模型-底层模型决定上层模型,在总线,设备,驱动的结构体中你总是可以看到它们间接或者直接的包含了kobject结构或kset结构。

一、重要知识点:

设备模型由总线、设备、驱动三要素组成。

底层模型决议上层模型,在总线,设备,驱动的结构体中你总是能够看到它们直接或许直接的包含了kobject结构或kset结构。

1.总线

总线是处理器和设备之间的通道,在设备模型中,一切设备都经过总线相连,乃至内部的虚拟“platform”总线。在linux设备模型中,总线由bus_type结构表明。界说在中。

总线描绘

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 dev_pm_ops *pm;  

struct bus_type_private *p;  

};  

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 dev_pm_ops *pm;struct bus_type_private *p;};

bus_type的bus_type_private 成员

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;  

};  

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

能够看出该结构体中包含了有device和dirver的kset目标。

总线的注册:

int bus_register(structbus_type *bus);

假如成功,新的总线将被增加到体系,在/sys/bus目录下能够看到。

咱们在深化看这个函数

int bus_register(struct bus_type *bus)  

{  

int retval;  

struct bus_type_private *priv;  

priv = kzalloc(sizeof(struct bus_type_private), GFP_KERNEL);  

if (!priv)  

return -ENOMEM;  

priv->busbus = bus;  

bus->p = priv;  

int bus_register(struct bus_type *bus){int retval;struct bus_type_private *priv;priv = kzalloc(sizeof(struct bus_type_private), GFP_KERNEL);if (!priv)return -ENOMEM;priv->bus = bus;bus->p = priv;

BLOCKING_INIT_NOTIFIER_HEAD(&priv->bus_noTIfier);  

retval = kobject_set_name(&priv->subsys.kobj, “%s”, bus->name);  

if (retval)  

goto out;  

priv->subsys.kobj.kset = bus_kset;  

priv->subsys.kobj.ktype = &bus_ktype;  

priv->drivers_autoprobe = 1;  

retval = kset_register(&priv->subsys);  

if (retval)  

goto out;  

retval = bus_create_file(bus, &bus_attr_uevent);  

if (retval)  

goto bus_uevent_fail;  

priv->devices_kset = kset_create_and_add(“devices”, NULL,  

&priv->subsys.kobj);  

if (!priv->devices_kset) {  

retval = -ENOMEM;  

goto bus_devices_fail;  

}  

priv->drivers_kset = kset_create_and_add(“drivers”, NULL,  

&priv->subsys.kobj);  

if (!priv->drivers_kset) {  

retval = -ENOMEM;  

goto bus_drivers_fail;  

}  

klist_init(&priv->klist_devices, klist_devices_get, klist_devices_put);  

klist_init(&priv->klist_drivers, NULL, NULL);  

retval = add_probe_files(bus);  

if (retval)  

goto bus_probe_files_fail;  

retval = bus_add_attrs(bus);  

if (retval)  

goto bus_attrs_fail;  

pr_debug(“bus: '%s': registered\n”, bus->name);  

return 0;  

bus_attrs_fail:  

remove_probe_files(bus);  

bus_probe_files_fail:  

kset_unregister(bus->p->drivers_kset);  

bus_drivers_fail:  

kset_unregister(bus->p->devices_kset);  

bus_devices_fail:  

bus_remove_file(bus, &bus_attr_uevent);  

bus_uevent_fail:  

kset_unregister(&bus->p->subsys);  

kfree(bus->p);  

out:  

return retval;  

}  

BLOCKING_INIT_NOTIFIER_HEAD(&priv->bus_notifier);retval = kobject_set_name(&priv->subsys.kobj, “%s”, bus->name);if (retval)goto out;priv->subsys.kobj.kset = bus_kset;priv->subsys.kobj.ktype = &bus_ktype;priv->drivers_autoprobe = 1;retval = kset_register(&priv->subsys);if (retval)goto out;retval = bus_create_file(bus, &bus_attr_uevent);if (retval)goto bus_uevent_fail;priv->devices_kset = kset_create_and_add(“devices”, NULL,&priv->subsys.kobj);if (!priv->devices_kset) {retval = -ENOMEM;goto bus_devices_fail;}priv->drivers_kset = kset_create_and_add(“drivers”, NULL,&priv->subsys.kobj);if (!priv->drivers_kset) {retval = -ENOMEM;goto bus_drivers_fail;}klist_init(&priv->klist_devices, klist_devices_get, klist_devices_put);klist_init(&priv->klist_drivers, NULL, NULL);retval = add_probe_files(bus);if (retval)goto bus_probe_files_fail;retval = bus_add_attrs(bus);if (retval)goto bus_attrs_fail;pr_debug(“bus: '%s': registered\n”, bus->name);return 0;bus_attrs_fail:remove_probe_files(bus);bus_probe_files_fail:kset_unregister(bus->p->drivers_kset);bus_drivers_fail:kset_unregister(bus->p->devices_kset);bus_devices_fail:bus_remove_file(bus, &bus_attr_uevent);bus_uevent_fail:kset_unregister(&bus->p->subsys);kfree(bus->p);out:return retval;}
 

从这儿

priv->subsys.kobj.kset = bus_kset;
priv->subsys.kobj.ktype = &bus_ktype;

能够看得出总线初始化了自己的kset目标。

总线的删去

void bus_unregister(struct bus_type *bus);

总线的match办法

int (*match)(struct device *dev, struct device_driver *drv);

当一个新设备或许驱动被增加到这个总线时,该办法被调用,用于判别指定的驱动程序是否能处理指定的设备。若能够,则回来非0值。下面的测验程序选用匹配设备的dev->bus_id字符串和驱动的drv->name字符串是否相同来判别驱动是否能处理该设备。

总线uevent办法

int  (*uevent)(structdevice *dev, char **envp, int num_envp)

在为用户发生热插拔事情之前,这个办法答应总线增加环境变量。

总线特点由结构bus_attribute描绘:

struct bus_attribute {

struct attribute        attr;

ssize_t (*show)(struct bus_type *bus,char *buf);

ssize_t (*store)(struct bus_type *bus,const char *buf, size_t count);

};

BUS_ATTR(name,mode, show, store)

在编译时创立和初始化bus_attribute结构,它将bus_attr_作为给定前缀来创立总线的真实称号。

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

将创立一个bus_attr_version结构体目标。

int bus_create_file(struct bus_type *bus, struct bus_attribute *attr)

创立特点文件

void bus_remove_file(struct bus_type *bus, struct bus_attribute *attr)

删去特点文件

2.设备

struct device {  

struct klist klist_children;  

struct klist_nodeknode_parent;/* node in sibling list */  

struct klist_nodeknode_driver;  

struct klist_nodeknode_bus;  

struct device *parent;  

struct kobject kobj;  

char bus_id[BUS_ID_SIZE];/* position on parent bus */  

unsigned uevent_suppress:1;  

const char *init_name; /* initial name of the device */  

struct device_type*type;  

struct semaphoresem;/* semaphore 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 *driver_data;/* data private to the driver */  

void *platform_data;/* Platform specific data, device  

core doesn't touch it */  

struct dev_pm_infopower;  

#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 device_dma_parameters *dma_parms;  

struct list_headdma_pools;/* dma pools (if dma'ble) */  

struct dma_coherent_mem*dma_mem; /* internal for coherent mem  

override */  

/* arch specific additions */  

struct dev_archdataarchdata;  

dev_t devt;/* dev_t, creates the sysfs “dev” */  

spinlock_t devres_lock;  

struct list_headdevres_head;  

struct klist_nodeknode_class;  

struct class *class;  

struct attribute_group**groups;/* optional groups */  

void (*release)(struct device *dev);  

};  

struct device {struct klist klist_children;struct klist_nodeknode_parent;/* node in sibling list */struct klist_nodeknode_driver;struct klist_nodeknode_bus;struct device *parent;struct kobject kobj;char bus_id[BUS_ID_SIZE];/* position on parent bus */unsigned uevent_suppress:1;const char *init_name; /* initial name of the device */struct device_type*type;struct semaphoresem;/* semaphore to synchronize calls to* its driver.*/struct bus_type*bus;/* type of bus device is on */struct device_driver *driver;/* which driver has allocated thisdevice */void *driver_data;/* data private to the driver */void *platform_data;/* Platform specific data, devicecore doesn't touch it */struct dev_pm_infopower;#ifdef CONFIG_NUMAint numa_node;/* NUMA node this device is close to */#endifu64 *dma_mask;/* dma mask (if dma'able device) */u64 coherent_dma_mask;/* Like dma_mask, but foralloc_coherent mappings asnot all hardware supports64 bit addresses for consistentallocations such descriptors. */struct device_dma_parameters *dma_parms;struct list_headdma_pools;/* dma pools (if dma'ble) */struct dma_coherent_mem*dma_mem; /* internal for coherent memoverride *//* arch specific additions */struct dev_archdataarchdata;dev_t devt;/* dev_t, creates the sysfs “dev” */spinlock_t devres_lock;struct list_headdevres_head;struct klist_nodeknode_class;struct class *class;struct attribute_group**groups;/* optional groups */void (*release)(struct device *dev);};
 

能够看出device结构体中也包含了一个kobject目标

intdevice_register(struct device *dev);

注册设备

vioddevice_unregister(struct device *dev)

刊出设备

设备特点由struct device_attribute描绘

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

};

int device_create_file(struct device *dev, struct device_attibute *entry)

创立特点文件

void device_remove_file(struct device *dev, struct device_attibute *entry)

删去特点文件

3.驱动

驱动程序由struct device_driver描绘:

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 dev_pm_ops *pm;  

struct driver_private *p;  

};  

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 dev_pm_ops *pm;struct driver_private *p;};
 

在看device_dirver的driver_private 目标

struct driver_private {
struct kobject kobj;
struct klist klist_devices;
struct klist_node knode_bus;
struct module_kobject *mkobj;
struct device_driver *driver;
};

能够看出driver_private结构体中也包含了一个kobject目标。和衔接设备的链表。

当总线的match回来非0值,也便是总线找到与驱动相匹配的设备时,驱动的probe的函数将被调用。

当设备从体系总删去是remove被调用。

当体系关机的时分shutdown被调用。

int driver_register(structdevice_driver *drv)

在总线上注册驱动

void driver_unregister(struct device_driver *drv)

载总线上刊出驱动

驱动的特点运用structdriver_attribute来描绘

structdriver_attribute{

structattribue attr;

ssize_t(*show)(struct device_driver *drv, const char *buf);

ssize_t(*store)(struct device_driver *drv, const char *buf, size_t count);

}

int dirver_create_file(struct device_driver *drv, struct driver_attribute *attr);

创立特点文件

void driver_remove_file struct device_driver *drv, struct driver_attribute *attr);

删去特点文件

二、测验模块

1.BUS

#include   

#include   

#include   

#include   

#include   

MODULE_AUTHOR(“David Xie”);  

MODULE_LICENSE(“Dual BSD/GPL”);  

static char *Version = “$Revision: 1.9 {1}quot;;  

static int my_match(struct device *dev, struct device_driver *driver)  

{  

return !strncmp(dev->bus_id, driver->name, strlen(driver->name));  

}  

static void my_bus_release(struct device *dev)  

{  

printk(KERN_DEBUG “my bus release\n”);  

}  

struct device my_bus = {  

.bus_id   = “my_bus0”,  

.release  = my_bus_release  

};  

struct bus_type my_bus_type = {  

.name = “my_bus”,  

.match = my_match,  

};  

EXPORT_SYMBOL(my_bus);  

EXPORT_SYMBOL(my_bus_type);  

/*  

* Export a simple attribute.  

*/  

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

#include #include #include #include #include MODULE_AUTHOR(“David Xie”);MODULE_LICENSE(“Dual BSD/GPL”);static char *Version = “$Revision: 1.9 {1}quot;;static int my_match(struct device *dev, struct device_driver *driver){return !strncmp(dev->bus_id, driver->name, strlen(driver->name));}static void my_bus_release(struct device *dev){printk(KERN_DEBUG “my bus release\n”);}struct device my_bus = {.bus_id = “my_bus0”,.release = my_bus_release};struct bus_type my_bus_type = {.name = “my_bus”,.match = my_match,};EXPORT_SYMBOL(my_bus);EXPORT_SYMBOL(my_bus_type);/** Export a simple attribute.*/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);

创立一条名为my_bus_type的总线和一个名为my_bus的总线设备,留意总线也是一个设备,也需求注册。

测验成果:


 

2.DEVICE

#include   

#include   

#include   

#include   

#include   

MODULE_AUTHOR(“David Xie”);  

MODULE_LICENSE(“Dual BSD/GPL”);  

extern struct device my_bus;   

extern struct bus_type my_bus_type;  

/* Why need this ?*/  

static void my_dev_release(struct device *dev)  

{   

}  

struct device my_dev = {  

.bus = &my_bus_type,  

.parent = &my_bus,  

.release = my_dev_release,  

};  

/*  

* Export a simple attribute.  

*/  

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;  

/* 初始化设备 */  

strncpy(my_dev.bus_id, “my_dev”, BUS_ID_SIZE);  

/*注册设备*/  

device_register(&my_dev);  

/*创立特点文件*/  

device_create_file(&my_dev, &dev_attr_dev);  

return ret;   

}  

static void my_device_exit(void)  

{  

device_unregister(&my_dev);  

}  

module_init(my_device_init);  

module_exit(my_device_exit);  

#include #include #include #include #include MODULE_AUTHOR(“David Xie”);MODULE_LICENSE(“Dual BSD/GPL”);extern struct device my_bus;extern struct bus_type my_bus_type;/* Why need this ?*/static void my_dev_release(struct device *dev){}struct device my_dev = {.bus = &my_bus_type,.parent = &my_bus,.release = my_dev_release,};/** Export a simple attribute.*/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;/* 初始化设备 */strncpy(my_dev.bus_id, “my_dev”, BUS_ID_SIZE);/*注册设备*/device_register(&my_dev);/*创立特点文件*/device_create_file(&my_dev, &dev_attr_dev);return ret;}static void my_device_exit(void){device_unregister(&my_dev);}module_init(my_device_init);module_exit(my_device_exit);

注册一个bus_id即姓名为my_dev的设备,该设备的bus成员指向上一步创立的my_bus_type总线,parent成员指向上一步创立的my_bus总线设备。

测验成果:

3.DRIVER

#include   

#include   

#include   

#include   

#include   

MODULE_AUTHOR(“David Xie”);  

MODULE_LICENSE(“Dual BSD/GPL”);  

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,  

};  

/*  

* Export a simple attribute.  

*/  

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

#include #include #include #include #include MODULE_AUTHOR(“David Xie”);MODULE_LICENSE(“Dual BSD/GPL”);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,};/** Export a simple attribute.*/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);

创立一个名为“bus_dev”的驱动,并将bus成员指向第一步创立的my_bus_type总线

测验成果:

 

声明:本文内容来自网络转载或用户投稿,文章版权归原作者和原出处所有。文中观点,不代表本站立场。若有侵权请联系本站删除(kf@86ic.com)https://www.86ic.net/fangan/fpga/88860.html

为您推荐

联系我们

联系我们

在线咨询: QQ交谈

邮箱: kf@86ic.com

关注微信
微信扫一扫关注我们

微信扫一扫关注我们

返回顶部