<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      嵌入式Linux中的LED驅(qū)動(dòng)控制(設(shè)備樹方式)(續(xù))

      嵌入式Linux中的LED驅(qū)動(dòng)控制(設(shè)備樹方式)”一文通過設(shè)備樹方式實(shí)現(xiàn)了在野火STM32MP157開發(fā)板上對三個(gè)LED燈的控制,這里來討論一下設(shè)備樹的原理。

      設(shè)備樹用于描述一個(gè)硬件平臺(tái)的硬件資源,它經(jīng)由bootloader傳遞到內(nèi)核,內(nèi)核就可從設(shè)備樹中獲取到硬件信息。設(shè)備樹描述硬件資源時(shí)有兩個(gè)特點(diǎn),其一,設(shè)備樹以“樹狀”結(jié)構(gòu)來描述硬件資源。其二,設(shè)備樹可以像頭文件那樣,一個(gè)設(shè)備樹文件可以包含(引用)另外一個(gè)設(shè)備樹文件,以實(shí)現(xiàn)設(shè)備樹內(nèi)容的共享重用。

      設(shè)備樹的代碼是一種基于文本描述的形式,其源碼文件以.dts為擴(kuò)展名,一般一個(gè).dts文件對應(yīng)一個(gè)硬件平臺(tái)。源碼文件一般位于Linux源碼的“/arch/arm/boot/dts”目錄下。設(shè)備樹目標(biāo)文件則以.dtb為擴(kuò)展名,是設(shè)備樹源碼經(jīng)過編譯后生成的二進(jìn)制文件,它可以直接被內(nèi)核獲取。另外,DTC是設(shè)備樹源碼的編譯工具,一般需要手動(dòng)安裝這個(gè)編譯工具。

      設(shè)備樹的源碼一般分為三個(gè)部分,即包含頭文件部分,設(shè)備樹節(jié)點(diǎn)部分和設(shè)備樹節(jié)點(diǎn)追加內(nèi)容部分。設(shè)備樹由一個(gè)根節(jié)點(diǎn)和多個(gè)子節(jié)點(diǎn)組成,子節(jié)點(diǎn)還可以繼續(xù)包含其他子節(jié)點(diǎn)。每個(gè)節(jié)點(diǎn)由一對大括號(hào)“{}”表示,而“/ {?};”表示“根節(jié)點(diǎn)”(注意最后以分號(hào)結(jié)尾),一個(gè)設(shè)備樹只允許有一個(gè)根節(jié)點(diǎn),不同文件中的根節(jié)點(diǎn)最終會(huì)合并為一個(gè)根節(jié)點(diǎn)。在根節(jié)點(diǎn)內(nèi)部會(huì)形成多個(gè)子節(jié)點(diǎn),如“aliases {?}”、“chosen{?}”、“memory {?}”等。

      設(shè)備樹中的每個(gè)節(jié)點(diǎn)都按照如下的形式約定命名。

      node-name@unit-address{
          屬性1 = ?
          屬性2 = ?
          屬性3 = ?
          子節(jié)點(diǎn)?
      };

      node-name用于指定節(jié)點(diǎn)的名稱,它的長度為1至31個(gè)字符。節(jié)點(diǎn)名應(yīng)當(dāng)使用大寫或小寫字母開頭,并且能夠描述設(shè)備類別。根節(jié)點(diǎn)沒有節(jié)點(diǎn)名,它直接使用“/”指代根節(jié)點(diǎn)。unit-address用于指定“單元地址”,它的值要和節(jié)點(diǎn)“reg”屬性的第一個(gè)地址一致。如果節(jié)點(diǎn)沒有“reg”屬性值,可以直接省略“@unit-address”部分。

      節(jié)點(diǎn)標(biāo)簽:節(jié)點(diǎn)名的簡寫,作用是當(dāng)其它位置需要引用時(shí)可以使用節(jié)點(diǎn)標(biāo)簽來向該節(jié)點(diǎn)中追加內(nèi)容。

      節(jié)點(diǎn)路徑:指從根節(jié)點(diǎn)到所需節(jié)點(diǎn)的完整路徑,可以唯一地標(biāo)識(shí)設(shè)備樹中的節(jié)點(diǎn),不同層次的設(shè)備樹節(jié)點(diǎn)名稱可以相同,同層次的設(shè)備樹節(jié)點(diǎn)名稱要唯一。

      節(jié)點(diǎn)屬性:指在節(jié)點(diǎn)“{}”之間包含的內(nèi)容,通常情況下一個(gè)節(jié)點(diǎn)有多個(gè)屬性,這些屬性信息是要傳遞到內(nèi)核的“板級(jí)硬件描述信息”,在驅(qū)動(dòng)程序中會(huì)通過一些API函數(shù)來獲取這些信息。編寫設(shè)備樹最主要的內(nèi)容就是編寫這些節(jié)點(diǎn)屬性,通常情況下一個(gè)節(jié)點(diǎn)代表一個(gè)設(shè)備。有些節(jié)點(diǎn)屬性是所有節(jié)點(diǎn)共有的,而有些屬性只作用于特定的節(jié)點(diǎn)。節(jié)點(diǎn)屬性分為標(biāo)準(zhǔn)屬性和自定義屬性,標(biāo)準(zhǔn)屬性的屬性名是固定的,自定義屬性的屬性名可按照要求自行定義。

      以下是一些重要的節(jié)點(diǎn)屬性:

      compatible屬性,其值由一個(gè)或多個(gè)字符串組成,有多個(gè)字符串時(shí)使用“,”分隔開。設(shè)備樹中每一個(gè)表示設(shè)備的節(jié)點(diǎn)都要有一個(gè)compatible屬性,compatible是系統(tǒng)用來決定綁定設(shè)備驅(qū)動(dòng)的關(guān)鍵。compatible屬性也是用來查找節(jié)點(diǎn)的方法之一(另外還可以通過節(jié)點(diǎn)名或節(jié)點(diǎn)路徑查找指定節(jié)點(diǎn))。例如,在系統(tǒng)初始化platform總線上的設(shè)備時(shí),會(huì)根據(jù)設(shè)備節(jié)點(diǎn)的”compatible”屬性與驅(qū)動(dòng)of_match_table中對應(yīng)的compatible值進(jìn)行匹配,匹配成功就加載對應(yīng)的驅(qū)動(dòng)。

      status屬性,用于指示設(shè)備的“操作狀態(tài)”,通過status可以禁止設(shè)備(disabled)或啟用設(shè)備(okay),默認(rèn)情況下status屬性設(shè)備是使能的。

      reg屬性,描述設(shè)備資源在其父總線定義的地址空間內(nèi)的地址,通常情況下用于表示一塊寄存器的起始地址(偏移地址)和長度,在特定情況下也會(huì)有不同的含義。reg屬性值由一串?dāng)?shù)字組成,ret屬性的書寫格式為reg = < cells cells cells cells cells cells?>,長度根據(jù)實(shí)際情況而定,這些數(shù)據(jù)分為地址數(shù)據(jù)(地址字段),長度數(shù)據(jù)(大小字段),例如reg = <0x900000 0x4000>,其中0x9000000表示的是地址,0x4000表示的是地址長度,這里的reg屬性指定了起始地址為0x9000000,長度為0x4000 的一塊地址空間。

      #address-cells和#size-cells屬性要同時(shí)存在,它們用在有子節(jié)點(diǎn)的設(shè)備節(jié)點(diǎn),用于設(shè)置子節(jié)點(diǎn)的“reg”屬性的“格式”。#address-cells用于指定子節(jié)點(diǎn)reg屬性“地址字段”所占的長度(單元格cells 的個(gè)數(shù))。#size-cells用于指定子節(jié)點(diǎn)reg 屬性“大小字段”所占的長度(單元格cells 的個(gè)數(shù))。例如像reg = <0x9000000 x4000>這樣的形式,應(yīng)該設(shè)置成#address-cells = <1>,#address-cells = <1>。

      model屬性,用于指定設(shè)備的制造商和型號(hào),推薦使用“制造商, 型號(hào)”的格式,也可以自定義。該屬性為非必要屬性。

      ranges屬性,提供了子節(jié)點(diǎn)地址空間和父地址空間的映射(轉(zhuǎn)換)方法,常見格式是ranges = < 子地址, 父地址, 轉(zhuǎn)換長度>。如果父地址空間和子地址空間相同則無需轉(zhuǎn)換,可以讓renges的內(nèi)容為空。 

      name屬性用于指定節(jié)點(diǎn)名,在舊的設(shè)備樹中它用于確定節(jié)點(diǎn)名,現(xiàn)在的設(shè)備樹已經(jīng)不用了。

      device_type屬性也是一個(gè)很少用的屬性,只用在CPU和內(nèi)存的節(jié)點(diǎn)上。

      下面來看兩類特殊的子節(jié)點(diǎn)。

      1、aliases子節(jié)點(diǎn),它的作用就是為其他節(jié)點(diǎn)起一個(gè)別名,如下面的示例。

      aliases {
        ethernet0 = &ethernet0;
        serial0 = &uart4;
        serial1 = &usart1;
        serial2 = &usart2;
        serial3 = &usart3;
      }

      以上面的“serial0 = &uart4;”為例,“serial0”是一個(gè)節(jié)點(diǎn)的名字,設(shè)置別名后可以使用“serial0”來指代uart4節(jié)點(diǎn),這與節(jié)點(diǎn)標(biāo)簽有點(diǎn)類似。在設(shè)備樹中更多的是為節(jié)點(diǎn)添加標(biāo)簽,而不太使用節(jié)點(diǎn)別名,別名的作用是為了“快速找到設(shè)備樹節(jié)點(diǎn)”。在驅(qū)動(dòng)中如果要查找一個(gè)節(jié)點(diǎn),通常情況下我們可以使用“節(jié)點(diǎn)路徑”一步步找到節(jié)點(diǎn)。也可以使用別名“一步到位”找到節(jié)點(diǎn)。

      2、chosen子節(jié)點(diǎn),它位于根節(jié)點(diǎn)下,它不代表實(shí)際硬件,主要用于給內(nèi)核傳遞參數(shù),如下面的示例。

      chosen {
        stdout-path = "serial0:115200n8";
      };

      上面只設(shè)置了“stdout-path =”serial0:115200n8”;”一條屬性,表示系統(tǒng)標(biāo)準(zhǔn)輸出stdout使用串口serial0,并指定了波特率、校驗(yàn)、位數(shù)等參數(shù)。此外,chosen節(jié)點(diǎn)還可做為uboot向Linux內(nèi)核傳遞配置參數(shù)的“通道”。

      子節(jié)點(diǎn)名稱前如果多加了一個(gè)“&”符號(hào),表示該節(jié)點(diǎn)是向已經(jīng)存在的子節(jié)點(diǎn)追加數(shù)據(jù),如“&cpu0 {?}”表示向已經(jīng)存在的cpu0這個(gè)子節(jié)點(diǎn)中追加信息。這些源碼并不一定包含在根節(jié)點(diǎn)“/{?}”內(nèi),它們本身并不是一個(gè)新的節(jié)點(diǎn),只是向原有的節(jié)點(diǎn)追加內(nèi)容,被追加的節(jié)點(diǎn)可能定義在當(dāng)前文件中,也可能定義在當(dāng)前文件所包含的其他設(shè)備樹文件中。

      以上是設(shè)備樹相關(guān)內(nèi)容的討論,接下來再討論一下與設(shè)備樹配套的平臺(tái)驅(qū)動(dòng)的相關(guān)內(nèi)容。

      在驅(qū)動(dòng)中,用一個(gè)名為device_node的結(jié)構(gòu)體來描述設(shè)備樹中的信息,該結(jié)構(gòu)體的形式如下。

      struct device_node {
        const char *name;
        const char *type;
        phandle phandle;
        const char *full_name;
        struct fwnode_handle fwnode;
        struct property *properties;
        struct property *deadprops; /* removed properties */
        struct device_node *parent;
        struct device_node *child;
        struct device_node *sibling;
        #if defined(CONFIG_OF_KOBJ)
        struct kobject kobj;
        #endif
        unsigned long _flags;
        void *data;
        #if defined(CONFIG_SPARC)
        const char *path_component_name;
        unsigned int unique_id;
        struct of_irq_controller *irq_trans;
        #endif
      };

      上述中,name為節(jié)點(diǎn)中屬性為name的值。type為節(jié)點(diǎn)中屬性為device_type的值。full_name為節(jié)點(diǎn)的名字,在device_node結(jié)構(gòu)體后面放一個(gè)字符串,full_name指向它。properties為鏈表,連接該節(jié)點(diǎn)的所有屬性。parent指向父節(jié)點(diǎn)。child指向子節(jié)點(diǎn)。sibling指向兄弟節(jié)點(diǎn)。

      驅(qū)動(dòng)如何從設(shè)備樹的設(shè)備節(jié)點(diǎn)獲取需要的數(shù)據(jù)?其實(shí)Linux內(nèi)核提供了一組用于從設(shè)備節(jié)點(diǎn)獲取資源(設(shè)備節(jié)點(diǎn)中定義的屬性)的函數(shù),這些函數(shù)均以of_ 開頭,一般稱為OF操作函數(shù)。

      1、根據(jù)節(jié)點(diǎn)路徑尋找節(jié)點(diǎn)函數(shù):struct device_node *of_find_node_by_path(const char *path),參數(shù)path指定節(jié)點(diǎn)在設(shè)備樹中的路徑。如果查找失敗則返回NULL,否則返回device_node類型的結(jié)構(gòu)體指針,它保存著設(shè)備節(jié)點(diǎn)的信息。

      2、根據(jù)節(jié)點(diǎn)名字尋找節(jié)點(diǎn)函數(shù):struct device_node *of_find_node_by_name(struct device_node *from, const char *name),參數(shù)from指定從哪個(gè)節(jié)點(diǎn)開始查找,它本身并不在查找行列中,只查找它后面的節(jié)點(diǎn),如果設(shè)置為NULL表示從根節(jié)點(diǎn)開始查找。參數(shù) name為要尋找的節(jié)點(diǎn)名。如果查找失敗則返回NULL,否則返回device_node類型的結(jié)構(gòu)體指針,它保存著設(shè)備節(jié)點(diǎn)的信息。

      3、根據(jù)節(jié)點(diǎn)類型尋找節(jié)點(diǎn)函數(shù):struct device_node *of_find_node_by_type(struct device_node *from, const char *type),參數(shù)from指定從哪個(gè)節(jié)點(diǎn)開始查找,它本身并不在查找行列中,只查找它后面的節(jié)點(diǎn),如果設(shè)置為NULL表示從根節(jié)點(diǎn)開始查找。參數(shù)type為要查找節(jié)點(diǎn)的類型,這個(gè)類型就是device_node-> type。返回值為device_node類型的結(jié)構(gòu)體指針,保存獲取得到的節(jié)點(diǎn)。同樣,如果失敗返回NULL。

      4、根據(jù)節(jié)點(diǎn)類型及compatible屬性尋找節(jié)點(diǎn)函數(shù):struct device_node *of_find_compatible_node(struct device_node from, const char *type, const char *compatible),參數(shù)from指定從哪個(gè)節(jié)點(diǎn)開始查找,它本身并不在查找行列中,只查找它后面的節(jié)點(diǎn),如果設(shè)置為NULL表示從根節(jié)點(diǎn)開始查找。參數(shù)type為要查找節(jié)點(diǎn)的類型,這個(gè)類型就是device_node-> type。參數(shù)compatible為要查找節(jié)點(diǎn)的compatible屬性,相比of_find_node_by_type函數(shù)增加了一個(gè)compatible屬性作為篩選條件。返回值為device_node類型的結(jié)構(gòu)體指針,保存獲取得到的節(jié)點(diǎn)。同樣,如果失敗返回NULL。

      5、根據(jù)匹配表尋找節(jié)點(diǎn)函數(shù):static inline struct device_node *of_find_matching_node_and_match(struct device_node *from, const struct of_device_id *matches, const struct of_device_id **match),參數(shù)from指定從哪個(gè)節(jié)點(diǎn)開始查找,它本身并不在查找行列中,只查找它后面的節(jié)點(diǎn),如果設(shè)置為NULL表示從根節(jié)點(diǎn)開始查找。參數(shù)matches為源匹配表,查找與該匹配表想匹配的設(shè)備節(jié)點(diǎn)。參數(shù)of_device_id是一個(gè)結(jié)構(gòu)體,原型如下。

      struct of_device_id {
        char name[32];
        char type[32];
        char compatible[128];
        const void *data;
      };

      上述中,name為節(jié)點(diǎn)中屬性為name的值。type為節(jié)點(diǎn)中屬性為device_type的值。compatible為節(jié)點(diǎn)的名字,在device_node結(jié)構(gòu)體后面放一個(gè)字符串,full_name指向它。data為鏈表,連接該節(jié)點(diǎn)的所有屬性該函數(shù)的返回值為device_node類型的結(jié)構(gòu)體指針,保存獲取得到的節(jié)點(diǎn)。同樣,如果失敗返回NULL。

      6、查找父節(jié)點(diǎn)函數(shù):struct device_node *of_get_parent(const struct device_node *node),參數(shù)node指定要查找哪個(gè)節(jié)點(diǎn)的父節(jié)點(diǎn)。返回值為device_node類型的結(jié)構(gòu)體指針,保存獲取得到的節(jié)點(diǎn)。同樣,如果失敗返回NULL。

      7、查找子節(jié)點(diǎn)函數(shù):struct device_node *of_get_next_child(const struct device_node *node, struct device_node *prev),參數(shù)node指定要查找哪個(gè)節(jié)點(diǎn)的子節(jié)點(diǎn)。參數(shù)prev為前一個(gè)子節(jié)點(diǎn),查找的是prev節(jié)點(diǎn)之后的節(jié)點(diǎn)。這是一個(gè)迭代查尋過程,例如尋找第二個(gè)子節(jié)點(diǎn),這里就要填第一個(gè)子節(jié)點(diǎn)。參數(shù)為NULL表示尋找第一個(gè)子節(jié)點(diǎn)。返回值為device_node類型的結(jié)構(gòu)體指針,保存獲取得到的節(jié)點(diǎn)。同樣,如果失敗返回NULL。

      以是7個(gè)函數(shù)有一個(gè)共同特點(diǎn),即返回值類型相同。只要找到了節(jié)點(diǎn)就會(huì)返回節(jié)點(diǎn)對應(yīng)的device_node結(jié)構(gòu)體,在驅(qū)動(dòng)程序中通過這個(gè)device_node來獲取設(shè)備節(jié)點(diǎn)的屬性信息,并查找它的父、子節(jié)點(diǎn)等等。函數(shù)of_find_node_by_path與后面六個(gè)不同,它是通過節(jié)點(diǎn)路徑尋找節(jié)點(diǎn)的,而“節(jié)點(diǎn)路徑”是從設(shè)備樹源文件(.dts) 中的到的。中間四個(gè)函數(shù)是根據(jù)節(jié)點(diǎn)屬性在某一個(gè)節(jié)點(diǎn)之后查找符合要求的設(shè)備節(jié)點(diǎn),這個(gè)“某一個(gè)節(jié)點(diǎn)”是設(shè)備節(jié)點(diǎn)結(jié)構(gòu)體(device_node),也就是說這個(gè)節(jié)點(diǎn)是已經(jīng)找到的。最后兩個(gè)函數(shù)與中間四個(gè)類似,只不過最后兩個(gè)沒有使用節(jié)點(diǎn)屬性而是根據(jù)父、子關(guān)系查找。

      下面來看節(jié)點(diǎn)屬性結(jié)構(gòu)體,名稱為property,該結(jié)構(gòu)體的形式如下。

      struct property {
        char *name;
        int length;
        void *value;
        struct property *next;
        #if defined(CONFIG_OF_DYNAMIC) || defined(CONFIG_SPARC)
        unsigned long _flags;
        #endif
        #if defined(CONFIG_OF_PROMTREE)
        unsigned int unique_id;
        #endif
        #if defined(CONFIG_OF_KOBJ)
        struct bin_attribute attr;
        #endif
      };

      上述中,name為屬性名,length為屬性長度,value為屬性值,next為下一個(gè)屬性。

      1、查找節(jié)點(diǎn)屬性函數(shù):struct property *of_find_property(const struct device_node *np, const char *name, int *lenp),參數(shù)np指定要獲取那個(gè)設(shè)備節(jié)點(diǎn)的屬性信息,參數(shù)name為屬性名,參數(shù)lenp為獲取得到的屬性值的大小,這個(gè)指針作為輸出參數(shù),這個(gè)參數(shù)被填充的值是實(shí)際獲取得到的屬性大小。返回值為property類型的結(jié)構(gòu)體指針,失敗返回NULL。從這個(gè)結(jié)構(gòu)體中可以得到想要的屬性值。

      2、讀取整型屬性函數(shù):int of_property_read_uX_array(const struct device_node *np, const char *propname, uX *out_values, size_t sz),注意這種函數(shù)一共有4個(gè)類型,以X值(8、16、32、64)不同來區(qū)分,其他都一樣。對數(shù)np指定要讀取那個(gè)設(shè)備節(jié)點(diǎn)結(jié)構(gòu)體,也就是說讀取那個(gè)設(shè)備節(jié)點(diǎn)的數(shù)據(jù)。參數(shù)propname指定要獲取設(shè)備節(jié)點(diǎn)的哪個(gè)屬性。參數(shù)out_values是一個(gè)輸出參數(shù),是函數(shù)的“返回值”,保存讀取得到的數(shù)據(jù)。參數(shù)sz是一個(gè)輸入?yún)?shù),它用于設(shè)置讀取的長度。返回值,成功返回0,錯(cuò)誤返回錯(cuò)誤狀態(tài)碼(非零值),EINVAL(屬性不存在),-ENODATA(沒有要讀取的數(shù)據(jù)),-EOVERFLOW(屬性值列表太小)。

      3、簡化后的讀取整型屬性函數(shù):int of_property_read_uX (const struct device_node *np, const char *propname, uX *out_values),這種函數(shù)也有4個(gè)類型,以X值(8、16、32、64)不同來區(qū)分,其他都一樣。

      4、讀取字符串屬性函數(shù)1:int of_property_read_string(const struct device_node *np, const char *propname, const char **out_string),參數(shù)np指定要獲取那個(gè)設(shè)備節(jié)點(diǎn)的屬性信息,參數(shù)propname為屬性名,參數(shù)out_string獲取得到字符串指針,這是一個(gè)“輸出”參數(shù),帶回一個(gè)字符串指針。也就是字符串屬性值的首地址。這個(gè)地址是“屬性值”在內(nèi)存中的真實(shí)位置,也就是說我們可以通過對地址操作獲取整個(gè)字符串屬性(一個(gè)字符串屬性可能包含多個(gè)字符串,這些字符串在內(nèi)存中連續(xù)存儲(chǔ),使用’0’分隔)。該函數(shù)成功時(shí)返回0,失敗返回時(shí)錯(cuò)誤狀態(tài)碼。

      5、讀取字符串屬性函數(shù)2:int of_property_read_string_index(const struct device_node *np, const char *propname, int index, const char **out_string),相比前面的函數(shù)增加了參數(shù)index,它用于指定讀取屬性值中第幾個(gè)字符串,index從零開始計(jì)數(shù)。第一個(gè)函數(shù)只能得到屬性值所在地址,也就是第一個(gè)字符串的地址,其他字符串需要我們手動(dòng)修改移動(dòng)地址,非常麻煩,推薦使用第2個(gè)函數(shù)。

      6、內(nèi)存映射相關(guān)of函數(shù):void __iomem *of_iomap(struct device_node *np, int index),參數(shù)np指定要獲取那個(gè)設(shè)備節(jié)點(diǎn)的屬性信息。參數(shù)index用于指定映射哪一段(reg屬性包含多段),標(biāo)號(hào)從0開始。返回值,若成功得到轉(zhuǎn)換得到的地址,失敗則返回NULL。

      7、獲取地址的of函數(shù):int of_address_to_resource(struct device_node *dev, int index, struct resource *r),參數(shù)np指定要獲取那個(gè)設(shè)備節(jié)點(diǎn)的屬性信息。參數(shù)index用于指定映射哪一段(reg屬性包含多段),標(biāo)號(hào)從0開始。參數(shù)r是一個(gè)resource結(jié)構(gòu)體指針,是“輸出參數(shù)”用于返回得到的地址信息。該函數(shù)成功返回0,失敗返回錯(cuò)誤狀態(tài)碼。

      以上就是設(shè)備樹配套的平臺(tái)驅(qū)動(dòng)的相關(guān)內(nèi)容。下面來看一下“嵌入式Linux中的LED驅(qū)動(dòng)控制(設(shè)備樹方式)”一文中的具體實(shí)現(xiàn)過程。

      先是在設(shè)備樹中加入了三個(gè)LED的節(jié)點(diǎn),如下。

      rgb_led{
              #address-cells = <1>;
              #size-cells = <1>;
              compatible = "fire,rgb_led";
              ranges;
              //紅色LED節(jié)點(diǎn)
              led_red@0x50002000{
                  compatible = "fire,led_red";
                  reg = < 0x50002000 0x00000004
                          0x50002004 0x00000004
                          0x50002008 0x00000004
                          0x5000200C 0x00000004
                          0x50002018 0x00000004
                          0x50000A28 0x00000004 >;
                  status = "okay";
              };
              //綠色LED節(jié)點(diǎn)
              led_green@0x50008000{
                  compatible = "fire,led_green";
                  reg = < 0x50008000 0x00000004
                          0x50008004 0x00000004
                          0x50008008 0x00000004
                          0x5000800C 0x00000004
                          0x50008018 0x00000004 >;
                  status = "okay";
              };
              //藍(lán)色LED節(jié)點(diǎn)
              led_blue@0x50003000{
                  compatible = "fire,led_blue";
                  reg = < 0x50003000 0x00000004
                          0x50003004 0x00000004
                          0x50003008 0x00000004
                          0x5000300C 0x00000004
                          0x50003018 0x00000004 >;
                  status = "okay";
              };
      };

      以上在設(shè)備樹的根下,新建了一個(gè)名為rgb_led的節(jié)點(diǎn),然后在該節(jié)點(diǎn)內(nèi)定義了#address-cells和#size-cells屬性,即指定在后面的reg屬性中,“地址字段”和“大小字段”所占的長度均為1個(gè)字(32位)。然后定義一個(gè)compatible,用于和平臺(tái)驅(qū)動(dòng)匹配。隨后指定一個(gè)空的ranges屬性(不能省略)。最后定了紅、綠、藍(lán)3個(gè)子節(jié)點(diǎn),并給出了連接三個(gè)LED引腳的物理地址。

      在子節(jié)點(diǎn)內(nèi)部,最重要的是reg屬性。以紅色LED為例,它接在PA引腳上,其基址為0x50002000,每個(gè)寄存器的偏移量為4字節(jié)(32位)。所以,從0x50002000到0x50002018,分別表示了PA端口MODER、OTYPER、OSPEEDR、PUPDR、BSRR四個(gè)寄存器的地址(寄存器的具體內(nèi)容可參看“嵌入式Linux中的LED驅(qū)動(dòng)控制(續(xù))”一文) 。最后一個(gè)地址0x50000A28則表示端口時(shí)鐘管理寄存器RCC_MP_AHB4ENSETR,它只用設(shè)置一次,所以在后面的綠、藍(lán)子節(jié)點(diǎn)中并沒有設(shè)這個(gè)地址。每個(gè)子節(jié)點(diǎn)的地址要與reg屬性中的第一個(gè)值一致。最后,三個(gè)子節(jié)點(diǎn)中,都設(shè)置了status狀態(tài)為啟用。

      接下來看平臺(tái)驅(qū)動(dòng),在驅(qū)動(dòng)程序的入口函數(shù)中,向內(nèi)核注冊了一個(gè)platform_driver結(jié)構(gòu)體,名稱為led_platform_driver(有關(guān)platform平臺(tái)的討論可參看“嵌入式Linux中platform平臺(tái)設(shè)備模型的框架(實(shí)現(xiàn)LED驅(qū)動(dòng))”一文)。在該結(jié)構(gòu)體的driver成員中,指定了匹配表of_match_table為一個(gè)of_device_id型結(jié)構(gòu)體,名為rgb_led[],在rgb_led[]中定義了一個(gè)compatible成員,它的值與設(shè)備樹中rgb_led節(jié)點(diǎn)下的compatible屬性值要一致,匹配成功會(huì)觸發(fā)led_pdrv_probe函數(shù)執(zhí)行。

      在led_pdrv_probe函數(shù)中,先調(diào)用of_find_node_by_path("/rgb_led")在設(shè)備樹中查找rgb_led節(jié)點(diǎn),找到后把該節(jié)點(diǎn)信息賦值給rgb_led_device_node。然后通過rgb_led_device_node節(jié)點(diǎn),再繼續(xù)調(diào)用of_find_node_by_name函數(shù)查找紅、綠、藍(lán)3個(gè)子節(jié)點(diǎn),找到后賦值給相應(yīng)的device_node變量。然后通過調(diào)用of_iomap函數(shù)把找到的設(shè)備子節(jié)點(diǎn)中的地址與相應(yīng)的寄存器變量映射起來。接下來的做法就和“嵌入式Linux中platform平臺(tái)設(shè)備模型的框架(實(shí)現(xiàn)LED驅(qū)動(dòng))”一文中基本一樣了,只不過解除映射放在了led_pdrv_remove函數(shù)中來進(jìn)行。

      posted @ 2024-07-10 23:56  fxzq  閱讀(331)  評(píng)論(0)    收藏  舉報(bào)
      主站蜘蛛池模板: 梧州市| 亚洲精品尤物av在线网站| 国偷自产一区二区三区在线视频| 午夜精品福利亚洲国产| 日韩精品人妻中文字幕| 中文字幕久久六月色综合| 无码专区 人妻系列 在线| 欧美人成在线播放网站免费| 亚洲av免费成人在线| 免费无码一区无码东京热| 欧美老少配性行为| 无码人妻丰满熟妇片毛片| 欧美片内射欧美美美妇| 老司机午夜精品视频资源| 日韩精品一区二区三区激情视频| 中国亚州女人69内射少妇| 日韩精品毛片一区到三区| 国产精品女在线观看| av中文字幕在线二区| 国产欧美日韩高清在线不卡| 亚洲国产成人资源在线| 精品国产乱码久久久久久婷婷| 国模肉肉视频一区二区三区| 日韩大片看一区二区三区| 欧洲性开放老太大| 又粗又大又黄又硬又爽免费看| a级国产乱理伦片在线观看al | 国产精品亚洲综合第一页| A级毛片100部免费看| 实拍女处破www免费看| 视频一区二区不中文字幕| 欧美熟妇乱子伦XX视频| 伊在人间香蕉最新视频| 国产精品自拍实拍在线看| 国产成人无码久久久精品一| 亚洲人成人日韩中文字幕| 婷婷久久香蕉五月综合加勒比| 野花社区在线观看视频| 无码人妻一区二区三区AV| 亚洲精品无码人妻无码| 亚洲精品美女一区二区|