歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux基礎 >> Linux教程 >> Linux設備模型之platform

Linux設備模型之platform

日期:2017/2/28 15:58:19   编辑:Linux教程
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;
}

Copyright © Linux教程網 All Rights Reserved