|
对于platform设备的概念在此不再赘述,在这里主要是和大家分享一下刚刚解决的一个问题,在网上的很多资料里说对于Platform设备,必须先注册platform_device然后再注册platform_driver,但我发现的事实似乎不是如此。这个结论是小弟我在一个简单的platform设备测试程序中得到的,platform设备测试程序如下:
plat_dev.c:- #include<linux/module.h>
- #include<linux/init.h>
- #include<linux/kernel.h>
- #include<linux/device.h>
- #include<linux/platform_device.h>
- struct platform_device my_dev =
- {
- .name = "my_dev",
- .id = -1,
- };
- static int __init platform_dev_init(void)
- {
- int ret;
-
- ret = platform_device_register(&my_dev);
- if(ret)
- {
- printk(KERN_NOTICE "##my_dev failed to register.\n");
- }
- else
- {
- printk(KERN_NOTICE "##register my_dev.\n");
- }
- return ret;
- }
- static void __exit platform_dev_exit(void)
- {
- platform_device_unregister(&my_dev);
- printk(KERN_NOTICE "##my_dev unregister.\n");
- }
- module_init(platform_dev_init);
- module_exit(platform_dev_exit);
- MODULE_LICENSE("GPL");
复制代码 plat_drv.c:- #include<linux/module.h>
- #include<linux/init.h>
- #include<linux/kernel.h>
- #include<linux/device.h>
- #include<linux/platform_device.h>
- static int probe_test(struct platform_device *pdev)
- {
- printk(KERN_NOTICE "##driver found device.\n");
- return 0;
- }
- static int remove_test(struct platform_device *pdev)
- {
- printk(KERN_DEBUG "##remove device.\n");
- return 0;
- }
- struct platform_driver my_drv =
- {
- .probe = probe_test,
- .remove = remove_test,
- .driver =
- {
- .name = "my_dev",
- .owner = THIS_MODULE,
- },
- };
- static int __init platform_drv_init(void)
- {
- int ret;
-
- ret = platform_driver_register(&my_drv);
- if(ret)
- {
- printk(KERN_NOTICE "##driver failed to register.\n");
- }
- else
- {
- printk(KERN_NOTICE "##register driver.\n",ret);
- }
- return ret;
- }
- static void __exit platform_drv_exit(void)
- {
- platform_driver_unregister(&my_drv);
- printk(KERN_NOTICE "##driver unregister.\n");
- }
- module_init(platform_drv_init);
- module_exit(platform_drv_exit);
- MODULE_LICENSE("GPL");
复制代码- [root@EmbedSky platform]# insmod plat_drv.ko
- ##register driver.
- [root@EmbedSky platform]# insmod plat_dev.ko
- ##driver found device.
- ##register my_dev.
复制代码 虽然测试结果只有寥寥几行,但已足以令我傻眼……对于此我当时有两个疑惑:
1.我是先加载的plat_drv.ko,也就是说相应的platform_device还未被注册,可是驱动却能注册成功。。
2.为何probe在加载plat_dev.ko,也就是说相应的Platform_device被注册时会被调用
这样看似乎是没法看出问题所在的。。。没办法,只能扎进源码里找答案了。。
我首先解决的是第二个问题,跟踪platform_device_register(),在platform_device_register()-->platform_device_add()-->device_add()-->bus_attach_device()-->bus_for_each_drv()中,遍历platform_bus下的klist_drivers,并且通过调用__device_attach()函数进行匹配,在__device_attach()中,如果匹配成功,则调用driver_probe_device()-->really_probe-->driver->probe,在此调用driver中得probe....所以就算是后注册platform_device,只要能够匹配到对应的驱动,驱动中的probe函数也一样能被调用!
然后是第一个问题,跟踪platform_driver_register(),发现在platform_driver_register()-->driver_register()-->bus_add_driver()中有这么一段:- if (drv->bus->p->drivers_autoprobe) {
- error = driver_attach(drv);/*搜寻匹配的设备与驱动相关联*/
- if (error)
- goto out_unregister;
- }
复制代码 driver_attach()的内容:- int driver_attach(struct device_driver *drv)
- {
- return bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);
- }
复制代码 __driver_attach的内容:- static int __driver_attach(struct device *dev, void *data)
- {
- struct device_driver *drv = data;
- /*
- * Lock device and try to bind to it. We drop the error
- * here and always return 0, because we need to keep trying
- * to bind to devices and some drivers will return an error
- * simply if it didn't support the device.
- *
- * driver_probe_device() will spit a warning if there
- * is an error.
- */
- if (!driver_match_device(drv, dev))
- return 0;
- if (dev->parent) /* Needed for USB */
- down(&dev->parent->sem);
- down(&dev->sem);
- if (!dev->driver)
- driver_probe_device(drv, dev);
- up(&dev->sem);
- if (dev->parent)
- up(&dev->parent->sem);
- return 0;
- }
复制代码 这个函数是问题的关键,可以发现,无论是否和一个设备匹配,该函数最终的会返回0,而在bus_for_each_dev()中,遍历klist_devices,调用__device_attach和每一个device进行匹配,即使最后找不到匹配的设备,bus_for_each_dev()返回的error值也是0!相关代码:- int bus_for_each_dev(struct bus_type *bus, struct device *start,
- void *data, int (*fn)(struct device *, void *))
- {
- struct klist_iter i;
- struct device *dev;
- int error = 0;
- if (!bus)
- return -EINVAL;
- klist_iter_init_node(&bus->p->klist_devices, &i,
- (start ? &start->p->knode_bus : NULL));
- while ((dev = next_device(&i)) && !error)
- error = fn(dev, data);
- klist_iter_exit(&i);
- return error;
- }
复制代码 也就是说最后返回给bus_add_driver()的error值是0,这样即使没有找到匹配的设备也不会导致驱动的注册失败!
得到的结论是:不论是注册device还是driver都会进行匹配,并且在匹配成功的情况下调用driver->probe,也就是说在这一点上,并不一定要先注册设备再注册驱动。。。即使是后注册设备也能调用probe...只是习惯上来说(或者其他我不知道的原因)应该是设备在先驱动在后.
就这样一个比较二的问题还是可以看出,驱动的学习最终还是要落在对内核源码的理解上,要对其内部的细节和原理进行探索,这样自己肚子里才感觉有东西,不能只停留在书本或者网友对其的分析阐述上!以上全属本人愚见,分析不到位之处望各路朋友指出! |
|