现在的位置: 首页 > 综合 > 正文

linux 设备模型(2)

2018年02月07日 ⁄ 综合 ⁄ 共 23242字 ⁄ 字号 评论关闭
二、linux设备模型层次关系:bus_type,device,device_driver

驱动核心可以注册多种类型的总线。
每种总线下面可以挂载许多设备。(通过kset devices)
每种总线下可以用很多设备驱动。(通过包含一个kset drivers)}
每个驱动可以处理一组设备。按照我的理解就是所有的设备都挂载到总线上,当加载驱动时,驱动就从总线上找到自己对应的设备。或者先把驱动加载上,来了一个设备就去总线找驱动。
这种基本关系的建立源于实际系统中各种总线,设备,驱动结构的抽象。

1.首先是总线,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 (*suspend_late)(struct device *dev, pm_message_t state); 
    int (*resume_early)(struct device *dev); 
    int (*resume)(struct device *dev); 
    struct dev_pm_ops *pm; 
    struct bus_type_private *p; 
}; 
//bus_type的bus_type_private 成员
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; 
}; 
(1)总线的删除
void bus_unregister(struct bus_type *bus);
(2)总线的match方法
int (*match)(struct device *dev, struct device_driver *drv);
//当一个新设备或者驱动被添加到这个总线时,该方法被调用,用于判断指定的驱动程序是否能处理指定的设备。若可以,则返回非0值。下面的测试程序采用匹配设备的dev->bus_id字符串和驱动的drv->name字符串是否相同来判断驱动是否能处理该设备。
(3)总线uevent方法
int (*uevent)(structdevice *dev, char **envp, int num_envp)//在为用户产生热插拔事件之前,这个方法允许总线添加环境变量。
(4)总线属性由结构bus_attribute描述:
struct bus_attribute {
    struct attribute attr;
    ssize_t (*show)(struct bus_type *bus,char *buf);
    ssize_t (*store)(struct bus_type *bus,const char *buf, size_t count);
};
BUS_ATTR(name,mode, show, store)//在编译时创建和初始化bus_attribute结构,它将bus_attr_作为给定前缀来创建总线的真正名称。
如:static BUS_ATTR(version, S_IRUGO, show_bus_version, NULL);//将创建一个bus_attr_version结构体对象。
(5)创建\删除属性文件
int bus_create_file(struct bus_type *bus, struct bus_attribute *attr)
void bus_remove_file(struct bus_type *bus, struct bus_attribute *attr)
(6)可以看出该结构体中包含了有device和dirver的kset对象。
总线的注册:int bus_register(structbus_type *bus);如果成功,新的总线将被添加到系统,在/sys/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->p = priv;//建立bus_type和bus_type_private的关系

    BLOCKING_INIT_NOTIFIER_HEAD(&priv->bus_notifier); 
    //设置总线子系统kobject的名称
    retval = kobject_set_name(&priv->subsys.kobj, "%s", bus->name);//给总线的kset结构里的kobject结构设置name,在/sys/bus目录下出现时就是这个bus名
    if (retval) 
        goto out; 
     
    priv->subsys.kobj.kset = bus_kset;//设置总线子系统kobject的所属集合,其实对应sys/bus/ 目录
    priv->subsys.kobj.ktype = &bus_ktype;//kobj_type类型变量,和sysfs有关 
    priv->drivers_autoprobe = 1; //这个变量如果置位,则会执行一个函数,在驱动注册会看到它的运用 
    
    //注册kset,就是建立/sys/bus/bus->name的目录
    retval = kset_register(&priv->subsys); 
    if (retval) 
        goto out; 
    
    //创建bus的属性文件 
    retval = bus_create_file(bus, &bus_attr_uevent);//调用sysfs_create_file(&bus->p->subsys.kobj, &attr->attr);
    if (retval) 
        goto bus_uevent_fail; 
     
    //在/sys/bus/bus->name目录下创建devices目录,父目录就是priv->subsys.kobj,即/sys/bus/bus->name的目录
    priv->devices_kset = kset_create_and_add("devices", NULL,&priv->subsys.kobj); 
    if (!priv->devices_kset) { 
        retval = -ENOMEM; 
        goto bus_devices_fail; 
    } 
     
    //在/sys/bus/bus->name目录下创建drivers目录,父目录就是priv->subsys.kobj,即/sys/bus/bus->name的目录 
    priv->drivers_kset = kset_create_and_add("drivers", NULL,&priv->subsys.kobj); 
    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);//添加探测属性retval = bus_create_file(bus, &bus_attr_drivers_probe); retval = bus_create_file(bus, &bus_attr_drivers_autoprobe); 
    if (retval) 
        goto bus_probe_files_fail; 
     
    retval = bus_add_attrs(bus);// 添加其他属性,bus_create_file(bus, &bus->bus_attrs[i]);
    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: 
    return retval; 
} 

