Menyambungkan Driver KMDF ke Pin I/O GPIO
Sumber daya I/O GPIO adalah sekumpulan satu atau beberapa pin GPIO yang dikonfigurasi sebagai input data atau output data. Driver untuk perangkat periferal yang secara fisik terhubung ke pin ini memperoleh sumber daya I/O GPIO yang sesuai dari sistem operasi. Driver perangkat periferal membuka koneksi ke pin GPIO di sumber daya ini dan mengirim permintaan I/O ke handel yang mewakili koneksi ini.
Contoh kode berikut menunjukkan bagaimana driver kerangka kerja driver mode kernel (KMDF) untuk perangkat periferal dapat memperoleh deskripsi sumber daya I/O GPIO yang telah ditetapkan manajer Plug and Play (PnP) ke driver.
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;
...
}
Dalam contoh kode sebelumnya, DeviceExtension
variabel adalah penunjuk ke konteks perangkat untuk perangkat periferal. Fungsi XyzDrvGetDeviceExtension
, yang mengambil konteks perangkat ini, diimplementasikan oleh driver perangkat periferal. Driver ini sebelumnya mendaftarkan fungsi panggilan balik EvtDevicePrepareHardware dengan memanggil metode WdfDeviceInitSetPnpowerEventCallbacks .
Contoh kode berikut menunjukkan bagaimana driver perangkat periferal dapat menggunakan deskripsi sumber daya GPIO yang diperolehnya dalam contoh kode sebelumnya untuk membuka handel WDFIOTARGET ke sumber daya I/O GPIO driver.
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;
}
...
Dalam contoh kode sebelumnya, Device
variabel adalah handel WDFDEVICE ke objek perangkat kerangka kerja untuk perangkat periferal. Fungsi RESOURCE_HUB_CREATE_PATH_FROM_ID membuat string yang berisi nama sumber daya I/O GPIO. Contoh kode menggunakan string ini untuk membuka sumber daya I/O GPIO berdasarkan nama.
Setelah driver perangkat periferal mendapatkan handel ke sumber daya I/O GPIO, driver ini dapat mengirim permintaan kontrol I/O untuk membaca data dari atau menulis data ke pin GPIO. Driver yang membuka sumber daya I/O GPIO untuk bacaan menggunakan IOCTL_GPIO_READ_PINS permintaan kontrol I/O untuk membaca data dari pin di sumber daya. Driver yang membuka sumber daya I/O GPIO untuk penulisan menggunakan IOCTL_GPIO_WRITE_PINS permintaan kontrol I/O untuk menulis data ke pin di sumber daya. Contoh kode berikut menunjukkan cara melakukan operasi baca atau tulis 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);
}
...
Dalam contoh kode sebelumnya, Data
adalah penunjuk ke buffer data, Size
adalah ukuran, dalam byte, dari buffer data ini, dan ReadOperation
menunjukkan apakah operasi yang diminta adalah baca (TRUE) atau tulis (FALSE).
Untuk informasi selengkapnya
Untuk informasi selengkapnya tentang permintaan IOCTL_GPIO_READ_PINS , termasuk pemetaan pin input data ke bit dalam buffer output permintaan, lihat IOCTL_GPIO_READ_PINS. Untuk informasi selengkapnya tentang permintaan IOCTL_GPIO_WRITE_PINS , termasuk pemetaan bit dalam buffer input permintaan ke pin output data, lihat IOCTL_GPIO_WRITE_PINS.
Untuk driver sampel yang menunjukkan cara menulis driver periferal GPIO yang berjalan dalam mode kernel, lihat driver sampel SimDevice di koleksi driver sampel GPIO di GitHub.