Linux设备模型 - linux-4.0-rc1

来源:互联网 发布:sql nvl函数用法 编辑:程序博客网 时间:2024/06/04 00:49

!Warning:请确保能够访问图床Imgur,以正常显示图片


源码基线:linux-4.0-rc1

设备模型概述

设备模型主要完成以下工作:

  1. 设备分类,以分层的架构对设备进行描述,隐藏设备内部的连接细节,对外清晰地展示可用的设备。
  2. 创建和管理设备的生命周期。
  3. 通过sysfs虚拟文件系统,向用户空间提供对设备的读写操作,获取设备的信息、改变设备的运行状态。

设备模型的结构组成:

1.总线。

所有的设备都通过总线相连,包括内部的虚拟总线。在内核中,用struct bus_type结构体来表示总线。

struct bus_type {      const char      * name;      struct kset     drivers;      struct kset     devices;  }  
  • name是总线的名字。
  • kset driverskset devices,分别代表了总线的驱动程序及插入总线的所有设备集合。

2.设备。

每个设备实例用struct device结构体来表示。

struct device {      struct device       *parent;      struct kobject kobj;          char bus_id[BUS_ID_SIZE];      struct bus_type * bus;      struct device_driver *driver;  }  
  • parent指向设备的所属父设备,通常是某种总线。
  • kobj表示本设备对象。
  • bus_id是总线上标识设备的ID信息,通常由字符串”<域编号>:<总线编号>:<设备编号>:<功能编号>”定义
  • bus标识了设备连接在哪个总线上。
  • driver管理设备的驱动程序。

3.驱动程序。

设备驱动程序设备模型可以跟踪所有注册的设备,驱动程序为设备提供服务,完成设备的工作。设备的驱动程序由结构体struct device_driver定义。

struct device_driver {      const char      * name;      struct bus_type     * bus;      struct kobject      kobj;          struct klist            klist_devices;  }  
  • name是驱动程序的名字。
  • bus是指驱动程序所操作的总线类型。
  • kobj表示驱动程序服务的设备对象。
  • klist_devices是驱动程序当前能操作的设备链表。

platform虚拟总线、设备、驱动

struct kobject与kset结构体

kobject与kset是组成设备模型的基本结构,为来表示设备模型的设备实例与设备层次关系。这两个结构体作为面向对象概念的基类,嵌套在其他结构体里使用。在sysfs中显示的每一个实例,都对应一个kobject。

/* 设备模型的基本结构。  * 在sysfs中显示的每一个对象,都对应一个kobject,它被用来与内核交互并创建它的可见表述。  * 内核用kobject结构将各个对象连接起来组成一个分层的结构体系 */  struct kobject {      const char      *name;      struct kref     kref; /* 对象的引用计数。一个内核对象被创建时,需要知道对象存活                的时间,跟踪生命周期的一个方法是使用引用计数,当内核中没有该对象的引用                时,表示对象的生命周期结束,可以被删除 */      struct list_head    entry; /* 连接到kset建立层次结构 */      struct kobject      * parent; /* parent保存了分层结构中上一层节点kobject结构                的指针。比如一个kobject结构表示了一个USB设备,它的parent指针可能指向                了表示USB集线器的对象,而USB设备是插在USB集线器上的。parent指针最重                要的用途是在sysfs分层结构中定位对象 */       struct kset     * kset; /* 一个kset是嵌入相同类型结构的kobject集合。每个kset                内部,包含了自己的kobject。kset总是在sysfs中出现,一旦设置了kset并                把它添加到系统中,将在sysfs中创建一个目录。kobject不必在sysfs中表示,                但kset中每一个kobject成员都将在sysfs中得到表述 */      struct kobj_type    * ktype; /* 属性结构。kset中也有一个ktype,其使用优先于                kobject的此处ktype,因此在典型应用中,kobject中的ktype成员被设置                为NULL */      struct sysfs_dirent * sd; /* 指向sysfs下以kobj.name所命名生成的目录 */  };  struct kset {      struct kobj_type    *ktype;      struct list_head    list;      spinlock_t      list_lock;      struct kobject      kobj;      struct kset_uevent_ops  *uevent_ops;  };  

假设有个总线X-bus,以及3个设备驱动A-driver、B-driver、C-driver,且这3个设备都属于同一类X-bus总线。那么kobject与kset在描述设备模型时,通常这样使用。在X-bus的描述结构体中包含kset结构体作为同一类型设备的集合;在描述设备驱动A、B、C的driver结构体中包含kset指针,指向所属的类型集合。每个driver都有一个kobject来表示驱动实例自身,并把所有集合按照加入的先后顺序通过list链表(kset.list与kobject.entry)连接起来。

