Chinaunix首页 | 论坛 | 博客
  • 博客访问: 533010
  • 博文数量: 174
  • 博客积分: 4177
  • 博客等级: 上校
  • 技术积分: 1827
  • 用 户 组: 普通用户
  • 注册时间: 2007-10-15 14:12
文章分类

全部博文(174)

文章存档

2018年(1)

2017年(1)

2013年(3)

2012年(9)

2010年(12)

2009年(5)

2008年(106)

2007年(37)

我的朋友

分类: LINUX

2008-12-23 20:14:40

由fb设备的注册过程来看内核的设备模型


    在<<platform设备添加流程 >>一文中,关于struct device方面的内容没有详加阐述,现在我们来一一分析。struct platform 结构里面有一个 struct device类型的成员,我们先来看看该结构的定义:

// include/linux/device.h:
 305struct device {
 306        struct klist            klist_children;
 307        struct klist_node       knode_parent;           /* node in sibling list */
 308        struct klist_node       knode_driver;
 309        struct klist_node       knode_bus;
 310        struct device   * parent;
 311
 312        struct kobject kobj;
 313        char    bus_id[BUS_ID_SIZE];    /* position on parent bus */
 314        struct device_attribute uevent_attr;
 315
 316        struct semaphore        sem;    /* semaphore to synchronize calls to
 317                                         * its driver.
 318                                         */
 319
 320        struct bus_type * bus;          /* type of bus device is on */
 321        struct device_driver *driver;   /* which driver has allocated this
 322                                           device */
 323        void            *driver_data;   /* data private to the driver */
 324        void            *platform_data; /* Platform specific data, device
 325                                           core doesn't touch it */
 326        void            *firmware_data; /* Firmware specific data (e.g. ACPI,
 327                                           BIOS data),reserved for device core*/
 328        struct dev_pm_info      power;
 329
 330        u64             *dma_mask;      /* dma mask (if dma'able device) */
 331        u64             coherent_dma_mask;/* Like dma_mask, but for
 332                                             alloc_coherent mappings as
 333                                             not all hardware supports
 334                                             64 bit addresses for consistent
 335                                             allocations such descriptors. */
 336
 337        struct list_head        dma_pools;      /* dma pools (if dma'ble) */
 338
 339        struct dma_coherent_mem *dma_mem; /* internal for coherent mem
 340                                             override */
 341
 342        void    (*release)(struct device * dev);
 343};


下面来看一下各个成员的函义:

g_list:                全局设备列表中的节点.
node:                 父设备的孩子列表中的节点.
bus_list:               设备从属的总线所属的设备列表中的节点.
driver_list:               设备对应的驱动所属的设备列表中的节点.
intf_list:               intf_data列表. 对每个该设备所支持的接口, 程序会分配一个结构体.
children:                子设备列表.
parent:                  *** 待修正 ***
name:                   设备描述(用ASCII码).例: " 3Com Corporation 3c905 100BaseTX [Boomerang]"
bus_id:                  设备总线的位置描述(用ASCII码). 此设备从属的总线下的所有设备应对应唯一的描述符.
            例: PCI总线bus_id的格式为
            <总线号(bus No.)>:<插槽号(slot No.)>:<功能号(function No.)>
            系统中所有PCI设备的bus_id都对应上述同一个名字.
lock:                   设备的自旋锁(spinlock).
                       (译注: 在自旋锁中, 线程简单地循环等待并检查, 直到锁可用.)(xlp补注: 在UP(uni processor)情况下,spinlock就是简单的cli(清中断)和seiL(设中断).
            在SMP情况下,spinlock_lock是循环检测锁,可用后获取锁,spinlock_unlock是直接释放锁).
refcount:               设备引用的数量.
bus:                   指向设备所属总线的bus_type结构体的指针.
dir:                   设备的sysfs目录.(译注: sysfs是Linux 2.6提供的虚拟文件系统. sysfs从内核设备模型中向用户空间导出设备及驱动的信息. 它也被用来进行配置.)
class_num:           设备的Class-enumerated值.
driver:                   指向设备驱动程序结构体device_driver的指针.
driver_data:           驱动相关的数据.
platform_data:           设备所在平台的数据.例: 对嵌入式或片上系统(SOC)这类用户自定义板上的设备, Linux常使用platform_data指向一个针对板的结构体, 来描述设备以及设备间
            的连线.这样一个结构体中可能包含可用的端口, 芯片参数, GPIO针扮演的额外角色等等. 它可以缩小"板支持包"(Board Support Packages, BSP)的体积并减少
            驱动中针对板的#ifdef的数量.
current_state:           设备当前电源状态.
saved_state:           指向设备已保存的状态的指针. 驱动可以利用它来控制设备,
release:               当所有设备引用都撤销后用来释放设备的回调函数. 它应由为设备分配空间的程序(也就是发现这个设备的总线驱动)来设置.


   现在再来看一下pxafb_device的定义

// arch/arm/mach-pxa/generic.c:
 229static struct platform_device pxafb_device = {
 230        .name           = "pxa2xx-fb",
 231        .id             = -1,
 232        .dev            = {
 233                .platform_data  = &pxa_fb_info,
 234                .dma_mask       = &fb_dma_mask,
 235                .coherent_dma_mask = 0xffffffff,
 236        },
 237        .num_resources  = ARRAY_SIZE(pxafb_resources),
 238        .resource       = pxafb_resources,
 239};

    也就是说只初始化了struct device结构的platform_data、dma_mask和coherent_dma_mask成员,相关的定义如下:

// arch/arm/mach-pxa/generic.c:
 207 static struct pxafb_mach_info pxa_fb_info;
 227 static u64 fb_dma_mask = ~(u64)0;


   那其它成员是什么时候赋值呢?记得当初我们在platform_device_register()曾经遇到过device_initialize(),当初直接跳过了,我们现在再来看它

// drivers/base/platform.c:
/**
 *    platform_device_register - add a platform-level device
 *    @pdev:    platform device we're adding
 *
 */
int platform_device_register(struct platform_device * pdev)
{
    device_initialize(&pdev->dev);
    return platform_device_add(pdev);
}


// drivers/base/core.c:
 216/**
 217 *      device_initialize - init device structure.
 218 *      @dev:   device.
 219 *
 220 *      This prepares the device for use by other layers,
 221 *      including adding it to the device hierarchy.
 222 *      It is the first half of device_register(), if called by
 223 *      that, though it can also be called separately, so one
 224 *      may use @dev's fields (e.g. the refcount).
 225 */
 226
 227void device_initialize(struct device *dev)
 228{
 229        kobj_set_kset_s(dev, devices_subsys);
 230        kobject_init(&dev->kobj);
 231        klist_init(&dev->klist_children, klist_children_get,
 232                   klist_children_put);
 233        INIT_LIST_HEAD(&dev->dma_pools);
 234        init_MUTEX(&dev->sem);
 235        device_init_wakeup(dev, 0);
 236}

这里的devices_subsys定义于 drivers/base/core.c,如下所示:

// drivers/base/core.c:
 164/*
 165 *      devices_subsys - structure to be registered with kobject core.
 166 */
 167
 168decl_subsys(devices, &ktype_device, &device_uevent_ops);

其中 decl_subsys是一个宏,定义于 include/linux/kobject.h中,如下所示:

// include/linux/kobject.h:
 165struct subsystem {
 166        struct kset             kset;
 167        struct rw_semaphore     rwsem;
 168};
 169
 170#define decl_subsys(_name,_type,_uevent_ops) \
 171struct subsystem _name##_subsys = { \
 172        .kset = { \
 173                .kobj = { .name = __stringify(_name) }, \
 174                .ktype = _type, \
 175                .uevent_ops =_uevent_ops, \
 176        } \
 177}

其中的__stringify()也是一个宏,定义于include/linux/stringify.h,如下所示:

#ifndef __LINUX_STRINGIFY_H
#define __LINUX_STRINGIFY_H

/* Indirect stringification.  Doing two levels allows the parameter to be a
 * macro itself.  For example, compile with -DFOO=bar, __stringify(FOO)
 * converts to "bar".
 */

#define __stringify_1(x)    #x
#define __stringify(x)        __stringify_1(x)

#endif    /* !__LINUX_STRINGIFY_H */

 "#"的作用是把宏参数转换成字符串,因此 __stringify(x) <===> "x"
需要注意的是,这里用了两层,原因可以查看博客上面C/C++里面<>


把它代入即得到
struct subsystem devices_subsys = {
    .kset = {
        .kobj = { .name = "devices" },
        .ktype = &ktype_device,
        .uevent_ops = &device_uevent_ops,
    }
}

其中 ktype_device和device_uevent_ops以及对应的dev_sysfs_ops均位于drivers/base/core.c,里面主要是指定了一些回调函数,如下所示:

// drivers/base/core.c:
  87static struct kobj_type ktype_device = {
  88        .release        = device_release,
  89        .sysfs_ops      = &dev_sysfs_ops,
  90};

 151static struct kset_uevent_ops device_uevent_ops = {
 152        .filter =       dev_uevent_filter,
 153        .name =         dev_uevent_name,
 154        .uevent =       dev_uevent,
 155};

  59static struct sysfs_ops dev_sysfs_ops = {
  60        .show   = dev_attr_show,
  61        .store  = dev_attr_store,
  62};

    实际上就是为一些函数指针指定了对应的调用函数。

   定义了这个变量之后,但相当于定义了一个子系统,名字就是devices,对应于/sys下面的devices目录。需要注意的是,在2.6内核的后期版本中,去掉了struct subsystem结构,直接用一个struct kset结构来代替,这是因为本质上二者其实是一个东西,去掉这么一个名词会让人更容易理解。之后,我们便可以调用subsystem_register()来对该子系统进行注册,但目前我们关注的重点不在这里,所以对subsystem的讨论暂且到这里。我们只需要记住,我们已经在内核中注册进了一个子系统,子系统的名字就是"devices",对应的变量为devices_subsys。

   现在继续回到我们的device_initialize()函数, 229行的 kobj_set_kset_s() 是一个宏,如下所示:

// include/linux/kobject.h:
 197/**
 198 *      kobj_set_kset_s(obj,subsys) - set kset for embedded kobject.
 199 *      @obj:           ptr to some object type.
 200 *      @subsys:        a subsystem object (not a ptr).
 201 *
 202 *      Can be used for any object type with an embedded ->kobj.
 203 */
 204
 205#define kobj_set_kset_s(obj,subsys) \
 206        (obj)->kobj.kset = &(subsys).kset

 116struct kset {
 117        struct subsystem        * subsys;
 118        struct kobj_type        * ktype;
 119        struct list_head        list;
 120        spinlock_t              list_lock;
 121        struct kobject          kobj;
 122        struct kset_uevent_ops  * uevent_ops;
 123};


    因此, kobj_set_kset_s(dev, devices_subsys)的作用实际上就是指定dev所指向的设备所属的kobject的kset为devices_subsys这个子系统(其实就是一个kset)。
    紧接着230行初始化struct device的kobj成员,相关定义如下:

// include/linux/kobject.h:
  50 struct kobject {
  51        const char              * k_name;
  52        char                    name[KOBJ_NAME_LEN];
  53        struct kref             kref;
  54        struct list_head        entry;
  55        struct kobject          * parent;
  56        struct kset             * kset;
  57        struct kobj_type        * ktype;
  58        struct dentry           * dentry;
  59};

  85 struct kobj_type {
  86        void (*release)(struct kobject *);
  87        struct sysfs_ops        * sysfs_ops;
  88        struct attribute        ** default_attrs;
  89};

//  lib/kobject.c
 123/**
 124 *      kobject_init - initialize object.
 125 *      @kobj:  object in question.
 126 */
 127 void kobject_init(struct kobject * kobj)
 128{
 129        kref_init(&kobj->kref);
 130        INIT_LIST_HEAD(&kobj->entry);
 131        kobj->kset = kset_get(kobj->kset);
 132}

 329/**
 330 *      kobject_get - increment refcount for object.
 331 *      @kobj:  object.
 332 */
 333
 334struct kobject * kobject_get(struct kobject * kobj)
 335{
 336        if (kobj)
 337                kref_get(&kobj->kref);
 338        return kobj;
 339}

    struct kref是内核中用来计数的一个结构,它的操作具有原子性。kref_init()将对应的object的引用计数设置为1。INIT_LIST_HEAD(&kobj->entry)将kobj的entry的prev和next指针都指向entry,最后来设置kobj的kset成员,首先来看用到的几个函数,如下所示:

// include/linux/kobject.h:
 131static inline struct kset * to_kset(struct kobject * kobj)
 132{
 133        return kobj ? container_of(kobj,struct kset,kobj) : NULL;
 134}
 135
 136static inline struct kset * kset_get(struct kset * k)
 137{
 138        return k ? to_kset(kobject_get(&k->kobj)) : NULL;
 139}

    由上可知,LCD对应的struct device中的kobj成员所指向的kset在之前已经设置为指向 devices_subsys子系统对应的kset。所以将会执行kset_get()中的to_kset(kobject_get(&k->kobj))
这个函数首先使kset对应的kobject的引用计数增1,也就是devices_subsys子系统对应的kset所对应的kobject的引用计数增1,然后再将我们的LCD对应的struct device中的kobj成员所指向的kset指向刚才的kset,绕了这么多,实际上也很简单,就是将kset的引用计数增1。


    再来看device_initialize()里面的231 - 232 行,即 klist_init(&dev->klist_children, klist_children_get,klist_children_put);

    struct klist是对struct list_head的一个包装,功能更强大一些:

// include/linux/klist.h
  21struct klist {
  22        spinlock_t              k_lock;
  23        struct list_head        k_list;
  24        void                    (*get)(struct klist_node *);
  25        void                    (*put)(struct klist_node *);
  26};

  32struct klist_node {
  33        struct klist            * n_klist;
  34        struct list_head        n_node;
  35        struct kref             n_ref;
  36        struct completion       n_removed;
  37};

// lib/klist.c
  42/**
  43 *      klist_init - Initialize a klist structure.
  44 *      @k:     The klist we're initializing.
  45 *      @get:   The get function for the embedding object (NULL if none)
  46 *      @put:   The put function for the embedding object (NULL if none)
  47 *
  48 * Initialises the klist structure.  If the klist_node structures are
  49 * going to be embedded in refcounted objects (necessary for safe
  50 * deletion) then the get/put arguments are used to initialise
  51 * functions that take and release references on the embedding
  52 * objects.
  53 */
  54
  55void klist_init(struct klist * k, void (*get)(struct klist_node *),
  56                void (*put)(struct klist_node *))
  57{
  58        INIT_LIST_HEAD(&k->k_list);
  59        spin_lock_init(&k->k_lock);
  60        k->get = get;
  61        k->put = put;
  62}

    到此,我们可以看出231 -232行的功能其实也很简单,就是初始化struct device里面的klist_children的k_list链表,设置klist_children的get函数为klist_children_get(),put函数为klist_children_put(),而这两个函数也很简单,如下

// drivers/base/core.c
 201static void klist_children_get(struct klist_node *n)
 202{
 203        struct device *dev = container_of(n, struct device, knode_parent);
 204
 205        get_device(dev);
 206}
 207
 208static void klist_children_put(struct klist_node *n)
 209{
 210        struct device *dev = container_of(n, struct device, knode_parent);
 211
 212        put_device(dev);
 213}

 322/**
 323 *      get_device - increment reference count for device.
 324 *      @dev:   device.
 325 *
 326 *      This simply forwards the call to kobject_get(), though
 327 *      we do take care to provide for the case that we get a NULL
 328 *      pointer passed in.
 329 */
 330
 331struct device * get_device(struct device * dev)
 332{
 333        return dev ? to_dev(kobject_get(&dev->kobj)) : NULL;
 334}
 335
 336
 337/**
 338 *      put_device - decrement reference count.
 339 *      @dev:   device in question.
 340 */
 341void put_device(struct device * dev)
 342{
 343        if (dev)
 344                kobject_put(&dev->kobj);
 345}

  31#define to_dev(obj) container_of(obj, struct device, kobj)


    从上可以看出,put和get函数也只是简单地减少或增加设备对就的kobject的引用计数。


   再回到device_initialize()函数里面,233行初始化设备的dma_pools链表,234行初始化结构体里面包含的信号量,235行device_init_wakeup(dev, 0)实际上是一个宏:

// include/linux/pm.h
 190#ifdef CONFIG_PM
 ...
 193#define device_set_wakeup_enable(dev,val) \
 194        ((dev)->power.should_wakeup = !!(val))
 ........
 201#else /* !CONFIG_PM */
 ........
 208#define device_set_wakeup_enable(dev,val)       do{}while(0)
 ........
 221#endif
 223/* changes to device_may_wakeup take effect on the next pm state change.
 224 * by default, devices should wakeup if they can.
 225 */
 226#define device_can_wakeup(dev) \
 227        ((dev)->power.can_wakeup)
 228#define device_init_wakeup(dev,val) \
 229        do { \
 230                device_can_wakeup(dev) = !!(val); \
 231                device_set_wakeup_enable(dev,val); \
 232        } while(0)
 233

    因此,如果有电源管理单元的话,!!作用不清楚,暂且跳过。至此,device_initialize()函数总算分析完毕,这还只是device_register()的top-half,OH GOD!

   在接下来的platform_device_add()函数里面,将struct device的parent成员指针指向platform_bus,这是一个device类型的变量,它的定义如下:

// drivers/base/platform.c:
  26struct device platform_bus = {
  27        .bus_id         = "platform",
  28};

   紧接着,设置设备的总线类型,将struct device的bus成员指针指向platform_bus_type

