Windows XP Windows 7 Windows 2003 Windows Vista Windows教程綜合 Linux 系統教程
Windows 10 Windows 8 Windows 2008 Windows NT Windows Server 電腦軟件教程
 Windows教程網 >> Linux系統教程 >> Linux教程 >> I2C設備與驅動的關聯

I2C設備與驅動的關聯

日期:2017/2/7 14:40:34      編輯:Linux教程
 

在Linux操作系統中,驅動程序的加載分為兩種:內核啟動時自動加載和用戶手動加載;硬件設備也可以采用兩種方式添加到系統中:在系統啟動前及系統運行時的熱插撥。下面,我們以arm體系結構下的at91處理器中的I2C控制器為例,介紹一下硬件設備及相關的驅動程序是如何綁定及松綁的。

1. 平台驅動注冊過程

1.1 at91_i2c_init()函數

在文件drivers/i2c/busses/i2c-at91.c中,定義了結構體struct platform_driver並進行了初始化,通過使用module_init()宏進行聲明,當模塊被加載到內核時會調用 at91_i2c_init()函數。在此函數中,調用了platform_driver_register()函數來完成注冊。

 

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);

}

1.2 platform_driver_register()函數

在文件drivers/base/platform.c中,實現並導出了platform_driver_register()函數,以便使其他模塊中的函數可以調用此函數。它在完成簡單的包裝後,調用了driver_register()函數,完成了從平台實現到Linux內核實現的過渡。

在此,我們需要關注一下platform_match()和platform_drv_probe()函數。platform_match() 函數確定驅動與設備的關聯,而platform_drv_probe()函數會在隨後介紹的函數中被調用。

//比較驅動信息中的name與設備信息中的name兩者是否一致

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);

}

 

struct bus_type platform_bus_type = {

.name = "platform",

.dev_attrs = platform_dev_attrs,

.match = platform_match,

.uevent = platform_uevent,

.suspend = platform_suspend,

.suspend_late = platform_suspend_late,

.resume_early = platform_resume_early,

.resume = platform_resume,

};

EXPORT_SYMBOL_GPL(platform_bus_type);

 

/**

* platform_driver_register

* @drv: platform driver structure

*/

int platform_driver_register(struct platform_driver *drv)

{

drv->driver.bus = &platform_bus_type;

//在really_probe函數中,回調了platform_drv_probe函數

if (drv->probe)

drv->driver.probe = platform_drv_probe;

if (drv->remove)

drv->driver.remove = platform_drv_remove;

if (drv->shutdown)

drv->driver.shutdown = platform_drv_shutdown;

if (drv->suspend)

drv->driver.suspend = platform_drv_suspend;

if (drv->resume)

drv->driver.resume = platform_drv_resume;

return driver_register(&drv->driver);

}

EXPORT_SYMBOL_GPL(platform_driver_register);

 

1.3 driver_register()函數

在文件drivers/base/driver.c中,實現了driver_register()函數。在此函數中,初始化結構體struct device_driver中的klist_device和unloaded字段,通過klist_device字段,可以保存此驅動支持的設備鏈表,通過“完成”接口機制,完成線程間的同步。鏈表和“完成”接口的詳細信息可以參考文獻[1]。返回bus_add_driver()函數的運行結果。

 

/**

* driver_register - register driver with bus

* @drv: driver to register

*

* We pass off most of the work to the bus_add_driver() call,

* since most of the things we have to do deal with the bus

* structures.

*

* The one interesting aspect is that we setup @drv->unloaded

* as a completion that gets complete when the driver reference

* count reaches 0.

*/

int driver_register(struct device_driver * drv)

{

if ((drv->bus->probe && drv->probe) ||

(drv->bus->remove && drv->remove) ||

(drv->bus->shutdown && drv->shutdown)) {

printk(KERN_WARNING "Driver '%s' needs updating - please use bus_type methods\n", drv->name);

}

klist_init(&drv->klist_devices, NULL, NULL);

init_completion(&drv->unloaded);

return bus_add_driver(drv);

}

 

1.4 bus_add_driver()函數

在文件drivers/base/bus.c中實現了bus_add_driver()函數,它通過語句klist_add_tail(&drv->knode_bus, &bus->klist_drivers); 將驅動信息保存到總線結構中,在設備注冊過程中,我們就可以明白此語句的作用了。在此語句之前,調用了driver_attach()函數。

/**

* bus_add_driver - Add a driver to the bus.

* @drv: driver.

*

*/

int bus_add_driver(struct device_driver *drv)

{

struct bus_type * bus = get_bus(drv->bus);

int error = 0;

 

if (!bus)

return 0;

 

pr_debug("bus %s: add driver %s\n", bus->name, drv->name);

Copyright © Windows教程網 All Rights Reserved