Linux I2C 子系統採用標準裝置驅動模型,實現 I2C 控制器驅動與從裝置驅動的自動綁定。本文以 AT91 處理器 I2C 控制器為例,詳細追蹤 platform_driver 註冊流程、bus_add_driver、driver_attach、platform_match 匹配邏輯,以及裝置註冊時的反向綁定過程。
static struct platform_driver at91_i2c_driver = {
.probe = at91_i2c_probe,
.remove = __devexit_p(at91_i2c_remove),
.suspend = at91_i2c_suspend,
.resume = at91_i2c_resume,
.driver = {
.name = "at91_i2c",
.owner = THIS_MODULE,
},
};
static int __init at91_i2c_init(void) {
return platform_driver_register(&at91_i2c_driver);
}
int platform_driver_register(struct platform_driver *drv) {
drv->driver.bus = &platform_bus_type;
if (drv->probe)
drv->driver.probe = platform_drv_probe; // 包裝 probe
if (drv->remove)
drv->driver.remove = platform_drv_remove;
// ... suspend/resume 同理
return driver_register(&drv->driver);
}
static int platform_match(struct device *dev, struct device_driver *drv) {
struct platform_device *pdev = container_of(dev, struct platform_device, dev);
return (strncmp(pdev->name, drv->name, BUS_ID_SIZE) == 0);
}
核心邏輯:比較裝置名稱與驅動名稱是否一致。
int driver_register(struct device_driver *drv) {
klist_init(&drv->klist_devices, NULL, NULL); // 初始化支援裝置鏈表
init_completion(&drv->unloaded); // 完成介面,用於同步
return bus_add_driver(drv);
}
int bus_add_driver(struct device_driver *drv) {
struct bus_type *bus = get_bus(drv->bus);
klist_add_tail(&drv->knode_bus, &bus->klist_drivers); // 加入總線驅動列表
driver_attach(drv); // 遍歷總線上所有裝置,嘗試匹配綁定
return 0;
}
driver_attach() 會對總線上的每個裝置呼叫 bus->match()(即 platform_match),匹配成功則呼叫驅動的 probe()。
當裝置註冊(device_register() → bus_add_device() → device_attach())時,同樣會遍歷總線上的所有驅動,呼叫 match() 並觸發 probe()。這實現了雙向自動綁定:
Platform 驅動 probe() 成功後,通常會:
struct i2c_adapter,填入 algo(演算法/傳輸實作)i2c_add_adapter() 註冊到 I2C 核心I2C 核心再管理掛載在該總線上的從裝置驅動(i2c_driver/i2c_client),形成兩層綁定架構。