您的位置:首页 > 运维架构 > Linux

linux设备模型之platform

2011-05-18 14:18 295 查看
===============================

本文系本站原创,欢迎转载!

转载请注明出处:http://blog.csdn.net/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架构以及初始化以及注册流程,结合前面关于标注模型的理解,理解这部分,应当很简单! ^_^
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: