iT邦幫忙

2023 iThome 鐵人賽

DAY 15
0

Day14介紹了如何建立專案以及設定相關專案屬性WPP軟體追蹤的宣告,今天我們接著介紹驅動程式主要標頭檔宣告和驅動程式主體

  • SioAccess.h
    • 參考Non-PnP driver sample,加入Day11中位於標頭檔的宣告。
      • NTDEVICE_NAME_STRING & SYMBOLIC_NAME_STRING
        • Day05中有提到,我們需要定義裝置名稱讓應用程式可以透過名稱或symbolic link存取裝置。
      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;
      ``
      
      
    • 參考Non-PnP driver sample,加入KMDF中必須有的函式,如DriverEntryDeviceAdd...等,以及我們用來存取I/O的函式,ReadIoPortWriteIoPort
      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
    • 添加在Day11中實作的ReadIoPortWriteIoPort
      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中增加對應ReadIoPortWriteIoPort的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閱讀。

參考內容

Sio-Repo


上一篇
Day14 使用I/O存取環控晶片-4
下一篇
Day16 使用I/O存取環控晶片-6
系列文
Windows Driver + Electron 學習筆記30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言