色偷偷91综合久久噜噜-色偷偷成人-色偷偷尼玛图亚洲综合-色偷偷人人澡久久天天-国内精品视频一区-国内精品视频一区二区三区

Hello! 歡迎來到小浪云!


Linux 設(shè)備樹 devicetree(DTS)入門


avatar
小浪云 2025-01-06 153

ARM devicetree的來源

在過去的arm linux中,存在大量的冗余代碼。這些設(shè)備代碼與特定公司的單板啟動或運行細節(jié)緊密耦合,無法被重用或移植。同時,內(nèi)核缺乏引導(dǎo)標準,導(dǎo)致代碼不斷膨脹。最終,由于tony lindgren向linus發(fā)送了一封郵件,請求提交omap平臺代碼的修改,并附上了修改內(nèi)容以及如何解決合并沖突的方法,使得linus怒不可遏地抱怨道:“該死。伙計們,這整個arm的事情真是個討厭的麻煩。”(linus對arm的代碼肯定已經(jīng)忍耐了很久了)。

經(jīng)過討論后,對ARM平臺相關(guān)代碼做出了一些規(guī)范:

  1. ARM的核心代碼仍然存放在arch/arm目錄下;
  2. ARM SoC核心架構(gòu)代碼存放在arch/arm目錄下;
  3. ARM SoC周邊外設(shè)模塊的驅(qū)動存放在drivers目錄下;
  4. ARM SoC特定的代碼存放在arch/arm/mach-xxx目錄下;
  5. ARM SoC板級特定的代碼被移除,由Device Tree機制來傳遞硬件拓撲和硬件資源信息。

從本質(zhì)上講,Device Tree改變了以前將硬件設(shè)備配置信息硬編碼到內(nèi)核代碼中的方式,改為使用引導(dǎo)加載程序傳遞一個描述性的數(shù)據(jù)結(jié)構(gòu)

DTS知識介紹

Arm系統(tǒng)啟動,硬件設(shè)備可以通過DTS(devicetree)或ACPI引導(dǎo)初始化,這里只講DTS方式,ACPI是由BIOS配置。

Linux 設(shè)備樹 devicetree(DTS)入門

如上圖,一般來說,arm內(nèi)核通過dts引導(dǎo)啟動,需要內(nèi)核Image、dtb和Filesystem,其中dtb是由dts通過dtc工具生成,里面包括初始化設(shè)備的硬件信息。內(nèi)核Image啟動過程中會解析dtb中內(nèi)容,并根據(jù)信息初始化設(shè)備平臺。這里提一句,dts由雖然由用戶配置,但是配置必須與硬件信息相匹配,否則會出現(xiàn)初始化失敗或設(shè)備部分功能不正常的問題。

DTS描述

Device Tree由一系列被命名的結(jié)點(node)和屬性(Property)組成,而結(jié)點本身可包含子結(jié)點。所謂屬性,其實就是成對出現(xiàn)的name和value。在Device Tree中,可描述的信息包括(原先這些信息大多被hard code到kernel中),CPU的數(shù)量和類別、內(nèi)存基地址和大、timer時鐘、外設(shè)連接、中斷配置、串口等。內(nèi)核在啟動過程中會解析每個node的硬件配置信息,根據(jù)這些信息初始化設(shè)備。

舉例,如下是arm gicv3中斷控制器的節(jié)點配置信息(來源Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.txt):

gic:?interrupt-controller@2cf00000?{ ?compatible?=?"arm,gic-v3"; ?#interrupt-cells?=?; ?#address-cells?=?; ?#size-cells?=?; ?ranges; ?interrupt-controller; ?reg?=?,??//?GICD ?,?//?GICR ?,?//?GICC ?,?//?GICH ?;??//?GICV ?interrupts?=?; ? ?msi-controller; ?mbi-ranges?=?; ? ?gic-its@2c200000?{ ?compatible?=?"arm,gic-v3-its"; ?msi-controller; ?#msi-cells?=?; ?reg?=?; ?}; ?}; 

gic: interrupt-controller@2cf00000:表示node節(jié)點信息,interrupt-controller@2cf00000是node節(jié)點的名稱,一般命名規(guī)范是 設(shè)備名@基地址或設(shè)備名,其中冒號前面gic可以看過node的“小名”,后續(xù)關(guān)聯(lián)node節(jié)點可以直接”&gic”;

{}中內(nèi)容:interrupt-controller的屬性,包括:

1)compatible = “arm,gic-v3”; compatible名稱,gicv3驅(qū)動代碼匹配”arm,gic-v3”后才會執(zhí)行初始化probe代碼;

