                          EISA バスサポート

                Marc Zyngier <maz@wild-wind.fr.eu.org>


この文書群は、新しい EISA/sysfs API への EISA ドライバ移植に関するラン
ダムノートです。

バージョン 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;           /* ブリッジデバイスへのポインタ */
          struct resource *res;
          unsigned long    bus_base_addr;
          int              slots;         /* 最大スロット数 */
          int              force_probe;   /* スロット 0 がなくてもプローブする */
          u64              dma_mask;      /* ブリッジデバイスから */
          int              bus_nr;        /* eisa_root_register によりセットされる */
          struct resource  eisa_root_res; /* 同上 */
  };

  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      : ヌルで終端された EISA ID 文字列の配列であり、最後は
                  空文字列。各文字列は、ドライバ依存の値 (driver_data)
                  と任意で組にすることができます。

  driver        : Documentation/driver-model/driver.txt で説明されて
                  いる汎用ドライバ。.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 eisa_device' 内にある 'struct 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; /* 汎用デバイス */
  };

  id       : デバイスから読みとる EISA ID. id.driver_data は、対応する
             ドライバ EISA ID をもとにセットされます。
  slot     : デバイスが検出されたスロットの番号
  state    : デバイスの状態を示すフラグのセット。現在のフラグは
             EISA_CONFIG_ENABLED と EISA_CONFIG_FORCED.
  res      : このデバイスに割り当てられた 4 つの 256 バイト I/O リー
             ジョンのセット
  dma_mask : 親デバイスから引き継いだ DMA マスク
  dev      : 汎用デバイス (Documentation/driver-model/device.txt 参照)

'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 以上 EISA_MAX_RESOURCES
    未満)。


カーネルパラメータ
------------------

  eisa_bus.enable_dev :

    有効にするスロットをカンマ区切りでリストしたもの。ファームウェアが
    カードを無効にしている場合でも有効にします。ドライバは、そのような
    状況の場合にも、適切にデバイスを初期化できなければなりません。

  eisa_bus.disable_dev :

    無効にするスロットをカンマ区切りでリストしたもの。ファームウェアが
    カードを有効にしている場合でも無効にします。このデバイスを操作する
    ために当該ドライバが呼ばれることはありません。

  virtual_root.force_probe :

    EISA 準拠のメインボードを発見できない場合でも (スロット 0 に何も
    ない場合でも)、プローブコードに強制的に EISA スロットをプローブ
    させます。デフォルトは 0 (強制しない) ですが、CONFIG_ALPHA_JENSEN
    もしくは CONFIG_EISA_VLB_PRIMING がセットされている場合は、1 (プ
    ローブを強制) にセットされます。


ランダムノート
--------------

EISA ドライバを新しい API に変更する作業は、ほとんどの場合、コードの
「削除」がおこなわれます (現在はコア EISA コードにプローブコードが存在
するからです)。残念ながら、ほとんどのドライバは、ISA, MCA, EISA 間で
自身のプローブルーチンを共有しています。これらの局所的な変更が他のバス
に影響を与えることがないよう、EISA コードを取り除くときには特別な注意が
必要です。

eisa_driver_register から戻ったときに何らかの EISA デバイスが検出されて
いることを期待しては「いけません」。というのは、バス自体がまだプローブ
されていない可能性があるからです。事実、たいていの場合はそうです (バス
ルートドライバは通常、どちらかというとブートプロセスのあとのほうで動作
し始めます)。残念ながら、ほとんどのドライバは自分でプローブをおこなって
おり、自らのプローブルーチンから抜けるときにはマシン全体を調べ終わって
いるものと期待しています。

例えば、お好みの EISA SCSI カードを「ホットプラグ」モデルに切り替える
ことは、"the right thing"(tm) です。(訳注："right thing" には、「でも、
正常な人ならそんなことはしないけどね」、というニュアンスもあります。
http://www.catb.org/~esr/jargon/html/R/Right-Thing.html を参照のこと)


謝辞
----

ご協力していただいたことに対して、次の方々に感謝したいと思います。

  - Xavier Benigni : 素晴らしい Alpha Jensen を私に貸してくれました。
  - James Bottomley, Jeff Garzik : これをカーネルに取り込んでくれました。
  - Andries Brouwer : 多数の EISA ID を提供してくれました。
  - Catrin Jones : 自宅で非常にたくさんのマシンに対応してくれました。

------------------------------------------------------------
翻訳団体： JF プロジェクト < http://www.linux.or.jp/JF/ >
翻訳日：   2004/05/23
翻訳者：   川崎 貴彦 <takahiko(a)hakubi.co.jp>
