FreeBSD为从父总线请求资源提供了一种面向对象的机制。几乎所有设备 都是某种类型的总线(PCI, ISA, USB, SCSI等等)的孩子成员,并且这些设备 需要从他们的父总线获取资源(例如内存段, 中断线, 或者DMA通道)。
为了对PCI设备做些有用的事情,你需要从PCI配置空间获取
Base Address Registers (BARs)。获取BAR时的
PCI特定的细节被抽象在函数bus_alloc_resource()
中。
例如,一个典型的驱动程序可能在attach()
函数中有些类似下面的东西:
每个基址寄存器的句柄被保存在softc
结构中,以便以后可以使用它们向设备写入。
然后就能使用这些句柄与bus_space_*
函数一起
读写设备寄存器。例如,驱动程序可能包含如下的快捷函数,用来读取板子
特定的寄存器:
类似的,可以用下面的函数写寄存器:
这些函数以8位,16位和32位的版本存在,你应当相应地使用
bus_space_{read|write}_{1|2|4}
。
在 FreeBSD 7.0 和更高版本中, 可以用
bus_*
函数来代替
bus_space_*
。
bus_*
函数使用的参数是 struct
resource * 指针, 而不是 bus tag 和句柄。
这样, 您就可以将 softc
中的 bus tag 和 bus 句柄这两个成员变量去掉, 并将
board_read()
函数改写为:
中断按照和分配内存资源相似的方式从面向对象的总线代码分配。首先, 必须从父总线分配IRQ资源,然后必须设置中断处理函数来处理这个IRQ。
再一次,来自设备attach()
函数的例子比文字
更具说明性。
在设备的分离例程中必须注意一些问题。你必须停顿设备的中断流,
并移除中断处理函数。一旦bus_teardown_intr()
返回,你知道你的中断处理函数不会再被调用,并且所有可能已经执行了
这个中断处理函数的线程都已经返回。由于此函数可以睡眠,调用此函数时
你必须不能拥有任何互斥体。
本节已废弃,只是由于历史原因而给出。处理这些问题的适当方法是
使用bus_space_dma*()
函数。当更新这一节以反映
那样用法时,这段就可能被去掉。然而,目前API还不断有些变动,因此一旦
它们固定下来后,更新这一节来反映那些改动就很好了。
在PC上,想进行总线主控DMA的外围设备必须处理物理地址,由于
FreeBSD使用虚拟内存并且只处理虚地址,这仍是个问题。幸运的是,有个
函数,vtophys()
可以帮助我们。
然而这个解决办法在alpha上有点不一样,并且我们真正想要的是一个
称为vtobus()
的函数。
本文档和其它文档可从这里下载: ftp://ftp.FreeBSD.org/pub/FreeBSD/doc/.
如果对于FreeBSD有问题,请先阅读
文档,如不能解决再联系
<questions@FreeBSD.org>.
关于本文档的问题请发信联系
<doc@FreeBSD.org>.