2.下面是设备device的定义:
struct device {
    struct klist klist_children; 
    struct klist_nodeknode_parent;/* node in sibling list */ 
    struct klist_nodeknode_driver; 
    struct klist_nodeknode_bus; 
    struct device *parent;//父设备,一般一个bus也对应一个设备。 
    struct kobject kobj; //代表自身 
    char bus_id[BUS_ID_SIZE];/* position on parent bus */ 
    unsigned uevent_suppress:1; 
    const char *init_name; /*设备初始名 */ 
    struct device_type*type; 
    struct semaphoresem;/* semaphore to synchronize calls to its driver. */ 
    struct bus_type*bus;/* 所属的总线 */ 
    struct device_driver *driver; /* 匹配的驱动*/ 
    void *driver_data;/* data private to the driver */ 
    void *platform_data;/* 由驱动定义并使用 */ 
    struct dev_pm_infopower; 
    u64 *dma_mask;/* dma mask (if dma'able device) */ 
    u64 coherent_dma_mask; 
    struct device_dma_parameters *dma_parms; 
    struct list_headdma_pools;/* dma pools (if dma'ble) */ 
    struct dma_coherent_mem*dma_mem; /* internal for coherent mem override */ 
    struct dev_archdataarchdata; /* arch specific additions */ 
    dev_t devt;/* dev_t, creates the sysfs "dev" */ 
    spinlock_t devres_lock; 
    struct list_headdevres_head; 
    struct klist_nodeknode_class; 
    struct class *class; 
    struct attribute_group**groups;/* optional groups */ 
    void (*release)(struct device *dev); 
}; 

//可以看出device结构体中也包含了一个kobject对象
(1)注册设备
int device_register(struct device *dev);
(2)注销设备
viod device_unregister(struct device *dev)
(3)设备属性由struct device_attribute描述
structdevice_attribute {
struct attribute attr;
ssize_t (*show)(struct device *dev,struct device_attribute *attr,char *buf);
ssize_t (*store)(struct device *dev,struct device_attribute *attr,const char *buf, size_t count);
};
(4)创建属性文件
int device_create_file(struct device *dev, struct device_attibute *entry)
(5)删除属性文件
void device_remove_file(struct device *dev, struct device_attibute *entry)
(6)device_register代码
int device_register(struct device *dev)
{
    device_initialize(dev);//初始化设备各个字段
    return device_add(dev);
}

