2001年2月23日
#include <driver/pcat/pci.h>
IMPORT WERR searchPciDev(W vendor, W devid)
vendor ベンダー ID
devid デバイス ID
関数値 >= 0 : 見つかった
関数値は、PCI コンフィグレーションアドレス(caddr)。
PCI コンフィグレーションレジスタの入出力に使用します。
< 0 : 見つからない
vendor < 0x10000 のとき
vendor, devid で指定したベンダー ID、デバイス ID を持つ
デバイスをサーチします。
vendor == 0x1nnnn のとき
デバイスクラスが nnnn のデバイスのうち、devid 番目のデバイス
をサーチします。devid == 0 は、最初のデバイス、devid == 1 は、
2 番目のデバイスをサーチします。
vendor == 0x1FFFF のとき
すべてのデバイスのうち、devid 番目のデバイスをサーチします。
vendor の特殊な値の指定のため、以下のマクロが定義されています。
#define SEARCH_CLASS(class) ((class) | 0x10000)
#define SEARCH_ALL (0x1FFFF)
(使用例-1) 特定のベンダー ID、デバイス ID を持つデバイスをサーチ
caddr = searchPciDev(VENDOR_ID, DEVICE_ID);
if (caddr < 0) {エラー} // 見つからない
(使用例-2) 特定のデバイスクラスを持つデバイスを順番にサーチ
for (order = 0; ;order++) {
caddr = searchPciDev(SEARCH_CLASS(DEV_CLASS), order);
if (caddr < 0) break; // 見つからない
if (対象デバイス) break; // 見つかった
// 対象デバイスかどうかは、ベンダー ID などから判断する
}
if (caddr < 0) {エラー} // 見つからない
(使用例-3) すべてのデバイスを順番にサーチ
for (order = 0; ;order++) {
caddr = searchPciDev(SEARCH_ALL, order);
if (caddr < 0) break; // 見つからない
if (対象デバイス) break; // 見つかった
// 対象デバイスかどうかは、ベンダー ID などから判断する
}
if (caddr < 0) {エラー} // 見つからない
IMPORT UB inPciConfB(W caddr, W reg); // 8 ビット IMPORT UH inPciConfH(W caddr, W reg); // 16 ビット IMPORT UW inPciConfW(W caddr, W reg); // 32 ビット caddr searchPciDev() で得られた、PCI コンフィグレーションアドレス reg PCI コンフィグレーションレジスタのオフセット (使用例-1) ベンダーIDの入力 vendor_id = inPciConfH(caddr, PCR_VENDORID); // 16 ビット (使用例-2) 割り当てられている割り込み番号 (IRQ) の入力 irq_no = inPciConfB(caddr, PCR_IRQLIN); // 8 ビット
IMPORT VOID outPciConfB(W caddr, W reg, UW dat); // 8 ビット IMPORT VOID outPciConfH(W caddr, W reg, UW dat); // 16ビット IMPORT VOID outPciConfW(W caddr, W reg, UW dat); // 32ビット caddr searchPciDev() で得られた、PCI コンフィグレーションアドレス reg PCI コンフィグレーションレジスタのオフセット dat 出力するデータ。outPciConfB() では下位 8 ビット、outPciConfH() では下位 16 ビットのみ有効となります。 (使用例-1) コマンドレジスタへの出力 outPciConfH(caddr, PCR_COMMAND, cmd_value); // 16 ビット (使用例-2) レイテンシタイマーレジスタへの出力 outPciConfH(caddr, PCR_LATENCY, latency_value); // 8 ビット
IMPORT W getPciBaseAddr(W caddr, W reg, VP *addr, W *size);
caddr searchPciDev() で得られた、PCI コンフィグレーションアドレス
reg PCI ベースアドレスレジスタのオフセット
PCR_BASEADDR_0 (0x10) 〜 PCR_BASEADDR_5 (0x24)のいずれかを
指定します。
*addr 得られたベースアドレス
*size 得られたベースアドレスのサイズ
(*addr) 〜 (*addr + *size - 1) がアドレス範囲となります。
関数値 0 〜 0x0F ( PTTI のビット対応の値)
I = 0: メモリアドレス, 1: I/O アドレス,
T = 0: 32 ビット空間, 1: 20 ビット空間, 2: 64 ビット空間
P = 0: プリフェッチ不可, 1: プリフェッチ可能
関数値の判断のために以下のマクロが用意されています。
#define isBaseAddrIO(t) ((t) == 0x01)
#define isBaseAddr32(t) (((t) & 0x07) == 0x00)
#define isBaseAddr20(t) (((t) & 0x07) == 0x02)
#define isBaseAddr64(t) (((t) & 0x07) == 0x04)
#define isBaseAddrPreFetch(t) (((t) & 0x08) == 0x08)
(使用例-1) ベースアドレス 0 の取り出し (I/O アドレスの場合)
t = getPciBaseAddr(caddr, PCR_BASEADDR_0, &io_addr, &io_size);
if (! isBaseAddrIO(t)) {エラー}
(使用例-2) ベースアドレス 1 の取り出し (32 ビットメモリアドレスの場合)
t = getPciBaseAddr(caddr, PCR_BASEADDR_1, &mem_addr, &mem_size);
if (! isBaseAddr32(t)) {エラー}
getPciBaseAddr() により取り出して、I/O 関数 (in_b(), in_h(), in_w(), out_b(), out_h(), out_w()) を使用して入出力を行います。
(使用例)
// ベースアドレス 0 から I/O アドレス(32 バイトレンジ)を取り出す
t = getPciBaseAddr(caddr, PCR_BASEADDR_0, &iob, &ios);
if (! (isBaseAddrIO(t) && ios != 0x20)) {エラー}
// 実際の I/O 操作を行う
d1 = in_b(iob + 4);
if ((d1 & 1) == 0) out_b(iob + 4, d1 | 1);
getPciBaseAddr() により取り出します。
#include <kernel/segment.h>
IMPORT ERR MapMemory(VP paddr, W len, UW attr, VP *laddr);
paddr マップする物理メモリアドレス
len マップする物理メモリアドレスのサイズ
attr マップするメモリの属性、以下の組み合わせで指定する。
#define MM_USER 0x04 // ユーザプロセスからアクセス可
#define MM_SYSTEM 0x00 // システムからアクセス可
#define MM_READ 0x00 // 読み込み可
#define MM_WRITE 0x02 // 書き込み可
#define MM_EXECUTE 0x00 // 実行可
#define MM_CDIS 0x18 // キャッシュ禁止
*laddr マップされた結果の論理メモリアドレス
関数値 == ER_OK 正常終了
< ER_OK エラー
物理メモリアドレス空間を論理メモリアドレス空間にマップします。
IMPORT ERR UnmapMemory(VP laddr);
laddr MapMemory() によりマップした論理メモリアドレス
関数値 == ER_OK 正常終了
< ER_OK エラー
マップした論理メモリアドレス空間をアンマップ(解放)します。
不要になった時点で必ず明示的にアンマップしてください。
(使用例)
// ベースアドレス 2 からメモリ空間を取り出す
t = getPciBaseAddr(caddr, PCR_BASEADDR_2, &paddr, &size);
if (! isBaseAddr32(t)) {エラー}
// paddr 〜 (paddr + size - 1) の範囲の物理メモリ空間を
// 論理アドレス空間にマップする
err = MapMemory(paddr, size,
(MM_SYSTEM|MM_READ|MM_WRITE|MM_CDIS), &laddr);
if (err < ER_OK) {エラー}
// laddr 〜 (laddr + size - 1) にマップされたので、
// メモリとしてアクセス可能となった
memset(laddr, 0, size); // 全体を 0 クリアする
::::
// マップした論理アドレスは不要になった時点でアンマップする
UnmapMemory(laddr);
inPciConfB(caddr, PCR_IRQLIN) により取り出して使用します。
def_int() ではなく、必ず、以下の defIntHdr() を使用して登録してください。
#include <driver/hwres.h> IMPORT ERR defIntHdr(W intno, FP inthdr, UW par); intno IRQ 番号 >= 0 intno を IRQ 番号とする割り込みハンドラ(inthdr)を登録し、 まだ割り込みが許可されていない場合は、割り込みを許可する。 < 0 - intno を IRQ 番号とする割り込みハンドラ(inthdr)を削除 し、共有している割り込みハンドラが他にない場合は、割り 込みを禁止する。 inthdr 割り込みハンドラのポインタ、NULL であってはいけない。 par 割り込みハンドラに渡す任意のパラメータ(内部データへのポインタなど) 関数値 == ER_OK 正常終了 < ER_OK エラー 指定した IRQ 番号が共有割り込み可能な場合、複数の割り込みハンドラを同一の IRQ 番号に対して登録することができます。 また、すでに登録済みの割り込みハンドラに対して、再度登録を行うと、割り込み ハンドラに渡すパラメータ(par)を変更することができます。 割り込みハンドラは、以下の形式の関数となります。 VOID inthdr(UW par)
DisableInt(), EnableInt(), ClearInt(), EndOfInt()) を行ってはいけません。
EndOfInt() を実行しないようにしてください。
rsvHwRes() による予約は特に必要ではありませんが、予約する場合は、SHARED_IRQ 指定を付加してください。
#include <driver/hwres.h> err = rsvHwRes(HW_IRQ(xx), irq|SHARED_IRQ, irq|SHARED_IRQ); // 上記のように、予約することにより、「システム環境設定」の // [システム資源:割り込み]に表示されます。
(使用例)
// 割り込みハンドラ
VOID inthdr(UW par)
{
while (対象デバイスからの割り込みがある) {
(割り込みの処理)
(割り込み要因のクリア)
}
}
::::
// 割り込み番号(IRQ)の取り出し
irq = inPciConfB(caddr, PCR_IRQLIN);
if (irq < IRQ3 || irq > IRQ15) {エラー}
// 割り込み番号(IRQ)の予約
err = rsvHwRes(HW_IRQ(xx), irq|SHARED_IRQ, irq|SHARED_IRQ);
if (err < ER_OK) {エラー}
// 対象デバイスからの割り込み発生を禁止しておく
// 割り込みハンドラの登録
err = defIntHdr(irq, inthdr, par);
if (err < ER_OK) {エラー}
::::
// 割り込みハンドラの登録の解除
err = defIntHdr(- irq, inthdr, par);
if (err < ER_OK) {エラー}
// 割り込み番号(IRQ)の解放
relHwRes(HW_IRQ(xx));
IMPORT WERR CnvPhysicalAddr(VP laddr, W len, VP *paddr);
laddr 論理メモリアドレス
len 論理メモリアドレスのサイズ
*paddr 変換した結果の物理メモリアドレス
関数値 > 0 変換した物理メモリアドレスのサイズ (<= len)
< 0 エラー
指定した論理メモリアドレス領域全体が、連続した 1 つの物理メモリアドレス領域に
対応しているとは限らない点に注意が必要です。物理メモリ領域はページ(4 KB)単位で
バラバラに論理アドレス空間に割り当てられているためです。
したがいまして、1 つの論理メモリアドレス領域に対する DMA を行う場合でも、複数
の物理メモリアドレス領域に分断して DMA を行う必要が出てきます。
(使用例)
// laddr 〜 (laddr + len - 1) の論理アドレス領域の
// 物理アドレスを求める。
plen = CnvPhysicalAddr(laddr, len, &paddr);
if (plen < 0) {エラー}
// paddr 〜 (paddr + plen - 1) が対応する物理アドレス領域
// となるが、plen == len という保証はないため、通常は、以下
// のような方法で物理メモリアドレス領域群を求める必要がある
for (n = 0; n < MAX_AREA && len > 0; n++) {
plen[n] = CnvPhysicalAddr(laddr, len, &paddr[n]);
if (plen[n] < 0) {エラー}
len -= plen[n];
laddr += plen[n];
}
if (n >= MAX_AREA) {エラー}
// paddr[i] 〜 (paddr[i] + plen[i] - 1), i = 0 〜 n -1 の
// n 個の物理メモリアドレス領域が求まった
このページのはじめに戻る
技術情報のページにもどる
超漢字開発者サイトのページにもどる