--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/kerneltest/e32test/usb/t_usb_win/src/t_usb_wintests.cpp Mon Oct 19 15:55:17 2009 +0100
@@ -0,0 +1,2544 @@
+// Copyright (c) 2001-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of the License "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+// e32test\usb\t_usb_win\src\t_usb_wintests.cpp
+// Win32 USB test program performs I/O with a device running the
+// Symbian OS test program T_USB_DEVICE, using the generic USB device driver USBIO.
+// === Includes ===
+//
+//
+
+#include "stdafx.h"
+#include <process.h> /* _beginthread, _endthread */
+
+#include <sys/timeb.h>
+
+#include "usbio.h" // USBIO Dev Kit
+#include "usbiopipe.h" // ditto
+
+#include "t_usb_win.h"
+#include "t_usb_winDlg.h"
+
+#include "global.h"
+
+#include "UsbcvControl.h"
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#undef THIS_FILE
+static char THIS_FILE[] = __FILE__;
+#endif
+
+extern BOOL EjectVolume(char driveLetter);
+extern BOOL WaitDriveReady (char driveLetter);
+extern DWORD PerlScript(char * scriptName);
+
+// === Global Vars ===
+
+extern char gScriptFileName[];
+extern char gManufacturerName[];
+extern char gProductName[];
+extern char gSerialNumber[];
+extern char gLogfileName[];
+extern BOOL gVerboseMode;
+extern BOOL gKeepOpen;
+extern BOOL gAbort;
+extern int gTransferMode;
+extern CT_usb_winDlg* gMainWindow;
+extern FILE *logStream;
+extern int gReadWriteTimeOut;
+
+// Our own private GUID (also used in the .inf file as 'DriverUserInterfaceGuid')
+// {55606403-E62D-4707-9F56-40D48C6736D0}
+GUID gUsbioID =
+ {0x55606403, 0xe62d, 0x4707, {0x9f, 0x56, 0x40, 0xd4, 0x8c, 0x67, 0x36, 0xd0}};
+
+// Another provate GUID used in the AtenSwitch.inf file
+// {A6942415-49EE-4ef2-9CE8-D33E888EF133}
+const GUID gSwitchID =
+ {0xA6942415, 0x49EE, 0x4ef2, {0x9C, 0xE8, 0xD3, 0x3E, 0x88, 0x8E, 0xF1, 0x33}};
+
+// Handle for USB device list
+static HDEVINFO gDevList = NULL;
+
+// USBIO supported device
+CUsbIo gUsbDev;
+
+static int gDevNumber = -1;
+static UCHAR gEndpointMap [MAX_INTERFACES] [MAX_SETTINGS] [MAX_ENDPOINTS];
+static WORD gPacketSizeMap [MAX_INTERFACES] [MAX_SETTINGS] [MAX_ENDPOINTS];
+static UCHAR gAlternateSettings [MAX_INTERFACES];
+static bool gIsoEndpoint [MAX_INTERFACES] [MAX_SETTINGS] [MAX_ENDPOINTS];
+
+static USHORT vendorId = 0;
+static USHORT productId = 0;
+static USHORT productIdMS = 0;
+
+// endpoints
+
+// Read/write buffer
+static const DWORD KMaxTransferSize = 1024*1024;
+static const DWORD KPreambleLength = 8;
+
+static bool gFinishAllTests = false;
+
+static HANDLE gThreadStartedEvent;
+static HANDLE gThreadEndedEvents[MAX_THREADS];
+static HANDLE gThreadWaitEvents[MAX_THREADS];
+
+HANDLE gDeviceConnectEvent;
+HANDLE gDeviceDisconnectEvent;
+
+static __int64 gDeviceIdleCount = -1;
+static struct _timeb gHostTime;
+
+enum
+ {
+ EXml,
+ ELoop,
+ ECompare,
+ EReceiveOnly,
+ ETransmitOnly,
+ EFileReceive,
+ EFileTransmit,
+ EComment,
+ EConnect,
+ EDisconnect,
+ EWait,
+ EFail,
+ ESwitch,
+ EWaitConnect,
+ EWaitDisconnect,
+ EDo,
+ ERepeat,
+ EUsbcv,
+ EMassStorage,
+ EEject,
+ EPerl,
+ EWaitDrive,
+ };
+
+enum Ep0Requests
+ {
+ EStop = 0x1,
+ EVersion = 0x10,
+ ETestParam = 0x20,
+ ETestResult = 0x30,
+ ETestFail = 0x40,
+ ETestConnect = 0x50,
+ ETestDisconnect = 0x60,
+ ETestMassStorage = 0x70,
+ ETestIdleCounter = 0x80,
+ };
+
+struct TestParamHost
+ {
+ WORD displayRate;
+ DWORD outRate;
+ DWORD inRate;
+ BYTE index;
+ bool signalNextSettingThread;
+ };
+typedef struct TestParamHost TestParamHostType;
+
+struct TestParam
+ {
+ DWORD minSize;
+ DWORD maxSize;
+ DWORD packetNumber;
+ BYTE interfaceNumber;
+ BYTE alternateSetting;
+ BYTE outPipe;
+ BYTE inPipe;
+ WORD repeat;
+ WORD settingRepeat;
+ BYTE beforeIndex;
+ BYTE afterIndex;
+ TestParamHostType host;
+ TestParam ();
+ };
+typedef struct TestParam TestParamType;
+typedef TestParamType* TestParamPtr;
+
+// The version of T_USB we require (at least)
+static const DWORD KTusbVersionMajor = 1;
+static const DWORD KTusbVersionMinor = 0;
+static const DWORD KTusbVersionMicro = 1;
+
+static const DWORD KHostLogFileSize = 64*1024;
+
+#define ERR_SCRIPT_NAME 0xF0000001L
+
+// use a timeout for a WaitConnect to activate a scan for hardware changes
+#define CONNECT_RESCAN_TIMEOUT 300000
+#define RESCAN_APPNAME "C:\\Program Files\\devcon\\i386\\devcon.exe"
+#define RESCAN_CMDLINE " rescan"
+
+/////////////////////////////////////////////////////////////////////////////
+// global functions
+
+//
+// print to output window
+//
+// Note:
+// This is a global function that is called from any thread context.
+// It is not possible to call MFC objects from a thread context that is
+// created by using non-MFC means.
+// So we use SendMessage to access the OutputWindow.
+//
+void PrintOut(BOOL screenFlag, BOOL logFlag, BOOL timeFlag, const char *format, ...)
+{
+ if (screenFlag)
+ {
+ const int buffersize = 512;
+ va_list argptr;
+
+ char buffer[buffersize];
+
+ // print to buffer
+ va_start(argptr,format);
+ _vsnprintf(buffer,buffersize-1,format,argptr);
+ buffer[buffersize-1] = 0;
+
+ // with a time stamp and carriage return linefeed
+ if (timeFlag)
+ {
+ SYSTEMTIME localTime;
+
+ GetLocalTime(&localTime);
+
+ unsigned int len = strlen(buffer);
+
+ GetDateFormat(LOCALE_USER_DEFAULT,0,&localTime,"dd MMM yyyy",&buffer[len],buffersize-len);
+
+ len = strlen(buffer);
+
+ GetTimeFormat(LOCALE_USER_DEFAULT,0,&localTime," H:mm:ss"NL,&buffer[len],buffersize-len);
+ }
+
+ // send buffer to output window (synchronous behavior for buffer protection)
+ gMainWindow->SendMessage(WM_USER_PRINTOUT,0,(LPARAM)buffer); \
+
+ if (logStream && logFlag)
+ fputs(buffer,logStream);
+
+ va_end(argptr);
+ }
+}
+
+static void Delay(int milliseconds)
+ {
+ PRINT_IF_VERBOSE "* Short wait... ");
+ Sleep(milliseconds);
+ PRINT_IF_VERBOSE "done"NL);
+ }
+
+TestParam::TestParam()
+ {
+ minSize = 10;
+ maxSize = 100;
+ packetNumber = 0;
+ interfaceNumber = 0;
+ alternateSetting = 0;
+ outPipe = 2;
+ inPipe = 1;
+ repeat = 0;
+ settingRepeat = 0;
+ beforeIndex = 0;
+ host.displayRate = 100;
+ host.outRate = 0;
+ host.inRate = 0;
+ host.index = 0;
+ host.signalNextSettingThread = FALSE;
+ }
+//
+// Process a line from the test script file
+// returns the test type and sets up the test parameter structure
+//
+static int ParseTestLine(char* aLine,TestParamPtr aParam, USBIO_CLASS_OR_VENDOR_REQUEST* aRequest)
+ {
+ int testType = EComment;
+
+ struct testKey
+ {
+ int testId;
+ char testString[20];
+ };
+ typedef struct testKey testKeyType;
+ size_t tokenLength = 0;
+
+ testKeyType testKeyTable[] =
+ {
+ EXml,"Xml",
+ ELoop,"Loop",
+ ECompare,"Compare",
+ EReceiveOnly,"Stream",
+ EFileReceive,"File",
+ EConnect,"Connect",
+ EDisconnect,"Disconnect",
+ EWait,"Wait",
+ EFail,"Fail",
+ ESwitch,"Switch",
+ EWaitConnect,"WaitConnect",
+ EWaitDisconnect, "WaitDisconnect",
+ ERepeat, "Repeat",
+ EDo, "Do",
+ EUsbcv, "Usbcv",
+ EMassStorage, "MStore",
+ EEject, "Eject",
+ EPerl, "Perl",
+ EWaitDrive, "WaitDrive",
+ };
+
+ size_t numKeys = sizeof( testKeyTable ) / sizeof( testKeyType );
+
+ char delim[] = " ,\t\n";
+ char stringDelim[] = "\"";
+ char * token = strtok(aLine,delim);
+ if (token == NULL)
+ {
+ return testType;
+ }
+
+ tokenLength = strlen(token);
+
+ memset (aParam,0,sizeof(TestParamType));
+
+ // default display rate
+ aParam->host.displayRate = 100;
+
+ for (int i = 0; i < (int)numKeys; i++)
+ {
+ if (strnicmp (token,testKeyTable[i].testString,tokenLength) == 0)
+ {
+ testType = testKeyTable[i].testId;
+ break;
+ }
+ }
+
+
+ int paramCount = 0;
+ // now set up test type in request setup packet
+ switch (testType)
+ {
+ case EXml:
+ aRequest->Value = 'X';
+ paramCount = 2;
+ break;
+
+ case ELoop:
+ aRequest->Value = 'L';
+ break;
+
+ case ECompare:
+ aRequest->Value = 'C';
+ break;
+
+ case EReceiveOnly:
+ aRequest->Value = 'S';
+ paramCount = 1;
+ break;
+
+ case EFileReceive:
+ aRequest->Value = 'F';
+ paramCount = 1;
+ break;
+
+ case EComment:
+ return testType;
+ break;
+
+ case EConnect:
+ aRequest->Value = 'R';
+ break;
+
+ case EDisconnect:
+ aRequest->Value = 'D';
+ break;
+
+ case EWait:
+ aParam->minSize = INFINITE;
+ break;
+
+ case EWaitConnect:
+ aParam->minSize = INFINITE;
+ break;
+
+ case EWaitDisconnect:
+ aParam->minSize = INFINITE;
+ break;
+
+ case EFail:
+ case ESwitch:
+ case EDo:
+ case ERepeat:
+ case EUsbcv:
+ case EMassStorage:
+ case EEject:
+ case EPerl:
+ case EWaitDrive:
+ break;
+
+ }
+
+ if (testType == EPerl)
+ {
+ // a space at the beginning of the line
+ aLine[0] = ' ';
+ strcpy(&aLine[1],&aLine[tokenLength+1]);
+ // strip off carriage return or line feed
+ if (iscntrl(aLine[strlen(aLine)-1]))
+ {
+ aLine[strlen(aLine)-1] = '\0';
+ if (iscntrl(aLine[strlen(aLine)-1]))
+ aLine[strlen(aLine)-1] = '\0';
+ }
+ return testType;
+ }
+
+ token = strtok(NULL,delim);
+ if (testType == EEject || testType == EWaitDrive)
+ {
+ strcpy(aLine,token);
+
+ return testType;
+ }
+
+ if (testType == EFileReceive)
+ {
+ // The first parameter is the drive letter on the device to use
+ if (token != NULL)
+ aParam->minSize = token[0];
+ else
+ aParam->minSize = 'D';
+
+ token = strtok(NULL,delim);
+ }
+
+ while (token != NULL)
+ {
+ unsigned long ulParam = strtoul (token,NULL,0);
+ switch (paramCount)
+ {
+ case 0 :
+ aParam->minSize = (DWORD)ulParam;
+ break;
+
+ case 1 :
+ aParam->maxSize = (DWORD)ulParam;
+ break;
+
+ case 2 :
+ aParam->packetNumber = (DWORD)ulParam;
+ break;
+
+ case 3 :
+ aParam->interfaceNumber = (BYTE)ulParam;
+ break;
+
+ case 4:
+ aParam->alternateSetting = (BYTE)ulParam;
+ // skip outpipe for Xml IN
+ if (testType == EXml)
+ {
+ paramCount++;
+ }
+ break;
+
+ case 5:
+ aParam->outPipe = (BYTE)ulParam;
+ break;
+
+ case 6 :
+ aParam->inPipe = (BYTE)ulParam;
+ if (aParam->inPipe > 31)
+ {
+ if (testType == EReceiveOnly)
+ testType = ETransmitOnly;
+ if (testType == EFileReceive)
+ testType = EFileTransmit;
+ }
+ break;
+
+ case 7 :
+ aParam->repeat = (WORD)ulParam;
+ break;
+
+ case 8 :
+ aParam->host.displayRate = (WORD)ulParam;
+ break;
+
+ case 9 :
+ aParam->settingRepeat = (WORD)ulParam;
+ break;
+
+ case 10 :
+ aParam->beforeIndex = (BYTE)ulParam;
+ break;
+
+ case 11 :
+ aParam->afterIndex = (BYTE)ulParam;
+ break;
+
+ case 12 :
+ aParam->host.outRate = (DWORD)ulParam;
+ break;
+
+ case 13 :
+ aParam->host.inRate = (DWORD)ulParam;
+ break;
+ }
+
+ paramCount++;
+ token = strtok(NULL,delim);
+ }
+
+ return testType;
+ }
+
+static void ShowErrorText (DWORD errCode)
+ {
+ char textBuf[80];
+
+ CUsbIo::ErrorText(textBuf,80,errCode);
+
+ PRINT_ALWAYS "%s"NL,textBuf);
+
+ gAbort = true;
+ }
+
+static DWORD OpenUsbDevice()
+ {
+ DWORD dwRC;
+ USB_DEVICE_DESCRIPTOR DevDesc;
+ // buffer used to store string descriptor
+ unsigned char StrDescBuffer[sizeof(USB_STRING_DESCRIPTOR)+512];
+ // pointer to USB string descriptor
+ USB_STRING_DESCRIPTOR* StrDesc;
+ DWORD StrDescSize;
+ WCHAR * WideString;
+ // helper variables
+ bool deviceFound = false;
+ bool moreDevices = true;
+
+ if (gDevList)
+ {
+ CUsbIo::DestroyDeviceList(gDevList);
+ gDevList = NULL;
+ gDevNumber = -1;
+ gUsbDev.Close();
+ }
+
+
+ // Enumerate attached USB devices supported by USBIO
+ gDevList = CUsbIo::CreateDeviceList(&gUsbioID);
+
+
+ if ( gDevList==NULL )
+ {
+ PRINT_ALWAYS "Unable to build a device list!"NL);
+ return USBIO_ERR_FAILED;
+ }
+
+ // open and query each device (max. 127)
+ for ( int i=0; i < 127 && !deviceFound && moreDevices; i++ )
+ {
+ StrDesc = NULL;
+
+ // open the device, using the global CUsbIo instance
+ dwRC = gUsbDev.Open(i,gDevList,&gUsbioID);
+ if ( dwRC != USBIO_ERR_SUCCESS )
+ {
+ // no more devices, or error leave loop
+ moreDevices = false;
+ break;
+ }
+
+ // we have found a device, query the device descriptor
+ dwRC = gUsbDev.GetDeviceDescriptor(&DevDesc);
+ if ( dwRC == USBIO_ERR_SUCCESS )
+ {
+ deviceFound = true;
+ // Check manufacturer string
+ if (strlen(gManufacturerName))
+ {
+ // Does the device have a manufacturer?
+ if ( DevDesc.iManufacturer != NULL )
+ {
+ WideString = new(WCHAR [strlen(gManufacturerName)+1]);
+ for (unsigned int j = 0; j < strlen(gManufacturerName); j++)
+ {
+ WideString[j] = (WCHAR)gManufacturerName[j];
+ }
+ WideString[strlen(gManufacturerName)] = (WCHAR)0;
+ // query the corresponding string descriptor
+ StrDesc = (USB_STRING_DESCRIPTOR*)StrDescBuffer;
+ StrDescSize = sizeof(StrDescBuffer);
+ dwRC = gUsbDev.GetStringDescriptor(StrDesc,StrDescSize,DevDesc.iManufacturer);
+ if ( dwRC == USBIO_ERR_SUCCESS )
+ {
+ size_t stringSize = wcslen (WideString);
+ if (stringSize != (size_t)(StrDesc->bLength - 2)/2)
+ deviceFound = false;
+ else
+ {
+ if (wcsncmp (WideString,StrDesc->bString,stringSize) != 0)
+ deviceFound = false;
+ }
+ }
+ else
+ {
+ deviceFound = false;
+ }
+ delete WideString;
+ }
+ else
+ {
+ deviceFound = false;
+ }
+ }
+
+ // check product string
+ if (strlen(gProductName))
+ {
+ // Does the device have a manufacturer?
+ if ( DevDesc.iProduct !=0 )
+ {
+ WideString = new(WCHAR [strlen(gProductName)+1]);
+ for (unsigned int j = 0; j < strlen(gProductName); j++)
+ {
+ WideString[j] = (WCHAR)gProductName[j];
+ }
+ WideString[strlen(gProductName)] = (WCHAR)0;
+ // query the corresponding string descriptor
+ StrDesc = (USB_STRING_DESCRIPTOR*)StrDescBuffer;
+ StrDescSize = sizeof(StrDescBuffer);
+ dwRC = gUsbDev.GetStringDescriptor(StrDesc,StrDescSize,DevDesc.iProduct);
+ if ( dwRC == USBIO_ERR_SUCCESS )
+ {
+ size_t stringSize = wcslen (WideString);
+ if (stringSize != (size_t)(StrDesc->bLength - 2)/2)
+ deviceFound = false;
+ else
+ {
+ if (wcsncmp (WideString,StrDesc->bString,stringSize) != 0)
+ deviceFound = false;
+ }
+ }
+ else
+ {
+ deviceFound = false;
+ }
+ delete WideString;
+ }
+ else
+ {
+ deviceFound = false;
+ }
+ }
+
+ // check serial number string
+ if (strlen(gSerialNumber))
+ {
+ // Does the device have a serial number?
+ if ( DevDesc.iSerialNumber !=0 )
+ {
+ WideString = new(WCHAR [strlen(gSerialNumber)+1]);
+ for (unsigned int j = 0; j < strlen(gSerialNumber); j++)
+ {
+ WideString[j] = (WCHAR)gSerialNumber[j];
+ }
+ WideString[strlen(gSerialNumber)] = (WCHAR)0;
+ // query the corresponding string descriptor
+ StrDesc = (USB_STRING_DESCRIPTOR*)StrDescBuffer;
+ StrDescSize = sizeof(StrDescBuffer);
+ dwRC = gUsbDev.GetStringDescriptor(StrDesc,StrDescSize,DevDesc.iSerialNumber);
+ if ( dwRC == USBIO_ERR_SUCCESS )
+ {
+ size_t stringSize = wcslen (WideString);
+ if (stringSize != (size_t)(StrDesc->bLength - 2)/2)
+ deviceFound = false;
+ else
+ {
+ if (wcsncmp (WideString,StrDesc->bString,stringSize) != 0)
+ deviceFound = false;
+ }
+ }
+ else
+ {
+ deviceFound = false;
+ }
+ delete WideString;
+ }
+ else
+ {
+ deviceFound = false;
+ }
+ }
+ if (deviceFound)
+ {
+ gDevNumber = i;
+ }
+ else
+ {
+ // close device
+ gUsbDev.Close();
+ }
+ }
+ else
+ {
+ // close device
+ gUsbDev.Close();
+ }
+ } // for
+
+
+ if (dwRC == USBIO_ERR_VERSION_MISMATCH)
+ {
+ PRINT_ALWAYS "\n* Error: \"The API version reported by the TUSBWIN driver"NL \
+ "* does not match the expected version.\""NL);
+ PRINT_ALWAYS "* The driver will need to be updated as follows:"NL);
+ PRINT_ALWAYS "* 1. Connect the device to the PC & start T_USB,"NL \
+ "* then find the USB device in the Windows Device Manager"NL \
+ "* ('Control Panel'->'System'->'Hardware'->'Device Manager')."NL \
+ "* Right click on the device name and choose 'Uninstall...'."NL);
+ PRINT_ALWAYS "* 2. In c:\\winnt\\inf\\, find (by searching for \"Symbian\") and"NL \
+ "* delete the *.INF file that was used to install the existing"NL \
+ "* version of TUSBWIN.SYS. Make sure to also delete the"NL \
+ "* precompiled version of that file (<samename>.PNF)."NL);
+ PRINT_ALWAYS "* 3. In c:\\winnt\\system32\\drivers\\, delete the file TUSBWIN.SYS."NL);
+ PRINT_ALWAYS "* Then unplug & reconnect the USB device and, when prompted, install"NL \
+ "* the new TUSBWIN.SYS driver using the .INF file from this distribution."NL \
+ "* (All files can be found under e32test\\usb\t_usb_win\\bin_distribution\\.)"NL);
+ }
+
+ return dwRC;
+ }
+
+static DWORD OpenSwitchDevice()
+ {
+ DWORD dwRC;
+
+ if (gDevList)
+ {
+ CUsbIo::DestroyDeviceList(gDevList);
+ gDevList = NULL;
+ gUsbDev.Close();
+ }
+
+ // Enumerate attached USB devices supported by USBIO
+ gDevList = CUsbIo::CreateDeviceList(&gSwitchID);
+
+ if (gDevList)
+ {
+ // Open first device in list
+ dwRC = gUsbDev.Open(0, gDevList, &gSwitchID);
+
+ PRINT_IF_VERBOSE "\nCUsbIo::Open returned <0x%X>"NL, dwRC);
+ }
+ else
+ {
+ dwRC = USBIO_ERR_DEVICE_NOT_FOUND;
+ }
+
+ return dwRC;
+ }
+
+static void CloseUsbDevice()
+ {
+ // Close the device
+ gUsbDev.Close();
+ PRINT_IF_VERBOSE "CUsbIo::Close called"NL);
+ }
+
+static DWORD GetDeviceDescriptor()
+ {
+ DWORD dwRC;
+ USB_DEVICE_DESCRIPTOR DeviceDescriptor;
+
+ memset(&DeviceDescriptor, 0, sizeof(USB_DEVICE_DESCRIPTOR));
+
+ // Get device descriptor
+ dwRC = gUsbDev.GetDeviceDescriptor(&DeviceDescriptor);
+ PRINT_IF_VERBOSE "CUsbIo::GetDeviceDescriptor returned <0x%X>"NL, dwRC);
+
+ if (dwRC == USBIO_ERR_SUCCESS)
+ {
+ vendorId = DeviceDescriptor.idVendor;
+ productId = DeviceDescriptor.idProduct;
+ }
+
+ if (gVerboseMode && (dwRC == USBIO_ERR_SUCCESS))
+ {
+ PRINT_ALWAYS "\nDEVICE DESCRIPTOR:"NL
+ "bLength = <%u>"NL
+ "bDescriptorType = <%u>"NL
+ "bcdUSB = <%u>"NL
+ "bDeviceClass = <%u>"NL
+ "bDeviceSubClass = <%u>"NL
+ "bDeviceProtocol = <%u>"NL
+ "bMaxPacketSize0 = <%u>"NL
+ "idVendor = <%u>"NL
+ "idProduct = <%u>"NL
+ "bcdDevice = <%u>"NL
+ "iManufacturer = <%u>"NL
+ "iProduct = <%u>"NL
+ "iSerialNumber = <%u>"NL
+ "bNumConfigurations = <%u>\n"NL,
+ DeviceDescriptor.bLength,
+ DeviceDescriptor.bDescriptorType,
+ DeviceDescriptor.bcdUSB,
+ DeviceDescriptor.bDeviceClass,
+ DeviceDescriptor.bDeviceSubClass,
+ DeviceDescriptor.bDeviceProtocol,
+ DeviceDescriptor.bMaxPacketSize0,
+ DeviceDescriptor.idVendor,
+ DeviceDescriptor.idProduct,
+ DeviceDescriptor.bcdDevice,
+ DeviceDescriptor.iManufacturer,
+ DeviceDescriptor.iProduct,
+ DeviceDescriptor.iSerialNumber,
+ DeviceDescriptor.bNumConfigurations);
+ }
+
+ if (gVerboseMode)
+ {
+ USBIO_BANDWIDTH_INFO bwInfo;
+
+ // Get bandwidth available
+ dwRC = gUsbDev.GetBandwidthInfo (&bwInfo);
+ if (dwRC == USBIO_ERR_SUCCESS)
+ {
+ PRINT_ALWAYS "Bandwidth total %d consumed %d"NL,bwInfo.TotalBandwidth,bwInfo.ConsumedBandwidth);
+ }
+ }
+
+ return dwRC;
+ }
+
+
+static DWORD GetConfigurationDescriptor()
+ {
+ DWORD dwRC;
+ int ifListIndex = 0;
+
+ CHAR szBuffer[MAX_DESCRIPTOR_BUFFER_SIZE] = "";
+ USB_CONFIGURATION_DESCRIPTOR* pConfigDescriptor = NULL;
+ USB_INTERFACE_DESCRIPTOR* pInterfaceDescriptor = NULL;
+ USB_ENDPOINT_DESCRIPTOR* pEndpointDescriptor = NULL;
+
+ DWORD dwByteCount = MAX_DESCRIPTOR_BUFFER_SIZE;
+
+ memset(szBuffer, 0, sizeof(szBuffer));
+
+ memset (gEndpointMap, 0, sizeof(gEndpointMap));
+ memset (gPacketSizeMap, 0, sizeof(gPacketSizeMap));
+
+ // force a set interface
+ memset (gAlternateSettings, 0, sizeof(gAlternateSettings));
+
+ // Get first configuration descriptor
+ dwRC = gUsbDev.GetConfigurationDescriptor((USB_CONFIGURATION_DESCRIPTOR*) szBuffer,
+ dwByteCount, 0);
+ PRINT_IF_VERBOSE "CUsbIo::GetConfigurationDescriptor returned <0x%X>"NL, dwRC);
+
+ USBIO_SET_CONFIGURATION SetConfig;
+
+ memset(&SetConfig, 0, sizeof(USBIO_SET_CONFIGURATION));
+
+ // Set the first configuration as active
+ SetConfig.ConfigurationIndex = 0;
+
+ if (dwRC == USBIO_ERR_SUCCESS)
+ {
+ USB_COMMON_DESCRIPTOR* Desc;
+ ULONG rl = dwByteCount;
+ ULONG ulDescLength = 0;
+ CHAR* data = szBuffer;
+ int interfaceNumber = 0;
+ int alternateSetting = 0;
+ int endpointIndex = 0;
+
+ while (rl > 0)
+ {
+ Desc = (USB_COMMON_DESCRIPTOR*) data;
+ ulDescLength = Desc->bLength;
+ if ((ulDescLength > rl) || (ulDescLength == 0))
+ {
+ PRINT_ALWAYS "Length remaining too short!"NL);
+ rl = 0;
+ }
+ else
+ {
+ switch (Desc->bDescriptorType)
+ {
+ case USB_CONFIGURATION_DESCRIPTOR_TYPE:
+ pConfigDescriptor =
+ (USB_CONFIGURATION_DESCRIPTOR*) data;
+ PRINT_IF_VERBOSE "\nCONFIGURATION DESCRIPTOR:"NL
+ "bLength = <%u>"NL
+ "bDescriptorType = <%u>"NL
+ "wTotalLength = <%u>"NL
+ "bNumInterfaces = <%u>"NL
+ "bConfigurationValue = <%u>"NL
+ "iConfiguration = <%u>"NL
+ "bmAttributes = <%u>"NL
+ "MaxPower = <%u>"NL,
+ pConfigDescriptor->bLength,
+ pConfigDescriptor->bDescriptorType,
+ pConfigDescriptor->wTotalLength,
+ pConfigDescriptor->bNumInterfaces,
+ pConfigDescriptor->bConfigurationValue,
+ pConfigDescriptor->iConfiguration,
+ pConfigDescriptor->bmAttributes,
+ pConfigDescriptor->MaxPower);
+ SetConfig.NbOfInterfaces = pConfigDescriptor->bNumInterfaces;
+ break;
+
+ case USB_INTERFACE_DESCRIPTOR_TYPE:
+ pInterfaceDescriptor = (USB_INTERFACE_DESCRIPTOR*) data;
+ interfaceNumber = pInterfaceDescriptor->bInterfaceNumber;
+ alternateSetting = pInterfaceDescriptor->bAlternateSetting;
+ endpointIndex = 0;
+ PRINT_IF_VERBOSE "\nINTERFACE DESCRIPTOR: "NL
+ "bLength = <%u>"NL
+ "bDescriptorType = <%u>"NL
+ "bInterfaceNumber = <%u>"NL
+ "bAlternateSetting = <%u>"NL
+ "bNumEndpoints = <%u>"NL
+ "bInterfaceClass = <%u>"NL
+ "bInterfaceSubClass = <%u>"NL
+ "bInterfaceProtocol = <%u>"NL
+ "iInterface = <%u>"NL,
+ pInterfaceDescriptor->bLength,
+ pInterfaceDescriptor->bDescriptorType,
+ pInterfaceDescriptor->bInterfaceNumber,
+ pInterfaceDescriptor->bAlternateSetting,
+ pInterfaceDescriptor->bNumEndpoints,
+ pInterfaceDescriptor->bInterfaceClass,
+ pInterfaceDescriptor->bInterfaceSubClass,
+ pInterfaceDescriptor->bInterfaceProtocol,
+ pInterfaceDescriptor->iInterface);
+ if (alternateSetting == 0)
+ {
+ SetConfig.InterfaceList[ifListIndex].InterfaceIndex = interfaceNumber;
+ SetConfig.InterfaceList[ifListIndex++].MaximumTransferSize = KMaxTransferSize;
+ }
+ break;
+
+ case USB_ENDPOINT_DESCRIPTOR_TYPE:
+ pEndpointDescriptor =
+ (USB_ENDPOINT_DESCRIPTOR*) data;
+ gEndpointMap[interfaceNumber] [alternateSetting] [endpointIndex] = pEndpointDescriptor->bEndpointAddress;
+ gPacketSizeMap[interfaceNumber] [alternateSetting] [endpointIndex++] = pEndpointDescriptor->wMaxPacketSize;
+ PRINT_IF_VERBOSE "\nENDPOINT DESCRIPTOR: "NL
+ "bLength = <%u>"NL
+ "bDescriptorType = <%u>"NL
+ "bEndpointAddress = <%X>"NL
+ "bmAttributes = <%u>"NL
+ "wMaxPacketSize = <%u>"NL
+ "bInterval = <%u>"NL,
+ pEndpointDescriptor->bLength,
+ pEndpointDescriptor->bDescriptorType,
+ pEndpointDescriptor->bEndpointAddress,
+ pEndpointDescriptor->bmAttributes,
+ pEndpointDescriptor->wMaxPacketSize,
+ pEndpointDescriptor->bInterval);
+ break;
+ default:
+ break;
+ }
+ }
+ data += ulDescLength;
+ rl -= ulDescLength;
+ }
+ }
+
+ dwRC = gUsbDev.SetConfiguration(&SetConfig);
+ PRINT_IF_VERBOSE "CUsbIo::SetConfiguration returned <0x%X>"NL, dwRC);
+
+
+ PRINT_IF_VERBOSE ""NL);
+
+ return dwRC;
+ }
+
+
+static DWORD GetStringDescriptor()
+ {
+ DWORD dwRC;
+
+ CHAR szBuffer[MAX_DESCRIPTOR_BUFFER_SIZE] = "";
+ USB_STRING_DESCRIPTOR* pStringDescriptor = NULL;
+ DWORD dwByteCount = MAX_DESCRIPTOR_BUFFER_SIZE;
+
+ memset(szBuffer, 0, sizeof(szBuffer));
+
+ // Get string descriptor
+ dwRC = gUsbDev.GetStringDescriptor((USB_STRING_DESCRIPTOR*) szBuffer,
+ dwByteCount, 1, 0);
+ PRINT_IF_VERBOSE "CUsbIo::GetStringDescriptor returned <0x%X>"NL, dwRC);
+
+ if (dwRC == USBIO_ERR_SUCCESS)
+ {
+ pStringDescriptor = (USB_STRING_DESCRIPTOR*) szBuffer;
+ PRINT_IF_VERBOSE "\nSTRING DESCRIPTOR:"NL
+ "bLength = <%u>"NL
+ "bDescriptorType = <%u>"NL
+ "bString = <", // output continues below!
+ pStringDescriptor->bLength,
+ pStringDescriptor->bDescriptorType);
+ INT i = 0;
+ CHAR* Ptr = szBuffer;
+ for (i = 2, Ptr += 2;
+ i < pStringDescriptor->bLength;
+ i += 2, Ptr += 2)
+ {
+ PRINT_IF_VERBOSE "%c", *Ptr);
+ }
+ PRINT_IF_VERBOSE ">\n"NL);
+ }
+
+ return dwRC;
+ }
+
+
+static DWORD GetConfigurationInfo()
+ {
+ DWORD dwRC;
+
+ USBIO_CONFIGURATION_INFO ConfigInfo;
+ USHORT i = 0;
+
+ memset(&ConfigInfo, 0, sizeof(USBIO_CONFIGURATION_INFO));
+
+ dwRC = gUsbDev.GetConfigurationInfo(&ConfigInfo);
+ PRINT_IF_VERBOSE "CUsbIo::GetConfigurationInfo returned <0x%X>"NL, dwRC);
+
+ if (dwRC == USBIO_ERR_SUCCESS)
+ {
+ PRINT_IF_VERBOSE "\nCONFIGURATION INFO:"NL
+ "NbOfInterfaces = <%lu>"NL
+ "NbOfPipes = <%lu>"NL,
+ ConfigInfo.NbOfInterfaces,
+ ConfigInfo.NbOfPipes);
+ for (i = 0; i < ConfigInfo.NbOfInterfaces; i++)
+ {
+ PRINT_IF_VERBOSE "\nINTERFACE <%u>:"NL, i + 1);
+ PRINT_IF_VERBOSE "InterfaceNumber = <%u>"NL
+ "AlternateSetting = <%u>"NL
+ "Class = <%u>"NL
+ "SubClass = <%u>"NL
+ "Protocol = <%u>"NL
+ "NumberOfPipes = <%u>"NL
+ "reserved1 = <%u>"NL
+ "reserved2 = <%u>"NL,
+ ConfigInfo.InterfaceInfo[i].InterfaceNumber,
+ ConfigInfo.InterfaceInfo[i].AlternateSetting,
+ ConfigInfo.InterfaceInfo[i].Class,
+ ConfigInfo.InterfaceInfo[i].SubClass,
+ ConfigInfo.InterfaceInfo[i].Protocol,
+ ConfigInfo.InterfaceInfo[i].NumberOfPipes,
+ ConfigInfo.InterfaceInfo[i].reserved1,
+ ConfigInfo.InterfaceInfo[i].reserved2);
+ }
+ for (i = 0; i < ConfigInfo.NbOfPipes; i++)
+ {
+ PRINT_IF_VERBOSE ""NL);
+ PRINT_IF_VERBOSE "PIPE <%u>"NL, i + 1);
+ PRINT_IF_VERBOSE "PipeType = <%d>"NL
+ "MaximumTransferSize = <%lu>"NL
+ "MaximumPacketSize = <%u>"NL
+ "EndpointAddress = <%X>"NL
+ "Interval = <%u>"NL
+ "InterfaceNumber = <%u>"NL
+ "reserved1 = <%u>"NL
+ "reserved2 = <%u>"NL
+ "reserved3 = <%u>"NL,
+ ConfigInfo.PipeInfo[i].PipeType,
+ ConfigInfo.PipeInfo[i].MaximumTransferSize,
+ ConfigInfo.PipeInfo[i].MaximumPacketSize,
+ ConfigInfo.PipeInfo[i].EndpointAddress,
+ ConfigInfo.PipeInfo[i].Interval,
+ ConfigInfo.PipeInfo[i].InterfaceNumber,
+ ConfigInfo.PipeInfo[i].reserved1,
+ ConfigInfo.PipeInfo[i].reserved2,
+ ConfigInfo.PipeInfo[i].reserved3);
+ }
+ }
+ PRINT_IF_VERBOSE ""NL);
+
+ return dwRC;
+ }
+
+
+static DWORD OpenPipes(CUsbIoPipe * inPipePtr, CUsbIoPipe * outPipePtr, TestParamPtr tpPtr)
+ {
+ DWORD dwRC = USBIO_ERR_SUCCESS;
+ UCHAR epAddress;
+
+ // Create the bulk OUT pipe
+ if (outPipePtr)
+ {
+ epAddress = gEndpointMap[tpPtr->interfaceNumber][tpPtr->alternateSetting][tpPtr->outPipe-1];
+ dwRC = outPipePtr->Bind(gDevNumber, epAddress, gDevList, &gUsbioID);
+
+ PRINT_IF_VERBOSE "CUsbIoPipe::Bind OUT address <0x%X> returned <0x%X>"NL, epAddress,dwRC);
+
+ if (dwRC == USBIO_ERR_SUCCESS)
+ {
+ // Set up for time statistics on OUT pipe
+ dwRC = outPipePtr->SetupPipeStatistics(1000L);
+ PRINT_IF_VERBOSE "CUsbIoPipe::SetupPipeStatistics OUT returned <0x%X>"NL, dwRC);
+ }
+ else
+ ShowErrorText(dwRC);
+ }
+
+ if (inPipePtr && dwRC == USBIO_ERR_SUCCESS)
+ {
+ // Create the IN pipe
+ epAddress = gEndpointMap[tpPtr->interfaceNumber][tpPtr->alternateSetting][tpPtr->inPipe-1];
+ dwRC = inPipePtr->Bind(gDevNumber, epAddress, gDevList, &gUsbioID);
+
+ PRINT_IF_VERBOSE "CUsbIoPipe::Bind IN address <0x%X> returned <0x%X>"NL, epAddress,dwRC);
+
+ if (dwRC == USBIO_ERR_SUCCESS)
+ {
+ // Set up for time statistics on IN pipe
+ dwRC = inPipePtr->SetupPipeStatistics(1000L);
+ PRINT_IF_VERBOSE "CUsbIoPipe::SetupPipeStatistics IN returned <0x%X>"NL, dwRC);
+ }
+ else
+ ShowErrorText(dwRC);
+
+ }
+
+ PRINT_IF_VERBOSE ""NL);
+
+ return dwRC;
+ }
+
+
+static DWORD ClosePipes(CUsbIoPipe * inPipePtr, CUsbIoPipe * outPipePtr)
+ {
+ DWORD dwRC = USBIO_ERR_SUCCESS;
+
+ // Close down the OUT pipe
+ if (outPipePtr)
+ {
+ dwRC = outPipePtr->Unbind();
+ PRINT_IF_VERBOSE "CUsbIoPipe::Unbind OUT returned <0x%X>"NL, dwRC);
+ }
+
+ if (inPipePtr && dwRC == USBIO_ERR_SUCCESS)
+ {
+ // Close down the IN pipe
+ dwRC = inPipePtr->Unbind();
+ PRINT_IF_VERBOSE "CUsbIoPipe::Unbind IN returned <0x%X>"NL, dwRC);
+ }
+
+ return dwRC;
+ }
+
+static void SendLogFile()
+ {
+ logStream = fopen (gLogfileName, "rb");
+ if (logStream == NULL)
+ {
+ return;
+ }
+
+ char logBuffer[KHostLogFileSize];
+ CUsbIoPipe* outPipePtr = new CUsbIoPipe();
+ CUsbIoBuf bufPtr((VOID*) logBuffer, KHostLogFileSize); // the data buffer
+ int bytesRead;
+
+ DWORD dwRC = USBIO_ERR_SUCCESS;
+ UCHAR epAddress;
+
+ // Create the bulk OUT pipe
+ epAddress = gEndpointMap[0][0][1];
+ dwRC = outPipePtr->Bind(gDevNumber, epAddress, gDevList, &gUsbioID);
+ if (dwRC != USBIO_ERR_SUCCESS)
+ {
+ return;
+ }
+
+ bytesRead = fread ( logBuffer, sizeof(char), KHostLogFileSize, logStream );
+ if (bytesRead > 0)
+ {
+ bufPtr.NumberOfBytesToTransfer = bytesRead;
+ outPipePtr->Write(&bufPtr);
+ dwRC = outPipePtr->WaitForCompletion(&bufPtr, gReadWriteTimeOut);
+ if (dwRC != USBIO_ERR_SUCCESS)
+ {
+ return;
+ }
+ }
+
+
+ bufPtr.NumberOfBytesToTransfer = 0;
+ outPipePtr->Write(&bufPtr);
+ dwRC = outPipePtr->WaitForCompletion(&bufPtr, gReadWriteTimeOut);
+
+ return;
+ }
+
+static DWORD ReceiveCounter()
+ {
+ DWORD dwRC = USBIO_ERR_SUCCESS;
+
+ DWORD bytes_read = sizeof(__int64);
+
+ // Here we (hope to) read an 8 byte packet containing a counter value.
+ PRINT_NOLOG "* Waiting for T_USB counter packet to arrive...");
+
+ __int64 counter;
+
+ USBIO_CLASS_OR_VENDOR_REQUEST request;
+ request.Flags = USBIO_SHORT_TRANSFER_OK;
+ request.Type = RequestTypeClass;
+ request.Recipient = RecipientDevice;
+ request.RequestTypeReservedBits = 0;
+ request.Request = ETestIdleCounter;
+ request.Value = gDeviceIdleCount < 0 ? 0 : 1;
+ request.Index = 0;
+
+
+ dwRC = gUsbDev.ClassOrVendorInRequest(&counter,bytes_read,&request);
+
+ PRINT_NOLOG " done."NL);
+ if (dwRC != USBIO_ERR_SUCCESS)
+ {
+ PRINT_ALWAYS "\n* Error: CUsbIoPipe::Read (version)");
+ ShowErrorText(dwRC);
+ return dwRC;
+ }
+
+ if (gDeviceIdleCount < 0)
+ {
+ // Initialise counter
+ gDeviceIdleCount = counter;
+ _ftime(&gHostTime);
+ PRINT_TIME " * Start Device Idle Counter"NL);
+ }
+ else
+ {
+ // if the counter is zero then the tests havent completed on the device
+ while (counter < gDeviceIdleCount)
+ {
+ Delay(WAIT_TEST_COMPLETE);
+ dwRC = gUsbDev.ClassOrVendorInRequest(&counter,bytes_read,&request);
+ if (dwRC != USBIO_ERR_SUCCESS)
+ {
+ PRINT_ALWAYS "\n* Error: CUsbIoPipe::Read (version)");
+ ShowErrorText(dwRC);
+ return dwRC;
+ }
+ }
+ __int64 diff = counter - gDeviceIdleCount;
+ struct _timeb tmp = gHostTime;
+ _ftime(&gHostTime);
+ gDeviceIdleCount = counter;
+ int ms = (gHostTime.time - tmp.time) * 1000 + gHostTime.millitm - tmp.millitm;
+ PRINT_TIME " * Stop Device Idle Counter: %I64d increments in %dms (%dinc/ms)"NL,
+ diff, ms, diff / ms);
+ }
+
+ return dwRC;
+ }
+
+static DWORD ReceiveVersion()
+ {
+ DWORD dwRC = USBIO_ERR_SUCCESS;
+
+ // Here we (hope to) read an 8 byte packet containing the T_USB version.
+ PRINT_NOLOG "* Waiting for T_USB version packet to arrive...");
+
+ BYTE versionData[VERSION_DATAIN_SIZE];
+
+ // The first 3 bytes are interpreted as a version.
+ DWORD bytes_read = VERSION_DATAIN_SIZE;
+
+ USBIO_CLASS_OR_VENDOR_REQUEST request;
+ request.Flags = USBIO_SHORT_TRANSFER_OK;
+ request.Type = RequestTypeClass;
+ request.Recipient = RecipientDevice;
+ request.RequestTypeReservedBits = 0;
+ request.Request = EVersion;
+ request.Value = 0;
+ request.Index = 0;
+
+
+ dwRC = gUsbDev.ClassOrVendorInRequest(&versionData[0],bytes_read,&request);
+
+ PRINT_NOLOG " done."NL);
+ if (dwRC != USBIO_ERR_SUCCESS)
+ {
+ PRINT_ALWAYS "\n* Error: CUsbIoPipe::Read (version)");
+ ShowErrorText(dwRC);
+ return dwRC;
+ }
+ if (versionData[0] < KTusbVersionMajor ||
+ (versionData[0] == KTusbVersionMajor && versionData[1] < KTusbVersionMinor) ||
+ (versionData[0] == KTusbVersionMajor && versionData[1] == KTusbVersionMinor && versionData[2] < KTusbVersionMicro))
+ {
+ PRINT_ALWAYS "* Inadequate version of T_USB: %d.%d.%d (we need at least %d.%d.%d)"NL,
+ versionData[0],versionData[1],versionData[2],KTusbVersionMajor,KTusbVersionMinor,KTusbVersionMicro);
+ dwRC = USBIO_ERR_FAILED;
+ return dwRC;
+ }
+ PRINT_NOLOG "* Suitable version of T_USB_DEVICE found: %d.%d.%d."NL, versionData[0],versionData[1],versionData[2]);
+
+ char * scriptFilePtr;
+ scriptFilePtr = strstr((char *)&versionData[3],"/script=");
+
+ if (scriptFilePtr != NULL)
+ {
+ * scriptFilePtr = '\0';
+ scriptFilePtr += 8;
+ PRINT_ALWAYS "Script file name %s"NL,scriptFilePtr);
+ if (strstr(gScriptFileName,scriptFilePtr) == NULL)
+ {
+ dwRC = ERR_SCRIPT_NAME;
+ }
+ }
+
+ PRINT_ALWAYS "Device configuration file %s"NL,&versionData[3]);
+
+ return dwRC;
+ }
+
+
+static DWORD SendVersion()
+ {
+ DWORD dwRC = USBIO_ERR_SUCCESS;
+
+ // Here we send an 8 byte packet containing T_USB_WIN's + USBIO's versions.
+ PRINT_NOLOG "* Sending our version packet to T_USB...");
+
+ BYTE versionData[VERSION_DATAOUT_SIZE];
+ versionData[0] = VERSION_MAJOR;
+ versionData[1] = VERSION_MINOR;
+ versionData[2] = VERSION_MICRO;
+ versionData[3] = USBIO_VERSION_MAJOR;
+ versionData[4] = USBIO_VERSION_MINOR;
+
+ USBIO_CLASS_OR_VENDOR_REQUEST request;
+ request.Flags = USBIO_SHORT_TRANSFER_OK;
+ request.Type = RequestTypeClass;
+ request.Recipient = RecipientDevice;
+ request.RequestTypeReservedBits = 0;
+ request.Request = EVersion;
+ request.Value = 0;
+ request.Index = 0;
+
+ DWORD data_bytes = VERSION_DATAOUT_SIZE;
+ dwRC = gUsbDev.ClassOrVendorOutRequest(&versionData[0],data_bytes,&request);
+ PRINT_NOLOG " done."NL);
+ if (dwRC != USBIO_ERR_SUCCESS)
+ {
+ PRINT_ALWAYS "\n* Error: CUsbIoPipe::Write (version)");
+ ShowErrorText(dwRC);
+ }
+
+ return dwRC;
+ }
+
+
+static DWORD ExchangeVersions()
+ {
+ DWORD dwRC = USBIO_ERR_SUCCESS;
+
+
+ dwRC = SendVersion();
+ if (dwRC != USBIO_ERR_SUCCESS)
+ return dwRC;
+ dwRC = ReceiveVersion();
+
+ return dwRC;
+ }
+
+
+static DWORD ChangeInterfaceSetting(BYTE aInterfaceNumber, BYTE aAlternateSetting)
+ {
+ DWORD dwRC = USBIO_ERR_SUCCESS;
+
+ if (gAlternateSettings[aInterfaceNumber] != aAlternateSetting)
+ {
+ gAlternateSettings[aInterfaceNumber] = aAlternateSetting;
+ USBIO_INTERFACE_SETTING ifSetting = {aInterfaceNumber,aAlternateSetting,4096};
+ dwRC = gUsbDev.SetInterface(&ifSetting);
+ if (dwRC == USBIO_ERR_SUCCESS)
+ {
+ PRINT_NOLOG "Set Interface %d to Alternate Setting %d"NL,aInterfaceNumber,aAlternateSetting);
+ }
+ else
+ {
+ PRINT_ALWAYS "\n* Error: Setting Interface %d Alternate Setting %d",aInterfaceNumber,aAlternateSetting);
+ ShowErrorText(dwRC);
+ }
+ }
+
+ return dwRC;
+ }
+
+static DWORD ReadData(CUsbIoPipe * inPipePtr,CUsbIoBuf* bufPtr, TestParamPtr tpPtr)
+ {
+ DWORD dwRC = USBIO_ERR_SUCCESS;
+ UCHAR epAddress = gEndpointMap[tpPtr->interfaceNumber][tpPtr->alternateSetting][tpPtr->inPipe-1];
+
+ // We have to setup a read for at least one byte in order to get
+ // the host to issue IN tokens for our zero-byte read:
+ inPipePtr->Read(bufPtr);
+ dwRC = inPipePtr->WaitForCompletion(bufPtr, gReadWriteTimeOut);
+
+ if (dwRC != USBIO_ERR_SUCCESS)
+ {
+ PRINT_ALWAYS "\n* Error: EP Number %d Address <0x%X> CUsbIoPipe::Read %d bytes",tpPtr->inPipe,epAddress, bufPtr->NumberOfBytesToTransfer);
+ ShowErrorText(dwRC);
+ }
+ else
+ {
+ if (bufPtr->BytesTransferred != bufPtr->NumberOfBytesToTransfer)
+ {
+ DWORD pktNum = *(DWORD *)bufPtr->Buffer();
+ PRINT_ALWAYS "* EP Address <0x%X> Read more/less bytes (%d) than expected (%d) packet number 0x%x"NL,
+ epAddress, bufPtr->BytesTransferred,bufPtr->NumberOfBytesToTransfer,pktNum);
+ dwRC = USBIO_ERR_FAILED;
+ }
+ else
+ {
+ PRINT_IF_VERBOSE "* EP Address <0x%X> Read %d bytes."NL, epAddress,bufPtr->BytesTransferred);
+ }
+ }
+
+ return dwRC;
+ }
+
+
+static DWORD WriteData(CUsbIoPipe * outPipePtr,CUsbIoBuf* bufPtr, TestParamPtr tpPtr)
+ {
+ DWORD dwRC = USBIO_ERR_SUCCESS;
+ UCHAR epAddress = gEndpointMap[tpPtr->interfaceNumber][tpPtr->alternateSetting][tpPtr->outPipe-1];
+
+ outPipePtr->Write(bufPtr);
+ dwRC = outPipePtr->WaitForCompletion(bufPtr, gReadWriteTimeOut);
+
+ if (dwRC == USBIO_ERR_SUCCESS)
+ {
+ PRINT_IF_VERBOSE "* EP Address <0x%X> Wrote %d bytes."NL, epAddress, bufPtr->BytesTransferred);
+ }
+ else
+ {
+ PRINT_ALWAYS "\n* Error: EP Number %d Address <0x%X> CUsbIoPipe::Write %d bytes",tpPtr->outPipe,epAddress, bufPtr->NumberOfBytesToTransfer);
+ ShowErrorText(dwRC);
+ }
+
+ return dwRC;
+ }
+
+
+static DWORD CheckAndPrintStats(CUsbIoPipe * inPipePtr, CUsbIoPipe * outPipePtr, BYTE testIndex, DWORD loopCount, DWORD * averageInRate, DWORD * averageOutRate, DWORD inRate = 0, DWORD outRate = 0)
+ {
+ DWORD dwRC = USBIO_ERR_SUCCESS;
+ USBIO_PIPE_STATISTICS pipeStats;
+
+ PRINT_NOLOG "*** Test Index %d Iteration %d ***"NL,testIndex,loopCount);
+ if (outPipePtr)
+ {
+ dwRC = outPipePtr->QueryPipeStatistics (&pipeStats);
+
+ if (dwRC == USBIO_ERR_SUCCESS)
+ {
+ __int64 byteCount = (((__int64)pipeStats.BytesTransferred_H)<<32) + pipeStats.BytesTransferred_L;
+ PRINT_NOLOG "OUT %I64u bytes Succeeded %lu Failed %lu Rate %lu bytes/sec."NL,
+ byteCount,pipeStats.RequestsSucceeded,pipeStats.RequestsFailed,pipeStats.AverageRate);
+
+ if (pipeStats.RequestsFailed)
+ {
+ PRINT_ALWAYS "%d OUT Requests Failed"NL,pipeStats.RequestsFailed);
+ dwRC = USBIO_ERR_FAILED;
+ }
+ * averageOutRate = pipeStats.AverageRate;
+ if (pipeStats.AverageRate < outRate)
+ {
+ PRINT_ALWAYS "Failure Average OUT Rate %lu < Minimum Rate %lu"NL,pipeStats.AverageRate,outRate);
+ dwRC = USBIO_ERR_FAILED;
+ }
+ }
+ else
+ {
+ PRINT_ALWAYS "\n* Error: CUsbIoPipe::Query OUT Pipe Statistics");
+ ShowErrorText(dwRC);
+ }
+
+ }
+
+ if (inPipePtr && dwRC == USBIO_ERR_SUCCESS)
+ {
+ dwRC = inPipePtr->QueryPipeStatistics (&pipeStats);
+
+ if (dwRC == USBIO_ERR_SUCCESS)
+ {
+ __int64 byteCount = (((__int64)pipeStats.BytesTransferred_H)<<32) + pipeStats.BytesTransferred_L;
+ PRINT_NOLOG "IN %I64u bytes Succeeded %lu Failed %lu Rate %lu bytes/sec."NL,
+ byteCount,pipeStats.RequestsSucceeded,pipeStats.RequestsFailed,pipeStats.AverageRate);
+
+ if (pipeStats.RequestsFailed)
+ {
+ PRINT_ALWAYS "%d IN Requests Failed"NL,pipeStats.RequestsFailed);
+ dwRC = USBIO_ERR_FAILED;
+ }
+ * averageInRate = pipeStats.AverageRate;
+ if (pipeStats.AverageRate < inRate)
+ {
+ PRINT_ALWAYS "Failure Average IN Rate %lu < Minimum Rate %lu"NL,pipeStats.AverageRate,inRate);
+ dwRC = USBIO_ERR_FAILED;
+ }
+
+ }
+ else
+ {
+ PRINT_ALWAYS "\n* Error: CUsbIoPipe::Query IN Pipe Statistics");
+ ShowErrorText(dwRC);
+ }
+ }
+
+ return dwRC;
+ }
+
+
+UINT LoopTransfer( LPVOID pParam )
+ {
+ DWORD dwRC = USBIO_ERR_SUCCESS;
+
+ TestParamType testParams = *(TestParamPtr)pParam;
+
+ PRINT_NOLOG "* Thread %d Loop Transfers -- reading & writing alternately."NL,testParams.host.index);
+
+ ResetEvent (gThreadEndedEvents[testParams.host.index]);
+ SetEvent (gThreadStartedEvent);
+
+ CUsbIoPipe* inPipePtr = new CUsbIoPipe();
+ CUsbIoPipe* outPipePtr = new CUsbIoPipe();
+
+ BYTE* DataPtr = new BYTE[testParams.maxSize];
+ CUsbIoBuf buf((VOID*) DataPtr, testParams.maxSize); // the data buffer
+
+ BYTE* WaitSettingDataPtr = new BYTE[WAIT_SETTING_BUFFER_SIZE];
+ CUsbIoBuf bufWaitSetting((VOID*) WaitSettingDataPtr, WAIT_SETTING_BUFFER_SIZE); // another data buffer
+ bufWaitSetting.NumberOfBytesToTransfer = WAIT_SETTING_BUFFER_SIZE;
+
+ if (!testParams.settingRepeat)
+ {
+ OpenPipes (inPipePtr,outPipePtr,&testParams);
+ }
+
+ DWORD averageInRate;
+ DWORD averageOutRate;
+ int repeatCount = 0;
+ buf.NumberOfBytesToTransfer = testParams.minSize;
+ while ((dwRC == USBIO_ERR_SUCCESS) && !gFinishAllTests && !gAbort && (!testParams.repeat || repeatCount < testParams.repeat))
+ {
+ if (testParams.settingRepeat)
+ {
+ if ((repeatCount % testParams.settingRepeat) == 0)
+ {
+ if (repeatCount)
+ {
+ // Wait for this extra read to ensure that ok to change interface setting
+ inPipePtr->Read(&bufWaitSetting);
+ dwRC = inPipePtr->WaitForCompletion(&bufWaitSetting, WAIT_SETTING_TIMEOUT);
+ // Not necessary if different interfaces used as setting interface closes pipes,
+ // but if the same interface is used then prevents errors when opening pipes
+ ClosePipes (inPipePtr,outPipePtr);
+ PRINT_IF_VERBOSE "Signal for thread %d"NL,testParams.host.index);
+ SetEvent (gThreadWaitEvents[testParams.host.index]);
+ }
+
+ PRINT_IF_VERBOSE "Wait for thread %d"NL,testParams.beforeIndex);
+ dwRC = WaitForSingleObject (gThreadWaitEvents[testParams.beforeIndex],WAIT_BEFORETHREAD_TIMEOUT);
+ if (dwRC != WAIT_OBJECT_0)
+ {
+ PRINT_ALWAYS "Error waiting for alternate setting before thread"NL);
+ return 0;
+ }
+ dwRC = ChangeInterfaceSetting (testParams.interfaceNumber,testParams.alternateSetting);
+ OpenPipes (inPipePtr,outPipePtr,&testParams);
+ }
+ }
+
+ dwRC = ReadData(inPipePtr,&buf,&testParams);
+ if (dwRC == USBIO_ERR_SUCCESS)
+ {
+ // Now we send the received data back to the client.
+ dwRC = WriteData(outPipePtr,&buf,&testParams);
+ }
+
+ repeatCount++;
+ if (dwRC == USBIO_ERR_SUCCESS)
+ {
+ if (repeatCount == testParams.repeat)
+ {
+ dwRC = CheckAndPrintStats(inPipePtr,outPipePtr,testParams.host.index,repeatCount,&averageInRate,&averageOutRate,testParams.host.inRate,testParams.host.outRate);
+ }
+ else
+ {
+ if (testParams.host.displayRate && (repeatCount % testParams.host.displayRate) == 0)
+ {
+ dwRC = CheckAndPrintStats(inPipePtr,outPipePtr,testParams.host.index,repeatCount,&averageInRate,&averageOutRate);
+ }
+ }
+ }
+
+ if (buf.NumberOfBytesToTransfer == testParams.maxSize)
+ {
+ buf.NumberOfBytesToTransfer = testParams.minSize;
+ }
+ else
+ {
+ buf.NumberOfBytesToTransfer++;
+ }
+ }
+
+
+ Delay (WAIT_TEST_COMPLETE);
+ USBIO_CLASS_OR_VENDOR_REQUEST request;
+ request.Flags = USBIO_SHORT_TRANSFER_OK;
+ request.Type = RequestTypeClass;
+ request.Recipient = RecipientDevice;
+ request.RequestTypeReservedBits = 0;
+ request.Request = ETestResult;
+ request.Index = testParams.host.index;
+ request.Value = (dwRC == USBIO_ERR_SUCCESS) ? true : false;
+ DWORD dataBytes = 0;
+ dwRC = gUsbDev.ClassOrVendorOutRequest(NULL,dataBytes,&request);
+
+ PRINT_TIME "Test Index %d IN rate %lu OUT rate %lu Loop %s ",testParams.host.index,averageInRate,averageOutRate,request.Value ? "Passed" : "Failed");
+
+ dwRC = ClosePipes (inPipePtr,outPipePtr);
+ delete DataPtr;
+ delete inPipePtr;
+ delete outPipePtr;
+
+ if (request.Value)
+ {
+ if (testParams.host.signalNextSettingThread)
+ {
+ PRINT_IF_VERBOSE "Signal for thread %d"NL,testParams.host.index);
+ SetEvent (gThreadWaitEvents[testParams.host.index]);
+ }
+ }
+ else
+ {
+ gAbort = true;
+ }
+
+ SetEvent (gThreadEndedEvents[testParams.host.index]);
+
+ return 0;
+ }
+
+
+UINT ReceiveOnlyTransfer(LPVOID pParam)
+ {
+ DWORD dwRC = USBIO_ERR_SUCCESS;
+ BYTE* DataPtr; // the read/write buffer
+
+ TestParamType testParams = *(TestParamPtr)pParam;
+
+ PRINT_NOLOG "* Receive-only transfers (IN)."NL);
+
+ ResetEvent (gThreadEndedEvents[testParams.host.index]);
+ SetEvent (gThreadStartedEvent);
+
+ CUsbIoPipe * inPipePtr = new CUsbIoPipe();
+
+ DataPtr = new BYTE[testParams.maxSize];
+ CUsbIoBuf buf((VOID*) DataPtr, testParams.maxSize); // the data buffer
+
+ if (!testParams.settingRepeat)
+ {
+ OpenPipes (inPipePtr,NULL,&testParams);
+ }
+
+ buf.NumberOfBytesToTransfer = testParams.maxSize;
+ DWORD averageInRate;
+ DWORD averageOutRate;
+ int repeatCount = 0;
+ DWORD expected = testParams.packetNumber;
+ DWORD pktNum = 0;
+ int saveTimeout = gReadWriteTimeOut;
+ gReadWriteTimeOut = FIRSTFILEREAD_TIMEOUT;
+ while ((dwRC == USBIO_ERR_SUCCESS) && !gFinishAllTests && !gAbort && (!testParams.repeat || repeatCount < testParams.repeat))
+ {
+ if (testParams.settingRepeat)
+ {
+ if ((repeatCount % testParams.settingRepeat) == 0)
+ {
+ if (repeatCount)
+ {
+ // Wait to ensure that ok to change interface setting
+ Delay (WAIT_SETTING_DELAY);
+ // Not necessary if different interfaces used as setting interface closes pipes,
+ // but if the same interface is used then prevents errors when opening pipes
+ ClosePipes (inPipePtr,NULL);
+ PRINT_IF_VERBOSE "Signal for thread %d"NL,testParams.host.index);
+ SetEvent (gThreadWaitEvents[testParams.host.index]);
+ }
+
+ PRINT_IF_VERBOSE "Wait for thread %d"NL,testParams.beforeIndex);
+ dwRC = WaitForSingleObject (gThreadWaitEvents[testParams.beforeIndex],WAIT_BEFORETHREAD_TIMEOUT);
+ if (dwRC != WAIT_OBJECT_0)
+ {
+ PRINT_ALWAYS "Error waiting for alternate setting before thread"NL);
+ return 0;
+ }
+ dwRC = ChangeInterfaceSetting(testParams.interfaceNumber,testParams.alternateSetting);
+ OpenPipes (inPipePtr,NULL,&testParams);
+ }
+ }
+
+ // Then we read the data bytes
+ dwRC = ReadData(inPipePtr,&buf,&testParams);
+ if (gDeviceIdleCount < 0)
+ {
+ gReadWriteTimeOut = saveTimeout;
+ ReceiveCounter();
+ }
+ pktNum = *(DWORD *)buf.Buffer();
+ if (pktNum != expected)
+ {
+ PRINT_ALWAYS "\n* Error: rcv'd wrong pkt number: 0x%x (expected: 0x%x)"NL, pktNum, expected);
+ expected = pktNum;
+ }
+ expected++;
+ // Finally, sometimes we print some statistics
+ repeatCount++;
+ if (dwRC == USBIO_ERR_SUCCESS)
+ {
+ if (repeatCount == testParams.repeat)
+ {
+ dwRC = CheckAndPrintStats(inPipePtr,NULL,testParams.host.index,repeatCount,&averageInRate,&averageOutRate,testParams.host.inRate,testParams.host.outRate);
+ }
+ else
+ {
+ if (testParams.host.displayRate && (repeatCount % testParams.host.displayRate) == 0)
+ {
+ dwRC = CheckAndPrintStats(inPipePtr,NULL,testParams.host.index,repeatCount,&averageInRate,&averageOutRate);
+ }
+ }
+ }
+ else
+ {
+ PRINT_ALWAYS "\n* Error: Receive-only transfer::read");
+ ShowErrorText(dwRC);
+ }
+ }
+
+ Delay (WAIT_TEST_COMPLETE);
+ USBIO_CLASS_OR_VENDOR_REQUEST request;
+ request.Flags = USBIO_SHORT_TRANSFER_OK;
+ request.Type = RequestTypeClass;
+ request.Recipient = RecipientDevice;
+ request.RequestTypeReservedBits = 0;
+ request.Request = ETestResult;
+ request.Index = testParams.host.index;
+ request.Value = (dwRC == USBIO_ERR_SUCCESS) ? true : false;
+ DWORD dataBytes = 0;
+ dwRC = gUsbDev.ClassOrVendorOutRequest(NULL,dataBytes,&request);
+
+ PRINT_TIME "Test Index %d IN rate %lu Receieve-Only %s ",testParams.host.index,averageInRate,request.Value ? "Passed" : "Failed");
+
+ dwRC = ClosePipes (inPipePtr,NULL);
+
+ delete DataPtr;
+ delete inPipePtr;
+
+ if (request.Value)
+ {
+ if (testParams.host.signalNextSettingThread)
+ {
+ PRINT_IF_VERBOSE "Signal for thread %d"NL,testParams.host.index);
+ SetEvent (gThreadWaitEvents[testParams.host.index]);
+ }
+ }
+ else
+ {
+ gAbort = true;
+ }
+
+ SetEvent (gThreadEndedEvents[testParams.host.index]);
+
+ return 0;
+ }
+
+
+UINT TransmitOnlyTransfer(LPVOID pParam)
+ {
+ DWORD dwRC = USBIO_ERR_SUCCESS;
+ BYTE* DataPtr; // the read/write buffer
+
+ PRINT_NOLOG "* Transmit-only transfers (OUT)."NL);
+
+ TestParamType testParams = *(TestParamPtr)pParam;
+
+ ResetEvent (gThreadEndedEvents[testParams.host.index]);
+ SetEvent (gThreadStartedEvent);
+
+ CUsbIoPipe * outPipePtr = new CUsbIoPipe();
+
+ DataPtr = new BYTE[testParams.maxSize];
+ CUsbIoBuf buf((VOID*) DataPtr, testParams.maxSize); // the data buffer
+
+ BYTE* WaitSettingDataPtr = new BYTE[WAIT_SETTING_BUFFER_SIZE];
+ CUsbIoBuf bufWaitSetting((VOID*) WaitSettingDataPtr, WAIT_SETTING_BUFFER_SIZE); // another data buffer
+ bufWaitSetting.NumberOfBytesToTransfer = WAIT_SETTING_BUFFER_SIZE;
+
+ if (!testParams.settingRepeat)
+ {
+ OpenPipes (NULL,outPipePtr,&testParams);
+ }
+
+ buf.NumberOfBytesToTransfer = testParams.maxSize;
+ DWORD averageInRate;
+ DWORD averageOutRate;
+ int repeatCount = 0;
+ DWORD pktNum = testParams.packetNumber;
+ while ((dwRC == USBIO_ERR_SUCCESS) && !gFinishAllTests && !gAbort && (!testParams.repeat || repeatCount < testParams.repeat))
+ {
+ if (testParams.settingRepeat)
+ {
+ if ((repeatCount % testParams.settingRepeat) == 0)
+ {
+ if (repeatCount)
+ {
+ // Wait to ensure that ok to change interface setting
+ Delay (WAIT_SETTING_DELAY);
+ // Not necessary if different interfaces used as setting interface closes pipes,
+ // but if the same interface is used then prevents errors when opening pipes
+ ClosePipes (NULL,outPipePtr);
+ PRINT_IF_VERBOSE "Signal for thread %d"NL,testParams.host.index);
+ SetEvent (gThreadWaitEvents[testParams.host.index]);
+ }
+
+ PRINT_IF_VERBOSE "Wait for thread %d"NL,testParams.beforeIndex);
+ dwRC = WaitForSingleObject (gThreadWaitEvents[testParams.beforeIndex],WAIT_BEFORETHREAD_TIMEOUT);
+ if (dwRC != WAIT_OBJECT_0)
+ {
+ PRINT_ALWAYS "Error waiting for alternate setting before thread"NL);
+ return 0;
+ }
+ dwRC = ChangeInterfaceSetting (testParams.interfaceNumber,testParams.alternateSetting);
+ OpenPipes (NULL,outPipePtr,&testParams);
+ }
+ }
+
+
+ // Then we write 'Length' bytes
+ *(DWORD *)buf.Buffer() = pktNum++;
+ dwRC = WriteData(outPipePtr,&buf,&testParams);
+
+ repeatCount++;
+ // Finally, sometimes we print some statistics
+ if (dwRC == USBIO_ERR_SUCCESS)
+ {
+ if (repeatCount == testParams.repeat)
+ {
+ dwRC = CheckAndPrintStats(NULL,outPipePtr,testParams.host.index,repeatCount,&averageInRate,&averageOutRate,testParams.host.inRate,testParams.host.outRate);
+ }
+ else
+ {
+ if (testParams.host.displayRate && (repeatCount % testParams.host.displayRate) == 0)
+ {
+ dwRC = CheckAndPrintStats(NULL,outPipePtr,testParams.host.index,repeatCount,&averageInRate,&averageOutRate);
+ }
+ }
+ }
+ else
+ {
+ PRINT_ALWAYS "\n* Error: Transmit-only transfer::write");
+ ShowErrorText(dwRC);
+ }
+ }
+
+ Delay (WAIT_TEST_COMPLETE);
+ USBIO_CLASS_OR_VENDOR_REQUEST request;
+ request.Flags = USBIO_SHORT_TRANSFER_OK;
+ request.Type = RequestTypeClass;
+ request.Recipient = RecipientDevice;
+ request.RequestTypeReservedBits = 0;
+ request.Request = ETestResult;
+ request.Index = testParams.host.index;
+ request.Value = (dwRC == USBIO_ERR_SUCCESS) ? true : false;
+ DWORD dataBytes = 0;
+ dwRC = gUsbDev.ClassOrVendorOutRequest(NULL,dataBytes,&request);
+
+ PRINT_TIME "Test Index %d OUT rate %lu Transmit Only %s ",testParams.host.index,averageOutRate,request.Value ? "Passed" : "Failed");
+
+ ClosePipes (NULL,outPipePtr);
+ delete DataPtr;
+ delete outPipePtr;
+
+ if (request.Value)
+ {
+ if (testParams.host.signalNextSettingThread)
+ {
+ PRINT_IF_VERBOSE "Signal for thread %d"NL,testParams.host.index);
+ SetEvent (gThreadWaitEvents[testParams.host.index]);
+ }
+ }
+ else
+ {
+ gAbort = true;
+ }
+
+ SetEvent (gThreadEndedEvents[testParams.host.index]);
+
+ return 0;
+ }
+
+
+static BOOL CreateEvents()
+ {
+ // Create a manual-reset event object.
+ // Any thread sets this to signaled when it has started.
+ gThreadStartedEvent = CreateEvent(
+ NULL, // no security attributes
+ TRUE, // manual-reset event
+ FALSE, // initial state is non-signaled
+ "ThreadStarted" // object name
+ );
+ if (gThreadStartedEvent == NULL)
+ {
+ PRINT_ALWAYS "Error creating thread started event"NL);
+ // error exit
+ return FALSE;
+ }
+ // Create a manual-reset event object.
+ // Set to signaled by CT_usb_winDlg when the device is connected.
+ gDeviceConnectEvent = CreateEvent(
+ NULL, // no security attributes
+ TRUE, // manual-reset event
+ FALSE, // initial state is non-signaled
+ "DeviceConnected" // object name
+ );
+ if (gDeviceConnectEvent == NULL)
+ {
+ PRINT_ALWAYS "Error creating device connected event"NL);
+ // error exit
+ return FALSE;
+ }
+ // Create a manual-reset event object.
+ // Set to nonsignaled by CT_usb_winDlg when the device is disconnected.
+ gDeviceDisconnectEvent = CreateEvent(
+ NULL, // no security attributes
+ TRUE, // manual-reset event
+ FALSE, // initial state is non-signaled
+ "DeviceDisconnected" // object name
+ );
+ if (gDeviceDisconnectEvent == NULL)
+ {
+ PRINT_ALWAYS "Error creating device disconnected event"NL);
+ // error exit
+ return FALSE;
+ }
+
+ for (int i = 0; i < MAX_THREADS; i++)
+ {
+ // Create manual-reset event object for each thread. Any thread sets
+ // this to nonsignaled when it has started.
+ gThreadEndedEvents[i] = CreateEvent(
+ NULL, // no security attributes
+ TRUE, // manual-reset event
+ FALSE, // initial state is non-signaled
+ "" // object name
+ );
+ if (gThreadEndedEvents[i] == NULL)
+ {
+ PRINT_ALWAYS "Error creating thread %d ended event"NL,i);
+ // error exit
+ return FALSE;
+ }
+ // Create auto-reset event object for each thread. Any thread sets
+ // this to nonsignaled when it has started.
+ gThreadWaitEvents[i] = CreateEvent(
+ NULL, // no security attributes
+ FALSE, // automatically-reset event
+ FALSE, // initial state is non-signaled
+ "" // object name
+ );
+ if (gThreadEndedEvents[i] == NULL)
+ {
+ PRINT_ALWAYS "Error creating thread %d ended event"NL,i);
+ // error exit
+ return FALSE;
+ }
+ }
+ return TRUE;
+ }
+
+
+static BOOL GetDeviceInfo()
+ {
+ DWORD dwRC;
+
+ dwRC = GetDeviceDescriptor();
+ if (dwRC == USBIO_ERR_SUCCESS)
+ {
+ dwRC = GetConfigurationDescriptor();
+ }
+ if (dwRC == USBIO_ERR_SUCCESS)
+ {
+ dwRC = GetStringDescriptor();
+ }
+ if (dwRC == USBIO_ERR_SUCCESS)
+ {
+ // In order to give the USB device-side program (t_usb_device)
+ // enough time after getting configured to carry out
+ // some device tests, we wait here for a short while
+ // before proceeding:
+ Delay(DEVICE_CONFIG_DELAY);
+ dwRC = GetConfigurationInfo();
+ }
+ if (dwRC == USBIO_ERR_SUCCESS)
+ {
+ dwRC = ExchangeVersions();
+ }
+ if (dwRC != USBIO_ERR_SUCCESS)
+ {
+ if (dwRC == ERR_SCRIPT_NAME)
+ PRINT_ALWAYS "*** Warning Script Name Mismatch "NL);
+ else
+ ShowErrorText(dwRC);
+ return FALSE;
+ }
+
+ return TRUE;
+ }
+
+UINT DoTests(LPVOID pParam)
+ {
+ DWORD dwRC = USBIO_ERR_SUCCESS;
+ bool firstSetting = true;
+ BYTE threadIndex = 0;
+ BYTE lastSettingThreadIndex = 0;
+ TestParamType testParams;
+ USBIO_CLASS_OR_VENDOR_REQUEST request;
+ DWORD dataBytes;
+ FILE* inStream;
+ char line[256];
+ long repeatPosition = -1;
+ long repeatCount = -1;
+ UsbcvControl * usbcv;
+ bool hostTestFail = false;
+ bool mstoreDriveReady = false;
+ DWORD waitConnectTime = 0;
+ STARTUPINFO si;
+ PROCESS_INFORMATION pi;
+
+ if (!CreateEvents())
+ {
+ return FALSE;
+ }
+ if( (inStream = fopen( gScriptFileName, "r" )) == NULL )
+ {
+ PRINT_ALWAYS "The test script file %s was not opened"NL,gScriptFileName );
+ return FALSE;
+ }
+ else
+ {
+ PRINT_IF_VERBOSE "The test script file %s opened"NL,gScriptFileName);
+ }
+
+ PRINT_ALWAYS "Script file %s"NL,gScriptFileName);
+
+ // set up the EP 0 request structure
+ request.Flags = USBIO_SHORT_TRANSFER_OK;
+ request.Type = RequestTypeClass;
+ request.Recipient = RecipientDevice;
+ request.RequestTypeReservedBits = 0;
+
+ gTransferMode = EComment;
+
+ PRINT_TIME "Tests Started ");
+
+ /* Cycle until end of file reached: */
+ while( !feof( inStream ) && !gAbort)
+ {
+ testParams.host.index = threadIndex;
+
+ // for loopback tests
+ if (gTransferMode < EComment)
+ {
+ if (testParams.settingRepeat == 0)
+ {
+ dwRC = ChangeInterfaceSetting (testParams.interfaceNumber,testParams.alternateSetting);
+ }
+ request.Request = ETestParam;
+ request.Index = testParams.host.index;
+ if (firstSetting && testParams.settingRepeat)
+ {
+ request.Index |= FIRST_SETTING_THREAD_MASK;
+ PRINT_IF_VERBOSE "Signal for thread %d"NL,testParams.beforeIndex);
+ lastSettingThreadIndex = testParams.beforeIndex;
+ SetEvent (gThreadWaitEvents[lastSettingThreadIndex]);
+ firstSetting = false;
+ }
+ if (testParams.settingRepeat && threadIndex == lastSettingThreadIndex)
+ {
+ request.Index |= LAST_SETTING_THREAD_MASK;
+ }
+ dataBytes = sizeof(testParams) - sizeof(TestParamHostType);
+ dwRC = gUsbDev.ClassOrVendorOutRequest(&testParams,dataBytes,&request);
+ if (dwRC != USBIO_ERR_SUCCESS)
+ {
+ PRINT_ALWAYS "\n* Error: CUsbIo::ClassOrVendorOutRequest ");
+ ShowErrorText(dwRC);
+ }
+ }
+
+ testParams.host.signalNextSettingThread = (testParams.settingRepeat && threadIndex != lastSettingThreadIndex);
+ switch (gTransferMode)
+ {
+ case EXml:
+ break;
+
+ case ELoop:
+ case ECompare:
+ if (gDeviceIdleCount < 0)
+ {
+ ReceiveCounter();
+ }
+ AfxBeginThread (LoopTransfer, &testParams);
+ break;
+
+ case EReceiveOnly:
+ case EFileReceive:
+ if (gDeviceIdleCount < 0 && gTransferMode != EFileReceive)
+ {
+ ReceiveCounter();
+ }
+ AfxBeginThread (ReceiveOnlyTransfer, &testParams);
+ break;
+
+ case ETransmitOnly:
+ case EFileTransmit:
+ if (gDeviceIdleCount < 0)
+ {
+ ReceiveCounter();
+ }
+ AfxBeginThread (TransmitOnlyTransfer, &testParams);
+ break;
+
+ case EConnect:
+ // ensure that connect and disconnect events are reset
+ ResetEvent (gDeviceConnectEvent);
+ ResetEvent (gDeviceDisconnectEvent);
+ request.Request = ETestConnect;
+ request.Value = (USHORT)testParams.minSize;
+ dataBytes = 0;
+ dwRC = gUsbDev.ClassOrVendorOutRequest(NULL,dataBytes,&request);
+ if (dwRC != USBIO_ERR_SUCCESS)
+ {
+ PRINT_ALWAYS "\n* Error: CUsbIo::ClassOrVendorOutRequest ");
+ ShowErrorText(dwRC);
+ }
+ break;
+
+ case EDisconnect:
+ if (gUsbDev.IsOpen())
+ {
+ CloseUsbDevice();
+ }
+ break;
+
+ case EComment:
+ break;
+
+ case EWait:
+ if (testParams.host.index > 0)
+ {
+ PRINT_ALWAYS "Waiting for %d tests to complete\n",testParams.host.index);
+ dwRC = WaitForMultipleObjects (testParams.host.index,gThreadEndedEvents,TRUE,testParams.minSize);
+ if (dwRC == WAIT_TIMEOUT)
+ {
+ PRINT_ALWAYS "Timeout on waiting for test completion\n");
+ bool anyTestNotCompleted = false;
+ for (int i = 0; i < testParams.host.index; i++)
+ {
+ dwRC = WaitForSingleObject(gThreadEndedEvents[i],0);
+ if (dwRC != WAIT_OBJECT_0)
+ {
+ anyTestNotCompleted = true;
+ PRINT_ALWAYS "Thread %d not completed\n",i);
+ }
+ }
+ if (anyTestNotCompleted)
+ {
+ gFinishAllTests = true;
+ dwRC = WaitForMultipleObjects (testParams.host.index,gThreadEndedEvents,TRUE,INFINITE);
+ gFinishAllTests = false;
+ gAbort = true;
+ }
+ }
+ if (dwRC < WAIT_OBJECT_0 || dwRC >= (WAIT_OBJECT_0 + testParams.host.index))
+ {
+ PRINT_ALWAYS "Error waiting for all threads to complete"NL);
+ gAbort = true;
+ gFinishAllTests = true;
+ }
+ ReceiveCounter();
+ gDeviceIdleCount = -1;
+ PRINT_TIME "Test Group Complete ");
+ }
+ threadIndex = 0;
+ firstSetting = true;
+ break;
+
+ case EFail:
+ request.Request = ETestFail;
+ dataBytes = 0;
+ dwRC = gUsbDev.ClassOrVendorOutRequest(NULL,dataBytes,&request);
+ if (dwRC != USBIO_ERR_SUCCESS)
+ {
+ PRINT_ALWAYS "\n* Error: CUsbIo::ClassOrVendorOutRequest ");
+ ShowErrorText(dwRC);
+ }
+ gAbort = true;
+ break;
+
+ case ESwitch:
+ PRINT_NOLOG "Switching USB to %d"NL,testParams.minSize);
+ dwRC = OpenSwitchDevice ();
+ if (dwRC == USBIO_ERR_SUCCESS)
+ {
+ dwRC = GetConfigurationDescriptor();
+ }
+ if (dwRC == USBIO_ERR_SUCCESS)
+ {
+ // Delay to allow the switch to take place
+ Delay (BEFORE_SWITCH_DELAY);
+
+ request.Recipient = RecipientInterface;
+ request.Request = SWITCH_REQUEST;
+ request.Index = SWITCH_INDEX;
+ request.Value = SWITCH_VALUE;
+ BYTE switchData[] = {SWITCH_DATA0,((BYTE)testParams.minSize << 4) | SWITCH_DATA1};
+ DWORD dataBytes = sizeof(switchData);
+ dwRC = gUsbDev.ClassOrVendorOutRequest(&switchData[0],dataBytes,&request);
+ request.Recipient = RecipientDevice;
+ CloseUsbDevice();
+
+ // Delay to allow the switch to take place
+ Delay (AFTER_SWITCH_DELAY);
+ }
+ if (dwRC != USBIO_ERR_SUCCESS)
+ {
+ PRINT_ALWAYS "\n* Error: GetConfigurationDescriptor or CUsbIo::ClassOrVendorOutRequest ");
+ gAbort = true;
+ }
+ break;
+
+ case EWaitConnect:
+ PRINT_NOLOG "Waiting for device connection"NL);
+ waitConnectTime = 0;
+ while (!gAbort && !gUsbDev.IsOpen())
+ {
+ ResetEvent (gDeviceConnectEvent);
+ ResetEvent (gDeviceDisconnectEvent);
+ dwRC = OpenUsbDevice();
+ if (dwRC == USBIO_ERR_SUCCESS)
+ {
+ if (!GetDeviceInfo())
+ {
+ dwRC = USBIO_ERR_FAILED;
+ PRINT_ALWAYS "\n* Error: GetDeviceInfo"NL);
+ gAbort = TRUE;
+ hostTestFail = FALSE;
+ }
+ }
+ else
+ {
+ dwRC = WaitForSingleObject (gDeviceConnectEvent,CONNECT_RESCAN_TIMEOUT);
+ if ((dwRC == WAIT_ABANDONED) || (dwRC == WAIT_FAILED))
+ {
+ PRINT_ALWAYS "Error waiting for device connection"NL);
+ gAbort = TRUE;
+ hostTestFail = FALSE;
+ }
+ if (dwRC == WAIT_TIMEOUT)
+ {
+ waitConnectTime += CONNECT_RESCAN_TIMEOUT;
+ if (testParams.minSize && waitConnectTime >= testParams.minSize)
+ {
+ PRINT_ALWAYS "Timeout for device connection"NL);
+ gAbort = TRUE;
+ hostTestFail = FALSE;
+ }
+ else
+ {
+ ZeroMemory( &si, sizeof(si) );
+ si.cb = sizeof(si);
+ ZeroMemory( &pi, sizeof(pi) );
+
+ dwRC = CreateProcess (RESCAN_APPNAME,RESCAN_CMDLINE,NULL,NULL,FALSE,0,NULL,NULL,&si,&pi);
+ if (dwRC < 0)
+ PRINT_ALWAYS "Error %d running Devcon Rescan"NL,dwRC);
+ }
+ }
+ }
+ }
+ if (hostTestFail)
+ {
+ // try to send a test fail to the device
+ request.Request = ETestResult;
+ request.Index = HOST_ERROR_INDEX;
+ request.Value = false;
+ dataBytes = 0;
+ dwRC = gUsbDev.ClassOrVendorOutRequest(NULL,dataBytes,&request);
+ if (dwRC != USBIO_ERR_SUCCESS)
+ {
+ PRINT_ALWAYS "\n* Error: CUsbIo::ClassOrVendorOutRequest ");
+ ShowErrorText(dwRC);
+ }
+ gAbort = true;
+ }
+ break;
+
+ case EWaitDisconnect:
+ PRINT_NOLOG "Waiting for device disconnection"NL);
+ dwRC = WaitForSingleObject (gDeviceDisconnectEvent,testParams.minSize);
+ if (dwRC != WAIT_OBJECT_0)
+ {
+ PRINT_ALWAYS "Error waiting for device disconnection"NL);
+ gAbort = true;
+ }
+ // ensure that connect and disconnect events are reset
+ ResetEvent (gDeviceConnectEvent);
+ ResetEvent (gDeviceDisconnectEvent);
+ break;
+
+ case EDo:
+ repeatPosition = ftell(inStream);
+ repeatCount = 0;
+ PRINT_IF_VERBOSE "Repeating from file position %ld"NL,repeatPosition);
+ break;
+
+ case ERepeat:
+ if (repeatPosition <= 0)
+ PRINT_ALWAYS "No REPEAT in file"NL);
+ else
+ {
+ if (repeatCount++ < (long)testParams.minSize)
+ {
+ if (!fseek( inStream, repeatPosition, SEEK_SET))
+ PRINT_ALWAYS "Repeat Iteration %d"NL,repeatCount);
+ else
+ PRINT_ALWAYS "ERROR: Repeat Iteration %d"NL,repeatCount);
+ }
+ }
+ break;
+
+ case EUsbcv:
+ CloseUsbDevice();
+ PRINT_TIME "USBCV Test Started ");
+ usbcv = new UsbcvControl();
+ dwRC = usbcv->Create();
+ if (dwRC == USBIO_ERR_SUCCESS)
+ {
+ dwRC = usbcv->TestAllDevices(vendorId,productId, productIdMS);
+ }
+ delete usbcv;
+ if (dwRC == USBIO_ERR_SUCCESS)
+ {
+ PRINT_TIME "USBCV Test Complete - %s ",gAbort ? "Failed" : "Passed");
+ }
+ else
+ {
+ gAbort = true;
+ PRINT_ALWAYS "Error in Running USBCV\n");
+ }
+ if (gAbort)
+ {
+ // allow further tests to carry on until waitConnect
+ hostTestFail = true;
+ gAbort = false;
+ }
+ // ensure that connect and disconnect events are reset
+ ResetEvent (gDeviceConnectEvent);
+ ResetEvent (gDeviceDisconnectEvent);
+ break;
+
+ case EMassStorage:
+ mstoreDriveReady = false;
+ ResetEvent (gDeviceConnectEvent);
+ ResetEvent (gDeviceDisconnectEvent);
+ PRINT_TIME "Mass Storage Test Started ");
+ request.Request = ETestMassStorage;
+ request.Value = (USHORT)testParams.minSize; // product id
+ productIdMS = (USHORT)testParams.minSize;
+ dataBytes = 0;
+ dwRC = gUsbDev.ClassOrVendorOutRequest(NULL,dataBytes,&request);
+ if (dwRC != USBIO_ERR_SUCCESS)
+ {
+ PRINT_ALWAYS "\n* Error: CUsbIo::ClassOrVendorOutRequest ");
+ ShowErrorText(dwRC);
+ }
+ CloseUsbDevice();
+ if (gAbort)
+ {
+ // allow further tests to carry on until waitConnect
+ hostTestFail = true;
+ gAbort = false;
+ }
+ break;
+
+ case EEject:
+ if (mstoreDriveReady)
+ {
+ PRINT_TIME "Mass Storage Test Completed ");
+ if (strlen(line) == 0)
+ gAbort = !EjectVolume(' ');
+ else
+ gAbort = !EjectVolume(line[0]);
+ PRINT_TIME "Mass Storage Test Complete - %s ",gAbort || hostTestFail ? "Failed" : "Passed");
+ if (gAbort)
+ {
+ // allow further tests to carry on until waitConnect
+ hostTestFail = true;
+ gAbort = false;
+ }
+ }
+ break;
+
+ case EPerl:
+ if (mstoreDriveReady)
+ {
+ PRINT_TIME "Starting Perl Script %s ",line);
+ if (strlen(gLogfileName))
+ {
+ strcat (line," --logfile=");
+ strcat (line,gLogfileName);
+ fclose (logStream);
+ }
+ dwRC = PerlScript (line);
+ if (strlen(gLogfileName))
+ {
+ logStream = fopen (gLogfileName, "a+");
+ }
+ PRINT_TIME "Perl Script Complete - %s ",dwRC == 0 ? "Passed" : "Failed");
+ if (dwRC != 0 || gAbort)
+ {
+ ShowErrorText (dwRC);
+ // allow further tests to carry on until waitConnect
+ hostTestFail = true;
+ gAbort = false;
+ }
+ }
+ break;
+
+ case EWaitDrive:
+ if (!hostTestFail)
+ {
+ PRINT_TIME "Waiting for removable drive - %c ",line[0]);
+ gAbort = !WaitDriveReady(line[0]);
+ PRINT_TIME "Waiting completed - %s ",gAbort ? "Failed" : "Successfully");
+ if (gAbort)
+ {
+ // allow further tests to carry on until waitConnect
+ hostTestFail = true;
+ gAbort = false;
+ }
+ else
+ {
+ mstoreDriveReady = true;
+ }
+ }
+ break;
+
+ default:
+ gAbort = true;
+ break;
+ }
+ if (!gAbort && gTransferMode < EComment)
+ {
+ dwRC = WaitForSingleObject (gThreadStartedEvent,1500);
+ if (dwRC != WAIT_OBJECT_0)
+ {
+ PRINT_ALWAYS "Error waiting for thread to become ready"NL);
+ gAbort = true;
+ }
+ threadIndex++;
+ dwRC = ResetEvent (gThreadStartedEvent);
+ }
+ if (!gAbort)
+ {
+ if( fgets( line, 100, inStream ) != NULL)
+ {
+ gTransferMode = ParseTestLine (line,&testParams,&request);
+ }
+ }
+ }
+
+ if (gAbort)
+ {
+ PRINT_TIME "Tests Not Completed - Failed ");
+ }
+ else
+ {
+ request.Request = EStop;
+ request.Value = (logStream == NULL) ? false : true;
+ dataBytes = 0;
+ dwRC = gUsbDev.ClassOrVendorOutRequest(NULL,dataBytes,&request);
+ if (dwRC != USBIO_ERR_SUCCESS)
+ {
+ PRINT_ALWAYS "\n* Error: CUsbIo::ClassOrVendorOutRequest ");
+ ShowErrorText(dwRC);
+ }
+
+ PRINT_TIME "Tests Completed - All Passed ");
+ }
+
+
+ PRINT_ALWAYS NL);
+
+ if (logStream != NULL)
+ {
+ fclose (logStream);
+ if (!gAbort)
+ {
+ SendLogFile();
+ }
+ }
+
+ PRINT_NOLOG "Waiting for device disconnection"NL);
+ dwRC = WaitForSingleObject (gDeviceDisconnectEvent,WAITDISCONNECT_TIMEOUT);
+ if (dwRC != WAIT_OBJECT_0 && !gAbort)
+ {
+ PRINT_ALWAYS "Error waiting for device disconnection"NL);
+ }
+
+ CloseUsbDevice();
+
+ if (!gKeepOpen)
+ {
+ ExitProcess(0);
+ }
+
+ return TRUE;
+ }
+
+// --eof