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 而需要实现的部分。

  • 驱动程序为总线提供它管理的设备列表,并实现必要的回调来探测和释放设备(如果被告知)。

下面的每个函数/结构都位于 <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 在家里处理了太多的机器。