您的位置:首页 > 运维架构 > Linux

linux驱动:设备驱动模型综述

2012-01-03 09:16 239 查看

设备驱动模型综述

已经停顿了好多天了,这部分很难看的。到现在也是懵懵懂懂,不能彻底弄清楚。很多事情是不能一步到位的,暂时这样吧,回头再搞,就此总结一下我对于linux设备驱动模型的一些理解

linux内核的设备驱动模型在网上有诸多文章介绍,但是多数是互相摘抄修改的,我也不例外的引用其中的一些说法,毕竟东西就那么一个,再怎么理解也玩不改头换面的花样。

设备驱动模型是一个用c实现c++继承的代码模型。其最底层的也可以理解为基类的结构体是kobject,之后所有的其他结构里面都直接或者间接的内嵌了一个kobject。可以认为kobject是最基本最底层的原型。在此基础上进行如下的扩充。

1,kobject是最基本的原型,是个基类

2,kobject表示的各个对象可以用链表连接起来,(用的还是linux老一套的内嵌一个list_head),然后把这个链表头赋值给kset结构体,也就是kset结构体除了包含有一个自身的kobject基类部分以外,还包含有一个链表头,该链表链出了一系列的kobject对象。

3,再上一层有个subsystem结构,该结构很简单就是封装了一个kset和一把读写锁。

4,除了上面这一条线以外,还有一条bus线,bus线我们从上往下说吧。bus_type包含了2个kset对象分别命名为devices和drivers,顾名思义,还包含了一个subsystem成员,该subsystem成员自然是描述了自身的属性,而2个kset最重要的是驱动和设备的2条链表来用。当进行bus_register的时候这2条链表中的keset->kobject->keset指针都指向bus_type->subsys->kset从而把这两条链表当中可以直接链接到bus_type最基本的kset当中来。而bus_type->subsys->kset->kobject->keset指针也无疑例外有所指向,这个指向不是自身,而是通过

#define decl_subsys(_name,_type,_hotplug_ops) \

struct subsystem _name##_subsys = { \

.kset = { \

.kobj = { .name = __stringify(_name) }, \

.ktype = _type, \

.hotplug_ops =_hotplug_ops, \

} \

}声明的一个bus_subsys的kset上。这样所有新注册的bus在系统总的bus_subsys当中链接着。bus_subsys在系统初始化的时候初始化

5,device是bus_type下面的kset的一条链表devices的内容,毫无疑问的含有一个kobject基本对象,和指向自身bus_type的指针关联的driver等

6,device_driver是bus_type下面的kset的一条链表drivers的内容,也毫无例外的含有一个kobject基本对象,和指向自身bus_type的指针关联的devices(这里带s哦,说明一个驱动可能驱动好多设备,但是一个设备只有一个驱动,这点区别在驱动和设备初始化的关联过程中也有体现)等和一些基本操作。

设备驱动模型kobject

kobject

定义如下:

struct kobject {

char * k_name;

char name[KOBJ_NAME_LEN];

struct kref kref;/* 生命周期(引用计数)管理 */

struct list_head entry;/* 用于链入所属kset 的链表 */

struct kobject * parent;

struct kset * kset;/* 所属kset */

struct kobj_type * ktype;/* 所属ktype */

struct dentry * dentry;

};

我们来看分析这个结构

1,kref指明了该对象被引用的次数,是一个模拟智能指针的做法,只有当引用次数为0,才销毁对象。所以,当其他对象的指针指向该object的时候,应该使用函数

extern struct kobject * kobject_get(struct kobject *);

extern void kobject_put(struct kobject *);

来提取和释放,这两个函数分别增加和减小了计数引用次数,并返回kobject基本对象,另外其他派生对象是没有引用计数成员的,因为他们包含了一个kobject对象。拿kset来说,系统提供了以下函数

static inline struct kset * to_kset(struct kobject * kobj)

