0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

一文總結(jié)linux的platform驅(qū)動(dòng)

嵌入式小生 ? 來(lái)源:嵌入式小生 ? 2023-10-16 16:45 ? 次閱讀

一、簡(jiǎn)介

相關(guān)文件;

  • /include/linux/platform_device.h
  • /drivers/base/platform.c

在linux設(shè)備驅(qū)動(dòng)中,有許多沒(méi)有特定總線的外設(shè)驅(qū)動(dòng),在實(shí)際開(kāi)發(fā)中,又需要使用到總線、驅(qū)動(dòng)和設(shè)備模型這三個(gè)概念,故而linux提供了platform這個(gè)虛擬總線,掛接在platform總線上的驅(qū)動(dòng)稱為platform驅(qū)動(dòng),由struct platform_driver描述,掛接在platorm總線上的設(shè)備稱為platform設(shè)備,由struct platform_device描述。

在linux內(nèi)核的驅(qū)動(dòng)源碼中,可以看見(jiàn)很多基于platform驅(qū)動(dòng)框架的驅(qū)動(dòng)案例實(shí)現(xiàn)。

二、platform總線

在linux內(nèi)核中,使用struct bus_type描述一個(gè)總線,為了抽象出platform這個(gè)虛擬總線,其定義如下(/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總線的注冊(cè)由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;
}

該函數(shù)在linux內(nèi)核啟動(dòng)過(guò)程中,在driver_init()中被調(diào)用,從而向linux內(nèi)核注冊(cè)了platform總線。

7f22bd46-6bf9-11ee-939d-92fbcf53809c.png

三、platform設(shè)備和驅(qū)動(dòng)的匹配過(guò)程

在定義platform總線的時(shí)候就定了該總線下設(shè)備和驅(qū)動(dòng)的具體匹配過(guò)程,由platform_match()實(shí)現(xiàn):

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設(shè)備和驅(qū)動(dòng)的匹配分為了四種方式處理:

  • 1、基于設(shè)備樹(shù)的匹配方式。

struct device_driver結(jié)構(gòu)中有個(gè)名為of_match_table的成員變量,此成員變量保存著驅(qū)動(dòng)的compatible匹配表,在設(shè)備樹(shù)中的每個(gè)設(shè)備節(jié)點(diǎn)的compatible屬性會(huì)和of_match_table表中的所有成員比較,查看是否存在相同的條目,如果存在則表示設(shè)備和此驅(qū)動(dòng)匹配,設(shè)備和驅(qū)動(dòng)匹配成功以后probe函數(shù)就會(huì)執(zhí)行(這個(gè)過(guò)程是由linux設(shè)備驅(qū)動(dòng)模型中的總線去完成)。

  • 2、ACPI的匹配方式。

  • 3、id_table 匹配。

每個(gè)struct platform_driver有一個(gè)id_table成員變量,用于保存很多id信息,這些id信息存放著這個(gè)platform驅(qū)動(dòng)所支持的驅(qū)動(dòng)類型。

  • 4、比較name字段

如果第三種匹配方式的id_table不存在,就直接比較驅(qū)動(dòng)和設(shè)備的name字段是否相等,如果相等則匹配成功;反之匹配不成功。

一般設(shè)備驅(qū)動(dòng)為了兼容性都支持設(shè)備樹(shù)和無(wú)設(shè)備樹(shù)兩種匹配方式。也就是第一種匹配方式一般都會(huì)存在,第三種和第四種只要存在一種就可以,一般用的最多的還是第四種,也就是直接比較驅(qū)動(dòng)和設(shè)備的name字段,因?yàn)檫@種方式最簡(jiǎn)單了。

四、platrom驅(qū)動(dòng)和platform設(shè)備

