1. 程式人生 > 實用技巧 >嵌入式Linux裝置驅動程式:在執行時讀取驅動程式狀態

嵌入式Linux裝置驅動程式:在執行時讀取驅動程式狀態

嵌入式Linux裝置驅動程式:在執行時讀取驅動程式狀態

Embedded Linux device drivers: Reading driver state at runtime

在執行時瞭解驅動程式

一旦有了一個正在執行的Linux系統,瞭解哪些裝置驅動程式被載入以及它們處於什麼狀態是很有用的。通過閱讀/proc和/sys中的檔案可以發現很多資訊。

首先,您可以通過讀取/proc/devices列出當前載入和啟用的字元和塊裝置驅動程式:

#cat/proc/devicesCharacterdevices:1mem2pty3ttyp4/dev/vc/04tty4ttyS5/dev/tty5/dev/console5/dev/ptmx7vcs10misc13input29fb81video4linux89i2c90mtd116alsa128ptm136pts153spi180usb189usb_device204ttySC204ttyAMA207ttymxc226drm239ttyLP240ttyTHS241ttySiRF242ttyPS243ttyWMT244ttyAS245ttyO246ttyMSM247ttyAML248bsg249iio250watchdog251ptp252pps253media254rtcBlockdevices:259blkext7loop8sd11sr31mtdblock65sd66sd67sd68sd69sd70sd71sd128sd129sd130sd131sd132sd133sd134sd135sd179mmc

對於每個驅動程式,您可以看到主要編號和基本名稱。但是,這並不能告訴您每個驅動程式連線了多少個裝置。它只顯示ttyAMA,但沒有提示它連線到四個真正的串列埠。稍後,當我研究sysfs時,我將回到這個問題。

當然,網路裝置不會出現在這個列表中,因為它們沒有裝置節點。相反,您可以使用ifconfig或ip等工具獲取網路裝置的列表:

#iplinkshow 1:lo:<loopback,up,lower_up>mtu65536qdiscnoqueuestateUNKNOWNmodeDEFAULTlink/loopback00:00:00:00:00:00brd00:00:00:00:00:002:eth0:<no-carrier,broadcast,multicast,up>mtu1500qdiscpfifo_faststateDOWNmodeDEFAULTqlen1000link/ether54:4a:16:bb:b7:03brdff:ff:ff:ff:ff:ff3:usb0:<broadcast,multicast,up,lower_up>mtu1500qdiscpfifo_faststateUPmodeDEFAULTqlen1000link/etheraa:fb:7f:5e:a8:d5brdff:ff:ff:ff:ff:ff

您還可以使用眾所周知的命令lsusb和lspci來了解連線到USB或PCI匯流排的裝置。在各自的手冊頁和大量的線上指南中都有關於它們的資訊,所以我在這裡不再贅述。

真正有趣的資訊在sysfs中,這是下一個主題。

從sysfs獲取資訊

可以用迂腐的方式將sysfs定義為核心物件、屬性和關係的表示。核心物件是目錄,屬性是檔案,關係是從一個物件到另一個物件的符號連結。從更實際的角度來看,由於Linux裝置驅動程式模型將所有裝置和驅動程式都表示為核心物件,因此您可以通過在/sys中檢視系統的核心檢視,如下所示:

#ls/sysblockclassdevicesfsmodulebusdevfirmwarekernelpower

在發現有關裝置和驅動程式的資訊時,我將檢視其中的三個目錄:devices、class和block。 裝置:/sys/devices

這是核心對自引導以來發現的裝置以及它們如何相互連線的檢視。它由系統匯流排在頂層組織,因此您看到的內容因系統而異。這是ARM Versatile的QEMU模擬:

#ls/sys/devicesplatformsoftwaresystemtracepointvirtual

所有系統上都有三個目錄:

system/:它包含位於系統核心的裝置,包括cpu和時鐘。

virtual/:包含基於記憶體的裝置。您將在virtual/mem中找到顯示為/dev/null、/dev/random和/dev/zero的記憶體裝置。您將在virtual/net中找到環回裝置lo。

平臺Platform/:這是一個包羅永珍的裝置,沒有通過傳統的硬體匯流排連線。這可能是嵌入式裝置上幾乎所有的東西。

其他裝置出現在與實際系統匯流排相對應的目錄中。例如,PCI根匯流排(如果有)顯示為pci0000:00。

導航這個層次結構非常困難,因為它需要了解系統的拓撲結構,並且路徑名變得非常長,並且很難記住。提供兩種不同的裝置/系統/生活/sys/classand/sys/block。

驅動程式:/sys/class

這是按型別顯示的裝置驅動程式的檢視。換句話說,它是軟體檢視而不是硬體檢視。每個子目錄代表一個驅動程式類,由驅動程式框架的一個元件實現。例如,UART裝置由tty層管理,您可以在/sys/class/tty中找到它們。同樣,您可以在/sys/class/net中找到網路裝置,在/sys/class/input中可以找到鍵盤、觸控式螢幕和滑鼠等輸入裝置。

對於該型別裝置的每個例項,每個子目錄中都有一個符號連結,指向其在/sys/device中的表示形式。

舉一個具體的例子,讓我們看看多功能PB上的串列埠。首先,我們可以看到其中有四種:

#ls-d/sys/class/tty/ttyAMA*/sys/class/tty/ttyAMA0/sys/class/tty/ttyAMA2/sys/class/tty/ttyAMA1/sys/class/tty/ttyAMA3

每個目錄都是與裝置介面例項關聯的核心物件的表示。在其中一個目錄中,我們可以看到物件的屬性(表示為檔案),以及與其他物件的關係(由連結表示):

名為device的連結指向裝置的硬體物件。名為subsystem的連結指向父子系統/sys/class/tty。其餘的目錄條目是屬性。有些特定於串列埠,例如xmit_fifo_size,而其他則適用於許多型別的裝置,如中斷號irq和裝置號dev。有些屬性檔案是可寫的,允許您在執行時調整驅動程式中的引數。

dev屬性特別有趣。如果你看看它的價值,你會發現:

 # cat /sys/class/tty/ttyAMA0/dev
204:64

這是這個裝置的主要和次要的號碼。此屬性是在驅動程式註冊此介面時建立的。udev和mdev正是從這個檔案中找到裝置驅動程式的主要和次要編號。

塊驅動程式:/sys/block

對於這個討論,還有一個對裝置模型很重要的檢視:可以在/sys/block中找到的塊驅動程式檢視。每個塊裝置都有一個子目錄。此示例取自BeagleBone Black:

#ls/sys/blockloop0loop4mmcblk0ram0ram12ram2ram6loop1loop5mmcblk1ram1ram13ram3ram7loop2loop6mmcblk1boot0ram10ram14ram4ram8loop3loop7mmcblk1boot1ram11ram15ram5ram9

如果您檢視主機板上的eMMC晶片mmcblk1,您可以看到介面的屬性和其中的分割槽:

因此,結論是,您可以通過閱讀sysfs來了解系統中存在的裝置(硬體)和驅動程式(軟體)。

找到合適的裝置驅動程式

典型的嵌入式電路板是基於製造商的參考設計,經過修改使其適合特定應用。參考板附帶的BSP應支援該板上的所有外圍裝置。但是,你可以定製設計,也許通過增加一個通過I2C連線的溫度感測器,一些通過GPIO引腳連線的燈和按鈕,一個通過MIPI介面的顯示面板,或者其他很多東西。您的工作是建立一個自定義核心來控制所有這些,但是您從哪裡開始尋找支援所有這些外圍裝置的裝置驅動程式呢?

最明顯的地方是製造商網站上的驅動程式支援頁面,或者你可以直接問他們。以我的經驗,這很少能得到你想要的結果;硬體製造商不是特別精通Linux,他們經常給你誤導性的資訊。他們可能有專有的驅動程式作為二進位制blob,或者他們可能有原始碼,但與您擁有的核心版本不同。所以,一定要試試這條路。就我個人而言,我會一直努力為手頭的任務找到一個開源驅動程式。

在您的核心中可能已經有了支援:在主線Linux中有數千個驅動程式,在供應商核心中有許多特定於供應商的驅動程式。首先執行makemenuconfig(或xconfig)並搜尋產品名稱或編號。如果找不到完全匹配的,請嘗試更通用的搜尋,允許大多數驅動程式處理來自同一系列的一系列產品。接下來,嘗試在drivers目錄中搜索程式碼(grep是您的朋友)。

如果你還沒有驅動程式,你可以嘗試在網上搜索,並在相關論壇上詢問是否有一個更高版本的Linux的驅動程式。如果找到了一個,就應該認真考慮更新BSP以使用後面的核心。有時這是不實際的,因此它可能需要考慮將驅動程式後移植到核心中。如果核心版本相似,這可能很簡單,但是如果它們之間的間隔超過12到18個月,那麼程式碼很可能已經改變,以至於您必須重寫驅動程式的一部分,以便將其與核心整合。如果以上所有的操作都失敗了,您將不得不自己通過編寫丟失的核心驅動程式來找到解決方案。但是,這並不總是必要的,我將在下一節中展示。