linux设备模型之platform
===============================
本文系本站原创,欢迎转载!
转载请注明出处: http://www.cnblogs.com/gdt-a20
===============================
platform可以说是内核抽象出来的一条虚拟总线平台,内核开发者原意是想把硬件层次上的结构关系用软件抽象模拟出来,但是对一些硬件,这样做往往不太合适,例如对于片上soc,外围设备的控制器都集成在处理器上,如果过度的剥离抽象,会使得原本物理上紧密的结构而在软件上变成的偏于独立,因此有了platform,对于联系紧密的soc这往往再合适不过,另外对于从soc上直接引出的引脚,难于独立出来,都可以利用platform来表述。
有了前面关于bus,driver,device的理解,platform平台的理解就比较简单,都是以前面为原型进行的再次封装,好了下面就让我们以具体代码为例进行分析。
一、platform的初始化
platform的初始化代码位于driver/base目录下的platform.c
int __init platform_bus_init(void)
{
int error;
early_platform_cleanup(); // 清除platform设备链表
error = device_register(&platform_bus); //将平台bus作为一个设备注册,出现在device目录
if (error)
return error;
error = bus_register(&platform_bus_type); //注册平台类型的bus,将出现在bus目录下
if (error)
device_unregister(&platform_bus);
return error;
}
先 来看一下 early_platform_cleanup() 这个函数:
void __init early_platform_cleanup(void)
{
struct platform_device *pd, *pd2;
/* clean up the devres list used to chain devices */
/* 遍历early_platform_device_list,把连接到此的所有节点清0,
平台设备都会挂到该节点,现在是平台设备的初始化阶段,自然不
能有连接到此的设备 */
l ist_for_each_entry_safe(pd, pd2, &early_platform_device_list,
dev.devres_head) {
list_del(&pd->dev.devres_head);
memset(&pd->dev.devres_head, 0, sizeof(pd->dev.devres_head));
}
}
再来看一下另外两个结构体:
struct device platform_bus = {
.init_name = "platform",
};
以及
struct bus_type platform_bus_type = {
.name = "platform",
.dev_attrs = platform_dev_attrs,
.match = platform_match,
.uevent = platform_uevent,
.pm = &platform_dev_pm_ops,
};
二、platform_device的注册
platform_device无疑是device的封装,先给出该结构具体代码:
struct platform_device {
const char * name; //名称
int id; //id号
struct device dev; //内嵌的标准模型device
u32 num_resources; //持有资源数
struct resource * resource; //指向具体资源
const struct platform_device_id *id_entry;
/* arch specific additions */
struct pdev_archdata archdata;
};
其中的资源结构体代码为:
struct resource {
resource_size_t start; //资源起始地址,可以是寄存器起始地址等等
resource_size_t end; //结束地址
const char *name; //名称
unsigned long flags; //标志
struct resource *parent, *sibling, *child; //层次级联结构指针
};
具体的注册函数为:
int platform_device_register(struct platform_device *pdev)
{
device_initialize(&pdev->dev); //和标准设备注册时候初始化是一样,就不多说了,
return platform_device_add(pdev); // 不明白的可以看 前面一篇文章 具,体看一下这个
}
===================================================
int platform_device_add(struct platform_device *pdev)
{
int i, ret = 0;
if (!pdev)
return -EINVAL;
if (!pdev->dev.parent)
pdev->dev.parent = &platform_bus; //挂接到platform_bus下面
pdev->dev.bus = &platform_bus_type; //指定bus类型为platform_bus_type
if (pdev->id != -1)
dev_set_name(&pdev->dev, "%s.%d",
pdev->name, pdev->id); //设置名字,将platform下的名字传到内部device,最终会
else //传到kobj
dev_set_name(&pdev->dev, "%s", pdev->name);
for (i = 0; i < pdev->num_resources; i++) { //设置资源层次结构
struct resource *p, *r = &pdev->resource[i];
if (r->name == NULL) //资源名称为NULL则把设备名称设置给它
r->name = dev_name(&pdev->dev);
p = r->parent; //取得资源的父节点,资源在内核中也是层次安排的,
if (!p) { //具有父节点,兄弟节点,子节点
if (resource_type(r) == IORESOURCE_MEM) //如果父节点为NULL,并且资源类型为
p = &iomem_resource; //IORESOURCE_MEM,则把父节点设置
//为iomem_resource,否则如果类型为
else if (resource_type(r) == IORESOURCE_IO) //IORESOURCE_IO,则把父节点设置为
p = &ioport_resource; //IORESOURCE_IO,由此我们可以看出
} //内核数据之间的条理性之强
if (p && insert_resource(p, r)) { //将资源插入父节点,也就是出现在父节点目录层次下
printk(KERN_ERR"%s: failed to claim resource %d/n",
dev_name(&pdev->dev), i);
ret = -EBUSY;
goto failed;
}
}
pr_debug("Registering platform device '%s'. Parent at %s/n",
dev_name(&pdev->dev), dev_name(pdev->dev.parent));
ret = device_add(&pdev->dev); //标准设备注册
if (ret == 0)
return ret;
failed:
while (--i >= 0) {
struct resource *r = &pdev->resource[i];
unsigned long type = resource_type(r);
if (type == IORESOURCE_MEM || type == IORESOURCE_IO)
release_resource(r);
}
return ret;
}
三、platform_driver的注册
driver部分比较简单,其结构为:
struct platform_driver {
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 (*resume)(struct platform_device *);
struct device_driver driver; //内嵌的标准driver结构
const struct platform_device_id *id_table; //支持的设备id表
};
注册函数分析:
int platform_driver_register(struct platform_driver *drv)
{
drv->driver.bus = &platform_bus_type; //设置bus
if (drv->probe) //如果platform_driver下的probe为真,就把内嵌
drv->driver.probe = platform_drv_probe; //的标准driver的probe设置成platform_drv_probe
if (drv->remove) //可见外层的probe比内层的优先级别高
drv->driver.remove = platform_drv_remove;
if (drv->shutdown)
drv->driver.shutdown = platform_drv_shutdown;
return driver_register(&drv->driver); //注册标准driver
}
四、总结
分析了platform架构以及初始化以及注册流程,结合前面关于标注模型的理解,理解这部分,应当很简单! ^_^