这个函数探测设备是否存在。如果驱动程序支持自动侦测设备配置的 某些部分(如中断向量或内存地址),则自动侦测必须在此例程中完成。
对于任意其他总线,如果不能侦测到设备,或者侦测到但自检失败, 或者发生某些其他问题,则应当返回一个正值的错误。如果设备不 存在则必须返回值 ENXIO。 其他错误值可能表示其他条件。零或负值 意味着成功。大多数驱动程序返回零表示成功。
当PnP设备支持多个接口时使用负返回值。例如,不同驱动程序支持 老的兼容接口和较新的高级接口。则两个驱动程序都将侦测设备。 在探测例程中返回较高值的驱动程序获得优先(换句话说,返回0的 驱动程序具有最高的优先级,返回-1的其次,返回-2的更后,等等)。 这样,仅支持老接口的设备将被老驱动程序处理(其应当从探测例程中 返回-1),而同时也支持新接口的设备将由新驱动程序处理(其应当从 探测例程中返回0)。
设备描述符结构xxx_softc由系统在调用探测例程之前分配。如果
探测例程返回错误,描述符会被系统自动取消分配。因此如果出现
探测错误,驱动程序必须保证取消分配探测期间它使用的所有资源,
且确保没有什么能够阻止描述符被安全地取消分配。如果探测成功
完成,描述符将由系统保存并在以后传递给例程
xxx_isa_attach()
。如果驱动程序返回负值,
就不能保证它将获得最高优先权且其连接例程会被调用。因此这种
情况下它也必须在返回前释放所有的资源,并在需要的时候在连接
例程中重新分配它们。当xxx_isa_probe()
返回0时,在返回前释放资源也是一个好主意,而且中规中矩的驱动
程序应当这样做。但在释放资源会存在某些问题的情况下,允许驱动
程序在从探测例程返回0和连接例程的执行之间保持资源。
典型的探测例程以取得设备描述符和单元号开始:
然后检查PnP设备。检查是通过一个包含PnP ID列表的表进行的。此表 包含这个驱动程序支持的PnP ID和以人工可读形式给出的对应这些ID的 设备型号的描述。
ISA_PNP_PROBE的逻辑如下:如果卡(设备单元)没有被作为PnP侦测到,
则返回ENOENT。如果被作为PnP侦测到,但侦测到的ID不匹配表中的
任一ID,则返回ENXIO。最后,如果设备能支持PnP且匹配表中的一个
ID,则返回0,并且由device_set_desc()
从
表中取得适当的描述进行设置。
如果设备驱动程序仅支持PnP设备,则情况看起来如下:
对于不支持PnP的驱动程序不需要特殊处理,因为驱动程序会传递空的 PnP ID表,且如果在PnP卡上调用会得到ENXIO。
探测例程通常至少需要某些最少量的资源,如I/O端口号,来发现并探测卡。 对于不同的硬件,驱动程序可能会自动发现其他必需的资源。PnP设备的 所有资源由PnP子系统预先设置,因此驱动程序不需要自己发现它们。
通常访问设备所需要的最少信息就是端口号。然后某些设备允许从设备 配置寄存器中取得其余信息(尽管不是所有的设备都这样)。因此首先 我们尝试取得端口起始值:
基端口地址被保存在softc结构中,以便将来使用。如果需要经常使用 端口,则每次都调用资源函数将会慢的无法忍受。如果我们没有得到 端口,则返回错误即可。相反,一些设备驱动程序相当聪明,尝试探测 所有可能的端口,如下:
当然,做这些事情通常应该使用驱动程序的
identify()
例程。但可能有一个正当的理由来
说明为什么在函数probe()
中完成更好:如果
这种探测会让一些其他敏感设备发疯。探测例程按旗标
sensitive
排序:敏感设备首先被探测,然后是
其他设备。但identify()
例程在所有探测之前
被调用,因此它们不会考虑敏感设备并可能扰乱这些设备。
现在,我们得到起始端口以后就需要设置端口数(PnP设备除外),因为 内核在配置文件中没有这个信息。
最后分配并激活一片端口地址空间(特殊值start和end意思是说
“使用我们通过bus_set_resource()
设置的那些值”):
现在可以访问端口映射的寄存器后,我们就可以以某种方式向设备写入 数据并检查设备是否如我们期望的那样作出反应。如果没有,则说明 可能其他的设备在这个地址上,或者这个地址上根本没有设备。
通常驱动程序直到连接例程才会设置中断处理函数。这之前我们替代以
轮询模式进行探测,超时则以DELAY()
实现。
探测例程必须确保不能永久挂起,设备上的所有等待必须在超时内完成。
如果设备不在这段时间内响应,则可能设备出故障或配置错误,驱动程序
必须返回错误,当确定超时间隔时,给设备一些额外时间以确保可靠:
尽管假定DELAY()
在任何机器上都延时相同数量的
时间,但随具体CPU的不同,此函数还是有一定的误差幅度。
如果探测例程真的想检查中断是否真的工作,它可以也配置和探测中断。 但不建议这样。
依赖于所发现设备的确切型号,函数
xxx_probe_ports()
也可能设置设备描述。但
如果只支持一种设备型号,则也可以硬编码的形式完成。当然,对于
PnP设备,PnP支持从表中自动设置描述。
探测例程应当或者通过读取设备配置寄存器来发现所有资源的范围, 或者确保由用户显式设置。我们将假定一个带板上内存的例子。 探测例程应当尽可能是非插入式的,这样分配和检查其余资源功能性 的工作就可以更好地留给连接例程来做。
内存地址可以在内核配置文件中指定,或者对应某些设备可以在非易失性 配置寄存器中预先配置。如果两种做法均可用却不同,那么应当用 哪个呢?可能用户厌烦在内核配置文件中明确设置地址,但他们知道 自己在干什么,则应当优先使用这个。一个实现的例子可能是这样的:
类似, 很容易检查IRQ和DRQ所用的资源。
如果一切进行正常,然后就可以释放所有资源并返回成功。
最后,处理棘手情况。所有资源应当在返回前被释放。我们利用这样一个 事实:softc结构在传递给我们以前被零化,因此我们能够找出是否分配了 某些资源:如果分配则这些资源的描述符非零。
这是完整的探测例程。资源的释放从多个地方完成,因此将它挪到一个 函数中,看起来可能像下面的样子:
本文档和其它文档可从这里下载: ftp://ftp.FreeBSD.org/pub/FreeBSD/doc/.
如果对于FreeBSD有问题,请先阅读
文档,如不能解决再联系
<questions@FreeBSD.org>.
关于本文档的问题请发信联系
<doc@FreeBSD.org>.