2)#interrupt-cells = ; 表示interrupt由3部分組成,對應(yīng)interrupts = ,分別是中斷類型(1表示PPI),中斷號9和中斷觸發(fā)方式(4表示上升沿觸發(fā));

3)#address-cells = ;

#size-cells = ; 表示地址信息用64位表示,比如reg = 表示GICD的基地址是0x02f000000(其中0x是高32bit,0x2f000000是低32bit),size是0x10000;

4)msi-controller; 表示msi,此字符串含義可以具體查看驅(qū)動代碼,驅(qū)動會get到這個字符串,然后做判斷,有會走A,沒有就跳過。

5)gic-its@2c200000 表示its節(jié)點的配置,gic-v3引入了its來接收SPI中斷;

如上,便是dts的基本配置,更加詳細的介紹可以參考linux內(nèi)核源碼:Documentation/devicetree/,每個硬件設(shè)備配置格式和屬性都有描述。

重要點

一般來說,linux菜鳥級別只要會看dts即可,Linux驅(qū)動開發(fā)才需要掌握dts的每行含義,因為任一行出錯,都可能導(dǎo)致驅(qū)動某項功能失效。下面我列一些經(jīng)常遇到的問題:

1.dts和dtb如何轉(zhuǎn)換

內(nèi)核源碼下scripts/dtc/dtc,dtc工具只有內(nèi)核編譯時才會編譯,所以如果希望得到,先編譯一遍內(nèi)核即可。

轉(zhuǎn)換命令:

dts轉(zhuǎn)dtb:dtc –I dts –O dtb test.dts –o test.dtb

dtb轉(zhuǎn)dts: dtc –I dtb –O dts test.dtb –o test.dts

2.dts中node節(jié)點如何查看,每行又是什么意義

這個問題經(jīng)常遇到,不知道設(shè)備節(jié)點配置的意義,其實每個配置都可以根據(jù)compatible在Documentation/devicetree/中查到說明,只是不搞內(nèi)核不知道這個方法,比如dts中看到:

v2m_serial0:?uart@090000?{ ??compatible?=?"arm,pl011",?"arm,primecell"; ?reg?=?; ?interrupts?=?; ?clocks?=?,?; ?clock-names?=?"uartclk",?"apb_pclk"; ?}; 

到linux內(nèi)核源碼運行:

cuibixuan@ubuntu:~/git/linux/Documentation/devicetree/bindings$?cd?Documentation/devicetree/bindings/ cuibixuan@ubuntu:~/git/linux/Documentation/devicetree/bindings$?grep?"arm,pl011"?-rn?* clock/hi3660-clock.txt:41:?compatible?=?"arm,pl011",?"arm,primecell"; clock/hi3670-clock.txt:37:?compatible?=?"arm,pl011",?"arm,primecell"; clock/lsi,axm5516-clks.txt:22:?compatible?=?"arm,pl011",?"arm,primecell"; clock/hix5hd2-clock.txt:25:?compatible?=?"arm,pl011",?"arm,primecell"; dma/ste-dma40.txt:130:?compatible?=?"arm,pl011",?"arm,primecell"; dma/snps-dma.txt:65:?compatible?=?"arm,pl011",?"arm,primecell"; pinctrl/axis,artpec6-pinctrl.txt:71:?compatible?=?"arm,pl011",?"arm,primecell"; pinctrl/axis,artpec6-pinctrl.txt:80:?compatible?=?"arm,pl011",?"arm,primecell"; pinctrl/ste,nomadik.txt:141:?compatible?=?"arm,pl011",?"arm,primecell"; serial/pl011.txt:4:-?compatible:?must?be?"arm,primecell",?"arm,pl011",?"zte,zx296702-uart" serial/pl011.txt:44:?compatible?=?"arm,pl011",?"arm,primecell"; vim?serial/pl011.txt 

