最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會員登陸 & 注冊

一文搞懂Linux驅(qū)動的來龍去脈

2022-07-27 17:07 作者:補(bǔ)給站Linux內(nèi)核  | 我要投稿

驅(qū)動相關(guān)的學(xué)習(xí)資料網(wǎng)上很多,但大部分都是碎片化的記錄,很少有系統(tǒng)化的總結(jié)整理。本文旨在系統(tǒng)化的講清楚 Linux 驅(qū)動的來龍去脈。先從總線,設(shè)備,驅(qū)動介紹內(nèi)核對于驅(qū)動的模型設(shè)計(jì);然后引入設(shè)備樹的概念,打通設(shè)備和驅(qū)動的關(guān)系;最后手把手和你一起定制自己的開發(fā)板。這也是拿到芯片后,如何 bringup 板子的入門工作。詳細(xì)交流可以加我微信 rrjike,一起學(xué)習(xí)進(jìn)步!

Linux 總線、設(shè)備、驅(qū)動模型的探究

設(shè)備驅(qū)動模型的需求

總線、設(shè)備和驅(qū)動模型,如果把它們之間的關(guān)系比喻成生活中的例子是比較容易理解的。舉個例子,充電墻壁插座安靜的嵌入在墻面上,無論設(shè)備是電腦還是手機(jī),插座都能依然不動的完成它的使命——充電,沒有說為了滿足各種設(shè)備充電而去更換插座的。其實(shí)這就是軟件工程強(qiáng)調(diào)的高內(nèi)聚、低耦合概念。

所謂高內(nèi)聚低耦合是模塊內(nèi)各元素聯(lián)系越緊密就代表內(nèi)聚性就越高,模塊間聯(lián)系越不緊密就代表耦合性低。所以高內(nèi)聚、低耦合強(qiáng)調(diào)的就是內(nèi)部要緊緊抱團(tuán)。設(shè)備和驅(qū)動就是基于這種模型去實(shí)現(xiàn)彼此隔離不相干的。這里,有的讀者就要問了,高內(nèi)聚、低耦合的軟件模型理解,可設(shè)備和驅(qū)動為什么要采用這種模型呢?沒錯,好問題。下面進(jìn)入今天的話題——總線、設(shè)備和驅(qū)動模型的探究。

設(shè)想一個叫 GITCHAT 的網(wǎng)卡,它需要接在 CPU 的內(nèi)部總線上,需要地址總線、數(shù)據(jù)總線和控制總線,以及中斷 pin 腳等。


那么在 GITCHAT 的驅(qū)動里需要定義 GITCHAT 的基地址、中斷號等信息。假設(shè) GITCHAT 的地址為0x0001,中斷號是 2,那么:

但是世界上的板子千千萬,有三星、華為、飛思卡爾……每個板子的信息也都不一樣,站在驅(qū)動的角度看,當(dāng)每次重新?lián)Q板子的時候,GITCHAT_BASE 和 GITCHAT_INTERRUPT 就不再一樣,那驅(qū)動代碼也要隨之改變。這樣的話一萬個開發(fā)板要寫一萬個驅(qū)動了,這就是文章剛開始提到的高內(nèi)聚、低耦合的應(yīng)用場景。

驅(qū)動想以不變應(yīng)萬變的姿態(tài)適配各種設(shè)備連接的話就要實(shí)現(xiàn)設(shè)備驅(qū)動模型?;旧衔覀兛梢哉J(rèn)為驅(qū)動不會因?yàn)?CPU 的改變而改變,所以它應(yīng)該是跨平臺的。自然像 “#define GITCHAT_BASE 0x0001,#define GITCHAT_INTERRUPT 2” 這樣描述和 CPU 相關(guān)信息的代碼不應(yīng)該出現(xiàn)在驅(qū)動里。


【文章福利】小編推薦自己的Linux內(nèi)核技術(shù)交流群:【891587639】整理了一些個人覺得比較好的學(xué)習(xí)書籍、視頻資料共享在群文件里面,有需要的可以自行添加哦?。。。ê曨l教程、電子書、實(shí)戰(zhàn)項(xiàng)目及代碼)? ? ? ??


設(shè)備驅(qū)動模型的實(shí)現(xiàn)