void device_initialize(struct device *dev)
{
 kobj_set_kset_s(dev, devices_subsys); //所有的dev属于devices_subsys这个集合
 kobject_init(&dev->kobj); //初始kobj
 klist_init(&dev->klist_children, klist_children_get,klist_children_put);//初始化子设备链表
 INIT_LIST_HEAD(&dev->dma_pools);
 INIT_LIST_HEAD(&dev->node);
 init_MUTEX(&dev->sem);
 device_init_wakeup(dev, 0);
}
int device_add(struct device *dev)
{
    struct device *parent = NULL;
    struct kobject *kobj;
    struct class_interface *class_intf;
    int error = -EINVAL;
    
    dev = get_device(dev);//增加使用计数
    if (!dev)
        goto done;
    
    if (!dev->p) {
        /*int device_private_init(struct device *dev)
            {
         dev->p = kzalloc(sizeof(*dev->p), GFP_KERNEL);
         if (!dev->p)
         return -ENOMEM;
         dev->p->device = dev;//指向设备自己
         klist_init(&dev->p->klist_children, klist_children_get,klist_children_put);//初始化设备私有成员的子设备链表,还有两个函数,关于增加和减少子设备引用计数的
         return 0;
        }
        */
        error = device_private_init(dev);
        if (error)
             goto done;
    }
    
    if (dev->init_name) {//设备初始名存在
        /*
            int dev_set_name(struct device *dev, const char *fmt, ...)
            {
     va_list vargs;
     int err;
     
     va_start(vargs, fmt);
     err = kobject_set_name_vargs(&dev->kobj, fmt, vargs);
     va_end(vargs);
     return err;
             }
        */
        dev_set_name(dev, "%s", dev->init_name);//赋值给设备本身的kobject结构的name
        dev->init_name = NULL;
    }
    
    /*检查设备名是否存在,否则使用dev->bus->dev_name, dev->id生成设备本身的kobject结构的name*/
    if (!dev_name(dev) && dev->bus && dev->bus->dev_name)
        dev_set_name(dev, "%s%u", dev->bus->dev_name, dev->id);
    
    if (!dev_name(dev)) {//再次检查name
        error = -EINVAL;
        goto name_error;
    }
    
    pr_debug("device: '%s': %s\n", dev_name(dev), __func__);
    
    parent = get_device(dev->parent);//增加父设备计数,并返回父设备结构
    kobj = get_device_parent(dev, parent);//找到父设备对应的kobject结构
    if (kobj)
        dev->kobj.parent = kobj;//将本设备的kobj的parent字段指向父设备的kobject结构
    
    /* use parent numa_node */
    if (parent)
        set_dev_node(dev, dev_to_node(parent));// dev->numa_node = node;
    
    //将Kobject对象注册到linux系统,即在dev->kobj.parent的目录下创建前边设置过的name的本设备的目录
    error = kobject_add(&dev->kobj, dev->kobj.parent, NULL);
    if (error)
        goto Error;
    
    /* notify platform of device entry */
    if (platform_notify)
        platform_notify(dev);
    
    //为sysfs文件系统创建设备的属性文件
    error = device_create_file(dev, &uevent_attr);
    if (error)
    goto attrError;
    
    if (MAJOR(dev->devt)) {//如果存在设备号则添加dev_t属性,这样udev就能读取设备号属性从而在/dev/目录下创建设备节点,这样kobj和cdev也关联了
        error = device_create_file(dev, &devt_attr);//创建属性文件static struct device_attribute devt_attr =__ATTR(dev, S_IRUGO, show_dev, NULL);
        if (error)
            goto ueventattrError;
        
        //创建一些符号链接
        error = device_create_sys_dev_entry(dev);
        if (error)
            goto devtattrError;
    
        devtmpfs_create_node(dev);//在/dev下动态创建设备节点
    }
    
    //建立类的sysfs符号连接 
    error = device_add_class_symlinks(dev);
    if (error)
        goto SymlinkError;
    error = device_add_attrs(dev);//调用device_create_file(dev, &bus->dev_attrs[i])为sysfs文件系统创建属性文件
    if (error)
        goto AttrsError;
    error = bus_add_device(dev);//创建bus的一些符号链接,将设备添加进总线中
    if (error)
        goto BusError;
    error = dpm_sysfs_add(dev);//电源管理
    if (error)
        goto DPMError;
    device_pm_add(dev);//电源管理
    
    if (dev->bus)//调用注册bus通知链上的所有函数
        blocking_notifier_call_chain(&dev->bus->p->bus_notifier,BUS_NOTIFY_ADD_DEVICE, dev);
    
    //主要是向用户空间发送消息,实现热插拔
    kobject_uevent(&dev->kobj, KOBJ_ADD);
    bus_probe_device(dev); //现在该为设备在总线上寻找合适的驱动了
    if (parent)//如果父设备存在
        klist_add_tail(&dev->p->knode_parent,&parent->p->klist_children);//将子设备添加到父设备的链表中
    
    if (dev->class) {
        mutex_lock(&dev->class->p->mutex);
        klist_add_tail(&dev->knode_class,&dev->class->p->klist_devices);    /* tie the class to the device */
    
        /* notify any interfaces that the device is here */
        list_for_each_entry(class_intf,&dev->class->p->interfaces, node)
             if (class_intf->add_dev)
                class_intf->add_dev(dev, class_intf);
        mutex_unlock(&dev->class->p->mutex);
    }
    done:
    put_device(dev);
    return error;
.......//出错处理
}

