Windows CEのデバイスドライバで、割り込み処理をする方法について簡単に説明します。
下図がHW割り込み発生から、ISTが駆動されるまでの大まかな流れです。
ISR: 割り込みサービス ルーチン (Interrupt Service Routine) 割り込みソースを識別し、対応するIRQ番号をカーネルに返す。
SYSINTR: 割り込み識別子。割り込みソースを示すソフトウェア用の割り込み識別子。
IST: 割り込みサービス スレッド (Interrupt Service Thread) デバイスドライバで実行される割り込み処理用のスレッド。
(1)HW割り込みが発生すると、対応するISRが呼び出されます。ISRはIRQ番号をカーネルに渡します。 (2)カーネルはIRQ番号に関連づけられたSYSINTRを返します。 (3)そしてそのSYSINTRに関連づけられたEventがセットされます。 (4)WaitForSingleObjectにてEvent待ちをしていたISTが駆動され、割り込み処理が実行されます。
ドライバで実装するのは、この流れで必要な、 (2)HW割り込みID(識別子)とSYSINTRの関連づけ、 (3)SYSINTRとEventの関連づけ、そして (4)ISTの3つになります。
以下が、実際のコード例です。
#define IRQ_DEVICE0 35 // そのデバイスに割り振られているHWレベルでのIRQ番号
#define DEVICE_THREAD_PRIORITY 150 // ISTのスレッド優先度
typedef struct {
HANDLE IntrThread;
UINT32 SysIntr;
HANDLE IntrEvent;
} DEVICE_STRUCT;
DEVICE_STRUCT *pDevice = NULL;
UINT32 irq = IRQ_DEVICE0;
// デバイス管理用構造体の生成
pDevice = (DEVICE_STRUCT *)LocalAlloc(LPTR, sizeof(DEVICE_STRUCT));
memset(pDevice, 0, sizeof(DEVICE_STRUCT));
// (2)デバイスのIRQ番号 IRQ_DEVICE0 に対応するSYSINTR の関連づけ
KernelIoControl(IOCTL_HAL_REQUEST_SYSINTR, &irq, sizeof(UINT32), &pDevice->SysIntr, sizeof(UINT32), NULL);
// 割り込みスレッド駆動用イベントの生成
pDevice->IntrEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
// (3)SYSINTRとイベントの関連づけ(これで割り込み発生時に対応するイベントが駆動される)
InterruptInitialize(pDevice->SysIntr, pDevice->IntrEvent, NULL, 0);
// ISTの生成
DeviceIntrThread = CreateThread((LPSECURITY_ATTRIBUTES)NULL, 0, (LPTHREAD_START_ROUTINE)DeviceInterruptThread, pDevice, 0, NULL);
// ISTの優先度設定
CeSetThreadPriority(pDevice->IntrThread, DEVICE_THREAD_PRIORITY);
// ISR本体
VOID DeviceInterruptThread(DEVICE_STRUCT *pDevice)
{
while(TRUE) {
// (4)Eventがセットされるのを待つ
WaitForSingleObject(pDevice->IntrEvent, INFINITE);
/* ここで割り込み処理を行う */
}
}