前文已經(jīng)提到:掛接在platform總線上的驅(qū)動(dòng)稱為platform驅(qū)動(dòng),由struct platform_driver描述,掛接在platorm總線上的設(shè)備稱為platform設(shè)備,由struct platform_device描述。要想開(kāi)發(fā)基于platform設(shè)備驅(qū)動(dòng)驅(qū)動(dòng)框架的驅(qū)動(dòng)程序,一定離不開(kāi)這兩個(gè)數(shù)據(jù)結(jié)構(gòu)。首先來(lái)看看platform驅(qū)動(dòng)的描述者struct platform_driver,該結(jié)構(gòu)定義如下(/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:當(dāng)驅(qū)動(dòng)與設(shè)備匹配成功以后.probe函數(shù)就會(huì)執(zhí)行,這是一個(gè)非常重要的函數(shù),一般驅(qū)動(dòng)的提供者都會(huì)設(shè)計(jì)該函數(shù)。
  • remove:當(dāng)platform驅(qū)動(dòng)移除的時(shí)候,.remove指向的函數(shù)將執(zhí)行。
  • shutdown、suspend和resume:與電源管理相關(guān)的函數(shù)。
  • driver:為device_driver結(jié)構(gòu)體變量,相當(dāng)于C++中的基類,提供了最基礎(chǔ)的驅(qū)動(dòng)框架。plaform_driver繼承了這個(gè)基類,然后在此基礎(chǔ)上又添加了一些特有的成員變量。
  • id_table:描述platform設(shè)備的id_table表,platform總線匹配驅(qū)動(dòng)和設(shè)備的時(shí)候會(huì)使用。
  • prevent_deferred_probe:布爾類型變量(內(nèi)部參數(shù)),用于防止驅(qū)動(dòng)程序請(qǐng)求延遲probe,以避免進(jìn)一步的徒勞的探測(cè)嘗試。

再看看platform設(shè)備的描述者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表示設(shè)備名字,該參數(shù)要和所使用的platform驅(qū)動(dòng)的name字段相同,否則設(shè)備就無(wú)法匹配到對(duì)應(yīng)的驅(qū)動(dòng)。
  • id:設(shè)備id。
  • dev:linux內(nèi)核面向?qū)ο蟮木唧w體現(xiàn),用于描述platform_device的基類。
  • num_resources:表示資源的數(shù)量。
  • resource:表示資源,也就是設(shè)備的信息,比如外設(shè)寄存器等。Linux內(nèi)核使用struct resource結(jié)構(gòu)體表示資源。
  • id_entry:platform設(shè)備對(duì)應(yīng)的id匹配表實(shí)例,在platform總線匹配驅(qū)動(dòng)和設(shè)備的時(shí)候會(huì)使用到。

五、platform驅(qū)動(dòng)設(shè)計(jì)

platform驅(qū)動(dòng)設(shè)計(jì)的總體思路分為兩種:

  • (1)使用【struct platform_device + struct platform_driver】的方式實(shí)現(xiàn)。

在這種實(shí)現(xiàn)方式中,需要實(shí)現(xiàn)描述設(shè)備信息的struct platform_device結(jié)構(gòu),并需要使用platform_device來(lái)描述具體的設(shè)備信息,然后使用platform_device_register()函數(shù)將設(shè)備信息注冊(cè)到 Linux 內(nèi)核中;如果不再使用platform了,可以通過(guò)platform_device_unregister()函數(shù)注銷相應(yīng)的platform設(shè)備。

這種方式在不支持設(shè)備樹(shù)的linux內(nèi)核中使用!

  • (2)使用【struct platform_driver + 設(shè)備樹(shù)】的方式來(lái)實(shí)現(xiàn)。

在編寫 platform 驅(qū)動(dòng)的時(shí)候,首先定義一個(gè)struct platform_driver結(jié)構(gòu)體變量,然后實(shí)現(xiàn)結(jié)構(gòu)體中的各個(gè)成員變量,重點(diǎn)是實(shí)現(xiàn)匹配方法以及probe 函數(shù)。當(dāng)驅(qū)動(dòng)和設(shè)備匹配成功以后.probe函數(shù)就會(huì)執(zhí)行,具體的驅(qū)動(dòng)程序在 probe 函數(shù)里面編寫。當(dāng)定義并初始化好 platform_driver 結(jié)構(gòu)體變量以后,需要在驅(qū)動(dòng)入口函數(shù)里面調(diào)用platform_driver_register()函數(shù)向Linux內(nèi)核注冊(cè)一個(gè)platform驅(qū)動(dòng)。

注意,如果linux內(nèi)核支持設(shè)備樹(shù),就可以不需要再使用struct platform_device來(lái)描述設(shè)備,直接使用設(shè)備樹(shù)去描述設(shè)備的信息。當(dāng)然,如果一定要用struct platform_device來(lái)描述設(shè)備信息也是可以的。基于新版的linux內(nèi)核的platform驅(qū)動(dòng)的開(kāi)發(fā),通常是通過(guò)設(shè)備樹(shù)來(lái)描述設(shè)備信息,我們只需要實(shí)現(xiàn)對(duì)應(yīng)的platform驅(qū)動(dòng)即可。