int bus_add_device(struct device *dev)
{
    struct bus_type *bus = bus_get(dev->bus);
    int error = 0;
    
    if (bus) {
        pr_debug("bus: '%s': add device %s\n", bus->name, dev_name(dev));
        error = device_add_attrs(bus, dev);//创建属性文件
        if (error)
            goto out_put;
        error = sysfs_create_link(&bus->p->devices_kset->kobj,&dev->kobj, dev_name(dev));//创建设备所在bus目录下的设备链接
        if (error)
            goto out_id;
        error = sysfs_create_link(&dev->kobj,&dev->bus->p->subsys.kobj, "subsystem");//创建链接
        if (error)
            goto out_subsys;
        klist_add_tail(&dev->p->knode_bus, &bus->p->klist_devices);//将设备添加到所在bus总线下的链表中,将设备添加进总线的设备链表
    }
    return 0;
    
out_subsys:
    sysfs_remove_link(&bus->p->devices_kset->kobj, dev_name(dev));
out_id:
    device_remove_attrs(bus, dev);
out_put:
    bus_put(dev->bus);
    return error;
}

void bus_probe_device(struct device *dev)
{
    struct bus_type *bus = dev->bus;//找到设备所在的总线
    int ret;
    
    if (bus && bus->p->drivers_autoprobe) {//drivers_autoprobe标志设为1,表明要自动匹配驱动
        ret = device_attach(dev); //为设备寻找驱动
        WARN_ON(ret < 0);
    }
}

int device_attach(struct device *dev)
{
    int ret = 0;

    device_lock(dev);//锁住设备
    if (dev->driver) {//如果设备有驱动
        ret = device_bind_driver(dev);//那么将设备和驱动绑定
        if (ret == 0)
            ret = 1;
        else {
            dev->driver = NULL;
            ret = 0;
        }
    } else {//如果设备没有驱动
        pm_runtime_get_noresume(dev);
        ret = bus_for_each_drv(dev->bus, NULL, dev, __device_attach); //在总线上寻找驱动与该设备进行匹配
        pm_runtime_put_sync(dev);
    }
    device_unlock(dev);
    return ret;
}

int device_bind_driver(struct device *dev)
{
    int ret;

    ret = driver_sysfs_add(dev);//主要是添加driver和dev之间的连接文件
    if (!ret)
        driver_bound(dev);//驱动绑定设备
    return ret;
}

static int driver_sysfs_add(struct device *dev)
{
    int ret;
        //1:在驱动目录下建立一个到设备的同名链接
        //2:在设备目录下建立一个名为driver。到驱动的链接
    ret = sysfs_create_link(&dev->driver->p->kobj, &dev->kobj,kobject_name(&dev->kobj)); //在driver目录下添加以dev->kobj名字的连接文件,连接到device
    if (ret == 0) {
        ret = sysfs_create_link(&dev->kobj, &dev->driver->p->kobj,"driver"); //同样在device目录下添加‘driver’为名字的连接文件连接到drvier
        if (ret)
            sysfs_remove_link(&dev->driver->p->kobj,kobject_name(&dev->kobj));
    }
    return ret;
}

static void driver_bound(struct device *dev)
{
    if (klist_node_attached(&dev->p->knode_driver)) {
        printk(KERN_WARNING "%s: device %s already bound\n",__func__, kobject_name(&dev->kobj));
        return;
    }
    
    pr_debug("driver: '%s': %s: bound to device '%s'\n", dev_name(dev),__func__, dev->driver->name);
    
    //实现将驱动程序和设备联系起来。
    klist_add_tail(&dev->p->knode_driver, &dev->driver->p->klist_devices);
    
    if (dev->bus)//调用注册bus通知链上的所有函数
        blocking_notifier_call_chain(&dev->bus->p->bus_notifier,BUS_NOTIFY_BOUND_DRIVER, dev);
}

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); //初始化i结构体
    while ((drv = next_driver(&i)) && !error)//遍历总线上的驱动
        error = fn(drv, data);//将驱动和设备进行匹配,这里的fn=__device_attach
    klist_iter_exit(&i);
    return error;
}


static int __device_attach(struct device_driver *drv, void *data)
{
    struct device *dev = data;

    if (!driver_match_device(drv, dev))//现用总线上的match匹配函数进行低级匹配
        return 0;

    return driver_probe_device(drv, dev); //再来高级匹配
}

 
static inline int driver_match_device(struct device_driver *drv, struct device *dev)
{
    return drv->bus->match ? drv->bus->match(dev, drv) : 1;//看到没,这里要调用总线上定义的match函数,实际就是比较设备名和驱动名是否一样
}