現(xiàn)在 CPU 板級信息和驅(qū)動分開的需求已經(jīng)刻不容緩。但是基地址、中斷號等板級信息始終和驅(qū)動是有一定聯(lián)系的,因?yàn)轵?qū)動畢竟要取出基地址、中斷號等。怎么???有一種方法是 GITCHAT 驅(qū)動滿世界去詢問各個板子:請問你的基地址是多少?中斷號是幾?細(xì)心的讀者會發(fā)現(xiàn)這仍然是一個耦合的情況。


對軟件工程熟悉的讀者肯定立刻想到能不能設(shè)計(jì)一個類似接口適配器的類(adapter)去適配不同的板級信息,這樣板子上的基地址、中斷號等信息都在一個 adapter 里去維護(hù),然后驅(qū)動通過這個 adapter 不同的 API 去獲取對應(yīng)的硬件信息。沒錯,Linux 內(nèi)核里就是運(yùn)用了這種設(shè)計(jì)思想去對設(shè)備和驅(qū)動進(jìn)行適配隔離的,只不過在內(nèi)核里我們不叫做適配層,而取名為總線,意為通過這個總線去把驅(qū)動和對應(yīng)的設(shè)備綁定一起,如圖:


基于這種設(shè)計(jì)思想,Linux 把設(shè)備驅(qū)動分為了總線、設(shè)備和驅(qū)動三個實(shí)體,這三個實(shí)體在內(nèi)核里的職責(zé)分別如下:


模型設(shè)計(jì)好后,下面來看一下具體驅(qū)動的實(shí)踐,首先把板子的硬件信息填入設(shè)備端,然后讓設(shè)備向總線注冊,這樣總線就間接的知道了設(shè)備的硬件信息。比如一個板子上有一個 GITCHAT,首先向總線注冊:

現(xiàn)在 platform 總線上自然知道了板子上關(guān)于 GITCHAT 設(shè)備的硬件信息,一旦 GITCHAT 的驅(qū)動也被注冊的話,總線就會把驅(qū)動和設(shè)備綁定起來,從而驅(qū)動就獲得了基地址、中斷號等板級信息。總線存在的目的就是把設(shè)備和對應(yīng)的驅(qū)動綁定起來,讓內(nèi)核成為該是誰的就是誰的和諧世界,有點(diǎn)像我們生活中紅娘的角色,把有緣人通過紅線牽在一起。設(shè)備注冊總線的代碼例子看完了,下面看下驅(qū)動注冊總線的代碼示例:

從代碼中看到驅(qū)動是通過總線 API 接口 platform_get_resource 取得板級信息,這樣驅(qū)動和設(shè)備之間就實(shí)現(xiàn)了高內(nèi)聚、低耦合的設(shè)計(jì),無論你設(shè)備怎么換,我驅(qū)動就可以巋然不動。

看到這里,可能有些喜歡探究本質(zhì)的讀者又要問了,設(shè)備向總線注冊了板級信息,驅(qū)動也向總線注冊了驅(qū)動模塊,但總線是怎么做到驅(qū)動和設(shè)備匹配的呢?接下來就講下設(shè)備和驅(qū)動是怎么通過總線進(jìn)行“聯(lián)姻”的。

總線里有很多匹配方式,比如:

從上面可知 platform 總線下的設(shè)備和驅(qū)動是通過名字進(jìn)行匹配的,先去匹配 platform_driver 中的 id_table 表中的各個名字與 platform_device->name 名字是否相同,如果相同則匹配。

設(shè)備驅(qū)動模型的改善

相信通過上面的學(xué)習(xí),相信對于設(shè)備、驅(qū)動通過總線來匹配的模型已經(jīng)有所了解。如果寫代碼的話應(yīng)該是下面結(jié)構(gòu)圖所示:


最底層是不同板子的板級文件代碼,中間層是內(nèi)核的總線,最上層是對應(yīng)的驅(qū)動,現(xiàn)在描述板級的代碼已經(jīng)和驅(qū)動解耦了,這也是 Linux 設(shè)備驅(qū)動模型最早的實(shí)現(xiàn)機(jī)制,但隨著時代的發(fā)展,就像是人類的貪婪促進(jìn)了社會的進(jìn)步一樣,開發(fā)人員對這種模型有了更高的要求,雖然驅(qū)動和設(shè)備解耦了,但是天下設(shè)備千千萬,每次設(shè)備的需求改動都要去修改 board-xxx.c 設(shè)備文件的話,這樣下去,有太多的板級文件需要維護(hù)。完美的 Linux 怎么會允許這樣的事情存在,于是乎,設(shè)備樹(DTS)就登向了歷史舞臺,下一篇內(nèi)容將探討設(shè)備樹的實(shí)現(xiàn)原理和用法。

Linux 設(shè)備樹(DTS)的深入理解

設(shè)備樹的出現(xiàn)

上面說過設(shè)備樹的出現(xiàn)是為了解決內(nèi)核中大量的板級文件代碼,通過 DTS 可以像應(yīng)用程序里的 XML 語言一樣很方便的對硬件信息進(jìn)行配置。關(guān)于設(shè)備樹的出現(xiàn)其實(shí)在 2005 年時候就已經(jīng)在 PowerPC Linux 里出現(xiàn)了,由于 DTS 的方便性,慢慢地被廣泛應(yīng)用到 ARM、MIPS、X86 等架構(gòu)上。為了理解設(shè)備樹的出現(xiàn)的好處,先來看下在使用設(shè)備樹之前是采用什么方式的。

關(guān)于硬件的描述信息之前一般放在一個個類似 arch/xxx/mach-xxx/board-xxx.c 的文件中,如:

一個很少的地址獲取,我們就要寫大量的類似代碼,當(dāng)年 Linus 看到內(nèi)核里有大量的類似代碼,很是生氣并且在 Linux 郵件列表里發(fā)了份郵件,才有了現(xiàn)在的設(shè)備樹概念,至于設(shè)備樹的出現(xiàn)到底帶來了哪些好處,先看一下設(shè)備樹的文件:

從代碼中可看到對于 GITCHAT 這個網(wǎng)卡驅(qū)動、一些寄存器、中斷號和上一層 gpio 節(jié)點(diǎn)都很清晰的被描述。比上一圖的代碼優(yōu)化了很多,也容易維護(hù)了很多。這樣就形成了設(shè)備在腳本,驅(qū)動在 c 文件里的關(guān)系圖:



從圖中可以看出 A、B、C 三個板子里都含有 GITCHAT 設(shè)備樹文件,這樣對于 GITCHAT 驅(qū)動寫一份就可以在 A、B、C 三個板子里共用。從上幅圖里不難看出,其實(shí)設(shè)備樹的出現(xiàn)在軟件模型上相對于之前并沒有太大的改變,設(shè)備樹的出現(xiàn)主要在設(shè)備維護(hù)上有了更上一層樓的提高,此外在內(nèi)核編譯上使內(nèi)核更精簡,鏡像更小。

設(shè)備樹的文件結(jié)構(gòu)和剖析

設(shè)備樹和設(shè)備樹之間到底是什么關(guān)系,有著哪些依賴和聯(lián)系,先看下設(shè)備樹之間的關(guān)系圖:



除了設(shè)備樹(DTS)外,還存有 dtsi 文件,就像代碼里的頭文件一樣,是不同設(shè)備樹共有的設(shè)備文件,這不難理解,但是值得注意的是如果 dts 和 dtsi 里都對某個屬性進(jìn)行定義的話,底層覆蓋上層的屬性定義。這樣的好處是什么呢?假如你要做一塊電路板,電路板里有很多模塊是已經(jīng)存在的,這樣就可以直接像包含頭文件一樣把共性的 dtsi 文件包含進(jìn)來,大大減少工作量,后期也可以對類似模塊再次利用。

設(shè)備樹文件的格式是 dts,包含的頭文件格式是 dtsi,dts 文件是一種程序員可以看懂的格式,但是 Uboot 和 Linux 只能識別二進(jìn)制文件,不能直接識別。所以就需要把 dts 文件編譯成 dtb 文件。把 dts 編譯成 dtb 文件的工具是 dtc,位于內(nèi)核目錄下 scripts/dtc,也可以手動安裝:sudo apt-get install device-tree-compiler 工具。具體 dts 是如何轉(zhuǎn)換成機(jī)器碼并在內(nèi)存里供 kernel 識別的,請看下圖:



設(shè)備樹的應(yīng)用