{

return kobj ? container_of(kobj,struct kset,kobj) : NULL;

}

static inline struct kset * kset_get(struct kset * k)

{

return k ? to_kset(kobject_get(&k->kobj)) : NULL;

}

static inline void kset_put(struct kset * k)

{

kobject_put(&k->kobj);

}

分别来引用或者销毁对应的kset对象,这里可以看出kset_get等也是间接引用kobject_get,linux利用成员指针获取父结构指针,从而层层索引,然而最重的计数功能还是落在了对应的kobject成员kref上面

2, struct list_head entry;/* 用于链入所属kset 的链表 */在初始化的时候肯定要把pre指向next,next指向pre的孤立做法。而作为其他对象子对象成员添加的时候,就要把该链表指向该指向的地方了。所以kobject有init和add 2个主要的初始化函数,代码如下。

/**

* kobject_init - initialize object.

* @kobj: object in question.

*/

void kobject_init(struct kobject * kobj)

{

kref_init(&kobj->kref);//初始化计数为1

INIT_LIST_HEAD(&kobj->entry);//链表初始化

kobj->kset = kset_get(kobj->kset);//引用计数加加

}

/**

* kobject_add - add an object to the hierarchy.

* @kobj: object.

*/

int kobject_add(struct kobject * kobj)

{

int error = 0;

struct kobject * parent;

if (!(kobj = kobject_get(kobj))));//获取对象一定要用对应的get,增加计数

return -ENOENT;

if (!kobj->k_name)

kobj->k_name = kobj->name;

parent = kobject_get(kobj->parent);//获取对象一定要用对应的get,增加计数

pr_debug("kobject %s: registering. parent: %s, set: %s\n",

kobject_name(kobj), parent ? kobject_name(parent) : "<NULL>",

kobj->kset ? kobj->kset->kobj.name : "<NULL>" );

if (kobj->kset) {//如果该kobject属于某个kset的话,就把他的entry增加到对应的kset的list当中

down_write(&kobj->kset->subsys->rwsem);

if (!parent)

parent = kobject_get(&kobj->kset->kobj);//成功增加的kobject一定有parent,至少是kset的kobj

list_add_tail(&kobj->entry,&kobj->kset->list);

up_write(&kobj->kset->subsys->rwsem);

}

kobj->parent = parent;

error = create_dir(kobj);//这里确实还没看

if (error) {

/* unlink does the kobject_put() for us */

unlink(kobj);

if (parent)

kobject_put(parent);//释放对象一定要用对应的put,减少计数

} else {

kobject_hotplug(kobj, KOBJ_ADD);

}

return error;

}

我们会发现kset对象、device、driver等对象的初始化都要用到这两个函数,为了方便使用,这两个函数合成了一个kobject_register供所有高级对象毫无例外的使用着

/**

* kobject_register - initialize and add an object.

* @kobj: object in question.

*/

int kobject_register(struct kobject * kobj)

{

int error = 0;

if (kobj) {

kobject_init(kobj);

error = kobject_add(kobj);

if (error) {

printk("kobject_register failed for %s (%d)\n",

kobject_name(kobj),error);

dump_stack();

}

} else

error = -EINVAL;

return error;

}

3,kobject对象还提供以下操作

void kobject_del(struct kobject * kobj)

int kobject_set_name(struct kobject * kobj, const char * fmt, ...)

设备驱动模型kset

kset的分析

先看结构体代码

struct kset {

struct subsystem * subsys;//所属subsystem

struct kobj_type * ktype;//所属ktype

struct list_head list;//所包含的kobject链表

struct kobject kobj;//所包含的子对象kobject,往往是list各kobject的parent

struct kset_hotplug_ops * hotplug_ops;

};

1,kset的初始化也有2个函数init和add

/**

* kset_init - initialize a kset for use

* @k: kset

*/

void kset_init(struct kset * k)

{

kobject_init(&k->kobj);//init则调用init函数

INIT_LIST_HEAD(&k->list);

}

/**

* kset_add - add a kset object to the hierarchy.

* @k: kset.

*

* Simply, this adds the kset's embedded kobject to the

* hierarchy.

* We also try to make sure that the kset's embedded kobject

* has a parent before it is added. We only care if the embedded

* kobject is not part of a kset itself, since kobject_add()

* assigns a parent in that case.

* If that is the case, and the kset has a controlling subsystem,

* then we set the kset's parent to be said subsystem.

*/

int kset_add(struct kset * k)

{

if (!k->kobj.parent && !k->kobj.kset && k->subsys)

k->kobj.parent = &k->subsys->kset.kobj;//如果有所属subsystem且无father,则模仿kobject对象为parent赋值

return kobject_add(&k->kobj);//add调用add

}

同样合成了一个register

/**

* kset_register - initialize and add a kset.

* @k: kset.

*/

int kset_register(struct kset * k)

{

kset_init(k);

return kset_add(k);

}

2,同样支持的操作包括

void kset_unregister(struct kset * k)

struct set * kset_get(struct kobject * kobj)

void kset_put(struct kobject * kobj)

设备驱动模型subsystem

subsystem

定义非常简单

struct subsystem {

struct kset kset;

struct rw_semaphore rwsem;

};

1,一个读写锁加一个kset变量的定义使得这个结构非常简单,可以很明显的感觉到,这里最主要的目的是在kset当中增加了一个读写锁了,所以在设备驱动模型链表修改过程中,几乎毫无疑问的都要用到这个读写锁,subsystem下面的读写锁

2,初始化函数

void subsystem_init(struct subsystem * s)

{

init_rwsem(&s->rwsem);

kset_init(&s->kset);

}

/**

* subsystem_register - register a subsystem.

* @s: the subsystem we're registering.

*

* Once we register the subsystem, we want to make sure that

* the kset points back to this subsystem for correct usage of

* the rwsem.

*/

int subsystem_register(struct subsystem * s)

{

int error;

subsystem_init(s);

pr_debug("subsystem %s: registering\n",s->kset.kobj.name);

if (!(error = kset_add(&s->kset))) {

if (!s->kset.subsys)

s->kset.subsys = s;

}

return error;

}

3,同样支持void subsystem_unregister(struct subsystem * s)

设备驱动模型device

device

结构说明

struct device {

struct list_head node; /* node in sibling list */

struct list_head bus_list; /* node in bus's list */

struct list_head driver_list;

struct list_head children;

struct device * parent;/* 父设备 */

struct kobject kobj;/* 内嵌的kobject */

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

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 (e.g. ACPI,

BIOS data relevant to device) */

struct dev_pm_info power;

u32 detach_state; /* State to enter when device is

detached from its driver. */

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 list_head dma_pools; /* dma pools (if dma'ble) */

struct dma_coherent_mem *dma_mem; /* internal for coherent mem

override */

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

};

1,一如既往的初始化分为2个步骤init和add

/**

* device_initialize - init device structure.

* @dev: device.

*

* This prepares the device for use by other layers,

* including adding it to the device hierarchy.

* It is the first half of device_register(), if called by

* that, though it can also be called separately, so one

* may use @dev's fields (e.g. the refcount).

*/

void device_initialize(struct device *dev)

{

kobj_set_kset_s(dev, devices_subsys);//把dev->object->kset指向decl_subsys声明的devices_subsys

kobject_init(&dev->kobj);

INIT_LIST_HEAD(&dev->node);

INIT_LIST_HEAD(&dev->children);

INIT_LIST_HEAD(&dev->driver_list);

INIT_LIST_HEAD(&dev->bus_list);

INIT_LIST_HEAD(&dev->dma_pools);

}