int driver_probe_device(struct device_driver *drv, struct device *dev)
{
    int ret = 0;

    if (!device_is_registered(dev)) //设备是否注册,返回 return dev->kobj.state_in_sysfs
        return -ENODEV;

    pr_debug("bus: '%s': %s: matched device %s with driver %s/n",drv->bus->name, __func__, dev_name(dev), drv->name);

    pm_runtime_get_noresume(dev);
    pm_runtime_barrier(dev);
    ret = really_probe(dev, drv);//调用真正的匹配
    pm_runtime_put_sync(dev);

    return ret;
}

static int really_probe(struct device *dev, struct device_driver *drv)
{
    int ret = 0;

    atomic_inc(&probe_count);
    pr_debug("bus: '%s': %s: probing driver %s with device %s/n",drv->bus->name, __func__, drv->name, dev_name(dev));
    WARN_ON(!list_empty(&dev->devres_head));

    dev->driver = drv;
    if (driver_sysfs_add(dev)) {//主要是添加driver和dev之间的连接文件,见上
        printk(KERN_ERR "%s: driver_sysfs_add(%s) failed/n",__func__, dev_name(dev));
        goto probe_failed;
    }

    if (dev->bus->probe) {//现用总线上定义的probe函数尝试一下
        ret = dev->bus->probe(dev);
        if (ret)
            goto probe_failed;
    } else if (drv->probe) {//如果不行,在用驱动上的probe尝试
        ret = drv->probe(dev);
        if (ret)
            goto probe_failed;
    }

    driver_bound(dev);//驱动绑定设备
    ret = 1;
    pr_debug("bus: '%s': %s: bound device %s to driver %s/n",drv->bus->name, __func__, dev_name(dev), drv->name);
    goto done;

probe_failed:
    devres_release_all(dev);
    driver_sysfs_remove(dev);
    dev->driver = NULL;

    if (ret != -ENODEV && ret != -ENXIO) {/* driver matched but the probe failed */
        printk(KERN_WARNING"%s: probe of %s failed with error %d/n",drv->name, dev_name(dev), ret);
    }

    ret = 0;
done:
    atomic_dec(&probe_count);
    wake_up(&probe_waitqueue);
    return ret;
}

3.下面是设备驱动定义:
struct device_driver {
    const char *name;//驱动名称
    struct bus_type*bus; //所在总线
    struct module *owner; 
    const char *mod_name;/* used for built-in modules */ 
    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); 
    struct attribute_group **groups; 
    struct dev_pm_ops *pm; 
    struct driver_private *p; //
};

struct driver_private {
    struct kobject kobj;//代表自身
    struct klist klist_devices;//设备列表
    struct klist_node knode_bus;
    struct module_kobject *mkobj;
    struct device_driver *driver;
};

(1)当总线的match返回非0值,也就是总线找到与驱动相匹配的设备时,驱动的probe的函数将被调用。
(2)当设备从系统总删除是remove被调用。
(3)当系统关机的时候shutdown被调用。
(4)创建属性文件
int dirver_create_file(struct device_driver *drv, struct driver_attribute *attr);
(5)删除属性文件
void driver_remove_file struct device_driver *drv, struct driver_attribute *attr);
(6)驱动的属性使用structdriver_attribute来描述
 structdriver_attribute{
   structattribue attr;
   ssize_t(*show)(struct device_driver *drv, const char *buf);
   ssize_t(*store)(struct device_driver *drv, const char *buf, size_t count);
 }
(7)卸载总线上注销驱动
int driver_register(structdevice_driver *drv)
(8)在总线上注册驱动
void driver_unregister(struct device_driver *drv)
(9)代码分析
int driver_register(struct device_driver *drv)
{
    int ret;
    struct device_driver *other;

    BUG_ON(!drv->bus->p); //判断bus->p是否为空

    if ((drv->bus->probe && drv->probe) || //判断驱动跟驱动的总线是否有冲突的函数注册,给出警告信息
        (drv->bus->remove && drv->remove) ||
        (drv->bus->shutdown && drv->shutdown))
        printk(KERN_WARNING "Driver '%s' needs updating - please use ""bus_type methods\n", drv->name);

    other = driver_find(drv->name, drv->bus); //在注册在bus上的driver寻找是否有跟要注册的driver相同,有则表明驱动已被注册过
    if (other) {
        put_driver(other);
        printk(KERN_ERR "Error: Driver '%s' is already registered, ""aborting...\n", drv->name);
        return -EBUSY;
    }

    ret = bus_add_driver(drv); //经过上面的验证后,将驱动添加注册到bus上
    if (ret)
        return ret;
    ret = driver_add_groups(drv, drv->groups); //如果grop不为空的话,将在驱动文件夹下创建以group名字的子文件夹,然后在子文件夹下添加group的属性文件
    if (ret)
        bus_remove_driver(drv);
    return ret;
}
         
