EISA 总线支持¶
- 作者:
Marc Zyngier <maz@wild-wind.fr.eu.org>
本文档汇总了关于将 EISA 驱动程序移植到新的 EISA/sysfs API 的随机说明。
从 2.5.59 版本开始,EISA 总线几乎与 PCI 或 USB 等其他更主流的总线具有相同的地位。这通过 sysfs 实现,sysfs 定义了一组不错的抽象来管理总线、设备和驱动程序。
虽然新的 API 使用起来非常简单,但将现有驱动程序转换为新的基础结构并非易事(主要是因为检测代码通常也用于探测 ISA 卡)。此外,大多数 EISA 驱动程序都是最古老的 Linux 驱动程序之一,所以,您可以想象,多年来这里已经积累了一些灰尘。
EISA 基础结构由三部分组成
总线代码实现了大部分通用代码。它在 EISA 代码运行的所有架构之间共享。它实现了总线探测(检测总线上可用的 EISA 卡)、分配 I/O 资源、允许通过 sysfs 进行花式命名,并为驱动程序提供注册接口。
总线根驱动程序实现了总线硬件和通用总线代码之间的粘合。它负责发现实现总线的设备,并设置它以便以后由总线代码探测。这可以简单到在 x86 上保留一个 I/O 区域,到更复杂的,例如 hppa EISA 代码。这是为了让 EISA 在“新”平台上运行而需要实现的部分。
驱动程序为总线提供它管理的设备列表,并实现必要的 callbacks 以在被告知时探测和释放设备。
下面的每个函数/结构都位于 <linux/eisa.h> 中,它严重依赖 <linux/device.h>。
总线根驱动程序¶
int eisa_root_register (struct eisa_root_device *root);
eisa_root_register 函数用于将设备声明为 EISA 总线的根。eisa_root_device 结构保存对该设备的引用,以及用于探测的一些参数
struct eisa_root_device {
struct device *dev; /* Pointer to bridge device */
struct resource *res;
unsigned long bus_base_addr;
int slots; /* Max slot number */
int force_probe; /* Probe even when no slot 0 */
u64 dma_mask; /* from bridge device */
int bus_nr; /* Set by eisa_root_register */
struct resource eisa_root_res; /* ditto */
};
node |
用于 eisa_root_register 内部目的 |
dev |
指向根设备的指针 |
res |
根设备 I/O 资源 |
bus_base_addr |
此总线上插槽 0 的地址 |
slots |
要探测的最大插槽号 |
force_probe |
即使插槽 0 为空(没有 EISA 主板)也进行探测 |
dma_mask |
默认 DMA 掩码。通常是桥接设备的 dma_mask。 |
bus_nr |
唯一的总线 ID,由 eisa_root_register 设置 |
驱动程序¶
int eisa_driver_register (struct eisa_driver *edrv);
void eisa_driver_unregister (struct eisa_driver *edrv);
足够清楚吗?
struct eisa_device_id {
char sig[EISA_SIG_LEN];
unsigned long driver_data;
};
struct eisa_driver {
const struct eisa_device_id *id_table;
struct device_driver driver;
};
id_table |
一个以 NULL 结尾的 EISA ID 字符串数组,后跟一个空字符串。每个字符串可以选择与驱动程序相关的值(driver_data)配对。 |
driver |
一个通用驱动程序,如设备驱动程序中所述。只有 .name、.probe 和 .remove 成员是强制性的。 |
例如,3c59x 驱动程序
static struct eisa_device_id vortex_eisa_ids[] = {
{ "TCM5920", EISA_3C592_OFFSET },
{ "TCM5970", EISA_3C597_OFFSET },
{ "" }
};
static struct eisa_driver vortex_eisa_driver = {
.id_table = vortex_eisa_ids,
.driver = {
.name = "3c59x",
.probe = vortex_eisa_probe,
.remove = vortex_eisa_remove
}
};
设备¶
sysfs 框架在设备发现和移除时调用 .probe 和 .remove 函数(请注意,.remove 函数仅在驱动程序构建为模块时调用)。
这两个函数都传递一个指向 ‘struct device
’ 的指针,该指针封装在如下所述的 ‘struct eisa_device’ 中
struct eisa_device {
struct eisa_device_id id;
int slot;
int state;
unsigned long base_addr;
struct resource res[EISA_MAX_RESOURCES];
u64 dma_mask;
struct device dev; /* generic device */
};
id |
EISA ID,从设备读取。id.driver_data 从匹配的驱动程序 EISA ID 设置。 |
slot |
检测到设备的插槽号 |
state |
指示设备状态的一组标志。当前标志为 EISA_CONFIG_ENABLED 和 EISA_CONFIG_FORCED。 |
res |
分配给此设备的四个 256 字节 I/O 区域集 |
dma_mask |
从父设备设置的 DMA 掩码。 |
dev |
通用设备(请参阅基本设备结构) |
您可以使用 ‘to_eisa_device’ 宏从 ‘struct device
’ 获取 ‘struct eisa_device’。
其他内容¶
void eisa_set_drvdata (struct eisa_device *edev, void *data);
将数据存储到设备的 driver_data 区域中。
void *eisa_get_drvdata (struct eisa_device *edev):
获取先前存储到设备的 driver_data 区域中的指针。
int eisa_get_region_index (void *addr);
返回给定地址的区域号 (0 <= x < EISA_MAX_RESOURCES)。
内核参数¶
- eisa_bus.enable_dev
一个逗号分隔的要启用的插槽列表,即使固件将该卡设置为禁用。驱动程序必须能够在这种情况正确初始化设备。
- eisa_bus.disable_dev
一个逗号分隔的要禁用的插槽列表,即使固件将该卡设置为启用。驱动程序不会被调用来处理此设备。
- virtual_root.force_probe
强制探测代码探测 EISA 插槽,即使它找不到兼容 EISA 的主板(插槽 0 上没有任何显示)。默认为 0(不强制),当设置 CONFIG_EISA_VLB_PRIMING 时设置为 1(强制探测)。
随机说明¶
将 EISA 驱动程序转换为新的 API 主要涉及删除代码(因为探测现在在核心 EISA 代码中)。不幸的是,大多数驱动程序在 ISA 和 EISA 之间共享它们的探测例程。在删除 EISA 代码时必须特别小心,这样其他总线才不会受到这些外科手术的影响……
从 eisa_driver_register 返回时,您不得期望检测到任何 EISA 设备,因为总线很可能尚未被探测。事实上,大多数情况下都是这样(总线根驱动程序通常在启动过程的后期启动)。不幸的是,大多数驱动程序都在自己进行探测,并期望在退出它们的探测例程时已经探索了整个机器。
例如,将您最喜欢的 EISA SCSI 卡切换到“热插拔”模型是“正确的事情”(tm)。
感谢¶
我要感谢以下人员的帮助
Xavier Benigni 借给我一台很棒的 Alpha Jensen,
James Bottomley、Jeff Garzik 将这些东西放入内核,
Andries Brouwer 贡献了许多 EISA ID,
Catrin Jones 在家中处理了太多机器。