嵌入式Linux设备驱动程序:在运行时读取驱动程序状态
Posted 吴建明
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了嵌入式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: <loopback,up,lower_up> 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: <no-carrier,broadcast,multicast,up> 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: <broadcast,multicast,up,lower_up> 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设备驱动程序:在运行时读取驱动程序状态的主要内容,如果未能解决你的问题,请参考以下文章