// drivers/base/platform.c:
 892struct bus_type platform_bus_type = {
 893        .name           = "platform",
 894        .dev_attrs      = platform_dev_attrs,
 895        .match          = platform_match,
 896        .uevent         = platform_uevent,
 897        .pm             = PLATFORM_PM_OPS_PTR,
 898};

   紧接着,设置设备的bus_id,为"pxa2xx-fb",在申请了相应的资源后,调用device_add()来向系统中添加设备,这应该算是device_register()的bottom-half,^-^!!下面来看它的定义:

// drivers/base/core.c
 238/**
 239 *      device_add - add device to device hierarchy.
 240 *      @dev:   device.
 241 *
 242 *      This is part 2 of device_register(), though may be called
 243 *      separately _iff_ device_initialize() has been called separately.
 244 *
 245 *      This adds it to the kobject hierarchy via kobject_add(), adds it
 246 *      to the global and sibling lists for the device, then
 247 *      adds it to the other relevant subsystems of the driver model.
 248 */
 249int device_add(struct device *dev)
 250{
 251        struct device *parent = NULL;
 252        int error = -EINVAL;
 253
 254        dev = get_device(dev);
 255        if (!dev || !strlen(dev->bus_id))
 256                goto Error;
 257
 258        parent = get_device(dev->parent);
 259
 260        pr_debug("DEV: registering device: ID = '%s'\n", dev->bus_id);
 261
 262        /* first, register with generic layer. */
 263        kobject_set_name(&dev->kobj, "%s", dev->bus_id);
 264        if (parent)
 265                dev->kobj.parent = &parent->kobj;
 266
 267        if ((error = kobject_add(&dev->kobj)))
 268                goto Error;
 269
 270        dev->uevent_attr.attr.name = "uevent";
 271        dev->uevent_attr.attr.mode = S_IWUSR;
 272        if (dev->driver)
 273                dev->uevent_attr.attr.owner = dev->driver->owner;
 274        dev->uevent_attr.store = store_uevent;
 275        device_create_file(dev, &dev->uevent_attr);
 276
 277        kobject_uevent(&dev->kobj, KOBJ_ADD);
 278        if ((error = device_pm_add(dev)))
 279                goto PMError;
 280        if ((error = bus_add_device(dev)))
 281                goto BusError;
 282        if (parent)
 283                klist_add_tail(&dev->knode_parent, &parent->klist_children);
 284
 285        /* notify platform of device entry */
 286        if (platform_notify)
 287                platform_notify(dev);
 288 Done:
 289        put_device(dev);
 290        return error;
 291 BusError:
 292        device_pm_remove(dev);
 293 PMError:
 294        kobject_uevent(&dev->kobj, KOBJ_REMOVE);
 295        kobject_del(&dev->kobj);
 296 Error:
 297        if (parent)
 298                put_device(parent);
 299        goto Done;
 300}

    254行的get_device()前面我们已经见过,就是增加device对应的kobject的引用计数。
    258行增加它的父device对应的kobject的引用计数。
    263行设置device对应的kobject的名字为"pxa2xx-fb"
    264 - 265行将device对应的kobject的parent指针指向父device对应的kobject
    267 - 268行调用kobject_add()来向系统中添加device对应的kobject
    270 - 274行设置device的uevent_attr成员,这是一个struct device_attribute结构,它的定义如下:

// include/linux/device.h:
 291/* interface for exporting device attributes */
 292 struct device_attribute {
 293        struct attribute        attr;
 294        ssize_t (*show)(struct device *dev, struct device_attribute *attr,
 295                        char *buf);
 296        ssize_t (*store)(struct device *dev, struct device_attribute *attr,
 297                         const char *buf, size_t count);
 298};


// include/linux/sysfs.h:
  18struct attribute {
  19        const char              * name;
  20        struct module           * owner;
  21        mode_t                  mode;
  22};

// drivers/base/core.c
 157static ssize_t store_uevent(struct device *dev, struct device_attribute *attr,
 158                            const char *buf, size_t count)
 159{
 160        kobject_uevent(&dev->kobj, KOBJ_ADD);
 161        return count;
 162}


    275行用来在sys中创建相应的文件和目录,如下所示:

// drivers/base/core.c
 171/**
 172 *      device_create_file - create sysfs attribute file for device.
 173 *      @dev:   device.
 174 *      @attr:  device attribute descriptor.
 175 */
 176
 177int device_create_file(struct device * dev, struct device_attribute * attr)
 178{
 179        int error = 0;
 180        if (get_device(dev)) {
 181                error = sysfs_create_file(&dev->kobj, &attr->attr);
 182                put_device(dev);
 183        }
 184        return error;
 185}

    277行用kobject_uevent()来添加设备。
    278 - 279行调用device_pm_add(),它是关于设备的电源管理方面的,在此只需要知道它的用途就行了,详细情况我们以后再考虑。
    280 - 281行调用bus_add_device(),它的定义如下:

