bus总线分析与注册

来源:互联网 发布:阿里云邮件推送资源包 编辑:程序博客网 时间:2024/04/26 03:40
                    bus总线注册及内部结构
一.下面是bus_type的结构
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;                    //这个是个非常重要的结构
};

struct bus_type_private {                    //这个结构体维护了各种链表
    struct kset subsys;                    
    struct kset *drivers_kset;                //这个保存了/sys/***/driver/集,
                                    应该可以说成一个路径,以后设备与驱动注册会用
    struct kset *devices_kset;                //这个保存了/sys/***/device/集
    struct klist klist_devices;                //这个链表管理着这类总线上所有设备
    struct klist klist_drivers;                //这个链表管理着这类总线上所有驱动
    struct blocking_notifier_head bus_notifier;        //事件注册与通知链表(以后再分析)
    unsigned int drivers_autoprobe:1;            //是否允许设备与驱动自动匹配的flag
    struct bus_type *bus;                    //总线类型指针
};
二.函数分析
int bus_register(struct bus_type *bus)
{
    int retval;
    struct bus_type_private *priv;                

    priv = kzalloc(sizeof(struct bus_type_private), GFP_KERNEL);    //分析上面那重要结构内存
    if (!priv)
        return -ENOMEM;

    priv->bus = bus;                        //初始化,bus_type_private成员bus指向当前bus
    bus->p = priv;                            //bus的bus_type_private指针指向刚分配内存的结构体

    BLOCKING_INIT_NOTIFIER_HEAD(&priv->bus_notifier);        //初始化通知链表

    retval = kobject_set_name(&priv->subsys.kobj, "%s", bus->name); //设置kobj的名字
    if (retval)
        goto out;

    priv->subsys.kobj.kset = bus_kset;                //设置kobj的父目录
    priv->subsys.kobj.ktype = &bus_ktype;                //kobj的操作方法
    priv->drivers_autoprobe = 1;                    //设置可以自己匹配

    retval = kset_register(&priv->subsys);                //kset注册,在/sys/建立目录
    if (retval)
        goto out;

    retval = bus_create_file(bus, &bus_attr_uevent);        // 在subsys集下建立事件属性文件
    if (retval)
        goto bus_uevent_fail;

    priv->devices_kset = kset_create_and_add("devices", NULL,
                         &priv->subsys.kobj);    //在subsys集下创建device目录
    if (!priv->devices_kset) {                    
        retval = -ENOMEM;
        goto bus_devices_fail;
    }

    priv->drivers_kset = kset_create_and_add("drivers", NULL,
                         &priv->subsys.kobj);    //在subsys集下创建driver目录
    if (!priv->drivers_kset) {
        retval = -ENOMEM;
        goto bus_drivers_fail;
    }

    klist_init(&priv->klist_devices, klist_devices_get, klist_devices_put);    //设备链表初始化
    klist_init(&priv->klist_drivers, NULL, NULL);                //驱动链表初始化

    retval = add_probe_files(bus);                        //创建(自动)探测属性文件                
    if (retval)
        goto bus_probe_files_fail;

    retval = bus_add_attrs(bus);                        //创建bus属性文件
    if (retval)
        goto bus_attrs_fail;

    pr_debug("bus: '%s': registered\n", bus->name);                //
    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;
}

到些,bus_register注册工作已经完成了

下面再看一下其他函数
void bus_unregister(struct bus_type *bus)        register的逆过程
{
    pr_debug("bus: '%s': unregistering\n", bus->name);
    bus_remove_attrs(bus);                //bus属性文件的移除
    remove_probe_files(bus);            //探测文件的移除
    kset_unregister(bus->p->drivers_kset);        //drivers目录的删除
    kset_unregister(bus->p->devices_kset);        //devices目录的删除
    bus_remove_file(bus, &bus_attr_uevent);        //uevent属性文件的移除
    kset_unregister(&bus->p->subsys);        //sussys集的移除
    kfree(bus->p);                    //释放bus_type_private
    bus->p = NULL;                    //安全操作指向空
}
获得subsys集的指针
struct kset *bus_get_kset(struct bus_type *bus)
{
    return &bus->p->subsys;
}
重新扫描事个链表,如果有匹配的设备与驱动则匹配
int bus_rescan_devices(struct bus_type *bus)    
{
    return bus_for_each_dev(bus, NULL, NULL, bus_rescan_devices_helper);//这里很重要,调用bus_rescan_devices_helper,让设备与驱动得以匹配
}

