summaryrefslogtreecommitdiff
path: root/pofx/UMDF2/App/PowerFxApp.cpp
diff options
context:
space:
mode:
authorDave Wilson <[email protected]>2015-03-17 19:50:07 -0700
committerDave Wilson <[email protected]>2015-03-17 19:50:07 -0700
commit97cf5197cf5b882b2c689d8dc2b555f2edf8f418 (patch)
tree46f3701832d70b420eb0fc0eb93261f9da45db3f /pofx/UMDF2/App/PowerFxApp.cpp
parentef1905bf1e8825bb31120dfb27e0daf3154d859a (diff)
Initial publish
Diffstat (limited to 'pofx/UMDF2/App/PowerFxApp.cpp')
-rw-r--r--pofx/UMDF2/App/PowerFxApp.cpp592
1 files changed, 592 insertions, 0 deletions
diff --git a/pofx/UMDF2/App/PowerFxApp.cpp b/pofx/UMDF2/App/PowerFxApp.cpp
new file mode 100644
index 00000000..c628d366
--- /dev/null
+++ b/pofx/UMDF2/App/PowerFxApp.cpp
@@ -0,0 +1,592 @@
+/*++
+
+Copyright (c) Microsoft Corporation
+
+Module Name:
+
+ PowerFxApp.cpp
+
+Abstract:
+
+ This application can be used to exercise KMDF sample drivers for the
+ new power framework. See application "usage" details for more information.
+
+Environment:
+
+ user mode only
+
+--*/
+
+#include "include.h"
+
+int __cdecl
+wmain(
+ _In_ int argc,
+ _In_reads_(argc) PWSTR argv[]
+ )
+{
+ DWORD err;
+ WCHAR devicePath[MAX_DEVPATH_LENGTH] = {UNICODE_NULL};
+ HANDLE hDevice = INVALID_HANDLE_VALUE;
+ HANDLE hCompletionPort = NULL;
+
+
+ //
+ // Process user input.
+ //
+ err = ProcessUserInput(argc, argv);
+ if (ERROR_SUCCESS != err)
+ {
+ goto clean0;
+ }
+
+ if ( !GetDevicePath(
+ (LPGUID) &GUID_DEVINTERFACE_POWERFX,
+ devicePath,
+ COUNT_OF(devicePath)))
+ {
+ printf("Unable to get device path. Has the device driver been installed? \n");
+ err = ERROR_OPEN_FAILED;
+ goto clean0;
+ }
+
+ hDevice = CreateFile(devicePath,
+ GENERIC_READ|GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL,
+ OPEN_EXISTING,
+ FILE_FLAG_OVERLAPPED,
+ NULL );
+
+ if (hDevice == INVALID_HANDLE_VALUE) {
+ err = GetLastError();
+ printf("Failed to open device. Error %d.\n",err);
+ goto clean0;
+ }
+
+ hCompletionPort = CreateIoCompletionPort(hDevice, NULL, 1, 0);
+ if (hCompletionPort == NULL) {
+ err = GetLastError();
+ printf("Cannot open completion port %d.\n",err);
+ goto clean0;
+ }
+
+ err = SendIO(hDevice,
+ hCompletionPort,
+ GetSetting(COMPONENT),
+ GetSetting(MAX_OUTSTANDING_IO),
+ GetSetting(DELAY),
+ (BOOLEAN)GetSetting(CANCEL));
+ if (ERROR_SUCCESS != err)
+ {
+ goto clean0;
+ }
+
+clean0:
+ if (INVALID_HANDLE_VALUE != hDevice)
+ {
+ CloseHandle(hDevice);
+ }
+ if (NULL != hCompletionPort)
+ {
+ CloseHandle(hCompletionPort);
+ }
+ return err;
+}
+
+DWORD Initialize(
+ _In_ ULONG Count,
+ _Out_ LPOVERLAPPED *pOverlappedPtr,
+ _Out_ PPOWERFX_READ_COMPONENT_INPUT *pInput,
+ _Out_ PPOWERFX_READ_COMPONENT_OUTPUT *pOutput
+ )
+{
+ PPOWERFX_READ_COMPONENT_INPUT inputBuffer = NULL;
+ PPOWERFX_READ_COMPONENT_OUTPUT outputBuffer = NULL;
+ LPOVERLAPPED pOverlapped = NULL;
+ DWORD err = ERROR_SUCCESS;
+
+ pOverlapped = new OVERLAPPED[Count];
+ if (NULL == pOverlapped)
+ {
+ err = ERROR_OUTOFMEMORY;
+ goto clean0;
+ }
+
+ inputBuffer = new POWERFX_READ_COMPONENT_INPUT[Count];
+ if (NULL == inputBuffer)
+ {
+ err = ERROR_OUTOFMEMORY;
+ goto clean0;
+ }
+
+ outputBuffer = new POWERFX_READ_COMPONENT_OUTPUT[Count];
+ if (NULL == outputBuffer)
+ {
+ err = ERROR_OUTOFMEMORY;
+ goto clean0;
+ }
+
+ ZeroMemory(pOverlapped,
+ sizeof(OVERLAPPED)*Count);
+
+ for (UINT i = 0; i < Count; i++)
+ {
+ //
+ // When the component number is set to UNUSED it indicates
+ // that a request has not been issued (or has completed)
+ // using this input buffer. Hence the buffer along with the
+ // overlapped structure at the corresponding index is available
+ // for issuing a request.
+ //
+ inputBuffer[i].ComponentNumber = UNUSED;
+ }
+
+ ZeroMemory(outputBuffer,
+ sizeof(POWERFX_READ_COMPONENT_OUTPUT)*Count);
+
+clean0:
+ if (err != ERROR_SUCCESS)
+ {
+ delete[] pOverlapped;
+ delete[] inputBuffer;
+ delete[] outputBuffer;
+ }
+ else
+ {
+ *pOverlappedPtr = pOverlapped;
+ *pInput = inputBuffer;
+ *pOutput = outputBuffer;
+ }
+ return err;
+}
+
+/*++
+
+Routine Description:
+
+ This function sends requests to the driver based on the settings passed
+ in the arguments. The requests are sent indefinitely until an error occurs.
+
+ Depending on the number of maximum outstanding I/O requests,
+ an array of overlapped structures and input/output buffers is allocated.
+ The method then loops through the overlapped structure array
+ to issue asynchronous requests. When a request completes, the
+ overlapped structure for that request is not immediately re-used to issue
+ a new request. Instead the method goes in-order through the array to
+ ensure that each issued request is completed in a reasonable amount
+ of time and it is able to detect if one or more requests do not complete
+ at all (or within the specified timeout).
+
+--*/
+DWORD SendIO(
+ _In_ HANDLE DeviceHandle,
+ _In_ HANDLE CompletionPortHandle,
+ _In_ ULONG Component,
+ _In_ ULONG MaxOutstandingIo,
+ _In_ ULONG Delay,
+ _In_ BOOLEAN Cancel
+ )
+{
+ LPOVERLAPPED pOverlapped = NULL;
+ LPOVERLAPPED pOv = NULL;
+ PPOWERFX_READ_COMPONENT_INPUT inputBuffer = NULL;
+ PPOWERFX_READ_COMPONENT_OUTPUT outputBuffer = NULL;
+ DWORD err = ERROR_SUCCESS;
+ UINT outstandingIoCount = 0;
+ UINT index = 0;
+
+ srand((DWORD)GetTickCount64());
+
+ err = Initialize(MaxOutstandingIo,
+ &pOverlapped,
+ &inputBuffer,
+ &outputBuffer);
+ if (ERROR_SUCCESS != err)
+ {
+ goto clean0;
+ }
+
+ UINT k = 0;
+
+ for (;;k++)
+ {
+ k = k % MaxOutstandingIo;
+
+ if (UNUSED == inputBuffer[k].ComponentNumber)
+ {
+ //
+ // This indicates the input buffer and corresponding overlapped
+ // structure is available to issue a new request.
+ //
+ pOv = &pOverlapped[k];
+ }
+ else
+ {
+ //
+ // Wait for request #k to complete.
+ //
+ DWORD completionStatus;
+ ULONGLONG startTime = GetTickCount64();
+
+ for(;;)
+ {
+ ULONG_PTR completedRequestIndex;
+
+ err = WaitForIoCompletion(CompletionPortHandle,
+ &pOv,
+ &completionStatus);
+ if (ERROR_SUCCESS != err) {
+ goto clean0;
+ }
+
+ completedRequestIndex = pOv-pOverlapped;
+
+ printf(" Request %d completed with status 0x%X.\n",
+ (DWORD)completedRequestIndex, completionStatus);
+
+ if (ERROR_SUCCESS != completionStatus)
+ {
+ if (!Cancel ||
+ ERROR_OPERATION_ABORTED != completionStatus)
+ {
+ //
+ // If there is a setting to cancel requests it is ok for
+ // the requests to complete with aborted status.
+ //
+ err = completionStatus;
+ printf(" Unexpected completion status %d. \n",
+ completionStatus);
+ goto clean0;
+ }
+ }
+ else
+ {
+ //
+ // If request completed successfully verify the contents of the buffer.
+ //
+ if (! VerifyRequest(&inputBuffer[completedRequestIndex],
+ &outputBuffer[completedRequestIndex]))
+ {
+ printf(" Request completed with unexpected data in"
+ " output buffer. \n");
+ err = ERROR_INVALID_DATA;
+ goto clean0;
+ }
+ }
+
+ inputBuffer[completedRequestIndex].ComponentNumber = UNUSED;
+ outstandingIoCount--;
+
+ if (k == completedRequestIndex)
+ {
+ //
+ // The request we are looking for has completed.
+ //
+ pOv = &pOverlapped[k];
+ break;
+ }
+ else if (GetTickCount64() - startTime > REQUEST_TIMEOUT)
+ {
+ //
+ // The request we are looking for did not complete on time.
+ //
+ err = ERROR_TIMEOUT;
+ printf(" Request %d did not complete within the expected"
+ " time. \n", k);
+ assert(0);
+ goto clean0;
+ }
+ }
+
+ }
+
+ //
+ // We now have an overlapped structure to use. Set the input buffer
+ // to the target component and send the request.
+ //
+ ZeroMemory(pOv, sizeof(OVERLAPPED));
+ inputBuffer[k].ComponentNumber = (Component == RANDOM_COMPONENT) ?
+ (rand() % COMPONENT_COUNT):
+ Component;
+
+ if (0 != Delay)
+ {
+ //
+ // If there is a setting to introduce a delay, sleep and then send the
+ // request.
+ //
+ Sleep(rand() % Delay);
+ }
+
+ err = SendRequest(DeviceHandle,
+ pOv,
+ &inputBuffer[k],
+ &outputBuffer[k]);
+ if (ERROR_SUCCESS != err)
+ {
+ goto clean0;
+ }
+
+ outstandingIoCount++;
+
+ printf(" Request number %d sent to component %d.\n", k,
+ inputBuffer[k].ComponentNumber);
+
+ if (Cancel)
+ {
+ //
+ // If there is a setting to cancel the request then cancel it after
+ // issuing it.
+ //
+ CancelIoEx(DeviceHandle,
+ pOv);
+ }
+ }
+
+clean0:
+ if (outstandingIoCount > 0)
+ {
+ CancelIo(DeviceHandle);
+ for (index=0; index < outstandingIoCount; index++)
+ {
+ WaitForIoCompletion(CompletionPortHandle,
+ NULL,
+ NULL);
+ }
+ }
+ delete[] pOverlapped;
+ delete[] inputBuffer;
+ delete[] outputBuffer;
+ return err;
+}
+
+BOOLEAN
+VerifyRequest(
+ _In_ PPOWERFX_READ_COMPONENT_INPUT input,
+ _In_ PPOWERFX_READ_COMPONENT_OUTPUT output)
+{
+ return (output->ComponentData == ~input->ComponentNumber);
+}
+
+DWORD
+SendRequest(
+ _In_ HANDLE DeviceHandle,
+ _In_ LPOVERLAPPED OverlappedPtr,
+ _In_ PPOWERFX_READ_COMPONENT_INPUT inputBuffer,
+ _In_ PPOWERFX_READ_COMPONENT_OUTPUT outputBuffer)
+{
+
+ BOOL bResult = FALSE;
+ DWORD err = ERROR_SUCCESS;
+
+ bResult = DeviceIoControl(DeviceHandle,
+ (DWORD) IOCTL_POWERFX_READ_COMPONENT,
+ (PVOID)inputBuffer,
+ sizeof(POWERFX_READ_COMPONENT_INPUT),
+ (PVOID)outputBuffer,
+ sizeof(POWERFX_READ_COMPONENT_OUTPUT),
+ NULL,
+ OverlappedPtr);
+ if (FALSE == bResult)
+ {
+ err = GetLastError();
+ if (ERROR_IO_PENDING == err)
+ {
+ //
+ // This is not really an error.
+ //
+ err = ERROR_SUCCESS;
+ }
+ else
+ {
+ printf("Unable to send request. DeviceIoControl failed with "
+ "error 0x%X. \n", err);
+ goto clean0;
+ }
+ }
+clean0:
+ return err;
+}
+
+DWORD
+WaitForIoCompletion(
+ _In_ HANDLE CompletionPortHandle,
+ _In_opt_ LPOVERLAPPED* POvPtr,
+ _Out_opt_ PDWORD CompletionStatus)
+{
+ BOOL bResult;
+ DWORD err;
+ DWORD numBytes;
+ ULONG_PTR completionKey;
+ LPOVERLAPPED ovPtr;
+ DWORD completionStatus;
+
+ //
+ // Assume successful completion of I/O request
+ //
+ completionStatus = ERROR_SUCCESS;
+
+ //
+ // Dequeue a completion packet
+ //
+ bResult = GetQueuedCompletionStatus(CompletionPortHandle,
+ &numBytes,
+ &completionKey,
+ &ovPtr,
+ REQUEST_TIMEOUT);
+ if (FALSE == bResult)
+ {
+ err = GetLastError();
+ if (NULL == ovPtr)
+ {
+ printf("Could not dequeue a completion packet. "
+ "GetQueuedCompletionStatus failed with error 0x%X.",
+ err);
+ assert(0);
+ goto clean0;
+ }
+
+ //
+ // We dequeued a completion packet for an I/O operation that failed.
+ // Make a note of the failure status, but we need to return success from
+ // this function because we got a completion packet (even though it was
+ // for a failed I/O operation).
+ //
+ completionStatus = err;
+ err = ERROR_SUCCESS;
+ }
+
+ if (NULL != POvPtr) {
+ *POvPtr = ovPtr;
+ }
+
+ if (NULL != CompletionStatus) {
+ *CompletionStatus = completionStatus;
+ }
+
+ err = ERROR_SUCCESS;
+
+clean0:
+ return err;
+}
+
+BOOL
+GetDevicePath(
+ IN LPGUID InterfaceGuid,
+ _Out_writes_(BufLen) PWSTR DevicePath,
+ _In_ size_t BufLen
+ )
+{
+ HDEVINFO HardwareDeviceInfo;
+ SP_DEVICE_INTERFACE_DATA DeviceInterfaceData;
+ PSP_DEVICE_INTERFACE_DETAIL_DATA DeviceInterfaceDetailData = NULL;
+ ULONG Length, RequiredLength = 0;
+ BOOL bResult;
+ HRESULT hr;
+
+ HardwareDeviceInfo = SetupDiGetClassDevs(
+ InterfaceGuid,
+ NULL,
+ NULL,
+ (DIGCF_PRESENT | DIGCF_DEVICEINTERFACE));
+
+ if (HardwareDeviceInfo == INVALID_HANDLE_VALUE) {
+ printf("SetupDiGetClassDevs failed!\n");
+ return FALSE;
+ }
+
+ DeviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
+
+ bResult = SetupDiEnumDeviceInterfaces(HardwareDeviceInfo,
+ 0,
+ InterfaceGuid,
+ 0,
+ &DeviceInterfaceData);
+
+ if (bResult == FALSE) {
+
+ LPVOID lpMsgBuf;
+
+ if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL,
+ GetLastError(),
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+ (LPWSTR) &lpMsgBuf,
+ 0,
+ NULL
+ )) {
+
+ printf("SetupDiEnumDeviceInterfaces failed: %ws", (LPTSTR)lpMsgBuf);
+ LocalFree(lpMsgBuf);
+ }
+
+ printf("SetupDiEnumDeviceInterfaces failed.\n");
+ SetupDiDestroyDeviceInfoList(HardwareDeviceInfo);
+ return FALSE;
+ }
+
+ SetupDiGetDeviceInterfaceDetail(
+ HardwareDeviceInfo,
+ &DeviceInterfaceData,
+ NULL,
+ 0,
+ &RequiredLength,
+ NULL
+ );
+
+ DeviceInterfaceDetailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA)LocalAlloc(LMEM_FIXED, RequiredLength);
+
+ if (DeviceInterfaceDetailData == NULL) {
+ SetupDiDestroyDeviceInfoList(HardwareDeviceInfo);
+ printf("Failed to allocate memory.\n");
+ return FALSE;
+ }
+
+ DeviceInterfaceDetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
+
+ Length = RequiredLength;
+
+ bResult = SetupDiGetDeviceInterfaceDetail(
+ HardwareDeviceInfo,
+ &DeviceInterfaceData,
+ DeviceInterfaceDetailData,
+ Length,
+ &RequiredLength,
+ NULL);
+
+ if (bResult == FALSE) {
+
+ LPVOID lpMsgBuf;
+
+ FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL,
+ GetLastError(),
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+ (LPWSTR) &lpMsgBuf,
+ 0,
+ NULL
+ );
+
+ SetupDiDestroyDeviceInfoList(HardwareDeviceInfo);
+ printf("Error in SetupDiGetDeviceInterfaceDetail: %ws\n", (LPWSTR)lpMsgBuf);
+ LocalFree(DeviceInterfaceDetailData);
+ LocalFree(lpMsgBuf);
+ return FALSE;
+ }
+
+ hr = StringCchCopy(DevicePath,
+ BufLen,
+ DeviceInterfaceDetailData->DevicePath) ;
+
+ SetupDiDestroyDeviceInfoList(HardwareDeviceInfo); // It must be executed in both success and failure traces
+ LocalFree(DeviceInterfaceDetailData);
+
+ return ( !FAILED(hr) ); // Result depends on StringCchCopy()
+}
+
+