尽管LDD3中说对多数程序员掌握设备驱动模型不是必要的,但对于嵌入式Linux的底层程序员而言,对设备驱动模型的学习非常重要。
Linux设备模型的目的:为内核建立一个统一的设备模型,从而又一个对系统结构的一般性抽象描述。换句话说,Linux设备模型提取了设备操作的共同属性,进行抽象,并将这部分共同的属性在内核中实现,而为需要新添加设备或驱动提供一般性的统一接口,这使得驱动程序的开发变得更简单了,而程序员只需要去学习接口就行了。
在内核里,有各种各样的总线,如 usb_bus_type、spi_bus_type、pci_bus_type、platform_bus_type、i2c_bus_type 等,内核通过总线将设备与驱动分离。此文,基于 Linux2.6.32.2 简单分析设备驱动模型,以后看具体的总线设备模型时会更加清晰。
设备模型是层次的结构,层次的每一个节点都是通过kobject实现的。在文件上则体现在sysfs文件系统。
关于kobkect,前面的文章已经分析过了,如果不清楚请移步 http://blog.csdn.net/lizuobin2/article/details/51523693
kobject 结构可能的层次结构如图:
关于 uevet mdev 前面也说过了,请参考 http://blog.csdn.net/lizuobin2/article/details/51534385
对于整个 设备总线驱动模型 的样子,大概如下图吧,也并不复杂。简单来说,bus 负责维护 注册进来的devcie 与 driver ,每注册进来一个device 或者 driver 都会调用 Bus->match 函数 将device 与 driver 进行配对,并将它们加入链表,
如果配对成功,调用Bus->probe或者driver->probe函数,
调用 kobject_uevent 函数设置环境变量,mdev进行创建设备节点等操作。后面,我们从 Bus driver 到 device三个部分进行详细的分析。
一、总线
内核通过 bus_register 进行 Bus 注册,那么它注册到了哪里,“根”在哪? 答案是 bus_kest
[cpp] view
plain copy
-
int __init buses_init(void)
-
{
-
-
bus_kset = kset_create_and_add("bus", &bus_uevent_ops, NULL);
-
if (!bus_kset)
-
return -ENOMEM;
-
return 0;
-
}
bus 的类型为 bus_type
[cpp] view
plain copy
-
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 (*resume)(struct device *dev);
-
-
const struct dev_pm_ops *pm;
-
-
struct bus_type_private *p;
-
};
[cpp] view
plain copy
-
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;
-
};
[cpp] view
plain copy
-
int bus_register(struct bus_type *bus)
-
{
-
int retval;
-
struct bus_type_private *priv;
-
-
priv = kzalloc(sizeof(struct bus_type_private), GFP_KERNEL);
-
-
-
priv->bus = bus;
-
-
bus->p = priv;
-
-
BLOCKING_INIT_NOTIFIER_HEAD(&priv->bus_notifier);
-
-
-
-
retval = kobject_set_name(&priv->subsys.kobj, "%s", bus->name);
-
-
priv->subsys.kobj.kset = bus_kset;
-
-
priv->subsys.kobj.ktype = &bus_ktype;
-
-
priv->drivers_autoprobe = 1;
-
-
-
-
retval = kset_register(&priv->subsys);
-
-
retval = 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);
-
-
klist_init(&priv->klist_devices, klist_devices_get, klist_devices_put);
-
klist_init(&priv->klist_drivers, NULL, NULL);
-
-
retval = add_probe_files(bus);
-
-
retval = bus_add_attrs(bus);
-
-
return 0;
-
-