linux设备驱动模型
在讲解设备驱动模型前,先介绍几个基本概念:
总线类型:bus_type
在linux中,所有的设备都是挂载在总线上的,比如pci,scsi,usb总线等。这些总线在sys文件系统中的反映,是在/sys/bus都会有一个属于自己的目录。linux提供了一套操作函数,比如:
bus_register():
用于向设备驱动核心注册总线,该函数会在下面做具体的 分析;
int (*match)(struct device* dev,struct device_driver*drv):
当一个新设备或者新的驱动被添加到这个总线上时,这个方法被调用一次或多次,诺制指定的驱动程序能够处理制定的设备,则返回非零值。
int (*uevent)(struct device*dev,struct kobj_uevent_env* env):
在为用户空间产生热插拔事件之前,这个方法允许总线添加环境变量
bus_for_each_dev():
bus_for_each_drv():
这两个函数迭代总线上的每个设备或驱动程序
2011-05-29
设备类型:device
每个设备都会有一个strut devcie结构,该结构通常会被内嵌到具体的设备结构体中。
与总线类似,在使用之前,先要对设备进行注册, 注册之前,最少需要设置parent,bus_id,bus,release成员,然后调用:
device_register();
设备驱动结构:device_driver
每个设备也会有一个struct device_driver结构,该结构通常也会被内嵌到具体的设备驱动结构中.设备驱动的注册通过driver_register()完成
要怎样来理解这三者的关系呢?你可以把总线看作月老,而设备是男生,设备驱动是女生。所有的设备和设备驱动在出生的时候都会在相应的总线上进行注册。而月老呢,一旦有男生或者女生注册过来,就会调用准备好的match函数,为这个男生去匹配所有的女生,或者为这个女生匹配所有的男生。如果,匹配成功,就将driver中的device指针指向这个device,把device的driver指针指向这个drive,然后,王子和公主就可以幸福的在一起了。同时,就像结婚需要登记一样,内核就像一个国家,为了统一管理,创建了一个叫/sys的文件系统。
说起文件系统,大家的概念都是在磁盘或者其它存储介质上数据的一种组织方式。而/sys有点特别,它并没有存在在具体的介质上,换句话说,它没有身体,只有灵魂。每次系统掉电以后,它就消失了。而在你访问它的时候,它是根据驱动模型的层次结构动态生成的。设备驱动模型的层次结构,又是怎样组织起来的呢?这就是我们下面具体要讲的东西了。
在驱动模型中,有几个比较总要的结构,按层次结构,从上往下分别为:
subsysterm->kset->kobject
子系统:
是对整个内核中一些高级部分的表述。它通常显示在sysfs分层结构的顶层。但在我的2.6.38内核中,貌似已经没有独立的subsysterm结构体了,而只存在kset结构体。
kset:
kset的主要功能是包容;我们可以认为它是kobject的顶层容器类,是相同类型的kobject的集合。实际上,每个kset内部都包含了一个kobject结构体,并且可以用多种处理kobject的方法来处理kset。需要注意的是,kset总是在sysfs中出现,一旦设置了kset并把它添加到了系统中,将在sysfs中创建一个目录吧。kobject不必在sysfs中表示,但是kset中的每一个kobject成员都将在sysfs中得到表述。
kobject:
kobject是组成设备模型的基本结构。单独的使用它是没有任何意义的。通常情况下,他会被内嵌到大型的数据机构中,用来控制对大型域的访问。比如最简单的字符驱动,会内嵌有kobject结构体:
struct cdev{
struct kobject kobj;
struct modle* owner;
struct file_operations* ops;
struct list_head list;
dev_t dev;
unsigned int count;
};
下面我们通过来分析bus_register这个函数,来对驱动模型有一个更加感性的认识,先贴上bus_register的代码:
/**
* bus_register - register a bus with the system.
* @bus: bus.
*
* Once we have that, we registered the bus with the kobject
* infrastructure, then register the children subsystems it has:
* the devices and drivers that belong to the bus.
*/
880 int 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;
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:
bus->p = NULL;
return retval;
}
首先看第883行,定义了一个struct bus_type_private类型的指针priv,该数据结构指针是bus_type结构体中的最后一个成员,如下:
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;
};
从结构的定义中,就可以看出,该结构定义了很多跟驱动模型相关的数据成员。看到第一个成员就是subsys,该成员实际上就是上面所说的subsysterm机构,只是在2.6.34中,该结构体已经完全呗kset结构体 所取代了。然后看第二个和第三个成员:struct kset* drivers_kset, struct kset* devices_kset,他们在下面会分别指向对应的/sys文件系统该bus目录下的device目录和driver目录。
继续看代码,第889和890行,新分配的priv结构体与bus_type进行了绑定,然后调用kobject_set_name()函数,对bus的name进行了初始化。看898行,这个很关键,他把priv->subsys.kobj.kset = bus_kset. 跳到bus_kset的定义出可以看到,实际上bus_kset也是个kset类型。他是在sys系统初始化的时候被注册到系统的,实际上/sys/bus目录就是由该bus_kset生成的。 同时,所有的总线kset的父kset都是bus_kset,所有的总线目录,比如PCI,USB等,都会在/sys/bus有相应的总线目录,比如/sys/bus/pci,/sys/bus/usb。
在902行,函数调用了kset_register()进行了注册。这是很核心的函数,需要仔细看,先贴出他的代码:
/**
* kset_register - initialize and add a kset.
* @k: kset.
*/
712 int kset_register(struct kset *k)
713 {
714 int err;
715
716 if (!k)
717 return -EINVAL;
718
719 kset_init(k);
720 err = kobject_add_internal(&k->kobj);
721 if (err)
722 return err;
723 kobject_uevent(&k->kobj, KOBJ_ADD);
724 return 0;
725 }
看到这个函数很短,但是,并不简单,原因是他调用了几个并不简单的函数。首先是kset_init():
/**
* kset_init - initialize a kset for use
* @k: kset
*/
671 void kset_init(struct kset *k)
672 {
673 kobject_init_internal(&k->kobj);
674 INIT_LIST_HEAD(&k->list);
675 spin_lock_init(&k->list_lock);
676 }
这个函数还是比较简单的,分别是对kobj,k->list节点,和list_lock自旋锁进行了初始化。跳进kobject_init_internal(),可以发现,对kobject的初始化,主要是初始话了kref引用指针,将其初始值设为了1,然后是初始了Kobj中的相关变量,这里不再缀诉。
让我们回到kset_register()中,看kobject_add_internal(),真正的好戏才开始:
static int kobject_add_internal(struct kobject *kobj)
{
int error = 0;
struct kobject *parent;
if (!kobj)
return -ENOENT;
if (!kobj->name || !kobj->name[0]) {
WARN(1, "kobject: (%p): attempted to be registered with empty "
"name!/n", kobj);
return -EINVAL;
}
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;
}
pr_debug("kobject: '%s' (%p): %s: parent: '%s', set: '%s'/n",
kobject_name(kobj), kobj, __func__,
parent ? kobject_name(parent) : "<NULL>",
kobj->kset ? kobject_name(&kobj->kset->kobj) : "<NULL>");
error = create_dir(kobj);
if (error) {
kobj_kset_leave(kobj);
kobject_put(parent);
kobj->parent = NULL;
/* be noisy on error issues */
if (error == -EEXIST)
printk(KERN_ERR "%s failed for %s with "
"-EEXIST, don't try to register things with "
"the same name in the same directory./n",
__func__, kobject_name(kobj));
else
printk(KERN_ERR "%s failed for %s (%d)/n",
__func__, kobject_name(kobj), error);
dump_stack();
} else
kobj->state_in_sysfs = 1;
return error;
}
该函数,首先试图去获得该kobject的parent指针。该指针是干嘛的呢?前面介绍kset的时候说过,kset是相同类型的kobject的容器,而这种关系是通过什么方式体现呢?在kobjcet层,就是通过parent指针体现的。kobject会把该指针指向其所属kset结构下的kobject结构体中。而因为bus_register()函数,在之前并没有对该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;
}
代码段会被执行。parent指针会被初始化为bus_kset的kobject,从而建立层次关系。
初始化好后,函数调用create_dir()函数,用来建立/sys文件系统下的具体目录结构。这个函数跟linux的VFS系统有关,有点复杂,以后在分析,至此,该bus在/sys/bus下的目录已经建立,基本的层次结构建立也已经完成。
让我们回到bus_register中,下面是bus_create_file(bus,&bus_attr_uevent),顾名思义,该函数在/sys/bus/$(bus_name)目录下创建了一个bus_attr_uevent的文件。下面的kset_create_and_add("devices",NULL,&priv->subsys.kobj)和kset_create_and_add("drivers",NULL,&priv->subsys.kobj)函数会在目录/sys/bus/$(bus_name)下创建名为devices和drivers的目录。跳入kset_create_and_add()实际上也只是调用了kset_register函数而已,所以在里不再重复,有兴趣的朋友可以自己看看。
接下去,bus_register()对klist_devices和klist_drivers链表进行了初始化。所有的跟总线相关的device和drives都会挂在这两条链表上。
2011-05-29