在Day14介紹了如何建立專案以及設定相關專案屬性跟WPP軟體追蹤的宣告,今天我們接著介紹驅動程式主要標頭檔宣告和驅動程式主體。
SioAccess.h
NTDEVICE_NAME_STRING
& SYMBOLIC_NAME_STRING
include <ntddk.h>
include <wdf.h>
include <initguid.h>
define NTSTRSAFE_LIB
include <ntstrsafe.h>
include <wdmsec.h> // for SDDLs
include "Trace.h" // contains macros for WPP tracing
define NTDEVICE_NAME_STRING L"\\Device\\SIOACC"
define SYMBOLIC_NAME_STRING L"\\DosDevices\\SIOACC"
define SIO_INDEX_PORT 0x2E
define SIO_DATA_PORT 0x2F
define SEC_SIO_INDEX_PORT 0x4E
define SEC_SIO_DATA_PORT 0x4F
define SIO_HWM_PORT_0 0x290
define SIO_HWM_PORT_1 0x2A0
define SIO_HWM_PORT_2 0xA20
define IOCTL_CUSTOM_READ_IO_COMMAND CTL_CODE(FILE_DEVICE_UNKNOWN, 0x801, METHOD_BUFFERED, FILE_ANY_ACCESS)
define IOCTL_CUSTOM_WRITE_IO_COMMAND CTL_CODE(FILE_DEVICE_UNKNOWN, 0x802, METHOD_BUFFERED, FILE_ANY_ACCESS)
ypedef struct _IO_PORT_INPUT {
ULONG PortNumber;
union _IO_PORT_DATA {
ULONG LongData;
USHORT ShortData;
UCHAR CharData;
} IoPortData;
IO_PORT_INPUT, * PIO_PORT_INPUT;
``
DriverEntry
、DeviceAdd
...等,以及我們用來存取I/O的函式,ReadIoPort
和WriteIoPort
。
ypedef struct _CONTROL_DEVICE_EXTENSION {
HANDLE FileHandle; // Store your control data here
CONTROL_DEVICE_EXTENSION, * PCONTROL_DEVICE_EXTENSION;
DF_DECLARE_CONTEXT_TYPE_WITH_NAME(CONTROL_DEVICE_EXTENSION,
ControlGetData)
/
/ Device driver routine declarations.
/
RIVER_INITIALIZE DriverEntry;
/
/ Don't use EVT_WDF_DRIVER_DEVICE_ADD for NonPnpDeviceAdd even though
/ the signature is same because this is not an event called by the
/ framework.
/
TSTATUS
ioAccDeviceAdd(
IN WDFDRIVER Driver,
IN PWDFDEVICE_INIT DeviceInit
;
VT_WDF_DRIVER_UNLOAD SioAccEvtDriverUnload;
VT_WDF_DEVICE_CONTEXT_CLEANUP SioAccEvtDriverContextCleanup;
VT_WDF_DEVICE_SHUTDOWN_NOTIFICATION SioAccShutdown;
VT_WDF_IO_QUEUE_IO_DEVICE_CONTROL SioAccEvtIoDeviceControl;
VT_WDF_DEVICE_FILE_CREATE SioAccEvtDeviceFileCreate;
VT_WDF_FILE_CLOSE SioAccEvtFileClose;
TSTATUS
eadIoPort(
IN WDFREQUEST Request,
IN ULONG IoControlCode
;
TSTATUS
riteIoPort(
IN WDFREQUEST Request,
IN ULONG IoControlCode
;
``
SioAccess.c
ReadIoPort
和WriteIoPort
。
TSTATUS
eadIoPort(
IN WDFREQUEST Request,
IN ULONG IoControlCode
NTSTATUS Status;
UCHAR Data;
USHORT PortNumber;
PIO_PORT_INPUT InputData = NULL;
size_t InDataSize;
PVOID outBuf = NULL;
size_t outBufSize = 0;
UNREFERENCED_PARAMETER(IoControlCode);
Status = WdfRequestRetrieveInputBuffer(Request, sizeof(IO_PORT_INPUT), (PVOID*)&InputData, &InDataSize);
if (!NT_SUCCESS(Status)) {
return STATUS_INSUFFICIENT_RESOURCES;
}
Status = WdfRequestRetrieveOutputBuffer(Request, 0, &outBuf, &outBufSize);
if (!NT_SUCCESS(Status)) {
return STATUS_INSUFFICIENT_RESOURCES;
}
if ((outBuf == NULL) || (outBufSize == 0)) {
return STATUS_BUFFER_TOO_SMALL;
}
PortNumber = (USHORT)InputData->PortNumber;
KdPrint(("PortNumber %x\n", PortNumber));
if ((PortNumber != SIO_INDEX_PORT) && (PortNumber != SIO_DATA_PORT) &&
(PortNumber != SEC_SIO_INDEX_PORT) && (PortNumber != SEC_SIO_DATA_PORT) &&
(PortNumber != (SIO_HWM_PORT_0 + 0x05)) && (PortNumber != (SIO_HWM_PORT_0 + 0x06)) &&
(PortNumber != (SIO_HWM_PORT_1 + 0x05)) && (PortNumber != (SIO_HWM_PORT_1 + 0x06)))
{
return STATUS_INVALID_PARAMETER;
}
Data = __inbyte(PortNumber);
KdPrint(("Data %x\n", Data));
RtlCopyMemory(outBuf, &Data, sizeof(UCHAR));
WdfRequestSetInformation(Request, sizeof(UCHAR));
return STATUS_SUCCESS;
TSTATUS
riteIoPort(
IN WDFREQUEST Request,
IN ULONG IoControlCode
NTSTATUS Status;
USHORT PortNumber;
PIO_PORT_INPUT InputData = NULL;
size_t InDataSize;
UNREFERENCED_PARAMETER(IoControlCode);
Status = WdfRequestRetrieveInputBuffer(Request, sizeof(IO_PORT_INPUT), (PVOID*)&InputData, &InDataSize);
if (!NT_SUCCESS(Status)) {
return STATUS_INSUFFICIENT_RESOURCES;
}
PortNumber = (USHORT)InputData->PortNumber;
KdPrint(("PortNumber %x, WriteData %x\n", PortNumber, InputData->IoPortData.CharData));
if ((PortNumber != SIO_INDEX_PORT) && (PortNumber != SIO_DATA_PORT) &&
(PortNumber != SEC_SIO_INDEX_PORT) && (PortNumber != SEC_SIO_DATA_PORT) &&
(PortNumber != (SIO_HWM_PORT_0 + 0x05)) && (PortNumber != (SIO_HWM_PORT_0 + 0x06)) &&
(PortNumber != (SIO_HWM_PORT_1 + 0x05)) && (PortNumber != (SIO_HWM_PORT_1 + 0x06)))
{
return STATUS_INVALID_PARAMETER;
}
__outbyte(PortNumber, InputData->IoPortData.CharData);
return STATUS_SUCCESS;
``
SioAccEvtIoDeviceControl
的switch case中增加對應ReadIoPort
和WriteIoPort
的I/O control code。
/
/ Determine which I/O control code was specified.
/
witch (IoControlCode)
ase IOCTL_CUSTOM_READ_IO_COMMAND:
KdPrint(("IOCTL_CUSTOM_READ_IO_COMMAND\n"));
status = ReadIoPort(Request, IoControlCode);
break;
ase IOCTL_CUSTOM_WRITE_IO_COMMAND:
KdPrint(("IOCTL_CUSTOM_WRITE_IO_COMMAND\n"));
status = WriteIoPort(Request, IoControlCode);
break;
efault:
//
// The specified I/O control code is unrecognized by this driver.
//
status = STATUS_INVALID_DEVICE_REQUEST;
TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL, "ERROR: unrecognized IOCTL %x\n", IoControlCode);
break;
``
如此一來便將之前暫時實作在Non-PnP driver sample的函式獨立成一個新的驅動程式,詳細的實作可以到參考內容中的Repo閱讀。