int bus_add_driver(struct device_driver *drv)
{
    struct bus_type *bus;
    struct driver_private *priv;
    int error = 0;

    bus = bus_get(drv->bus);//找到该drv所属的bus,其实就是增加该bus->p->subsys->kobject->kref的引用计数
    if (!bus)
        return -EINVAL;

    pr_debug("bus: '%s': add driver %s\n", bus->name, drv->name);

    priv = kzalloc(sizeof(*priv), GFP_KERNEL);//分配driver_private结构
    if (!priv) {
        error = -ENOMEM;
        goto out_put_bus;
    }
    klist_init(&priv->klist_devices, NULL, NULL);//初始化priv->klist_devices
    priv->driver = drv; //将该drv赋值给priv->driver
    drv->p = priv; //而drv的drv->p又等于priv
    priv->kobj.kset = bus->p->drivers_kset; //指向bus的drvier容器
    //在sysfs文件系统下在总线所在的drivers_kset目录下添加该驱动的目录
    error = kobject_init_and_add(&priv->kobj, &driver_ktype, NULL,"%s", drv->name); //驱动的kobject初始化和添加dir到sysfs中
    if (error)
        goto out_unregister;

    if (drv->bus->p->drivers_autoprobe) { //这个变量默认是为1的
        error = driver_attach(drv); //匹配相应的设备
        if (error)
            goto out_unregister;
    }
    klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers); //将priv->knode_bus添加到bus->p->klist_drivers,即添加到总线上
    module_add_driver(drv->owner, drv); //添加drv的module

    error = driver_create_file(drv, &driver_attr_uevent); //在sysfs的目录下创建文件uevent属性文件
    if (error) {
        printk(KERN_ERR "%s: uevent attr (%s) failed\n",__func__, drv->name);
    }
    error = driver_add_attrs(bus, drv);//给driver添加bus上的所有属性
    if (error) {
        printk(KERN_ERR "%s: driver_add_attrs(%s) failed\n",__func__, drv->name);
    }
    error = add_bind_files(drv); //添加绑定文件,driver_attr_bind 和 driver_attr_unbind
    if (error) {
        printk(KERN_ERR "%s: add_bind_files(%s) failed\n", __func__, drv->name);
    }

    kobject_uevent(&priv->kobj, KOBJ_ADD); //产生一个KOBJ_ADD uevent
    return 0;
out_unregister:
    kfree(drv->p);
    drv->p = NULL;
    kobject_put(&priv->kobj);
out_put_bus:
    bus_put(bus);
    return error;
} 
         
int driver_attach(struct device_driver *drv)
{
    return bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);
}

//该函数将调用bus_for_each_dev()。
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)); //将bus中的已注册的device列表放到迭代器中,方便索引
    while ((dev = next_device(&i)) && !error) //将驱动逐个地与列表中每一个的device匹配,可能一个驱动匹配好几个设备
        error = fn(dev, data); //这个fn就是上面传下来的__driver_attach
    klist_iter_exit(&i);
    return error;
}

static int __driver_attach(struct device *dev, void *data)
{
    struct device_driver *drv = data;
    if (!driver_match_device(drv, dev)) //跟名字的意思一样,driver跟device尝试匹配
        return 0;

    if (dev->parent) /* Needed for USB */
        down(&dev->parent->sem);
    down(&dev->sem);
    if (!dev->driver)
        driver_probe_device(drv, dev);//再来高级匹配
    up(&dev->sem);
    if (dev->parent)
        up(&dev->parent->sem);

    return 0;
}

static inline int driver_match_device(struct device_driver *drv,struct device *dev)
{
    return drv->bus->match ? drv->bus->match(dev, drv) : 1;//调用总线的match函数
} 
 
int driver_probe_device(struct device_driver *drv, struct device *dev)
{
    int ret = 0;

    if (!device_is_registered(dev)) //首先判断这个device是否已经注册
        return -ENODEV;

    pr_debug("bus: '%s': %s: matched device %s with driver %s\n",drv->bus->name, __func__, dev_name(dev), drv->name);

    ret = really_probe(dev, drv); //转而调用really_probe(),同以上的device_register()里调用的

    return ret;
} 