int bus_for_each_dev(struct bus_type *bus, struct device *start,
             void *data, int (*fn)(struct device *, void *))
{
    struct klist_iter i;            //定义一个遍历结构
    struct device *dev;
    int error = 0;

    if (!bus)
        return -EINVAL;

    klist_iter_init_node(&bus->p->klist_devices, &i,
                 (start ? &start->p->knode_bus : NULL));        //初始化一个遍历结构
    while ((dev = next_device(&i)) && !error)                //遍历所有设备
        error = fn(dev, data);                        
    klist_iter_exit(&i);                            //iter安全处理
    return error;
}

static struct device_driver *next_driver(struct klist_iter *i)         //获取下一个驱动指针
{
    struct klist_node *n = klist_next(i);
    struct driver_private *drv_priv;

    if (n) {
        drv_priv = container_of(n, struct driver_private, knode_bus);
        return drv_priv->driver;
    }
    return NULL;
}
static struct device *next_device(struct klist_iter *i)        
{
    struct klist_node *n = klist_next(i);  //获取下一个结点
    struct device *dev = NULL;
    struct device_private *dev_prv;

    if (n) {
        dev_prv = to_device_private_bus(n);//获取下一个p指针,利用container_of(obj, struct device_private, knode_bus)
        dev = dev_prv->device;            //获取设备指针
    }
    return dev;
}

struct device *bus_find_device(struct bus_type *bus,
                   struct device *start, void *data,
                   int (*match)(struct device *dev, void *data))        //查看设备是否在总线中
{
    struct klist_iter i;
    struct device *dev;

    if (!bus)
        return NULL;

    klist_iter_init_node(&bus->p->klist_devices, &i,
                 (start ? &start->p->knode_bus : NULL));
    while ((dev = next_device(&i)))
        if (match(dev, data) && get_device(dev))
            break;
    klist_iter_exit(&i);
    return dev;
}
struct device *bus_find_device_by_name(struct bus_type *bus,
                       struct device *start, const char *name)    //通过名字查看设备是否在总线,实际调用上面的一个函数
{
    return bus_find_device(bus, start, (void *)name, match_name);
}


int bus_for_each_drv(struct bus_type *bus, struct device_driver *start,
             void *data, int (*fn)(struct device_driver *, void *))    //遍历每一个驱动并匹配设备
{
    struct klist_iter i;
    struct device_driver *drv;
    int error = 0;

    if (!bus)
        return -EINVAL;

    klist_iter_init_node(&bus->p->klist_drivers, &i,
                 start ? &start->p->knode_bus : NULL);
    while ((drv = next_driver(&i)) && !error)
        error = fn(drv, data);
    klist_iter_exit(&i);
    return error;
}
到此bus注册已经完成了

下面附上一个例子
  1 #include <linux/module.h>
  2 #include <linux/device.h>
  3 #include <linux/init.h>
  4 #include <linux/types.h>
  5
  6
  7 MODULE_AUTHOR("emperor");
  8 MODULE_LICENSE("GPL");
  9
 10 static char *version = "2014.4.14";
 11
 12 static int bus_match(struct device *dev, struct device_driver *drv)
 13 {
 14         return (strcmp(dev->init_name, drv->name) == 0);
 15 }
 16
 17 struct bus_type my_bus = {
 18         .name = "bus_test",
 19         .match = bus_match,
 20 };
 21
 22 static ssize_t  bus_show(struct bus_type *bus, char *buf)
 23 {
 24         return snprintf(buf, PAGE_SIZE, "%s\n", version);
 25 }
 26
 27 static BUS_ATTR(version, S_IRUGO, bus_show, NULL);
 28
 29 static int __init bus_init(void)
 30 {
 31         int ret;
 32         ret = bus_register(&my_bus);
 33         if(ret)
 34                 printk(KERN_DEBUG "BUS register is fail\n");
 35         bus_create_file(&my_bus, &bus_attr_version);
 36         return 0;


小生也是刚刚开始钻研,望各位指出错误,互相进步







1 0
原创粉丝点击