diff options
Diffstat (limited to 'general/echo/kmdf/exe/echoapp.cpp')
| -rw-r--r-- | general/echo/kmdf/exe/echoapp.cpp | 700 |
1 files changed, 700 insertions, 0 deletions
diff --git a/general/echo/kmdf/exe/echoapp.cpp b/general/echo/kmdf/exe/echoapp.cpp new file mode 100644 index 00000000..9649a407 --- /dev/null +++ b/general/echo/kmdf/exe/echoapp.cpp @@ -0,0 +1,700 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + ioctl.cpp + +Abstract: + + A simple asynch test for usb driver. + + +Environment: + + user mode only + +--*/ + + +#include <DriverSpecs.h> +_Analysis_mode_(_Analysis_code_type_user_code_) + +#define INITGUID + +#include <windows.h> +#include <strsafe.h> +#include <setupapi.h> +#include <stdio.h> +#include <stdlib.h> +#include "public.h" + +#define NUM_ASYNCH_IO 100 +#define BUFFER_SIZE (40*1024) + +#define READER_TYPE 1 +#define WRITER_TYPE 2 + +#define MAX_DEVPATH_LENGTH 256 + +BOOLEAN G_PerformAsyncIo; +BOOLEAN G_LimitedLoops; +ULONG G_AsyncIoLoopsNum; +CHAR G_DevicePath[MAX_DEVPATH_LENGTH]; + + +ULONG +AsyncIo( + PVOID ThreadParameter + ); + +BOOLEAN +PerformWriteReadTest( + IN HANDLE hDevice, + IN ULONG TestLength + ); + +BOOL +GetDevicePath( + IN LPGUID InterfaceGuid, + _Out_writes_(BufLen) PCHAR DevicePath, + _In_ size_t BufLen + ); + + +int __cdecl +main( + _In_ int argc, + _In_reads_(argc) char* argv[] + ) +{ + HANDLE hDevice = INVALID_HANDLE_VALUE; + HANDLE th1 = NULL; + BOOLEAN result = TRUE; + + + if (argc > 1) { + if(!_strnicmp (argv[1], "-Async", 6) ) { + G_PerformAsyncIo = TRUE; + if (argc > 2) { + G_AsyncIoLoopsNum = atoi(argv[2]); + G_LimitedLoops = TRUE; + } + else { + G_LimitedLoops = FALSE; + } + + } else { + printf("Usage:\n"); + printf(" Echoapp.exe --- Send single write and read request synchronously\n"); + printf(" Echoapp.exe -Async --- Send reads and writes asynchronously without terminating\n"); + printf(" Echoapp.exe -Async <number> --- Send <number> reads and writes asynchronously\n"); + printf("Exit the app anytime by pressing Ctrl-C\n"); + result = FALSE; + goto exit; + } + } + + if ( !GetDevicePath( + (LPGUID) &GUID_DEVINTERFACE_ECHO, + G_DevicePath, + sizeof(G_DevicePath)/sizeof(G_DevicePath[0])) ) + { + result = FALSE; + goto exit; + } + + printf("DevicePath: %s\n", G_DevicePath); + + hDevice = CreateFile(G_DevicePath, + GENERIC_READ|GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + 0, + NULL ); + + if (hDevice == INVALID_HANDLE_VALUE) { + printf("Failed to open device. Error %d\n",GetLastError()); + result = FALSE; + goto exit; + } + + printf("Opened device successfully\n"); + + if(G_PerformAsyncIo) { + + printf("Starting AsyncIo\n"); + + // + // Create a reader thread + // + th1 = CreateThread( NULL, // Default Security Attrib. + 0, // Initial Stack Size, + (LPTHREAD_START_ROUTINE) AsyncIo, // Thread Func + (LPVOID)READER_TYPE, + 0, // Creation Flags + NULL ); // Don't need the Thread Id. + + if (th1 == NULL) { + printf("Couldn't create reader thread - error %d\n", GetLastError()); + result = FALSE; + goto exit; + } + + // + // Use this thread for peforming write. + // + result = (BOOLEAN)AsyncIo((PVOID)WRITER_TYPE); + + }else { + // + // Write pattern buffers and read them back, then verify them + // + result = PerformWriteReadTest(hDevice, 512); + if(!result) { + goto exit; + } + + result = PerformWriteReadTest(hDevice, 30*1024); + if(!result) { + goto exit; + } + + } + +exit: + + if (th1 != NULL) { + WaitForSingleObject(th1, INFINITE); + CloseHandle(th1); + } + + if (hDevice != INVALID_HANDLE_VALUE) { + CloseHandle(hDevice); + } + + return ((result == TRUE) ? 0 : 1); + +} + +PUCHAR +CreatePatternBuffer( + IN ULONG Length + ) +{ + unsigned int i; + PUCHAR p, pBuf; + + pBuf = (PUCHAR)malloc(Length); + if( pBuf == NULL ) { + printf("Could not allocate %d byte buffer\n",Length); + return NULL; + } + + p = pBuf; + + for(i=0; i < Length; i++ ) { + *p = (UCHAR)i; + p++; + } + + return pBuf; +} + +BOOLEAN +VerifyPatternBuffer( + _In_reads_bytes_(Length) PUCHAR pBuffer, + _In_ ULONG Length + ) +{ + unsigned int i; + PUCHAR p = pBuffer; + + for( i=0; i < Length; i++ ) { + + if( *p != (UCHAR)(i & 0xFF) ) { + printf("Pattern changed. SB 0x%x, Is 0x%x\n", + (UCHAR)(i & 0xFF), *p); + return FALSE; + } + + p++; + } + + return TRUE; +} + +BOOLEAN +PerformWriteReadTest( + IN HANDLE hDevice, + IN ULONG TestLength + ) +/* +*/ +{ + ULONG bytesReturned =0; + PUCHAR WriteBuffer = NULL, + ReadBuffer = NULL; + BOOLEAN result = TRUE; + + WriteBuffer = CreatePatternBuffer(TestLength); + if( WriteBuffer == NULL ) { + + result = FALSE; + goto Cleanup; + } + + ReadBuffer = (PUCHAR)malloc(TestLength); + if( ReadBuffer == NULL ) { + + printf("PerformWriteReadTest: Could not allocate %d " + "bytes ReadBuffer\n",TestLength); + + result = FALSE; + goto Cleanup; + + } + + // + // Write the pattern to the device + // + bytesReturned = 0; + + if (!WriteFile ( hDevice, + WriteBuffer, + TestLength, + &bytesReturned, + NULL)) { + + printf ("PerformWriteReadTest: WriteFile failed: " + "Error %d\n", GetLastError()); + + result = FALSE; + goto Cleanup; + + } else { + + if( bytesReturned != TestLength ) { + + printf("bytes written is not test length! Written %d, " + "SB %d\n",bytesReturned, TestLength); + + result = FALSE; + goto Cleanup; + } + + printf ("%d Pattern Bytes Written successfully\n", + bytesReturned); + } + + bytesReturned = 0; + + if ( !ReadFile (hDevice, + ReadBuffer, + TestLength, + &bytesReturned, + NULL)) { + + printf ("PerformWriteReadTest: ReadFile failed: " + "Error %d\n", GetLastError()); + + result = FALSE; + goto Cleanup; + + } else { + + if( bytesReturned != TestLength ) { + + printf("bytes Read is not test length! Read %d, " + "SB %d\n",bytesReturned, TestLength); + + // + // Note: Is this a Failure Case?? + // + result = FALSE; + goto Cleanup; + } + + printf ("%d Pattern Bytes Read successfully\n",bytesReturned); + } + + // + // Now compare + // + if( !VerifyPatternBuffer(ReadBuffer, TestLength) ) { + + printf("Verify failed\n"); + + result = FALSE; + goto Cleanup; + } + + printf("Pattern Verified successfully\n"); + +Cleanup: + + // + // Free WriteBuffer if non NULL. + // + if (WriteBuffer) { + free (WriteBuffer); + } + + // + // Free ReadBuffer if non NULL + // + if (ReadBuffer) { + free (ReadBuffer); + } + + return result; +} + + + +ULONG +AsyncIo( + PVOID ThreadParameter + ) +{ + HANDLE hDevice = INVALID_HANDLE_VALUE; + HANDLE hCompletionPort = NULL; + OVERLAPPED *pOvList = NULL; + PUCHAR buf = NULL; + ULONG numberOfBytesTransferred; + OVERLAPPED *completedOv; + ULONG_PTR i; + ULONG ioType = (ULONG)(ULONG_PTR)ThreadParameter; + ULONG_PTR key; + ULONG error; + BOOLEAN result = TRUE; + ULONG maxPendingRequests = NUM_ASYNCH_IO; + ULONG remainingRequestsToSend = 0; + ULONG remainingRequestsToReceive = 0; + + hDevice = CreateFile(G_DevicePath, + GENERIC_WRITE|GENERIC_READ, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + FILE_FLAG_OVERLAPPED, + NULL ); + + + if (hDevice == INVALID_HANDLE_VALUE) { + printf("Cannot open %s error %d\n", G_DevicePath, GetLastError()); + result = FALSE; + goto Error; + } + + hCompletionPort = CreateIoCompletionPort(hDevice, NULL, 1, 0); + if (hCompletionPort == NULL) { + printf("Cannot open completion port %d \n",GetLastError()); + result = FALSE; + goto Error; + } + + // + // We will only have NUM_ASYNCH_IO or G_AsyncIoLoopsNum pending at any + // time (whichever is less) + // + if (G_LimitedLoops == TRUE) { + remainingRequestsToReceive = G_AsyncIoLoopsNum; + if (G_AsyncIoLoopsNum > NUM_ASYNCH_IO) { + // + // After we send the initial NUM_ASYNCH_IO, we will have additional + // (G_AsyncIoLoopsNum - NUM_ASYNCH_IO) I/Os to send + // + maxPendingRequests = NUM_ASYNCH_IO; + remainingRequestsToSend = G_AsyncIoLoopsNum - NUM_ASYNCH_IO; + } + else { + maxPendingRequests = G_AsyncIoLoopsNum; + remainingRequestsToSend = 0; + + } + } + + pOvList = (OVERLAPPED *)malloc(maxPendingRequests * sizeof(OVERLAPPED)); + if (pOvList == NULL) { + printf("Cannot allocate overlapped array \n"); + result = FALSE; + goto Error; + } + + buf = (PUCHAR)malloc(maxPendingRequests * BUFFER_SIZE); + if (buf == NULL) { + printf("Cannot allocate buffer \n"); + result = FALSE; + goto Error; + } + + ZeroMemory(pOvList, maxPendingRequests * sizeof(OVERLAPPED)); + ZeroMemory(buf, maxPendingRequests * BUFFER_SIZE); + + // + // Issue asynch I/O + // + + for (i = 0; i < maxPendingRequests; i++) { + if (ioType == READER_TYPE) { + if ( ReadFile( hDevice, + buf + (i* BUFFER_SIZE), + BUFFER_SIZE, + NULL, + &pOvList[i]) == 0) { + + error = GetLastError(); + if (error != ERROR_IO_PENDING) { + printf(" %dth Read failed %d \n",i, GetLastError()); + result = FALSE; + goto Error; + } + } + + } else { + if ( WriteFile( hDevice, + buf + (i* BUFFER_SIZE), + BUFFER_SIZE, + NULL, + &pOvList[i]) == 0) { + error = GetLastError(); + if (error != ERROR_IO_PENDING) { + printf(" %dth Write failed %d \n",i, GetLastError()); + result = FALSE; + goto Error; + } + } + } + } + + // + // Wait for the I/Os to complete. If one completes then reissue the I/O + // + + WHILE (1) { + + if ( GetQueuedCompletionStatus(hCompletionPort, &numberOfBytesTransferred, &key, &completedOv, INFINITE) == 0) { + printf("GetQueuedCompletionStatus failed %d\n", GetLastError()); + result = FALSE; + goto Error; + } + + // + // Read successfully completed. If we're doing unlimited I/Os then Issue another one. + // + + if (ioType == READER_TYPE) { + + i = completedOv - pOvList; + printf("Number of bytes read by request number %d is %d\n", i, numberOfBytesTransferred); + + // + // If we're done with the I/Os, then exit + // + if (G_LimitedLoops == TRUE) { + if ((--remainingRequestsToReceive) == 0) { + break; + } + + if (remainingRequestsToSend == 0) { + continue; + } + else { + remainingRequestsToSend--; + } + } + + + if ( ReadFile( hDevice, + buf + (i * BUFFER_SIZE), + BUFFER_SIZE, + NULL, + completedOv) == 0) { + error = GetLastError(); + if (error != ERROR_IO_PENDING) { + printf("%dth Read failed %d \n", i, GetLastError()); + result = FALSE; + goto Error; + } + } + } else { + + i = completedOv - pOvList; + + printf("Number of bytes written by request number %d is %d\n", i, numberOfBytesTransferred); + + // + // If we're done with the I/Os, then exit + // + if (G_LimitedLoops == TRUE) { + if ((--remainingRequestsToReceive) == 0) { + break; + } + + if (remainingRequestsToSend == 0) { + continue; + } + else { + remainingRequestsToSend--; + } + } + + + if ( WriteFile( hDevice, + buf + (i * BUFFER_SIZE), + BUFFER_SIZE, + NULL, + completedOv) == 0) { + error = GetLastError(); + if (error != ERROR_IO_PENDING) { + + printf("%dth write failed %d \n", i, GetLastError()); + result = FALSE; + goto Error; + } + } + } + } + +Error: + if(hDevice != INVALID_HANDLE_VALUE) { + CloseHandle(hDevice); + } + + if(hCompletionPort) { + CloseHandle(hCompletionPort); + } + + if(buf) { + free(buf); + } + if(pOvList) { + free(pOvList); + } + + return (ULONG)result; + +} + + +BOOL +GetDevicePath( + IN LPGUID InterfaceGuid, + _Out_writes_(BufLen) PCHAR 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), + (LPSTR) &lpMsgBuf, + 0, + NULL + )) { + + printf("SetupDiEnumDeviceInterfaces failed: %s", (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), + (LPSTR) &lpMsgBuf, + 0, + NULL + ); + + SetupDiDestroyDeviceInfoList(HardwareDeviceInfo); + printf("Error in SetupDiGetDeviceInterfaceDetail: %s\n", (LPTSTR)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() +} + |
