この章の目次にもどる
次頁:第2章 PC (PCMCIA) カードマネージャにすすむ

第1章 デバイスドライバ共通仕様

1.1 概要

デバイスドライバは、 中心核 ( ITRON ) 上で独立したタスクとして動作し、 デバイスに対して以下の基本操作を要求に応じて行う。

通常要求
OPEN デバイスの使用開始
CLOSE デバイスの使用終了
CLOSEALLデバイスの使用終了、メディアのイジェクト
READ データの読み込み
WRITE データの書き込み
特殊要求
ABORT 現在の処理のアボート
SUSPEND サスペンド状態へ移行
RESUME リジューム(サスペンド状態から復帰)
CARDEVENTPCMCIA カードの事象
USBEVENTUSB デバイスの事象

また、デバイス毎に決められた事象の発生を検出し、事象通知を行う。

ドライバが取り扱うデータはデータ番号により指定され、 以下の 2 種類に大別される。

属性データ : データ番号 < 0
ドライバ / デバイスの状態や特殊処理のために使用される基本的に固定長のデータ。 原則として、データ全体の一括の読み込み / 書き込みのみ可能。
固有データ : データ番号 ≧ 0
デバイスの固有データを意味する基本的に可変長のデータ。 原則として、指定したサイズのデータの読み込み / 書き込みが可能。

デバイスドライバは、BTRON のプロセス / タスクではなく、 ITRON のタスクとして動作する。 したがって、ランデブなどの同期・通信機能も、 ITRON のシステムコールを使用する。

1.2 基本構造

デバイスドライバーの基本構造および基本的な処理方法を示す。 ここに記述されている方法に囚われる必要はない。 デバイスドライバーの内部構造および処理方法は、 対象のハードウエアにより様々である。 デバイス管理など外部とのインターフェースが 仕様に則っていれば内部は自由である。

デバイスドライバーの基本構造
図 1 : デバイスドライバーの基本構造

通常要求処理タスクの動作

システム初期化 ( デバイスドライバー起動処理 ) 時にタスクとして起動される。 タスク起動パラメータとしてデバイスに固有のパラメータが渡される。

  1. 各種初期化を行う。
  2. デバイス管理にデバイス登録を行う。
  3. 受付用ランデブポートより、通常要求を受け付ける。
  4. 要求に対応する処理を行い、ランデブ応答を戻す。待ちに入る処理は一般的に以下のように行う。
    1. 要求の初期処理を行う
    2. 割り込み / タイムアウト待ち
    3. 割り込み / タイムアウト後の処理
    4. さらに処理が必要な場合は、1.へ戻る
  5. 3.へ戻る。

特殊要求処理タスクの動作

ドライバ初期化時に、必要に応じて生成 / 起動される。

  1. 受付用ランデブポートより、特殊要求を受け付ける。
  2. ABORT 要求:
    指定されたタスクからの要求を処理中の時は、 その処理をエラー終了させる。そうでなければ、何もしない。
    異常終了させる処理は、一般的に以下のように行う。
    1. 要求処理タスクの待ちを、何らかの方法で解除し、 エラー応答のランデブ応答を戻すようにする。
    2. デバイスに対しての処理を中断し、 今後の処理に問題ないように後始末を行う。
    SUSPEND 要求:
    サスペンド処理を行う(詳細後述)
    RESUME 要求:
    リジューム処理を行う(詳細後述)
    CARDEVENT 要求:
    PC カードの処理を行う(詳細は第2章 PC (PCMCIA) カードマネージャ仕様を参照)
    USBEVENT 要求:
    USB デバイスの処理を行う(詳細は第15章 USB マネージャ仕様を参照)
  3. 受け付けたランデブの応答を戻す。
  4. 1.へ戻る。

事象通知の動作

指定された事象通知用メッセージバッファに対して、 事象の発生を通知する。事象はデバイス毎に規定され、 メッセージバッファが指定されている場合は、 すべての事象をそのバッファに通知する。

必要であれば、事象の検出用の別タスクを生成 / 起動する。

定周期に事象の発生をチェックする必要がある場合は、 周期起動ハンドラを使用しても良いが、 事象発生のチェック処理に時間がかかる場合は、 周期起動ハンドラからタスクを起動するようにする。 また、周期に厳密さがあまり必要でない場合は、 周期起動ハンドラを使用せずに、dly_tsk などを使用してもよい。

1.3 デバイスドライバーのエントリー

デバイスドライバーには、 カーネル組み込み形式とカーネルにリンクしない追加組み込み形式がある。 カーネル組み込み形式は、 デバイスドライバーとカーネル ( OS 核 ) をリンクする形式であり、 カーネルをコンパイルできる環境が必要となる。 したがって、一般には追加組み込み形式を使用する。

● カーネル組み込み形式

カーネル組み込み形式の場合 main() 関数はなく、 初期起動タスクがエントリーとなる。

    void XxxxxDriver( DevDrvParam *drvpar )
    typedef struct {
        ID  mbfid;  /* デフォールトの事象通知用MBF ID */
        VP  info;   /* デバイス固有情報へのポインタ */
    } DevDrvParam;

    drvpar  デバイスドライバー起動パラメータ

