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

来源:互联网 发布:手机淘宝代付 编辑:程序博客网 时间:2024/05/17 04:52

设备驱动模型综述

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

原创粉丝点击