參考:https://my.oschina.net/felixliang/blog/80741
platform_driver_register( )負(fù)責(zé)注冊(cè)平臺(tái)驅(qū)動(dòng)程序低匙,如果在內(nèi)核中找到了使用驅(qū)動(dòng)程序的設(shè)備报账,調(diào)用probe( )阔馋。刨去參數(shù)檢查页衙、錯(cuò)誤處理兄春,platform_driver_register的主要過程如下:
...
{
...
return platform_driver_register(&bcm2708_i2c_driver);
...
}
int platform_driver_register(struct platform_driver *drv)
{
...
return driver_register(&drv->driver);
}
int driver_register(struct device_driver *drv)
{
...
ret = bus_add_driver(drv); //platform是一個(gè)虛擬總線
...
}
int bus_add_driver(struct device_driver *drv)
{
...
if (drv->bus->p->drivers_autoprobe) {
error = driver_attach(drv);
if (error)
goto out_unregister;
}
...
kobject_uevent(&priv->kobj, KOBJ_ADD); //發(fā)送uevent消息
return 0;
...
}
/**內(nèi)核驅(qū)動(dòng)通過kobject_uevent()/kobject_uevent_env()發(fā)送uevent到用戶空間,主要包括兩部分工作:
一是通過netlink_broadcast_filtered()發(fā)送netlink消息;另一是通過
call_usermodehelper_setup()/call_usermodehelper_exec()調(diào)用用戶空間程序處理uevent消息。
**/
int driver_attach(struct device_driver *drv) //driver_attach() 驅(qū)動(dòng)自動(dòng)匹配設(shè)備
{
return bus_for_each_dev(drv->bus, NULL, drv, __driver_attach); //監(jiān)測(cè)到bus設(shè)備授舟,調(diào)用
__driver_attach( )
}
//調(diào)用該函數(shù),那么drv驅(qū)動(dòng)程序會(huì)和drv所在總線上連接了的物理設(shè)備進(jìn)行一一匹配
static int __driver_attach(struct device *dev, void *data) //dev 為使用驅(qū)動(dòng)程式的設(shè)備結(jié)構(gòu)體
{
...
if (!dev->driver)
driver_probe_device(drv, dev);
...
return 0;
}
int driver_probe_device(struct device_driver *drv, struct device *dev)
{
...
ret = really_probe(dev, drv);
...
}
static int really_probe(struct device *dev, struct device_driver *drv)
{
...
dev->driver = drv;
if (driver_sysfs_add(dev)) { //在sysfs中添加設(shè)備的Kobject目錄和熟悉文件
...
}
if (dev->bus->probe) {
...
} else if (drv->probe) {
ret = drv->probe(dev); //調(diào)用driver的probe( ),dev為設(shè)備結(jié)構(gòu)體
...
}
...
}
補(bǔ)充:
1贸辈、uevent()函數(shù)參考:https://www.cnblogs.com/sky-heaven/p/14042128.html
2释树、driver_attach() 驅(qū)動(dòng)自動(dòng)匹配設(shè)備