如下圖,有說明,有舉例,很清晰

Linux 設(shè)備樹 devicetree(DTS)入門

如果還不懂,或者找不到,那么恭喜你,你要看驅(qū)動代碼了

cuibixuan@ubuntu:~/git/linux$?cd?drivers/tty/serial/ cuibixuan@ubuntu:~/git/linux/drivers/tty/serial$?grep?"arm,pl011"?-rn?* amba-pl011.c:2473:OF_EARLYCON_DECLARE(pl011,?"arm,pl011",?pl011_early_console_setup); 

3.內(nèi)核初始化設(shè)備驅(qū)動,根據(jù)compatible來決定是否初始化

compatible的字符串,是驅(qū)動匹配的關(guān)鍵,如果匹配不到,那么就不會初始化。這點設(shè)計非常棒,在編譯Image完畢后,用戶還可以根據(jù)dts選配啟動哪些硬件。

一直有人有疑問,既然內(nèi)核都有config選項來決定了,為什么還要dts來再加一道門禁呢。你可以設(shè)想下,如果內(nèi)核啟動配置了哪些config就初始化哪些功能,那么啟動要多么繁瑣呀,大部分都是你不知道的功能都在啟動,萬一失敗了,還得查看哪里問題,至少編譯一次內(nèi)核。尤其是嵌入式設(shè)備,要精簡,更要達到“我只關(guān)心我配置的設(shè)備”的目的。

好了扯遠了,以上面串口驅(qū)動代碼舉例(提示:驅(qū)動代碼的開頭是probe函數(shù),一般翻到代碼底部即可,上面都是功能的實現(xiàn)),

static?const?Struct?of_device_id?sbsa_uart_of_match[]?=?{ ?{?.compatible?=?"arm,sbsa-uart",?}, ?{}, }; MODULE_DEVICE_TABLE(of,?sbsa_uart_of_match); ? static?struct?platform_driver?arm_sbsa_uart_platform_driver?=?{ ?.probe?=?sbsa_uart_probe, ?.remove??=?sbsa_uart_remove, ?.driver?=?{ ?.name?=?"sbsa-uart", ?.of_match_table?=?of_match_ptr(sbsa_uart_of_match), ?.acpi_match_table?=?ACPI_PTR(sbsa_uart_acpi_match), ?.suppress_bind_attrs?=?IS_BUILTIN(CONFIG_SERIAL_AMBA_PL011), ?}, }; ? … ? static?int?__init?pl011_init(void) { ?printk(KERN_INFO?"Serial:?AMBA?PL011?UART?driver "); ? ?if?(platform_driver_register(&arm_sbsa_uart_platform_driver)) ?pr_warn("could?not?register?SBSA?UART?platform?driver "); ?return?amba_driver_register(&pl011_driver); } 

內(nèi)核通過platform_driver_register()來注冊設(shè)備,arm_sbsa_uart_platform_driver是初始化成struct platform_driver的結(jié)構(gòu)體結(jié)構(gòu)體指定了設(shè)備的probe,remove等鉤子函數(shù),.driver記錄設(shè)備的name,.compatible = “arm,sbsa-uart”(of_match_table來匹配),這里多提一句,.of_match_table是dts啟動匹配字符串”arm,sbsa-uart”,.acpi_match_table是ACPI啟動匹配PTR。

如上,如果dts中node節(jié)點有compatible帶”arm,sbsa-uart”,那么就會執(zhí)行指定的鉤子函數(shù).probe = sbsa_uart_probe,函數(shù)再進行node節(jié)點其他參數(shù)的解析(說是解析,就是get字符串或數(shù)值,在進行對應(yīng)初始化或讀寫寄存器)。

4.reg=和interrupts=里面數(shù)值代表什么?

