编写设备驱动程序

驱动程序测试条件

设备驱动程序可以正常运行后,应在分发之前全面测试该驱动程序。除了测试传统 UNIX 设备驱动程序中的功能以外,Solaris 驱动程序还需要测试电源管理功能,如驱动程序的动态装入和卸载。

配置测试

驱动程序能否处理多种设备配置是测试过程的重要部分。驱动程序可以在一种简单(或缺省)配置中正常工作后,还应该测试其他配置。根据设备不同,可以通过更改跳线或 DIP 开关来完成配置测试。如果可能的配置数较少,则应尝试测试所有配置。如果可能的配置数较多,则应为这些可能的配置定义不同的类,并抽样测试每类配置。定义这些类取决于不同配置参数之间的潜在交互。这些交互是设备类型与驱动程序编写方式之间的配合。

对于每种设备配置,必须测试基本运行情况,包括装入、打开、读取、写入、关闭和卸载驱动程序。任何取决于配置的运行情况都需要特别注意。例如,更改设备寄存器的基本内存地址不可能影响大多数驱动程序函数的行为。如果驱动程序在一个地址上正常工作,则该驱动程序在其他地址上也能正常工作。另一方面,特殊 I/O 控制调用的结果可能会因特定设备配置而异。

以不同配置装入驱动程序可确保 probe(9E)attach(9E) 入口点能够在不同地址找到设备。对于基本功能测试,使用常规的 UNIX 命令(如 cat(1)dd(1M))通常就可满足字符设备的要求。对于块设备,可能需要挂载或引导。

功能测试

对驱动程序进行全面的配置测试之后,应全面测试驱动程序的所有功能。这些测试需要执行驱动程序所有入口点的操作。

许多驱动程序需要使用自定义的应用程序来测试功能。但是,对于磁盘、磁带或异步板等设备的基本驱动程序,使用标准系统实用程序即可进行测试。在此过程中,应测试所有入口点,包括 devmap(9E)chpoll(9E)ioctl(9E)(如果适用)。对于每种驱动程序,ioctl () 测试可能完全不同。对于非标准设备,通常需要使用自定义的测试应用程序。

错误处理

在理想环境中,驱动程序也许可以正确执行,但如果出现错误(如操作错误或数据错 误),则可能会失败。因此,驱动程序测试的一个重要部分是测试驱动程序的错误处理。

应该执行驱动程序的所有可能的错误情况,包括实际硬件故障导致的错误情况。某些硬件错误情况可能难于引发,但如有可能,应尽力强制引发或模拟此类错误。在实际使用时,所有这些情况都有可能遇到。为了测试以找出这些错误的根源,应该拆除或松开电缆、拆除板以及编写错误的用户应用程序代码。另请参见第 13 章


注意 – 注意 –

测试时,请务必采取正确的电气预防措施。


测试装入和卸载

由于没有装入或卸载的驱动程序会导致意外的停机时间,因此必须全面测试装入和卸载。

与以下示例类似的脚本应该足够满足要求:

#!/bin/sh
cd <location_of_driver>
while [ 1 ]
do
    modunload -i 'modinfo | grep " <driver_name> " | cut -cl-3' &
    modload <driver_name> &
done

压力、性能和互操作性测试

为有助于确保驱动程序正常执行,应对该驱动程序进行强有力的压力测试。例如,通过驱动程序运行单个线程并不会测试必须等待的锁定逻辑或条件变量。设备操作应由多个进程同时执行,以使几个线程同时执行同一代码。

执行同时测试的方法取决于驱动程序。某些驱动程序需要使用特殊的测试应用程序,而在后台启动多个 UNIX 命令适用于其他驱动程序。正确的测试取决于特定驱动程序在何处使用锁定和条件变量。在多处理器计算机上测试驱动程序比在单处理器计算机上测试更有可能暴露问题。

此外,还必须测试驱动程序之间的互操作性,尤其是在不同的设备可以共享中断级别的情况下。如有可能,请配置与正在测试的设备的中断级别相同的另一个设备。压力测试可以确定驱动程序是否正确请求其自己的中断,以及是否按照预期目标运行。应该对两个设备同时运行压力测试。即使设备不共享中断级别,该测试仍然很重要。例如,假设在测试某个网络驱动程序时,串行通信设备遇到错误。同一问题也可能会导致系统的其余部分遇到中断延迟问题。

这些压力测试下的驱动程序性能应使用 UNIX 性能度量工具进行度量。此类测试与使用 time(1) 命令以及压力测试所用命令一样简单。

DDI/DKI 兼容性测试

为确保与更高发行版的兼容性以及对当前发行版的可靠支持,每个驱动程序都应该与 DDI/DKI 兼容。检查是否仅使用了《man pages section 9: DDI and DKI Kernel Functions》《man pages section 9: DDI and DKI Driver Entry Points》中的内核例程以及《man pages section 9: DDI and DKI Properties and Data Structures》中的数据结构。

安装和打包测试

驱动程序是以软件包形式提供给客户的。使用标准机制,可在系统中添加或删除软件包(请参见《应用程序包开发者指南》)。

应对用户在系统中添加或删除软件包的能力进行测试。测试时,应从供发行使用的每种类型的介质中安装和删除软件包。该测试应该包含多种系统配置。对于目标系统的目录环境,软件包不能做出任何无根据的假设。但是,可以对标准内核文件的保留位置做出某些有效假设。此外,还要在新安装的、尚未修改开发环境的计算机上测试软件包的添加和删除。常见的打包错误是软件包依赖于仅在开发时使用的工具或文件。例如,在驱动程序安装程序中,不应使用源兼容性软件包 SUNWscpu 中的任何工具。

驱动程序安装必须在不带任何可选软件包的最小 Solaris 系统上测试。

测试特定类型驱动程序

本节提供了一些有关如何测试某些类型的标准设备的建议。

磁带驱动程序

磁带驱动程序应通过执行多次归档和恢复操作来测试。cpio(1)tar(1) 命令可用于此目的。使用 dd(1M) 命令可将整个磁盘分区写入磁带。接下来,读回数据,并将数据写入另一个相同大小的分区。然后比较这两个副本。mt(1) 命令可以执行特定于磁带驱动程序的大多数 I/O 控制。请参见 mtio(7I) 手册页。尝试使用所有选项。以下三种方法可以测试磁带驱动程序的错误处理能力:

磁带驱动程序通常实现以独占方式访问的 open(9E) 调用。可以通过打开设备,然后让另一个进程尝试打开同一设备,来测试这些 open() 调用。

磁盘驱动程序

磁盘驱动程序应在原始设备模式和块设备模式下进行测试。对于块设备测试,请在设备上创建一个新的文件系统。然后,尝试挂载该新文件系统,并尝试执行多种文件操作。


注 –

文件系统使用页缓存,因此重复读取相同文件实际上并不会执行驱动程序。通过使用 mmap(2) 对文件进行内存映射,可以强制页缓存从设备中检索数据。然后使用 msync(3C) 使内存中的副本无效。


将另一个相同大小的(未挂载)分区复制到原始设备。然后使用 fsck(1M) 之类的命令检验副本的正确性。 新分区也可以挂载,然后以后与旧分区进行逐文件比较。

异步通信驱动程序

通过为串行端口设置一个 login 连接线,可对异步驱动程序进行基本级别的测试。是否为一种较好的测试方法要看用户是否可以通过此连接线登录。但是,要充分测试异步驱动程序,必须使用多个高速中断来测试所有 I/O 控制函数。涉及回送串行电缆和较高数据传输速率的测试有助于确定驱动程序的可靠性。您可以在该连接线上运行 uucp(1C),以提供某些实践。但是,由于 uucp 执行其自己的错误处理,因此请验证驱动程序不会报告 uucp 进程的额外的错误数。

这些类型的设备通常是基于 STREAMS 的。有关更多信息,请参见《STREAMS Programming Guide》

网络驱动程序

可以使用标准网络实用程序对网络驱动程序进行测试。由于可在网络的每个端点上比较文件,因此 ftp(1)rcp(1) 命令非常有用。该驱动程序应在网络负载较重的情况下测试,以便多个进程可以运行各种命令。

网络负载较重包括以下情况:

执行测试时,应拔下网络电缆,以确保驱动程序可从产生的错误情况中正常恢复。另一项重要测试是让驱动程序快速连续接收多个包,即背对背包。在这种情况下,负载较轻的网络上相对较快的主机应向测试计算机快速连续发送多个包。请检验接收驱动程序不会丢弃第二个以及后续的包。

这些类型的设备通常是基于 STREAMS 的。有关更多信息,请参见《STREAMS Programming Guide》