/**

* device_add - add device to device hierarchy.

* @dev: device.

*

* This is part 2 of device_register(), though may be called

* separately _iff_ device_initialize() has been called separately.

*

* This adds it to the kobject hierarchy via kobject_add(), adds it

* to the global and sibling lists for the device, then

* adds it to the other relevant subsystems of the driver model.

*/

int device_add(struct device *dev)

{

struct device *parent = NULL;

int error = -EINVAL;

dev = get_device(dev);//利用get获取device增加计数

if (!dev || !strlen(dev->bus_id))

goto Error;

parent = get_device(dev->parent);//利用get获取device增加计数

pr_debug("DEV: registering device: ID = '%s'\n", dev->bus_id);

/* first, register with generic layer. */

kobject_set_name(&dev->kobj, "%s", dev->bus_id);//设置子kobject对象名称也就是自身name

if (parent)

dev->kobj.parent = &parent->kobj;

if ((error = kobject_add(&dev->kobj)))//调用kobject_add增加子对象

goto Error;

if ((error = device_pm_add(dev)))

goto PMError;

if ((error = bus_add_device(dev)))//增加device到总线,并探测驱动

goto BusError;

down_write(&devices_subsys.rwsem);

if (parent)

list_add_tail(&dev->node, &parent->children);//如果有父设备,则添加到其子对象列表

up_write(&devices_subsys.rwsem);

/* notify platform of device entry */

if (platform_notify)

platform_notify(dev);

Done:

put_device(dev);

return error;

BusError:

device_pm_remove(dev);

PMError:

kobject_del(&dev->kobj);

Error:

if (parent)

put_device(parent);

goto Done;

}

两部合一就是个register

/**

* device_register - register a device with the system.

* @dev: pointer to the device structure

*

* This happens in two clean steps - initialize the device

* and add it to the system. The two steps can be called

* separately, but this is the easiest and most common.

* I.e. you should only call the two helpers separately if

* have a clearly defined need to use and refcount the device

* before it is added to the hierarchy.

*/

int device_register(struct device *dev)

{

device_initialize(dev);

return device_add(dev);

}

2,同样支持的操作包括

struct device * get_device(struct device * dev)

struct device * get_device(struct device * dev)

void device_del(struct device * dev)

void device_unregister(struct device * dev)

3,初始化函数bus_add_device在bus当中提到

设备驱动模型device_driver

device_driver

struct device_driver {

char * name;

struct bus_type * bus;

struct completion unload_done;

struct kobject kobj;

struct list_head devices;

struct module * owner;

int (*probe) (struct device * dev);

int (*remove) (struct device * dev);

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

int (*suspend) (struct device * dev, u32 state, u32 level);

int (*resume) (struct device * dev, u32 level);

};

1,这个是看起来最简单的结构了,初始化只有个register

/**

* driver_register - register driver with bus

* @drv: driver to register

*

* We pass off most of the work to the bus_add_driver() call,

* since most of the things we have to do deal with the bus

* structures.

*

* We init the completion strcut here. When the reference

* count reaches zero, complete() is called from bus_release().

*/

int driver_register(struct device_driver * drv)

{

INIT_LIST_HEAD(&drv->devices);

init_completion(&drv->unload_done);

return bus_add_driver(drv);

}

2,同样支持void put_driver(struct device_driver * drv)

struct device_driver * get_driver(struct device_driver * drv)

void driver_unregister(struct device_driver * drv)

设备驱动模型bus_type

bus_type

struct bus_type {

char * name;

struct subsystem subsys;

struct kset drivers;

struct kset devices;

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 (*hotplug) (struct device *dev, char **envp,

int num_envp, char *buffer, int buffer_size);

int (*suspend)(struct device * dev, u32 state);

int (*resume)(struct device * dev);

};

1,bus_type自身包含一个subsystem和2个kset,所以其初始化要一一完成

/**

* 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.

*/

int bus_register(struct bus_type * bus)