有了理論,在具體的工程里如何做設(shè)備樹呢?這里介紹三大法寶:文檔、腳本、代碼。文檔是對各種 node 的描述,位于內(nèi)核 documentation/devicetree/bingdings/arm/ 下,腳本就是設(shè)備樹 dts,代碼就是你要寫的設(shè)備代碼,一般位于 arch/arm/ 下,以后在寫設(shè)備的時候可以用這種方法,絕對的事半功倍。很多上層應(yīng)用開發(fā)者沒有做過內(nèi)核開發(fā)的經(jīng)驗(yàn),對內(nèi)核一直覺得很神秘,其實(shí)可以換一種思路來看內(nèi)核,相信上層應(yīng)用開發(fā)者最熟悉的就是各種 API,工作中可以說就是和 API 打交道,對于內(nèi)核也可以想象是各種 API,只不過是內(nèi)核態(tài)的 API。這里設(shè)備文件就是根據(jù)各種內(nèi)核態(tài)的 API 來調(diào)用設(shè)備樹里的板級信息:

  • struct device_node *of_find_node_by_phandle(phandle handle);

  • struct device_node *of_get_parent(const struct device_node_ *node);

  • of_get_child_count()

  • of_property_read_u32_array()

  • of_property_read_u64()

  • of_property_read_string()

  • of_property_read_string_array()

  • of_property_read_bool()

具體的用法這里不做進(jìn)一步的解釋,大家可以查詢資料或者看官網(wǎng)解釋。

這里對設(shè)備樹做個總結(jié),設(shè)備樹可以總結(jié)為三大作用:一是平臺標(biāo)識,所謂平臺標(biāo)識就是板級識別,讓內(nèi)核知道當(dāng)前使用的是哪個開發(fā)板,這里識別的方式是根據(jù) root 節(jié)點(diǎn)下的 compatible 字段來匹配。二是運(yùn)行時配置,就是在內(nèi)核啟動的時候 ramdisk 的配置,比如 bootargs 的配置,ramdisk 的起始和結(jié)束地址。三是設(shè)備信息集合,這也是最重要的信息,集合了各種設(shè)備控制器,接下來的實(shí)踐課會對這一作用重點(diǎn)應(yīng)用。這里有張圖對大家理解設(shè)備樹作用有一定的幫助:



Linux 設(shè)備和驅(qū)動的相遇

一個開發(fā)板

上面的最后我們講到設(shè)備樹的三大作用,其最后一個作用也是最重要的作用:設(shè)備信息集合。這一節(jié)結(jié)合設(shè)備信息集合的詳細(xì)講解來認(rèn)識一下設(shè)備和驅(qū)動是如何綁定的。所謂設(shè)備信息集合,就是根據(jù)不同的外設(shè)尋找各自的外設(shè)信息,我們知道一個完整的開發(fā)板有 CPU 和各種控制器(如 I2C 控制器、SPI 控制器、DMA 控制器等),CPU 和控制器可以統(tǒng)稱為 SOC,除此之外還有各種外設(shè) IP,如 LCD、HDMI、SD、CAMERA 等,如下圖:


我們看到一個開發(fā)板有很多的設(shè)備,這些設(shè)備是如何一層一層展開的呢?設(shè)備和驅(qū)動又是如何綁定的呢?我們帶著這些疑問進(jìn)入本節(jié)的主題。

各級設(shè)備的展開

內(nèi)核啟動的時候是一層一層展開地去尋找設(shè)備,設(shè)備樹之所以叫設(shè)備樹也是因?yàn)樵O(shè)備在內(nèi)核中的結(jié)構(gòu)就像樹一樣,從根部一層一層的向外展開,為了更形象的理解來看一張圖:



大的圓圈中就是我們常說的 soc,里面包括 CPU 和各種控制器 A、B、I2C、SPI,soc 外面接了外設(shè) E 和 F。IP 外設(shè)有具體的總線,如 I2C 總線、SPI 總線,對應(yīng)的 I2C 設(shè)備和 SPI 設(shè)備就掛在各自的總線上,但是在 soc 內(nèi)部只有系統(tǒng)總線,是沒有具體總線的。

第一節(jié)中講了總線、設(shè)備和驅(qū)動模型的原理,即任何驅(qū)動都是通過對應(yīng)的總線和設(shè)備發(fā)生聯(lián)系的,故雖然 soc 內(nèi)部沒有具體的總線,但是內(nèi)核通過 platform 這條虛擬總線,把控制器一個一個找到,一樣遵循了內(nèi)核高內(nèi)聚、低耦合的設(shè)計(jì)理念。下面我們按照 platform 設(shè)備、i2c 設(shè)備、spi 設(shè)備的順序探究設(shè)備是如何一層一層展開的。


1.展開 platform 設(shè)備

上圖中可以看到紅色字體標(biāo)注的 simple-bus,這些就是連接各類控制器的總線,在內(nèi)核里即為 platform 總線,掛載的設(shè)備為 platform 設(shè)備。下面看下 platform 設(shè)備是如何展開的。

還記得上一節(jié)講到在內(nèi)核初始化的時候有一個叫做 init_machine() 的回調(diào)函數(shù)嗎?如果你在板級文件里注冊了這個函數(shù),那么在系統(tǒng)啟動的時候這個函數(shù)會被調(diào)用,如果沒有定義,則會通過調(diào)用 of_platform_populate() 來展開掛在“simple-bus”下的設(shè)備,如圖(分別位于 kernel/arch/arm/kernel/setup.c,kernel/drivers/of/platform.c):


這樣就把 simple-bus 下面的節(jié)點(diǎn)一個一個的展開為 platform 設(shè)備。

2.展開 i2c 設(shè)備

有經(jīng)驗(yàn)的小伙伴知道在寫 i2c 控制器的時候肯定會調(diào)用 i2c_register_adapter() 函數(shù),該函數(shù)的實(shí)現(xiàn)如下(kernel/drivers/i2c/i2c-core.c):



注冊函數(shù)的最后有一個函數(shù) of_i2c_register_devices(adap),實(shí)現(xiàn)如下:



of_i2c_register_devices()函數(shù)中會遍歷控制器下的節(jié)點(diǎn),然后通過of_i2c_register_device()函數(shù)把 i2c 控制器下的設(shè)備注冊進(jìn)去。

3.展開 spi 設(shè)備

spi 設(shè)備的注冊和 i2c 設(shè)備一樣,在 spi 控制器下遍歷 spi 節(jié)點(diǎn)下的設(shè)備,然后通過相應(yīng)的注冊函數(shù)進(jìn)行注冊,只是和 i2c 注冊的 api 接口不一樣,下面看一下具體的代碼(kernel/drivers/spi/spi.c):



當(dāng)通過 spi_register_master 注冊 spi 控制器的時候會通過 of_register_spi_devices 來遍歷 spi 總線下的設(shè)備,從而注冊。這樣就完成了 spi 設(shè)備的注冊。

各級設(shè)備的展開

學(xué)到這里相信應(yīng)該了解設(shè)備的硬件信息是從設(shè)備樹里獲取的,如寄存器地址、中斷號、時鐘等等。接下來我們一起看下這些信息在設(shè)備樹里是怎么記錄的,為下一節(jié)動手定制開發(fā)板做好準(zhǔn)備。

1.reg 寄存器



我們先看設(shè)備樹里的 soc 描述信息,紅色標(biāo)注的代表著寄存器地址用幾個數(shù)據(jù)量來表述,綠色標(biāo)注的代表著寄存器空間大小用幾個數(shù)據(jù)量來表述。圖中的含義是中斷控制器的基地址是 0xfec00000,空間大小是 0x1000。如果 address-cells 的值是 2 的話表示需要兩個數(shù)量級來表示基地址,比如寄存器是 64 位的話就需要兩個數(shù)量級來表示,每個代表著 32 位的數(shù)。

2.ranges 取值范圍


ranges 代表了 local 地址向 parent 地址的轉(zhuǎn)換,如果 ranges 為空的話代表著與 cpu 是 1:1 的映射關(guān)系,如果沒有 range 的話表示不是內(nèi)存區(qū)域。

動手定制一個開發(fā)板案例

前面通過學(xué)習(xí)總線、設(shè)備、驅(qū)動模型知識后,知道了設(shè)備和驅(qū)動之間都是通過總線進(jìn)行綁定而匹配的;然后通過設(shè)備樹的深入探究,知道了設(shè)備樹的出現(xiàn)大大增加了驅(qū)動的通用性;接著我們一起看了 Linux 的啟動流程和設(shè)備在內(nèi)核里一層一層的展開。

通過前面的課程學(xué)習(xí),相信內(nèi)核初學(xué)者對內(nèi)核和驅(qū)動有了一個大概的感性認(rèn)識,有內(nèi)核經(jīng)驗(yàn)的小伙伴相信也有了系統(tǒng)化的梳理。都說“實(shí)踐是檢驗(yàn)真理的唯一標(biāo)準(zhǔn)”,為了檢驗(yàn)前面的理論性,更為了加深理解,這里我們手把手一起從設(shè)備樹入手,模擬一個電路板,上面有中斷控制器、GPIO 控制器、I2C 控制器、SPI 控制器、以太網(wǎng)控制器等,并根據(jù)這個電路板從頭到尾構(gòu)建一個 DTS 文件,使內(nèi)核支持我們自己定制的開發(fā)板。

添加一個新的 SOC

我們假設(shè) csdn 是一家芯片廠商,研發(fā)了一塊叫做 gitchat 的芯片,對應(yīng)的開發(fā)板叫做 evb。需要做什么工作才能定制一套開發(fā)板并且使 Linux 支持我們這塊電路板呢?

首先我們在 arch/arm 目錄下創(chuàng)建一個 mach-gitchat 的目錄,然后創(chuàng)建 arch/arm/machgitchat/Kconfig,Makefile,common.c。


其中,Kconfig 里做了一個叫 ARCH_GITCHAT 的假芯片,common.c 是對應(yīng)的驅(qū)動,Makefile 里對這個驅(qū)動做了編譯。我們來簡單的看一下這個驅(qū)動


就像前幾節(jié)課講的那樣,我們是通過 DT_MACHINE_START 來定義一個電路板的,里面有很多回調(diào)函數(shù),這里簡單的寫了 init_late 和 dt_compat,其中 dt_compat 會根據(jù)設(shè)備樹里的字段進(jìn)行匹配,如果字段一致就說明匹配正確,這里的字段是“csdn, gitchat”。

3.展開 spi 設(shè)備

spi 設(shè)備的注冊和 i2c 設(shè)備一樣,在 spi 控制器下遍歷 spi 節(jié)點(diǎn)下的設(shè)備,然后通過相應(yīng)的注冊函數(shù)進(jìn)行注冊,只是和 i2c 注冊的 api 接口不一樣,下面看一下具體的代碼(kernel/drivers/spi/spi.c):


當(dāng)通過 spi_register_master 注冊 spi 控制器的時候會通過 of_register_spi_devices 來遍歷 spi 總線下的設(shè)備,從而注冊。這樣就完成了 spi 設(shè)備的注冊。

各級設(shè)備的展開

學(xué)到這里相信應(yīng)該了解設(shè)備的硬件信息是從設(shè)備樹里獲取的,如寄存器地址、中斷號、時鐘等等。接下來我們一起看下這些信息在設(shè)備樹里是怎么記錄的,為下一節(jié)動手定制開發(fā)板做好準(zhǔn)備。

1.reg 寄存器


我們先看設(shè)備樹里的 soc 描述信息,紅色標(biāo)注的代表著寄存器地址用幾個數(shù)據(jù)量來表述,綠色標(biāo)注的代表著寄存器空間大小用幾個數(shù)據(jù)量來表述。圖中的含義是中斷控制器的基地址是 0xfec00000,空間大小是 0x1000。如果 address-cells 的值是 2 的話表示需要兩個數(shù)量級來表示基地址,比如寄存器是 64 位的話就需要兩個數(shù)量級來表示,每個代表著 32 位的數(shù)。

2.ranges 取值范圍


ranges 代表了 local 地址向 parent 地址的轉(zhuǎn)換,如果 ranges 為空的話代表著與 cpu 是 1:1 的映射關(guān)系,如果沒有 range 的話表示不是內(nèi)存區(qū)域。

動手定制一個開發(fā)板案例

前面通過學(xué)習(xí)總線、設(shè)備、驅(qū)動模型知識后,知道了設(shè)備和驅(qū)動之間都是通過總線進(jìn)行綁定而匹配的;然后通過設(shè)備樹的深入探究,知道了設(shè)備樹的出現(xiàn)大大增加了驅(qū)動的通用性;接著我們一起看了 Linux 的啟動流程和設(shè)備在內(nèi)核里一層一層的展開。