// drivers/base/bus.c:
 355/**
 356 *      bus_add_device - add device to bus
 357 *      @dev:   device being added
 358 *
 359 *      - Add the device to its bus's list of devices.
 360 *      - Try to attach to driver.
 361 *      - Create link to device's physical location.
 362 */
 363int bus_add_device(struct device * dev)
 364{
 365        struct bus_type * bus = get_bus(dev->bus);
 366        int error = 0;
 367
 368        if (bus) {
 369                pr_debug("bus %s: add device %s\n", bus->name, dev->bus_id);
 370                device_attach(dev);
 371                klist_add_tail(&dev->knode_bus, &bus->klist_devices);
 372                error = device_add_attrs(bus, dev);
 373                if (!error) {
 374                        sysfs_create_link(&bus->devices.kobj, &dev->kobj, dev->bus_id);
 375                        sysfs_create_link(&dev->kobj, &dev->bus->subsys.kset.kobj, "bus");
 376                }
 377        }
 378        return error;
 379}


    365行中的get_bus()定义如下:

// drivers/base/bus.c:
 540struct bus_type * get_bus(struct bus_type * bus)
 541{
 542        return bus ? container_of(subsys_get(&bus->subsys), struct bus_type, subsys) : NULL;
 543}
 544
    
    由上可知,它的功能实际上是先将bus所指向的总线所属的subsys引用计数增1,然后再返回指向bus的指针。

    由前面的分析可知,在platform_device_add()函数中,我们已经将device的bus成员指向了platform_bus_type,所以bus指针不为NULL。
    下面看370行的device_attach(),它的定义如下:

// drivers/base/dd.c
 123/**
 124 *      device_attach - try to attach device to a driver.
 125 *      @dev:   device.
 126 *
 127 *      Walk the list of drivers that the bus has and call
 128 *      driver_probe_device() for each pair. If a compatible
 129 *      pair is found, break out and return.
 130 *
 131 *      Returns 1 if the device was bound to a driver;
 132 *      0 if no matching device was found; error code otherwise.
 133 *
 134 *      When called for a USB interface, @dev->parent->sem must be held.
 135 */
 136int device_attach(struct device * dev)
 137{
 138        int ret = 0;
 139
 140        down(&dev->sem);
 141        if (dev->driver) {
 142                device_bind_driver(dev);
 143                ret = 1;
 144        } else
 145                ret = bus_for_each_drv(dev->bus, NULL, dev, __device_attach);
 146        up(&dev->sem);
 147        return ret;
 148}


    回顾整个过程,我们还没有给device的driver成员赋值,所以driver指针应该指向NULL,因此这里会调用bus_for_each_drv(dev->bus, NULL, dev, __device_attach),它的定义如下:

// drivers/base/bus.c:
 279static struct device_driver * next_driver(struct klist_iter * i)
 280{
 281        struct klist_node * n = klist_next(i);
 282        return n ? container_of(n, struct device_driver, knode_bus) : NULL;
 283}
 284
 285/**
 286 *      bus_for_each_drv - driver iterator
 287 *      @bus:   bus we're dealing with.
 288 *      @start: driver to start iterating on.
 289 *      @data:  data to pass to the callback.
 290 *      @fn:    function to call for each driver.
 291 *
 292 *      This is nearly identical to the device iterator above.
 293 *      We iterate over each driver that belongs to @bus, and call
 294 *      @fn for each. If @fn returns anything but 0, we break out
 295 *      and return it. If @start is not NULL, we use it as the head
 296 *      of the list.
 297 *
 298 *      NOTE: we don't return the driver that returns a non-zero
 299 *      value, nor do we leave the reference count incremented for that
 300 *      driver. If the caller needs to know that info, it must set it
 301 *      in the callback. It must also be sure to increment the refcount
 302 *      so it doesn't disappear before returning to the caller.
 303 */
 304
 305int bus_for_each_drv(struct bus_type * bus, struct device_driver * start,
 306                     void * data, int (*fn)(struct device_driver *, void *))
 307{
 308        struct klist_iter i;
 309        struct device_driver * drv;
 310        int error = 0;
 311
 312        if (!bus)
 313                return -EINVAL;
 314
 315        klist_iter_init_node(&bus->klist_drivers, &i,
 316                             start ? &start->knode_bus : NULL);
 317        while ((drv = next_driver(&i)) && !error)
 318                error = fn(drv, data);
 319        klist_iter_exit(&i);
 320        return error;
 321}

    315 - 316行初始化一个klist_iter结构
    317 - 318行依次从上面的驱动链表中取出一个driver然后调用相应的回调函数。

    结合我们当前的情景,实际上就是从platform_bus_type下面的驱动链中依次取出一个driver,然后调用__device_attach()函数,而该函数的定义如下:

