嵌入式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个月,那么代码很可能已经改变,以至于您必须重写驱动程序的一部分,以便将其与内核集成。如果以上所有的操作都失败了,您将不得不自己通过编写丢失的内核驱动程序来找到解决方案。但是,这并不总是必要的,我将在下一节中展示。

posted @ 2020-07-11 12:20  吴建明wujianming  阅读(756)  评论(0编辑  收藏  举报