● 追加組み込み形式

次の形式の main() 関数が、ドライバーのエントリーとなる。

    ERR main( Bool StartUp, TC *arg )
    StartUp True  : 初期化
            False : 終了
            終了は、要求されることがない。
            もし終了要求が来ても、ER_NOSPT を返すだけでよい。
    arg パラメータ

IMS から次のように起動する。

    [IMS]% kerext driver parameter

この parameter の文字列の先頭が arg に渡される。 parameter は空白も含まれる 1 つの文字列である。

main() 関数は、デバイスドライバー起動パラメータ ( DevDrvParam ) を準備し、 デバイスドライバー本体のタスク ( 初期起動タスク ) を起動して return する。 return しないと IMS に制御が戻らない。

main() 関数から return しない限り次のデバイスドライバーの起動は行われない。 デバイスドライバーの起動順序に依存性がある場合は、 return する前に必要な初期化処理をすべて終わらせておくことで起動順序が守られる。

1.4 論理デバイス名

デバイスは、論理デバイス名により識別される。

論理デバイス名は、一般的に種別、ユニット、 サブユニットを示すフィールドから構成されるが、 ユニット、サブユニットが存在しない場合は、 それぞれのフィールドは存在しない。

種別 デバイスの種別を示す名前
ユニット 物理的なデバイスを示す "a" 〜 の 1 文字
サブユニット 論理的なデバイスを示す "0" 〜 の数字

デバイス名には、以下の様なものがある ( 文字コードは TRON コード )

* :
ユニット指定 "a" 〜
# :
サブユニット番号 "0" 〜
hd* ハードディスク(ユニット)
hd*#ハードディスク(パーティション)
fd* フロッピーディスク
rs* RS-232C
kbpd キーボード / ポインティングデバイス

1.5 デバイスの登録

デバイスドライバは初期起動時に自分でサポートするデバイスを上位のデバイス管理に対してユニット毎に登録する。 登録時にデバイスを指定するデバイス ID が戻される。

デバイスの登録は、以下の関数で行う。関数値はデバイス ID。

    ID DefDevice(DevDef *devdef, DiskInfo *info)

    /* デバイス属性 */
    typedef struct {
        UW  devinfo:8;      /* デバイス詳細情報             */
        UW  devkind:8;      /* デバイス/メディア種別        */
        UW  reserved:10;    /* 予約(0)                      */
        UW  openreq:1;      /* 毎回オープン/クローズが必要 */
        UW  lockreq:1;      /* アドレス空間のロックが必要   */
        UW  diskinfo:1;     /* DN_DISKINFO のサポート有無   */
        UW  chardev:1;      /* 文字型デバイス               */
        UW  nowait:1;       /* NOWAITモードの適用の有無     */
        UW  eject:1;        /* イジェクトの可否             */
    } DevAttr;
devinfo :
デバイスの詳細情報を示す値で、デバイスに依存する。
通常はデバイスを物理的に識別するための位置情報が入る。
devkind :
実際のデバイス/メディアの種別を示す値。 上位 4 ビットは基本種別を示し、 下位 4 ビットは同一基本種別内の詳細種別を示す。
ディスクタイプのデバイスに対しては以下が定義されている。 ディスク以外に関しては未定義 ( BTRON3 仕様書 「第2編 OS 仕様 1.8 デバイス管理」を参照 )。
  #define DK_UNDEF        0x00    /* 未定義/不明            */
  #define DK_DISK         0x10    /* ディスクタイプ         */

  #define DK_DISK_UNDEF   0x10    /* その他のディスク       */
  #define DK_DISK_RAM     0x11    /* RAM ディスク           */
  #define DK_DISK_ROM     0x12    /* ROM ディスク           */
  #define DK_DISK_FLA     0x13    /* FLASH ROM / SS ディスク*/
  #define DK_DISK_FD      0x14    /* フロッピーディスク     */
  #define DK_DISK_HD      0x15    /* ハードディスク         */
  #define DK_DISK_CDROM   0x16    /* CD-ROM                 */
openreq :
毎回オープン / クローズ要求が必要な場合は 1、そうでないときは 0
要求ごとに処理が完結しないため、 オープン / クローズされた情報を必要とする場合に指定する。
lockreq :
アドレス空間のロック ( 常駐化 ) が必要な場合は 1、そうでないときは 0
ロック要求とした場合はデバイス管理側でユーザアドレス空間のロック / アンロック処理を行うため、 ドライバ側は常にロックされていることを前提として処理することができる。
diskinfo :
DN_DISKINO をサポートしている場合は 1、そうでないときは 0 ディスクドライバ以外は未サポートとする。 1 とした場合は、 info にディスク情報を設定する。0 の場合には infoNULL とする ( DiskInfo の詳細は後述 ) 。
chardev :
文字型デバイスの場合は 1、そうでないときは 0 この情報はデバイス管理側でデバイスの情報として アプリケーション側に渡すために使用され、動作には影響しない。
nowait :
NOWAIT モードが適用される場合は 1、そうでないときは 0
NOWAIT モードは、非同期処理を意味するのではなく、 デバイスがビジー状態の時に待つか、 待たないかを意味するもので、 待たない場合でも処理自体は完了する ( ポーリング処理 ) 。
外部状況に依存した長時間のビジー状態がある文字型デバイスに対してのみ適用される。
eject :
イジェクト可能な時は 1、そうでない時は 0
    /* デバイス登録 */
    #define L_DEVNM     8   /* デバイス名の長さ     */
    typedef struct {
        DevAttr attr;           /* デバイス属性               */
        W       subunits:       /* サブユニット数             */
        TC      name[L_DEVNM];  /* 登録するデバイス名         */
        ID      portid;         /* 受け付け用ランデブポートID */
    } DevDef;
attr :
登録するデバイスの属性。
subunits :
登録するサブユニット数。0 はサブユニットが存在しないことを意味する。
name[] :
デバイス名 ( ユニット名 ) 。hdafda など。
portid :
要求受け付け用ランデブポート ID。

サブユニット数、登録されるデバイス名、 デバイス ID の関連は以下の通り。

サブユニット数登録されるデバイス名デバイスID
0xxx ID
1xxx ID
xxx0 ID+1
Nxxx ID
xxx0 ID+1
: :
xxx(N-1)ID+N

1.6 デバイス処理要求

デバイス処理要求はランデブによりドライバに渡され、 ドライバは処理を行った後ランデブ応答を戻す。

    /* コマンド種別     */
    typedef enum {
        DC_OPEN         = 1,
        DC_CLOSE        = 2,
        DC_CLOSEALL     = 3,
        DC_READ         = 4,
        DC_WRITE        = 5,
        DC_ABORT        = 6,
        DC_SUSPEND      = 7,
        DC_RESUME       = 8,
        DC_CARDEVENT    = 9,
        DC_USBEVENT     = 10
    } DevCmdKind;

    #define D_CALPTN(devcmd)    ( 1 << (devcmd) )
    /* 通常要求の calptn */
    #define D_NORM_PTN      ( D_CALPTN(DC_OPEN)     \
                             |D_CALPTN(DC_CLOSE)    \
                             |D_CALPTN(DC_CLOSEALL) \
                             |D_CALPTN(DC_READ)     \
                             |D_CALPTN(DC_WRITE)    )
    /* 例外要求の calptn */
    #define D_ABORT_PTN     ( D_CALPTN(DC_ABORT)    \
                             |D_CALPTN(DC_SUSPEND)  \
                             |D_CALPTN(DC_RESUME)   \
                             |D_CALPTN(DC_CARDEVENT) \
                             |D_CALPTN(DC_USBEVENT) )
    /* デバイス要求コマンド */
    typdef  struct {
        UW          nowait:1;   /* NOWAIT モード        */
        UW          rsv0:14;    /* 予約(0)              */
        UW          adcnv:1;    /* アドレス変換モード   */
        DevCmdKind  cmd:16;     /* コマンド             */
    } DevCmd;

    /* デバイス処理要求メッセージ */
    typedef struct {
        ID      devid;      /* 対象のデバイスID */
        DevCmd  cmd;        /* 要求コマンド     */
        W       datano;     /* データ番号       */
        W       datacnt;    /* データ数         */
        ID      taskid;     /* 要求したタスクID */
        VP      memptr;     /* メモリーポインタ */
    } DevReq;

    /* デバイス処理応答メッセージ */
    typedef struct {
        ID      devid;      /* 対象のデバイスID */
        DevCmd  cmd;        /* 要求コマンド     */
        W       datano;     /* データ番号       */
        W       datacnt;    /* データ数         */
        ErrCode error;      /* エラーコード     */
    } DevRsp;
devid:
操作対象デバイスを示すデバイスID。応答時には同じ値を戻す。
cmd:
要求コマンド。応答時には同じ値を戻す。
cmd.nowait :
NOWAIT モード指定
NOWAIT モードをサポートしていない場合は無視する。
cmd.adcnv :
アドレス変換指定
cmd.cmd :
コマンド種別
DC_OPEN :
デバイスの使用を可能にする。
実際の処理内容はデバイスに依存する。
多重にオープンされた場合、 デバイス属性の openreq = 0 の時は、 最初の 1 回のみ発行される。 openreq = 1 の時は、毎回発行される。
taskid にはオープンしたタスク ID、 datano にはオープンしたタスクが属するプロセス ID が入る ( タスク ID、プロセス ID が不明 / 未定義の時は、それぞれ 0 が入る ) 。
datacntmemptr は未使用。
DC_CLOSE :
デバイスの使用を終了する。
実際の処理内容はデバイスに依存する。
多重にオープンされたのちにクローズされた場合、 デバイス属性の openreq = 0 の時は、 最後の 1 回のみ発行される。 openreq = 1 の時は、毎回発行される。
taskid にはクローズしたタスク ID、 datano にはクローズしたタスクが属するプロセス IDが入る ( タスク ID、プロセス ID が不明 / 未定義の時は、それぞれ 0 が入る)。
datacntmemptr は未使用。
DC_CLOSEALL :
デバイスの使用を終了し、メディアを取り出す。
イジェクト可能デバイスの時は、 DC_CLOSE の処理の後、メディアをイジェクトする。 イジェクト不能デバイスの時は、DC_CLOSE と同じ。
  • DC_OPENDC_CLOSEDC_CLOSEALL はデバイスの使用開始・終了を明示的に示すためのものであり、 対象デバイスの特性上特に処理すべきことがなければ何もしなくてもよい。 また、オープンされていない状態での DC_READDC_WRITE 等の要求は、 デバイスの動作上特に問題が無ければエラーとする必要はない ( オープンされているか否かをエラーのためだけにチェックする必要はない ) 。
DC_READ :
データを読み込む。
datano のデータを datacnt だけ、 taskid のタスクの memptr の領域に読み込む。
DC_WRITE :
データを書き込む。
taskid のタスクの memptr の領域のデータを、 datacnt だけ、datano に書き込む。
DC_ABORT :
処理をアボートする。
taskid のタスクから要求された処理を処理中の場合は、 その処理を即時に中止し、 その要求はエラー応答を戻す。 そうでない場合は何もしない。
datanodatacntmemptr は未使用。
DC_SUSPEND :
サスペンド状態に移行する。
taskiddatanodatacntmemptr は未使用。 処理の詳細は後述。
DC_RESUME :
サスペンド状態から復帰 ( リジューム ) する。 taskiddatanodatacntmemptr は未使用。 処理の詳細は後述。
  • DC_SUSPEND および DC_RESUME は、 デバイスユニットに対し要求される。 サブユニットに対しては要求されない。
DC_CARDEVENT :
PCMCIA カードの場合、カードマネージャから発行される事象要求。 詳細は、第2章 PC (PCMCIA) カードマネージャ仕様を参照のこと。
DC_USBEVENT :
USB デバイス場合、USB マネージャから発行される事象要求。 詳細は、第15章 USB マネージャ仕様を参照のこと。
datano :
datacnt :
読み込み / 書き込みの対象となるデータ番号およびデータ数。 データの内容はデバイスに依存する。
datano < 0 デバイス属性データ
デバイス属性データは、基本的に固定長のデータである。
datacnt の単位はバイト数で、 原則的にデータ全体を一括しての読み込み / 書き込みのみ可能である。
datacnt = 0
実際の読み書きは行わずに、 応答時の datacnt にデータ長を戻す。
datacnt < データ長
エラーとなる。
datacnt >= データ長
データ長だけの読み込み / 書き込みを行い、 応答時の datacnt にデータ長を戻す。
datano >= 0 デバイス固有データ
デバイス固有データは、基本的に可変長のデータである。
datacnt の単位はデバイスに依存する。
datacnt = 0
実際の読み書きは行わずに、 応答時の datacnt に有効 ( 読み書き可能 ) なデータ長を戻す。
datacnt < 0
エラーとなる。
datacnt > 0
有効 ( 読み書き可能 ) なデータ長の読み込み / 書き込みを行い、 応答時の datacnt に実際に読み込み / 書き込みを行ったデータ長を戻す。
taskid :
要求したタスクを示すタスク ID。
memptr :
読み込み / 書き込みを行うメモリーポインタ ( 論理アドレス ) 。
cmd.adcnv = 0 の時
memptr で示されるメモリーは常に直接アクセス可能であり、 論理空間の切り換えおよび不正アドレスのチェックは不要である。
cmd.adcnv = 1 の時
要求タスクの論理空間に切り換え、 不正アドレスのチェックを行う必要がある。 これらを行った後にメモリーのアクセスを行わなくてはならない。
DMA 等物理アドレスによるアクセスを行う場合には、 論理アドレスから物理アドレスに変換する必要がある。
datacnt = 0 の場合は、memptr の正当性はチェックしない。
error :
処理のエラーコード。
error= 0 ( ER_OK )
正常
< 0
エラー ( 詳細は別途デバイスごとに定義される )
処理をアボートした場合は通常 ER_MINTR を返すが、 そのデバイスの特性に合わせて他のエラーコードを返してもよい。 RS-232C などでは、 データの取りこぼしが起きないような配慮が必要である。

1.7 サスペンド / リジューム処理

1.7.1 サスペンド (DC_SUSPEND)

次の処理を行う。

  1. 現在処理中の要求があれば、終了するまで待つか、 中断または中止する。 どの方法を選択するかはドライバーのインプリメントに依存する。 ただし、長期の待ちに入ってしまうような場合には、 終了まで待たずに中断または中止しなければならない。
    DC_SUSPEND コマンド自身は、 デバイスユニットに対して要求されるが、 現在処理中の要求がサブユニットに対するものでも同様に処理する。
    中断:
    ドライバー内部で処理を一時的に中断し、リジューム後に続きを行う。
    中止:
    DC_ABORT 要求と同様に、処理中の要求を中止してしまう。 この時、エラーコードは原則として ER_MINTR とし、 アプリケーションから見たときメッセージハンドラの起動による中止と等価に見えるようにする。 なお、エラーコードについては、 そのデバイスの特性に合わせて他のエラーコードを返してもよい。
  2. DC_RESUME 以外の新たな要求の受け付けを停止する。
    サブユニットを持つデバイスでは、全サブユニットの要求受付も停止する。
  3. 必要に応じて、ハードウエアのサスペンド処理を行う。

1.7.2 リジューム (DC_RESUME)

次の処理を行う。

  1. 必要に応じて、ハードウエアのリジューム処理を行う。
  2. 中断していた処理があれば再開する。
  3. 要求受け付けを再開する。
    サブユニットを持つデバイスでは、全サブユニットの要求受付も再開する。

DC_SUSPEND 要求は、DC_ABORT 要求と同様に他の通常要求の処理中であっても、 任意の時点で受け付けられなければならない。
DC_RESUME 要求は、サスペンド状態の期間中だけ受け付ければよい。 それ以外のときは無視する。

1.8 カードイベント処理

DC_CARDEVENT に関しては、第2章 PC (PCMCIA) カードマネージャ仕様を参照のこと。

1.9 USB イベント処理

DC_USBEVENT に関しては、第15章 USB マネージャ仕様を参照のこと。

1.10 共通デバイス属性データ

デバイス属性データは、 基本的には個々のデバイスによって異なるが、 下記の属性についてはデータ番号を共通化する。
しかし、すべてのデバイスで下記の属性データが存在するとは限らない。 存在しない属性データに対するアクセスは ER_PAR とする。

    /* 共通デバイス属性データ番号 */
    typedef enum {
        DN_EVENT       = -1,   /* 事象通知用メッセージバッファ ID */
        DN_DISKINFO    = -2,   /* ディスク情報 */
        DN_DISPSPEC    = -3,   /* 表示デバイス仕様 */
        DN_PCMCIAINFO  = -4,   /* PC カード情報 */
        /* -99 まで拡張用予備としてリザーブ */
    } CommonDataNo;

-1 〜 -99 までを共通属性データ番号とする。 各デバイス別の属性データ番号には -100 以降を利用する。

DN_EVENT :
事象通知用メッセージバッファ ID RW
data:
ID
DN_DISKINFO :
ディスク情報 R
data:
typedef struct {
    DiskFormat format;          /* フォーマット形式 */
    Bool        protect:1;      /* プロテクト状態 */
    Bool        removable:1;    /* 取り外し可否 */
    UW          rsv:30;         /* 予約 (0) */
    W           blocksize;      /* ブロックバイト数 */
    W           blockcont;      /* 総ブロック数 */
} DiskInfo;
protect :
ハード的に書き込みが禁止されている時 True
removable :
メディアの取り外しが可能な場合に True
typedef enum {
    DiskFmt_MEMINIT = -2,       /* メモリーディスク初期化 */
    DiskFmt_MEM     = -1,       /* メモリーディスク */
    DiskFmt_STD     =  0,       /* 標準 (HD等) */
    DiskFmt_2DD     =  1,       /* 2DD 720KB */
    DiskFmt_2HD     =  2,       /* 2HD 1.44MB */
    DiskFmt_VHD     =  3        /* フロプチカル 20MB */
    DiskFmt_CDROM   =  4,       /* CD-ROM 640MB */
    DiskFmt_2HD12   =  0x12     /* 2HD 1.2MB */
} DiskFormat;

フロッピーディスクの様に1台のドライブで複数種類のメディア ( フォーマット形式 ) を使用する様な場合を除き、 フォーマット形式は標準 ( DiskFmt_STD ) を使用する。

メモリーディスク ( DiskFmt_MEM ) は、 RAM Disk の様にメモリーとしてアクセスできる場合に使用する。

DN_DISPSPEC :
表示デバイス仕様の取り出し R
data:
typedef struct {
    H   attr;       /* デバイス属性     */
    H   planes;     /* プレーン数       */
    H   pixbits;    /* ピクセルビット数 */
    H   hpixels;    /* 横のピクセル数   */
    H   vpixels;    /* 縦のピクセル数   */
    H   hres;       /* 横の解像度       */
    H   vres;       /* 縦の解像度       */
    H   color[4];   /* カラー情報       */
    H   resv[6];
} DEV_SPEC;

DP の DEV_SPEC の仕様に準ずる ( BTRON3 仕様書「第2編 OS 仕様」-「2.3 基本関数」の gget_spc() 参照)。

この属性データがサポートされているデバイスは、 表示 ( 印刷 ) デバイスである。 したがって、DP は gopn_dev でデバイス描画環境を生成する時、 このデータを読み出すことができれば、 描画環境を生成可能なデバイスと判定することができる。

DN_PCMCIAINFO :
PC カード情報 R
data:
typedef struct {
    UB  major;      /* 仕様バージョン(上位) */
    UB  minor;      /* 仕様バージョン(下位) */
    UB  info[40];   /* 製品情報             */
} PCMCIAInfo;

現在挿入されている PC カードから、 カード属性情報の製品情報を読み出す。

major:
minor:
PCMCIA 仕様のバージョン
info:
製品情報文字列
'\0' で終わる ASCII 文字列である。

PC カードが挿入されていない場合には、エラー ( ER_NOMDA ) となる。

デバイスが PC カードでない場合にはこの情報は読み出せず、 エラー ( ER_PAR ) となる。

1.11 事象通知

事象通知用属性データ ( DN_EVENT ) にメッセージバッファ ID ( ≠0 ) が書き込まれると、 それ以降に発生した事象をメッセージバッファに送信する。 0 が書き込まれると、それ以降の事象通知は行わない。 ドライバの初期化の時点では、 デバイスドライバー起動パラメータ ( DevDrvParam ) で指定されたメッセージバッファ ID がデフォルトとして設定される。

    /* 事象種別 */
    typedef enum {
        DE_unknown      = 0,        /* 未定義           */
        DE_MOUNT        = 0x01,     /* メディア挿入     */
        DE_EJECT        = 0x02,     /* メディア排出     */
        DE_ILLMOUNT     = 0x03,     /* メディア不正挿入 */
        DE_ILLEJECT     = 0x04,     /* メディア不正排出 */
        DE_REMOUNT      = 0x05,     /* メディア再挿入   */
        DE_CARDBATLOW   = 0x06,     /* カードバッテリ残量警告 */
        DE_CARDBATFAIL  = 0x07,     /* カードバッテリ異常     */
        DE_REQEJECT     = 0x08,     /* メディア排出要求 */
        DE_PDBUT        = 0x11,     /* PDボタン変化     */
        DE_PDMOVE       = 0x12,     /* PD位置移動       */
        DE_PDSTATE      = 0x13,     /* PDの状態変化     */
        DE_PDEXT        = 0x14,     /* PD拡張事象	*/
        DE_KEYDOWN      = 0x21,     /* キーダウン       */
        DE_KEYUP        = 0x22,     /* キーアップ       */
        DE_KEYMETA      = 0x23,     /* メタキー状態の変化    */
        DE_POWEROFF     = 0x31,     /* 電源スイッチオフ */
        DE_POWERLOW     = 0x32,     /* 電源残量警告     */
        DE_POWERFAIL    = 0x33,     /* 電源異常         */
        DE_POWERSUS     = 0x34,     /* 自動サスペンド   */
        DE_POWERUPTM    = 0x35,     /* 時計更新         */
        DE_CKPWON       = 0x41      /* 自動電源 ON 通知 */
    } DevEvtKind;

    #define L_VD        0

    typedef struct {
        DevEvtKind   kind;       /* 事象種別     */
     /* VW           info[L_VD];    付加情報     */
    } DevEvt;
kind :
事象の種別
info :
事象の種別に依存した付加情報
サイズは事象種別によって異なる。

各事象の詳細は、対象のデバイスドライバー仕様を参照のこと。

メッセージバッファが一杯で事象通知を行えない場合は、 その事象が通知されないことで 事象の受信側の動作に悪影響が出ないようにしなければならない。 メッセージバッファが空くまで待ってから事象通知を行ってもよい。 その場合も原則として、 事象通知以外のデバイスドライバーの処理が滞ってはいけない。

1.12 デバイスドライバー用サービス関数

デバイスドライバーでは、 ITRON システムコールといくつかのライブラリ関数を使用することができる。 デバイスドライバーでは、 原則として BTRON システムコールは使用できない。

ITRON システムコール

下記を除く μITRON 3.0 システムコールが使用できる。

ITRON の資源を獲得する場合は、 オブジェクトID やハンドラ番号の自動割り当て機能を使用する。 デバイスドライバーで固定のオブジェクトID やハンドラ番号を使用してはいけない。

次のような資源の自動割り当て機能があるので、これらを使用する。

vcre_tsk, vcre_sem, vcre_flg, vcre_mbx, vcre_mbf, vcre_por, vdef_cyc, vdef_alm

ITRON の詳細については、ITRON の仕様書を参照のこと

デバイスの登録

    ID  DefDevice(DevDef *devdef, DiskInfo *info)

*devdef で指定したデバイスをシステムに登録し、 登録したデバイス ID を関数値として戻す。

devdef->attr.diskinfo = 1 の場合
info にディスク情報を設定する。
devdef->attr.diskinfo = 0 の場合
infoNULL とする。
関数値: > 0
正常 ( デバイスID )
関数値: < 0
エラー

タスクアドレス空間の設定

    ERR SetTaskSpace(ID taskid)

taskid で指定したタスクのアドレス空間、 およびアクセス権情報が自タスクに設定される。

これにより、taskid のタスクと同じメモリーがアクセスできるようになり、 また、taskid のタスクにアクセス権がないメモリーへのアクセスを不正アドレスのチェック ( CheckSpaceXX ) により検出することができるようになる。

要求コマンドの cmd.adcnv = 1 の時は、memptr で指定されたアドレスに対する不正アドレスのチェック、 およびメモリーアクセスの前に、 必ずアドレス空間を切り換えなくてはいけない。

taskid に自タスクのタスク ID を指定することはできない。
ただし、TSK_SELF により自タスクを指定した場合は、 自タスクが本来持つアクセス権 ( タスク生成直後のアクセス権 ) 情報が設定される。このとき、アドレス空間は切り替わらない。

関数値: = 0
正常
関数値: < 0
エラー ( ER_INNER : ITRON エラーコード )

不正アドレスのチェック

    ERR CheckSpaceR(VP address, W len)       R チェック
    ERR CheckSpaceRW(VP address, W len)     RW チェック
    ERR CheckSpaceRE(VP address, W len)     RE チェック

指定した address から len バイトのメモリー領域に対するアクセスが正当かどうかチェックする。 自タスクの現在のアクセス権情報でアクセスが許可されていない領域が含まれていれば、 エラー ( ER_ADR ) を返す。

メモリーのアクセス権情報は次のように設定される。

要求コマンドの cmd.adcnv = 1 の時は、 memptr で指定されたアドレスに対してアクセスする前に、 SetTaskSpace() を行い、 不正アドレスのチェックを行わなくてはならない。

関数値 = 0
正常
関数値 < 0
エラー ( ER_ADR )

不正アドレスのチェック ( TC 文字列 )

    WERR    CheckStrSpaceR(TC *str, W max)       R チェック
    WERR    CheckStrSpaceRW(TC *str, W max)     RW チェック

str から TNULL に達するか max 文字目に達するまでのメモリー領域に対するアクセスが正当かチェックする。 ただし max = 0 の場合は、文字数 ( max ) は無視する。

正当ならその文字数、または max の値 ( max != 0max 文字目に達するまでに TNULL がない場合 ) を返し、 不当ならエラー ( ER_ADR ) を返す。

関数値 ≧ 0
正常(文字数)
関数値 < 0
エラー ( ER_ADR )

不正アドレスのチェック ( B 文字列 )

    WERR    CheckBStrSpaceR(UB *str, W max)      R チェック
    WERR    CheckBStrSpaceRW(UB *str, W max)    RW チェック

str から '\0' に達するか max バイト目に達するまでのメモリー領域に対するアクセスが正当かチェックする。 ただし max = 0 の場合は、バイト数 ( max ) は無視する。

正当ならそのバイト数、または max の値 ( max != 0max バイト目に達するまでに '\0' がない場合 ) を返し、不当ならエラー ( ER_ADR ) を返す。

関数値 ≧ 0
正常(バイト数)
関数値 < 0
エラー(ER_ADR)

物理アドレス空間の獲得 / ロック

    ERR LockSpace(VP address, W len, ID taskid)

taskid で指定したタスクのアドレス空間上の address から len バイトのメモリー領域をロック ( 常駐化 ) する。

使用が終わったら、 必ず UnlockSapce() によりアンロック ( 常駐化解除 ) しなければならない。

関数値 = 0
正常
関数値 < 0
エラー
    ERR UnlockSpace(VP address, W len, ID taskid)

LockSpace() でロック ( 常駐化 ) したメモリー領域をアンロック ( 常駐化解除 ) する。

関数値 = 0
正常
関数値 < 0
エラー
    WERR    CnvPhysicalAddr(VP addr, W len, VP *physical_addr)

指定した address から len バイトのメモリー領域の物理アドレスを求め、 *physical_address に戻し、 物理アドレスの連続バイト長さを関数値に戻す。

連続した論理アドレスであっても物理アドレスは連続しているとは限らない。
関数値 < len の場合は、 物理アドレス上では len バイトの領域が連続していないことを意味するため、 DMA アクセスを行う場合は分割して操作する必要がある。

指定したアドレスはロック ( 常駐化 ) されていなければいけない。

関数値 ≧ 0
正常 ( 値は物理アドレスの連続バイト長 ≦ len )
関数値 < 0
エラー

排他制御用高速ロック

    ERR     CreateLock(FastLock *lock)
    void    DeleteLock(FastLock *lock)
    void    Lock(FastLock *lock)
    void    Unlock(FastLock *lock)

排他制御を行うための高速ロック。

内部で ITRON のセマフォを使用しているが、 ITRON のセマフォを直接使用するより高速である。

CreateLock() によりロックを生成し、 Lock()Unlock() により排他制御を行う。

    /* 高速セマフォ */
    typedef struct {
        W   cnt;
        ID  semid;
    } FastLock;
関数値 = 0
正常
関数値 < 0
エラー ( ER_INNER : ITRON エラーコード)

μ秒単位の待ち

    void    WaitUsec(UW usec)

usec μ秒待つ。待ち時間はあまり正確ではない。

この待ちは、ITRON の待ち ( WAIT ) 状態ではない。 積極的に他のタスクへ CPU を明け渡すようなことはしない。 したがって、長時間の待ちに使用すべきではない。

I/O ポートアクセスのタイミング調整等の極短時間の待ちに使用する。

I/O ポートアクセス

    void    out_w(W port, UW data)      W サイズ
    void    out_h(W port, UH data)      H サイズ
    void    out_b(W port, UB data)      B サイズ

I/O 空間の port 番地へ data を書き込む。

    UW  in_w(W port)            W サイズ
    UH  in_h(W port)            H サイズ
    UB  in_b(W port)            B サイズ

I/O 空間の port 番地から読み出す。

CPU 割込マスク制御

    DI(UW imask)        割込禁止
    EI(UW imask)        割込許可(imask の状態へ戻す)

CPU の割込禁止状態を制御する。DI により割込を禁止し、 EI により割込を許可する。

DI(imask)imask に現在の割込禁止状態を保存した後、 割込を禁止する。
EI(imask)imask に保存されている割込禁止状態へ復帰する。
つまり、EIDI の直前の状態に戻す。 したがって、DI の時点ですでに割込禁止となっていた場合には、 EI で元の状態に戻しても割込禁止のままである。

imask の内容は機種に依存している。
DIEI はマクロである。

割込コントローラ制御

機種ごとに割込コントローラの制御方法は異なるので、 機種ごとに用意されている関数も異なる。 基本的に、異なる機種でも同等の機能であれば同じ関数名を使用している。

割り込みベクター番号 ( IntVector ) の定義も機種ごとに異なる。

B-right/V で使用できる関数
    void    EnableInt(IntVector vector)
    void    DisableInt(IntVector vector)
    void    ClearInt(IntVector vector)
    void    EndOfInt(IntVector vector)
    W       CheckInt(IntVector vector)

    void    EnableInt(IntVector vector)

vector で指定した割り込みを許可する。
既に割り込み要求があった場合は、許可した直後に割り込みが発生する。

    void    DisableInt(IntVector vector)

vector で指定した割り込みを禁止する。
割り込み禁止中に発生した割り込み要求は、保持される。

    void    ResetInt(IntVector vector)

vector で指定した割り込み要求をリセットする。

    void    ClearInt(IntVector vector)

vector で指定した割り込み要求をクリアする。

    void    EndOfInt(IntVector vector)

vector で指定した割り込みの割り込み処理終了を通知する。 現在処理している割り込みレベルを示す vector を指定しなければならない。

    void    LevelInt(IntVector vector)

vector で指定した割り込み要求をレベルトリガに設定する。

    void    EdgeInt(IntVector vector)

vector で指定した割り込み要求をエッジトリガに設定する。

    W   CheckInt(IntVector vector)

vector で指定した割り込みの要求の有無をチェックする。 要求がある場合は、0 でない値が戻る。

デバイスコンフィグレーション情報

デバイスコンフィグレーション情報 ( DEVCONF ) から、情報を取得する。

    W   GetDevConf(B *name, W val[L_DEVCONF_VAL])
name :
項目名 ( 最大 16 文字の ASCII 文字列 )
val :
取り出したワード値の格納用配列
関数値
取り出したワード数
関数値 = 0
項目は存在しない
    W   GetDevConfStr(B *name, B str[L_DEVCONF_STR])
name :
項目名 ( 最大 16 文字の ASCII 文字列 )
str :
取り出した文字列の格納領域
関数値
取り出した文字数
関数値 = 0
項目は存在しない

デバイスコンフィグレーション情報は、 /SYS/DEVCONF にファイルとして存在する。 このファイルは、システム起動時にメモリーに読み込まれる。 上記関数はこのメモリー上の情報を取得する。 したがって、DEVCONF ファイルを変更しても、 システムを再起動しなければ、その変更は反映されない。

DMA 専用メモリー

PC-AT の場合、下位 16MB のメモリー空間に対してしか DMA 転送を行うことができず、 また 64KB または 128KB 境界を含む領域に対して DMA 転送ができない。これらの制約から、 DMA 転送可能な領域を確保するための特殊なメモリー管理機能が用意されている。

    ERR b_get_mbk(VP *adr, W nblk, UW atr)
adr :
獲得したメモリーブロックの先頭アドレスが返される。
nblk :
獲得するメモリーブロック数( 1ブロック = 4KB )。
atr :
メモリーブロックの属性
関数値 = 0
正常
関数値 < 0
エラー

latr = M_DMA|M_SYSTEM|M_RESIDENT の指定により、 DMA 専用メモリーを確保する。他のオプションの組み合わせは許されない。

得られるメモリーは 64KB 境界を含まないことが保証される。 したがって、最大で 64KB の連続領域しか確保できない。

得られるアドレスは論理アドレスである。

    ERR b_rel_mbk(VP adr)
adr :
解放する DMA 専用メモリーの先頭アドレス
関数値 = 0
正常
関数値 < 0
エラー

DMA 専用メモリーを解放する。

1.13 エラーコード

デバイス処理の応答メッセージに返す主なエラーコードには 下記のようなものがある。

    ER_OK (=0)  正常終了

エラークラス ( ErrCode.c.eclass )

    EC_ADR      不正アドレス
    EC_PAR      パラメータエラー、ユニットが存在しない
    EC_RONLY    書き込み保護メディア
    EC_BUSY     ビジー状態
    EC_NODEV    デバイスへのアクセス不可(電源OFF, 非接続, など)
    EC_ERDEV    装置異常が発生した
    EC_NOMDA    メディアが存在しない
    EC_IO       入出力エラーが発生した
    EC_MINTR    処理をアボートした
    EC_INNER    ITRON システムコールのエラー

詳細エラーコード ( ErrCode.c.detail )

デバイスごとに定義される。各デバイスドライバー仕様を参照のこと。
下記は、全デバイス共通の詳細エラーコードである。

    EC_PAR:     ED_CMD      不正コマンド
                ED_DEVID    不正デバイスID
                ED_DATANO   不正データ番号
                ED_DATACNT  不正データ数
                ED_DATA     不正データ

    EC_INNER:   ITRON のエラーコード ER を UH にキャストした値

この章の目次にもどる
次頁:第2章 PC (PCMCIA) カードマネージャにすすむ