// drivers/base/dd.c
  54/**
  55 *      driver_probe_device - attempt to bind device & driver.
  56 *      @drv:   driver.
  57 *      @dev:   device.
  58 *
  59 *      First, we call the bus's match function, if one present, which
  60 *      should compare the device IDs the driver supports with the
  61 *      device IDs of the device. Note we don't do this ourselves
  62 *      because we don't know the format of the ID structures, nor what
  63 *      is to be considered a match and what is not.
  64 *
  65 *      This function returns 1 if a match is found, an error if one
  66 *      occurs (that is not -ENODEV or -ENXIO), and 0 otherwise.
  67 *
  68 *      This function must be called with @dev->sem held.  When called
  69 *      for a USB interface, @dev->parent->sem must be held as well.
  70 */
  71int driver_probe_device(struct device_driver * drv, struct device * dev)
  72{
  73        int ret = 0;
  74
  75        if (drv->bus->match && !drv->bus->match(dev, drv))
  76                goto Done;
  77
  78        pr_debug("%s: Matched Device %s with Driver %s\n",
  79                 drv->bus->name, dev->bus_id, drv->name);
  80        dev->driver = drv;
  81        if (dev->bus->probe) {
  82                ret = dev->bus->probe(dev);
  83                if (ret) {
  84                        dev->driver = NULL;
  85                        goto ProbeFailed;
  86                }
  87        } else if (drv->probe) {
  88                ret = drv->probe(dev);
  89                if (ret) {
  90                        dev->driver = NULL;
  91                        goto ProbeFailed;
  92                }
  93        }
  94        device_bind_driver(dev);
  95        ret = 1;
  96        pr_debug("%s: Bound Device %s to Driver %s\n",
  97                 drv->bus->name, dev->bus_id, drv->name);
  98        goto Done;
  99
 100 ProbeFailed:
 101        if (ret == -ENODEV || ret == -ENXIO) {
 102                /* Driver matched, but didn't support device
 103                 * or device not found.
 104                 * Not an error; keep going.
 105                 */
 106                ret = 0;
 107        } else {
 108                /* driver matched but the probe failed */
 109                printk(KERN_WARNING
 110                       "%s: probe of %s failed with error %d\n",
 111                       drv->name, dev->bus_id, ret);
 112        }
 113 Done:
 114        return ret;
 115}
 116
 117static int __device_attach(struct device_driver * drv, void * data)
 118{
 119        struct device * dev = data;
 120        return driver_probe_device(drv, dev);
 121}

    根据函数开头那部分的说明,我们首先检测bus的match函数是否存在,如果存在的话则调用它来检测驱动支持的设备ID与设备的ID是否匹配。说明里面还提到我们不能自己进行比较,因为我们自己不清楚ID结构的格式等,也不知道什么算是匹配,什么算是不匹配。

    如果找到匹配的设备与驱动的话,将device的driver指针指向该驱动。
    81 - 86行检测bus的probe()函数是否存在,如果存在的话,则调用它来检测我们的驱动是否合适,如果不合适的话则报错
    87 - 93行 如果bus的probe()函数不存在,则检测driver中的probe()函数是否存在,如果存在的话,则调用它来检测设备,同样如果不符号的话将报错。
    94行调用device_bind_driver()函数进行设备与驱动的绑定。下面来看它的定义:

// drivers/base/dd.c
  27/**
  28 *      device_bind_driver - bind a driver to one device.
  29 *      @dev:   device.
  30 *
  31 *      Allow manual attachment of a driver to a device.
  32 *      Caller must have already set @dev->driver.
  33 *
  34 *      Note that this does not modify the bus reference count
  35 *      nor take the bus's rwsem. Please verify those are accounted
  36 *      for before calling this. (It is ok to call with no other effort
  37 *      from a driver's probe() method.)
  38 *
  39 *      This function must be called with @dev->sem held.
  40 */
  41void device_bind_driver(struct device * dev)
  42{
  43        if (klist_node_attached(&dev->knode_driver))
  44                return;
  45
  46        pr_debug("bound device '%s' to driver '%s'\n",
  47                 dev->bus_id, dev->driver->name);
  48        klist_add_tail(&dev->knode_driver, &dev->driver->klist_devices);
  49        sysfs_create_link(&dev->driver->kobj, &dev->kobj,
  50                          kobject_name(&dev->kobj));
  51        sysfs_create_link(&dev->kobj, &dev->driver->kobj, "driver");
  52}


// lib/klist.c:
 174/**
 175 *      klist_node_attached - Say whether a node is bound to a list or not.
 176 *      @n:     Node that we're testing.
 177 */
 178
 179int klist_node_attached(struct klist_node * n)
 180{
 181        return (n->n_klist != NULL);
 182}


    43 - 44行,如果我们的设备的驱动链表不为空的话,则返回
    48行,将dev->knode_driver加到设备的驱动支持的设备链表中。
    49 - 50行,调用sysfs_create_link()函数在dev->driver->kobj对应的目录里面(pxa2xx-fb目录?)创建链接,指向dev->kobj对应的目录(pxa2xx-fb目录?),链接名为
    51行,调用sysfs_create_link()函数在dev->kobj对应的目录里面(pxa2xx-fb目录?)创建链接,指向dev->driver->kobj对应的目录(pxa2xx-fb目录?),链接名为"driver"

    至些,设备与驱动的绑定device_attach()完毕。我们再回到bus_add_device()函数里面,我们再把该函数列一下:

// drivers/base/bus.c:
 355/**
 356 *      bus_add_device - add device to bus
 357 *      @dev:   device being added
 358 *
 359 *      - Add the device to its bus's list of devices.
 360 *      - Try to attach to driver.
 361 *      - Create link to device's physical location.
 362 */
 363int bus_add_device(struct device * dev)
 364{
 365        struct bus_type * bus = get_bus(dev->bus);
 366        int error = 0;
 367
 368        if (bus) {
 369                pr_debug("bus %s: add device %s\n", bus->name, dev->bus_id);
 370                device_attach(dev);
 371                klist_add_tail(&dev->knode_bus, &bus->klist_devices);
 372                error = device_add_attrs(bus, dev);
 373                if (!error) {
 374                        sysfs_create_link(&bus->devices.kobj, &dev->kobj, dev->bus_id);
 375                        sysfs_create_link(&dev->kobj, &dev->bus->subsys.kset.kobj, "bus");
 376                }
 377        }
 378        return error;
 379}

    371行,将dev->knode_bus,添加到总线支持的设备列表bus->klist_deives中。
    372行,调用device_add_attrs()函数添加设备属性,其定义如下所示:

// drivers/base/bus.c:
 323static int device_add_attrs(struct bus_type * bus, struct device * dev)
 324{
 325        int error = 0;
 326        int i;
 327
 328        if (bus->dev_attrs) {
 329                for (i = 0; attr_name(bus->dev_attrs[i]); i++) {
 330                        error = device_create_file(dev,&bus->dev_attrs[i]);
 331                        if (error)
 332                                goto Err;
 333                }
 334        }
 335 Done:
 336        return error;
 337 Err:
 338        while (--i >= 0)
 339                device_remove_file(dev,&bus->dev_attrs[i]);
 340        goto Done;
 341}

    实际上就是将设备的属性一一创建一个属性文件反映在sys中。
    374行,在bus->devices.kobj对应的目录里面(platform目录?)创建链接,指向dev->kobj对应的目录(pxa2xx-fb目录?),链接名为dev->bus_id,即"pxa2xx-fb"。
    372行,在dev->kobj对应的目录(pxa2xx-fb目录?)里面创建链接,指向dev->bus->subsys.kset.kobj对应的目录(platform目录?),链接名为"bus"。


   再回到device_add()函数里面,
// drivers/base/core.c
 282        if (parent)
 283                klist_add_tail(&dev->knode_parent, &parent->klist_children);
 285        /* notify platform of device entry */
 286        if (platform_notify)
 287                platform_notify(dev);


    282 - 283行,如果你指针不为空的话,则将dev->knode_parent加到parent->klist_children。
    286 - 287行,如果platform_notify指针不为空的话,则调用它,它的定义如下:

// drivers/base/core.c
int (*platform_notify)(struct device * dev) = NULL;
 


    至此,device_add()函数分析完毕,device_initialize()和device_add()函数组合成device_register(),它们分别被称为上半部与下半部。

驱动程序模型-device               
 
阅读(1104) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~