Linux PCMCIA プログラマの手引き David Hinds, dhinds@allegro.stanford.edu v1.35, 1997/11/14 08:25:25 Kazuyuki Okamoto, ikko-@pacific.rim.or.jp Hiroshi Kawashima (kei@sm.sony.co.jp) Hiro Sugawara, hiro@arkusa.com JF project v1.35, 1997/12/11 01:00:00 この文書は Linux PCMCIA カードサービスインターフェースの為のカーネルデ バイスドライバの書き方を説明しています。また、カードサービスの利用者用 ユーティリティの書き方も説明します。この文書(text,html,sgml) の最新は hyper.stanford.edu の /pub/pcmcia/doc にあります。 HTML 版は http://hyper.stanford.edu/HyperNews/get/pcmcia/home.html にあります。 ______________________________________________________________________ 目次 1. 概説 1.1 著作権表示と放棄声明 1.2 謝辞 2. 基本的な PCMCIA の概念 2.1 PCMCIA ソケットインタフェース 2.2 PCMCIA ソケット制御装置 3. カードサービス関数解説 3.1 クライアント管理関数 3.1.1 RegisterClient 3.1.2 DeregisterClient 3.1.3 SetEventMask 3.1.4 BindDevice 3.2 ソケット状態管理 3.2.1 GetStatus 3.2.2 ResetCard 3.2.3 SuspendCard 3.2.4 ResumeCard 3.2.5 EjectCard 3.2.6 InsertCard 3.3 入出力カードの設定関数 3.3.1 RequestIO 3.3.2 ReleaseIO 3.3.3 RequestIRQ 3.3.4 ReleaseIRQ 3.3.5 RequestConfiguration 3.3.6 ModifyConfiguration 3.3.7 ReleaseConfiguration 3.3.8 GetConfigurationInfo 3.4 カード情報構造体 (CIS) 使用法 3.4.1 GetFirstTuple, GetNextTuple 3.4.2 GetTupleData 3.4.3 ParseTuple 3.4.4 ValidateCIS 3.5 メモリ領域制御 3.5.1 RequestWindow 3.5.2 ModifyWindow 3.5.3 MapMemPage 3.5.4 ReleaseWindow 3.6 大容量メモリサービス 3.6.1 RegisterMTD 3.6.2 GetFirstRegion, GetNextRegion 3.6.3 OpenMemory 3.6.4 CloseMemory 3.6.5 ReadMemory, WriteMemory 3.6.6 RegisterEraseQueue 3.6.7 DeregisterEraseQueue 3.6.8 CheckEraseQueue 3.7 各種呼び出し 3.7.1 GetCardServicesInfo 3.7.2 AccessConfigurationRegister 3.7.3 AdjustResourceInfo 3.7.4 ReportError 4. カード情報構造体 (CIS) の定義 4.1 CIS タプルの定義 4.1.1 CISTPL_CHECKSUM 4.1.2 CISTPL_LONGLINK_A, CISTPL_LONGLINK_C, CISTPL_LINKTARGET, CISTPL_NOLINK 4.1.3 CISTPL_LONGLINK_MFC 4.1.4 CISTPL_DEVICE, CISTPL_DEVICE_A 4.1.5 CISTPL_VERS_1 4.1.6 CISTPL_ALTSTR 4.1.7 CISTPL_JEDEC_C, CISTPL_JEDEC_A 4.1.8 CISTPL_CONFIG 4.1.9 CISTPL_CFTABLE_ENTRY 4.1.10 CISTPL_MANFID 4.1.11 CISTPL_FUNCID 4.1.12 CISTPL_DEVICE_GEO 4.1.13 CISTPL_VERS_2 4.1.14 CISTPL_ORG 4.2 CIS 構成レジスタ 4.2.1 Configuration Option Register 4.2.2 カードの構成情報と状態レジスタ 4.2.3 ピン代替レジスタ 4.2.4 ソケットとコピーレジスタ 4.2.5 拡張状態レジスタ 5. カードサービスイベントの扱いについて 5.1 イベントハンドラの操作 5.2 イベントの説明 5.3 クライアントドライバのイベント操作の役割について 6. メモリテクノロジドライバ 6.1 MTD 要求の処理 6.2 MTD 支援関数 6.2.1 MTDRequestWindow, MTDReleaseWindow 6.2.2 MTDModifyWindow 6.2.3 MTDSetVpp 6.2.4 MTDRDYMask 7. ドライバサービスインタフェース 7.1 他のクライアントドライバへのインタフェース 7.1.1 dev_link_t 構造体 7.1.2 register_pcmcia_driver 7.1.3 unregister_pcmcia_driver 7.2 ユーザモードの PCMCIA ユティリティとのインタフェース 7.2.1 カードサービスのイベント通知 7.2.2 ioctl の説明 8. カードサービスクライアントドライバの解剖 8.1 モジュールの初期化とリセット 8.2 *_attach() と *_detach() 関数 8.3 *_config() と *_release() 関数 8.4 PCMCIA イベントハンドラ 8.5 ロックと同期について 8.6 現有の Linux のドライバで PCMCIA デバイスをアクセスする方法 9. さらなる情報はどこにあるか? ______________________________________________________________________ 1. 概説 Linux Kernel PCMCIA システムは 3 つの部分に分かれています。最下位のイ ンターフェースはソケットドライバです。次はカードサービスモジュールで す。特定のカード用のドライバはカードサービスの上位に位置しています。あ る特定のカードサービスクライアントはドライバサービスと呼ばれ、利用者用 PCMCIA ユーティリティとカーネル PCMCIA 機能との間を結びます。 ソケットドライバ層はソケットサービス API を大体利用しています。 2 つの ソケットドライバモジュールがあります。tcic モジュールは PCMCIA コント ローラの TCIC-2 系列のデータブックをサポートしています。i82365 モジュ ールは Intel i82365sl 系列と Cirrus, VLSI, Ricoh, Vadem チップのインテ ル互換のコントローラをサポートしています。 カードサービスは PCMCIA パッケージの最も大きな単独の構成要素です。この サービスの API は DOS のカードサービスと似ており Unix 環境に適応してい ます。Linux への実装は Solaris PCMCIA のインターフェース仕様に準拠して います。この仕様は pcmcia_core モジュールに実装しています。バージョン 2.1 の殆んどといくつかの PC Card 95 の仕様を実装しました。 ドライバサービス層は PCMCIA ユーティリティから呼ばれるいくつかのカード サービス関数をアクセスする利用者用疑似ドライバとして実装しています。こ の実装は全ての PCMCIA クライアントドライバを見失わないようにするのと、 物理ソケットとドライバを引き当てるのを確実にしています。ds モジュール 内に実装しています。 この文書はカードサービスとドライバサービスモジュールとドライバサービス へのユーザインターフェースのカーネルインターフェースについて説明してい ます。PCMCIA デバイスドライバの開発者の為に書いています。 Linux PCMCIA-HOWTO はどのように導入するかと Linux で PCMCIA をどのように使う かについて説明しています。この文書は cb-iris.stanford.edu の /pub/pcmcia にあります。 1.1. 著作権表示と放棄声明 Copyright (c) 1996, 1997 David A. Hinds この文書は著者の許可なしに如何なる形で複写または配布してかまいません。 この文書を他の言語に翻訳など変更したものを含んで、変更点を明確に名乗っ て、この著作権表示をそのままに添付して自由に配布してください。 私の同意無しに商用配布に利用可能です。必須ではありませんが、商用利用に あたり、私に通知して下さい。出版物に統合したいと思っている場合、最新の ものを使う必要がありますので私に連絡して下さい。 この文書は明示的または暗黙的保証無しに``ありのまま''提供しています。こ の文書にある情報は御自身の責任で利用して下さい。 1.2. 謝辞 この PCMCIA ソフトウェアとドライバの開発のテストとデバッグを手伝ってく れた Linux ユーザの皆さんに感謝したいと思います。そしてカーネル開発を 助けてくれた Linus Torvalds, Donald Becker, Alan Cox, と Bjorn Ekwall に感謝します。特に Solaris PCMCIA の実装について多くの助言となった打ち 合せを行なった Michael Bender に感謝します。 2. 基本的な PCMCIA の概念 2.1. PCMCIA ソケットインタフェース PCMCIA カードバスには 2 つの基本操作モードがあります。それは ``メモリ のみ''と``メモリと入出力''です。最初のモードは元々の第 1 版の仕様で定 義されて単にメモリカードをサポートするものでした。次のモードは第 2 版 で定義され、少しのメモリカードの制御信号が IO ポートと入出力割り込み信 号を扱えるように再定義しています。 PCMCIA カードは 2 つのメモリ空間があります。それは``属性メモリ''と ``一般メモリ''です。PCMCIA インタフェースはそれぞれの形式のメモリの 16MB 以上のメモリを使えます。属性メモリは一般に種類の情報や構成するレ ジスタを保持するのに使用します。一般メモリはメモリカードの殆んどの領域 か IO カードの場合はバッファ領域に使用します。PCMCIA 仕様 第2版に適合 している全てのカードはカードがどのように構成されているかのカード情報構 造(Card Information Structure (つまり ``CIS'')) を属性メモリに格納しま す。 カードは分離制御信号を使って操作状況をホストに知らせます。この制御信号 はカードの探知、レディ/ビジー状態、書き込み保護、電池不足と電池切れで 構成しています。 ``メモリと入出力''型のインターフェースモードのカードは 64K 以上の入出 力ポートにアクセスできます。このモードでは入出力割り込みとカードの出力 をホストシステムのスピーカへの経路を提供します。このモードではいくつか のメモリカード制御信号は特別な入出力カード信号を伝達するのにこれらのピ ンを使っているので使用できません。いくつかのカードでは制御信号を属性メ モリから特別な構成レジスタを読み出す代わりに用います。これを``ピン代替 レジスタ''型のカードと呼びます。 2.2. PCMCIA ソケット制御装置 PCMCIA 制御装置を PCMCIA カードとシステムバスの間の橋渡しをします。制 御装置にはいくつかの種類がありますが、基本機能は同じです。ソケットサー ビス層は PCMCIA 制御装置を如何に扱うかの詳細を処理しています。 PCMCIA 制御装置はホストメモリのジョブ空間と入出力空間のアドレス領域と カードのアドレス領域の割りつけを行ないます。全ての制御装置は最低 4つの 独立したメモリ領域と2つの入出力領域をソケット毎に持っています。 それぞれのメモリ領域はホストアドレス空間の基底アドレス、カード空間の基 底アドレスとその領域の大きさで定義されます。いくつかの制御装置ではメモ リ領域の境界調整に違いがありますが、全ての制御装置は最低 4K 、且つその 2 のべき乗の大きさのメモリ領域と基底アドレスで領域の倍数の大きさの領域 をサポートしています。それぞれの領域を属性メモリか一般メモリを指すよう にプログラム出来ます。 ホストアドレス上の入出力領域のアドレスがカード上に渡っても変更されない 事がメモリ領域と異なっています。実際に、ホストとカードの領域の基底アド レスはいつも同じです。入出力領域は通常、境界調整が無いか大きさの制限は ありません。入出力領域の境界の始点と終点は 64K 内のバイト境界です。 PCMCIA カードバスはカードから制御装置への一つの割り込み信号を定義しま す。制御装置はこの時適切なインラプト要求(IRQ) を操る役目を負います。全 ての制御装置はカード入出力割り込みを空いている割り込みに割り当てます。 従って制御装置はカード自身どの割り込みを使うか事前には分かりません。 全ての PCMCIA 制御装置はカードが返す状態変更の割り込みを生成します。こ の割り込みは入出力カードが生成した入出力割り込みと区別され、別の割り込 み線を使います。この信号はカードの検知、レディ/ビジー、書き込み保護、 電池不足、電池切れを含んでいます。 3. カードサービス関数解説 カードサービスは一般に次の形で呼びます。: #include "cs_types.h" #include "cs.h" int CardServices(int subfunc, void *arg1, void *arg2, ...); いくつかのカードサービス関数は #include 文を追加する必要があります。特 殊な下位の関数は引数の数を認識します。CS_SUCCESS の戻り値は呼出が成功 した事を示しています。その他の戻り値は失敗を示しています。 3.1. クライアント管理関数 カードサービス関数を使うデバイスドライバを``クライアント''と呼びます。 デバイスドライバは他のサービスを使用する前に RegisterClient を呼び出し てクライアントハンドルを取得しなければいけません。カードを抜く前にドラ イバを DeregisterClient を使用して抹消する必要があります。 3.1.1. RegisterClient int CardServices(RegisterClient, client_handle_t *client, client_reg_t *reg); client_reg_t データ構造体の定義は次のとおり: typedef struct client_reg_t { dev_info_t *dev_info; u_long Attributes; u_long EventMask; int (*event_handler)(event_t event, int priority, event_callback_args_t *args); event_callback_args_t event_callback_args; u_long Version; } client_reg_t; RegisterClient はクライアントドライバとカードサービスの結合を確立しク ライアントに適切なソケットを接続します。 dev_info パラメタはソケットと 関数をクライアントに合わせるのにカードサービスが使います。この対応を BindDevice を呼ぶ事を通してドライバサービスによって確立します。対応が 確立したら、クライアントハンドルが client に返ります。 次のフラグが属性に指定できます。: INFO_MASTER_CLIENT ドライバサービスクライアントだけが使用します。他に、ソケットから カードを抜いた時はクライアントが自動でなく解放しなければいけませ ん。 INFO_IO_CLIENT クライアントが入出力カードドライバの場合に指定します。 INFO_MEM_CLIENT クライアントがメモリテクノロジドライバの場合に指定します。 INFO_MEM_CLIENT クライアントがメモリカードドライバの場合に指定します。 INFO_CARD_SHARE 互換性の為に入っています。何もしません。 INFO_CARD_EXCL 互換性の為に入っています。何もしません。 EventMask はクライアントに何が起こっているか通知する時に指定します。 event_handler の項目は EventMask で処理されるとカードサービスによって 呼ばれます。event_handler_args 構造体はイベントハンドラに渡される構造 体の雛型 (テンプレートr) です。Version パラメタはこのドライバが要求す るカードサービスのバージョンレベルを示します。これは現在無視されます。 ドライバが RegisterClient を呼び出す前にカードサービスを扱う準備を行な う必要があります。この呼び出しはいつも CS_REGISTRATION_COMPLETE イベン トを生成し、ソケットが現在使用している場合は、わざと CS_CARD_INSERTION イベントを生成します。 戻り値 : CS_OUT_OF_RESOURCE ドライバに必要な適切なドライバが見つかりません。 3.1.2. DeregisterClient int CardServices(DeregisterClient, client_handle_t client); DeregisterClient はクライアントとカードサービスの連結を行ないます。ク ライアントが割り当てられたリソースを解放した後で呼びます。連結が切れた ら、BindDevice を他のクライアントが呼ぶまで再確立出来ません。 戻り値 : CS_BAD_HANDLE クライアントハンドルが無効です。 CS_IN_USE クライアントに入出力ポート領域や割り込みなどのリソースが割り当て られているかソケット構成がロックされています。 3.1.3. SetEventMask int CardServices(SetEventMask, client_handle_t client, eventmask_t *mask); eventmask_t 構造体の定義は次のとおり: typedef struct eventmask_t { u_long Attributes; u_long EventMask; } eventmask_t; SetEventMask はクライアントに通知されたイベントを認識するようにマスク を更新します。 戻り値 : CS_BAD_HANDLE クライアントハンドルが無効です。 3.1.4. BindDevice int CardServices(BindDevice, bind_req_t *req); bind_req 構造体の定義は次のとおり: typedef struct bind_req_t { socket_t Socket; u_char Function; dev_info_t *dev_info; } bind_req_t; BindDevice でデバイスドライバと適切なソケットを関係づけます。通常、新 規に挿入されたカードが認識できた後でデバイスサービスから呼ばれます。一 旦、ドライバがソケットと接続されると、そのソケットのクライアントととし てドライバを登録するのに適格でしょう。この呼び出しは引数がクライアント ハンドルではないことに注意して下さい。カードサービス呼び出しだけはソ ケット番号を引数に用いています。 Function 変数はドライバに結合したい多機能カードのうちの機能 (複数可 ) を指定します。Function 番号はカードの CISTPL_LONGLINK_MFC タプルに相当 します。Function を BIND_FN_ALL に設定した場合は、ドライバはカードの全 ての機能を接続します。ドライバは CIS タプルに相当する機能に接続する事 だけが可能です。 戻り値 : CS_BAD_SOCKET 指定したソケット番号は無効です。 3.2. ソケット状態管理 これらの関数は多かれ少なかれ現在のソケットの状態の獲得と設定に関与して います。GetStatus は現在のソケット状態を返します。ResetCard はハードリ セット信号をソケットに送ります。SuspendCard と ResumeCard は電源オフと 電源オンを現在接続しているドライバを切り離す事なしに行ないます。 EjectCard と InsertCard は本質的に実際にカードの排出と挿入イベントを真 似します。 3.2.1. GetStatus int CardServices(GetStatus, client_handle_t client, status_t *status); status_t データ構造体の定義は次のとおり: typedef struct status_t { u_char Function; u_long CardState; u_long SocketState; } status_t; GetStatus はクライアントのソケットの現在の状態を返します。入出力モード に設定されているカードでは、GetStatus はピン代替レジスタと拡張状態レジ スタをカード状態を認識するのに使っています。通常のクライアントには Function 変数は無視されますが、 BIND_FN_ALL を指定しているクライアント ではこの変数で指定した機能の構成レジスタでソケット状態を決定するのに使 用します。 CardState には次のフラグを定義しています。: CS_EVENT_CARD_DETECT 指定したソケットを使用します。 CS_EVENT_WRITE_PROTECT 指定したカードを書き込み禁止にしました。 CS_EVENT_BATTERY_LOW 指定したカードの電池が不足しました。 CS_EVENT_BATTERY_DEAD 指定したカードは電池切れです。 CS_EVENT_READY_CHANGE 指定したカードは準備完了です。 CS_EVENT_PM_SUSPEND 指定したソケットは停止しました。 CS_EVENT_REQUEST_ATTENTION 指定した拡張状態レジスタ内の要求命令ビットを設定しました。 SocketState は現在使われていませんが、原則的には CardState の状態変数 の中に組み込まれていくでしょう。 戻り値 : CS_BAD_HANDLE クライアントハンドルは無効です。 3.2.2. ResetCard int CardServices(ResetCard, client_handle_t client); ResetCard はクライアントのソケットのリセットを要求します。この呼び出し が発生した時、カードサービスは全てのクライアントに CS_EVENT_RESET_REQUEST イベントを送ります。クライアントがこの要求を拒 否した場合は、カードサービスクライアントを初期化する為に CS_EVENT_RESET_COMPLETE イベントを event_callback_args.info にクライア ントの要求拒否の返り値を設定してクライアントに送ります。 全てのクライアントがこの要求に同意すると、カードサービスは CS_EVENT_RESET_PHYSICAL イベントを送り、ソケットをリセットします。ソ ケット信号が準備完了になると、CS_EVENT_CARD_RESET イベントを生成しま す。最後に CS_EVENT_RESET_COMPLETE イベントを event_callback_args.info にゼロを設定して初期化するクライアントに送ります。 戻り値 : CS_BAD_HANDLE クライアントハンドルは無効です。 CS_NO_CARD クライアントに割り付けたソケットは現在使われていません。 CS_IN_USE ソケットは現在リセットしています。 3.2.3. SuspendCard int CardServices(SuspendCard, client_handle_t client); カードサービスは全てのクライアントに CS_EVENT_PM_SUSPEND イベントを送 ります。ソケットをシャットダウンと電源オフさせます。 戻り値 : CS_BAD_HANDLE クライアントハンドルは無効です。 CS_NO_CARD クライアントに割り付けたソケットは現在使われていません。 CS_IN_USE ソケットは既に中止しています。 3.2.4. ResumeCard int CardServices(ResumeCard, client_handle_t client); ソケットが電源オフした後、カードサービスは全てのクライアントに CS_EVENT_PM_RESUME イベントを送ります。 戻り値 : CS_BAD_HANDLE クライアントハンドルは無効です。 CS_NO_CARD クライアントに割り付けたソケットは現在使われていません。 CS_IN_USE ソケットは既に中止しています。 3.2.5. EjectCard int CardServices(EjectCard, client_handle_t client); カードサービスは全てのクライアントに 排出 (イジェクト) イベントを送り ます。ソケットをシャットダウンと電源オフさせます。全てのクライアントが ドライバサービスがソケットを切り離す為にイベントを受け取ります。 戻り値 : CS_BAD_HANDLE クライアントハンドルは無効です。 CS_NO_CARD クライアントに割り付けたソケットは現在使われていません。 3.2.6. InsertCard int CardServices(InsertCard, client_handle_t client); カードサービスは挿入イベントを全てのソケットのクライアントに送ります。 (通常、ドライバサービス限定です) 戻り値 : CS_BAD_HANDLE クライアントハンドルは無効です。 CS_NO_CARD クライアントに割り付けたソケットは現在使われていません。 CS_IN_USE ソケットは既に設定しています。 3.3. 入出力カードの設定関数 普通のイベントの順番はドライバ用に入出力ポートと RequestIO と RequestIR を呼び出して割り込み線を予約します。そして、 RequestConfiguration を呼び出して実際のソケットを設定します。これらの 呼び出しに失敗したら、うまく予約ができるようにリソースを解放するように ドライバを確認して下さい。 多機能カードはそれぞれの機能を分離して設定しましょう。しかしながら他の 機能と調和している必要があります。それぞれのカード機能はその自身のレジ スタのセットを持ち、それぞれのソケットは一つの割り込み線と二つの連続し た入出力ポート番号を割り当てます。 3.3.1. RequestIO int CardServices(RequestIO, client_handle_t client, io_req_t *req); io_req_t 構造体の定義は次のとおり: typedef struct io_req_t { ioaddr_t BasePort1; ioaddr_t NumPorts1; u_long Attributes1; ioaddr_t BasePort2; ioaddr_t NumPorts2; u_long Attributes2; u_long IOAddrLines; } io_req_t; RequestIO はカード用入出力領域を予約します。BasePort1 がゼロでない場合 は、予約する領域の入出力ポートアドレスです。ゼロの場合は、カードサービ スが利用できる領域をみつけて、BasePort1 にそのアドレスを設定することで す。NumPorts2 がゼロでない場合は、2番目の入出力ポート領域も予約しま す。IOAddrLines は PCMCIA カードで実際にデコードするアドレス線の数を指 定します。これは現在使われていません。 多機能カードではこの呼び出しでそれぞれの物理ポートに対応する 2 つの低 層入出力領域を割り付けそれぞれのカード機能に対応した全てのポートに入出 力ポートを割り当てます。例えば、仮に4機能カードの場合 8 ポートを所有す る1つの入出力領域をドライバは割り当て、カードサービスは 1 つの連続した 32-ポートブロックに統合します。 この呼び出しは実際のソケットの入出力領域を設定するものではありません。 続いて RequestConfiguration を呼び出して設定して下さい。 次のフラグは Attributes1 と Attributes2 に指定します。: IO_DATA_PATH_WIDTH この変数は 16 ビットアクセス用の IO_DATA_PATH_WIDTH_16 もしくは 8 ビットアクセス用の IO_DATA_PATH_WIDTH_8 もしくはアクセスするバ スの大きさに合わせた動的な領域の大きさを決める IO_DATA_PATH_WIDTH_AUTO のどちらか一方に設定します。 戻り値 : CS_BAD_HANDLE クライアントハンドルは無効です。 CS_NO_CARD クライアントに割り付けたソケットは現在使われていません。 CS_IN_USE ソケットの入出力領域は既に予約されています。 CS_CONFIGURATION_LOCKED ソケットの構成は RequestConfiguration によってロックされていま す。 CS_BAD_ATTRIBUTE サポートしていない属性フラグが指定されました。 3.3.2. ReleaseIO int CardServices(ReleaseIO, client_handle_t client, io_req_t *req); ReleaseIO は RequestIO が呼ばれる前に割り当てられていた入出力ポート領 域を解放します。req 変数は RequestIO にそのまま渡します。いくつかのカ ードの機能が大きな入出力ポート領域を共有している場合、一つの機能がポー トを解放しても全てのカードの機能が入出力ポートを解放するまでは他が使っ ているポートを使えなくしてしまってはいけません。 戻り値 : CS_BAD_HANDLE クライアントハンドルは無効です。 CS_CONFIGURATION_LOCKED ソケットの構成は RequestConfiguration によってロックされていま す。その構成は ReleaseIO を呼ぶ前に解放されています。 CS_BAD_ARGS req に入っている変数が RequestIO に渡されたものと一致していませ ん。 3.3.3. RequestIRQ int CardServices(RequestIRQ, client_handle_t client, irq_req_t *req); irq_req_t 構造体の定義は次のとおり: typedef struct irq_req_t { u_long Attributes; u_long AssignedIRQ; u_long IRQInfo1, IRQInfo2; void *(Handler)(int, struct pt_regs *); void *Instance } irq_req_t; RequestIRQ は PCMCIA カードが使用する割り込み線を予約します。 IRQInfo1 と IRQInfo2 変数は CFTABLE_ENTRY タプル内の割り込み記述語と一致してい ます。IRQ_INFO2_VALID を IRQInfo1 に設定しているならば IRQInfo2 を割り 込みの数値を考慮したビットマップマスクを設定しましょう。それぞれのビッ トは一つの割り込み線と一致しています。例えばビット 0 は割り込み 0 、 ビット 1 は割り込み 1 などです。従って、 0x1100 というマスクは割り込み 12 と割り込み 8 を使う事を意味しています。IRQ_INFO2_VALID を設定してい ない場合は、IRQInfo1 は割り込み番号を指定する必要があります。この呼び 出しが成功した時は、AssignedIRQ に予約された割り込み番号が返ってきま す。 IRQ_HANDLER_PRESENT フラグを設定すると、その時この呼び出しが割り込みが 有効になっている時に割り込みハンドラを導入することを示していま す。RequestConfiguration が呼ばれた時、Handler で指定した割り込みハン ドラが導入されます。カーネル 2.0 以降では割り込みハンドラは Instance で与えられる ``実体'' のドライバと共に導入されます。カーネル 2.1.60 以 前では、カーネルの irq2dev_map テーブルも更新するでしょう。多機能カー ドでは、割り込みは共有モードで割り当てられ、ハンドラは割り込みを受け 取った時カードに機能を認識させる役割を負います。クライアントがカードサ ービスを迂回する為に独自の割り込みサービスルーチンを導入する場合は、ク ライアントが多機能カードと結合するには共有モードで割り当てましょう。 Attributes で指定できるフラグは次のとおり: IRQ_FORCED_PULSE 指定する割り込みは標準のレベルモードよりはパルスモードで設定しま しょう。 IRQ_TYPE_TIME 指定する割り込みは他のカードサービスドライバで時分割で行ないま しょう。一つのドライバではいつでも割り込み可能になります。 IRQ_FIRST_SHARED IRQ_TYPE_TIME と組み合わせて、最初のドライバを共有割り込みするよ うに設定します。 IRQ_HANDLER_PRESENT Handler 変数が導入済みの割り込みサービスルーチンを指すようにしま す。 戻り値 : CS_BAD_HANDLE クライアントハンドルは無効です。 CS_NO_CARD クライアントに割り付けたソケットは現在使われていません。 CS_IN_USE ソケットの入出力領域は既に予約されているか、要求した割り込みは使 用できません。 CS_CONFIGURATION_LOCKED ソケットの構成は RequestConfiguration によってロックされていま す。 CS_BAD_ATTRIBUTE サポートしていない属性フラグが指定されました。 3.3.4. ReleaseIRQ int CardServices(ReleaseIRQ, client_handle_t client, irq_req_t *req); ReleaseIRQ はそれ以前に割り当てられている割り込みの予約解除をします。 req 構造体は RequestIRQ に渡される構造体と同じものです。ハンドラを RequestIRQ 呼び出しで指定した場合は、この時点で登録解除されます。 戻り値 : CS_BAD_HANDLE クライアントハンドルは無効です。 CS_CONFIGURATION_LOCKED ソケットの構成は RequestConfiguration によってロックされていま す。構成は ReleaseIRQ が呼ばれる前に解除されています。 CS_BAD_IRQ req で指定したパラメータが RequestIRQ に渡されていたものと一致し ていません。 3.3.5. RequestConfiguration int CardServices(RequestConfiguration, client_handle_t client, config_req_t *req); config_req_t 構造体の定義は次のとおり: typedef struct config_req_t { u_long Attributes; u_long Vcc, Vpp1, Vpp2; u_long IntType; caddr_t ConfigBase; u_char Status, Pin, Copy, ExtStatus; u_char ConfigIndex; u_long Present; } config_req_t; RequestConfiguration は実際にソケットの構成を行ないます。これは電圧の 設定、 CIS 構成レジスタの設定、入出力ポート領域の設定、割り込みの設定 を行ないます。 IntType は使用するカードのインターフェースの型を指定します。その型は INT_MEMORY または INT_MEMORY_AND_IO のいずれかを指定します。 Voltages は 1/10 ボルトの単位で指定します。現在は、Vpp1 と Vpp2 は同じである必 要があります. 多機能カードではそれぞれのカード機能は別々に構成します。それぞれの機能 は CIS 構成レジスタの組み合わせで行ないます。しかしながら、全ての機能 は同じ電源とインタフェースで構成しなければいけません。 次のフラグは Attributes で指定するものです。DMA とスピーカ制御は全ての システムでサポートはしていません。 CONF_ENABLE_IRQ RequestIRQ 以前を入出力割り込みを予約可能にします。 CONF_ENABLE_DMA ソケット用に DMA アクセスを有効にします。 CONF_ENABLE_SPKR ソケットからスピーカ出力を有効にします。 Present 変数はカードに実装している CIS 構成レジスタで指定するビット マップです。ConfigBase は属性メモリ内の構成レジスタのオフセットで与え ます。次のレジスタで指定します。: PRESENT_OPTION 現在の構成オプションレジスタ(COR) を指定します。 COR レジスタは ConfigIndex 変数を使って指定します。 PRESENT_STATUS 現在のカード構成(CC) と 状態レジスタ(SR) を指定します。 CCSR は Status 変数で初期化します。 PRESENT_PIN_REPLACE 現在のピン代替レジスタ(PRR) を指定します。PRR は Pin 変数で初期 化します。 PRESENT_COPY 現在のソケット(S) とコピーレジスタ(CR) を指定します。SCR は Copy 変数で初期化します。 PRESENT_EXT_STATUS 現在の拡張状態レジスタ(ESR) を指定します。ESR は ExtStatus 変数 で初期化します。 戻り値 : CS_BAD_HANDLE クライアントハンドルは無効です。 CS_NO_CARD クライアントに割り付けたソケットは現在使われていません。 CS_OUT_OF_RESOURCE カードサービスはカードの構成レジスタにアクセスするメモリ領域が割 り当てできません。 CS_CONFIGURATION_LOCKED カードの構成は RequestConfiguration によってロックされています。 CS_BAD_VCC 要求された Vcc 電圧はサポートしていません。 CS_BAD_VPP 要求された Vpp1/Vpp2 電圧はサポートしていません。 3.3.6. ModifyConfiguration int CardServices(ModifyConfiguration, client_handle_t client, modconf_t *mod); modconf_t 構造体の定義は次のとおり: typedef struct modconf_t { u_long Attributes; u_long Vcc, Vpp1, Vpp2; } modconf_t; ModifyConfiguration は RequestConfiguration を呼び出して設定したソケッ トの属性を変更します。 Attributes で指定できるフラグは次のとおり: CONF_IRQ_CHANGE_VALID CONF_ENABLE_IRQ の設定を変更する事を表しています。 CONF_ENABLE_IRQ ソケットに有効になっている入出力割り込みを指定します。 CONF_VCC_CHANGE_VALID Vcc を変更することを表しています。 CONF_VPP1_CHANGE_VALID Vpp1 を変更することを表しています。 CONF_VPP2_CHANGE_VALID Vpp2 を変更することを表しています。 現在、Vpp1 と Vpp2 は常に同じ値でなければいけません。従って、2つの値は 同時に変更する必要があります。 戻り値 : CS_BAD_HANDLE クライアントハンドルは無効です。 CS_NO_CARD クライアントに割り付けたソケットは現在使われていません。 CS_CONFIGURATION_LOCKED 実際には、ソケットはロックされていません。 CS_BAD_VCC 要求された Vcc 電圧はサポートしていません。 CS_BAD_VPP 要求された Vpp1/Vpp2 電圧はサポートしていません。 3.3.7. ReleaseConfiguration int CardServices(ReleaseConfiguration, client_handle_t client, config_req_t *req); ReleaseConfiguration はそれ以前に設定されている構成の解除をします。 req 構造体は ソケットを設定するときと同じものです。 戻り値 : CS_BAD_HANDLE クライアントハンドルが無効か、ソケットが設定されていません。 3.3.8. GetConfigurationInfo int CardServices(GetConfigurationInfo, client_handle_t client, config_info_t *config); config_info_t 構造体の定義は次のとおり: typedef struct config_info_t { u_char Function; u_long Attributes; u_long Vcc, Vpp1, Vpp2; u_long IntType; caddr_t ConfigBase; u_char Status, Pin, Copy, Option, ExtStatus; u_long Present; u_long AssignedIRQ; u_long IRQAttributes; ioaddr_t BasePort1; ioaddr_t NumPorts1; u_long Attributes1; ioaddr_t BasePort2; ioaddr_t NumPorts2; u_long Attributes2; u_long IOAddrLines; } config_info_t; GetConfigurationInfo は RequestIO, RequestIRQ と RequestConfiguration で設定した現在のソケットの構成を返します。完全に構成したソケットに対し て適応してください。単機能のカードに結合しているクライアントでは、 Function 変数は無視され、クライアントが指定している機能のデータを返し ます。BIND_FN_ALL と結合しているクライアントではこの変数は指定した関数 の構成データを返します。 戻り値 : CS_BAD_HANDLE クライアントハンドルが無効か、ソケットが設定されていません。 CS_NO_CARD クライアントに割り付けたソケットは現在使われていません。 CS_CONFIGURATION_LOCKED 実際には、ソケットはロックされていません。 3.4. カード情報構造体 (CIS) 使用法 カード情報構造体 (CIS) は PCMCIA 標準の中で最も分かりにくいところで す。全ての第 2 版の PCMCIA カードはここでどう設定するか説明する CIS を 持っています。CIS はカードの属性メモリ空間の中の``タプル (tuples)''の 連結リストです。タプルは識別コード、データ長と一連のデータからなりま す。いくつかのタプルでのデータの配置はことごとく全てのビットを使うよう な明らかな努力を必要とするほど、かなり複雑です。 ValidateCIS 呼び出しは正当な CIS を使っているカードかどうか調べます。 GetFirstTuple と GetNextTuple 呼び出しは CIS タプルリストを移動する方 法です。GetTupleData はタプルからデータを取り出します。そして ParseTuple は特に重要な限られた数のタプルを解釈します。 3.4.1. GetFirstTuple, GetNextTuple #include "cistpl.h" int CardServices(GetFirstTuple, client_handle_t client, tuple_t *tuple); int CardServices(GetNextTuple, client_handle_t client, tuple_t *tuple); tuple_t データ構造体の定義は次のとおり: typedef struct tuple_t { u_long Attributes; cis_data_t DesiredTuple; u_long Flags; cisdata_t TupleCode; u_long TupleLink; cisdata_t TupleOffset; cisdata_t TupleDataMax; cisdata_t TupleDataLen; cisdata_t *TupleData; } tuple_t; GetFirstTuple は DesiredTuple に一致する最初のタプルコードをカードの CIS から探します。特別な RETURN_FIRST_TUPLE コードはどんな種類のタプル に一致します。TupleCode を最初に一致したタプルのコードに設定しま す。TupleLink は属性メモリ内のタプルのアドレスです。 GetNextTuple は事前に実行した GetFirstTuple が返す tuple_t 構造体を与 えることを除いて GetFirstTuple に似ています。また、GetNextTuple は次に 一致させたいタプルを DesiredTuple に返します。 これらの関数は自動的に CIS 内のリンクタプルを全て手繰って調査します。 多機能カードでは CISTPL_LONGLINK_MFC タプルを持っているのは、これらの 関数がクライアントドライバの指している機能を指定した CIS だけを自動的 に追跡できるようにするためです。クライアントが BIND_FN_ALL を結合して いる場合は、全てのタプルが返るでしょう。 Attributes で指定できるフラグは次のとおり: TUPLE_RETURN_LINK リンクタプル (CISTPL_LONGLINK_A, CISTPL_LONGLINK_C, CISTPL_LONGLINK_MFC, CISTPL_NOLINK, CISTPL_LINKTARGET) を返すこ とを表しています。普通はこれらのタプルは暗黙のうちに処理されま す。 TUPLE_RETURN_COMMON 多機能 CIS の``共有'' CIS セクションのタプルを返すことを表してい ます。このフラグがない時は通常、カードサービスはクライアントに結 合させる機能を表すタプルを返します. 戻り値 : CS_BAD_HANDLE クライアントハンドルが無効です。 CS_OUT_OF_RESOURCE カードサービスはメモリ領域をカードの CIS に割り付けできませんで した。 CS_NO_MORE_ITEMS DesiredTuple に一致するタプルはありません。 3.4.2. GetTupleData #include "cistpl.h" int CardServices(GetTupleData, client_handle_t client, tuple_t *tuple); GetTupleData は一連のデータを事前に呼んだ GetFirstTuple または GetNextTuple の返してきた指定されたタプルから取り出します。 TupleDataMax の最大長は TupleData バッファにコピーされて、 TupleOffset のオフセットから始まります。コピーされたバイト数は TupleDataLen に入っ ています。 戻り値 : CS_BAD_HANDLE クライアントハンドルが無効です。 CS_OUT_OF_RESOURCE カードサービスはメモリ領域をカードの CIS に割り付けできませんで した。 CS_NO_MORE_ITEMS タプルには何もデータが格納されていません。TuppleOffset はタプル の長さと等しいかより大きいです。 3.4.3. ParseTuple #include "cistpl.h" int CardServices(ParseTuple, client_handle_t client, tuple_t *tuple, cisparse_t *parse); cisparse_t データ 構造体は次のとおり: typedef union cisparse_t { cistpl_device_t device; cistpl_checksum_t checksum; cistpl_longlink_t longlink; cistpl_longlink_mfc_t longlink_mfc; cistpl_vers_1_t version_1; cistpl_altstr_t altstr; cistpl_jedec_t jedec; cistpl_manfid_t manfid; cistpl_funcid_t funcid; cistpl_config_t config; cistpl_cftable_entry_t cftable_entry; cistpl_device_geo_t device_geo; cistpl_vers_2_t version_2; cistpl_org_t org; } cisparse_t; ParseTuple は事前に呼んだ GetTupleData が返してきたタプルのデータを解 釈します。返ってきた構造体は解析したタプルの型に依存します。これらの構 造体の定義は cistpl.h ファイルを参照して下さい。そのうちのいくつかは大 変複雑なものです。 戻り値 : CS_BAD_TUPLE タプルの解析中にエラーが発生しました。タプルが不完全か、書式が正 しくありません。 CS_UNSUPPORTED_FUNCTION ParseTuple が指定されたタプルの型を解析できません。 3.4.4. ValidateCIS int CardServices(ValidateCIS, client_handle_t client, cisinfo_t *cisinfo); cisinfo_t 構造体は次のとおり: typedef struct cisinfo_t { u_long Chains; } cisinfo_t; ValidateCIS はカードが妥当なカード情報構造体(CIS) を持っているか検証し ます。Chains に見つかったタプルの数が返ってきます。CIS が解釈不能だと 思えたら、Chains を 0 に設定します。 戻り値 : CS_BAD_HANDLE クライアントハンドルが無効です。 CS_OUT_OF_RESOURCE カードサービスはメモリ領域をカードの CIS に割り付けできませんで した。 3.5. メモリ領域制御 それぞれのソケットは4つ以上のメモリ領域を持て、PCMCIA メモリの一部をホ ストのアドレス空間に割り付けます。PCMCIA 機器は一般メモリと属性メモリ の両方に 16MB 程度アクセスできます。領域は一般に 2 のべき乗の大きさを していますが、ホストとカードのアドレス空間では領域の大きさの倍数に境界 調整しています。 メモリ領域は RequestWindow を呼び出して初期化します。いくつかの領域属 性は ModifyWindow を使用して変更を行ないます。領域に割り付けられたカー ドメモリの一部は MapMemPage を使用して変更します。領域は ReleaseWindow で解放します。他のカードサービス関数とは異なって、client_handle_t ハン ドルでなく window_handle_t ハンドルで動作します。 3.5.1. RequestWindow int CardServices(RequestWindow, client_handle_t *handle, win_req_t *req); win_req_t 構造体は次のとおり: typedef struct win_req_t { u_long Attributes; caddr_t Base; u_long Size; u_long AccessSpeed; } win_req_t; RequestWindow はカードメモリの領域をシステムメモリへ割り当てます。呼ぶ 前に、handle 変数が有効なクライアントハンドルを指すようにします。返っ てきたら、この後呼ばれる ModifyWindow、MapMemPage と ReleaseWindow で 使用する window_handle_t ハンドルで置き換えられます。 Attributes で指定できるフラグは次のとおり: WIN_MEMORY_TYPE この変数は一般メモリでは WIN_MEMORY_TYPE_CM 、属性メモリでは WIN_MEMORY_TYPE_AM のいずれかになります。 WIN_DATA_WIDTH 16 ビットアクセスでは WIN_DATA_WIDTH_16 、8 ビットアクセスなら WIN_DATA_WIDTH_8 のいずれかになります。 WIN_ENABLE これを設定すると、領域が使用可能になります。 WIN_USE_WAIT 制御装置がカードの MWAIT 信号を監視するように指定します。 Base はシステムメモリでの領域の基底アドレスを指定します。NULL の場合 は、カードサービスは最初に見つかった利用可能な領域のアドレスを設定しま す。Size は領域の大きさをバイト単位で指定します。AccessSpeed はメモリ アクセススピードをナノ秒単位で指定します。 戻り値 : CS_BAD_HANDLE クライアントハンドルが無効です。 CS_NO_CARD クライアントに割り付けたソケットは現在使われていません。 CS_BAD_ATTRIBUTE サポートしていない領域の属性が指定されました。 CS_OUT_OF_RESOURCE そのソケットに対するメモリ領域の最大数は使用済みです。 CS_IN_USE RequestWindow はシステムメモリのあき領域が見つけられません。 3.5.2. ModifyWindow int CardServices(ModifyWindow, window_handle_t, modwin_t *); modwin_t 構造体は次のとおり: typedef struct modwin_t { u_long Attributes; u_long AccessSpeed; } modwin_t; ModifyWindow は事前に呼んだ RequestWindow から返ってきた領域ハンドルの 属性を変更します。変更できる属性は次のとおり: WIN_MEMORY_TYPE この変数は一般メモリでは WIN_MEMORY_TYPE_CM 、属性メモリでは WIN_MEMORY_TYPE_AM のいずれかになります。 WIN_DATA_WIDTH 16 ビットアクセスでは WIN_DATA_WIDTH_16 、8 ビットアクセスなら WIN_DATA_WIDTH_8 のいずれかになります。 WIN_ENABLE これを設定すると、領域が使用可能になります。 AccessSpeed はメモリアクセススピードをナノ秒単位で指定します。 戻り値 : CS_BAD_HANDLE 領域ハンドルは無効です。 3.5.3. MapMemPage int CardServices(MapMemPage, window_handle_t, memreq_t *); memreq_t 構造体は次のとおり: typedef struct memreq_t { u_long CardOffset; page_t Page; } memreq_t; MapMemPage は CardOffset で割り付けたメモリ領域の基底アドレスをカード メモリのアドレスに設定します。領域は RequestWindow を呼び出して作成し ておきましょう。Page 変数はこの版では実装していませんので、0 に設定し てください。 戻り値 : CS_BAD_HANDLE 領域ハンドルは無効です。 CS_BAD_PAGE Page の値がゼロ以外です。 3.5.4. ReleaseWindow int CardServices(ReleaseWindow, window_handle_t handle); ReleaseWindow は事前に RequestWindow で割り当てたメモリ領域を解放しま す。 戻り値 : CS_BAD_HANDLE 領域ハンドルは無効です。 3.6. 大容量メモリサービス 大容量メモリサービスはメモリ領域サービスで提供しているインターフェース よりメモリ領域にアクセスするインターフェースはより高度になっています。 大容量メモリ呼び出しを使用するクライアントは背後にあるメモリの機構やア クセス法についての知識は必要ありません。機器に依存したプログラムはメモ リテクノロジドライバ(MTD) と呼ばれる特殊なカードサービスに入れていま す。 3.6.1. RegisterMTD int CardServices(RegisterMTD, client_handle_t handle, mtd_reg_t *reg); mtd_reg_t データ 構造体は次のとおり: typedef union mtd_reg_t { u_long Attributes; u_long Offset; u_long MediaID; } mtd_reg_t; RegisterMTD はカードサービスにクライアントの MTD が指定したメモリ領域 を扱う要求を通知します。Offset 変数はメモリ領域の開始アドレスを指定し ます。Attributes で指定できる内容は次のとおり: REGION_TYPE 一般メモリでは REGION_TYPE_CM もしくは 属性メモリでは REGION_TYPE_AM のどちらかを指定します。 MediaID 変数はカードサービスが書き込みます。MTD にこのメモリ領域を参照 する時の要求の一部として渡します。 一旦、MTD がこの呼び出しでメモリ領域に結合すると、DeregisterClient を 呼び出すまで結合しつづけます。 戻り値 : CS_BAD_HANDLE クライアントハンドルが無効です。 CS_BAD_OFFSET 有効なカードのメモリ領域とオフセットが一致しないか、他の MTD が 既にこのメモリ領域を登録しています。 3.6.2. GetFirstRegion, GetNextRegion int CardServices(GetFirstRegion, client_handle_t handle, region_info_t *region); int CardServices(GetNextRegion, client_handle_t handle, region_info_t *region); region_info_t データ 構造体は次のとおり: typedef union region_info_t { u_long Attributes; u_long CardOffset; u_long RegionSize; u_long AccessSpeed; u_long BlockSize; u_long PartMultiple; u_char JedecMfr, JedecInfo; memory_handle_t next; } region_info_t; GetFirstRegion と GetNextRegion はカードの CISTPL_DEVICE, CISTPL_JEDEC, と CISTPL_DEVICE_GEO タプルの情報を要約しま す。CardOffset は領域の開始アドレスを提供します。RegionSize は領域の大 きさをバイト単位で提供します。 AccessSpeed は機器のサイクル時間をナノ 秒単位で提供します。 BlockSize は消去ブロックの大きさをバイト単位で提 供し、PartMultiple は区画の最小の大きさを BlockSize 単位で提供しま す。JedecMfr と JedecInfo は 領域が JEDEC に準拠している証明情報を提供 します。 Attributes で指定できる変数は次のとおり: REGION_TYPE 一般メモリでは REGION_TYPE_CM もしくは 属性メモリでは REGION_TYPE_AM のどちらかを指定します。 これらの呼び出しが MTD クライアントによって行なわれた時、BindMTD を呼 び出したクライアントに BindMTD が返すメモリを結合させます。 戻り値 : CS_BAD_HANDLE クライアントハンドルが無効です。 CS_NO_MORE_ITEMS メモリ領域が定義されていません。 3.6.3. OpenMemory int CardServices(OpenMemory, client_handle_t *handle, open_mem_t *req); pen_mem_t 構造体は次のとおり: typedef struct open_mem_t { u_long Attributes; u_long Offset; } open_mem_t; OpenMemory は他の大容量メモリサービス経由でメモリ領域をアクセスするハ ンドルを獲得します。Offset 変数はアクセスするメモリ領域の基底アドレス を指定します。うまくいったら、クライアントハンドル引数は新しいメモリハ ンドルに置き換わります。 Attributes で指定できる変数は次のとおり: MEMORY_TYPE この引数は一般メモリでは MEMORY_TYPE_CM 、属性メモリでは MEMORY_TYPE_AM のいずれかになります。 MEMORY_EXCLUSIVE クライアントがメモリ領域を排他的にアクセスする為に指定します。 戻り値 : CS_BAD_HANDLE 領域ハンドルが無効です。 CS_BAD_OFFSET 有効な領域のオフセットが指定されていないか、大容量メモリ要求と関 連づける MTD の大容量メモリサービスに領域がありません。 3.6.4. CloseMemory int CardServices(CloseMemory, memory_handle_t handle); CloseMemory は 以前に呼び出した OpenMemory が返したメモリハンドルを解 放します。クライアントは DeregisterClient を呼び出す前に全てのメモリハ ンドルを解放しましょう。 戻り値 : CS_BAD_HANDLE メモリハンドルが無効です。 3.6.5. ReadMemory, WriteMemory int CardServices(ReadMemory, memory_handle_t handle mem_op_t *req, caddr_t buf); int CardServices(WriteMemory, memory_handle_t handle, mem_op_t *req, caddr_t buf); mem_io_t 構造体は次のとおり: typedef struct mem_op_t { u_long Attributes; u_long Offset; u_long Count; } mem_op_t; ReadMemory と WriteMemory は以前に呼び出した OpenMemory が返した指定し たメモリハンドルで指定したカードメモリ領域を読み書きします。 Offset 変 数はカードメモリ領域の開始アドレスを指定します。 Count 変数は転送する バイト数を指定します。buf 変数は ReadMemory 操作用の対象又は WriteMemory 操作の対象となるホストメモリのバッファを指します。 Attributes で指定できる変数は次のとおり: MEM_OP_BUFFER ホストバッファがユーザメモリセグメントにある時は MEM_OP_BUFFER_USER もしくはホストバッファがカーネルメモリにある 時は MEM_OP_BUFFER_KERNEL を指定します。 MEM_OP_DISABLE_ERASE カード領域を書き込む前に消去しないように指定します。 MEM_OP_VERIFY 書き込みの時に検証するときに指定します。 戻り値 : CS_BAD_HANDLE 領域ハンドルが無効です。 CS_BAD_OFFSET 指定したカードオフセットがメモリ領域の終了アドレスを越えていま す。 CS_BAD_SIZE 指定した転送サイズがメモリ領域の終了アドレスを越えています。 3.6.6. RegisterEraseQueue int CardServices(RegisterEraseQueue, client_handle_t *handle, eraseq_hdr_t *header); eraceq_hdr_t 構造体は次のとおり: typedef struct erase_queue_header_t { int QueueEntryCount; eraseq_entry_t *QueueEntryArray; } eraseq_hdr_t; この呼び出しはカードサービスの消去キューを登録します。 eraseq_handle_t ハンドルは *handle に返ります。クライアントが CheckEraseQueue を呼び出 した時、カードサービスがキューを調べて新しい要求の非同期処理を開始しま す。 eraseq_entry_t 構造体は次のとおり: typedef struct eraseq_entry_t { memory_handle_t Handle; u_char State; u_long Size; u_long Offset; u_long *Optional; } eraseq_entry_t; 消去キューの登録には、Header 変数は以前に呼ばれた OpenMemory が返した メモリハンドルを入れます。State 変数は消去キューの状態を示します。次の 値が定義されています。: ERASE_QUEUED 新規に要求をした時クライアントが設定します。 ERASE_IDLE 登録がアクティブでない時クライアントが設定します。 ERASE_PASSED 消去がうまく完了した時 MTD が設定します。 ERASE_FAILED 消去に失敗した時 MTD が設定します。 ERASE_MEDIA_WRPROT 領域が書き込み禁止になっている事を示しています。 ERASE_NOT_ERASABLE 領域が消去をサポートしていない事を示しています。 ERASE_BAD_OFFSET 消去が消去ブロックの境界で始まっていない事を示しています。 ERASE_BAD_SIZE 要求している消去の大きさが消去ブロックの倍数になっていない事を示 しています。 ERASE_BAD_SOCKET MTD がカードがない事を示しています。 加えて、ERASE_IN_PROGRESS() マクロは処理している消去の State の値の真 の状態を返します。 Size 変数は消去要求を大きさをバイト単位で与えます。Offset 変数は領域の 開始位置からのオフセットで与えます。大きさとオフセットは消去ブロック境 界に境界調整しておきます。Optional 変数はカードサービスでは使われてい ませんが、クライアントドライバで使われています。 戻り値 : CS_BAD_HANDLE クライアントハンドルが無効です。 3.6.7. DeregisterEraseQueue int CardServices(DeregisterEraseQueue, eraseq_handle_t handle); DeregisterEraseQueue は以前に RegisterEraseQueue により登録されたキュ ーを解放します。指定されたキューに処理中のキューがある場合は、呼び出し は失敗します。 戻り値 : CS_BAD_HANDLE 消去キューハンドルが無効です。 CS_BUSY 消去キューが消去処理中です。 3.6.8. CheckEraseQueue int CardServices(CheckEraseQueue, eraseq_handle_t handle); この呼び出しは以前に RegisterEraseQueue で登録された新しい消去要求をカ ードサービスに通知します。 例によって、クライアントは最初にそれぞれのキューに ERASE_IDLE 状態を割 り当てます。キューに新しい要求が追加された時は、クライアントはキューの 状態を ERASE_QUEUED にして、CheckEraseQueue を呼びます。クライアントが 消去完了イベントを受け取った場合は、要求が成功したか状態変数を確認しま す。 戻り値 : CS_BAD_HANDLE 消去キューハンドルが無効です。 3.7. 各種呼び出し 3.7.1. GetCardServicesInfo int CardServices(GetCardServicesInfo, servinfo_t *info); servinfo_t 構造体は次のとおり: typedef struct servinfo_t { char Signature[2]; u_long Count; u_long Revision; u_long CSLevel; char *VendorString; } servinfo_t; GetCardServicesInfo はこのカードサービスのバージョンの修正情報を返しま す。Signature は ``CS'' に設定します。Count は現状構成のソケットの数を 設定します。 Revision にはカードサービスパッケージの修正レベルを設定し CSLevel は PCMCIA 標準に準じたレベルを設定します。BCD 数で表記していま す。VendorString は RCS 識別文字列へのポインタを設定します。 この呼び出しは常に成功します。 3.7.2. AccessConfigurationRegister #include "cisreg.h" int CardServices(AccessConfigurationRegister, client_handle_t handle, conf_reg_t *reg); resource.memory で記述したメモリの範囲を指定します。 RES_IO_RANGE adj->resource.io で記述した入出力ポートを指定します。 RES_IRQ adj->resource.irq で記述した割り込みを指定します。 Attributes で指定できる内容は次のとおり: RES_RESERVED PCMCIA ドライバ用に要求し,予約した資源を示しています。利用可能 なカードサービスの問い合わせしたデバイス用の資源ではありません。 これは未だ実装していません。 戻り値 : CS_UNSUPPORTED_FUNCTION 指定した Action と Resource はサポートしていません。 CS_BAD_BASE 指定した入出力アドレスは範囲外です。 CS_BAD_SIZE 指定したメモリまたは入出力領域のサイズは範囲外です。 CS_IN_USE 指定した割り込みは現在カードサービスクライアントが使用中です。 3.7.4. ReportError int CardServices(ReportError, client_handle_t handle, error_info_t *err); error_info_T 構造体の定義は次のとおり: typedef struct error_info_t { int func; int retcode; } error_info_t; ReportError は指定した prefix 文字列とカードサービスの機能コードと戻り 値を含んだカーネルエラーメッセージを生成します。例を挙げると : error_info_t err = { RequestIO, CS_BAD_HANDLE }; CardServices(ReportError, handle, &err); は次のメッセージを生成します。: serial_cs: RequestIO: Bad handle この呼び出しは常に正常終了します。 4. カード情報構造体 (CIS) の定義 4.1. CIS タプルの定義 カードサービスタプル解析 (Card Services ParseTuple) 機能は、 GetTupleData で得た生の CIS タプルを解析し、それぞれのタプルの種類に依 存した形式でタプルの内容を返します。 #include "cistpl.h" 4.1.1. CISTPL_CHECKSUM cistpl_checksum_t 構造体の定義は次のとおり: typedef struct cistpl_checksum_t { u_short addr; u_short len; u_char sum; } cistpl_checksum_t; 4.1.2. CISTPL_LONGLINK_A, CISTPL_LONGLINK_C, CISTPL_LINKTARGET, CISTPL_NOLINK cistpl_longlink_t 構造体の定義は次のとおり: typedef struct cistpl_longlink_t { u_long addr; } cistpl_longlink_t; これらのタプルは属性や、一般メモリなどへの他の CIS タプルチェーンへの ポインタになっています。それぞれの CIS タプルは、少なくとも 1 以上の長 さのリンクです。CISTPL_LONGLINK_A タプルは、アトリビュートメモリへのポ インタであり、CISTPL_LONGLINK_C タプルは一般メモリへのポインタです。属 性メモリのアドレス 0 から始まる標準 CIS チェーンは、同時に一般メモリの アドレス 0 へのリンクも意味しています。(@@) このようなデフォールトのリ ンクをキャンセルしたい場合には CISTPL_NOLINK というタプルを使います。 ロングリンクによって指されるチェーンの最初のタプル は、CISTPL_LINKTARGET でなければなりません。CS タプルを扱うコードは自 動的にロングリンクをたどり、リンク先を(ターゲット)を調べま す。GetNextTuple によって、 TUPLE_RETURN_LINK 属性が指定されていない限 り、これらのタプルはユーザーからは見えません。 4.1.3. CISTPL_LONGLINK_MFC cistpl_longlink_mfc_t 構造体の定義は次のとおり: typedef struct cistpl_longlink_mfc_t { int nfn; struct { u_char space; u_long addr; } fn[CISTPL_MAX_FUNCTIONS; } cistpl_longlink_mfc_t; このタプルはマルチファンクション(多機能)カードを識別するのに使われま す。それぞれの機能ごとの CIS チェーンへのロングリンクポインタを指定し ます。 space 変数は、属性の場合 CISTPL_MFC_ATTR が、一般メモリの場合に は CISTPL_MFC_COMMON が指定されます。 4.1.4. CISTPL_DEVICE, CISTPL_DEVICE_A cistpl_device_t 構造体の定義は次のとおり: typedef struct cistpl_device_t { int ndev; struct device_info { u_char type; u_char wp; u_long speed; u_long size; } dev[CISTPL_MAX_DEVICES]; } cistpl_device_t; CISTPL_DEVICE タプルはカードの一般メモリのアドレス領域に関して記述して います。CISTPL_DEVICE_A タプルは属性メモリ領域を記述しています。 type フラグはその領域に関するメモリデバイスの種類を示します。 wp フラグは、 その領域がライトプロテクトされているかどうかを示します。 speed 変数は ナノ秒単位で、size はバイト単位で示されます。アドレス領域はアドレス 0 番地から連続した領域であることが仮定されています。次のようなデバイスタ イプが定義されています。 CISTPL_DTYPE_NULL なにもデバイスが存在しない、または、そのカードのアドレス空間の中 で「穴」であることを示します。 CISTPL_DTYPE_ROM マスク ROM です。 CISTPL_DTYPE_OTPROM 一度だけ書き込み可能な ROM です。(訳注:原文の 「One-type」は 「One-time」の間違いであると思います。) CISTPL_DTYPE_EPROM 紫外線消去可能な PROM です。(UV-EPROM) CISTPL_DTYPE_EEPROM 電気的に消去可能な PROM です。 CISTPL_DTYPE_FLASH フラッシュ EPROM です。 CISTPL_DTYPE_SRAM スタティックまたは不揮発性の RAM です。 CISTPL_DTYPE_DRAM ダイナミックまたは揮発性の RAM です。 CISTPL_DTYPE_FUNCSPEC 機能定義可能なデバイスであることを示します。つまり、汎用の記憶で はなくて、例えば メモリーマップドI/O デバイスやバッファのような ものです。 CISTPL_DTYPE_EXTEND 拡張型のデバイスタイプを示します。これは将来の拡張のために予約さ れています。 4.1.5. CISTPL_VERS_1 cistpl_vers_1_t 構造体の定義は次のとおり: typedef struct cistpl_vers_1_t { u_char major; u_char minor; int ns; int ofs[CISTPL_VERS_1_MAX_PROD_STRINGS]; char str[254]; } cistpl_vers_1_t; ns 変数は、このタプルの中に含まれている製品情報文字列の長さを示してい ます。文字列情報は str という配列に格納されています。それぞれの文字列 はヌル文字で終っており、ofs はそれぞれの文字列の始まりへのオフセットを 示しています。 4.1.6. CISTPL_ALTSTR cistpl_altstr_t 構造体の定義は次のとおり: typedef struct cistpl_altstr_t { int ns; int ofs[CISTPL_ALTSTR_MAX_STRINGS]; char str[254]; } cistpl_altstr_t; ns 変数は、このタプルに含まれている代替用語文字列の数を示しています。 実際の文字列は、str 配列に格納されています。それぞれの文字列はヌル文字 で終っており、ofs はそれぞれの文字列の始まりへのオフセットを示していま す。 4.1.7. CISTPL_JEDEC_C, CISTPL_JEDEC_A cistpl_jedec_t 構造体の定義は次のとおり: typedef struct cistpl_jedec_t { int nid; struct jedec_id { u_char mfr; u_char info; } id[CISTPL_MAX_DEVICES]; } cistpl_jedec_t; jedec_id (JEDEC 識別子) は、PCMCIA メモリを実現するために使われる特定 のデバイスタイプを記述しています。 nid 変数はこのタプルの中にいくつの jedec_id が含まれているかを示します。このjedec_id (JEDEC identifier) と、それに対応する CISTPL_DEVICE タプルの中のデバイス定義は、一対一の 対応がとれていなければなりません。 4.1.8. CISTPL_CONFIG cistpl_config_t 構造体の定義は次のとおり: typedef struct cistpl_config_t { u_char last_idx; u_long base; u_long rmask[4]; u_char subtuples; } cistpl_config_t; last_idx 変数は、構成情報テーブルの一番最後の項目のインデックスを示し ます。 base 変数は、属性メモリ中にあるカードの構成情報レジスタへのオフ セットを示します。 rmask 配列はどの構成情報レジスタが存在するのかを示 すビットマスクです。 rmask[0] のビット 0 は、COR に対応し、ビット 1 は CCSR に対応する... といった具合です。subtuple 変数は、通常のタプルの 内容に続いて何バイトのタプルが存在するか、を示しています。 4.1.9. CISTPL_CFTABLE_ENTRY cistpl_cftable_entry_t 構造体の定義は次のとおり: typedef struct cistpl_cftable_entry_t { u_char index; u_char flags; u_char interface; cistpl_power_t vcc, vpp1, vpp2; cistpl_timing_t timing; cistpl_io_t io; cistpl_irq_t irq; cistpl_mem_t mem; u_char subtuples; } cistpl_cftable_entry_t; CISTPL_CFTABLE_ENTRY 構造体はそのカードに対する完全な動作モードを記述 しています。多くの部分が省略可能です。index 変数はこの動作モードについ ての構成情報インデックスを示します。カードの Configuration Option Register にこの値を書き込むことでこのモードを選択することができま す。flags 変数には、次の値が定義されています: CISTPL_CFTABLE_DEFAULT デフォールトの構成情報テーブルの項目であることを示します。 CISTPL_CFTABLE_BVDS この設定は ピン代替レジスタ 中で BVD1 と BVD2 信号を実装している ことを示します。 CISTPL_CFTABLE_WP この設定は ピン代替レジスタ 中で 書き込み禁止を実装していること を示します。 CISTPL_CFTABLE_RDYBSY この設定は ピン代替レジスタ 中で Ready/Busy 信号を実装しているこ とを示します。 CISTPL_CFTABLE_MWAIT メモリーアクセス中に、WAIT 信号を使う必要があることを示します。 CISTPL_CFTABLE_AUDIO この設定はオーディオ信号を発生し、ホストシステムのスピーカーに出 力することができることを示します。 CISTPL_CFTABLE_READONLY この設定ではカード中に読みだし専用のメモリ領域が存在することを示 します。 CISTPL_CFTABLE_PWRDOWN カード構成情報と状態レジスタ を通じて、パワーダウンモードをサポ ートしていることを示します。 cistpl_power_t 構造体の定義は次のとおり: typedef struct cistpl_power_t { u_char present; u_char flags; u_long param[7]; } cistpl_power_t; present 変数はビットマップ形式になっており、この電源信号に関して、どの パラメータが存在しているか、を示します。次のようなインデックスが定義さ れています: CISTPL_POWER_VNOM 標準的な電源電圧 CISTPL_POWER_VMIN 最低電源電圧 CISTPL_POWER_VMAX 最高電源電圧 CISTPL_POWER_ISTATIC 連続供給が必要な電源電流 CISTPL_POWER_IAVG 1 秒間を通じて平均した最大供給電流 CISTPL_POWER_IPEAK 10m 秒間を通じて平均した最大供給電流 CISTPL_POWER_IDOWN パワーダウンモードで必要な供給電流 電圧は 10 マイクロボルト単位、電流は 100 ナノアンペア単位で表されてい ます。 cistpl_timing_t 構造体の定義は次のとおり: typedef cistpl_timing_t { u_long wait, waitscale; u_long ready, rdyscale; u_long reserved, rsvscale; } cistpl_timing_t; それぞれの時間はナノ秒を基底とした値と、尺度乗数から構成されています。 定義されていない(Unspecified) 時間の値は 0 です。 cistpl_io_t 構造体の定義は次のとおり: typedef struct cistpl_io_t { u_char flags; int nwin; struct { u_long base; u_long len; } win[CISTPL_IO_MAX_WIN; } cistpl_io_t; nwin は 入出力領域の数を示します。それぞれの領域は基底アドレス: base、 バイト単位での長さ: len で記述されます。 flags では、次のようなビット マップが定義されています: CISTPL_IO_LINES_MASK このカードでデコードされる入出力の本数。 CISTPL_IO_8BIT このカードは 16 ビットの入出力レジスタに対して、独立した 8 ビッ トアクセスをサポートしていることを示す。 CISTPL_IO_16BIT このカードは入出力レジスタに対して 16 ビットアクセスをサポートし ていることを示す。 cistpl_irq_t 構造体の定義は次のとおり: typedef struct cistpl_irq_t { u_long IRQInfo1; u_long IRQInfo2; } cistpl_irq_t; IRQInfo1 では次のビットマップが定義されています: IRQ_MASK このカードが使うべき割り込み番号を示す。 IRQ_NMI_ID, IRQ_IOCK_ID, IRQ_BERR_ID, IRQ_VEND_ID" IRQ_INFO2_VALID がセットされている時、これらのビッ トマップはそれぞれの特殊割り込みがこのカードに割り当てられている かどうかを示す。これら4つのフラグはそれぞれ、マスク不可能、 IO チェック、バスエラー、ベンダー特有の割り込みを意味します。 IRQ_INFO2_VALID IRQInfo2 が、許可された、正しい割り込み番号を含んでいることを示 す。 IRQ_LEVEL_ID このカードはレベル割り込みをサポートしていることを示す。 IRQ_PULSE_ID このカードはパルス割り込みをサポートしていることを示す。 IRQ_SHARE_ID このカードは割り込み共有をサポートしていることを示す。 IRQInfo1 が 0 の場合、割り込みに関する情報は存在しないことを意味しま す。 cistpl_mem_t 構造体の定義は次のとおり: typedef struct cistpl_mem_t { u_char nwin; struct { u_long len; u_long card_addr; caddr_t host_addr; } win[CISTPL_MEM_MAX_WIN; } cistpl_mem_t; nwin はメモリ領域の数を示す。それぞれの領域は、カードのメモリ空間中の アドレス: card_addr、ホストのメモリ空間中のアドレス: host_addr、バイト 単位での長さ: len で定義される。ホストアドレスが 0 の場合、領域の位置 は任意 (arbitrary) であることを意味する。 4.1.10. CISTPL_MANFID cistpl_manfid_t 構造体の定義は次のとおり: typedef struct cistpl_manfid_t { u_short manf; u_short card; } cistpl_manfid_t; manf 変数はそのカードの製造業者を表します。 card 変数はそれぞれのベン ダーによって定義され、カードの種類と、モデルを識別できるようにしなけれ ばなりません。 4.1.11. CISTPL_FUNCID cistpl_funcid_t 構造体の定義は次のとおり: typedef struct cistpl_funcid_t { u_char func; u_char sysinit; } cistpl_funcid_t; func 変数はそのカードの機能を表します。sysinit 変数はブート時にそのカ ードがどのように設定されるべきかをビットマップフラグで示してます。 次の機能が定義されています: CISTPL_FUNCID_MULTI マルチファンクション(多機能)カード CISTPL_FUNCID_MEMORY 単純なメモリデバイス CISTPL_FUNCID_SERIAL シリアルポートまたはモデムデバイス CISTPL_FUNCID_PARALLEL パラレルポートデバイス CISTPL_FUNCID_FIXED 固定ディスクデバイス(ハードディスクなど) CISTPL_FUNCID_VIDEO ビデオインターフェース CISTPL_FUNCID_NETWORK ネットワークアダプタ CISTPL_FUNCID_AIMS 自動増分機能のある大容量記憶装置 sysinit では次のフラグが定義されている: CISTPL_SYSINIT_POST システムのパワーオン初期化時にこのカードの設定を試みる必要がある ことを示す。 CISTPL_SYSINIT_ROM このカードは、ブート時に設定する必要のあるシステム拡張 ROM を含 んでいることを示す。 4.1.12. CISTPL_DEVICE_GEO cistpl_device_geo_t 構造体の定義は次のとおり: typedef struct cistpl_device_geo_t { int ngeo; struct geo { u_char buswidth; u_long erase_block; u_long read_block; u_long write_block; u_long partition; u_long interleave; } geo[CISTPL_MAX_DEVICES]; } cistpl_device_geo_t; erase_block, read_block, write_block の大きさは、それぞれ buswidth の 値に interleave の値を乗じたバイト数を単位として表される。 partition の大きさは、erase_block の大きさを単位として表される。 4.1.13. CISTPL_VERS_2 cistpl_vers_2_t 構造体の定義は次のとおり: typedef struct cistpl_vers_2_t { u_char vers; u_char comply; u_short dindex; u_char vspec8, vspec9; u_char nhdr; int vendor, info; char str[244]; } cistpl_vers_2_t; vers 変数は常に 0 でなければなりません。comply 変数は標準への準拠の度 合を示しますが、同じく 0 でなければなりません。 dindex 変数は一般メモ リの最初の何バイトが予約されているかを示します。vspec8 と vspec9 変数 にはベンダー特有の情報が含まれている場合があります。nhdr 変数はこのカ ード上にいくつの CIS のコピーが存在しているかを示します。 str 配列は、 二つの文字列を含んでいます: ベンダーの名前と、このカードについて記述し ているなんらかの情報です。ベンダー名の文字列へのオフセットは vendor で 示され、製品情報の文字列へのオフセットは info で示されます。 4.1.14. CISTPL_ORG cistpl_org_t 構造体の定義は次のとおり: typedef struct cistpl_org_t { u_char data_org; char desc[30]; このタプルはメモリパーティッションのデータの構成を定義します。 data_org には次の値が定義されています: CISTPL_ORG_FS このパーティッションはファイルシステムを含んでいます。 CISTPL_ORG_APPSPEC このパーティッションはアプリケーション特有の形式です。 CISTPL_ORG_XIP このパーティッションは「その場で実行」(Execute-In-Place)仕様に従 います。 desc 変数には、データの構成についての文字による記述が含まれています。 4.2. CIS 構成レジスタ PCMCIA 標準規格は、カードの属性メモリ空間中に、いくつかの標準的な構成 情報レジスタを定義しています。これらのレジスタのうち、どのレジスタが実 装されているかは、カードの CONFIG タプルに記述されています。これらの定 義を使う必要のあるプログラムは次をインクルードする必要があります: #include "cisreg.h" 4.2.1. Configuration Option Register このレジスタに書き込むことによって、構成情報テーブルの項目を選択し、カ ードの入出力機能が使えるようになります。 次のビット変数が定義されています: COR_CONFIG_MASK 構成情報テーブルインデックスは、カードの現在の動作モードを指して いることを示す。 COR_LEVEL_REQ このカードはレベル(エッジトリガー)割り込みを生成することを示しま す。これはデフォールトです。 COR_SOFT_RESET このビットをセットすることで、「ソフト」リセット動作を実行しま す。カードをリセットしたい時には、ドライバはこのレジスタに直接に 書き込むのではなく、ResetCard 呼び出しを使うべきです。 4.2.2. カードの構成情報と状態レジスタ 次のビット変数が定義されています: CCSR_INTR_ACK このビットが設定されている場合、CCSR_INTR_PENDING ビットは陽にク リアされるまでセットされたままになります。 CCSR_INTR_PENDING このカードが現在割り込み要求をしていることを示す。この信号は割り 込み共有を目的として使われることもあります。 CCSR_POWER_DOWN このビットをセットすると、カードに対してパワーダウンモードに入る ことを要求します。 CCSR_AUDIO_ENA このビットをセットすると、カードのオーディオ出力を可能にします。 CCSR_IOIS8 このビットをセットすることで、このホストは 8 ビット入出力しか行 なえないので、16 ビットの入出力は二回に分けた 8 ビット入出力で実 行することを通知します。 CCSR_SIGCHG_ENA このビットをセットすることで、カードが WP, READY, BVD1, BVD2 信 号の変化を、SIGCHG 信号を通じて伝えるように要求します。 CCSR_CHANGED このビットがセットされることで、ピン代替レジスタのいずれかのビッ トの状態が変化したことがホストに通知されます。 4.2.3. ピン代替レジスタ ソケットがメモリ/入出力モードで動作する時に使えなくなってしまう(ピン の) 信号をこのレジスタの中の信号で置き換えることができます。 (訳注: ピ ンが足りなくなってしまって、ソケット経由で引き出すことができなくなった 信号をソフトウエア的にこのレジスタを通じて読み出すことができるという意 味でしょう) このレジスタの中の信号のどれかが変化した時には通常、カード は SIGCHG 信号をアサートし、ドライバはこのレジスタを読み出すことで、何 が起きたのかを知ることができます。 次のビット変数が定義されています: PRR_WP_STATUS 書き込み信号の現在の状態。 PRR_READY_STATUS レディ信号の現在の状態。 PRR_BVD2_STATUS 電池警告信号の現在の状態。 PRR_BVD1_STATUS 電池切れ信号の現在の状態。 PRR_WP_EVENT 最後に PRR レジスタが読み出されてから、書き込み禁止信号が変化し たことを示す。 PRR_READY_EVENT 最後に PRR レジスタが読み出されてから、レディ信号が変化したこと を示す。 PRR_BVD2_EVENT 最後に PRR レジスタが読み出されてから、電池警告信号が変化したこ とを示す。 PRR_BVD1_EVENT 最後に PRR レジスタが読み出されてから、電池切れ信号が変化したこ とを示す。 このレジスタは書き込みも可能です。この場合には STATUS ビットはマスクと して機能します。つまり、その STATUS ビットがセットされている場合には、 対応するEVENT のビットが書き込みによって更新されます。 4.2.4. ソケットとコピーレジスタ このレジスタは、いくつかの同じカードが同じ範囲の入出力ポートを共有する ような設定を可能にするような場合や、いくつかのデバイスを制御する ISA バスのカードをエミュレートする場合に使われます。例えば、一枚の ISA ハ ードディスクコントローラは、入出力ポートにドライブ番号を書き込むことで 複数のドライブを制御することができます。何枚かの PCMCIA ドライブカード によってこのようなコントローラをエミュレートするためには、どの入出力操 作がどれに対するものであるかを識別できるように、それぞれのカードが自分 がどのドライブであるかを「知る」必要があります。 次のビット変数が定義されています: SCR_SOCKET_NUM カードの位置するソケット番号を表している必要があります。 SCR_COPY_NUM 複数の同じカードがシステムに存在する時には、この変数はそれらのカ ードのどれであるのかを識別するための特有な番号に設定されている必 要があります。 4.2.5. 拡張状態レジスタ 次のビット変数が定義されています: ESR_REQ_ATTN_ENA セットされると、ESR_REQ_ATTN ビットがセットされた時に CCSR_CHANGED ビットもセットされるのと同様にどうしても状態変化割 り込みが発生します。 ESR_REQ_ATTN モデムへ着信があったときなど、なんらかのカードイベントが発生した ことを示します。 5. カードサービスイベントの扱いについて カードサービスイベントはいくつかの情報源を持っています。: o カードの状態変更が下位のソケットドライバから報告されました。 o カードサービス自身が人為的なイベントを発生させました。 o アドバンスドパワーマネージメント(APM) のイベント。 o その他のカードサービスクライアントが発生させたイベント。 ソケットドライバのイベントは割り込み駆動またはポーリングのどちらかとな ります。 5.1. イベントハンドラの操作 カードサービスがイベントが発生した事を認識した時に、それぞれのクライア ントがイベント通知を受けたかイベントマスクを調査します。カードサービス にクライアントか登録された時、イベントハンドラの回収(callback)関数を指 定します。このハンドラは次の様式をしています。: int (*event_handler)(event_t event, int priority, event_callback_args_t *args); priority 変数は通常のイベント用の CS_EVENT_PRI_LOW か即時応答要求のイ ベント用の CS_EVENT_PRI_HIGH なのかを設定します。高優先順位のイベント のみ CS_EVENT_CARD_REMOVAL を設定します。クライアントイベントハンドラ はこの高優先順位のイベントを特に出来るだけ速くカードサービスが他のクラ イアントに通知出来るように処理します。 event_callback_args_t 構造体の定義は次のとおり: typedef struct event_callback_args_t { client_handle_t client_handle; void *info; void *mtdrequest; void *buffer; void *misc; void *client_data; } event_callback_args_t; client_handle メンバはイベントに対応するソケットのクライアントのハンド ラを設定します。この方法はドライバがいくつかのソケットと結合している場 合に有益です。info 変数は現状では ResetCard へ渡す呼出しの終了状態を返 すのに使われるだけです。client_data 変数は該当するデバイスと関連するロ ーカルなデータ構造体を指すのにドライバが使います。他の変数は使われてい ません。 5.2. イベントの説明 CS_EVENT_CARD_INSERTION カードが挿入された事を表すイベント信号。ドライバが使用中のソケッ トに結合されている場合は、カードサービスはドライバに人為的に挿入 イベントを送出します。 CS_EVENT_CARD_REMOVAL カードが抜かれた事を表すイベント信号。このイベントはカードサービ スが全てのクライアントに可能な限り速く通知する為に最小の遅延時間 で取り扱います。 CS_EVENT_BATTERY_LOW ``電池不足''状態に変化した事を表すイベント信号。 CS_EVENT_BATTERY_DEAD ``電池切れ''状態に変化した事を表すイベント信号。 CS_EVENT_READY_CHANGE ``準備完了''状態に変化した事を表すイベント信号。 CS_EVENT_WRITE_PROTECT ``書き込み禁止''状態に変化した事を表すイベント信号。 CS_EVENT_REGISTRATION_COMPLETE RegisterClient の呼び出しが成功した後にドライバに送るイベント。 CS_EVENT_RESET_REQUEST クライアントが ResetCard を呼んだ時に送るイベント。イベントハン ドラは呼び出しが失敗したらリセット操作を拒否できます。 CS_EVENT_RESET_PHYSICAL リセット信号をカードに送る直前に全てのクライアントに送ります。 CS_EVENT_CARD_RESET リセット操作が終了したら送るイベント信号。リセットが成功したか失 敗したかは GetStatus を使用して認識します。 CS_EVENT_RESET_COMPLETE ResetCard を呼んでリセット処理の完了したことをクライアントに通知 するイベント。 CS_EVENT_PM_SUSPEND カードサービスがユーザの初期化または APM サスペンド要求を受け 取った事を表すイベント信号。イベントハンドラは呼び出しが失敗した らサスペンドを拒否できます。 CS_EVENT_PM_RESUME サスペンド/リジューム命令の後でシステムが停止したことを表す信 号。 CS_EVENT_MTD_REQUEST MTD メモリ操作の初期化に使います。要求の種類は callback 引数の mtdrequest 変数の中に渡されます。ホストのバッファアドレスは buffer 変数に渡されます。 CS_EVENT_ERASE_COMPLETE キューに入れた消去操作が終了した事をクライアントに通知するのに使 用します。消去キューへのポインタは callback 引数の info 変数に返 ります。 5.3. クライアントドライバのイベント操作の役割について クライアントドライバはソケットが設定されたか解除されたかによって発生す る CS_EVENT_CARD_INSERTION イベントと CS_EVENT_CARD_REMOVAL イベントに 応答します。従ってカードの除去は高い優先度のイベントなのでドライバは即 時にソケットとの入出力を遮断し、device 構造体にフラグを設定し、その他 全ての処理を後で発生する時間割り込みを使用して中止するように予定に組み 込みます。 CS_EVENT_PM_RESET_REQUEST イベントを受け取った時は、ドライバは入出力を 遮断しロックしたソケットの設定を解放し、ドライバはソケットの設定と遮断 前の入出力を格納します。CS_EVENT_CARD_RESET を受け取った時は、ドライバ 構成を格納し入出力の封鎖を解きます。 入出力が遮断されかつソケットの構成が解放された場合に CS_EVENT_PM_SUSPEND イベントは大体 CS_EVENT_PM_RESET_REQUEST イベント のように扱われます。 CS_EVENT_PM_RESUME イベントを受け取った時はドライ バがカードの再設定の準備が出来ている場合を除いて、CS_EVENT_CARD_RESET イベントを受け取った時と同様です。 6. メモリテクノロジドライバ メモリテクノロジドライバ (``MTD'') は、ある種のメモリデバイスでさまざ まなメモリサービスを実現するために、カードサービスが使用します。 MTD は、RegisterClient を呼び出して、通常のカードサービスのクライアントと して登録しなければなりません。カード挿入のイベントを受け取ったら、管理 するメモリの範囲を知るために、GetFirstRegion と GetNextRegion を呼び出 します。そうしたら、RegisterMTD を使ってそれらの範囲を制御します。MTD の読み出し、書き込み、消去の要求は、カードサービスによって CS_EVENT_MTD_REQUEST にパッケージ化され、MTD のイベントハンドラに渡さ れて処理されます。 6.1. MTD 要求の処理 MTD は、カードサービスからの要求を CS_EVENT_MTD_REQUEST イベントとして 受け取ります。カードサービスは、要求の内容をイベントコールバックの引き 数の mtdrequest 変数に入れて渡します。データをホストと受け渡しする要求 については、ホストのバッファのアドレスが buffer 変数に渡されます。 mtd_request_t 構造体の定義は次のとおり: typedef struct mtd_request_t { u_long SrcCardOffset; u_long DestCardOffset; u_long TransferLength; u_long Function; u_long MediaID; u_long Status; u_long Timeout; } mtd_request_t; Function の変数はビットマップで、この要求で実行される動作を示していま す。 MTD_REQ_ACTION MTD_REQ_ERASE, MTD_REQ_READ, MTD_REQ_WRITE, MTD_REQ_COPY のいず れか。 MTD_REQ_NOERASE ブロックの境界と大きさがにぴったりはまるような書込みコマンドのと き、消去が不要なことを示します。 MTD_REQ_VERIFY 書き込み確認(verify) を指定します。 MTD_REQ_READY この要求が、前回の要求がカードが準備完了を返すまで延期された後の 再試行であることを示します。 MTD_REQ_TIMEOUT この要求が、前回の要求が時間切れで延期された後の再試行であること を示します。 MTD_REQ_FIRST この要求が、一連の要求の最初のものであることを示します。 MTD_REQ_LAST この要求が、一連の要求の最後のものであることを示します。 MTD_REQ_KERNEL 読み書きコマンドのホストバッファが、ユーザメモリでなくカーネルメ モリ中にあることを示します。 MediaID 変数は、このメモリ範囲を表わすために RegisterMTD 要求の中で指 定された値です。Status 変数は、デバイスが何らかの処理を実行中で要求に 応えることができなかったことを表わすために MTD が使います。MTD 要求 は、通常は封鎖しません。要求が通常は封鎖するような場合でも、実際には封 鎖せず、エラーコードとして CS_BUSY を返し、Status に次のいずれかの値を 設定するはずです。訳注:「封鎖」は「block」の訳語です。「塊」の意味の 「ブロック」 (「データブロック」など) との混同を避けるために使っていま す。使用例:宇津宮孝一・福田晃共訳「オペレーティングシステムの概念」 (1987年・倍風館) MTD_WAITREQ 現在実行中の別の要求の処理が正常終了した後に、要求を再試行すべき であることを示します。 MTD_WAITTIMER timeout 変数で示される時間が経過した後に、要求を継続すべきである ことを示します。 MTD_WAITRDY カードが準備完了状態になるか,あるいは timeout 変数で示される時 間が経過するか、どちらかが先に起った後に、要求を継続すべきである ことを示します。 MTD_WAITPOWER ソケットの電源の供給に影響する何事かが起った後に、要求を再試行す べきであることを示します。 MTD_WAITTIMER と MTD_WAITRDY では、Timeout 変数の値はミリ秒単位のタイ ムアウトの時間です。 6.2. MTD 支援関数 MTD はカードサービスが発生する要求を処理するので、MTD のイベントハンド ラから安全に実行できるカードサービス呼び出しの種類には制限があるかもし れません。 MTD の支援関数は、MTD が必要とするかもしれないが通常のカー ドサービス呼び出しを使って実現するとすると扱いにくいであろう特別なサー ビスを、限定されたセットとして提供します。 Linux における PCMCIA の実 装では、ほとんどのカードサービス呼び出しは MTD から安全に呼び出すこと ができますが、互換性のために MTD の支援インターフェイスが含まれていま す。 #include "cs_types.h" #include "cs.h" #include "bulkmem.h" int MTDHelperEntry(int subfunc, void *arg1, void *arg2); 6.2.1. MTDRequestWindow, MTDReleaseWindow int MTDHelperEntry(MTDRequestWindow, client_handle_t *handle, win_req_t *mod); int MTDHelperEntry(MTDReleaseWindow, window_handle_t handle); These services are identical to the standard Card Services RequestWindow and ReleaseWindow calls. 6.2.2. MTDModifyWindow int MTDHelperEntry(MTDModifyWindow, memory_handle_t handle, mtd_mod_req_t *mod); mtd_mod_req_t の構造体は次のとおり: typedef struct mtd_mod_req_t { u_long Attributes; u_long AccessSpeed; u_long CardOffset; } mtd_mod_req_t; MTDModifyWindow は、通常の ModifyWindow と MapMemPage の呼出しを使うの と本質的に同じです。 Attributes で指定できる内容は次のとおり。: WIN_MEMORY_TYPE WIN_MEMORY_TYPE_CM で一般メモリを示すか、または WIN_MEMORY_TYPE_AM で属性メモリを示します。 WIN_USE_WAIT コントローラがカードの MWAIT 信号を監視する必要があることを示し ます。 MTDModifyWindow で設定された領域は常に使用可能であり、16 ビットのデー タ幅を持ちます。 戻り値 : CS_BAD_HANDLE メモリハンドルが不正です。 6.2.3. MTDSetVpp int MTDHelperEntry(MTDSetVpp, client_handle_t client, mtd_vpp_req_t *req); typedef struct mtd_vpp_req_t { u_char Vpp1, Vpp2; } mtd_vpp_req_t; MTDSetVpp はソケットのプログラム電圧を変更します。Vpp1 と Vpp2 は 1/10 ボルト単位で与えられます。現在のところ、Vpp1 と Vpp2 は常に等しくなけ ればなりません。 戻り値 : CS_BAD_HANDLE クライアントハンドルが不正です。 CS_BAD_VPP 指定された Vpp が正しくないか、または Vpp1 と Vpp2 が等しくな い。 6.2.4. MTDRDYMask int MTDHelperEntry(MTDRDYMask, client_handle_t client, mtd_rdy_req_t *req); typedef struct mtd_rdy_req_t { u_long Mask; } mtd_rdy_req_t; MTDRDYMask は、CS_EVENT_READY_CHANGE イベントを使用できるようにするか どうかを選択します。クライアントは、RegisterClient 又は SetEventMask のいずれかの呼出しを使って、カードサービスに対してこれらのイベントを受 け取ることを表明しておかなければなりません。Mask 引き数の CS_EVENT_READY_CHANGE ビットがセットされていると、イベントの変更ができ るようになります。 戻り値 : CS_BAD_HANDLE クライアントハンドルが不正です。 7. ドライバサービスインタフェース ドライバサービスは、カードサービスのクライアントドライバと cardmgr の ようなユーザモードのユティリティを結び付けます。カードサービスの「スー パクライアント」といってもよいでしょう。ドライバサービスは、 BindDevice 関数を使って、他のクライアントドライバをそれぞれの PCMCIA カードと結び付けます。他のクライアントとは異なり、ドライバサービスは、 カードの抜き差しが行われても、ずっと全部のソケットに拘束されたまま残り ます。 7.1. 他のクライアントドライバへのインタフェース ドライバサービスは、導入されていてソケットに結合できる状態になっている すべてのクライアントドライバを把握しています。クライアントドライバに は、デバイスの「実体」の作成と削除をするための項目がなければなりませ ん。ここで言うデバイスの実体とは、ある PCMCIA カードを制御するために必 要なすべてを意味します。 各デバイスは、cs_types.h に定義された特別な型 dev_info_t を持つ、ユニ ークな1 6 文字のタグで識別されます。各デバイスの実体は、 dev_link_t 構 造体で記述されます。 7.1.1. dev_link_t 構造体 dev_link_t のデータ構造体は次のとおり: #include "ds.h" typedef struct dev_node_t { char dev_name[8]; u_char major, minor; struct dev_node_t *next; } typedef struct dev_link_t { dev_node_t *dev; u_long state, open; struct wait_queue *pending struct timer_list release client_handle_t handle; io_req_t io; irq_req_t irq; config_req_t conf; window_handle_t win; void *priv; struct dev_link_t *next; } dev_link_t; dev_link_t 構造体の dev 変数はリンクリストの dev_node_t 構造体をポイン トしています。dev_node_t の dev_name 変数は、ドライバによって、このデ バイスをアクセスするためのファイル名が書き込まれます(可能な場合のみ)。 例えば、serial_cs は「ttyS1」の様な名前を使います。major と minor の変 数は、このデバイスをアクセスするためのメジャー番号とマイナー番号です。 ドライバサービスは、これらの変数を DS_GET_DEVICE_INFO ioctl でユーザモ ードプログラムに返します。 dev_link_t の state 変数は、現在のデバイスの状態を把握するために使われ ます。次のフラグが定義されています。: DEV_PRESENT カードが存在することを示します。このビットは、ドライバのイベント ハンドラによって、カードの抜差しのイベントに対応してセットまたは クリアされます。 DEV_CONFIG カードが設定済みであることを示します。 DEV_CONFIG_PENDING カードの設定作業が実行中であることを示します。 DEV_SUSPEND カードが一時的に使用できないことを示します。 DEV_BUSY 入出力動作が実行中であることを示します。このビットは、アクセスの 衝突を防ぐためのインターロックとして使うこともできます。 DEV_STALE_CONFIG ドライバによっては、実行中のカードが抜かれた時には、そのカードに 対応するすべてのデバイスが閉じるまでは、ソケットを解放すべきでは ありません。このフラグは、デバイスがク閉じた時にソケットを解放し なければならないことを示します。 DEV_STALE_LINK ドライバの実体は、そのすべての PCMCIA リソースが解放されるまで削 除されてはなりません。このフラグは、ソケットが解放されたらすぐに ドライバの実体が削除されなければならないことを示します。 open 変数は、このデバイスが何重に使われているかを数えます。デバイス は、このカウントがゼロになるまで解放されてはなりません。 pending 変数 は、このデバイスを使うために待っているプロセスの待ち行列を管理するため に使うことができます。 release 変数は、カードが抜かれた時に、デバイスのシャットダウン処理を予 定に入れるために使われます。カードの引抜きのイベントは高い優先度で実行 されなければなりません。ドライバのイベントハンドラは、通常デバイス状態 の DEV_PRESENT ビットをリセットし、その時シャットダウン処理が後で実行 されるように予定することでイジェクトの処理をします。 handle、io、irq、confおよび win の各変数は、通常の PCMCIA 入出力カード を組み込むために必要な普通の PCMCIA データ構造に対応します。 priv 変数は、デバイスを管理するために必要などんな私的なデータ構造の目 的のためにでも使うことができます。next 変数は、複数の実体を扱うことの できるドライバで、dev_link_t 構造体の結合リストを作るために使うことが できます。 7.1.2. register_pcmcia_driver int register_pcmcia_driver(dev_info_t *dev_info, dev_link_t *(*attach)(void), void (*detach)(dev_link_t *)); register_pcmcia_driver は、ドライバサービスに、クライアントドライバが 存在していてソケットに結び付けられる状態であることを知らせます。ドライ バサービスがこのドライバの dev_info 文字列に等しい DS_BIND_REQUEST ioctl を受け取ると、ドライバサービスはドライバの attach() 関数を呼び出 します。DS_UNBIND_REQU EST ioctl を受け取ったときは、detach() を呼び出 します。 7.1.3. unregister_pcmcia_driver int unregister_pcmcia_driver(dev_info_t *dev_info); この関数は、ドライバサービスに、指定されたクライアントドライバにはソ ケットを結び付けてはならないことを知らせます。 7.2. ユーザモードの PCMCIA ユティリティとのインタフェース ドライバサービスは、ユーザモードの PCMCIA ユティリティと通信するために 疑似デバイスを作ります。このデバイスのメジャー番号は動的に選ば れ、PCMCIA ユティリティは /proc/devices を読んでその値を得なければなり ません。マイナー番号は 0 から始まるソケットの番号に対応します。 ただ一つのプロセスだけが、あるソケットを読書きのためにオープンすること ができます。他のプロセスは、読出し専用モードでのみ、このソケットをオー プンできます。読出しのみの接続では、一部の ioctl 機能だけが使えます。 読書き両方の接続では、すべての ioctl 機能が使え、カードサービスからの イベントの通知を受け取ることができます。 7.2.1. カードサービスのイベント通知 ドライバサービスは、イベントの通知のために read() と select() の関数を 実装しています。ある PCMCIA デバイスから読出しを行うと、前回の read() 以降ドライバサービスが受信したすべてのイベントが unsigned long の値と して返されます。もしイベントが何も発生していなければ、イベントが発生す るまで、呼出しは封鎖します。select() を使って、複数のソケットの新規の イベントを監視することができます。 ドライバサービスは、次のイベントを監視します。: CS_EVENT_CARD_INSERTION, CS_EVENT_CARD_REMOVAL, CS_EVENT_RESET_PHYSICAL, CS_EVENT_CARD_RESET と CS_EVENT_RESET_COMPLETE. 7.2.2. ioctl の説明 ほとんどのドライバサービスの ioctl の動作は、カードサービスの関数に直 接対応します。ioctl の呼出しは、次の形式です。: int ioctl(int fd, int cmd, ds_ioctl_arg_t *arg); ds_ioctl_arg_t の構造体は次のとおり: typedef union ds_ioctl_arg_t { servinfo_t servinfo; adjust_t adjust; config_info_t config; tuple_t tuple; tuple_parse_t tuple_parse; client_req_t client_req; status_t status; conf_reg_t conf_reg; cisinfo_t cisinfo; region_info_t region; bind_info_t bind_info; mtd_info_t mtd_info; } ds_ioctl_arg_t; 次の ioctl のコマンドは、対応するカードサービスの関数を実行します。: DS_GET_CARD_SERVICES_INFO CardServices(GetCardServicesInfo, ..., &arg->servinfo) を呼び出 します。 DS_ADJUST_RESOURCE_INFO CardServices(AdjustResourceInfo, ..., &arg->adjust) を呼び出しま す。 DS_GET_CONFIGURATION_INFO CardServices(GetConfigurationInfo, ..., &arg->config) を呼び出し ます。 DS_GET_FIRST_TUPLE CardServices(GetFirstTuple, ..., &arg->tuple) を呼び出します。 DS_GET_NEXT_TUPLE CardServices(GetNextTuple, ..., &arg->tuple) を呼び出します。 DS_GET_TUPLE_DATA CardServices(GetTupleData, ..., &arg->tuple_parse.tuple) を呼び 出します。タプルデータが arg->tuple_parse.data の中に返ります。 DS_PARSE_TUPLE CardServices(ParseTuple, ..., &arg->tuple_parse.tuple, &arg->tuple_parse.parse) を呼び出します。 DS_RESET_CARD CardServices(ResetCard, ...) を呼び出します。 DS_GET_STATUS CardServices(GetStatus, ..., &arg->status) を呼び出します。 DS_ACCESS_CONFIGURATION_REGISTER CardServices(AccessConfigurationRegister, ..., &arg->conf_reg) を呼び出します。 DS_VALIDATE_CIS CardServices(ValidateCIS, ..., &arg->cisinfo) を呼び出します。 DS_SUSPEND_CARD CardServices(SuspendCard, ...) を呼び出します。 DS_RESUME_CARD CardServices(ResumeCard, ...) を呼び出します。 DS_EJECT_CARD CardServices(EjectCard, ...) を呼び出します。 DS_INSERT_CARD CardServices(InsertCard, ...) を呼び出します。 DS_GET_FIRST_REGION CardServices(GetFirstRegion, ..., &arg->region) を呼び出します。 DS_GET_NEXT_REGION CardServices(GetNextRegion, ..., &arg->region) を呼び出します。 次の ioctl のコマンドは、特別なドライバサービスの関数を呼び出します。 これらのコマンドは、bind_info_t 構造体に作用します。: typedef struct bind_info_t { dev_info_t dev_info; u_char function; struct dev_info_t *instance; char name[8]; u_char major, minor; void *next; } bind_info_t; DS_BIND_REQUEST このコマンドは、ソケットをクライアントドライバに接続します。指定 されたデバイス識別子の dev_info が、登録されたドライバのリストか ら検索されます。もしこのカードが多機能カードの場合は、 function 変数がどのカード機能を接続するかを指定します。もしドライバが見つ かると、ドライバはこのソケットと機能を、 BindDevice を呼び出すこ とによって接続されます。その後、ドライバサービスはドライバの attach() 項目を呼び出してデバイスの実体を作成します。新しい dev_link_t が instance の中に返されます。 DS_GET_DEVICE_INFO このコマンドは、instance が指し示す dev_link_t 構造体から、 dev_name、major、 minor の項目を検索します。 DS_UNBIND_REQUEST このコマンドはドライバと instance を指定した detach() 関数を呼び 出してデバイスをシャットダウンさせます。 最後に DS_BIND_MTD 要求は、引き数に mtd_info_t の型をとります。: typedef struct mtd_info_t { dev_info_t dev_info; u_long Attributes; u_long CardOffset; } mtd_info_t; この呼び出しは、dev_info によって識別される MTD と Attributes と CardOffset によって記述されるメモリ範囲を関連づけます。 Attributes と CardOffset は、カードサービスの BindMTD の呼出しのときと同じ意味です。 8. カードサービスクライアントドライバの解剖 Linux PCMCIA パッケージのそれぞれの版は、最初から新規にドライバを書け るように良く文書化された``雛型''のクライアントドライバと一緒に提供して います。 modules/skeleton.c に置いています。 8.1. モジュールの初期化とリセット 全てのローダブルモジュールは init_module() と cleanup_module() 関数を 備えなければいけません。それはモジュールを着脱するときにモジュールを支 援するプログラムが必要とするからです。PCMCIA クライアントドライバの初 期化関数は register_pcmcia_driver() 呼び出し経由でドライバサービスに よってドライバを登録します。再初期化(cleanup) 関数は unregister_pcmcia_driver() を使用してドライバサービスによって登録解除 します。ドライバによっては、再初期化関数はシャットダウン時に存在するデ バイスの構造体を解放する為にも呼ばれるかもしれません。 8.2. *_attach() と *_detach() 関数 *_attach() 関数はドライバの ``実体'' を作成し、1つの PCMCIA カードの管 理に必要なデータ構造体の設定を行なう役目があります。*_attach() 関数は dev_link_t 構造体の割り当てと初期化を行ない、RegisterClient を呼び出し てカードサービスとの結合を確立します。RegisterClient は新しく出来た dev_link_t 構造体へのポインタを返し、作成できなかった時は NULL を返し ます。 *_detach() 関数は以前に発行した *_attach が作成したドライバの実体を削 除します。また、カードサービスとの結合も DeregisterClient を使って解除 します。 *_attach() 関数は DS_BIND_REQUEST ioctl() で一致するドライバが識別で き、割り付けがうまくいった時にドライバサービスによって呼ばれます。 *_detach() 関数は DS_UNBIND_REQUEST ioctl() を呼ぶことに応答し起動しま す。 8.3. *_config() と *_release() 関数 *_config() 関数はカードに対する入出力の準備の為に呼ばれます。殆んどの ドライバは詳細な情報はカード自身から読み出しますが、どのようにデバイス を設定するかの最小限の知識はドライバに組み込まれています。例えば、シリ アルカードのドライバはカードの CFTABLE_ENTRY タプルから一致する入出力 ポートの基底アドレスと一致する設定指標を読み込みますが、 CIS 内の割り 込み情報は無視します。*_config 関数はカードの CIS の関連する部分を解析 します。そして RequestIO, RequestIRQ や RequestWindow を呼び出せます。 それから RequestConfiguration を呼びます。 カードの設定がうまくいったら、*_config() ルーチンが dev_link_t 構造体 の dev_name, major と minor 変数に書き込みます。これらの変数は DS_GET_DEVICE_INFO ioctl () の応答としてドライバサービスがユーザプログ ラムに返します。 *_release() 関数は以前に呼んだ *_config() が割り当てたリソースを解放 し、デバイスの dev_name 変数を空白にします。 *_config() と *_release 関数は通常カード状態の変更イベントまたはタイマ ー割り込みに反応して呼ばれます。この時、これらの関数はスリープ出来な く、他のカーネル関数から呼ばれないように遮断しておきます。 8.4. PCMCIA イベントハンドラ *_event() 関数はカードサービスからカード状態次変更イベントを通知する為 に呼ばれます。 8.5. ロックと同期について 設定したソケットは全ての関連したデバイスが閉じられた時にのみ解放されま す。ソケットの解放はソケットのシステム資源を他のデバイスで使用出来るよ うにします。解放された資源が元のデバイスで入出力に使用している場合は、 元のドライバは新しいデバイスを使用してします。 ドライバの実体は一致するソケットの構成が解放された後のみ解放されます。 カードサービスは DeregisterClient が成功する為にはクライアントが明らか に割り当てた資源を解放する必要があります。 全てのローダブルモジュールは安全にモジュールを解放する時にシステムが使 用する ``使用回数(use count)'' を持っています。PCMCIA クライアントドラ イバの慣習はデバイスをオープンすると使用回数を増加させ、デバイスをクロ ーズすると使用回数を減少させます。従ってドライバを解放するには全ての関 連するデバイスは閉じている必要があります。特に、ソケットが接続している 時にドライバを解放出来ます。モジュール再初期化プログラムは適切な解放で きる既に割当済みの資源を必要とします。これは使用回数がゼロで、全てのデ バイスが閉じていて、つまり全てのソケットが解放できる状態で全てのデバイ スが外せる場合に安全な方法です。 デバイスが開いている状態で *_release() 関数が呼ばれたら、デバイス状態 の DEV_STALE_CONFIG フラグが設定され close() 関数が呼ばれた時にデバイ スを解放するように通知します。構成したデバイスを*_detach() 関数で呼び 出したら、DEV_STALE_LINK フラグは *_release() 関数が呼ばれた時に実体が 解放されるように通知するように設定されます。 8.6. 現有の Linux のドライバで PCMCIA デバイスをアクセスする方法 現在の PCMCIA クライアントドライバは現有の Linux のドライバをデバイス の入出力操作を行ないます。カードサービスクライアントモジュールはカード の構成とカード状態の変更イベントの監視を行ないますが、通常の ISA バス のカードのドライバと互換性のある入出力を行ないます。いくつかの場合で は、普通のドライバを変更無しに使う事が出来ます。しかしながら、活線抜去 やパワーマネージメントのような PCMCIA の機能はすべてはサポートされてい ませんので、PCMCIA クライアントプログラムとデバイス入出力プログラムの 間で通信をする必要があります。 殆んどのドライバはブート時にデバイスを探知するのと着脱出来るデバイスを 扱うように設計されています。ドライバのモジュール化の副作用は通常着脱可 能なデバイスを扱うのにモジュラー化したドライバは簡単に受け入れられると いうことです。 重要な事は、適切でない時にデバイスを取り去ってしまいデバイスドライバが 使えなくなる事です。最善の方法はドライバが入出力操作や入出力割り込みを 行なう前にデバイスを事前に確認する事です。デバイスの状態の確認の繰返し は時間切れになってしまい、結局デバイスが応答しない場合は終了します。 9. さらなる情報はどこにあるか? Michael Johnson が書いた Linux カーネルハッカーの手引き (Linux Kernel Hackers' Guide) は Linux のデバイスドライバを書く為の良い一般的な情報 源です。一般の Linux の FTP サイトにまとめられた Linux 文書とともにお いてあります。 本物の PCMCIA 標準は PCMCIA 協会それ自身だけが発行してますが途方もなく 高価です。新しい PC Card 95 標準は 399 ドルですが古い 2.1 標準はかなり 値引きが出来ると思います。 Personal Computer Memory Card International Association 1030 East Duane Avenue, Suite G Sunnyvale, CA 94086 USA (408) 720-0107, (408) 720-9416 FAX, (408) 720-9388 BBS http://www.pc-card.com その代わりにMichael Mori が書いた PCMCIA 開発者の手引き (PCMCIA Developer's Guide) は Sycard Technology から発行され、 ISBN 0-9640342-1-2 で、およそ 89.95 ドルです。 Sycard Technology 1180-F Miraloma Way Sunnyvale, CA 94086 USA (408) 749-0130, (408) 749-1323 FAX Dana Beatty, Steven Kipisz と Brian Moore が書いた PCMCIA ソフトウェア 開発者のハンドブック (PCMCIA Software Developer's Handbook) はPCMCIA 標準の概要とクライアントドライバの書き方の説明をしています。ま た、Linux PCMCIA プログラマの手引きを付録に添付しています。発行は Peer-to-Peer Communications で ISBN 1-57398-010-2 です。 Larry Levine はより一般的な PCMCIA への紹介文である 1995 年の夏に書店 に並んだ PCMCIA 入門(PCMCIA Primer)を書いています。 M & T Books が出版 し、ISBN 1-55828-437-0 です。 各種の PCMCIA 制御装置に関するプログラム情報は該当するチップベンダーか ら取り寄せましょう。: Intel Corporation (800) 628-8686 Cirrus Logic (510) 623-8300 Vadem (408) 943-9301 Databook Inc. (716) 889-4204 [EOF]