{

int retval;

retval = kobject_set_name(&bus->subsys.kset.kobj, "%s", bus->name);//设置自身kobj的name

if (retval)

goto out;

subsys_set_kset(bus, bus_subsys);//同样关联到decl_subsys申明的bus_subsys上,kobj->kset

retval = subsystem_register(&bus->subsys);//subsys初始化

if (retval)

goto out;

kobject_set_name(&bus->devices.kobj, "devices");//设置成员devices的名字

bus->devices.subsys = &bus->subsys;//device的subsys置为自己的subsys

retval = kset_register(&bus->devices);//注册kset

if (retval)

goto bus_devices_fail;

kobject_set_name(&bus->drivers.kobj, "drivers");//设置成员drivers的名字

bus->drivers.subsys = &bus->subsys;//设置driver的subsys为自己的subsys

bus->drivers.ktype = &ktype_driver;//设置driver的ktype为自己的ktype

retval = kset_register(&bus->drivers);//注册kset

if (retval)

goto bus_drivers_fail;

bus_add_attrs(bus);

pr_debug("bus type '%s' registered\n", bus->name);

return 0;

bus_drivers_fail:

kset_unregister(&bus->devices);

bus_devices_fail:

subsystem_unregister(&bus->subsys);

out:

return retval;

}

2,同样支持void bus_unregister(struct bus_type * bus)

extern struct bus_type * get_bus(struct bus_type * bus);

extern void put_bus(struct bus_type * bus);

extern struct bus_type * find_bus(char * name);

3,bus_add_device函数

/**

* bus_add_device - add device to bus

* @dev: device being added

*

* - Add the device to its bus's list of devices.

* - Try to attach to driver.

* - Create link to device's physical location.

*/

int bus_add_device(struct device * dev)

{

struct bus_type * bus = get_bus(dev->bus);//用get获取bus增加计数

int error = 0;

if (bus) {

down_write(&dev->bus->subsys.rwsem);

pr_debug("bus %s: add device %s\n", bus->name, dev->bus_id);

list_add_tail(&dev->bus_list, &dev->bus->devices.list);//自身的bus_list增加到bus_type->kset.list

device_attach(dev);//搜索匹配的驱动

up_write(&dev->bus->subsys.rwsem);

device_add_attrs(bus, dev);

sysfs_create_link(&bus->devices.kobj, &dev->kobj, dev->bus_id);

}

return error;

}

/**

* device_attach - try to attach device to a driver.

* @dev: device.

*

* Walk the list of drivers that the bus has and call

* driver_probe_device() for each pair. If a compatible

* pair is found, break out and return.

*/

int device_attach(struct device * dev)

{

struct bus_type * bus = dev->bus;

struct list_head * entry;

int error;

if (dev->driver) {//已经定义好了驱动,则直接绑定

device_bind_driver(dev);

return 1;

}

if (bus->match) {

list_for_each(entry, &bus->drivers.list) {//否则搜索并绑定

struct device_driver * drv = to_drv(entry);

error = driver_probe_device(drv, dev);

if (!error)

/* success, driver matched */

return 1;

if (error != -ENODEV)

/* driver matched but the probe failed */

printk(KERN_WARNING

"%s: probe of %s failed with error %d\n",

drv->name, dev->bus_id, error);

}

}

return 0;

}

int driver_probe_device(struct device_driver * drv, struct device * dev)

{

if (drv->bus->match && !drv->bus->match(dev, drv))

return -ENODEV;

dev->driver = drv;

if (drv->probe) {

int error = drv->probe(dev);

if (error) {

dev->driver = NULL;

return error;

}

}

device_bind_driver(dev);

return 0;

}

4,类似的还有bus_add_driver不再细表了
目前分析了kobject、kset、subsystem、device、device_driver、bus_type还缺少kobj_type、class_type、attr等等,暂时不想看了,因为多数的关于devide.hkobject.c bus.c driver.c等已经分析了,还有一些其他的总线,如platform等暂时没办法一一了解,以后继续。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: