作者 |趙青窕
審校 |孫淑娟
在安卓驅動開發中,不少開發同事反饋的問題在定位后,我發現這些問題大多不是驅動本身的問題,而是開發者對驅動框架理解的不夠透徹。比如有些開發者燒錄到硬件板子中的鏡像本身就不包含驅動的任何信息,有些開發者本地的代碼中沒有對應器件的驅動。
在這兩種情況下,有些剛開始接觸驅動的開發者已經開始進行基于硬件環境的調試,此時他們的硬件環境中是不存在對應的器件驅動的,該器件百分百是無法工作的。但經驗不足的開發者甚至可能會消耗數天時間來排查器件不工作的原因,為了防止這種低端問題的再次出現,我整理了一份驅動檢查表,其主要內容如下:
- 你當前的軟件代碼中是否存在器件對應的驅動和設備樹信息
- 如不存在驅動和設備樹,該如何處理
- 如何確保你的驅動和設備樹已正常編譯
- 如何確保你的鏡像中包含正確使用的驅動和設備樹
- 如何確保燒錄鏡像后的硬件環境中,存在對應的驅動和設備樹信息
以上這五項是環環相扣的,只有在上一步正確的前提條件下,才能進行下一步。
對于初級開發人員來說,強烈建議按照上面的步驟進行開發調試,因為許多初級人員無法像高級開發人員那樣,可以從機器的狀態和節點信息,快速推斷出可能出問題的模塊或者環節。接下來,我將詳細的描述如何確認每一個環節。
1.驅動和設備樹信息確認及獲取
對于安卓模式來說,項目中所用的大部分器件的驅動和設備樹均需要從器件廠的FAE處獲取,比如指紋,LCD,sensor,NFC。當我們拿到這類器件的設備樹和驅動后,結合硬件原理圖進行設備樹的適配,把驅動和設備樹放在本地代碼相應位置處,然后進行編譯配置進行編譯即可。
除了上述類型的器件外,還有一類器件,比如SD卡驅動,按鍵驅動,指示燈驅動等會隨著平臺方(高通,展銳,MTK等)的基線進行釋放,但也有例外,我最近從事的MTK平臺的項目,其釋放的基線中就不包含某一功能的驅動,最后我是從MTK平臺索要的驅動代碼,然后進行的功能調試。
對于一些特殊的定制化功能,可能就沒有供應商,且平臺默認也不支持這種功能,這種時候就需要自己編寫驅動和設備樹。
綜上所述,假如當前代碼中缺少對應平臺的驅動和設備樹,需要通過平臺提供的渠道索要獲取,其他驅動可以從器件供應商處獲取。那么問題來了,我們如何判斷當前代碼是否已包含我們需要的驅動和設備樹呢?
實際上,對于有經驗的工程師來說,通常只看代碼就能很快判斷出是否缺少驅動或者設備樹配置,畢竟他們對代碼實現等已經很熟悉了。但對于新手來說,通常要先了解對應平臺下某一模塊代碼架構和實現等,才能做出判斷,下面是我入門時所采用的方式,供新手作為參考:
- 從平臺方MTK,高通或者展銳等提供的渠道中獲取對應的文檔,如下圖所示,是我獲取的MTK文檔,這種方式獲取的文檔是比較權威的。
- 通過網絡搜索相關系列教程,網上的內容比較繁多,而且系列教程的比例是比較少的。對于需要入門的開發者來說,盡量查找系列類教程。
- 向別人請教,有些公司會有自己的代碼架構,這種只能通過公司內部途徑,或者自己看代碼,文檔來做進一步了解。
2.驅動和設備樹編譯
實際上,編譯是個龐大的系統,但在本文不打算說明編譯相關內容,僅僅用來說明我們的驅動和設備樹是否被編譯到。
對于驅動來說,當進行編譯后,會在特定路徑下生成對應的中間文件,我們可以通過查看是否有中間文件,或者中間文件的時間戳是否更新,從而確認驅動是否已經編譯。
下圖中顯示了中間文件的路徑為:out/target/product/(項目對應路徑)/obj/KERNEL_OBJ/drivers (圖中省略了個人或者項目信息)。
對于設備樹來說,當進行編譯后,同樣也可以在out路徑中找到,如下圖是采用在設備樹編譯的中間文件中查找關鍵字的方式,采用的命令是grep “cd-gpios” .–rn,此處查找的cd-gpios是SD卡相關功能中設備樹中的配置項,從下圖中可以看出當前我的SD卡對應的設備樹確實已經編譯,且采用的cd檢測引腳是GPIO4。假如在設備樹中修改了cd檢測引腳,那么可以在編譯后重新采用下圖中的方式來確認修改是否生效。
當發現驅動或者設備樹沒有編譯,那就需要查看配置是否正確,此處要注意有些公司會對代碼進行局部重構,重構后的代碼對應的中間文件可能會因為編譯腳本的原因而存在于其他路徑,本文中僅僅說明上圖中的兩個標準路徑,供大家學習了解。
3.鏡像中是否包含修改
鏡像本質上是打包壓縮,因其進行了壓縮,所以無法使用grep等類似方式來查詢鏡像中是否進行了修改,要想確認是否包含了修改,可以采用反編譯的方式,且大多數平臺代碼路徑編譯out/host/下是有對應的反編譯工具,比如反編譯dtbo.img(設備樹相關鏡像),就需要用到out/host下的反編譯工具mkdtimg 和dtc,但是該方法不常見,通常我就是采用時間戳來進行簡單判斷,刷機時采用最近的鏡像即可。
4.判斷硬件環境中是否有對應驅動和設備樹信息
我們得感謝內核的sys架構,我們的驅動和設備樹均會在/sys/bus下的對應路徑創建對應的節點信息,只有在該路徑下對應的總線下能找到驅動和設備樹信息(比如在/sys/bus/platform/device和/sys/bus/platform/driver),我們才可以開始調試驅動,否則你所做的驅動調試工作將是徒勞的。
如下圖所示是在SPI總線(/sys/bus/spi)的drivers路徑下查找到對應的驅動信息和在devices下找到的設備樹信息。
在進行查找的時候,首先我們需要知道驅動和設備樹對應的總線信息。上圖中對應的驅動代碼在加載的時候采用spi_register_driver函數來把對應驅動注冊到spi總線,所以是在spi下總線查找對應的信息的。倘若您的代碼中采用的是platform_driver_register函數,那么就應該在/sys/bus/platform總線下查找。若采用i2c_register_driver注冊驅動,那么就應該在/sys/bus/i2c總線下查找。總之,您代碼中使用的驅動注冊函數就決定了您的驅動對應的總線信息,在對應總線下查找信息即可。
假如您的設備樹是在spi節點下,那就需要在/sys/bus/spi/device下查找對應的設備樹信息。假如您的設備是在I2C節點下,那就需要在/sys/bus/i2c/device下查找對應的設備樹信息。總之,設備樹中添加節點的位置就決定了您設備樹對應的總線信息,需要在對應的總線下查找對應的設備信息。
5.總結
本文沒有談及設計驅動和設備樹的任何編寫注意事項或者技巧,也并非代碼調試技巧,而是說明了在代碼調試過程中的幾個關鍵注意點,只有在這些關鍵點全部沒問題的情況下,才能開始代碼調試。
作者介紹
趙青窕,51CTO社區編輯,從事多年驅動開發。研究興趣包含安全OS和網絡安全領域,發表過網絡相關專利。