void module_add_driver(struct module *mod, struct device_driver *drv)
{
    char *driver_name;
    int no_warn;
    struct module_kobject *mk = NULL;

    if (!drv)
        return;

    if (mod)//一般情况下为THIS_MODULE
        mk = &mod->mkobj;
    else if (drv->mod_name) {//如果没模块,则检查驱动的模块名
        struct kobject *mkobj;
        mkobj = kset_find_obj(module_kset, drv->mod_name); //根据驱动模块的名字去module_kset集合中找
        if (mkobj) {
            mk = container_of(mkobj, struct module_kobject, kobj); //用container_of方法通过kobj转换成module_kobject
            drv->p->mkobj = mk; //赋值给驱动的mkobj
            kobject_put(mkobj);
        }
    }

    if (!mk) //mk如果为null则返回
        return;

    no_warn = sysfs_create_link(&drv->p->kobj, &mk->kobj, "module"); //在驱动文件夹下创建名为‘module’的链接文件,链接到module文件夹
    driver_name = make_driver_name(drv); //生成driver_name,给module用
    if (driver_name) {
        module_create_drivers_dir(mk); //在具体的module文件夹下创建driver目录
        no_warn = sysfs_create_link(mk->drivers_dir, &drv->p->kobj,make_driver_name()); //在上面创建的driver目录下,生成一个名为driver_name指定的链接文件,链接到驱动的文件夹
        kfree(driver_name);
    }
}
总体来说,驱动的注册比较复杂,但是我们可以简单概况一下。
1、在总线上找找该驱动有没有被注册过
2、若没有注册过,则将驱动加入到总线驱动集合中
3、在总线上找能匹配驱动的设备
     1、将总线上每个设备进行匹配
     2、首先用总线的match 函数进行低级匹配
     3、然后在用总线的probe函数进行高级匹配,若失败,则用驱动上的probe寒酸进行高级匹配
     4、如果匹配成功,则将设备绑定到驱动链表中
4、如果匹配成功,则将驱动加入到总线的驱动链表中

4、结束语
系统初始化时,会扫描连接那些设备,并为扫描到的设备建立一个struct device的变量,接下来就是驱动,每次扫描有一个驱动程序,就要为其分配一个struct device_driver结构变量,并把这些变量加入相应的链表中,device插入devices、driver插入drivers中去,这样总线伤的两条链表变这样诞生了。在以前的系统中都是先有设备后又驱动的,因为设备都是先插好了再商店开机的。这样devices链表会先被创建,而后就是drivers链表,然后驱动程序就开始初始化,开始注册其struct devicr_driver结构,然后他就去总线的devices链表中去寻找(遍历)还没有绑定driver的设备,即struct device中的struct device_driver指针乃为空的设备。然后去观察该设备的特征,若匹配就会调用device_bind_driver的函数结合在一起,换句话说,把struct device中的struct devicr_drive driver指向这个driver,而struct device_driver drivers加入他的那张struct klist *klist_devices链表中来,这样 bus、device、driver就建立起关系并联系起来了。

三、测试模块

         1.BUS
[html] view plaincopy 
#include <linux/device.h>  
#include <linux/module.h>  
#include <linux/kernel.h>  
#include <linux/init.h>  
#include <linux/string.h>  
  
MODULE_AUTHOR("David Xie");  
MODULE_LICENSE("Dual BSD/GPL");  
  
static char *Version = "$Revision: 1.9 {1}quot;;  
  
static int my_match(struct device *dev, struct device_driver *driver)  
{  
    return !strncmp(dev->bus_id, driver->name, strlen(driver->name));  
}  
  
static void my_bus_release(struct device *dev)  
{  
    printk(KERN_DEBUG "my bus release\n");  
}  
      
struct device my_bus = {  
    .bus_id   = "my_bus0",  
    .release  = my_bus_release  
};  
  
  
struct bus_type my_bus_type = {  
    .name = "my_bus",  
    .match = my_match,  
};  
  
EXPORT_SYMBOL(my_bus);  
EXPORT_SYMBOL(my_bus_type);  
  
  
/*  
 * Export a simple attribute.  
 */  
static ssize_t show_bus_version(struct bus_type *bus, char *buf)  
{  
    return snprintf(buf, PAGE_SIZE, "%s\n", Version);  
}  
  
