嵌入式Linux设备驱动程序:在运行时读取驱动程序状态
嵌入式Linux設備驅動程序:在運行時讀取驅動程序狀態
Embedded Linux device drivers: Reading driver state at runtime
在運行時了解驅動程序
一旦有了一個正在運行的Linux系統,了解哪些設備驅動程序被加載以及它們處于什么狀態是很有用的。通過閱讀/proc和/sys中的文件可以發現很多信息。
首先,您可以通過讀取/proc/devices列出當前加載和激活的字符和塊設備驅動程序:
# cat /proc/devices Character devices: 1 mem 2 pty 3 ttyp 4 /dev/vc/0 4 tty 4 ttyS 5 /dev/tty 5 /dev/console 5 /dev/ptmx 7 vcs 10 misc 13 input 29 fb 81 video4linux 89 i2c 90 mtd 116 alsa 128 ptm 136 pts 153 spi 180 usb 189 usb_device 204 ttySC 204 ttyAMA 207 ttymxc 226 drm 239 ttyLP 240 ttyTHS 241 ttySiRF 242 ttyPS 243 ttyWMT 244 ttyAS 245 ttyO 246 ttyMSM 247 ttyAML 248 bsg 249 iio 250 watchdog 251 ptp 252 pps 253 media 254 rtc Block devices: 259 blkext 7 loop 8 sd 11 sr 31 mtdblock 65 sd 66 sd 67 sd 68 sd 69 sd 70 sd 71 sd 128 sd 129 sd 130 sd 131 sd 132 sd 133 sd 134 sd 135 sd 179 mmc
對于每個驅動程序,您可以看到主要編號和基本名稱。但是,這并不能告訴您每個驅動程序連接了多少個設備。它只顯示ttyAMA,但沒有提示它連接到四個真正的串行端口。稍后,當我研究sysfs時,我將回到這個問題。
當然,網絡設備不會出現在這個列表中,因為它們沒有設備節點。相反,您可以使用ifconfig或ip等工具獲取網絡設備的列表:
# ip link show 1: lo: mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 2: eth0: mtu 1500 qdisc pfifo_fast state DOWN mode DEFAULT qlen 1000 link/ether 54:4a:16:bb:b7:03 brd ff:ff:ff:ff:ff:ff 3: usb0: mtu 1500 qdisc pfifo_fast state UP mode DEFAULT qlen 1000 link/ether aa:fb:7f:5e:a8:d5 brd ff:ff:ff:ff:ff:ff
您還可以使用眾所周知的命令lsusb和lspci來了解連接到USB或PCI總線的設備。在各自的手冊頁和大量的在線指南中都有關于它們的信息,所以我在這里不再贅述。
真正有趣的信息在sysfs中,這是下一個主題。
從sysfs獲取信息
可以用迂腐的方式將sysfs定義為內核對象、屬性和關系的表示。內核對象是目錄,屬性是文件,關系是從一個對象到另一個對象的符號鏈接。從更實際的角度來看,由于Linux設備驅動程序模型將所有設備和驅動程序都表示為內核對象,因此您可以通過在/sys中查看系統的內核視圖,如下所示:
# ls /sys block class devices fs module bus dev firmware kernel power
在發現有關設備和驅動程序的信息時,我將查看其中的三個目錄:devices、class和block。
設備:/sys/devices
這是內核對自引導以來發現的設備以及它們如何相互連接的視圖。它由系統總線在頂層組織,因此您看到的內容因系統而異。這是ARM Versatile的QEMU仿真:
# ls /sys/devices platform software system tracepoint virtual
所有系統上都有三個目錄:
system/:它包含位于系統核心的設備,包括cpu和時鐘。
virtual/:包含基于內存的設備。您將在virtual/mem中找到顯示為/dev/null、/dev/random和/dev/zero的內存設備。您將在virtual/net中找到環回設備lo。
平臺Platform/:這是一個包羅萬象的設備,沒有通過傳統的硬件總線連接。這可能是嵌入式設備上幾乎所有的東西。
其他設備出現在與實際系統總線相對應的目錄中。例如,PCI根總線(如果有)顯示為pci0000:00。
導航這個層次結構非常困難,因為它需要了解系統的拓撲結構,并且路徑名變得非常長,并且很難記住。提供兩種不同的設備/系統/生活/sys/class and /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/block loop0 loop4 mmcblk0 ram0 ram12 ram2 ram6 loop1 loop5 mmcblk1 ram1 ram13 ram3 ram7 loop2 loop6 mmcblk1boot0 ram10 ram14 ram4 ram8 loop3 loop7 mmcblk1boot1 ram11 ram15 ram5 ram9
如果您查看主板上的eMMC芯片mmcblk1,您可以看到接口的屬性和其中的分區:
因此,結論是,您可以通過閱讀sysfs來了解系統中存在的設備(硬件)和驅動程序(軟件)。
找到合適的設備驅動程序
典型的嵌入式電路板是基于制造商的參考設計,經過修改使其適合特定應用。參考板附帶的BSP應支持該板上的所有外圍設備。但是,你可以定制設計,也許通過增加一個通過I2C連接的溫度傳感器,一些通過GPIO引腳連接的燈和按鈕,一個通過MIPI接口的顯示面板,或者其他很多東西。您的工作是創建一個自定義內核來控制所有這些,但是您從哪里開始尋找支持所有這些外圍設備的設備驅動程序呢?
最明顯的地方是制造商網站上的驅動程序支持頁面,或者你可以直接問他們。以我的經驗,這很少能得到你想要的結果;硬件制造商不是特別精通Linux,他們經常給你誤導性的信息。他們可能有專有的驅動程序作為二進制blob,或者他們可能有源代碼,但與您擁有的內核版本不同。所以,一定要試試這條路。就我個人而言,我會一直努力為手頭的任務找到一個開源驅動程序。
在您的內核中可能已經有了支持:在主線Linux中有數千個驅動程序,在供應商內核中有許多特定于供應商的驅動程序。首先運行makemenuconfig(或xconfig)并搜索產品名稱或編號。如果找不到完全匹配的,請嘗試更通用的搜索,允許大多數驅動程序處理來自同一系列的一系列產品。接下來,嘗試在drivers目錄中搜索代碼(grep是您的朋友)。
如果你還沒有驅動程序,你可以嘗試在網上搜索,并在相關論壇上詢問是否有一個更高版本的Linux的驅動程序。如果找到了一個,就應該認真考慮更新BSP以使用后面的內核。有時這是不實際的,因此它可能需要考慮將驅動程序后移植到內核中。如果內核版本相似,這可能很簡單,但是如果它們之間的間隔超過12到18個月,那么代碼很可能已經改變,以至于您必須重寫驅動程序的一部分,以便將其與內核集成。如果以上所有的操作都失敗了,您將不得不自己通過編寫丟失的內核驅動程序來找到解決方案。但是,這并不總是必要的,我將在下一節中展示。
總結
以上是生活随笔為你收集整理的嵌入式Linux设备驱动程序:在运行时读取驱动程序状态的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 嵌入式Linux设备驱动程序:用户空间中
- 下一篇: 基于ARMv8的固件系统体系结构