Linux驅動下的platform總線架構(轉)

 2023-10-07 阅读 24 评论 0

摘要:從 Linux 2.6 內核起,引入一套新的驅動管理和注冊機制:platform_device 和 platform_driver 。 ??? Linux 中大部分的設備驅動,都可以使用這套機制,設備用 platform_device 表示;驅動用 platform_driver 進行注冊。 ???? ??? Linux platfo
從 Linux 2.6 內核起,引入一套新的驅動管理和注冊機制:platform_device 和 platform_driver 。
??? Linux 中大部分的設備驅動,都可以使用這套機制,設備用 platform_device 表示;驅動用 platform_driver 進行注冊。
????
??? Linux platform driver 機制和傳統的 device driver 機制(即:通過 driver_register 函數進行注冊)相比,一個十分明顯的優勢在于 platform 機制將設備本身的資源注冊進內核,由內核統一管理,在驅動程序中用使用這些資源時,通過 platform device 提供的標準接口進行申請并使用。
platform 是一個虛擬的地址總線,相比 PCI、USB,它主要用于描述 SOC 上的片上資源。比如 S3C2410 上集成的控制器( LCD、Watchdog、RTC等),platform 所描述的資源有一個共同點:在 CPU 的總線上直接取址。
平臺設備會分到一個名稱(用在驅動綁定中)以及一系列諸如地址和中斷請求號(IRQ)之類的資源。
struct platform_device {?????????????? // include/linux/platform_device.h?
??? const char??? * name;
??? int??????? id;
??? struct device??? dev;
??? u32??????? num_resources;
??? struct resource??? * resource;
};
***************************************************************************
/*
*? 主要用于定義具體設備占用的硬件資源(如:地址空間、中斷號等)。
*/
struct resource {
??? resource_size_t start;
??? resource_size_t end;
??? const char *name;
??? unsigned long flags;
??? struct resource *parent, *sibling, *child;
};
***************************************************************************
platform 總線下驅動的開發步驟是:
?? 1、設備
? 設備注冊中,需要實現的機構體是:platform_device 。
1)初始化 resource 結構變量
2)初始化 platform_device 結構變量
3)向系統注冊設備:platform_device_register。(以上三步,必須在 設備驅動加載前完成,所以,AT91RM9200 的內核下,該三步是放在 arch/arm/mach-at91/board-dk.c 中)
?? 2、驅動
? 驅動注冊中,需要實現的結構體是:platform_driver 。
struct platform_driver {?????????????????????????? // include/linux/platform_device.h
??? int (*probe)(struct platform_device *);
??? int (*remove)(struct platform_device *);
??? void (*shutdown)(struct platform_device *);
??? int (*suspend)(struct platform_device *, pm_message_t state);
??? int (*suspend_late)(struct platform_device *, pm_message_t state);
??? int (*resume_early)(struct platform_device *);
??? int (*resume)(struct platform_device *);
??? struct pm_ext_ops *pm;
??? struct device_driver driver;
};?
在驅動程序的初始化函數中,調用了 platform_driver_register() 注冊 platform_driver 。
需要注意的是:platform_driver 和 platform_device 中的 name 變量的值必須是相同的 。這樣在?
platform_driver_register() 注冊時,會將當前注冊的 platform_driver 中的 name 變量的值和已注冊的所有 platform_device 中的 name 變量的值進行比較,只有找到具有相同名稱的 platform_device 才能注冊成功。當注冊成功時,會調用 platform_driver 結構元素 probe 函數指針。
rtc-ds1302.c 中,驅動首先執行:
********************************************************************
static int __init ds1302_rtc_init(void)
{
??? return platform_driver_register(&ds1302_platform_driver);
}
********************************************************************
然后,進入:drivers/base/platform.c:platform_driver_register()
********************************************************************
/**
?* platform_driver_register
?* @drv: platform driver structure
?*/
int platform_driver_register(struct platform_driver *drv)
{
??? drv->driver.bus = &platform_bus_type;
??? 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;
??? if (drv->pm)
??????? drv->driver.pm = &drv->pm->base;
??? return driver_register(&drv->driver);
}
此處,對drv->driver 結構體中的幾個函數指針進行初始化設置。最后,調用 driver_register 注冊 driver 成員。
drv->driver 的類型是:
struct platform_driver {???????????????????? // include/linux/platform_device.h
??? int (*probe)(struct platform_device *);
??? int (*remove)(struct platform_device *);
??? void (*shutdown)(struct platform_device *);
??? int (*suspend)(struct platform_device *, pm_message_t state);
??? int (*suspend_late)(struct platform_device *, pm_message_t state);
??? int (*resume_early)(struct platform_device *);
??? int (*resume)(struct platform_device *);
??? struct pm_ext_ops *pm;
??? struct device_driver driver;????????? // drv->driver?
};
struct device_driver {????????????????????? // include/linux/device.h
??? const char??????? *name;
??? struct bus_type??????? *bus;
struct module??????? *owner;
??? const char???????? *mod_name;??? /* used for built-in modules */
int (*probe) (struct device *dev);
??? int (*remove) (struct device *dev);
??? void (*shutdown) (struct device *dev);
??? int (*suspend) (struct device *dev, pm_message_t state);
??? int (*resume) (struct device *dev);
??? struct attribute_group **groups;
struct pm_ops *pm;
struct driver_private *p;
};
********************************************************************
然后,進入:drivers/base/driver.c:driver_register
********************************************************************
/**
?* 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.
?*/
int driver_register(struct device_driver *drv)
{
??? int ret;
??? struct device_driver *other;
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);
other = driver_find(drv->name, drv->bus);
??? if (other) {
??????? put_driver(other);
??????? printk(KERN_ERR "Error: Driver '%s' is already registered, "
??????????? "aborting...\n
", drv->name);
??????? return -EEXIST;
??? }
ret = bus_add_driver(drv);?????????????? // 調用:bus_add_driver(),執行到此處,drv->bus 指向的是 platform_bus_type 這一全局變量。
??? if (ret)
??????? return ret;
??? ret = driver_add_groups(drv, drv->groups);
??? if (ret)
??????? bus_remove_driver(drv);
??? return ret;
}
********************************************************************
然后,進入:drivers/base/bus.c:bus_add_driver
********************************************************************
/**
?* bus_add_driver - Add a driver to the bus.
?* @drv: driver.
?*/
int bus_add_driver(struct device_driver *drv)
{
??? struct bus_type *bus;
??? struct driver_private *priv;
??? int error = 0;
bus = bus_get(drv->bus);
??? if (!bus)
??????? return -EINVAL;
pr_debug("bus: '%s': add driver %s\n", bus->name, drv->name);
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
??? if (!priv) {
??????? error = -ENOMEM;
??????? goto out_put_bus;
??? }
??? klist_init(&priv->klist_devices, NULL, NULL);
??? priv->driver = drv;
??? drv->p = priv;
??? priv->kobj.kset = bus->p->drivers_kset;
??? error = kobject_init_and_add(&priv->kobj, &driver_ktype, NULL,
???????????????????? "%s", drv->name);
??? if (error)
??????? goto out_unregister;
if (drv->bus->p->drivers_autoprobe) {
??????? error = driver_attach(drv);
??????? if (error)
??????????? goto out_unregister;
??? }
??? klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers);
??? module_add_driver(drv->owner, drv);
error = driver_create_file(drv, &driver_attr_uevent);
??? if (error) {
??????? printk(KERN_ERR "%s: uevent attr (%s) failed\n",
??????????? __func__, drv->name);
??? }
??? error = driver_add_attrs(bus, drv);
??? if (error) {
??????? /* How the hell do we get out of this pickle? Give up */
??????? printk(KERN_ERR "%s: driver_add_attrs(%s) failed\n",
??????????? __func__, drv->name);
??? }
??? error = add_bind_files(drv);
??? if (error) {
??????? /* Ditto */
??????? printk(KERN_ERR "%s: add_bind_files(%s) failed\n",
??????????? __func__, drv->name);
??? }
kobject_uevent(&priv->kobj, KOBJ_ADD);
??? return error;
out_unregister:
??? kobject_put(&priv->kobj);
out_put_bus:
??? bus_put(bus);
??? return error;

版权声明:本站所有资料均为网友推荐收集整理而来,仅供学习和研究交流使用。

原文链接:https://hbdhgg.com/4/126654.html

发表评论:

本站为非赢利网站,部分文章来源或改编自互联网及其他公众平台,主要目的在于分享信息,版权归原作者所有,内容仅供读者参考,如有侵权请联系我们删除!

Copyright © 2022 匯編語言學習筆記 Inc. 保留所有权利。

底部版权信息