static BUS_ATTR(version, S_IRUGO, show_bus_version, NULL);  
  
  
static int __init my_bus_init(void)  
{  
    int ret;  
          
        /*注册总线*/  
    ret = bus_register(&my_bus_type);  
    if (ret)  
        return ret;  
          
    /*创建属性文件*/    
    if (bus_create_file(&my_bus_type, &bus_attr_version))  
        printk(KERN_NOTICE "Fail to create version attribute!\n");  
      
    /*注册总线设备*/  
    ret = device_register(&my_bus);  
    if (ret)  
        printk(KERN_NOTICE "Fail to register device:my_bus!\n");  
          
    return ret;  
}  
  
static void my_bus_exit(void)  
{  
    device_unregister(&my_bus);  
    bus_unregister(&my_bus_type);  
}  
  
module_init(my_bus_init);  
module_exit(my_bus_exit);  
创建一条名为my_bus_type的总线和一个名为my_bus的总线设备,注意总线也是一个设备,也需要注册。
测试结果:



2.DEVICE
[html] view plaincopy 
#include <linux/device.h>  
#include <linux/module.h>  
#include <linux/kernel.h>  
#include <linux/init.h>  
#include <linux/string.h>  
  
MODULE_AUTHOR("David Xie");  
MODULE_LICENSE("Dual BSD/GPL");  
  
extern struct device my_bus;   
extern struct bus_type my_bus_type;  
  
/* Why need this ?*/  
static void my_dev_release(struct device *dev)  
{   
      
}  
  
struct device my_dev = {  
    .bus = &my_bus_type,  
    .parent = &my_bus,  
    .release = my_dev_release,  
};  
  
/*  
 * Export a simple attribute.  
 */  
static ssize_t mydev_show(struct device *dev, char *buf)  
{  
    return sprintf(buf, "%s\n", "This is my device!");  
}  
  
static DEVICE_ATTR(dev, S_IRUGO, mydev_show, NULL);  
  
static int __init my_device_init(void)  
{  
    int ret = 0;  
          
        /* 初始化设备 */  
    strncpy(my_dev.bus_id, "my_dev", BUS_ID_SIZE);  
          
        /*注册设备*/  
    device_register(&my_dev);  
          
    /*创建属性文件*/  
    device_create_file(&my_dev, &dev_attr_dev);  
      
    return ret;   
  
}  
  
static void my_device_exit(void)  
{  
    device_unregister(&my_dev);  
}  
  
module_init(my_device_init);  
module_exit(my_device_exit);  

注册一个bus_id即名字为my_dev的设备,该设备的bus成员指向上一步创建的my_bus_type总线,parent成员指向上一步创建的my_bus总线设备。
         测试结果:


3.DRIVER
[html] view plaincopy
#include <linux/device.h>  
#include <linux/module.h>  
#include <linux/kernel.h>  
#include <linux/init.h>  
#include <linux/string.h>  
  
MODULE_AUTHOR("David Xie");  
MODULE_LICENSE("Dual BSD/GPL");  
  
extern struct bus_type my_bus_type;  
  
static int my_probe(struct device *dev)  
{  
    printk("Driver found device which my driver can handle!\n");  
    return 0;  
}  
  
static int my_remove(struct device *dev)  
{  
    printk("Driver found device unpluged!\n");  
    return 0;  
}  
  
struct device_driver my_driver = {  
    .name = "my_dev",  
    .bus = &my_bus_type,  
    .probe = my_probe,  
        .remove = my_remove,  
};  
  
/*  
 * Export a simple attribute.  
 */  
static ssize_t mydriver_show(struct device_driver *driver, char *buf)  
{  
    return sprintf(buf, "%s\n", "This is my driver!");  
}  
  
static DRIVER_ATTR(drv, S_IRUGO, mydriver_show, NULL);  
  
static int __init my_driver_init(void)  
{  
    int ret = 0;  
          
        /*注册驱动*/  
    driver_register(&my_driver);  
          
    /*创建属性文件*/  
    driver_create_file(&my_driver, &driver_attr_drv);  
      
    return ret;   
  
}  
  
static void my_driver_exit(void)  
{  
    driver_unregister(&my_driver);  
}  
  
module_init(my_driver_init);  
module_exit(my_driver_exit);  
创建一个名为“bus_dev”的驱动,并将bus成员指向第一步创建的my_bus_type总线

抱歉!评论已关闭.