六、代碼示例

本小節(jié)基于【struct platform_driver + 設(shè)備樹(shù)】給出一個(gè)基本的platform驅(qū)動(dòng)的設(shè)計(jì)結(jié)構(gòu)。

首先使用設(shè)備樹(shù)描述設(shè)備的信息:

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";
};

上述代碼描述了一個(gè)名為debug_device_node的設(shè)備節(jié)點(diǎn),給出了compatible屬性值。

platform驅(qū)動(dòng)設(shè)計(jì):

#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");

以模塊方式構(gòu)建上述代碼,運(yùn)行后結(jié)果如下:

7f3a1f72-6bf9-11ee-939d-92fbcf53809c.png

從上述結(jié)果可知:platform驅(qū)動(dòng)和對(duì)應(yīng)的設(shè)備匹配成功,且.probe指向的函數(shù)得以執(zhí)行,當(dāng)模塊退出時(shí),platform驅(qū)動(dòng)將被移除,這時(shí)候.remove指向的函數(shù)得以執(zhí)行。結(jié)果符合程序預(yù)期效果!


聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • Linux
    +關(guān)注

    關(guān)注

    87

    文章

    11304

    瀏覽量

    209523
  • 函數(shù)
    +關(guān)注

    關(guān)注

    3

    文章

    4331

    瀏覽量

    62622
  • platform
    +關(guān)注

    關(guān)注

    0

    文章

    19

    瀏覽量

    17406

原文標(biāo)題:干貨 | 一文總結(jié)linux的platform驅(qū)動(dòng)