reg和interrupt數(shù)值都有具體的含義,上文提到:

#interrupt-cells = ; 表示interrupt由3部分組成,對應(yīng)interrupts = ,分別是中斷類型(1表示PPI),中斷號9和中斷觸發(fā)方式(4表示高電平觸發(fā));

這里再補充一下:

interrupts = ,分別是

中斷類型:0表示SPI,1表示PPI

中斷號9,其中PPI是[0-15],SPI范圍[32-1019]

中斷觸發(fā)方式:

1 = low-to-high edge triggered

2 = high-to-low edge triggered

4 = active high edge triggered

8 = active low edge triggered

恩,翻譯一下就時上升沿觸發(fā)、下降沿觸發(fā)、高電平觸發(fā)、低電平觸發(fā)。

#address-cells = ;

#size-cells = ; 表示地址信息用64位表示,比如reg = 表示GICD的基地址是0x02f000000(其中0x是高32bit,0x2f000000是第32bit),size是0x10000;

舉例, = 0x12f000000,= 0x100000001

5.dts支持include

對于可復(fù)用的描述節(jié)點,支持以include方式被多個dts包含,可放在dtsi文件,在dts中以

#include “uart.dtsi”包含使用。

dts文件:Foundation-platform.dts

默認變量

一般dts首個{}前面的信息表示全局默認變量,意思即node無特殊配置,則默認采用這里的配置

????????#address-cells?=?;?//地址長度64bit ????????#size-cells?=?;??//size長度32bit ????????model?=?"V2P-AARCH64";?//model名稱 ????????compatible?=?"arm,vexpress,v2p-aarch64",?"arm,vexpress"; ????????interrupt-parent?=?;?//中斷parent是gic 

CPU配置

