由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 |
|小黑屋|最新主题|手机版|微赢网络技术论坛 ( 苏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.