文章出處:【微信號(hào):嵌入式小生,微信公眾號(hào):嵌入式小生】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏

    評(píng)論

    相關(guān)推薦

    Linuxplatform機(jī)制開(kāi)發(fā)驅(qū)動(dòng)流程是怎么樣的?

    Linux 2.6起引入了套新的驅(qū)動(dòng)管理和注冊(cè)機(jī)制:platform_device和platform_driver。
    發(fā)表于 09-23 07:31

    「正點(diǎn)原子Linux連載」第五十四章 platform設(shè)備驅(qū)動(dòng)實(shí)驗(yàn)(

    ,在這個(gè)思路下誕生了我們將來(lái)最常打交道的platform設(shè)備驅(qū)動(dòng),也叫做平臺(tái)設(shè)備驅(qū)動(dòng)。本章我們就來(lái)學(xué)習(xí)Linux下的
    發(fā)表于 03-21 10:01

    「正點(diǎn)原子Linux連載」第五十四章 platform設(shè)備驅(qū)動(dòng)實(shí)驗(yàn)(二)

    IMX6U-ALPHA開(kāi)發(fā)板上的LED燈,因此實(shí)驗(yàn)硬件原理圖參考8.3小節(jié)即可。54.4試驗(yàn)程序編寫本實(shí)驗(yàn)對(duì)應(yīng)的例程路徑為:開(kāi)發(fā)板光盤->2、Linux驅(qū)動(dòng)例程->17_platform。本章實(shí)驗(yàn)我們
    發(fā)表于 03-21 10:02

    「正點(diǎn)原子Linux連載」第五十五章設(shè)備樹(shù)下的platform驅(qū)動(dòng)編寫

    1)實(shí)驗(yàn)平臺(tái):正點(diǎn)原子Linux開(kāi)發(fā)板2)摘自《正點(diǎn)原子I.MX6U嵌入式Linux驅(qū)動(dòng)開(kāi)發(fā)指南》關(guān)注官方微信號(hào)公眾號(hào),獲取更多資料:正點(diǎn)原子第五十五章設(shè)備樹(shù)下的platform
    發(fā)表于 03-21 10:03

    Linux驅(qū)動(dòng)之基本理論常識(shí)總結(jié)

    0 引言前面Linux專題中關(guān)于Linux下系統(tǒng)編程總結(jié)了17篇博,主要是為了提高Linux下的C編程應(yīng)用能力,熟悉
    發(fā)表于 07-01 10:38

    Linux之leds_platform教程

    Linux之leds_platform教程,很好的Linux自學(xué)資料,快來(lái)學(xué)習(xí)吧。
    發(fā)表于 04-15 17:59 ?9次下載

    LCD驅(qū)動(dòng)總結(jié)

    介紹了基于LINUX的LCD驅(qū)動(dòng)總結(jié),很詳細(xì)。是我在實(shí)際項(xiàng)目中所做的。
    發(fā)表于 06-20 17:48 ?13次下載

    Linux ALSA聲卡驅(qū)動(dòng)之八:ASoC架構(gòu)中的Platform

    前面幾章內(nèi)容已經(jīng)說(shuō)過(guò),ASoC被分為Machine,Platform和Codec三大部件,Platform驅(qū)動(dòng)的主要作用是完成音頻數(shù)據(jù)的管理,最終通過(guò)CPU的數(shù)字音頻接口(DAI)把音頻數(shù)據(jù)傳送給Codec進(jìn)行處理,最終由Cod
    發(fā)表于 05-06 17:39 ?2017次閱讀
    <b class='flag-5'>Linux</b> ALSA聲卡<b class='flag-5'>驅(qū)動(dòng)</b>之八:ASoC架構(gòu)中的<b class='flag-5'>Platform</b>

    linux Platform設(shè)備驅(qū)動(dòng)

    個(gè)現(xiàn)實(shí)的Linux設(shè)備和驅(qū)動(dòng)通常都需要掛接在種總線上,對(duì)于本身依附于PCI、USB、I2C、SPI等的設(shè)備而言,這自然不是問(wèn)題, 但是在嵌入式系統(tǒng)里面,SoC系統(tǒng)中集成的獨(dú)立
    發(fā)表于 05-10 14:18 ?2025次閱讀

    Linux設(shè)備驅(qū)動(dòng)platform

    根據(jù)Linux設(shè)備模型可知,個(gè)現(xiàn)實(shí)的Linux設(shè)備和驅(qū)動(dòng)通常都需要掛接在種總線上,對(duì)于本身依附于PCI、USB等的設(shè)備而言,這自然不是問(wèn)
    發(fā)表于 05-13 11:43 ?1080次閱讀
    <b class='flag-5'>Linux</b>設(shè)備<b class='flag-5'>驅(qū)動(dòng)</b>之<b class='flag-5'>platform</b>

    驅(qū)動(dòng)之路之platform按鍵驅(qū)動(dòng)

    Linux 2.6起引入了套新的驅(qū)動(dòng)管理和注冊(cè)機(jī)制,platform_device和platform_driver,
    發(fā)表于 05-15 17:14 ?1045次閱讀
    <b class='flag-5'>驅(qū)動(dòng)</b>之路之<b class='flag-5'>platform</b>按鍵<b class='flag-5'>驅(qū)動(dòng)</b>

    Linux內(nèi)核驅(qū)動(dòng)platform機(jī)制是怎樣的

    Linux 2.6起引入了套新的驅(qū)動(dòng)管理和注冊(cè)機(jī)制:platform_device和platform_driver。
    發(fā)表于 11-06 14:12 ?1636次閱讀
    <b class='flag-5'>Linux</b>內(nèi)核<b class='flag-5'>驅(qū)動(dòng)</b>的<b class='flag-5'>platform</b>機(jī)制是怎樣的

    Linux驅(qū)動(dòng)中的platform總線詳解

    platform總線是學(xué)習(xí)linux驅(qū)動(dòng)必須要掌握的個(gè)知識(shí)點(diǎn)。 、概念 嵌入式系統(tǒng)中有很多的物理總線:I2c、SPI、USB、uart、
    的頭像 發(fā)表于 02-26 14:02 ?4090次閱讀
    <b class='flag-5'>Linux</b><b class='flag-5'>驅(qū)動(dòng)</b>中的<b class='flag-5'>platform</b>總線詳解

    深入解析LinuxPlatform_device 及Platform_driver

    [導(dǎo)讀] 前文分析了Linux設(shè)備驅(qū)動(dòng)驅(qū)動(dòng)模型,本文來(lái)聊聊Platform_driver/Platform_device這個(gè)類。做嵌入式
    發(fā)表于 02-07 10:10 ?11次下載
    深入解析<b class='flag-5'>Linux</b>下 <b class='flag-5'>Platform</b>_device 及<b class='flag-5'>Platform</b>_driver

    Linux內(nèi)核中現(xiàn)存的所有platform_device

    platform_device,證明其來(lái)源于 dtb。 note:/proc/device-tree 是鏈接文件, 指向 /sys/firmware/devicetree/base 以上是 Linux 原生的節(jié)點(diǎn),可以供我們使用。如果你用的芯片是某個(gè)廠家,這個(gè)廠家客制
    的頭像 發(fā)表于 07-30 15:28 ?1039次閱讀