アドテックシステムサイエンス aPCI-P54 Linux デバイスドライバ
概要
本ドライバは アドテックシステムサイエンス社製 PCIボード aPCI-P54,入出力48点
TTLレベルパラレルI/Oボードをユーザプログラムから使用するための
デバイスドライバ(モジュール)である.I/Oアクセスに限れば,Linuxでは
root の権限のプロセスから直接操作可能であるが,本ドライバでは
若干のオーバヘッドはあるものの一般ユーザの権限での I/Oアクセス,
さらには割り込み機能の利用を可能とする.
特徴
本ドライバは以下の特徴を有する.
- ボードの全機能を ioctl() システムコールで扱うことができるように
することで,root の権限がなくとも I/O ポートにアクセス可能である.
- ボードの情報を ioctl() システムコールにより読み出し,root の
権限で直接操作することが可能である.
- select() システムコールを利用した,プロセスへの割り込み発生通知
機能により,面倒な知識を必要とすることなく,またカーネルレベルでの
プログラムを作成する際の危険を犯すことなく,容易に割り込みを利用することが
可能である.
- ボード上のロータリスイッチにより設定される
BSN(ボードセレクトナンバー)により,同時に16枚768ポート64割り込みを
使用することが可能である(*).割り込み条件は64本に対して一括で
管理する.なお,同一コンピュータに BSNの一致するボードを複数
搭載した場合,1枚のみ認識される.
(*): 実装したのみで実際には機能は確認していない.
コンパイル・ロード
コンパイルはソース,ヘッダファイルを用意し,
gcc -c apcip54.c -DLINUX -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -pipe -m486
で行う.
これにより apcip54.o が作成される.できた apcip54.o はLinuxの
モジュールである. root になって insmod apcip54 でモジュールが
ロードされる. この際, コンソールにはドライバのボード認識情報が
表示される. モジュールの除去は rmmod apcip54 である.
本ドライバはデバイスドライバのメジャー番号58(暫定)を使用する
(マイナー番号は現在チェックしていないが, 将来的には
他のADなどのボードと区別することになると考えられる).
アクセスするために デバイスファイルが必要となるため, mknod で
作成する. 方法は mknod /dev/apcip54 c 58 0 である. これは
root で一度実行すれば良い.
Makefile による make
必要ならば, Makefile の冒頭のデバイスのメジャー番号, RDTSC使用の
有無(Pentium以降なら推奨)を変更の上, make する.
Slackware 3.5(kernel 2.0.36,gcc: 2.7.2.3)で問題ないことを確認している.
そのあと root で make makedev とすることで, デバイスファイルを作成する.
make ins でドライバ(モジュール)の登録ができる.
コンフィギュレーション
- デバイスメジャー番号
デバイスのメジャー番号を決定。/usr/src/linux/Documentation/devices.txt
にすでに予約されたものなどがあるので、空きを適当に指定する。
ドライバのコンパイルと mknod で一致していれば問題ない。
ソースもしくはMakefile で指定。
- 同時アクセス数
ソース簡略のため、各プロセスからアクセスされる際の情報を
記録するデータ構造を固定長の配列にしている。このサイズを
きめるのが定数 FILEACCESS である。デフォルトで32であるが、
open して EBUSY が返るようなら、この数値を大きくする。
ソースに直接記述
ボード・ドライバの使用法の概要
以下にあらわれる ioctl へのリクエスト番号は後述する.
1:root権限で直接操作
/dev/apcip54 を open() した後, ioctl にてドライバに aPCIP54_CHECKBSN と
ボードの設定BSNをわたし, ボードの存在を確認する. BSNが不明な場合,
BSN に0-15を順次指定し, 検索すれば良い. BSNが確定後,
aPCIP54_BASEADDRESS により, I/Oのベースアドレスを取得, 得られた
アドレスを基準に inb/outb などの関数(-O2オプションをつけてコンパイル
すると, インライン展開される)を用いて直接アクセスする. なお,
ボードのアドレスを得た場合, close() してもかまわない.
2:ドライバ経由の間接操作
これには root の権限は不要である. /dev/apcip54をopen()しaPCIP54_CHECKBSN
でボードを確認するところまでは同じである. ベースアドレスは必要ない.
I/Oのアクセスは aPCIP54_READPORT, aPCIP54_WRITEPORT により行う.
これには引数として, ボード識別のための BSN(0-15)およびポート番号
(0-15), ポートの値を含む構造体 struct aPCIP54port へのポインタを渡す.
ポートに対して, 一括の入出力を行うaPCIP54_READPORTBSN,
aPCIP54_WRITEPORTBSN もあり, その場合, BSN, 書き込み時のマスク,
ポート値の配列を含む aPCIP54portBSNを渡す.
3:割り込みの使用
割り込みの利用にもrootの権限は不要である. /dev/apcip54 をopen()し
BSNを取得する. その後, ioctl() にて aPCIP54_SETIRQMASK リクエストを
行い, 応答する割り込みを設定する. 割り込みマスクは struct aPCIP54irq
内のirq_maskメンバで指定する. ビットが1であるところに対して
応答する. このマスクは全BSNに対応したものであり, 下位より4ビットずつ
各ボードの PC0,PC3,PF0,PF3 に対応する(全64ビット). すなわち,
BSNに応じて, 適当なところを指定しなければならないが, 全ボードの
割り込みに対して一括して応答することが可能である.
なお, ボード自体の割り込み設定は, aPCIP54_SETIRQMASKのリクエストの
処理過程で自動的に設定されるため, 操作する必要はない.
割り込みのマスクを指定したのち, select()システムコールにより,
/dev/apcip54 を open した際のファイル記述子を読み込みで待機にする.
割り込みが発生した場合, もしくは引数で指定したタイムアウトを
した場合に select()から実行が戻るため, 割り込みによる
ものかを FD_ISSETにより確認する. なお, 割り込みは select()を
呼び出したあとに発生したものだけに応答し, それ以前に発生した
ものには応答しない. 例外的に, 複数のデバイスに対して同時に
selectを発行し, 他のデバイスが先に読み取り可能になった場合には
次のselectまでに受けた割り込みに対しても応答する.
割り込み直後の割り込み発生ボードの全ポートの値および, 発生時間は
aPCIP54_GETINTERRUPTSTATUS リクエストで確認できる. これは
最後に発生した割り込みの状況を保存する. 発生時間はPentium
以降のCPUに装備されている RDTSC 命令によるもので, リセット後に
CPUのサイクルごとに0からカウントアップする64bit のカウンタの
値である(最新のCPUでも千年程度は単調増加が保証されることが計算できる).
なお, Pentium以前のCPUなどで RDTSCをサポートしていない場合は,
ソース頭部の #define USERDTSC をコメントアウトする. その場合,
Linuxの内部タイマによる数値(一般に100/sec)が使用される.
実際の割り込み発生からの応答速度であるが, マルチタスクOSであるが
ゆえに, 一概に言えない. 期待値としては以下のようになる.
- 現在, OSが idel であるならば(実行中のプロセスがない)場合
PentiumII300MHz 程度であれば 10μsec 程度でselectが応答する
- 現在, 実行中のプロセスがある場合, 0〜10msec 程度で応答する.
これは Linux のマルチタスク部分で10msecごとの割り込みにより,
強制的に現在実行中のプロセスが中断させられ, 次のプロセスに
処理が移るためである.
- システムで実行待ちのプロセスが多数ある場合はこの限りではない.
プロセスの待ち行列が込んでいる場合, 当然, 別のプロセスが
先に実行される. これを避けるには実行優先順位を上げる.
root 権限で指定可能な負のnice値を指定することで,
待ち行列の先頭で待機することができる.
- /usr/src/linux/asm/param.h 内の HZ の値を大きくすることで,
上述のタスク切り替えの割り込み頻度を上げることができる. たとえば,
1000 にすることで 1msec 単位になる. これによっても, 応答性が
向上する. ただし, OSのオーバヘッドが増加するため, 若干コンピュータの
パフォーマンスが低下する. またpsなど一部のプログラムの結果などに
影響が生じるようである.
ioctl リクエスト一覧
ボードの認識確認
- aPCIP54_CHECKBSN
ioctl(fd,aPCIP54_CHECKBSN); によって, ボードの認識を確認できる.
ボードが認識されている場合, ioctl は 0を返す. 存在しない/
認識できていない場合は-1を返す.
ボード値取得リクエスト
リクエストには次の構造体へのポインタを引数とする.
struct aPCIP54value
{
int bsn; // BSN指定
int value; // 値入力
};
bsn はボード番号をあらかじめ指定し, ioctlが成功した場合, value に
値が返る.
- aPCIP54_BASEADDRESS
ボード番号 bsn のボードの I/O のベースアドレスを得る. 直接 I/O命令で
アクセスする場合に必要.
- aPCIP54_IRQ
ボード番号 bsn のボードの使用IRQを得る. 一般に必要ではないと考えられる.
1ポート入出力
リクエストには次の構造体へのポインタを引数とする.
struct aPCIP54port
{
int bsn; // BSN指定
int port; // ポート指定
int value; // 値指定/読み込み結果
};
bsn はボード番号(0-15)を指定し, port は読み書きするオフセット(0-15,
0-5:通常ポート,6:方向設定, 15:ローカルコントロール)である.
書き込み時はvalue(0-255)を事前設定し, 読み出し時にはvalueに値(0-255)が返る.
- aPCIP54_READPORT
bsn:port より読み出し, 結果を value に設定する.
- aPCIP54_WRITEPORT
bsn:port に value を書き込む.
ボード一括ポート入出力
リクエストには次の構造体へのポインタを引数とする.
struct aPCIP54portBSN
{
int bsn,mask; // BSN および 書き込みマスク指定
unsigned char ports[8]; // 入出力データ
};
bsn(0-15) はボード番号を指定, mask は書き込み時のマスクを指定する.
ports は書き込み/読み取り内容.
- aPCIP54_READPORTBSN
指定したボードのポートを一括して読み取る. ports[0-6]にはオフセット
0-6, すなわちA-Fのポートおよび方向レジスタが, ports[7]にはオフセット
15, すなわちローカルコントロールレジスタが読み込まれる.
- aPCIP54_WRITEPORTBSN
指定したボードのポートに一括して書き込む. ports[0-6]にはオフセット
0-6, すなわちA-Fのポートおよび方向レジスタに書き込むべき値を
セットする. mask には ビット0〜6がそれぞれのポートに対して
書き込むか否かを決定し, 1で書き込む.
割り込み
- aPCIP54_SETIRQMASK
aPCIP54_GETIRQMASK
struct aPCIP54irq
{
unsigned long long irq_mask; // 割り込み mask
};
aPCI-P54群より発生する割り込みを select()で受けるかどうかを決定する
割り込みマスクを設定/読み出しする.
Linux においてlong long は64bit の変数である. これを下位から
4bitずつ区切り, BSN0-15に対応させ, 各4bitで下位より PC0,PC3,PF0,PF3の
割り込みに対応する. 該当ビットが1のとき, その割り込みに応答する.
なお, open した段階では0にクリアされているため, 割り込みは受け付けない.
- aPCIP54_GETINTERRUPTSTATUS
struct aPCIP54interrupt
{
unsigned long long irq_mask; // 発生割り込み
int bsn; // 発生 BSN
unsigned char ports[8]; // 割り込み発生時のポート (0-6)
unsigned long long time; // 発生時刻(RDTSC:当然若干の誤差あり)
int count; // 前回読み出しよりの割り込み回数
};
最も最近の割り込みが発生した際の情報を取得する. 引数として上記
aPCIP54interrupt 構造体へのポインタを与える. irq_maskは
実際に発生した割り込みを示す. これは aPCIP54irq構造体のirq_maskと
同じ配列である. 発生BSNは割り込み要因のボード番号を示し,
ports[0-6]には割り込み発生後のポートの状態を読み取ったものが
記録されている. time は割り込み発生時の時刻であり, RDTSC 命令で
得られる, 1CPUサイクルで1カウントアップするカウンタの値である.
これらの値は割り込みを受信するたびに変更され, 次の割り込み発生まで
保存される.
付属チェックプログラム apcip54check
本プログラムは最低限の機能チェックを行うためのプログラムである.
起動オプションは特にない. 4種類のコマンドがあり,
- i [bsn] [port]
ボード [bsn](0-f) の ポート[port](0-f)からの値の入力および表示
- o [bsn] [port] [value]
ボード [bsn](0-f) の ポート[port](0-f)への値[value](0-ff)の
出力
- I [bsn] [port]
ボード [bsn](0-f) の ポートの一括読み込みと表示, ただし
ポート 0-6 および, ポート0xf
- m [bsn] [mask]
ボード [bsn](0-f) からの割り込みの受付マスク設定
である. 数値はすべて16進数で指定する.
割り込みマスクを設定した上で, 割り込みを検出すると, その情報が表示される
(自分自身のポート出力にも割り込みは応答するため, ボード単体で試験可能).
例:
% ./apcip54check
check aPCIP54: BSN 0: no board
check aPCIP54: BSN 1: no board
check aPCIP54: BSN 2: no board
check aPCIP54: BSN 3: Exist Base address:14F0 IRQ:10
check aPCIP54: BSN 4: no board
check aPCIP54: BSN 5: no board
check aPCIP54: BSN 6: no board
check aPCIP54: BSN 7: no board
check aPCIP54: BSN 8: no board
check aPCIP54: BSN 9: no board
check aPCIP54: BSN 10: no board
check aPCIP54: BSN 11: no board
check aPCIP54: BSN 12: no board
check aPCIP54: BSN 13: no board
check aPCIP54: BSN 14: no board
check aPCIP54: BSN 15: no board
o3 6 3 // ボード3のポート6=方向指定 PCのみ出力
o3 2 0 // ポート2=PCに0を出力
m3 ff // 割り込みマスクを全有効
irq mask: 000000000000F000 // 割り込みマスクの表示(確認)
o3 2 1 // PC0をビット立て
Interrupt detected: // 割り込み検出
Interrupt: 0000000000001000 BSN:port 3:PC0 // ボード3 PC0
time: 112624950631326, delay:0.066939[msec] // 時間
interrupt count: 1 // 割り込み回数
ports: FF FF 01 FF FF FF // 割り込み時のポート状態
quit
%
なお, delay と表示されているのは, 割り込み発生後に select()により
ユーザプロセスに実行が移るまでの概算の時間である. apcip54check.c の
冒頭のCPUCLOCKにより計算されるので, コンピュータに応じて変更すること.
本ドライバについて
- 本ドライバは
アドテックシステムサイエンス社製
aPCI-P54
付属マニュアルを参考に熊谷正朗が開発しました. また、
一部ボードの不明な点についてアドテックシステムサイエンス社さんより
情報を頂いております。
- 本ドライバの利用・改変について本注意事項以外の制限はいっさいもうけません.
- 本ドライバの使用にあたっては各自の責任の元, 内容の確認,
動作確認等を行ってください. 特に, 性質上危険ですので, 設定等に
十分注意して使用してください. 何らかの損害が生じたとしても,
作者はいっさいの責任を負いません.
- 本ドライバはアドテックシステムサイエンス社さんとは全く関係ありません.
ソフト誤動作の苦情, 問い合わせなどを絶対にしてはなりません.
- 少なくとも, 当方では本ドライバを問題なく使えることを確認して
おりますが, ご利用の際には十分ご注意下さい.
最悪, システムに致命的なダメージを与えます.
- バグ等の連絡先:kumagai@emura.mech.tohoku.ac.jp くまがいまさあき宛
熊谷正朗/くまがいまさあき/Masaaki KUMAGAI kumagai@emura.mech.tohoku.ac.jp