注册platform总线

函数入口driver_init()

void __init driver_init(void)  {      devices_init();      buses_init();      platform_bus_init();  }  

devices_init()

devices_init()创建sysfs模型如下:

/sys
├── dev
│ ├── block
│ └── char
└── devices

struct kset *devices_kset; /* /sys/devices/ */static struct kobject *dev_kobj;struct kobject *sysfs_dev_char_kobj;struct kobject *sysfs_dev_block_kobj;int __init devices_init(void){    devices_kset = kset_create_and_add("devices", &device_uevent_ops, NULL);    dev_kobj = kobject_create_and_add("dev", NULL);    sysfs_dev_block_kobj = kobject_create_and_add("block", dev_kobj);    sysfs_dev_char_kobj = kobject_create_and_add("char", dev_kobj);}

kset_create_and_add()

/* 动态创建kset结构体,在sysfs中创建以@name命名的目录,如果kset->kobj.ktype有属性值,   则在目录下创建以属性名命名的文件 */struct kset *kset_create_and_add(const char *name,                 const struct kset_uevent_ops *uevent_ops,                 struct kobject *parent_kobj){    struct kset *kset;    kset = kset_create(name, uevent_ops, parent_kobj); /* 动态创建kset结构体 */    kset_register(kset); /* 初始化kset,并加入到sysfs */}/* 动态创建kset结构体 */static struct kset *kset_create(const char *name,                const struct kset_uevent_ops *uevent_ops,                struct kobject *parent_kobj){    struct kset *kset;    int retval;    kset = kzalloc(sizeof(*kset), GFP_KERNEL);    kobject_set_name(&kset->kobj, "%s", name);    kset->uevent_ops = uevent_ops;    kset->kobj.parent = parent_kobj;    kset->kobj.ktype = &kset_ktype;    kset->kobj.kset = NULL;    return kset;}/* 初始化kset,并加入到sysfs */int kset_register(struct kset * k)  {          kset_init(k);          kobject_add_internal(&k->kobj);        kobject_uevent(&k->kobj, KOBJ_ADD);  }          void kset_init(struct kset * k)  {      kobject_init_internal(&k->kobj);    INIT_LIST_HEAD(&k->list);    spin_lock_init(&k->list_lock);}  static void kobject_init_internal(struct kobject *kobj){          kref_init(&kobj->kref); /* 初始化kobject的引用计数为1 */          INIT_LIST_HEAD(&kobj->entry); /* 初始化entry链表 */          kobj->state_in_sysfs = 0;        kobj->state_add_uevent_sent = 0;        kobj->state_remove_uevent_sent = 0;        kobj->state_initialized = 1;}/* kobject_add_internal()在sysfs下建立以kobj.name命名的目录 */static int kobject_add_internal(struct kobject *kobj){    struct kobject *parent;    parent = kobject_get(kobj->parent);    /* join kset if set, use it as parent if we do not already have one */    if (kobj->kset) {        if (!parent)            parent = kobject_get(&kobj->kset->kobj);        kobj_kset_join(kobj);        kobj->parent = parent;    }    create_dir(kobj);    kobj->state_in_sysfs = 1;}/* 创建kobject对象的目录及属性文件 */static int create_dir(struct kobject *kobj){    const struct kobj_ns_type_operations *ops;    sysfs_create_dir_ns(kobj, kobject_namespace(kobj)); /* 创建目录 */     populate_dir(kobj); /* 创建属性文件 */    sysfs_get(kobj->sd);    ops = kobj_child_ns_ops(kobj);    if (ops) {        sysfs_enable_ns(kobj->sd);    }}  /* 以kobj.name命名,在sysfs下创建一个目录 */int sysfs_create_dir_ns(struct kobject *kobj, const void *ns){    struct kernfs_node *parent, *kn;    /* 指定创建的kobj目录所属的的父目录,默认为sysfs根目录 */    if (kobj->parent)        parent = kobj->parent->sd;    else        parent = sysfs_root_kn;    /* 在parent目录下,创建以kobj.name命名的目录 */    kn = kernfs_create_dir_ns(parent, kobject_name(kobj),                  S_IRWXU | S_IRUGO | S_IXUGO, kobj, ns);    kobj->sd = kn;}/* 对象可能是带有属性的,在kobject目录下创建以属性名命名的文件 */static int populate_dir(struct kobject *kobj){    struct kobj_type *t = get_ktype(kobj);    struct attribute *attr;    int i;    if (t && t->default_attrs) {        for (i = 0; (attr = t->default_attrs[i]) != NULL; i++) {            sysfs_create_file(kobj, attr);        }    }}

devices_kset = kset_create_and_add("devices", &device_uevent_ops, NULL)创建的模型:

kobject_create_and_add()

/* 动态创建一个kobject对象,并且加入到sysfs */struct kobject *kobject_create_and_add(const char *name, struct kobject *parent){    struct kobject *kobj;    kobj = kobject_create();    kobject_add(kobj, parent, "%s", name);    return kobj;}struct kobject *kobject_create(void){    struct kobject *kobj;    kobj = kzalloc(sizeof(*kobj), GFP_KERNEL);    kobject_init(kobj, &dynamic_kobj_ktype);    return kobj;}/* 初始化kobject结构体 */void kobject_init(struct kobject *kobj, struct kobj_type *ktype){    kobject_init_internal(kobj);    kobj->ktype = ktype;}int kobject_add(struct kobject *kobj, struct kobject *parent,        const char *fmt, ...){    va_list args;    va_start(args, fmt);    kobject_add_varg(kobj, parent, fmt, args);    va_end(args);}static int kobject_add_varg(struct kobject *kobj, struct kobject *parent,                const char *fmt, va_list vargs){    kobject_set_name_vargs(kobj, fmt, vargs);    kobj->parent = parent;    return kobject_add_internal(kobj);}/* 设置@kobj的name */int kobject_set_name_vargs(struct kobject *kobj, const char *fmt,                  va_list vargs){    char *s;    kobj->name = kvasprintf(GFP_KERNEL, fmt, vargs);    /* 名字中不能包含有'/'的字符,如果有,则直接截短 */    while ((s = strchr(kobj->name, '/')))        s[0] = '!';}

dev_kobj = kobject_create_and_add("dev", NULL)创建的模型:

sysfs_dev_block_kobj = kobject_create_and_add("block", dev_kobj)
sysfs_dev_char_kobj = kobject_create_and_add("char", dev_kobj)创建的模型:

buses_init()

buses_init()创建sysfs模型如下:

/sys
├── bus
└── devices
└── system

static struct kset *bus_kset;static struct kset *system_kset; /* /sys/devices/system */int __init buses_init(void){    bus_kset = kset_create_and_add("bus", &bus_uevent_ops, NULL);    system_kset = kset_create_and_add("system", NULL, &devices_kset->kobj);}

bus_kset = kset_create_and_add("bus", &bus_uevent_ops, NULL)创建的模型:

system_kset = kset_create_and_add("system", NULL, &devices_kset->kobj)创建的模型:

platform_bus_init()

platform_bus_init()完成虚拟设备platform,及虚拟总线platform的创建。

/sys
└── devices
└── platform
└── uevent /* -rw-r–r– */

/* platform设备 */struct device platform_bus = {    .init_name  = "platform",};/* platform总线 */struct bus_type platform_bus_type = {    .name       = "platform",    .dev_groups = platform_dev_groups,    .match      = platform_match,    .uevent     = platform_uevent,    .pm     = &platform_dev_pm_ops,};int __init platform_bus_init(void){    early_platform_cleanup();    device_register(&platform_bus); /* 注册到devices目录中 */      bus_register(&platform_bus_type); /* 注册到bus目录中 */      of_platform_register_reconfig_notifier();}

device_register()

