一、簡介
相關文件;
- /include/linux/platform_device.h
- /drivers/base/platform.c
在linux設備驅動中,有許多沒有特定總線的外設驅動,在實際開發中,又需要使用到總線、驅動和設備模型這三個概念,故而linux提供了platform這個虛擬總線,掛接在platform總線上的驅動稱為platform驅動,由struct platform_driver
描述,掛接在platorm總線上的設備稱為platform設備,由struct platform_device
描述。
在linux內核的驅動源碼中,可以看見很多基于platform驅動框架的驅動案例實現。
二、platform總線
在linux內核中,使用struct bus_type
描述一個總線,為了抽象出platform這個虛擬總線,其定義如下(/drivers/base/platform.c):
structbus_typeplatform_bus_type={
.name="platform",
.dev_groups=platform_dev_groups,
.match=platform_match,
.uevent=platform_uevent,
.pm=&platform_dev_pm_ops,
};
platform總線的注冊由platform_bus_init()
完成:
int__initplatform_bus_init(void)
{
interror;
early_platform_cleanup();
error=device_register(&platform_bus);
if(error)
returnerror;
error=bus_register(&platform_bus_type);
if(error)
device_unregister(&platform_bus);
of_platform_register_reconfig_notifier();
returnerror;
}
該函數在linux內核啟動過程中,在driver_init()
中被調用,從而向linux內核注冊了platform總線。