通過前面的課程學(xué)習(xí),相信內(nèi)核初學(xué)者對內(nèi)核和驅(qū)動有了一個大概的感性認(rèn)識,有內(nèi)核經(jīng)驗(yàn)的小伙伴相信也有了系統(tǒng)化的梳理。都說“實(shí)踐是檢驗(yàn)真理的唯一標(biāo)準(zhǔn)”,為了檢驗(yàn)前面的理論性,更為了加深理解,這里我們手把手一起從設(shè)備樹入手,模擬一個電路板,上面有中斷控制器、GPIO 控制器、I2C 控制器、SPI 控制器、以太網(wǎng)控制器等,并根據(jù)這個電路板從頭到尾構(gòu)建一個 DTS 文件,使內(nèi)核支持我們自己定制的開發(fā)板。

添加一個新的 SOC

我們假設(shè) csdn 是一家芯片廠商,研發(fā)了一塊叫做 gitchat 的芯片,對應(yīng)的開發(fā)板叫做 evb。需要做什么工作才能定制一套開發(fā)板并且使 Linux 支持我們這塊電路板呢?

首先我們在 arch/arm 目錄下創(chuàng)建一個 mach-gitchat 的目錄,然后創(chuàng)建 arch/arm/machgitchat/Kconfig,Makefile,common.c。


其中,Kconfig 里做了一個叫 ARCH_GITCHAT 的假芯片,common.c 是對應(yīng)的驅(qū)動,Makefile 里對這個驅(qū)動做了編譯。我們來簡單的看一下這個驅(qū)動


就像前幾節(jié)課講的那樣,我們是通過 DT_MACHINE_START 來定義一個電路板的,里面有很多回調(diào)函數(shù),這里簡單的寫了 init_late 和 dt_compat,其中 dt_compat 會根據(jù)設(shè)備樹里的字段進(jìn)行匹配,如果字段一致就說明匹配正確,這里的字段是“csdn, gitchat”。

添加對應(yīng)的 DTS

現(xiàn)在已經(jīng)在 Linux 里添加了我們定義的 soc,接下來需要添加 soc 對應(yīng)的設(shè)備樹,即具體的板級文件信息。

在 arch/arm/boot/dts 下創(chuàng)建 csdn-gitchat.dtsi 和 csdn-gitchat-evb.dts。csdn-gitchat.dtsi 是對芯片的描述,csdn-gitchat-evb.dts 是針對這個芯片的 evb 板子描述,其內(nèi)容分別如下:

由于篇幅限制,這里我們只寫了部分代碼。

DTS 的編譯

在 arch/arm/boot/dts/Makefile 里添加我們的板子:


剛剛平臺目錄下我們已經(jīng)對 MACH_GITCHAT 進(jìn)行了定義,這里就會把設(shè)備樹編譯成 dtb 文件。我們也可以通過命令手動來編譯生成 csdn-gitchat-evb.dtb 文件:

$ dtc -I dts -O dtb csdn-gitchat-evb.dts -o csdn-gitchat-evb.dtb

至此,一個自己定制的開發(fā)板就已經(jīng)搞定,這里虛擬了一個開發(fā)板,如果定制一個真實(shí)的電路板的話需要根據(jù)芯片手冊把設(shè)備樹里的信息完善起來。但是通過這個系列學(xué)習(xí)完全可以理解從零是如何定制一個開發(fā)板的。


一文搞懂Linux驅(qū)動的來龍去脈的評論 (共 條)

分享到微博請遵守國家法律
双牌县| 栖霞市| 北海市| 尚志市| 温泉县| 台南县| 青海省| 天等县| 宜阳县| 象州县| 光泽县| 望城县| 云梦县| 阿城市| 黄冈市| 和林格尔县| 武安市| 石阡县| 金乡县| 石首市| 东乌珠穆沁旗| 平舆县| 道孚县| 莱芜市| 县级市| 五大连池市| 龙海市| 青阳县| 锡林浩特市| 筠连县| 库伦旗| 老河口市| 正定县| 湖北省| 罗田县| 潮安县| 彭阳县| 集贤县| 迁安市| 嘉定区| 庆阳市|