/* 注册设备:初始化设备的数据结构,将其加入到数据结构的网络中。    完成设备注册后,可以在/sys/devices目录中看到 */  int device_register(struct device *dev)  {      device_initialize(dev); /* 初始化dev结构 */      device_add(dev); /* 添加dev至sysfs */  }  void device_initialize(struct device *dev)  {      /* 将设备kobject的kset集合指向devices_kset */      dev->kobj.kset = devices_kset;     kobject_init(&dev->kobj, &device_ktype);}  #define DEVICE_ATTR_RW(_name) \    struct device_attribute dev_attr_##_name = __ATTR_RW(_name)#define __ATTR_RW(_name) __ATTR(_name, (S_IWUSR | S_IRUGO),     \             _name##_show, _name##_store)#define __ATTR(_name, _mode, _show, _store) {               \    .attr = {.name = __stringify(_name),                \         .mode = VERIFY_OCTAL_PERMISSIONS(_mode) },     \    .show   = _show,                        \    .store  = _store,                       \}static DEVICE_ATTR_RW(uevent); /* 定义dev_attr_uevent,其展开宏如下:    struct device_attribute dev_attr_uevent {        .attr = {            .name = "uevent",            .mode = (S_IWUSR | S_IRUGO),        },        .show = uevent_show,        .store = uevent_store,    }; */int device_add(struct device *dev)  {      struct device *parent = NULL;      struct kobject *kobj;    struct class_interface *class_intf;      dev = get_device(dev); /* 将设备的引用计数加1 */     if (!dev->p) {        device_private_init(dev);    }    /* 使用dev.init_name设置dev.kobj.name,并置空dev.init_name */    if (dev->init_name) {        dev_set_name(dev, "%s", dev->init_name);        dev->init_name = NULL;    }    /* 如果kobject_add()的第二个参数parent为空,则以dev->kobj.kset.kobj作为父目录 */      kobject_add(&dev->kobj, dev->kobj.parent, NULL);      /* dev_attr_uevent由宏DEVICE_ATTR_RW()定义,在dev.kobj目录下创建以       dev_attr_uevent.attr.name命名,权限为dev_attr_uevent.attr.mode的文件 */    device_create_file(dev, &dev_attr_uevent);     device_add_class_symlinks(dev); /* 创建类型软链接 */}  

device_register()

bus_register(&platform_bus_type)向系统添加一个新总线。

/sys
└── bus
└── platform
├── devices
├── drivers
├── drivers_autoprobe /* -rw-r–r– */
├── drivers_probe /* –w——- */
└── uevent /* –w——- */

```cstruct bus_type {      const char      * name; /* 总线的文本名称,用于在sysfs文件系统中标识总线 */      /* 试图查找与给定设备匹配的驱动程序 */      int     (*match)(struct device * dev, struct device_driver * drv);      int     (*uevent)(struct device *dev, struct kobj_uevent_env *env);      /* 在有必要将驱动程序关联到设备时,会调用probe。该函数检测设备在系统中是否        真正存在 */      int     (*probe)(struct device * dev);      /* 删除驱动程序和设备之间的关联。例如,在将可热挺拔的设备从系统中移除时,会        调用该函数 */      int     (*remove)(struct device * dev);      struct subsys_private *p;};  struct bus_type platform_bus_type = {    .name       = "platform",    .dev_groups = platform_dev_groups,    .match      = platform_match,    .uevent     = platform_uevent,    .pm     = &platform_dev_pm_ops,};static BUS_ATTR(uevent, S_IWUSR, NULL, bus_uevent_store); /* 定义bus_attr_uevent    ,其展开宏如下:    struct bus_attribute bus_attr_uevent {        .attr = {            .name = "uevent",            .mode = S_IWUSR,        },        .show = NULL,        .store = bus_uevent_store,    }; *//* 注册新的总线 */  int bus_register(struct bus_type *bus){    int retval;    struct subsys_private *priv;    struct lock_class_key *key = &bus->lock_key;    priv = kzalloc(sizeof(struct subsys_private), GFP_KERNEL);    priv->bus = bus;    bus->p = priv;    /*  */    kobject_set_name(&priv->subsys.kobj, "%s", bus->name);      priv->subsys.kobj.kset = bus_kset; /* 父目录指向bus_kset.kobj */    priv->subsys.kobj.ktype = &bus_ktype;    priv->drivers_autoprobe = 1;    /* 初始化&priv->subsys,并加入到sysfs */    kset_register(&priv->subsys);    /* bus_attr_uevent由宏BUS_ATTR()定义,在priv.subsys.kobj目录下创建以       bus_attr_uevent.attr.name命名,权限为bus_attr_uevent.attr.mode的文件 */    bus_create_file(bus, &bus_attr_uevent);    priv->devices_kset = kset_create_and_add("devices", NULL,                         &priv->subsys.kobj);    priv->drivers_kset = kset_create_and_add("drivers", NULL,                         &priv->subsys.kobj);    add_probe_files(bus); /* 创建drivers_probe与drivers_autoprobe文件 */    bus_add_groups(bus, bus->bus_groups);}  

最终模型

driver_init()最终形成的模型,如下所示:

/sys
├── bus
│ └── platform
│ ├── devices
│ ├── drivers
│ ├── drivers_autoprobe /* -rw-r–r– */
│ ├── drivers_probe /* –w——- */
│ └── uevent /* –w——- */
├── dev
│ ├── block
│ └── char
└── devices
└── platform
└── uevent /* -rw-r–r– */

0 0