????????cpus?{ ????????????????#address-cells?=?;? ????????????????#size-cells?=?;  //?配置cpu0-cpu3的信息,最終啟動4核 ????????????????cpu@0?{ ????????????????????????device_type?=?"cpu";??//設(shè)備類型:cpu ????????????????????????compatible?=?"arm,armv8";?//表示armv8的cpu ????????????????????????reg?=?;?//cpu信息 ????????????????????????enable-method?=?"spin-table";?//采用spintable方式拉起從核 ????????????????????????cpu-release-addr?=?;?//cpu初啟動的pc指針存放位置 ????????????????}; ????????????????cpu@1?{ ????????????????????????device_type?=?"cpu"; ????????????????????????compatible?=?"arm,armv8"; ????????????????????????reg?=?; ????????????????????????enable-method?=?"spin-table"; ????????????????????????cpu-release-addr?=?; ????????????????}; ????????????????cpu@2?{ ????????????????????????device_type?=?"cpu"; ????????????????????????compatible?=?"arm,armv8"; ????????????????????????reg?=?; ????????????????????????enable-method?=?"spin-table"; ????????????????????????cpu-release-addr?=?; ????????????????}; ????????????????cpu@3?{ ????????????????????????device_type?=?"cpu"; ????????????????????????compatible?=?"arm,armv8"; ????????????????????????reg?=?; ????????????????????????enable-method?=?"spin-table"; ????????????????????????cpu-release-addr?=?; ????????????????}; ????????}; 

內(nèi)存配置

????????memory@80000000?{ ????????????????device_type?=?"memory"; //此節(jié)點配置內(nèi)存,內(nèi)存2塊: //起始地址:0x80000000,?長度0x80000000; //起始地址:0x880000000,?長度0x80000000; ????????????????reg?=?; ????????}; 

中斷控制器

????????gic:?interrupt-controller@2c001000?{ //?中斷控制器使用?cortex?a15,gic ????????????????compatible?=?"arm,cortex-a15-gic"; ????????????????#interrupt-cells?=?; ????????????????#address-cells?=?; ????????????????interrupt-controller; //?GICD,GICH等信息,具體參考Documentation/devicetree/bindings/interrupt-controller/arm,gic.txt //-?reg?:?Specifies?base?physical?address(s)?and?size?of?the?GIC?registers.?The ??first?region?is?the?GIC?distributor?register?base?and?size.?The?2nd?region?is ??the?GIC?cpu?interface?register?base?and?size. ????????????????reg?=?, ??????????????????????, ??????????????????????, ??????????????????????; //?虛擬化使用,-?interrupts?:?VGIC?maintenance?interrupt. //*?GIC?virtualization?extensions?(VGIC) ????????????????interrupts?=?; ????????}; 

PMU

????????pmu?{ //?使用armv8?pmuv3 ????????????????compatible?=?"arm,armv8-pmuv3"; //?pmu的中斷配置,這段配置完畢,即可以使用arm?cpu的pmu功能 ????????????????interrupts?=?; ????????}; 

Timer:

????????timer?{ //定時器配置 ????????????????compatible?=?"arm,armv8-timer"; ????????????????interrupts?=?, ?????????????????????????????, ?????????????????????????????, ?????????????????????????????; ????????????????clock-frequency?=?; ????????}; 

串口配置

????????????????iofpga@3,00000000?{ ????????????????????????compatible?=?"arm,amba-bus",?"simple-bus"; ????????????????????????#address-cells?=?; ????????????????????????#size-cells?=?; ????????????????????????ranges?=?;  ????????????????????????sysreg@010000?{ ????????????????????????????????compatible?=?"arm,vexpress-sysreg"; ????????????????????????????????reg?=?; ????????????????????????};  ????????????????????????v2m_serial0:?uart@090000?{ ????????????????????????????????compatible?=?"arm,pl011",?"arm,primecell";?//串口驅(qū)動 ????????????????????????????????reg?=?;?//串口基地址和長度 ????????????????????????????????interrupts?=?;??//串口中斷號 ????????????????????????????????clocks?=?,?;?//串口波特率 ????????????????????????????????clock-names?=?"uartclk",?"apb_pclk"; ????????????????????????};  ????????????????????????v2m_serial1:?uart@0a0000?{ ????????????????????????????????compatible?=?"arm,pl011",?"arm,primecell"; ????????????????????????????????reg?=?; ????????????????????????????????interrupts?=?; ????????????????????????????????clocks?=?,?; ????????????????????????????????clock-names?=?"uartclk",?"apb_pclk"; ????????????????????????};  ????????????????????????v2m_serial2:?uart@0b0000?{ ????????????????????????????????compatible?=?"arm,pl011",?"arm,primecell"; ????????????????????????????????reg?=?; ????????????????????????????????interrupts?=?; ????????????????????????????????clocks?=?,?; ????????????????????????????????clock-names?=?"uartclk",?"apb_pclk"; ????????????????????????};  ????????????????????????v2m_serial3:?uart@0c0000?{ ????????????????????????????????compatible?=?"arm,pl011",?"arm,primecell"; ????????????????????????????????reg?=?; ????????????????????????????????interrupts?=?; ????????????????????????????????clocks?=?,?; ????????????????????????????????clock-names?=?"uartclk",?"apb_pclk"; ????????????????????????};  ????????????????????????virtio_block@0130000?{ ????????????????????????????????compatible?=?"virtio,mmio"; ????????????????????????????????reg?=?; ????????????????????????????????interrupts?=?; ????????????????????????}; ????????????????}; ????????};  ????????/*?chosen?*/ }; 

從device_node中獲取信息:

int?of_property_read_u8_array(const?struct?device_node?*np,?const?char?*propname,u8?*out_values,?size_t?sz); int?of_property_read_u16_array(const?struct?device_node?*np,?const?char?*propname,u16?*out_values,?size_t?sz); int?of_property_read_u32_array(const?struct?device_node?*np,?const?char?*propname,u32?*out_values,?size_t?sz); 

從設(shè)備結(jié)點np中讀取屬性名為propname,類型為8、16、32、位整型數(shù)組的屬性值,并放入out_values,sz指明了要讀取的個數(shù)。

static?inline?int?of_property_read_u8(const?struct?device_node?*np,const?char?*propname,u8?*out_value)? static?inline?int?of_property_read_u16(const?struct?device_node?*np,const?char?*propname,u8?*out_value)? static?inline?int?of_property_read_u32(const?struct?device_node?*np,const?char?*propname,u8?*out_value) 

從設(shè)備結(jié)點np中讀取屬性名為propname,類型為8、16、32位的屬性值,并放入out_values。實際上這里調(diào)用的就是sz為1的XXX_array函數(shù)。

int?of_property_read_u32_index(const?struct?device_node?*np,const?char*propname,u32?index,?u32?*out_value) 

從設(shè)備結(jié)點np中讀取屬性名為propname的屬性值中第index個u32數(shù)值給out_value

int?of_property_read_u64(conststruct?device_node?*np,?const?char?*propname,u64?*out_value) 

從設(shè)備結(jié)點np中讀取屬性名為propname,類型為64位的屬性值,并放入out_values

int?of_property_read_string(struct?device_node?*np,?const?char?*propname,const?char**out_string) 

從設(shè)備結(jié)點np中讀取屬性名為propname的字符串型屬性值

int?of_property_read_string_index(struct?device_node?*np,?const?char?*propname,intindex,?const?char?**output) 

從設(shè)備結(jié)點np中讀取屬性名為propname的字符串型屬性值數(shù)組中的第index個字符串

int?of_property_count_strings(struct?device_node?*np,?const?char?*propname) 

從設(shè)備結(jié)點np中讀取屬性名為propname的字符串型屬性值的個數(shù)

unsigned?int?irq_of_parse_and_map(struct?device_node?*dev,?int?index) 

從設(shè)備節(jié)點dev中讀取第index個irq號

int?of_irq_to_Resource(struct?device_node?*dev,?int?index,?struct?resource?*r) 

從設(shè)備節(jié)點dev中讀取第index個irq號,并填充一個irq資源結(jié)構(gòu)體

int?of_irq_count(struct?device_node?*dev) 

獲取設(shè)備節(jié)點dev的irq個數(shù)

static?inline?bool?of_property_read_bool(const?struct?device_node?*np,const?char?*propname); 

如果設(shè)備結(jié)點np含有propname屬性,則返回true,否則返回false。一般用于檢查空屬性是否存在。

struct?property*?of_find_property(const?struct?device_node?*np,const?char?*name,int?*lenp) 

根據(jù)name參數(shù),在指定的設(shè)備結(jié)點np中查找匹配的property,并返回這個property

const?void?*?of_get_property(const?struct?device_node?*np,?const?char?*name,int?*lenp) 

根據(jù)name參數(shù),在指定的設(shè)備結(jié)點np中查找匹配的property,并返回這個property的屬性值

struct?device_node*?of_get_parent(const?struct?device_node?*node) 

獲得node節(jié)點的父節(jié)點的device node

int?of_device_is_compatible(const?struct?device_node?*device,const?char?*compat); 

判斷設(shè)備結(jié)點device的compatible屬性是否包含compat指定的字符串

從of_allnodes中查找信息:

struct?device_node*?of_find_node_by_path(const?char?*path) 根據(jù)路徑參數(shù),在全局鏈表of_allnodes中,查找匹配的device_node 
struct?device_node*?of_find_node_by_name(struct?device_node?*from,const?char?*name) 則根據(jù)name在全局鏈表of_allnodes中查找匹配的device_node,若from=NULL表示從頭開始查找 
struct?device_node*?of_find_node_by_type(struct?device_node?*from,const?char?*type) 

根據(jù)設(shè)備類型在全局鏈表of_allnodes中查找匹配的device_node

struct?device_node?*?of_find_compatible_node(struct?device_node?*from,?const?char*type,?const?char,*compatible); 

根據(jù)compatible的屬性值在全局鏈表of_allnodes中查找匹配的device_node,大多數(shù)情況下,from、type為NULL。

struct?device_node*?of_find_node_with_property(struct?device_node?*from,const?char?*prop_name) 

根據(jù)節(jié)點屬性的name在全局鏈表of_allnodes中查找匹配的device_node

struct?device_node*?of_find_node_by_phandle(phandle?handle) 

根據(jù)phandle在全局鏈表of_allnodes中查找匹配的device_node

雜:

void?__iomem*?of_iomap(struct?device_node?*node,?int?index); 

通過設(shè)備結(jié)點直接進行設(shè)備內(nèi)存區(qū)間的 ioremap(),index是內(nèi)存段的索引。若設(shè)備結(jié)點的reg屬性有多段,可通過index標示要ioremap的是哪一段,只有1段的情況,index為0

unsigned?long?__init?of_get_flat_dt_root(void) 

用來查找在dtb中的根節(jié)點,好像返回的都是0

int?of_alias_get_id(struct?device_node?*np,?const?char?*stem) 

獲取節(jié)點np對應(yīng)的aliasid號

struct?device_node*?of_node_get(struct?device_node?*node) void?of_node_put(struct?device_node?*node) 

device node計數(shù)增加/減少

const?struct?of_device_id*?of_match_node(const?struct?of_device_id?*matches,const?struct?device_node*node) 

將matches數(shù)組中of_device_id結(jié)構(gòu)的name和type與device node的compatible和type匹配,返回匹配度最高的of_device_id結(jié)構(gòu)

platform_device和resource相關(guān):

int?of_address_to_resource(struct?device_node?*dev,?int?index,struct?resource?*r) 

根據(jù)設(shè)備節(jié)點dev的reg屬性值,填充資源結(jié)構(gòu)體r。Index參數(shù)指明了使用reg屬性中第幾個屬性值,一般設(shè)置為0,表示第一個。

struct?platform_device*?of_device_alloc(struct?device_node?*np,const?char?*bus_id,struct?device?*parent) 

根據(jù)device node,bus_id以及父節(jié)點創(chuàng)建該設(shè)備的platform_device結(jié)構(gòu),同時會初始化它的resource成員。

int?of_platform_bus_probe(struct?device_node?*root,const?struct?of_device_id?*matches,struct?device?*parent) 

遍歷of_allnodes中的節(jié)點掛接到of_platform_bus_type總線上,由于此時of_platform_bus_type總線上還沒有驅(qū)動,所以此時不進行匹配

int?of_platform_populate(struct?device_node?*root,const?struct?of_device_id?*matches,const?struct?of_dev_auxdata?*lookup,struct?device?*parent) 

遍歷of_allnodes中的所有節(jié)點,生成并初始化所以節(jié)點的platform_device結(jié)構(gòu)

struct?platform_device*?of_find_device_by_node(struct?device_node?*np) 

根據(jù)device_node查找返回該設(shè)備對應(yīng)的platform_device結(jié)構(gòu)

相關(guān)閱讀

主站蜘蛛池模板: 日日夜夜精品免费视频 | 国产旗袍丝袜在线观看视频 | 精品久久久一二三区 | 天天插天天干天天射 | 色1看片网 | 国产日韩在线看 | 久久精品伊人网 | 欧美亚洲一区二区三区导航 | 久久国产高清一区二区三区 | 成年网站视频在线观看 | 久久国产亚洲欧美日韩精品 | 神马午神马午夜98 | 四虎影院永久在线观看 | 韩国一级永久免费观看网址 | 国内精品久久久久久久亚洲 | 玖玖操 | 久久精品国产一区二区三区不卡 | 五月婷婷六月丁香 | 四虎精品成人免费永久 | 黄色小视频在线免费观看 | 天天干天天曰天天操 | 欧美特黄高清免费观看的 | 亚洲综合精品 | 欧美亚洲日本一区 | 国产欧美日韩综合一区二区三区 | 国产精品亚洲二线在线播放 | 日本美女视频网站 | 久久亚洲一区二区 | 国产欧美日韩不卡一区二区三区 | 天天摸天天 | 精品69久久久久久99 | 狠狠狠色 | 日本在线永久 | 中日韩一区二区三区 | 亚洲日本黄色片 | 日本天堂网址 | 三级国产 | 欧美伊人久久久久久久久影院 | 狠狠狠狠干 | 日日干夜| 精品中文字幕久久久久久 |