KMDF ドライバーの GPIO I/O ピンへの接続
GPIO I/O リソースは、データ入力またはデータ出力として構成されている 1 つ以上の GPIO ピンのセットです。 これらのピンに物理的に接続する周辺機器のドライバーは、オペレーティング システムから対応する GPIO I/O リソースを取得します。 周辺機器ドライバーは、このリソースの GPIO ピンへの接続を開き、この接続を表すハンドルに I/O 要求を送信します。
次のコード例は、周辺機器のカーネル モード ドライバー フレームワーク (KMDF) ドライバーが、プラグ アンド プレイ (PnP) マネージャーがドライバーに割り当てた GPIO I/O リソースの記述を取得する方法を示しています。
NTSTATUS
EvtDevicePrepareHardware(
_In_ WDFDEVICE Device,
_In_ WDFCMRESLIST ResourcesRaw,
_In_ WDFCMRESLIST ResourcesTranslated
)
{
int ResourceCount, Index;
PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor;
XYZ_DEVICE_CONTEXT *DeviceExtension;
...
DeviceExtension = XyzDrvGetDeviceExtension(Device);
ResourceCount = WdfCmResourceListGetCount(ResourcesTranslated);
for (Index = 0; Index < ResourceCount; Index += 1) {
Descriptor = WdfCmResourceListGetDescriptor(ResourcesTranslated, Index);
switch (Descriptor->Type) {
//
// GPIO I/O descriptors
//
case CmResourceTypeConnection:
//
// Check against expected connection type.
//
if ((Descriptor->u.Connection.Class == CM_RESOURCE_CONNECTION_CLASS_GPIO) &&
(Descriptor->u.Connection.Type == CM_RESOURCE_CONNECTION_TYPE_GPIO_IO)) {
DeviceExtension->ConnectionId.LowPart = Descriptor->u.Connection.IdLowPart;
DeviceExtension->ConnectionId.HighPart = Descriptor->u.Connection.IdHighPart;
...
}
前のコード例では、DeviceExtension
変数は周辺機器のデバイス コンテキストへのポインターです。 このデバイス コンテキストを取得する XyzDrvGetDeviceExtension
関数は、周辺機器ドライバーによって実装されます。 このドライバーは以前に、WdfDeviceInitSetPnpPowerEventCallbacks メソッドを呼び出すことによって、EvtDevicePrepareHardware コールバック関数を登録しました。
次のコード例は、周辺機器ドライバーが前のコード例で取得した GPIO リソースの記述を使用して、ドライバーの GPIO I/O リソースへの WDFIOTARGET ハンドルを開く方法を示しています。
NTSTATUS IoRoutine(WDFDEVICE Device, BOOLEAN ReadOperation)
{
WDFIOTARGET IoTarget;
XYZ_DEVICE_CONTEXT *DeviceExtension;
UNICODE_STRING ReadString;
WCHAR ReadStringBuffer[100];;
BOOL DesiredAccess;
NTSTATUS Status;
WDF_OBJECT_ATTRIBUTES ObjectAttributes;
WDF_IO_TARGET_OPEN_PARAMS OpenParams
DeviceExtension = XyzDrvGetDeviceExtension(Device);
RtlInitEmptyUnicodeString(&ReadString,
ReadStringBuffer,
sizeof(ReadStringBuffer));
Status = RESOURCE_HUB_CREATE_PATH_FROM_ID(&ReadString,
DeviceExtension->ConnectionId.LowPart,
DeviceExtension->ConnectionId.HighPart);
NT_ASSERT(NT_SUCCESS(Status));
WDF_OBJECT_ATTRIBUTES_INIT(&ObjectAttributes);
ObjectAttributes.ParentObject = Device;
Status = WdfIoTargetCreate(Device, &ObjectAttributes, &IoTarget);
if (!NT_SUCCESS(Status)) {
goto IoErrorEnd;
}
if (ReadOperation != FALSE) {
DesiredAccess = GENERIC_READ;
} else {
DesiredAccess = GENERIC_WRITE;
}
WDF_IO_TARGET_OPEN_PARAMS_INIT_OPEN_BY_NAME(&OpenParams, ReadString, DesiredAccess);
Status = WdfIoTargetOpen(IoTarget, &OpenParams);
if (!NT_SUCCESS(Status)) {
goto IoErrorEnd;
}
...
前のコード例では、Device
変数は周辺機器のフレームワーク デバイス オブジェクトに対する WDFDEVICE ハンドルです。 RESOURCE_HUB_CREATE_PATH_FROM_ID 関数は、GPIO I/O リソースの名前を含む文字列を作成します。 このコード例では、この文字列を使用して、GPIO I/O リソースを名前で開きます。
周辺機器ドライバーが GPIO I/O リソースへのハンドルを取得した後、このドライバーは GPIO ピンに対するデータの読み取りまたはデータの書き込みのために I/O コントロール要求を送信できます。 読み取り用に GPIO I/O リソースを開くドライバーは、IOCTL_GPIO_READ_PINS I/O コントロール要求を使用して、リソース内のピンからデータを読み取ります。 書き込み用に GPIO I/O リソースを開くドライバーは、IOCTL_GPIO_WRITE_PINS I/O コントロール要求を使用して、リソース内のピンにデータを書き込みます。 次のコード例は、GPIO の読み取りまたは書き込み操作を実行する方法を示しています。
WDF_OBJECT_ATTRIBUTES RequestAttributes;
WDF_OBJECT_ATTRIBUTES Attributes;
WDF_REQUEST_SEND_OPTIONS SendOptions;
WDFREQUEST IoctlRequest;
WDFIOTARGET IoTarget;
WDFMEMORY WdfMemory;
NTSTATUS Status;
WDF_OBJECT_ATTRIBUTES_INIT(&RequestAttributes);
Status = WdfRequestCreate(&RequestAttributes, IoTarget, &IoctlRequest);
if (!NT_SUCCESS(Status)) {
goto RwErrorExit;
}
//
// Set up a WDF memory object for the IOCTL request.
//
WDF_OBJECT_ATTRIBUTES_INIT(&Attributes);
Attributes.ParentObject = IoctlRequest;
Status = WdfMemoryCreatePreallocated(&Attributes, Data, Size, &WdfMemory);
if (!NT_SUCCESS(Status)) {
goto RwErrorExit;
}
//
// Format the request.
//
if (ReadOperation != FALSE) {
Status = WdfIoTargetFormatRequestForIoctl(IoTarget,
IoctlRequest,
IOCTL_GPIO_READ_PINS,
NULL,
0,
WdfMemory,
0);
} else {
Status = WdfIoTargetFormatRequestForIoctl(IoTarget,
IoctlRequest,
IOCTL_GPIO_WRITE_PINS,
WdfMemory,
0,
WdfMemory,
0);
}
if (!NT_SUCCESS(Status)) {
goto RwErrorExit;
}
//
// Send the request synchronously (with a 60-second time-out).
//
WDF_REQUEST_SEND_OPTIONS_INIT(&SendOptions,
WDF_REQUEST_SEND_OPTION_SYNCHRONOUS);
WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT(&SendOptions,
WDF_REL_TIMEOUT_IN_SEC(60));
Status = WdfRequestAllocateTimer(IoctlRequest);
if (!NT_SUCCESS(Status)) {
goto RwErrorExit;
}
if (!WdfRequestSend(IoctlRequest, IoTarget, &SendOptions)) {
Status = WdfRequestGetStatus(IoctlRequest);
}
...
前のコード例では、Data
はデータ バッファーへのポインターで、Size
はこのデータ バッファーのサイズ (バイト単位) です。また、ReadOperation
は要求された操作が読み取り (TRUE) か書き込み (FALSE) かを示します。
詳細情報
要求出力バッファー内のビットに対するデータ入力ピンのマッピングなど、IOCTL_GPIO_READ_PINS 要求の詳細については、「IOCTL_GPIO_READ_PINS」を参照してください。 データ出力ピンに対する要求入力バッファー内のビットのマッピングなど、IOCTL_GPIO_WRITE_PINS 要求の詳細については、「IOCTL_GPIO_WRITE_PINS」を参照してください。
カーネル モードで実行される GPIO 周辺機器ドライバーを記述する方法を示すサンプル ドライバーについては、GitHub の GPIO サンプル ドライバー コレクションの SimDevice サンプル ドライバーを参照してください。