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 在家中处理了太多机器。