免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 1159 | 回复: 0
打印 上一主题 下一主题

由fb设备的注册过程来看内核的设备模型 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2008-12-23 20:14 |只看该作者 |倒序浏览
由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的格式为
            ::
            系统中所有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++) {
330                        error = device_create_file(dev,&bus->dev_attrs);
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);
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                http://www.ourkernel.com/bbs/archiver/?tid-55.html


本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u1/50916/showart_1737175.html
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP