この方法で共有されるメモリをページ ロックする必要があります (例、メモリをハード ディスクへ交換できないし、また CPU にキャッシュできません)。その結果、すべてのプロセッサからメモリに安全にアクセスできます。
カーネルでバッファを割り当てるには、先ず、ユーザー モードから WD_DmaLock () 関数を呼ぶ必要があります。連続するカーネル バッファを割り当てるには、WD_DMA 構造体のdwOptions フィールドに DMA_KERNEL_BUFFER_ALLOC フラグを設定します。WD_DmaLock() 関数は、メモリのユーザー モード マップ (dma.pUserAddr) と同様に、割り当てられたメモリの物理アドレス (dma.Page[0].pPhysicalAddr) を返します。[注意: Solaris では、ユーザー マップを返しません]。WinDriver v6.00 以降、連続する Buffer DMA 割り当ての場合、WD_DMALock() 関数は、dma.pKernelAddr 内で、割り当てられたバッファのカーネル バッファを返します。
malloc() コールの結果として、戻されたユーザー モード マップ アドレス (dma.pUserAddr) を使用して、ユーザー モード アプリケーションから割り当てられたメモリにアクセスできます。Solaris (v6.10 以降) の場合、WD_Transfer() 関数を使用して、メモリにアクセスし、WD_DMALock() 関数から戻されたアドレス (dma.pKernelAddr) のカーネル マップに渡します。
Kernel PlugIn アプリケーションから共有メモリ バッファへアクセスするには、Kernel PlugIn へ割り当てられたバッファのカーネル マップを渡す必要があります。上記で説明したとおり、WinDriver v6.00 以降を使用してる場合、このアドレスを WD_DMALock() 関数で dma.pKernelAddr に返します。[WinDriver v5.22 またはそれ以前を使用してる場合、WD_CardRegister() 関数で、cardReg.Card.Item[0].dwTransAddr に返される、物理アドレスのカーネル バッファを受信するために、物理ベース アドレスと割り当てられたバッファ長を渡し (それぞれ、cardReg.Card.Item[0].I.Mem. dwPhysicalAddr および cardReg.Card.Item[0].I.Mem. dwBytes に設定)、WD_DMALock() 関数からの戻りとして (それぞれ、dma.Page[0].pPhysicalAddr および dma.Page[0].dwBytes に設定)、まず、WD_CardRegister() 関数を呼びます。そして、以下の dma.pKernelAddr の説明のように、このカーネル マップ アドレスを Kernel PlugIn へ渡すことができます]。
[ユーザー モードで直接カーネル マップ アドレスにアクセスしないで下さい。これはカーネル モード アドレスなので、ユーザー モードからアクセスすると、例外保護違反となります。ユーザー モードから直接アクセスするには、ユーザー モード マップ dma.pUserAddr を使用するか、カーネル マップ アドレスで WD_Transfer() 関数を呼びます]。
カーネル仮想アドレスを Kernel PlugIn へ渡します。
このためには、WD_KERNEL_PLUGIN_CALL 構造体を作成し、pData フィールドを設定して、仮想カーネル アドレス dma.pKernelAddr を保持します (以前のバージョンでは、cardReg.Card.Item[0].dwTransAddr)。
そして、以下の方法の何れかで、この構造体を Kernel PlugIn へ渡すことができます:
- WD_KernelPlugInCall() への呼び出し。この場合、Kernel PlugIn の KP_Call() コールバック関数内からカーネル仮想アドレスにアクセスできます。
- WD_IntEnable()/InterruptEnable() 関数 (または、v5.22 以前の場合、Interrupt ThreadEnable() 関数) への呼び出し。この場合、ユーザー モードで、関数へ渡される WD_INTERRUPT 構造体の kpCall フィールドの WD_KERNEL_PLUGIN_CALL 構造体を保存します。そして、Kernel PlugIn で KP_IntEnable() コールバック関数内からカーネル仮想アドレスにアクセスできます。
Kernel PlugIn でカーネル仮想バッファ アドレスを取得後、Kernel PlugIn モジュールに保存してください (グローバル変数または割り当てられたメモリの場所)。これによって、カーネル モードおよびユーザー モードの両方で同じメモリ バッファにアクセスできます。
*********************************************************************
// sample user mode code:
HANDLE hWD;
WD_DMA dma;
WD_KERNEL_PLUGIN kerPlug;
WD_KERNEL_PLUGIN_CALL kpCall;
WD_CARD_REGISTER cardReg; // For version 5.22 or below
hWD = WD_Open();
BZERO(dma);
dma.pUserAddr = NULL;
dma.dwBytes = 0x10000; // allocate 16K
dma.dwOptions = DMA_KERNEL_BUFFER_ALLOC; // kernel contiguous buffer
WD_DMALock(hWD, &dma);
if (!dma.hDma)
{
printf("failed allocating dma buffer\n");
// exit
}
// At this point, dma.pUserAddr holds the
// user mode mapping of the allocated memory,
// dma.pKernelAddr holds the kernel mapping of
// the memory, and dma.Page[0].pPhysicalAddr
// holds the physical memory address.
////////////////////////////////////////////////////////////////
// The following is required only for version 5.22 or
// earlier of WinDriver:
BZERO(cardReg);
cardReg.Card.dwItems = 1;
cardReg.Card.Item[0].item = ITEM_MEMORY;
cardReg.Card.Item[0].I.Mem.dwBytes = dma.dwBytes;
cardReg.Card.Item[0].I.Mem.dwPhysicalAddr =
(DWORD)dma.Page[0].pPhysicalAddr;
WD_CardRegister(hWD, &cardReg);
if (!cardReg.hCard)
{
printf("failed mapping dma memory buffer\n");
// exit
}
printf("allocated 0x%x bytes, in physical address 0x%x,"
"user mode address 0x%x, kernel mode address 0x%x\n",
dma.dwBytes, dma.Page[0].pPhysicalAddr,
cardReg.Card.Item[0].I.Mem.dwUserDirectAddr,
cardReg.Card.Item[0].I.Mem.dwTransAddr);
////////////////////////////////////////////////////////////////
// pass the kernel address to the Kernel PlugIn:
BZERO (kerPlug);
kerPlug.pcDriverName = KP_DRIVER_NAME;
WD_KernelPlugInOpen(hWD, &kerPlug);
if (!kerPlug.hKernelPlugIn)
{
printf("failed opening a handle to the Kernel PlugIn\n");
// exit
}
BZERO (kpCall);
kpCall.hKernelPlugIn = kerPlug.hKernelPlugIn;
kpCall.dwMessage = YOUR_MESSAGE;
kpCall.pData = dma.pKernelAddr; // [or dwTransAddr - for previous versions]
WD_KernelPlugInCall(hWD, &kpCall);
*********************************************************************
|