已经停顿了好多天了,这部分很难看的。到现在也是懵懵懂懂,不能彻底弄清楚。很多事情是不能一步到位的,暂时这样吧,回头再搞,就此总结一下我对于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
定义如下:
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的分析
先看结构体代码
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
定义非常简单
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
结构说明
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
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
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等暂时没办法一一了解,以后继续。