三、platform設備和驅動的匹配過程
在定義platform總線的時候就定了該總線下設備和驅動的具體匹配過程,由platform_match()
實現:
staticintplatform_match(structdevice*dev,structdevice_driver*drv)
{
structplatform_device*pdev=to_platform_device(dev);
structplatform_driver*pdrv=to_platform_driver(drv);
/*Whendriver_overrideisset,onlybindtothematchingdriver*/
if(pdev->driver_override)
return!strcmp(pdev->driver_override,drv->name);
/*AttemptanOFstylematchfirst*/
if(of_driver_match_device(dev,drv))
return1;
/*ThentryACPIstylematch*/
if(acpi_driver_match_device(dev,drv))
return1;
/*Thentrytomatchagainsttheidtable*/
if(pdrv->id_table)
returnplatform_match_id(pdrv->id_table,pdev)!=NULL;
/*fall-backtodrivernamematch*/
return(strcmp(pdev->name,drv->name)==0);
}
從上述代碼可知,platform設備和驅動的匹配分為了四種方式處理:
- 1、基于設備樹的匹配方式。
struct device_driver
結構中有個名為of_match_table
的成員變量,此成員變量保存著驅動的compatible匹配表,在設備樹中的每個設備節點的compatible
屬性會和of_match_table
表中的所有成員比較,查看是否存在相同的條目,如果存在則表示設備和此驅動匹配,設備和驅動匹配成功以后probe函數就會執行(這個過程是由linux設備驅動模型中的總線去完成)。
-
2、ACPI的匹配方式。
-
3、id_table 匹配。
每個struct platform_driver
有一個id_table
成員變量,用于保存很多id信息,這些id信息存放著這個platform驅動所支持的驅動類型。
-
4、比較
name
字段
如果第三種匹配方式的id_table
不存在,就直接比較驅動和設備的name
字段是否相等,如果相等則匹配成功;反之匹配不成功。
一般設備驅動為了兼容性都支持設備樹和無設備樹兩種匹配方式。也就是第一種匹配方式一般都會存在,第三種和第四種只要存在一種就可以,一般用的最多的還是第四種,也就是直接比較驅動和設備的
name
字段,因為這種方式最簡單了。
四、platrom驅動和platform設備
前文已經提到:掛接在platform總線上的驅動稱為platform驅動,由struct platform_driver
描述,掛接在platorm總線上的設備稱為platform設備,由struct platform_device
描述。要想開發基于platform設備驅動驅動框架的驅動程序,一定離不開這兩個數據結構。首先來看看platform驅動的描述者struct platform_driver
,該結構定義如下(/include/linux/platform_device.h):
structplatform_driver{
int(*probe)(structplatform_device*);
int(*remove)(structplatform_device*);
void(*shutdown)(structplatform_device*);
int(*suspend)(structplatform_device*,pm_message_tstate);
int(*resume)(structplatform_device*);
structdevice_driverdriver;
conststructplatform_device_id*id_table;
boolprevent_deferred_probe;
};
-
probe:當驅動與設備匹配成功以后
.probe
函數就會執行,這是一個非常重要的函數,一般驅動的提供者都會設計該函數。 -
remove:當platform驅動移除的時候,
.remove
指向的函數將執行。 - shutdown、suspend和resume:與電源管理相關的函數。
- driver:為device_driver結構體變量,相當于C++中的基類,提供了最基礎的驅動框架。plaform_driver繼承了這個基類,然后在此基礎上又添加了一些特有的成員變量。
- id_table:描述platform設備的id_table表,platform總線匹配驅動和設備的時候會使用。
-
prevent_deferred_probe:布爾類型變量(內部參數),用于防止驅動程序請求延遲
probe
,以避免進一步的徒勞的探測嘗試。
再看看platform設備的描述者struct platform_device
,定義如下(/include/linux/platform_device.h):
structplatform_device{
constchar*name;
intid;
boolid_auto;
structdevicedev;
u32num_resources;
structresource*resource;
conststructplatform_device_id*id_entry;
char*driver_override;/*Drivernametoforceamatch*/
/*MFDcellpointer*/
structmfd_cell*mfd_cell;
/*archspecificadditions*/
structpdev_archdataarchdata;
};
- name :name表示設備名字,該參數要和所使用的platform驅動的name字段相同,否則設備就無法匹配到對應的驅動。
- id:設備id。
- dev:linux內核面向對象的具體體現,用于描述platform_device的基類。
- num_resources:表示資源的數量。
-
resource:表示資源,也就是設備的信息,比如外設寄存器等。Linux內核使用
struct resource
結構體表示資源。 - id_entry:platform設備對應的id匹配表實例,在platform總線匹配驅動和設備的時候會使用到。
五、platform驅動設計
platform驅動設計的總體思路分為兩種:
- (1)使用【struct platform_device + struct platform_driver】的方式實現。
在這種實現方式中,需要實現描述設備信息的struct platform_device
結構,并需要使用platform_device
來描述具體的設備信息,然后使用platform_device_register()
函數將設備信息注冊到 Linux 內核中;如果不再使用platform了,可以通過platform_device_unregister()
函數注銷相應的platform設備。
這種方式在不支持設備樹的linux內核中使用!
- (2)使用【struct platform_driver + 設備樹】的方式來實現。
在編寫 platform 驅動的時候,首先定義一個struct platform_driver
結構體變量,然后實現結構體中的各個成員變量,重點是實現匹配方法以及probe
函數。當驅動和設備匹配成功以后.probe
函數就會執行,具體的驅動程序在 probe 函數里面編寫。當定義并初始化好 platform_driver 結構體變量以后,需要在驅動入口函數里面調用platform_driver_register()
函數向Linux內核注冊一個platform驅動。
注意,如果linux內核支持設備樹,就可以不需要再使用
struct platform_device
來描述設備,直接使用設備樹去描述設備的信息。當然,如果一定要用struct platform_device
來描述設備信息也是可以的。基于新版的linux內核的platform驅動的開發,通常是通過設備樹來描述設備信息,我們只需要實現對應的platform驅動即可。
六、代碼示例
本小節基于【struct platform_driver + 設備樹】給出一個基本的platform驅動的設計結構。
首先使用設備樹描述設備的信息:
debug_device_node{
compatible="iriczhao_debug";
pinctrl-0=<&pinctrl_usdhc2_8bit>;
pinctrl-1=<&pinctrl_usdhc2_8bit_100mhz>;
pinctrl-2=<&pinctrl_usdhc2_8bit_200mhz>;
bus-width=<8>;
non-removable;
status="okay";
};
上述代碼描述了一個名為debug_device_node
的設備節點,給出了compatible
屬性值。
platform驅動設計:
#include
#include
#include
#include
#include
#include
#include
staticintplatform_demo_probe(structplatform_device*dev)
{printk("
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
");
printk("doplatform_demo_probe
");
printk("
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
");
return0;
}
staticintplatform_demo_remove(structplatform_device*dev)
{
printk("doplatform_demo_remove
");
return0;
}
staticconststructof_device_idplatform_demo_id[]={
{.compatible="iriczhao_debug"},
{/*Sentinel*/}
};
MODULE_DEVICE_TABLE(of,platform_demo_id);
staticstructplatform_driverplatform_demo_driver={
.probe=platform_demo_probe,
.remove=platform_demo_remove,
.driver={
.name="dd",
.of_match_table=platform_demo_id,
}
};
staticint__initplatform_demo_init(void)
{
printk("doplatform_demo_init
");
returnplatform_driver_register(&platform_demo_driver);
}
staticvoid__exitplatform_demo_exit(void)
{
printk("doplatform_demo_exit
");
platform_driver_unregister(&platform_demo_driver);
}
module_init(platform_demo_init);
module_exit(platform_demo_exit);
MODULE_AUTHOR("IRIC");
MODULE_LICENSE("GPL");
以模塊方式構建上述代碼,運行后結果如下:
從上述結果可知:platform驅動和對應的設備匹配成功,且.probe
指向的函數得以執行,當模塊退出時,platform驅動將被移除,這時候.remove
指向的函數得以執行。結果符合程序預期效果!
-
Linux
+關注
關注
87文章
11414瀏覽量
212248 -
函數
+關注
關注
3文章
4363瀏覽量
63778 -
platform
+關注
關注
0文章
19瀏覽量
17519
原文標題:干貨 | 一文總結linux的platform驅動
文章出處:【微信號:嵌入式小生,微信公眾號:嵌入式小生】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
Linux的platform機制開發驅動流程是怎么樣的?
「正點原子Linux連載」第五十四章 platform設備驅動實驗(一)
「正點原子Linux連載」第五十四章 platform設備驅動實驗(二)
「正點原子Linux連載」第五十五章設備樹下的platform驅動編寫
Linux ALSA聲卡驅動之八:ASoC架構中的Platform

linux Platform設備驅動
Linux設備驅動之platform

驅動之路之platform按鍵驅動

Linux內核驅動的platform機制是怎樣的

深入解析Linux下 Platform_device 及Platform_driver

評論