存储技术原理分析
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人

2.6 驱动模型对象

在上面介绍了内核对象和syfs文件系统,本节分析Linux驱动模型。Linux驱动模型适用于Linux各种子系统,它描述了总线类型、设备、驱动以及类和接口之间的关系。每个子系统都有属于自己的唯一的总线类型,它上面链接了注册到这一总线类型上的多个设备,另外它还将注册到这个总线类型的多个驱动链接在一起。每个设备可能暂时还未绑定到驱动,或者可能被绑定到最多一个驱动。而驱动则可以暂时未绑定任何设备,也可能已经绑定了一个或多个设备。

总线类型、设备、驱动这三者的关系,使得子系统支持热插拔变得非常容易。早期的计算机系统不支持热插拔,驱动必须在设备被发现之前已经被加载。而支持热插拔的系统还可以允许在驱动已经加载的情况下安装设备。事实上,Linux驱动模型的处理方式是,在设备被发现时,它被加入所注册总线类型的设备链表,然后在该总线类型的驱动链表中查找可以处理这个设备的驱动并绑定。类似地,在驱动被加载时,被加入到它所注册的总线类型的驱动链表,同时在该总线类型的设备链表中查找并绑定可以处理的设备。显然,在这样的实现思路下,设备发现和驱动加载的顺序不再那么重要了。

从上面的描述我们看到,设备最多可以属于一个驱动。在某些情况下,这个限制过于严苛。比如,SCSI磁盘,它作为一个磁盘类设备,被唯一地绑定到SCSI磁盘驱动。但是,有时我们希望把它作为一个普通的SCSI设备,向它发送INQUIRY等SCSI命令。Linux驱动模型对此的解决方案是,引入类和接口。每个设备还可以唯一属于某个类,设备被链入到类的设备链表。类还有另一个接口链表,用于链接注册到该类的所有接口。在设备被发现,或接口被添加时,无论何种顺序,只要它们属于同一个类,那么接口注册的回调函数都会被作用在设备之上。

Linux驱动模型实现的对象关系如图2-11所示,图中各种关系的功能如下。

图2-11 Linux驱动模型对象之间的关系

• bus_type和bus_type_private共同描述总线类型。

• device_driver和driver_private共同描述驱动。

• device和device_private共同描述设备。

• class和class_private共同描述类。

• class_interface表示的接口。

2.6.1 总线类型

Linux驱动模型中的总线类型结构使用bus_type和bus_type_private两个结构体来表示。之所以这样,纯粹是从编程的角度来考虑的,程序员在实现一个新的总线类型时,只需要定义bus_type结构体,并实现其中的方法和函数,而不必关注那些完全被驱动模型核心使用的内部域。

但是,需要注意的是,这两个结构体是同时存在的,并且有一一对应关系。事实上,两个结构体各自有一个指针域指向对方。bus_type结构中的域和bus_type_private结构中的域分别如表2-12和表2-13所示。

表2-12 bus_type结构中的域(来自文件include/linux/device.h)

表2-13 bus_type_private结构中的域(来自文件drivers/base/base.h)

每个总线类型被注册后,将在/sys/bus下创建一个和其名字对应的子目录,在该子目录下又有两个子目录:drivers和devices。和总线类型子目录对应的内嵌的kset,即subsys域,而drivers_kset和devices_kset是指向和drivers子目录以及devices子目录对应的kset的指针。

总线类型有两个链表:一个是在该总线类型上发现的设备链表,另一个是在该总线类型上加载的驱动链表。注意这里用作链表的表头和连接件结构分别为klist和klist_node,它们实际上也是Linux内核双循环链表结构list_head的封装,具体实现的分析留给读者。

某些子系统(或模块)会定义自己的总线类型,这时初始化的一个主要工作就是向Linux内核注册其总线类型,对于某些子系统(或模块),它甚至是初始化的全部工作。

Linux驱动模型核心提供了bus_register函数(其代码如程序2-12所示),被用来注册总线类型。子系统(或模块)调用该函数前,必须已经声明了一个bus_type类型的变量,调用时将其指针作为参数传入。

程序2-12 函数bus_register()代码(摘自文件drivers/base/bus.c)

bus_register()

880int bus_register(struct bus_type *bus)
881{
882    int retval;
883    struct bus_type_private *priv;
884
885    priv = kzalloc(sizeof(struct bus_type_private), GFP_KERNEL);
886    if (!priv)
887        return -ENOMEM;
888
889    priv->bus = bus;
890    bus->p = priv;
891
892    BLOCKING_INIT_NOTIFIER_HEAD(&priv->bus_notifier);
893
894    retval = kobject_set_name(&priv->subsys.kobj, "%s", bus->name);
895    if (retval)
896        goto out;
897
898    priv->subsys.kobj.kset = bus_kset;
899    priv->subsys.kobj.ktype = &bus_ktype;
900    priv->drivers_autoprobe = 1;
901
902    retval = kset_register(&priv->subsys);
903    if (retval)
904        goto out;
905
906    retval = bus_create_file(bus, &bus_attr_uevent);
907    if (retval)
908        goto bus_uevent_fail;
909
910    priv->devices_kset = kset_create_and_add("devices", NULL,
911                         &priv->subsys.kobj);
912    if (!priv->devices_kset) {
913        retval = -ENOMEM;
914        goto bus_devices_fail;
915   }
916
917    priv->drivers_kset = kset_create_and_add("drivers", NULL,
918                         &priv->subsys.kobj);
919    if (!priv->drivers_kset) {
920        retval = -ENOMEM;
921        goto bus_drivers_fail;
922   }
923
924    klist_init(&priv->klist_devices, klist_devices_get, klist_devices_put);
925    klist_init(&priv->klist_drivers, NULL, NULL);
926
927    retval = add_probe_files(bus);
928    if (retval)
929        goto bus_probe_files_fail;
930
931    retval = bus_add_attrs(bus);
932    if (retval)
933        goto bus_attrs_fail;
934
935    pr_debug("bus: '%s': registered\n", bus->name);
936    return 0;
937
938bus_attrs_fail:
939    remove_probe_files(bus);
940bus_probe_files_fail:
941    kset_unregister(bus->p->drivers_kset);
942bus_drivers_fail:
943    kset_unregister(bus->p->devices_kset);
944bus_devices_fail:
945    bus_remove_file(bus, &bus_attr_uevent);
946bus_uevent_fail:
947    kset_unregister(&bus->p->subsys);
948    kfree(bus->p);
949out:
950    bus->p = NULL;
951    return retval;
952}

总线类型注册的主要任务是分配和初始化相关的结构,以及在sysfs文件系统中创建相应的子目录树。

我们说过,在调用这个函数前,用户已经声明了一个bus_type类型的变量,但是bus_type_private结构的空间还没有分配,第885行分配之。第889和890行让两个结构相互关联起来。

接下来对总线类型私有数据结构的内嵌kset的内嵌kobject进行初始化,包括如下内容。

• 设置其名字为总线类型名字(第894行)。

• 设置其kset为bus_kset,而后者在系统初始化过程的buses_init函数(见文件drivers/base/bus.c)中调用kset_create_and_add创建,它在sysfs文件系统中对应的目录为sys/bus,它的kset_uevent_ops为bus_uevent_ops(第895行)。

• 设置其ktype为bus_ktype(第896行)。

做过上面的设置后,调用kset_register一次性初始化总线类型私有数据结构的内嵌kset,并将它添加到sysfs文件系统。这将在sys/bus/下创建一个以总线类型名字(为叙述方便,假设为###)为名字的子目录,即sys/bus/###/。

第906~908行调用bus_create_file在该子目录下添加uevent属性文件,即sys/bus/###/uevent。这是一个只写的属性文件,这用于手动触发热插拔。热插拔机制需要用户空间服务程序(例如udevd)的配合,该程序侦听内核空间发出的uevent事件,匹配规则做相应的动作。在系统启动后内核注册了很多设备,但用户空间还没有启动,所以这些事件没有机会被处理。为此,在每个注册的设备文件夹下生成一个uevent属性文件,当服务程序启动后,可以扫描sysfs文件系统中所有uevent属性文件,向其写入add命令,从而触发uevent事件,这样服务程序就有机会处理这些事件了。

第910~915行在该子目录下添加devices子目录(即sys/bus/###/devices),对应的kset被保存在devices_kset域。以便将来在该总线类型下发现设备的时候,向对应的子目录中添加设备的符号链接。

第917~922行在该子目录下添加drivers子目录(即sys/bus/###/drivers),对应的kset被保存在drivers_kset域。以便将来在该总线类型下加载驱动的时候,向对应的子目录中添加驱动的子目录。

第924行和第925行分别初始化总线类型的设备链表和驱动链表。

第927~929行调用add_probe_files在该总线类型的子目录下添加drivers_probe和drivers_autoprobe两个文件,即sys/bus/###/drivers_probe和sys/bus/###/drivers_autoprobe。后者用来显示和修改总线类型描述符的drivers_ autoprobe域,而前者是一个只写的属性文件,向其中写任何值都会触发对总线类型对它的设备重新扫描。

最后,第931~933行调用bus_add_attrs在总线类型子目录下为声明bus_type时给出的总线类型属性添加文件。例如对于PCI总线,只定义了一个这样的属性:rescan。

和bus_register对应的函数是bus_unregister,用于总线类型注销时,它执行如下一些相反的操作。

• 调用bus_remove_attrs为总线类型删除公有属性文件,这些属性由bus_type类型变量的bus_attrs域指针所指向。

• 调用remove_probe_files从总线类型下删除probe和autoprobe两个属性文件。

• 调用kset_unregister从子树中删除drivers子目录。

• 调用kset_unregister从子树中删除devices子目录。

• 调用bus_remove_file从总线类型中删除uevent属性文件。

• 调用kset_unregister从系统中注销总线类型内嵌的kset。

Linux驱动模型核心提供了遍历每个链表的辅助函数。

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

这两个辅助函数的使用会在后面看到,它们都在成功时返回0,“错误”时返回非零值。

bus_for_each_dev函数遍历总线类型的设备链表,bus_for_each_drv函数遍历总线类型的驱动链表,对于链表中每个设备或驱动,调用传入的回调函数fn。回调函数返回零就继续处理链表的后一个设备或驱动,返回非零值则退出循环。这主要用在设备和驱动的匹配,即在设备链表中查找驱动可以绑定的设备,或者在驱动链表中查找可以绑定设备的驱动。

我们有必要对“错误”的引号做一下说明。记住设备只能被绑定到最多一个驱动。用设备在总线类型的驱动链表上寻求匹配的时候,无论是否找到匹配项,都是正常的。因为一定要区分,我们将匹配作为一种“错误”,出现时就退出循环,不需要继续处理链表中余下的驱动了。

对比地看,驱动可以绑定一个或多个设备。用驱动在总线类型的设备链表上进行匹配的时候,应该处理完所有的设备,除非出现真正意义上的错误。而且对每个设备,无论是否匹配,都是正常的。这里的错误用法采用的是正常的思维。

更具体的解释请参看后面关于device_attach和driver_attach函数的跟踪。

2.6.2 设备

Linux驱动模型中的设备,我们有时简称为驱动模型设备,使用device和device_private两个结构体来表示。两个结构体相互关联,各自有一个域指向对方。这两个结构体中的域分别如表2-14和表2-15所示。

表2-14 device结构中的域(来自文件include/linux/device.h)

表2-15 device_private结构中的域(来自文件drivers/base/base.h)

在Linux驱动模型下,每个设备被归到一种总线类型,通过bus域指向它。设备也可以属于唯一的类,由class域指向。如果设备被绑定,则通过driver域指向对应的驱动。同内核对象一样,设备也被组织成层次结构,通过parent域指向父亲设备。对应地,设备被加入到如下四个链表。

• 所属总线类型的设备链表,总线类型的klist_devices域为这个链表的表头,设备的knode_bus域为链入此链表的连接件。

• 所属类的设备链表,类的class_devices域为这个链表的表头,设备的knode_class域为链入此链表的连接件。

• 绑定它的驱动的设备链表,驱动的klist_devices域为这个链表的表头,设备的knode_driver域为链入此链表的连接件。

• 父设备的孩子链表,父设备的klist_children域为这个链表的表头,设备的knode_parent域为链入此链表的连接件。

在实际使用中,驱动模型设备被内嵌到业务子系统的设备结构中。后者通过驱动模型设备被链接到业务子系统的总线类型实例,或者被链接到业务子系统的类实例,两者取其一,也就是说每个驱动模型设备只会使用knode_bus和knode_class两个域中的一个。如果业务子系统的设备结构需要同时被链接到总线类型实例和类实例,则需要包含两个内嵌的驱动模型设备,用于链接到总线类型实例的驱动模型设备被称为通用设备,而用于链接到类实例的驱动模型设备被称为类设备。

业务子系统可以借助于驱动模型中的链表实现对设备的遍历,在其总线类型实例或类实例中查找满足某些条件的业务子系统设备。例如PCI子系统中的for_each_pci_dev宏,还有SCSI子系统中的scsi_host_lookup函数。

同样,类似于kobject,每个device都属于一种设备类型,其结构为device_type(该结构中的域如表2-16所示),定义了这种类型设备的公共方法和成员。

表2-16 device_type结构中的域(来自文件include/linux/device.h)

设备被发现后,需要向Linux驱动模型注册。设备注册的函数为device_register(其代码如程序2-13所示),它有唯一的参数,即指向device描述符的指针。调用者已经为这个device描述符分配好了空间,实际上,device描述符往往被嵌入其他结构中,它的空间随着其他结构分配。

程序2-13 函数device_register()代码(摘自文件drivers/base/core.c)

device_register()

1043int device_register(struct device *dev)
1044{
1045    device_initialize(dev);
1046    return device_add(dev);
1047}

设备注册分配两个步骤:初始化设备,以及将设备添加到sysfs。分别调用device_initialize(代码如程序2-14所示)和device_add函数(代码如程序2-15所示)。

程序2-14 函数device_initialize()代码(摘自文件drivers/base/core.c)

device_register()→device_initialize()

557void device_initialize(struct device *dev)
558{
559    dev->kobj.kset = devices_kset;
560    kobject_init(&dev->kobj, &device_ktype);
561    INIT_LIST_HEAD(&dev->dma_pools);
562    init_MUTEX(&dev->sem);
563    spin_lock_init(&dev->devres_lock);
564    INIT_LIST_HEAD(&dev->devres_head);
565    device_init_wakeup(dev, 0);
566    device_pm_init(dev);
567    set_dev_node(dev, -1);
568}

device_initializate是设备注册的第一步。我们只关注前面两行代码。第559行将设备内嵌的kobject关联到内核对象集devices_kset,而后者在系统初始化过程的devices_init函数(见文件drivers/base/core.c)中调用kset_create_and_add创建,它在sysfs文件系统中对应的目录为sys/devices。此外,devices_kset的uevent操作表并赋值为device_uevent_ops。如前所述,这将控制内核中设备状态发生变化时向用户空间发送uevent的方式。

第560行将设备的内嵌对象的对象类型设置为device_ktype,其中定义了设备的公共属性操作表,以及释放方法。后者确保在对设备的引用计数减到0时,销毁整个device结构。

程序2-15 函数device_add()代码(摘自文件drivers/base/core.c)

device_register()→device_add()

890int device_add(struct device *dev)
891{
892    struct device *parent = NULL;
893    struct class_interface *class_intf;
894    int error = -EINVAL;
895
896    dev = get_device(dev);
897    if (!dev)
898        goto done;
899
900    if (!dev->p) {
901        error = device_private_init(dev);
902        if (error)
903            goto done;
904   }
905
906    /*
907     * for statically allocated devices, which should all be converted
908     * some day, we need to initialize the name. We prevent reading back
909     * the name, and force the use of dev_name()
910     */
911    if (dev->init_name) {
912        dev_set_name(dev, "%s", dev->init_name);
913        dev->init_name = NULL;
914   }
915
916    if (!dev_name(dev)) {
917        error = -EINVAL;
918        goto name_error;
919   }
920
921    pr_debug("device: '%s': %s\n", dev_name(dev), __func__);
922
923    parent = get_device(dev->parent);
924    setup_parent(dev, parent);
925
926    /* use parent numa_node */
927    if (parent)
928        set_dev_node(dev, dev_to_node(parent));
929
930    /* first, register with generic layer. */
931    /* we require the name to be set before, and pass NULL */
932    error = kobject_add(&dev->kobj, dev->kobj.parent, NULL);
933    if (error)
934        goto Error;
935
936    /* notify platform of device entry */
937    if (platform_notify)
938        platform_notify(dev);
939
940    error = device_create_file(dev, &uevent_attr);
941    if (error)
942        goto attrError;
943
944    if (MAJOR(dev->devt)) {
945        error = device_create_file(dev, &devt_attr);
946        if (error)
947            goto ueventattrError;
948
949        error = device_create_sys_dev_entry(dev);
950        if (error)
951            goto devtattrError;
952
953        devtmpfs_create_node(dev);
954   }
955
956    error = device_add_class_symlinks(dev);
957    if (error)
958        goto SymlinkError;
959    error = device_add_attrs(dev);
960    if (error)
961        goto AttrsError;
962    error = bus_add_device(dev);
963    if (error)
964        goto BusError;
965    error = dpm_sysfs_add(dev);
966    if (error)
967        goto DPMError;
968    device_pm_add(dev);
969
970    /* Notify clients of device addition. This call must come
971     * after dpm_sysf_add() and before kobject_uevent().
972     */
973    if (dev->bus)
974        blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
975                       BUS_NOTIFY_ADD_DEVICE, dev);
976
977    kobject_uevent(&dev->kobj, KOBJ_ADD);
978    bus_probe_device(dev);
979    if (parent)
980        klist_add_tail(&dev->p->knode_parent,
981                &parent->p->klist_children);
982
983    if (dev->class) {
984        mutex_lock(&dev->class->p->class_mutex);
985        /* tie the class to the device */
986        klist_add_tail(&dev->knode_class,
987                &dev->class->p->class_devices);
988
989        /* notify any interfaces that the device is here */
990        list_for_each_entry(class_intf,
991                  &dev->class->p->class_interfaces, node)
992            if (class_intf->add_dev)
993                class_intf->add_dev(dev, class_intf);
994        mutex_unlock(&dev->class->p->class_mutex);
995   }
996done:
997    put_device(dev);
998    return error;
999 DPMError:
1000    bus_remove_device(dev);
1001 BusError:
1002    device_remove_attrs(dev);
1003 AttrsError:
1004    device_remove_class_symlinks(dev);
1005 SymlinkError:
1006    if (MAJOR(dev->devt))
1007        devtmpfs_delete_node(dev);
1008    if (MAJOR(dev->devt))
1009        device_remove_sys_dev_entry(dev);
1010 devtattrError:
1011    if (MAJOR(dev->devt))
1012        device_remove_file(dev, &devt_attr);
1013 ueventattrError:
1014    device_remove_file(dev, &uevent_attr);
1015 attrError:
1016    kobject_uevent(&dev->kobj, KOBJ_REMOVE);
1017    kobject_del(&dev->kobj);
1018 Error:
1019    cleanup_device_parent(dev);
1020    if (parent)
1021        put_device(parent);
1022name_error:
1023    kfree(dev->p);
1024    dev->p = NULL;
1025    goto done;
1026}

device_add是设备注册的第二步,负责将设备添加到系统。

设备的私有数据结构可能还没有被分配,在第900~904行分配。在第911~919行设置并验证设备的名字。然后,调用setup_parent设置设备的父亲,同时确定了设备在sysfs中的位置。这是一个比较复杂的过程,我们后面会专门讨论它。

第932~934行,调用kobject_add将设备的内嵌kobject添加到系统,这将在sys/devices/目录下添加一个以设备名为名字的子目录;

然后在sysfs文件系统中创建属性文件:第940~942行创建uevent属性对应的文件,这是一个只写的属性文件,可以从用户空间写事件到这个文件,从而手动产生事件。

第944~954行,如果设备有设备号:

• 在设备目录下创建dev属性对应的文件,这是一个只读的属性文件,用户空间读取这个文件时,将返回设备的设备号,以##:##的形式;

• 调用device_create_sys_dev_entry函数(文件drivers/base/core.c)在sys/block/或sys/char/下创建一个到设备所在目录的符号链接,链接名为##:##的形式的设备号。具体选择目录取决于设备所属的类。如果属于block_class,即为块设备,将在sys/block下创建;如果属于其他类,或者不属于任何类,都会在sys/char/下创建。

第956~958行,调用device_add_class_symlinks,如果设备属于某个类,则为设备创建和类相关的符号链接。这又包括下面的步骤:

• 在设备目录下,创建到所属类的符号链接,链接名为subsystem;

• 在所属类的目录下,创建到设备的符号链接,链接名为设备名;

• 如果设备有父设备,并且设备不为分区,在设备目录下,创建到其父设备的符号链接,链接名为device。

第959~961行,调用device_add_attrs为设备的默认属性添加对应的文件。

第962~964行,调用bus_add_device,如果设备有指定总线类型,则会将设备添加到该总线类型。这又包括下面的步骤:

• 为设备添加该总线类型下设备的公有属性文件,这些属性由设备所属bus_type类型变量的dev_attrs域指针所指向;

• 在总线类型子目录的devices目录下创建到该设备的符号链接,链接名为设备名;

• 在设备的目录下创建到总线类型的符号链接,链接名为subsystem;

• 将设备连接到总线类型的设备链表。

在bus_add_device函数过程中,还会调用make_deprecated_bus_links函数,后者被早期的版本用于在设备目录下创建另外一个到总线类型的符号链接,链接名为bus。如果内核编译未指定CONFIG_SYSFS_DEPRECATED选项,那么这个函数为空,什么也不做。

至此,设备自身的添加工作已经完成,第977行调用kobject_uevent向用户空间报告KOBJ_ADD事件。

然后调用bus_probe_device试图将设备绑定到某个驱动,这个过程我们也在后面专门讨论。

第979~981行,如果指定了parent,则将设备添加到它的孩子链表中。

此外,第983~995行,如果设备设置了class域,则将设备添加到类的设备链表。而且,对于注册到该类的每个接口,如果定义了add_dev回调函数,则调用它。这个动作是系统对设备热插处理在类上的体现。

到现在,设备注册过程已经比较完整了,除了第924行的setup_parent函数和第978行的bus_probe_device函数。它们的作用都很重要,并且过程也比较复杂,下面用专门的篇幅来讨论。

1.设备在sysfs的位置

setup_parent函数的根本目的就是确定设备在sysfs文件系统中的位置。之所以说它重要,是因为理解内核对象之间的层次关系就是理解Linux驱动模型的一个关键。

分析device的结构,可以看到有两个parent域:

• device描述符的parent域,指向设备的父设备;

• device描述符内嵌的kobject的parent域,决定了设备在sysfs文件系统中的位置。

setup_parent函数(其代码如程序2-16所示)的实质就是为后者赋值。它传入两个参数:第一个为指向设备本身的device描述符的指针;第二个为指向其父设备的device描述符的指针。

程序2-16 函数setup_parent()代码(摘自文件drivers/base/core.c)

device_register()→device_add()→setup_parent()

676static void setup_parent(struct device *dev, struct device *parent)
677{
678    struct kobject *kobj;
679    kobj = get_device_parent(dev, parent);
680    if (kobj)
681        dev->kobj.parent = kobj;
682}

setup_parent函数将主要工作交给get_device_parent函数(其代码如程序2-17所示)。若后者的返回值非NULL,则保存在设备的内嵌对象的parent域。

程序2-17 函数get_device_parent()代码(摘自文件drivers/base/core.c)

device_register()→device_add()→setup_parent()→get_device_parent()

599static struct kobject *get_device_parent(struct device *dev,
600                     struct device *parent)
601{
602    int retval;
603
604    if (dev->class) {
605        static DEFINE_MUTEX(gdp_mutex);
606        struct kobject *kobj = NULL;
607        struct kobject *parent_kobj;
608        struct kobject *k;
609
610        /*
611         * If we have no parent, we live in "virtual".
612         * Class-devices with a non class-device as parent, live
613         * in a "glue" directory to prevent namespace collisions.
614         */
615        if (parent == NULL)
616            parent_kobj = virtual_device_parent(dev);
617        else if (parent->class)
618            return &parent->kobj;
619        else
620            parent_kobj = &parent->kobj;
621
622        mutex_lock(&gdp_mutex);
623
624        /* find our class-directory at the parent and reference it */
625        spin_lock(&dev->class->p->class_dirs.list_lock);
626        list_for_each_entry(k, &dev->class->p->class_dirs.list, entry)
627            if (k->parent == parent_kobj) {
628                kobj = kobject_get(k);
629                break;
630           }
631        spin_unlock(&dev->class->p->class_dirs.list_lock);
632        if (kobj) {
633            mutex_unlock(&gdp_mutex);
634            return kobj;
635       }
636
637        /* or create a new class-directory at the parent device */
638        k = kobject_create();
639        if (!k) {
640            mutex_unlock(&gdp_mutex);
641            return NULL;
642       }
643        k->kset = &dev->class->p->class_dirs;
644        retval = kobject_add(k, parent_kobj, "%s", dev->class->name);
645        if (retval < 0) {
646            mutex_unlock(&gdp_mutex);
647            kobject_put(k);
648            return NULL;
649       }
650        /* do not emit an uevent for this simple "glue" directory */
651        mutex_unlock(&gdp_mutex);
652        return k;
653   }
654
655    if (parent)
656        return &parent->kobj;
657    return NULL;
658}

决定device描述符的内嵌kobject的父kobject的因素有如下三个:

• 设备本身device描述符的parent域;

• 设备本身device描述符的class域;

• 父设备device描述符的class域(如果父设备存在的话)。

Linux当前版本的处理方法和以前版本稍有不同。我们只考虑当前版本的处理规则,即代码中未定义CONFIG_SYS_DEPRECATED的部分。设置设备内嵌内核对象的父对象的情况有6种,如图2-12所示,具体说明如下。

• device有class,有parent,且parent有class,不管parent->class和device->class是否相同,parent_kobj都为parent内嵌的kobject;这分别对应图中的情况①和②。

• device有class,有parent,且parent没有class,则parent_obj为新创建的一个kobject,保存在class的class_dirs(这是个kset)里。这个新创建的kobject的parent为parent内嵌的kobject,名称为device的class_name,也就是说,它对应的sysfs目录为sys/devices/.../parent_name/ class_name/。这对应图中的情况③。

图2-12 设置设备内嵌内核对象的父对象

• device有class,没有parent,则parent_kobj为新创建的一个kobject,保存在class的class_dirs(这是个kset)里。这个新创建的kobject的parent为sys/devices/virtual/目录对应的kobject,名称为device的class_name,也就是说,它对应的sys目录为sys/devices/virtual/class_name。这对应图中的情况④。

• device无class,有parent,则device->kobj.parent = parent.kobj。这对应图中的情况⑤。

• device无class,无parent,则device->kobj.parent为空。这对应图中的情况⑥。应该说这是一种理论上的可能,在Linux代码中没有找到这样的例子(万一出现,设备目录将直接建在sys/之下)。我们将它列举在这里,纯粹出于完整性的考虑。

对于情况③和④的补充说明:class_dirs是用于保存那些为了将其父设备为空,或其父设备的class为空的设备挂入sys/devices/子树,而新创建的内核对象,它将这些内核对象链接在一起。这些内核对象将作为前述设备内嵌内核对象的父对象。

综合上述情况,deivce在sysfs中的目录有以下几种形式:

• sys/devices/.../parent_name/device_name;

• sys/devices/.../parent_name/class_name/device_name;

• sys/devices/virtual/class_name/device_name。

如果采用新规则,所有的设备都放在sys/devices/目录下(这不同于旧规则将设备分散在sys/devices/和sys/class/两个目录中),这个系统的设备树统一在sys/devices/一个目录中。

2.将设备绑定到驱动

将设备添加到系统,还需要尝试将设备绑定到驱动。我们现在来看对bus_probe_device函数(其代码如程序2-18所示)的调用。它只有一个参数,即指向设备本身的device描述符的指针;

程序2-18 函数bus_probe_device()代码(摘自文件drivers/base/bus.c)

device_register()→device_add()→bus_probe_device()

509void bus_probe_device(struct device *dev)
510{
511    struct bus_type *bus = dev->bus;
512    int ret;
513
514    if (bus && bus->p->drivers_autoprobe) {
515        ret = device_attach(dev);
516        WARN_ON(ret < 0);
517   }
518}

从字面上理解,这个函数的功能是自动探测设备,探测的主体是总线类型上的驱动。探测需要设备所在总线类型的支持。如果设备不属于任何总线类型,或者总线类型没有自动探测能力(即driver_autoprobe域为0),则什么也不需要做;否则调用device_attach函数,其代码如程序2-19所示。

程序2-19 函数device_attach()代码(摘自文件drivers/base/dd.c)

device_register()→device_add()→bus_probe_device()→device_attach()

238int device_attach(struct device *dev)
239{
240    int ret = 0;
241
242    device_lock(dev);
243    if (dev->driver) {
244        ret = device_bind_driver(dev);
245        if (ret == 0)
246            ret = 1;
247        else {
248            dev->driver = NULL;
249            ret = 0;
250       }
251   } else {
252        pm_runtime_get_noresume(dev);
253        ret = bus_for_each_drv(dev->bus, NULL, dev, __device_attach);
254        pm_runtime_put_sync(dev);
255   }
256    device_unlock(dev);
257    return ret;
258

device_attach函数的目的是试图将设备绑定到某个驱动,返回1表示设备被绑定到驱动,返回0表示没有找到匹配的驱动。在调用device_attach时,存在两种情况:

• 已经为设备指定了驱动,即设备的driver域已经设置,就直接调用device_bind_driver函数。如果它返回错误,说明设备没办法被绑定到这个驱动,那么就清零设备的driver域,将错误报告给调用者;

• 否则遍历总线类型的驱动链表,调用__device_attach函数(其代码如程序2-20所示)尝试将设备绑定到这些驱动。如果设备不能被绑定到任何驱动,那么bus_for_each_drv宏最终会返回0,我们直接回传给调用者,报告错误。

我们只跟踪后面一种情况的执行流程。事实上,前面一种情况,所做的工作只是其中的一部分。

程序2-20 函数__device_attach()代码(摘自文件drivers/base/dd.c)

device_register()→device_add()→bus_probe_device()→device_attach()→__device_attach()

214static int __device_attach(struct device_driver *drv, void *data)
215{
216    struct device *dev = data;
217
218    if (!driver_match_device(drv, dev))
219        return 0;
220
221    return driver_probe_device(drv, dev);
222}

记住,__device_attach函数试图绑定具体驱动和具体设备。同样,它返回1表示设备被绑定到驱动,返回0表示没有找到匹配的驱动。这个返回值被bus_for_each_drv宏进行了非正常思维的解释:返回1被当成一种“错误”,遇到即退出循环,放弃处理驱动链表中余下的驱动。

它调用driver_match_device函数(其代码如程序2-21所示)检查是否匹配,匹配失败,返回0。若匹配成功,则调用driver_probe_device函数(其代码如程序2-22所示)进一步探测,并向调用者传递它的返回值:成功时为1;否则为0。

程序2-21 函数driver_match_device()代码(摘自文件drivers/base/base.h)

device_register()→device_add()→bus_probe_device()→device_attach()→__device_attach()
→driver_match_device()

120static inline int driver_match_device(struct device_driver *drv,
121                   struct device *dev)
122{
123    return drv->bus->match ? drv->bus->match(dev, drv) : 1;
124}

驱动和设备的匹配是子系统特定的,Linux驱动模型必须通过回调函数来实现。子系统在声明总线类型时,可以给出其match方法。它以device和device_driver作为其参数,在具体实现中,需要先转换为对应的设备和驱动描述符(例如pci_dev和pci_driver)。match回调函数判断驱动是否能“匹配”设备。若是,返回1;否则返回0。如果没定义match回调函数,我们直接返回1。认为是总线类型自动匹配了驱动和设备。

程序2-22 函数driver_probe_device()代码(摘自文件drivers/base/dd.c)

device_register()→device_add()→bus_probe_device()→device_attach()→__device_attach()
→driver_probe_device()

196int driver_probe_device(struct device_driver *drv, struct device *dev)
197{
198    int ret = 0;
199
200    if (!device_is_registered(dev))
201        return -ENODEV;
202
203    pr_debug("bus: '%s': %s: matched device %s with driver %s\n",
204         drv->bus->name, __func__, dev_name(dev), drv->name);
205
206    pm_runtime_get_noresume(dev);
207    pm_runtime_barrier(dev);
208    ret = really_probe(dev, drv);
209    pm_runtime_put_sync(dev);
210
211    return ret;
212}

进一步探测设备要求设备已经注册。如果设备被注册,对本驱动以及后续驱动的匹配都没有意义,返回负的错误码,这是一种真正意义上的错误。

这个函数调用了多个与电源管理有关的函数,因为电源管理不是本书的重点,我们跳过它们,直接跟踪第208行的really_probe函数,其代码如程序2-23所示。

程序2-23 函数really_probe()代码(摘自文件drivers/base/dd.c)

device_register()→device_add()→bus_probe_device()→device_attach()→__device_attach()
→driver_probe_device()→really_probe()

104static int really_probe(struct device *dev, struct device_driver *drv)
105{
106    int ret = 0;
107
108    atomic_inc(&probe_count);
109    pr_debug("bus: '%s': %s: probing driver %s with device %s\n",
110         drv->bus->name, __func__, drv->name, dev_name(dev));
111    WARN_ON(!list_empty(&dev->devres_head));
112
113    dev->driver = drv;
114    if (driver_sysfs_add(dev)) {
115        printk(KERN_ERR "%s: driver_sysfs_add(%s) failed\n",
116            __func__, dev_name(dev));
117        goto probe_failed;
118   }
119
120    if (dev->bus->probe) {
121        ret = dev->bus->probe(dev);
122        if (ret)
123            goto probe_failed;
124   } else if (drv->probe) {
125        ret = drv->probe(dev);
126        if (ret)
127            goto probe_failed;
128   }
129
130    driver_bound(dev);
131    ret = 1;
132    pr_debug("bus: '%s': %s: bound device %s to driver %s\n",
133         drv->bus->name, __func__, dev_name(dev), drv->name);
134    goto done;
135
136probe_failed:
137    devres_release_all(dev);
138    driver_sysfs_remove(dev);
139    dev->driver = NULL;
140
141    if (ret != -ENODEV && ret != -ENXIO) {
142        /* driver matched but the probe failed */
143        printk(KERN_WARNING
144            "%s: probe of %s failed with error %d\n",
145            drv->name, dev_name(dev), ret);
146   }
147    /*
148     * Ignore errors returned by ->probe so that the next driver can try
149     * its luck.
150     */
151    ret = 0;
152done:
153    atomic_dec(&probe_count);
154    wake_up(&probe_waitqueue);
155    return ret;
156}

最终,如果设备可以绑定到驱动,则需要执行下列操作:

• 第113行将设备的driver域指向驱动;

• 第114~118行,调用driver_sysfs_add在sysfs文件系统中“绑定”,即在驱动对应的目录下创建目标为设备的符号链接,链接名使用设备名,同时在设备对应的目录下创建目标为驱动的符号链接,链接名为“driver”;

• 第120~128行,如果设备的总线类型给出了probe方法,则调用之;否则如果设备的驱动给出了probe方法,调用之。probe函数返回0表示成功;否则返回错误码;

• 第130行调用driver_bound将设备链入驱动的设备链表。

如果一切正常,really_probe函数返回1,表示匹配成功。如果中间出现问题,回滚已经做过的操作,向调用者返回0。

我们再看一下总线类型和驱动的probe回调函数(如图2-13所示)。这两个函数都是在设备可以被绑定到驱动的情况下,用来对设备进行初始化。若成功,返回0;否则返回错误码。

对于PCI子系统,总线类型的probe回调函数是pci_device_probe,驱动的probe回调函数为NULL。PCI设备的初始化是具体HBA特定的,比如PCI-SCSI适配器要在这时开始SCSI设备扫描,因此pci_device_probe进而会调用PCI驱动的probe回调函数,即具体HBA驱动的探测方法实现。注意,这里驱动的probe回调函数是指device_driver结构的probe域;而PCI驱动的probe回调函数是指pci_driver结构的probe域。

对于SCSI子系统,总线类型的probe回调函数为NULL,驱动的probe回调函数随具体SCSI驱动的定义提供。例如对于SCSI磁盘驱动,该回调函数被定义为sd_probe,它将为这个SCSI磁盘设备分配通用磁盘描述符。

总结一下,Linux驱动模型会为设备在sysfs文件系统中创建的符号链接列举如下。相应代码分散在前面的函数里,集中整理于此。

类相关的符号链接:

• device对应的目录下,名称为subsystem,指向device->class对应的目录;

图2-13 PCI驱动和SCSI驱动的probe回调函数

• device->class对应的目录下,名称为device_name,指向device对应的目录,仅当device对应的目录不在device->class对应的目录下,并且device不是块设备分区的情况下才创建;

• device对应的目录下,名称为device,指向device->parent对应的目录,仅当device有parent并且device不是块设备分区的情况下才创建。

总线类型相关的符号链接:

• device->bus的devices_kset对应的目录下,名称为device_name,指向device对应的目录;

• device对应的目录下,名称为subsystem,指向device->bus对应的目录。

驱动相关的符号链接:

• device->driver对应的目录下,名称为device_name,指向device对应的目录;

• device对应的目录下,名称为driver,指向device->driver对应的目录。

注意:在device对应的目录下,名称为subsystem的符号链接,可能指向device->class或是device->bus对应的目录。这里并不会出现冲突的情况,即便对应SCSI设备(可能属于总线类型scsi_bus_type或类sg_sysfs_class)。它在scsi_device结构中定义了两个内嵌对象域(内嵌通用对象域和内嵌类对象域)。

和device_register对应的函数是device_unregister,用于从系统注销设备。

2.6.3 驱动

同总线类型和设备一样,在Linux驱动模型中表示一个驱动也需要两个结构体:device_driver和driver_private。这两个结构体同时存在,并且一一对应。程序员在遵循驱动模型编程时只需要实现device_driver,其结构中的域如表2-17所示,而结构体driver_private中的域如表2-18所示。

表2-17 device_driver结构中的域(来自文件include/linux/device.h)

表2-18 driver_private结构中的域(来自文件drivers/base/base.h)

驱动和总线类型与设备的关系是:驱动的bus域指向所属的总线类型,以knode_bus域为连接件链入到它以klist_drivers域为表头的驱动链表。驱动还有一个绑定到它的设备链表,以klist_devices为表头,设备链入此链表的连接件为knode_driver域。

在驱动被加载时,需要向Linux驱动模型注册,为此调用它提供的公共函数driver_register(其代码如程序2-24所示)。这个函数具有唯一的参数,指向device_driver描述符的指针。

程序2-24 函数driver_register()代码(摘自文件drivers/base/driver.c)

driver_register()

222int driver_register(struct device_driver *drv)
223{
224    int ret;
225    struct device_driver *other;
226
227    BUG_ON(!drv->bus->p);
228
229    if ((drv->bus->probe && drv->probe) ||
230      (drv->bus->remove && drv->remove) ||
231      (drv->bus->shutdown && drv->shutdown))
232        printk(KERN_WARNING "Driver '%s' needs updating - please use "
233            "bus_type methods\n", drv->name);
234
235    other = driver_find(drv->name, drv->bus);
236    if (other) {
237        put_driver(other);
238        printk(KERN_ERR "Error: Driver '%s' is already registered, "
239            "aborting...\n", drv->name);
240        return -EBUSY;
241   }
242
243    ret = bus_add_driver(drv);
244    if (ret)
245        return ret;
246    ret = driver_add_groups(drv, drv->groups);
247    if (ret)
248        bus_remove_driver(drv);
249    return ret;
250}

在注册驱动前,必须为驱动指定了总线类型,并且该总线类型已经注册到Linux驱动模型,第227行确保这一点。

第229~233行给出一个警告消息,如果总线类型和驱动都定义了相同名字的函数。实际上,Linux驱动模型只会使用其中的一个。前面,在really_probe函数中,我们已经看到过了。

第235~241行调用driver_find在总线类型的驱动链表中查找该驱动名,如果找到,表明这个驱动名已经在使用中,我们只好返回错误。

否则继续,在第243行调用bus_add_driver添加驱动到系统,我们马上会详细分析它。

如果一切正常,第246行添加驱动的属性组文件并结束驱动注册过程。

就驱动注册来讲,函数bus_add_driver(该函数的代码如程序2-25所示)无疑是最主要的函数,因为大部分工作还是要在总线类型上做的。这个函数返回0表示成功,否则表示错误。

程序2-25 函数bus_add_driver代码(摘自文件drivers/base/bus.c)

driver_register()→bus_add_driver()

648int bus_add_driver(struct device_driver *drv)
649{
650    struct bus_type *bus;
651    struct driver_private *priv;
652    int error = 0;
653
654    bus = bus_get(drv->bus);
655    if (!bus)
656        return -EINVAL;
657
658    pr_debug("bus: '%s': add driver %s\n", bus->name, drv->name);
659
660    priv = kzalloc(sizeof(*priv), GFP_KERNEL);
661    if (!priv) {
662        error = -ENOMEM;
663        goto out_put_bus;
664   }
665    klist_init(&priv->klist_devices, NULL, NULL);
666    priv->driver = drv;
667    drv->p = priv;
668    priv->kobj.kset = bus->p->drivers_kset;
669    error = kobject_init_and_add(&priv->kobj, &driver_ktype, NULL,
670                   "%s", drv->name);
671    if (error)
672        goto out_unregister;
673
674    if (drv->bus->p->drivers_autoprobe) {
675        error = driver_attach(drv);
676        if (error)
677            goto out_unregister;
678   }
679    klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers);
680    module_add_driver(drv->owner, drv);
681
682    error = driver_create_file(drv, &driver_attr_uevent);
683    if (error) {
684        printk(KERN_ERR "%s: uevent attr (%s) failed\n",
685            __func__, drv->name);
686   }
687    error = driver_add_attrs(bus, drv);
688    if (error) {
689        /* How the hell do we get out of this pickle? Give up */
690        printk(KERN_ERR "%s: driver_add_attrs(%s) failed\n",
691            __func__, drv->name);
692   }
693
694    if (!drv->suppress_bind_attrs) {
695        error = add_bind_files(drv);
696        if (error) {
697            /* Ditto */
698            printk(KERN_ERR "%s: add_bind_files(%s) failed\n",
699                __func__, drv->name);
700       }
701   }
702
703    kobject_uevent(&priv->kobj, KOBJ_ADD);
704    return 0;
705
706out_unregister:
707    kobject_put(&priv->kobj);
708    kfree(drv->p);
709    drv->p = NULL;
710out_put_bus:
711    bus_put(bus);
712    return error;
713}

因为要把驱动添加到总线类型,自然驱动描述符的bus域应该已经设置。第654~656行的代码确保这一点。

一般来说,驱动的私有数据结构应该还没有被分配,在第660~664行进行分配,并在第666和667行将它和驱动结构相互关联在一起。

然后,第668行,将驱动通过私有数据结构的内嵌kobj关联到总线类型的drivers_kset,接下来,第669行执行kobject_init_and_add会添加驱动到sysfs文件系统,将它放在总线类型所对应目录的drivers子目录下。

第673~678行,如果总线类型支持自动探测,我们调用driver_attach。这个函数(其代码如程序2-26所示)在后面分析。

第679行将驱动添加到总线类型的驱动链表。

接下来,在驱动目录下创建各种属性文件:

• 第682~685行,调用driver_create_file在驱动子目录下添加uevent属性文件,即sys/bus/###/drivers/###/ uevent。这是一个只写的属性文件,可以从用户空间写事件到这个文件,从而手动产生事件;

• 第687~692行,调用driver_add_attrs为驱动的默认属性添加对应的文件;

• 第694~701行,如果允许通过sysfs文件系统从用户空间绑定/松绑,则调用add_bind_files,这会在驱动目录下创建bind和unbind两个属性文件。这两个文件都是只写的,被用来手动绑定某个设备,或者松绑某个设备。

至此,驱动自身的添加工作已经完成,第703行调用kobject_uevent函数向用户空间报告KOBJ_ADD事件。

程序2-26 函数driver_attach()代码(摘自文件drivers/base/dd.c)

driver_register()→bus_add_driver()→driver_attach()

299int driver_attach(struct device_driver *drv)
300{
301    return bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);
302}

driver_attach函数的目的是试图将驱动去绑定所有可能的设备,成功返回0,否则返回非零值。

它调用bus_for_each_dev遍历总线类型的设备链表,调用是传入__driver_attach作为回调函数(其代码如程序2-27所示)。

程序2-27 函数__driver_attach()代码(摘自文件drivers/base/dd.c)

driver_register()→bus_add_driver()→driver_attach()→__driver_attach()

261static int __driver_attach(struct device *dev, void *data)
262{
263    struct device_driver *drv = data;
264
265    /*
266     * Lock device and try to bind to it. We drop the error
267     * here and always return 0, because we need to keep trying
268     * to bind to devices and some drivers will return an error
269     * simply if it didn't support the device.
270     *
271     * driver_probe_device() will spit a warning if there
272     * is an error.
273     */
274
275    if (!driver_match_device(drv, dev))
276        return 0;
277
278    if (dev->parent)    /* Needed for USB */
279        device_lock(dev->parent);
280    device_lock(dev);
281    if (!dev->driver)
282        driver_probe_device(drv, dev);
283    device_unlock(dev);
284    if (dev->parent)
285        device_unlock(dev->parent);
286
287    return 0;
288}

到了__driver_attach函数,我们又碰到了具体驱动和具体设备的绑定问题。除了为某些USB设备所加入的特定锁代码,大体流程和__device_attach是相同的。这里也调用了driver_match_device和driver_probe_device两个函数。需要注意,这个函数只返回0,因为当前没有一种错误可以阻止我们让驱动继续尝试匹配设备链表的下一个设备。

关于device_attach和driver_attach函数,做一个小结:

• device_attach函数的目的是试图将设备绑定到某个驱动。它以回调函数__device_attach调用bus_for_each_drv。device_attach和__device_attach函数都用返回1表示设备被绑定到驱动,返回0表示没有找到匹配的驱动;

• driver_attach函数的目的是试图将驱动去绑定所有可能的设备。它以回调函数__driver_attach调用bus_for_each_dev。driver_attach和__driver_attach函数都用返回0表示成功,返回1表示错误。但实际上__driver_attach函数只会返回0。

和driver_register对应的函数是driver_unregister,用于从系统注销驱动。

2.6.4 类

Linux驱动模型中的类用相互关联的class和class_private域表示。class结构中的域如表2-19所示,class_private结构中的域如表2-20所示。

表2-19 class结构中的域(来自文件include/linux/class.h)

表2-20 class_private结构中的域(来自文件drivers/base/base.h)

每个类有一个内嵌的kset,即class_subsys域,因为它,在类被注册后,会在/sys/class下创建一个和类名对应的子目录。类有两个链表,一个链接属于该类的所有设备,另一个链接注册到这个类的接口。另外,需要说明的是class_dirs域,它的作用在前面已经介绍过。

子系统要注册类,需调用Linux驱动模型提供的class_register方法。它被定义为一个宏,在文件include/linux/device.h,是__class_register的简单封装。我们直接看__class_register,其函数的代码如程序2-28所示。

程序2-28 函数__class_register()代码(摘自文件drivers/base/class.c)

__class_register()

154int __class_register(struct class *cls, struct lock_class_key *key)
155{
156    struct class_private *cp;
157    int error;
158
159    pr_debug("device class '%s': registering\n", cls->name);
160
161    cp = kzalloc(sizeof(*cp), GFP_KERNEL);
162    if (!cp)
163        return -ENOMEM;
164    klist_init(&cp->class_devices, klist_class_dev_get, klist_class_dev_put);
165    INIT_LIST_HEAD(&cp->class_interfaces);
166    kset_init(&cp->class_dirs);
167    __mutex_init(&cp->class_mutex, "struct class mutex", key);
168    error = kobject_set_name(&cp->class_subsys.kobj, "%s", cls->name);
169    if (error) {
170        kfree(cp);
171        return error;
172   }
173
174    /* set the default /sys/dev directory for devices of this class */
175    if (!cls->dev_kobj)
176        cls->dev_kobj = sysfs_dev_char_kobj;
177
178#if defined(CONFIG_SYSFS_DEPRECATED) && defined(CONFIG_BLOCK)
179    /* let the block class directory show up in the root of sysfs */
180    if (cls != &block_class)
181        cp->class_subsys.kobj.kset = class_kset;
182#else
183    cp->class_subsys.kobj.kset = class_kset;
184#endif
185    cp->class_subsys.kobj.ktype = &class_ktype;
186    cp->class = cls;
187    cls->p = cp;
188
189    error = kset_register(&cp->class_subsys);
190    if (error) {
191        kfree(cp);
192        return error;
193   }
194    error = add_class_attrs(class_get(cls));
195    class_put(cls);
196    return error;
197}

第161~163行分配类的私有数据结构,接着进行一些初始化。第168~172行设置类的class_subsys域的内嵌kobject的名字为类的名字,这就是显示在/sys/class/下的类的目录名。

早期的类被分开放置。block类位于/sys/目录下,而其他类则位于/sys/class/目录下,最新版本的内核作了统一。所有类都被放在/sys/class/目录下,这就是第178~184行代码产生的效果。

第186和187行,将类结构和类私有数据结构相互关联起来。

第189~193行调用kset_register注册类的class_subsys,这最终创建类在sysfs文件系统中的对应目录。第194行,调用add_class_attrs在类的目录下创建默认的类属性文件。

和class_register对应的函数是class_unregister,用于从系统注销类。

2.6.5 接口

相对于前面的结构,接口比较简单,它用class_interface(其结构中的域如表2-21所示)来表示。

表2-21 class_interface结构中的域(来自文件include/linux/device.h)

每个接口都是相对于某个类的,通过class域指向它。接口被链接到类的接口链表,类的class_interfaces域为表头,接口的node域为连接件。

Linux驱动模型提供用于类接口注册的公共函数为class_interface_register,该函数的代码如程序2-29所示。

程序2-29 函数class_interface_register()代码(摘自文件drivers/base/class.c)

class_interface_register()

447int class_interface_register(struct class_interface *class_intf)
448{
449    struct class *parent;
450    struct class_dev_iter iter;
451    struct device *dev;
452
453    if (!class_intf || !class_intf->class)
454        return -ENODEV;
455
456    parent = class_get(class_intf->class);
457    if (!parent)
458        return -EINVAL;
459
460    mutex_lock(&parent->p->class_mutex);
461    list_add_tail(&class_intf->node, &parent->p->class_interfaces);
462    if (class_intf->add_dev) {
463        class_dev_iter_init(&iter, parent, NULL, NULL);
464        while ((dev = class_dev_iter_next(&iter)))
465            class_intf->add_dev(dev, class_intf);
466        class_dev_iter_exit(&iter);
467   }
468    mutex_unlock(&parent->p->class_mutex);
469
470    return 0;
471}

函数要求传入的类接口不为NULL,并且设置了class域,即被关联到某个类(第453~454行)。

注册类接口的具体操作只有两个:

• 将类接口添加到类的接口链表,这是第461行;

• 如果类接口提供了add_dev方法,对类的设备链表上的每个设备调用之,这是第462~467行。

需要强调的是后面一点,也是“热插拔”的一种表现。类接口虽然不绑定到设备,但它可以通过自定义的回调方法作用于设备,并且无论是先发现设备,还是先注册接口。

和class_interface_register对应的函数是class_interface_unregister,用于从系统注销接口。