有了前面關於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;
}