找回密码
 注册
搜索
热搜: 回贴
微赢网络技术论坛 门户 服务器 Linux/BSD 查看内容

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

2009-12-20 13:48| 发布者: admin| 查看: 85| 评论: 0|原作者: 段誉

由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





最新评论

QQ|小黑屋|最新主题|手机版|微赢网络技术论坛 ( 苏ICP备08020429号 )

GMT+8, 2024-9-30 03:29 , Processed in 0.221681 second(s), 12 queries , Gzip On, MemCache On.

Powered by Discuz! X3.5

© 2001-2023 Discuz! Team.

返回顶部