kerneltest/e32test/device/t_usbco2.cpp
changeset 0 a41df078684a
child 19 4a8fed1c0ef6
equal deleted inserted replaced
-1:000000000000 0:a41df078684a
       
     1 // Copyright (c) 2000-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of the License "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 // e32test/device/t_usbco2.cpp
       
    15 // USB Test Program T_USB, functional part.
       
    16 // Device-side part, to work against USBRFLCT running on the host.
       
    17 // 
       
    18 //
       
    19 
       
    20 #include <e32hal.h>
       
    21 #include <e32uid.h>
       
    22 #include <hal.h>
       
    23 
       
    24 #include "t_usb.h"											// CActiveConsole, CActiveRW
       
    25 #include "t_usblib.h"										// Helpers
       
    26 
       
    27 
       
    28 _LIT(KUsbLddFilename, "eusbc");								// .ldd assumed - it's a filename
       
    29 _LIT(KOtgdiLddFilename, "otgdi");
       
    30 _LIT(KUsbDeviceName, "Usbc");
       
    31 _LIT(KFileName, "\\T_USBFILE.BIN");
       
    32 _LIT(KActivePanic, "T_USB");
       
    33 
       
    34 static const TUint32 KTusbVersion = 20070524;				// just an edit date really
       
    35 static const TUint8 KUsbrflctVersionMajor = 1;				// the version we're compatible with
       
    36 static const TUint8 KUsbrflctVersionMinor = 5;
       
    37 static const TUint8 KUsbrflctVersionMicro = 0;
       
    38 
       
    39 static const TInt KMaxFileSize = 100 * 1024 * 1024;			// 100MB (requires at least 128MB card)
       
    40 static const TInt KInitialBufSz = 0;
       
    41 static const TInt stridx1 = 0xCC;
       
    42 static const TInt stridx2 = 0xEE;
       
    43 
       
    44 //
       
    45 // --- class CActiveConsole ---------------------------------------------------------
       
    46 //
       
    47 
       
    48 CActiveConsole::CActiveConsole(CConsoleBase* aConsole, TBool aVerboseOutput)
       
    49 	: CActive(EPriorityNormal),
       
    50 	  iConsole(aConsole),
       
    51 	  iRW(NULL),
       
    52 	  iBufferSizeChosen(EFalse),
       
    53 	  iBandwidthPriorityChosen(EFalse),
       
    54 	  iDMAChosen(EFalse),
       
    55 	  iDoubleBufferingChosen(EFalse),
       
    56 	  iSoftwareConnect(EFalse),
       
    57 	  iHighSpeed(EFalse),
       
    58 	  iOtg(EFalse),
       
    59 	  iVerbose(aVerboseOutput)
       
    60 	{}
       
    61 
       
    62 
       
    63 CActiveConsole* CActiveConsole::NewLC(CConsoleBase* aConsole, TBool aVerboseOutput)
       
    64 	{
       
    65 	CActiveConsole* self = new (ELeave) CActiveConsole(aConsole, aVerboseOutput);
       
    66 	CleanupStack::PushL(self);
       
    67 	self->ConstructL();
       
    68 	return self;
       
    69 	}
       
    70 
       
    71 
       
    72 CActiveConsole* CActiveConsole::NewL(CConsoleBase* aConsole, TBool aVerboseOutput)
       
    73 	{
       
    74 	CActiveConsole* self = NewLC(aConsole, aVerboseOutput);
       
    75 	CleanupStack::Pop();
       
    76 	return self;
       
    77 	}
       
    78 
       
    79 
       
    80 void CActiveConsole::ConstructL()
       
    81 	{
       
    82 	CActiveScheduler::Add(this);
       
    83 
       
    84 	// Load logical driver (LDD)
       
    85 	// (There's no physical driver (PDD) with USB: it's a kernel extension DLL which
       
    86 	//  was already loaded at boot time.)
       
    87 	TInt r = User::LoadLogicalDevice(KUsbLddFilename);
       
    88 	if (r != KErrNone && r != KErrAlreadyExists)
       
    89 		{
       
    90 		TUSB_PRINT1("Error %d on loading USB LDD", r);
       
    91 		User::Leave(-1);
       
    92 		return;
       
    93 		}
       
    94 	TUSB_PRINT("Successfully loaded USB LDD");
       
    95 
       
    96 	// Open USB channel
       
    97 	r = iPort.Open(0);
       
    98 	if (r != KErrNone)
       
    99 		{
       
   100 		TUSB_PRINT1("Error %d on opening USB port", r);
       
   101 		User::Leave(-1);
       
   102 		return;
       
   103 		}
       
   104 	TUSB_PRINT("Successfully opened USB port");
       
   105 
       
   106 	// Create Reader/Writer active object
       
   107 	iRW = CActiveRW::NewL(iConsole, &iPort, iVerbose);
       
   108 	if (!iRW)
       
   109 		{
       
   110 		TUSB_PRINT("Failed to create reader/writer");
       
   111 		User::Leave(-1);
       
   112 		return;
       
   113 		}
       
   114 	TUSB_PRINT("Created reader/writer");
       
   115 
       
   116 	// Check for OTG support
       
   117 	TBuf8<KUsbDescSize_Otg> otg_desc;
       
   118 	r = iPort.GetOtgDescriptor(otg_desc);
       
   119 	if (!(r == KErrNotSupported || r == KErrNone))
       
   120 		{
       
   121 		TUSB_PRINT1("Error %d while fetching OTG descriptor", r);
       
   122 		User::Leave(-1);
       
   123 		return;
       
   124 		}
       
   125 	iOtg = (r != KErrNotSupported) ? ETrue : EFalse;
       
   126 
       
   127 	// On an OTG device we have to start the OTG driver, otherwise the Client
       
   128 	// stack will remain disabled forever.
       
   129 	if (iOtg)
       
   130 		{
       
   131 		TUSB_PRINT("Running on OTG device: loading OTG driver");
       
   132 		r = User::LoadLogicalDevice(KOtgdiLddFilename);
       
   133 		if (r != KErrNone)
       
   134 			{
       
   135 			TUSB_PRINT1("Error %d on loading OTG LDD", r);
       
   136 			User::Leave(-1);
       
   137 			return;
       
   138 			}
       
   139 		r = iOtgPort.Open();
       
   140 		if (r != KErrNone)
       
   141 			{
       
   142 			TUSB_PRINT1("Error %d on opening OTG port", r);
       
   143 			User::Leave(-1);
       
   144 			return;
       
   145 			}
       
   146 		r = iOtgPort.StartStacks();
       
   147 		if (r != KErrNone)
       
   148 			{
       
   149 			TUSB_PRINT1("Error %d on starting USB stack", r);
       
   150 			User::Leave(-1);
       
   151 			return;
       
   152 			}
       
   153 		}
       
   154 	}
       
   155 
       
   156 
       
   157 TInt CActiveConsole::SetupInterface()
       
   158 	{
       
   159 	// Query the USB device/Setup the USB interface
       
   160 	TInt r = QueryUsbClientL();
       
   161 	if (r != KErrNone)
       
   162 		{
       
   163 		TUSB_PRINT1("Interface setup failed", r);
       
   164 		return r;
       
   165 		}
       
   166 	TUSB_PRINT("Interface successfully set up");
       
   167 
       
   168 	// Change some descriptors to contain suitable values
       
   169 	r = SetupDescriptors();
       
   170 	if (r != KErrNone)
       
   171 		{
       
   172 		TUSB_PRINT1("Descriptor setup failed", r);
       
   173 		return r;
       
   174 		}
       
   175 
       
   176 	// Create device state active object
       
   177 	iDeviceStateNotifier = CActiveDeviceStateNotifier::NewL(iConsole, &iPort, iVerbose);
       
   178 	if (!iDeviceStateNotifier)
       
   179 		{
       
   180 		TUSB_PRINT("Failed to create device state notifier");
       
   181 		return r;
       
   182 		}
       
   183 	iDeviceStateNotifier->Activate();
       
   184 
       
   185 	// Create endpoint stall status active object
       
   186 	iStallNotifier = CActiveStallNotifier::NewL(iConsole, &iPort, iVerbose);
       
   187 	if (!iStallNotifier)
       
   188 		{
       
   189 		TUSB_PRINT("Failed to create stall notifier");
       
   190 		return r;
       
   191 		}
       
   192 	iStallNotifier->Activate();
       
   193 
       
   194 	return r;
       
   195 	}
       
   196 
       
   197 
       
   198 CActiveConsole::~CActiveConsole()
       
   199 	{
       
   200 	TUSB_VERBOSE_PRINT("CActiveConsole::~CActiveConsole()");
       
   201 	Cancel();												// base class cancel -> calls our DoCancel
       
   202 	delete iRW;												// destroy the reader/writer
       
   203 	delete iDeviceStateNotifier;
       
   204 	delete iStallNotifier;
       
   205 	TInt r = iPort.RemoveStringDescriptor(stridx1);
       
   206 	if (r != KErrNone)
       
   207 		{
       
   208 		TUSB_PRINT1("Error %d on string removal", r);
       
   209 		}
       
   210 	r = iPort.RemoveStringDescriptor(stridx2);
       
   211 	if (r != KErrNone)
       
   212 		{
       
   213 		TUSB_PRINT1("Error %d on string removal", r);
       
   214 		}
       
   215 	if (iOtg)
       
   216 		{
       
   217 		TUSB_PRINT("Running on OTG device: unloading OTG driver");
       
   218 		iOtgPort.StopStacks();
       
   219 		iOtgPort.Close();
       
   220 		r = User::FreeLogicalDevice(RUsbOtgDriver::Name());
       
   221 		if (r != KErrNone)
       
   222 			{
       
   223 			TUSB_PRINT1("Error %d on freeing OTG LDD", r);
       
   224 			}
       
   225 		}
       
   226 	iPort.Close();											// close USB channel
       
   227 	r = User::FreeLogicalDevice(KUsbDeviceName);
       
   228 	if (r != KErrNone)
       
   229 		{
       
   230 		TUSB_PRINT1("Error %d during unloading USB LDD", r);
       
   231 		User::Leave(-1);
       
   232 		return;
       
   233 		}
       
   234 	TUSB_PRINT("Successfully unloaded USB LDD");	
       
   235 	}
       
   236 
       
   237 
       
   238 void CActiveConsole::DoCancel()
       
   239 	{
       
   240 	TUSB_VERBOSE_PRINT("CActiveConsole::DoCancel()");
       
   241 	iConsole->ReadCancel();
       
   242 	}
       
   243 
       
   244 
       
   245 void CActiveConsole::RunL()
       
   246 	{
       
   247 	TUSB_VERBOSE_PRINT("CActiveConsole::RunL()");
       
   248 	ProcessKeyPressL(static_cast<TChar>(iConsole->KeyCode()));
       
   249 	}
       
   250 
       
   251 
       
   252 void CActiveConsole::RequestCharacter()
       
   253 	{
       
   254 	// A request is issued to the CConsoleBase to accept a character from the keyboard.
       
   255 	__ASSERT_ALWAYS(!IsActive(), User::Panic(KActivePanic, 666));
       
   256 	if (!iBufferSizeChosen)
       
   257 		{
       
   258 		iConsole->Printf(_L("\n"));
       
   259 		iConsole->Printf(_L("++++ Choose max. Transfer Size ++++\n"));
       
   260 		iConsole->Printf(_L("  '0' - Set up USB device for USBCV\n"));
       
   261 		iConsole->Printf(_L("  '1' -   32 bytes\n"));
       
   262 		iConsole->Printf(_L("  '2' - 1024 bytes\n"));
       
   263 		iConsole->Printf(_L("  '3' -   64 kbytes\n"));
       
   264 		iConsole->Printf(_L("  '4' -    1 Mbyte\n"));
       
   265 		}
       
   266 	else if (!iBandwidthPriorityChosen)
       
   267 		{
       
   268 		iConsole->Printf(_L("\n"));
       
   269 		iConsole->Printf(_L("++++ Choose Bandwidth Priority ++++\n"));
       
   270 		iConsole->Printf(_L("  '1' - Economical buffering - default\n"));
       
   271 		iConsole->Printf(_L("  '2' - More memory than default buffering - Plus1\n"));
       
   272 		iConsole->Printf(_L("  '3' - More memory than Plus1 buffering - Plus2\n"));
       
   273 		iConsole->Printf(_L("  '4' - Maximum buffering\n"));
       
   274 		}
       
   275 	else if (!iDMAChosen)
       
   276 		{
       
   277 		iConsole->Printf(_L("\n"));
       
   278 		iConsole->Printf(_L("++++ Choose Endpoint I/O Transfer Mode ++++\n"));
       
   279 		iConsole->Printf(_L("  '1' - Interrupt Mode\n"));
       
   280 		iConsole->Printf(_L("  '2' - DMA Mode (recommended)\n"));
       
   281 		}
       
   282 	else if (!iDoubleBufferingChosen)
       
   283 		{
       
   284 		iConsole->Printf(_L("\n"));
       
   285 		iConsole->Printf(_L("++++ Choose Endpoint FIFO Mode ++++\n"));
       
   286 		iConsole->Printf(_L("  '1' - Normal Buffering Mode\n"));
       
   287 		iConsole->Printf(_L("  '2' - Double Buffering Mode (recommended)\n"));
       
   288 		}
       
   289 	else
       
   290 		{
       
   291 		iConsole->Printf(_L("\n"));
       
   292 		iConsole->Printf(_L("++++ Select Program Option ++++\n"));
       
   293 		iConsole->Printf(_L("  'L'oop test\n"));
       
   294 		iConsole->Printf(_L("   Loop test with data 'C'ompare\n"));
       
   295 		iConsole->Printf(_L("  'R'eceive-only test (we receive, host transmits)\n"));
       
   296 		iConsole->Printf(_L("  'T'ransmit-only test\n"));
       
   297 		iConsole->Printf(_L("   Receive and 'P'ut (write) to File\n"));
       
   298 		iConsole->Printf(_L("   Transmit and 'G'et (read) from File\n"));
       
   299 		iConsole->Printf(_L("   Signal Remote-'W'akeup to the host\n"));
       
   300 		iConsole->Printf(_L("  'S'top current transfer\n"));
       
   301 #ifdef WITH_DUMP_OPTION
       
   302 		iConsole->Printf(_L("  'D'ump USB regs to debugout\n"));
       
   303 #endif
       
   304 		iConsole->Printf(_L("   Re'E'numerate device\n"));
       
   305 		iConsole->Printf(_L("  'Q'uit this app\n"));
       
   306 		}
       
   307 	iConsole->Read(iStatus);
       
   308 	SetActive();
       
   309 	}
       
   310 
       
   311 
       
   312 void CActiveConsole::ProcessKeyPressL(TChar aChar)
       
   313 	{
       
   314 	if (aChar == EKeyEscape)
       
   315 		{
       
   316 		RDebug::Print(_L("CActiveConsole: ESC key pressed -> stopping active scheduler..."));
       
   317 		CActiveScheduler::Stop();
       
   318 		return;
       
   319 		}
       
   320 	if (!iBufferSizeChosen)
       
   321 		{
       
   322 		// Set maximum buffer size from keypress
       
   323 		switch (aChar)
       
   324 			{
       
   325 		case '0':
       
   326 			// This is for creating a USB device that just enumerates,
       
   327 			// to be used for compliance testing with USBCV.
       
   328 			iRW->SetMaxBufSize(0);
       
   329 			break;
       
   330 		case '1':
       
   331 			iRW->SetMaxBufSize(32);
       
   332 			break;
       
   333 		case '2':
       
   334 			iRW->SetMaxBufSize(1024);
       
   335 			break;
       
   336 		case '3':
       
   337 			iRW->SetMaxBufSize(64 * 1024);
       
   338 			break;
       
   339 		case '4':
       
   340 			iRW->SetMaxBufSize(KMaxBufSize);
       
   341 			break;
       
   342 		default:
       
   343 			TUSB_PRINT1("Not a valid input character: %c", aChar.operator TUint());
       
   344 			goto request_char;
       
   345 			}
       
   346 		TUSB_PRINT1("Maximum buffer size set to %d bytes", iRW->MaxBufSize());
       
   347 		iBufferSizeChosen = ETrue;
       
   348 		}
       
   349 	else if (!iBandwidthPriorityChosen)
       
   350 		{
       
   351 		// Set bandwidth priority from keypress
       
   352 		switch (aChar)
       
   353 			{
       
   354 		case '1':
       
   355 			iBandwidthPriority = EUsbcBandwidthOUTDefault | EUsbcBandwidthINDefault;
       
   356 			TUSB_PRINT("Bandwith priority set to default");
       
   357 			break;
       
   358 		case '2':
       
   359 			iBandwidthPriority = EUsbcBandwidthOUTPlus1 | EUsbcBandwidthINPlus1;
       
   360 			TUSB_PRINT("Bandwith priority set to Plus1");
       
   361 			break;
       
   362 		case '3':
       
   363 			iBandwidthPriority = EUsbcBandwidthOUTPlus2 | EUsbcBandwidthINPlus2;
       
   364 			TUSB_PRINT("Bandwith priority set to Plus2");
       
   365 			break;
       
   366 		case '4':
       
   367 			iBandwidthPriority = EUsbcBandwidthINMaximum | EUsbcBandwidthOUTMaximum;
       
   368 			TUSB_PRINT("Bandwith priority set to maximum");
       
   369 			break;
       
   370 		default:
       
   371 			TUSB_PRINT1("Not a valid input character: %c", aChar.operator TUint());
       
   372 			goto request_char;
       
   373 			}
       
   374 		TUSB_PRINT1("(Set to 0x%08X)", iBandwidthPriority);
       
   375 		iBandwidthPriorityChosen = ETrue;
       
   376 
       
   377 		TUSB_PRINT("Configuring interface...");
       
   378 		TInt r = SetupInterface();
       
   379 		if (r != KErrNone)
       
   380 			{
       
   381 			TUSB_PRINT1("Error: %d. Stopping active scheduler...", r);
       
   382 			CActiveScheduler::Stop();
       
   383 			return;
       
   384 			}
       
   385 		}
       
   386 	else if (!iDMAChosen)
       
   387 		{
       
   388 		// Set DMA mode from keypress
       
   389 		switch (aChar)
       
   390 			{
       
   391 		case '1':
       
   392 			TUSB_PRINT("- Trying to deallocate endpoint DMA:\n");
       
   393 			DeAllocateEndpointDMA(EEndpoint1);
       
   394 			DeAllocateEndpointDMA(EEndpoint2);
       
   395 			break;
       
   396 		case '2':
       
   397 			TUSB_PRINT("- Trying to allocate endpoint DMA:\n");
       
   398 			AllocateEndpointDMA(EEndpoint1);
       
   399 			AllocateEndpointDMA(EEndpoint2);
       
   400 			break;
       
   401 		default:
       
   402 			TUSB_PRINT1("Not a valid input character: %c", aChar.operator TUint());
       
   403 			goto request_char;
       
   404 			}
       
   405 		iDMAChosen = ETrue;
       
   406 		}
       
   407 	else if (!iDoubleBufferingChosen)
       
   408 		{
       
   409 		// Set Double Buffering from keypress
       
   410 		switch (aChar)
       
   411 			{
       
   412 		case '1':
       
   413 			TUSB_PRINT("- Trying to deallocate Double Buffering:\n");
       
   414 			DeAllocateDoubleBuffering(EEndpoint1);
       
   415 			DeAllocateDoubleBuffering(EEndpoint2);
       
   416 			break;
       
   417 		case '2':
       
   418 			TUSB_PRINT("- Trying to allocate Double Buffering:\n");
       
   419 			AllocateDoubleBuffering(EEndpoint1);
       
   420 			AllocateDoubleBuffering(EEndpoint2);
       
   421 			break;
       
   422 		default:
       
   423 			TUSB_PRINT1("Not a valid input character: %c", aChar.operator TUint());
       
   424 			goto request_char;
       
   425 			}
       
   426 		iDoubleBufferingChosen = ETrue;
       
   427 
       
   428 		// Everything chosen, so let's re-enumerate...
       
   429 		TUSB_PRINT("Enumeration...");
       
   430 		TInt r = ReEnumerate();
       
   431 		if (r != KErrNone)
       
   432 			{
       
   433 			TUSB_PRINT1("Error: %d. Stopping active scheduler...", r);
       
   434 			CActiveScheduler::Stop();
       
   435 			return;
       
   436 			}
       
   437 		TUSB_PRINT("Device successfully re-enumerated\n");
       
   438 
       
   439 		// Make sure program versions match if testing against USBRFLCT
       
   440 		if (iRW->MaxBufSize() != 0)
       
   441 			{
       
   442 			r = iRW->ExchangeVersions();
       
   443 			if (r != KErrNone)
       
   444 				{
       
   445 				TUSB_PRINT1("Error: %d. Stopping active scheduler...", r);
       
   446 				CActiveScheduler::Stop();
       
   447 				return;
       
   448 				}
       
   449 			}
       
   450 		}
       
   451 	else
       
   452 		{
       
   453 		// Execute one of the 'proper' program functions
       
   454 		switch (aChar)
       
   455 			{
       
   456 		case 'l':					// start loop test
       
   457 		case 'L':
       
   458 			TUSB_PRINT("-> Loop test selected\n");
       
   459 			iRW->SetTransferMode(ELoop);
       
   460 			iRW->SendPreamble();
       
   461 			break;
       
   462 		case 'c':					// start loop/compare test
       
   463 		case 'C':
       
   464 			TUSB_PRINT("-> Loop test with compare selected\n");
       
   465 			iRW->SetTransferMode(ELoopComp);
       
   466 			iRW->SendPreamble();
       
   467 			break;
       
   468 		case 'r':					// start receive-only test
       
   469 		case 'R':
       
   470 			TUSB_PRINT("-> Receive-only test selected\n");
       
   471 			iRW->SetTransferMode(EReceiveOnly);
       
   472 			iRW->SendPreamble();
       
   473 			break;
       
   474 		case 't':					// start transmit-only test
       
   475 		case 'T':
       
   476 			TUSB_PRINT("-> Transmit-only test selected\n");
       
   477 			iRW->SetTransferMode(ETransmitOnly);
       
   478 			iRW->SendPreamble();
       
   479 			break;
       
   480 		case 'g':					// start transmit & get-from-file test
       
   481 		case 'G':
       
   482 			TUSB_PRINT("-> Transmit from file test selected\n");
       
   483 			iRW->SetTransferMode(ETransmitOnly);
       
   484 			iRW->ReadFromDisk(ETrue);
       
   485 			iRW->SendPreamble();
       
   486 			break;
       
   487 		case 'p':					// start receive & put-to-file test
       
   488 		case 'P':
       
   489 			TUSB_PRINT("-> Receive to file test selected\n");
       
   490 			iRW->SetTransferMode(EReceiveOnly);
       
   491 			iRW->WriteToDisk(ETrue);
       
   492 			iRW->SendPreamble();
       
   493 			break;
       
   494 		case 'w':					// remote-wakeup
       
   495 		case 'W':
       
   496 			TUSB_PRINT("-> Signal Remote-wakeup selected\n");
       
   497 			iPort.SignalRemoteWakeup();
       
   498 			break;
       
   499 		case 's':					// stop either
       
   500 		case 'S':
       
   501 			TUSB_PRINT("-> Stop transfer selected\n");
       
   502 			iRW->Stop();
       
   503 			break;
       
   504 #ifdef WITH_DUMP_OPTION
       
   505 		case 'd':					// dump controller registers
       
   506 		case 'D':
       
   507 			TUSB_PRINT("-> Dump option selected\n");
       
   508 			iPort.DumpRegisters();
       
   509 			QueryRxBuffer();
       
   510 			break;
       
   511 #endif
       
   512 		case 'e':					// ReEnumerate()
       
   513 		case 'E':
       
   514 			TUSB_PRINT("-> Re-enumerate device selected\n");
       
   515 			ReEnumerate();
       
   516 			break;
       
   517 		case 'q':					// quit
       
   518 		case 'Q':
       
   519 			TUSB_PRINT("-> Quit program selected\n");
       
   520 			TUSB_VERBOSE_PRINT("CActiveConsole: stopping active scheduler...");
       
   521 			CActiveScheduler::Stop();
       
   522 			return;
       
   523 		default:
       
   524 			TUSB_PRINT1("-> Not a valid input character: %c", aChar.operator TUint());
       
   525 			goto request_char;
       
   526 			}
       
   527 		}
       
   528  request_char:
       
   529 	RequestCharacter();
       
   530 	return;
       
   531 	}
       
   532 
       
   533 
       
   534 #ifdef WITH_DUMP_OPTION
       
   535 void CActiveConsole::QueryRxBuffer()
       
   536 	{
       
   537 	// Let's look whether there's data in the rx buffer
       
   538 	TInt bytes = 0;
       
   539 	TInt r = iPort.QueryReceiveBuffer(EEndpoint2, bytes);
       
   540 	if (r != KErrNone)
       
   541 		{
       
   542 		RDebug::Print(_L(" Error %d on querying read buffer\n"), r);
       
   543 		}
       
   544 	else
       
   545 		{
       
   546 		RDebug::Print(_L(" %d bytes in RX buffer\n"), bytes);
       
   547 		}
       
   548 	}
       
   549 #endif
       
   550 
       
   551 
       
   552 TInt CActiveConsole::QueryUsbClientL()
       
   553 	{
       
   554 	// Not really just querying... but rather setting up the whole interface.
       
   555 	// It's in fact a bit lengthy, but all these steps are required, once,
       
   556 	// and in that order.
       
   557 
       
   558 	// Get device/endpoint capabilities
       
   559 	//
       
   560 	// A TPckg, or TPckBuf was not used in the following, because
       
   561 	//
       
   562 	//	 TPckgBuf<TUsbcEndpointData[KUsbcMaxEndpoints]> databuf;
       
   563 	//
       
   564 	// doesn't work. Also,
       
   565 	//
       
   566 	//	 TUsbcEndpointData data[KUsbcMaxEndpoints];
       
   567 	//	 TPckgBuf<TUsbcEndpointData[KUsbcMaxEndpoints]> databuf(data);
       
   568 	//
       
   569 	// doesn't work. Also,
       
   570 	//
       
   571 	//	 TUsbcEndpointData data[KUsbcMaxEndpoints];
       
   572 	//	 TPckgBuf<TUsbcEndpointData[]> databuf(data);
       
   573 	//
       
   574 	// doesn't work.
       
   575 	// So we seem to have to stick to the ugly cast below.
       
   576 	//
       
   577 	//	 TUsbcEndpointData data[KUsbcMaxEndpoints];
       
   578 	//	 TPtr8 databuf(reinterpret_cast<TUint8*>(data), sizeof(data), sizeof(data));
       
   579 	//
       
   580 
       
   581 	// Device
       
   582 	TUsbDeviceCaps d_caps;
       
   583 	TInt r = iPort.DeviceCaps(d_caps);
       
   584 	if (r != KErrNone)
       
   585 		{
       
   586 		TUSB_PRINT1("Error %d on querying device capabilities", r);
       
   587 		return KErrGeneral;
       
   588 		}
       
   589 	const TInt n = d_caps().iTotalEndpoints;
       
   590 
       
   591 	TUSB_PRINT("###  USB device capabilities:");
       
   592 	TUSB_PRINT1("Number of endpoints:                        %d", n);
       
   593 	TUSB_PRINT1("Supports Software-Connect:                  %s",
       
   594 				d_caps().iConnect ? _S("yes") : _S("no"));
       
   595 	TUSB_PRINT1("Device is Self-Powered:                     %s",
       
   596 				d_caps().iSelfPowered ? _S("yes") : _S("no"));
       
   597 	TUSB_PRINT1("Supports Remote-Wakeup:                     %s",
       
   598 				d_caps().iRemoteWakeup ? _S("yes") : _S("no"));
       
   599 	TUSB_PRINT1("Supports High-speed:                        %s",
       
   600 				d_caps().iHighSpeed ? _S("yes") : _S("no"));
       
   601 	TUSB_PRINT1("Supports OTG:                               %s",
       
   602 				iOtg ? _S("yes") : _S("no"));
       
   603 	TUSB_PRINT1("Supports unpowered cable detection:         %s",
       
   604 				(d_caps().iFeatureWord1 & KUsbDevCapsFeatureWord1_CableDetectWithoutPower) ?
       
   605 				_S("yes") : _S("no"));
       
   606 	TUSB_PRINT1("Supports endpoint resource alloc scheme V2: %s\n",
       
   607 				(d_caps().iFeatureWord1 & KUsbDevCapsFeatureWord1_EndpointResourceAllocV2) ?
       
   608 				_S("yes") : _S("no"));
       
   609 	TUSB_PRINT("");
       
   610 
       
   611 	iSoftwareConnect = d_caps().iConnect;					// we need to remember this
       
   612 
       
   613 	if (n < 2)
       
   614 		{
       
   615 		TUSB_PRINT1("Error: only %d endpoints available on device", n);
       
   616 		return KErrGeneral;
       
   617 		}
       
   618 
       
   619 	// Endpoints
       
   620 	TUsbcEndpointData data[KUsbcMaxEndpoints];
       
   621 	TPtr8 dataptr(reinterpret_cast<TUint8*>(data), sizeof(data), sizeof(data));
       
   622 	r = iPort.EndpointCaps(dataptr);
       
   623 	if (r != KErrNone)
       
   624 		{
       
   625 		TUSB_PRINT1("Error %d on querying endpoint capabilities", r);
       
   626 		return KErrGeneral;
       
   627 		}
       
   628 	TUSB_PRINT("### USB device endpoint capabilities:");
       
   629 	for (TInt i = 0; i < n; i++)
       
   630 		{
       
   631 		const TUsbcEndpointCaps* caps = &data[i].iCaps;
       
   632 		TUSB_PRINT2("Endpoint: SizeMask = 0x%08x TypeDirMask = 0x%08x",
       
   633 					caps->iSizes, caps->iTypesAndDir);
       
   634 		}
       
   635 	TUSB_PRINT("");
       
   636 
       
   637 	// Set up the active interface
       
   638 	TUsbcInterfaceInfoBuf ifc;
       
   639 	TInt ep_found = 0;
       
   640 	TBool foundBulkIN = EFalse;
       
   641 	TBool foundBulkOUT = EFalse;
       
   642 	for (TInt i = 0; i < n; i++)
       
   643 		{
       
   644 		const TUsbcEndpointCaps* const caps = &data[i].iCaps;
       
   645 		const TInt mps = caps->MaxPacketSize();
       
   646 		if (!foundBulkIN &&
       
   647 			(caps->iTypesAndDir & (KUsbEpTypeBulk | KUsbEpDirIn)) ==
       
   648 			(KUsbEpTypeBulk | KUsbEpDirIn))
       
   649 			{
       
   650 			if (!(mps == 64 || mps == 512))
       
   651 				{
       
   652 				TUSB_PRINT1("Funny Bulk IN MaxPacketSize: %d - T_USB will probably fail...", mps);
       
   653 				}
       
   654 			// EEndpoint1 is going to be our Tx (IN) endpoint
       
   655 			ifc().iEndpointData[0].iType = KUsbEpTypeBulk;
       
   656 			ifc().iEndpointData[0].iDir	 = KUsbEpDirIn;
       
   657 			ifc().iEndpointData[0].iSize = mps;
       
   658 			foundBulkIN = ETrue;
       
   659 			if (++ep_found == 2)
       
   660 				break;
       
   661 			}
       
   662 		else if (!foundBulkOUT &&
       
   663 			(caps->iTypesAndDir & (KUsbEpTypeBulk | KUsbEpDirOut)) ==
       
   664 			(KUsbEpTypeBulk | KUsbEpDirOut))
       
   665 			{
       
   666 			if (!(mps == 64 || mps == 512))
       
   667 				{
       
   668 				TUSB_PRINT1("Funny Bulk OUT MaxPacketSize: %d - T_USB will probably fail...", mps);
       
   669 				}
       
   670 			// EEndpoint2 is going to be our Rx (OUT) endpoint
       
   671 			ifc().iEndpointData[1].iType = KUsbEpTypeBulk;
       
   672 			ifc().iEndpointData[1].iDir	 = KUsbEpDirOut;
       
   673 			ifc().iEndpointData[1].iSize = mps;
       
   674 			foundBulkOUT = ETrue;
       
   675 			if (++ep_found == 2)
       
   676 				break;
       
   677 			}
       
   678 		}
       
   679 	if (ep_found != 2)
       
   680 		{
       
   681 		TUSB_PRINT1("No suitable endpoints found", r);
       
   682 		return KErrGeneral;
       
   683 		}
       
   684 
       
   685 	_LIT16(ifcname, "T_USB Test Interface (Default Setting 0)");
       
   686 	ifc().iString = const_cast<TDesC16*>(&ifcname);
       
   687 	ifc().iTotalEndpointsUsed = 2;
       
   688 	ifc().iClass.iClassNum	  = 0xff;						// vendor-specific
       
   689 	ifc().iClass.iSubClassNum = 0xff;						// vendor-specific
       
   690 	ifc().iClass.iProtocolNum = 0xff;						// vendor-specific
       
   691 	r = iPort.SetInterface(0, ifc, iBandwidthPriority);
       
   692 	if (r != KErrNone)
       
   693 		{
       
   694 		TUSB_PRINT1("Error %d on setting active interface", r);
       
   695 		}
       
   696 
       
   697 	// Find ep's for an alternate ifc setting.
       
   698 	// We're not really going to use it, but it gives USBCV et al. more stuff to play with.
       
   699 	if (!SupportsAlternateInterfaces())
       
   700 		{
       
   701 		TUSB_PRINT("Alternate Interfaces not supported - skipping alternate setting setup\n");
       
   702 		return KErrNone;
       
   703 		}
       
   704 	ep_found = 0;
       
   705 	TBool foundIsoIN  = EFalse;
       
   706 	TBool foundIsoOUT = EFalse;
       
   707 
       
   708 	// NB! We cannot assume that any specific device has any given set of
       
   709 	// capabilities, so whilst we try and set an assortment of endpoint types
       
   710 	// we may not get what we want.
       
   711 
       
   712 	// Also, note that the endpoint[] array in the interface descriptor
       
   713 	// must be filled from ep[0]...ep[n-1].
       
   714 
       
   715 	for (TInt i = 0; i < n; i++)
       
   716 		{
       
   717 		const TUsbcEndpointCaps* const caps = &data[i].iCaps;
       
   718 		const TInt mps = caps->MaxPacketSize();
       
   719 		if (!foundIsoIN &&
       
   720 			(caps->iTypesAndDir & (KUsbEpTypeIsochronous | KUsbEpDirIn)) ==
       
   721 			(KUsbEpTypeIsochronous | KUsbEpDirIn))
       
   722 			{
       
   723 			// This is going to be our Iso TX (IN) endpoint
       
   724 			ifc().iEndpointData[ep_found].iType  = KUsbEpTypeIsochronous;
       
   725 			ifc().iEndpointData[ep_found].iDir   = KUsbEpDirIn;
       
   726 			ifc().iEndpointData[ep_found].iSize  = mps;
       
   727 			ifc().iEndpointData[ep_found].iInterval = 0x01;	// 2^(bInterval-1)ms, bInterval must be [1..16]
       
   728 			ifc().iEndpointData[ep_found].iInterval_Hs  = 0x01;	// same as for FS
       
   729 			ifc().iEndpointData[ep_found].iExtra = 2;		// 2 extra bytes for Audio Class EP descriptor
       
   730 			foundIsoIN = ETrue;
       
   731 			if (++ep_found == 2)
       
   732 				break;
       
   733 			}
       
   734 		else if (!foundIsoOUT &&
       
   735 				 (caps->iTypesAndDir & (KUsbEpTypeIsochronous | KUsbEpDirOut)) ==
       
   736 				 (KUsbEpTypeIsochronous | KUsbEpDirOut))
       
   737 			{
       
   738 			// This is going to be our Iso RX (OUT) endpoint
       
   739 			ifc().iEndpointData[ep_found].iType  = KUsbEpTypeIsochronous;
       
   740 			ifc().iEndpointData[ep_found].iDir   = KUsbEpDirOut;
       
   741 			ifc().iEndpointData[ep_found].iSize  = mps;
       
   742 			ifc().iEndpointData[ep_found].iInterval = 0x01;	// 2^(bInterval-1)ms, bInterval must be [1..16]
       
   743 			ifc().iEndpointData[ep_found].iExtra = 2;		// 2 extra bytes for Audio Class EP descriptor
       
   744 			foundIsoOUT = ETrue;
       
   745 			if (++ep_found == 2)
       
   746 				break;
       
   747 			}
       
   748 		}
       
   749 	// Let's try to add Bulk endpoints up to the max # of 2.
       
   750 	if (ep_found < 2)
       
   751 		{
       
   752 		for (TInt i = 0; i < n; i++)
       
   753 			{
       
   754 			const TUsbcEndpointCaps* const caps = &data[i].iCaps;
       
   755 			const TUint mps = caps->MaxPacketSize();
       
   756 			if (caps->iTypesAndDir & KUsbEpTypeBulk)
       
   757 				{
       
   758 				const TUint dir = (caps->iTypesAndDir & KUsbEpDirIn) ? KUsbEpDirIn : KUsbEpDirOut;
       
   759 				ifc().iEndpointData[ep_found].iType = KUsbEpTypeBulk;
       
   760 				ifc().iEndpointData[ep_found].iDir = dir;
       
   761 				ifc().iEndpointData[ep_found].iSize = mps;
       
   762 				if (++ep_found == 2)
       
   763 					break;
       
   764 				}
       
   765 			}
       
   766 		}
       
   767 	if (ep_found == 0)
       
   768 		{
       
   769 		TUSB_PRINT("Not enough suitable endpoints found for alt ifc");
       
   770 		// not a disaster though
       
   771 		return KErrNone;
       
   772 		}
       
   773 
       
   774 	_LIT16(ifcname1, "T_USB Test Interface (Alternate Setting 1)");
       
   775 	ifc().iString = const_cast<TDesC16*>(&ifcname1);
       
   776 	ifc().iTotalEndpointsUsed = ep_found;
       
   777 	ifc().iClass.iClassNum	  = KUsbAudioInterfaceClassCode;
       
   778 	ifc().iClass.iSubClassNum = KUsbAudioInterfaceSubclassCode_Audiostreaming;
       
   779 	ifc().iClass.iProtocolNum = KUsbAudioInterfaceProtocolCode_Pr_Protocol_Undefined;
       
   780 	// Tell the driver that this setting is not interested in Ep0 requests:
       
   781 	ifc().iFeatureWord |= KUsbcInterfaceInfo_NoEp0RequestsPlease;
       
   782 	r = iPort.SetInterface(1, ifc);
       
   783 	if (r != KErrNone)
       
   784 		{
       
   785 		TUSB_PRINT1("Error %d on setting alternate interface", r);
       
   786 		}
       
   787 
       
   788 	return r;
       
   789 	}
       
   790 
       
   791 
       
   792 void CActiveConsole::AllocateEndpointDMA(TEndpointNumber aEndpoint)
       
   793 	{
       
   794 	TInt r = iPort.AllocateEndpointResource(aEndpoint, EUsbcEndpointResourceDMA);
       
   795 	if (r == KErrNone)
       
   796 		RDebug::Print(_L("DMA allocation on endpoint %d: KErrNone"), aEndpoint);
       
   797 	else if (r == KErrInUse)
       
   798 		RDebug::Print(_L("DMA allocation on endpoint %d: KErrInUse"), aEndpoint);
       
   799 	else if (r == KErrNotSupported)
       
   800 		RDebug::Print(_L("DMA allocation on endpoint %d: KErrNotSupported"), aEndpoint);
       
   801 	else
       
   802 		RDebug::Print(_L("DMA allocation on endpoint %d: unexpected return value %d"),
       
   803 					  aEndpoint, r);
       
   804 	TBool res = iPort.QueryEndpointResourceUse(aEndpoint, EUsbcEndpointResourceDMA);
       
   805 	TUSB_PRINT2("DMA on endpoint %d %s\n",
       
   806 				aEndpoint, res ? _S("allocated") : _S("not allocated"));
       
   807 
       
   808 	if ((r == KErrNone) && !res)
       
   809 		RDebug::Print(_L("(Allocation success but negative query result: contradiction!)\n"));
       
   810 	else if ((r != KErrNone) && res)
       
   811 		RDebug::Print(_L("(Allocation failure but positive query result: contradiction!)\n"));
       
   812 	}
       
   813 
       
   814 
       
   815 void CActiveConsole::DeAllocateEndpointDMA(TEndpointNumber aEndpoint)
       
   816 	{
       
   817 	TInt r = iPort.DeAllocateEndpointResource(aEndpoint, EUsbcEndpointResourceDMA);
       
   818 	if (r == KErrNone)
       
   819 		RDebug::Print(_L("DMA deallocation on endpoint %d: KErrNone"), aEndpoint);
       
   820 	else if (r == KErrNotSupported)
       
   821 		RDebug::Print(_L("DMA deallocation on endpoint %d: KErrNotSupported"), aEndpoint);
       
   822 	else
       
   823 		RDebug::Print(_L("DMA deallocation on endpoint %d: unexpected return value %d"),
       
   824 					  aEndpoint, r);
       
   825 	TBool res = iPort.QueryEndpointResourceUse(aEndpoint, EUsbcEndpointResourceDMA);
       
   826 	TUSB_PRINT2("DMA on endpoint %d %s\n",
       
   827 				aEndpoint, res ? _S("allocated") : _S("not allocated"));
       
   828 	}
       
   829 
       
   830 
       
   831 void CActiveConsole::AllocateDoubleBuffering(TEndpointNumber aEndpoint)
       
   832 	{
       
   833 	TInt r = iPort.AllocateEndpointResource(aEndpoint, EUsbcEndpointResourceDoubleBuffering);
       
   834 	if (r == KErrNone)
       
   835 		RDebug::Print(_L("Double Buffering allocation on endpoint %d: KErrNone"), aEndpoint);
       
   836 	else if (r == KErrInUse)
       
   837 		RDebug::Print(_L("Double Buffering allocation on endpoint %d: KErrInUse"), aEndpoint);
       
   838 	else if (r == KErrNotSupported)
       
   839 		RDebug::Print(_L("Double Buffering allocation on endpoint %d: KErrNotSupported"), aEndpoint);
       
   840 	else
       
   841 		RDebug::Print(_L("Double Buffering allocation on endpoint %d: unexpected return value %d"),
       
   842 					  aEndpoint, r);
       
   843 	TBool res = iPort.QueryEndpointResourceUse(aEndpoint, EUsbcEndpointResourceDoubleBuffering);
       
   844 	TUSB_PRINT2("Double Buffering on endpoint %d %s\n",
       
   845 				aEndpoint, res ? _S("allocated") : _S("not allocated"));
       
   846 
       
   847 	if ((r == KErrNone) && !res)
       
   848 		RDebug::Print(_L("(Allocation success but negative query result: contradiction!)\n"));
       
   849 	else if ((r != KErrNone) && res)
       
   850 		RDebug::Print(_L("(Allocation failure but positive query result: contradiction!)\n"));
       
   851 	}
       
   852 
       
   853 
       
   854 void CActiveConsole::DeAllocateDoubleBuffering(TEndpointNumber aEndpoint)
       
   855 	{
       
   856 	TInt r = iPort.DeAllocateEndpointResource(aEndpoint, EUsbcEndpointResourceDoubleBuffering);
       
   857 	if (r == KErrNone)
       
   858 		RDebug::Print(_L("Double Buffering deallocation on endpoint %d: KErrNone"), aEndpoint);
       
   859 	else if (r == KErrNotSupported)
       
   860 		RDebug::Print(_L("Double Buffering deallocation on endpoint %d: KErrNotSupported"), aEndpoint);
       
   861 	else
       
   862 		RDebug::Print(_L("Double Buffering deallocation on endpoint %d: unexpected return value %d"),
       
   863 					  aEndpoint, r);
       
   864 	TBool res = iPort.QueryEndpointResourceUse(aEndpoint, EUsbcEndpointResourceDoubleBuffering);
       
   865 	TUSB_PRINT2("Double Buffering on endpoint %d %s\n",
       
   866 				aEndpoint, res ? _S("allocated") : _S("not allocated"));
       
   867 	}
       
   868 
       
   869 
       
   870 TInt CActiveConsole::ReEnumerate()
       
   871 	{
       
   872 	TRequestStatus enum_status;
       
   873 	iPort.ReEnumerate(enum_status);
       
   874 	if (!iSoftwareConnect)
       
   875 		{
       
   876 		iConsole->Printf(_L("This device does not support software\n"));
       
   877 		iConsole->Printf(_L("disconnect/reconnect\n"));
       
   878 		iConsole->Printf(_L("Please physically unplug and replug\n"));
       
   879 		iConsole->Printf(_L("the USB cable NOW... "));
       
   880 		}
       
   881 	iConsole->Printf(_L("\n>>> START THE USBRFLCT PROGRAM ON THE HOST SIDE NOW <<<\n"));
       
   882 	User::WaitForRequest(enum_status);
       
   883 	if (enum_status != KErrNone)
       
   884 		{
       
   885 		TUSB_PRINT1("Error: Re-enumeration status = %d", enum_status.Int());
       
   886 		return KErrGeneral;
       
   887 		}
       
   888 	TUsbcDeviceState device_state =	EUsbcDeviceStateUndefined;
       
   889 	TInt r = iPort.DeviceStatus(device_state);
       
   890 	if (r != KErrNone)
       
   891 		{
       
   892 		TUSB_PRINT1("Error %d on querying device state", r);
       
   893 		}
       
   894 	else
       
   895 		{
       
   896 		TUSB_PRINT1("Current device state: %s",
       
   897 					(device_state == EUsbcDeviceStateUndefined) ? _S("Undefined") :
       
   898 					((device_state == EUsbcDeviceStateAttached) ? _S("Attached") :
       
   899 					 ((device_state == EUsbcDeviceStatePowered) ? _S("Powered") :
       
   900 					  ((device_state == EUsbcDeviceStateDefault) ? _S("Default") :
       
   901 					   ((device_state == EUsbcDeviceStateAddress) ? _S("Address") :
       
   902 						((device_state == EUsbcDeviceStateConfigured) ? _S("Configured") :
       
   903 						 ((device_state == EUsbcDeviceStateSuspended) ? _S("Suspended") :
       
   904 						  _S("Unknown"))))))));
       
   905 		}
       
   906 
       
   907 	// Check the speed of the established physical USB connection
       
   908 	iHighSpeed = iPort.CurrentlyUsingHighSpeed();
       
   909 	if (iHighSpeed)
       
   910 		{
       
   911 		TUSB_PRINT("---> USB High-speed Testing\n");
       
   912 		// It can only be 512 bytes when using high-speed.
       
   913 		iRW->SetMaxPacketSize(512);							// iRW already exists at this point
       
   914 		}
       
   915 	else
       
   916 		{
       
   917 		TUSB_PRINT("---> USB Full-speed Testing\n");
       
   918 		// We only support 64 bytes when using full-speed.
       
   919 		iRW->SetMaxPacketSize(64);							// iRW already exists at this point
       
   920 		}
       
   921 
       
   922 	return KErrNone;
       
   923 	}
       
   924 
       
   925 
       
   926 #ifdef test
       
   927 #undef test
       
   928 #endif
       
   929 #define test(x) \
       
   930 	do { \
       
   931 		if (!(x)) \
       
   932 			{ \
       
   933 			TUSB_PRINT1("Failure occurred!	- on line %d", __LINE__); \
       
   934 			return KErrGeneral; \
       
   935 			} \
       
   936 	} while (0)
       
   937 
       
   938 
       
   939 TInt CActiveConsole::SetupDescriptors()
       
   940 	{
       
   941 	// === Device Descriptor
       
   942 
       
   943 	TInt deviceDescriptorSize = 0;
       
   944 	iPort.GetDeviceDescriptorSize(deviceDescriptorSize);
       
   945 	test(static_cast<TUint>(deviceDescriptorSize) == KUsbDescSize_Device);
       
   946 
       
   947 	TBuf8<KUsbDescSize_Device> deviceDescriptor;
       
   948 	TInt r = iPort.GetDeviceDescriptor(deviceDescriptor);
       
   949 	test(r == KErrNone);
       
   950 
       
   951 	const TInt KUsbSpecOffset = 2;
       
   952 	const TInt KUsbVendorIdOffset = 8;
       
   953 	const TInt KUsbProductIdOffset = 10;
       
   954 	const TInt KUsbDevReleaseOffset = 12;
       
   955 	// Change the USB spec number to 2.00
       
   956 	deviceDescriptor[KUsbSpecOffset]   = 0x00;
       
   957 	deviceDescriptor[KUsbSpecOffset+1] = 0x02;
       
   958 	// Change the device vendor ID (VID) to 0x0E22 (Symbian)
       
   959 	deviceDescriptor[KUsbVendorIdOffset]   = 0x22;			// little endian!
       
   960 	deviceDescriptor[KUsbVendorIdOffset+1] = 0x0E;
       
   961 	// Change the device product ID (PID) to 0x1111
       
   962 	deviceDescriptor[KUsbProductIdOffset]	= 0x11;
       
   963 	deviceDescriptor[KUsbProductIdOffset+1] = 0x11;
       
   964 	// Change the device release number to 3.05
       
   965 	deviceDescriptor[KUsbDevReleaseOffset]	 = 0x05;
       
   966 	deviceDescriptor[KUsbDevReleaseOffset+1] = 0x03;
       
   967 	r = iPort.SetDeviceDescriptor(deviceDescriptor);
       
   968 	test(r == KErrNone);
       
   969 
       
   970 	const TUint16 Vid = (((TUint16)deviceDescriptor[KUsbVendorIdOffset + 1] << 8) & 0xff00) |
       
   971 		deviceDescriptor[KUsbVendorIdOffset];
       
   972 	const TUint16 Pid = (((TUint16)deviceDescriptor[KUsbProductIdOffset + 1] << 8) & 0xff00) |
       
   973 		deviceDescriptor[KUsbProductIdOffset];
       
   974 
       
   975 	TUSB_PRINT6("\nVID = 0x%04X / PID = 0x%04X / DevRel = %d%d.%d%d\n", Vid, Pid,
       
   976 				((deviceDescriptor[KUsbDevReleaseOffset + 1] >> 4) & 0x0f),
       
   977 				(deviceDescriptor[KUsbDevReleaseOffset + 1] & 0x0f),
       
   978 				((deviceDescriptor[KUsbDevReleaseOffset] >> 4) & 0x0f),
       
   979 				(deviceDescriptor[KUsbDevReleaseOffset] & 0x0f));
       
   980 
       
   981 	// === Configuration Descriptor
       
   982 
       
   983 	TInt configDescriptorSize = 0;
       
   984 	iPort.GetConfigurationDescriptorSize(configDescriptorSize);
       
   985 	test(static_cast<TUint>(configDescriptorSize) == KUsbDescSize_Config);
       
   986 
       
   987 	TBuf8<KUsbDescSize_Config> configDescriptor;
       
   988 	r = iPort.GetConfigurationDescriptor(configDescriptor);
       
   989 	test(r == KErrNone);
       
   990 
       
   991 	// Change the reported max power to 100mA (= 2 * 0x32),
       
   992 	// which is the highest value allowed for a bus-powered device.
       
   993 	const TInt KUsbMaxPowerOffset = 8;
       
   994 	configDescriptor[KUsbMaxPowerOffset] = 0x32;
       
   995 	r = iPort.SetConfigurationDescriptor(configDescriptor);
       
   996 	test(r == KErrNone);
       
   997 
       
   998 	// === String Descriptors
       
   999 
       
  1000 	// Set up two arbitrary string descriptors, which can be queried
       
  1001 	// manually from the host side for testing purposes (for instance
       
  1002 	// using 'usbcheck').
       
  1003 
       
  1004 	_LIT16(string_one, "Arbitrary String Descriptor Test String 1");
       
  1005 	TBuf16<KUsbStringDescStringMaxSize / 2> wr_str(string_one);
       
  1006 	r = iPort.SetStringDescriptor(stridx1, wr_str);
       
  1007 	test(r == KErrNone);
       
  1008 
       
  1009 	_LIT16(string_two, "Another Arbitrary String Descriptor Test String");
       
  1010 	wr_str.FillZ(wr_str.MaxLength());
       
  1011 	wr_str = string_two;
       
  1012 	r = iPort.SetStringDescriptor(stridx2, wr_str);
       
  1013 	test(r == KErrNone);
       
  1014 
       
  1015 	return KErrNone;
       
  1016 	}
       
  1017 
       
  1018 
       
  1019 //
       
  1020 // --- class CActiveRW ---------------------------------------------------------
       
  1021 //
       
  1022 
       
  1023 CActiveRW::CActiveRW(CConsoleBase* aConsole, RDevUsbcClient* aPort, TBool aVerboseOutput)
       
  1024 	: CActive(EPriorityNormal),
       
  1025 	  iConsole(aConsole),
       
  1026 	  iPort(aPort),
       
  1027 	  iBufSz(KInitialBufSz),
       
  1028 	  iMaxBufSz(KInitialBufSz),
       
  1029 	  iMaxPktSz(0),
       
  1030 	  iCurrentXfer(ENone),
       
  1031 	  iXferMode(::ENone),
       
  1032 	  iDoStop(EFalse),
       
  1033 	  iPktNum(~0),
       
  1034 	  iVerbose(aVerboseOutput)
       
  1035 	{
       
  1036 	TUSB_VERBOSE_PRINT("CActiveRW::CActiveRW()");
       
  1037 	}
       
  1038 
       
  1039 
       
  1040 CActiveRW* CActiveRW::NewL(CConsoleBase* aConsole, RDevUsbcClient* aPort, TBool aVerboseOutput)
       
  1041 	{
       
  1042 	CActiveRW* self = new (ELeave) CActiveRW(aConsole, aPort, aVerboseOutput);
       
  1043 	CleanupStack::PushL(self);
       
  1044 	self->ConstructL();
       
  1045 	CActiveScheduler::Add(self);
       
  1046 	CleanupStack::Pop();									// self
       
  1047 	return self;
       
  1048 	}
       
  1049 
       
  1050 
       
  1051 void CActiveRW::ConstructL()
       
  1052 	{
       
  1053 	TUSB_VERBOSE_PRINT("CActiveRW::ConstructL()");
       
  1054 
       
  1055 	User::LeaveIfError(iFs.Connect());
       
  1056 
       
  1057 	// Prepare Preamble buffer
       
  1058 	iPreambleBuf.SetMax();
       
  1059 	iPreambleBuf.FillZ();
       
  1060 
       
  1061 	// Prepare IN data buffer
       
  1062 	iWriteBuf.SetMax();
       
  1063 	for (TInt i = 0; i < iWriteBuf.MaxSize(); i++)
       
  1064 		{
       
  1065 		iWriteBuf[i] = i;
       
  1066 		}
       
  1067 
       
  1068 	// Prepare OUT data buffer
       
  1069 	iReadBuf.SetMax();
       
  1070 
       
  1071 	// Create read timeout timer active object (but don't activate it yet)
       
  1072 	iTimeoutTimer = CActiveTimer::NewL(iConsole, iPort, iVerbose);
       
  1073 	if (!iTimeoutTimer)
       
  1074 		{
       
  1075 		TUSB_PRINT("Failed to create timeout timer");
       
  1076 		}
       
  1077 	}
       
  1078 
       
  1079 
       
  1080 CActiveRW::~CActiveRW()
       
  1081 	{
       
  1082 	TUSB_VERBOSE_PRINT("CActiveRW::~CActiveRW()");
       
  1083 	Cancel();												// base class
       
  1084 	delete iTimeoutTimer;
       
  1085 	iFile.Close();
       
  1086 	iFs.Close();
       
  1087 	}
       
  1088 
       
  1089 
       
  1090 void CActiveRW::SetMaxBufSize(TInt aBufSz)
       
  1091 	{
       
  1092 	if (aBufSz > KMaxBufSize)
       
  1093 		{
       
  1094 		TUSB_PRINT2("SetMaxBufSize(): too large: %d! (using %d)", aBufSz, KMaxBufSize);
       
  1095 		aBufSz = KMaxBufSize;
       
  1096 		}
       
  1097 	iMaxBufSz = aBufSz;
       
  1098 	}
       
  1099 
       
  1100 
       
  1101 void CActiveRW::SetMaxPacketSize(TInt aPktSz)
       
  1102 	{
       
  1103 	iMaxPktSz = aPktSz;
       
  1104 	}
       
  1105 
       
  1106 
       
  1107 TInt CActiveRW::MaxBufSize() const
       
  1108 	{
       
  1109 	return iMaxBufSz;
       
  1110 	}
       
  1111 
       
  1112 
       
  1113 void CActiveRW::SetTransferMode(TXferMode aMode)
       
  1114 	{
       
  1115 	iXferMode = aMode;
       
  1116 	if (aMode == EReceiveOnly || aMode == ETransmitOnly)
       
  1117 		{
       
  1118 		// For streaming transfers we do this only once.
       
  1119 		iBufSz = iMaxBufSz;
       
  1120 		}
       
  1121 	}
       
  1122 
       
  1123 
       
  1124 void CActiveRW::RunL()
       
  1125 	{
       
  1126 	TUSB_VERBOSE_PRINT("CActiveRW::RunL()");
       
  1127 	if (iStatus != KErrNone)
       
  1128 		{
       
  1129 		TUSB_PRINT1("Error %d in RunL", iStatus.Int());
       
  1130 		}
       
  1131 	if (iDoStop)
       
  1132 		{
       
  1133 		TUSB_PRINT("Stopped");
       
  1134 		iDoStop = EFalse;
       
  1135 		return;
       
  1136 		}
       
  1137 	switch (iCurrentXfer)
       
  1138 		{
       
  1139 	case EPreamble:
       
  1140 		if (iXferMode != EReceiveOnly)
       
  1141 			SendData();										// next we write data
       
  1142 		else
       
  1143 			ReadData();										// or we read data
       
  1144 		break;
       
  1145 	case EWriteXfer:
       
  1146 		if (iXferMode == ETransmitOnly)
       
  1147 			SendData();										// next we send data
       
  1148 		else
       
  1149 			ReadData();										// or we read data
       
  1150 		break;
       
  1151 	case EReadXfer:
       
  1152 		if (iXferMode == EReceiveOnly)
       
  1153 			{
       
  1154 			const TUint32 num = *reinterpret_cast<const TUint32*>(iReadBuf.Ptr());
       
  1155 			if (num != ++iPktNum)
       
  1156 				{
       
  1157 				TUSB_PRINT2("*** rcv'd wrong pkt number: 0x%x (expected: 0x%x)", num, iPktNum);
       
  1158 				// Update the packet number with the received number, so that
       
  1159 				// if a single packet is duplicated or lost then a single error occurs
       
  1160 				iPktNum = num;
       
  1161 				}
       
  1162 			if (iDiskAccessEnabled)
       
  1163 				{
       
  1164 				// Write out to disk previous completed Read
       
  1165 				TUSB_VERBOSE_PRINT2("iMaxBufSz = %d (iReadBuf.Size(): %d)",
       
  1166 									iMaxBufSz, iReadBuf.Size());
       
  1167 				WriteBufferToDisk(iReadBuf, iMaxBufSz);
       
  1168 				}
       
  1169 			ReadData();										// next we read data
       
  1170 			break;
       
  1171 			}
       
  1172 		if (iXferMode == ELoopComp)
       
  1173 			{
       
  1174 			if (!CompareBuffers(iBufSz))
       
  1175 				{
       
  1176 				TUSB_PRINT1("Error while comparing tx & rx buffers for packet 0x%x", iPktNum);
       
  1177 				}
       
  1178 			}
       
  1179 		else if (iBufSz > 3)
       
  1180 			{
       
  1181 			const TUint32 num = *reinterpret_cast<const TUint32*>(iReadBuf.Ptr());
       
  1182 			if (num != iPktNum)
       
  1183 				{
       
  1184 				TUSB_PRINT2("*** rcv'd wrong pkt number: 0x%x (expected: 0x%x)", num, iPktNum);
       
  1185 				}
       
  1186 			}
       
  1187 		if (iBufSz == iMaxBufSz)
       
  1188 			{
       
  1189 			iBufSz = KInitialBufSz;
       
  1190 			}
       
  1191 		else
       
  1192 			{
       
  1193 			++iBufSz;
       
  1194 			}
       
  1195 		SendPreamble();										// next we send the length
       
  1196 		break;
       
  1197 	default:
       
  1198 		TUSB_PRINT("Oops. (Shouldn't end up here...)");
       
  1199 		break;
       
  1200 		}
       
  1201 	return;
       
  1202 	}
       
  1203 
       
  1204 
       
  1205 TInt CActiveRW::SendVersion()
       
  1206 	{
       
  1207 	TUSB_VERBOSE_PRINT("CActiveRW::SendVersion()");
       
  1208 	if (iXferMode != ::ENone)
       
  1209 		{
       
  1210 		TUSB_PRINT1("Error : wrong state: %d", iXferMode);
       
  1211 		return KErrGeneral;
       
  1212 		}
       
  1213 	// Here we send our version packet to the host.
       
  1214 	// (We can use the preamble buffer because we only need it
       
  1215 	//  once and that's also before the preamble uses.)
       
  1216 	TUSB_PRINT1("Sending T_USB version: %d\n", KTusbVersion);
       
  1217 	iPreambleBuf.FillZ();
       
  1218 	*reinterpret_cast<TUint32*>(&iPreambleBuf[0]) = SWAP_BYTES_32(KTusbVersion);
       
  1219 	// A 'magic' string so that USBRFLCT doesn't interpret the first 4 bytes
       
  1220 	// of a data preamble packet of an old T_USB as the version number.
       
  1221 	iPreambleBuf[4] = 'V';
       
  1222 	iPreambleBuf[5] = 'e';
       
  1223 	iPreambleBuf[6] = 'r';
       
  1224 	iPreambleBuf[7] = 's';
       
  1225 	TRequestStatus send_status;
       
  1226 	iPort->Write(send_status, EEndpoint1, iPreambleBuf, KPreambleLength);
       
  1227 	TUSB_VERBOSE_PRINT("Waiting for write request to complete...");
       
  1228 	User::WaitForRequest(send_status);
       
  1229 	TUSB_VERBOSE_PRINT("...done.\n");
       
  1230 	return send_status.Int();
       
  1231 	}
       
  1232 
       
  1233 
       
  1234 TInt CActiveRW::ReceiveVersion()
       
  1235 	{
       
  1236 	TUSB_VERBOSE_PRINT("CActiveRW::ReceiveVersion()");
       
  1237 	if (iXferMode != ::ENone)
       
  1238 		{
       
  1239 		TUSB_PRINT1("Error : wrong state: %d", iXferMode);
       
  1240 		return KErrGeneral;
       
  1241 		}
       
  1242 	// Here we try to receive a version packet from the host.
       
  1243 	// (We can use the preamble buffer because we only need it
       
  1244 	//  once and that's also before the preamble uses.)
       
  1245 	TUSB_PRINT("Getting host program versions...");
       
  1246 	iPreambleBuf.FillZ();
       
  1247 	TRequestStatus receive_status;
       
  1248 	iPort->Read(receive_status, EEndpoint2, iPreambleBuf, KPreambleLength);
       
  1249 	TUSB_VERBOSE_PRINT("Waiting for read request to complete...");
       
  1250 	iTimeoutTimer->Activate(5000000);						// Host gets 5s
       
  1251 	User::WaitForRequest(receive_status, iTimeoutTimer->iStatus);
       
  1252 	if (receive_status == KRequestPending)
       
  1253 		{
       
  1254 		// Read() still pending...
       
  1255 		TUSB_PRINT("Cancelling USB Read(): no response from host.\n");
       
  1256 		iPort->ReadCancel(EEndpoint2);
       
  1257 		TUSB_PRINT("THIS COULD BE DUE TO AN OLD VERSION OF USBRFLCT ON THE PC:");
       
  1258 		TUSB_PRINT3("PLEASE CHECK THE VERSION THERE - WE NEED AT LEAST V%d.%d.%d!\n",
       
  1259 					KUsbrflctVersionMajor, KUsbrflctVersionMinor, KUsbrflctVersionMicro);
       
  1260 		TUSB_PRINT("When updating an existing USBRFLCT installation <= v1.3.1,\n" \
       
  1261 				   L"the following three things will need to be done:\n");
       
  1262 		TUSB_PRINT("1. Connect the device to the PC & start T_USB (just as now),\n" \
       
  1263 				   L"then find the USB device in the Windows Device Manager\n" \
       
  1264 				   L"('Control Panel'->'System'->'Hardware'->'Device Manager').\n" \
       
  1265 				   L"Right click on the device name and choose 'Uninstall...'.\n");
       
  1266 		TUSB_PRINT("2. In c:\\winnt\\inf\\, find (by searching for \"Symbian\") and\n" \
       
  1267 				   L"delete the *.INF file that was used to install the existing\n" \
       
  1268 				   L"version of USBRFLCT.SYS. Make sure to also delete the\n" \
       
  1269 				   L"precompiled version of that file (<samename>.PNF).\n");
       
  1270 		TUSB_PRINT("3. In c:\\winnt\\system32\\drivers\\, delete the file USBRFLCT.SYS.\n");
       
  1271 		TUSB_PRINT("Then unplug & reconnect the USB device and, when prompted, install\n" \
       
  1272 				   L"the new USBRFLCT.SYS driver using the .INF file from this distribution.\n" \
       
  1273 				   L"(All files can be found under e32test\\win32\\usbrflct_distribution\\.)\n");
       
  1274 		TUSB_PRINT("Use the new USBRFLCT.EXE from this distribution.\n");
       
  1275 		}
       
  1276 	else
       
  1277 		{
       
  1278 		TUSB_VERBOSE_PRINT("...done.");
       
  1279 		// Timeout not needed any longer
       
  1280 		TUSB_VERBOSE_PRINT("Cancelling timeout timer: USB Read() completed.\n");
       
  1281 		iTimeoutTimer->Cancel();
       
  1282 		}
       
  1283 	return receive_status.Int();
       
  1284 	}
       
  1285 
       
  1286 
       
  1287 TInt CActiveRW::ExchangeVersions()
       
  1288 	{
       
  1289 	TUSB_VERBOSE_PRINT("CActiveRW::ExchangeVersions()");
       
  1290 	// First check the version of USBRFLCT that's running on the host
       
  1291 	TInt r = ReceiveVersion();
       
  1292 	if (r != KErrNone)
       
  1293 		{
       
  1294 		return KErrGeneral;
       
  1295 		}
       
  1296 	TUint8 usbrflct_ver_major = iPreambleBuf[0];
       
  1297 	TUint8 usbrflct_ver_minor = iPreambleBuf[1];
       
  1298 	TUint8 usbrflct_ver_micro = iPreambleBuf[2];
       
  1299 	TUint8 usbio_ver_major = iPreambleBuf[3];
       
  1300 	TUint8 usbio_ver_minor = iPreambleBuf[4];
       
  1301 	TUSB_PRINT5("Host-side: USBRFLCT v%d.%d.%d  USBIO v%d.%d\n",
       
  1302 				usbrflct_ver_major, usbrflct_ver_minor, usbrflct_ver_micro,
       
  1303 				usbio_ver_major, usbio_ver_minor);
       
  1304 	if (usbrflct_ver_major < KUsbrflctVersionMajor)
       
  1305 		{
       
  1306 		TUSB_PRINT1("USBRFLCT version not sufficient (need at least v%d.x.x)\n",
       
  1307 					KUsbrflctVersionMajor);
       
  1308 		return KErrGeneral;
       
  1309 		}
       
  1310 	// Just using '<' instead of the seemingly absurd '<= && !==' doesn't work without
       
  1311 	// GCC compiler warning because Kxxx can also be zero (in which case there's no '<').
       
  1312 	else if ((usbrflct_ver_minor <= KUsbrflctVersionMinor) &&
       
  1313 			 !(usbrflct_ver_minor == KUsbrflctVersionMinor))
       
  1314 		{
       
  1315 		TUSB_PRINT2("USBRFLCT version not sufficient (need at least v%d.%d.x)\n",
       
  1316 					KUsbrflctVersionMajor, KUsbrflctVersionMinor);
       
  1317 		return KErrGeneral;
       
  1318 		}
       
  1319 	// Just using '<' instead of the seemingly absurd '<= && !==' doesn't work without
       
  1320 	// GCC compiler warning because Kxxx can also be zero (in which case there's no '<').
       
  1321 	else if ((usbrflct_ver_micro <= KUsbrflctVersionMicro) &&
       
  1322 			 !(usbrflct_ver_micro == KUsbrflctVersionMicro))
       
  1323 		{
       
  1324 		TUSB_PRINT3("USBRFLCT version not sufficient (need at least v%d.%d.%d)\n",
       
  1325 					KUsbrflctVersionMajor, KUsbrflctVersionMinor, KUsbrflctVersionMicro);
       
  1326 		return KErrGeneral;
       
  1327 		}
       
  1328 	// Now we send T_USB's version to the host
       
  1329 	r = SendVersion();
       
  1330 	if (r != KErrNone)
       
  1331 		{
       
  1332 		return KErrGeneral;
       
  1333 		}
       
  1334 	return KErrNone;
       
  1335 	}
       
  1336 
       
  1337 
       
  1338 void CActiveRW::SendPreamble()
       
  1339 	{
       
  1340 	TUSB_VERBOSE_PRINT("CActiveRW::SendPreamble()");
       
  1341 	__ASSERT_ALWAYS(!IsActive(), User::Panic(KActivePanic, 666));
       
  1342 	TUSB_VERBOSE_PRINT1("Sending data length: %d bytes", iBufSz);
       
  1343 	*reinterpret_cast<TUint32*>(&iPreambleBuf[0]) = SWAP_BYTES_32(iBufSz);
       
  1344 	iPort->Write(iStatus, EEndpoint1, iPreambleBuf, KPreambleLength);
       
  1345 	iCurrentXfer = EPreamble;
       
  1346 	SetActive();
       
  1347 	}
       
  1348 
       
  1349 
       
  1350 void CActiveRW::SendData()
       
  1351 	{
       
  1352 	TUSB_VERBOSE_PRINT("CActiveRW::SendData()");
       
  1353 	__ASSERT_ALWAYS(!IsActive(), User::Panic(KActivePanic, 666));
       
  1354 	if (iDiskAccessEnabled)
       
  1355 		{
       
  1356 		ReadBufferFromDisk(iWriteBuf, iBufSz);
       
  1357 		}
       
  1358 	++iPktNum;
       
  1359 	if (iBufSz > 3)
       
  1360 		{
       
  1361 		*reinterpret_cast<TUint32*>(const_cast<TUint8*>(iWriteBuf.Ptr())) = iPktNum;
       
  1362 		}
       
  1363 	if (iXferMode == ELoopComp)
       
  1364 		{
       
  1365 		for (TInt i = 4; i < iBufSz; i++)
       
  1366 			{
       
  1367 			iWriteBuf[i] = static_cast<TUint8>(iPktNum & 0x000000ff);
       
  1368 			}
       
  1369 		}
       
  1370 	TUSB_VERBOSE_PRINT1("Sending data: %d bytes", iBufSz);
       
  1371 	iPort->Write(iStatus, EEndpoint1, iWriteBuf, iBufSz);
       
  1372 	iCurrentXfer = EWriteXfer;
       
  1373 	SetActive();
       
  1374 	}
       
  1375 
       
  1376 
       
  1377 TInt CActiveRW::SelectDrive()
       
  1378 	{
       
  1379 	TDriveList driveList;
       
  1380 	TInt r = iFs.DriveList(driveList);
       
  1381 	if (r != KErrNone)
       
  1382 		{
       
  1383 		TUSB_PRINT1("RFs::DriveList() returned %d", r);
       
  1384 		return r;
       
  1385 		}
       
  1386 	TUSB_PRINT("Available drives:");
       
  1387 	for (TInt n = 0; n < KMaxDrives; n++)
       
  1388 		{
       
  1389 		if (driveList[n] != 0)
       
  1390 			{
       
  1391 			TVolumeInfo volumeInfo;
       
  1392 			r = iFs.Volume(volumeInfo, n);
       
  1393 			if (r == KErrNone)
       
  1394 				{
       
  1395 				TPtr name(volumeInfo.iName.Des());
       
  1396 				TUSB_PRINT2("Drive %c: %- 16S", 'A' + n, &name);
       
  1397 				if (volumeInfo.iDrive.iMediaAtt & KMediaAttWriteProtected)
       
  1398 					TUSB_PRINT("  (read-only)");
       
  1399 				TUSB_PRINT("");
       
  1400 				}
       
  1401 			}
       
  1402 		}
       
  1403 	iConsole->Printf(_L("Please select a drive letter (or 'Q' to quit)..."));
       
  1404 	TChar driveLetter;
       
  1405 	TInt driveNumber;
       
  1406 	TVolumeInfo volumeInfo;
       
  1407 	do
       
  1408 		{
       
  1409 		driveLetter = (TUint)iConsole->Getch();
       
  1410 		driveLetter.UpperCase();
       
  1411 		if (driveLetter == 'Q')
       
  1412 			{
       
  1413 			return KErrCancel;
       
  1414 			}
       
  1415 		driveNumber = (TUint)driveLetter - 'A';
       
  1416 		r = iFs.Volume(volumeInfo, driveNumber);
       
  1417 		}
       
  1418 	while ((driveNumber < 0) ||
       
  1419 		   (driveNumber >= KMaxDrives) ||
       
  1420 		   (r) ||
       
  1421 		   (driveList[driveNumber] == 0) ||
       
  1422 		   (volumeInfo.iDrive.iMediaAtt & KMediaAttWriteProtected));
       
  1423 
       
  1424 	iFileName.Format(_L("%c:"), driveLetter.operator TUint());
       
  1425 	iFileName.Append(KFileName);
       
  1426 	TUSB_PRINT1("\nFilename = %S", &iFileName);
       
  1427 	TUSB_PRINT1("File size: %d", KMaxFileSize);
       
  1428 	return r;
       
  1429 	}
       
  1430 
       
  1431 
       
  1432 TInt CActiveRW::WriteToDisk(TBool aEnable)
       
  1433 	{
       
  1434 	iDiskAccessEnabled = aEnable;
       
  1435 	TInt r = KErrNone;
       
  1436 
       
  1437 	if (iDiskAccessEnabled)
       
  1438 		{
       
  1439 		r = SelectDrive();
       
  1440 		if (r != KErrNone)
       
  1441 			{
       
  1442 			iDiskAccessEnabled = EFalse;
       
  1443 			return r;
       
  1444 			}
       
  1445 		// open the record file
       
  1446 		r = iFile.Replace(iFs, iFileName, EFileWrite);
       
  1447 		iFileOffset = 0;
       
  1448 		}
       
  1449 	return r;
       
  1450 	}
       
  1451 
       
  1452 
       
  1453 TInt CActiveRW::ReadFromDisk(TBool aEnable)
       
  1454 	{
       
  1455 	iDiskAccessEnabled = aEnable;
       
  1456 	TInt r = KErrNone;
       
  1457 
       
  1458 	if (iDiskAccessEnabled)
       
  1459 		{
       
  1460 		r = SelectDrive();
       
  1461 		if (r != KErrNone)
       
  1462 			{
       
  1463 			iDiskAccessEnabled = EFalse;
       
  1464 			return r;
       
  1465 			}
       
  1466 		// First create the file & fill it
       
  1467 		r = iFile.Replace(iFs, iFileName, EFileWrite);
       
  1468 		if (r != KErrNone)
       
  1469 			{
       
  1470 			TUSB_PRINT1("RFile::Replace() returned %d", r);
       
  1471 			iDiskAccessEnabled = EFalse;
       
  1472 			return r;
       
  1473 			}
       
  1474 		const TInt KBufferSize = 4 * 1024;
       
  1475 		TBuf8<KBufferSize> buffer;
       
  1476 		buffer.SetLength(KBufferSize);
       
  1477 		for (TInt n = 0; n < KBufferSize; n++)
       
  1478 			{
       
  1479 			buffer[n] = static_cast<TUint8>(n & 0x000000ff);
       
  1480 			}
       
  1481 		TUSB_PRINT("Writing data to file (this may take some minutes...)");
       
  1482 		for (TInt n = 0; n < KMaxFileSize; n += KBufferSize)
       
  1483 			{
       
  1484 			r = iFile.Write(buffer, KBufferSize);
       
  1485 			if (r != KErrNone)
       
  1486 				{
       
  1487 				TUSB_PRINT1("RFile::Write() returned %d (disk full?)", r);
       
  1488 				iFile.Close();
       
  1489 				iDiskAccessEnabled = EFalse;
       
  1490 				return r;
       
  1491 				}
       
  1492 			}
       
  1493 		TUSB_PRINT("Done.");
       
  1494 		iFile.Close();
       
  1495 		// Now open the file for reading
       
  1496 		r = iFile.Open(iFs, iFileName, EFileRead);
       
  1497 		if (r != KErrNone)
       
  1498 			{
       
  1499 			TUSB_PRINT1("RFile::Open() returned %d", r);
       
  1500 			iDiskAccessEnabled = EFalse;
       
  1501 			return r;
       
  1502 			}
       
  1503 		iFileOffset = 0;
       
  1504 		}
       
  1505 	return r;
       
  1506 	}
       
  1507 
       
  1508 
       
  1509 void CActiveRW::WriteBufferToDisk(TDes8& aBuffer, TInt aLen)
       
  1510 	{
       
  1511 	TUSB_VERBOSE_PRINT1("CActiveRW::WriteBufferToDisk(), len = %d", aLen);
       
  1512 	TInt r = iFile.Write(aBuffer, aLen);
       
  1513 	if (r != KErrNone)
       
  1514 		{
       
  1515 		TUSB_PRINT2("Error writing to %S (%d)", &iFileName, r);
       
  1516 		iDiskAccessEnabled = EFalse;
       
  1517 		return;
       
  1518 		}
       
  1519 	iFileOffset += aLen;
       
  1520 	if (iFileOffset >= KMaxFileSize)
       
  1521 		{
       
  1522 		iFileOffset = 0;
       
  1523 		iFile.Seek(ESeekStart, iFileOffset);
       
  1524 		}
       
  1525 	}
       
  1526 
       
  1527 
       
  1528 void CActiveRW::ReadBufferFromDisk(TDes8& aBuffer, TInt aLen)
       
  1529 	{
       
  1530 	if (iFileOffset + aLen >= KMaxFileSize)
       
  1531 		{
       
  1532 		iFileOffset = 0;
       
  1533 		iFile.Seek(ESeekStart, iFileOffset);
       
  1534 		}
       
  1535 	const TInt r = iFile.Read(aBuffer, aLen);
       
  1536 	if (r != KErrNone)
       
  1537 		{
       
  1538 		TUSB_PRINT2("Error reading from %S (%d)", &iFileName, r);
       
  1539 		iDiskAccessEnabled = EFalse;
       
  1540 		return;
       
  1541 		}
       
  1542 	TInt readLen = aBuffer.Length();
       
  1543 	TUSB_VERBOSE_PRINT1("CActiveRW::ReadBufferFromDisk(), len = %d\n", readLen);
       
  1544 	if (readLen < aLen)
       
  1545 		{
       
  1546 		TUSB_PRINT3("Only %d bytes of %d read from file %S)",
       
  1547 					readLen, aLen, &iFileName);
       
  1548 		iDiskAccessEnabled = EFalse;
       
  1549 		return;
       
  1550 		}
       
  1551 	iFileOffset += aLen;
       
  1552 	}
       
  1553 
       
  1554 
       
  1555 void CActiveRW::ReadData()
       
  1556 	{
       
  1557 	TUSB_VERBOSE_PRINT("CActiveRW::ReadData()");
       
  1558 	__ASSERT_ALWAYS(!IsActive(), User::Panic(KActivePanic, 666));
       
  1559 	TUSB_VERBOSE_PRINT1("Reading data: %d bytes", iBufSz);
       
  1560 	if (iXferMode == EReceiveOnly)
       
  1561 		{
       
  1562 		TUSB_VERBOSE_PRINT("  (rx only)");
       
  1563 		iPort->Read(iStatus, EEndpoint2, iReadBuf, iBufSz);
       
  1564 		}
       
  1565 	else if (iBufSz == iMaxPktSz)
       
  1566 		{
       
  1567 		// we also want to test the packet version of Read()
       
  1568 		TUSB_VERBOSE_PRINT("  (a single packet)");
       
  1569 		iPort->ReadPacket(iStatus, EEndpoint2, iReadBuf, iBufSz);
       
  1570 		}
       
  1571 	else if (iBufSz == iReadBuf.MaxSize())
       
  1572 		{
       
  1573 		// or we could perhaps test the three-parameter version
       
  1574 		TUSB_VERBOSE_PRINT("  (w/o length)");
       
  1575 		iPort->Read(iStatus, EEndpoint2, iReadBuf);
       
  1576 		}
       
  1577 	else
       
  1578 		{
       
  1579 		// otherwise, we use the universal default version
       
  1580 		TUSB_VERBOSE_PRINT("  (normal)");
       
  1581 		iPort->Read(iStatus, EEndpoint2, iReadBuf, iBufSz);
       
  1582 		}
       
  1583 	iCurrentXfer = EReadXfer;
       
  1584 	SetActive();
       
  1585 	}
       
  1586 
       
  1587 
       
  1588 void CActiveRW::Stop()
       
  1589 	{
       
  1590 	if (!IsActive())
       
  1591 		{
       
  1592 		TUSB_PRINT("CActiveRW::Stop(): Not active");
       
  1593 		return;
       
  1594 		}
       
  1595 	TUSB_PRINT("Cancelling outstanding transfer requests\n");
       
  1596 	iBufSz = KInitialBufSz;
       
  1597 	iPktNum = ~0;
       
  1598 	iDoStop = ETrue;
       
  1599 	iCurrentXfer = ENone;
       
  1600 	Cancel();
       
  1601 	}
       
  1602 
       
  1603 
       
  1604 void CActiveRW::DoCancel()
       
  1605 	{
       
  1606 	TUSB_VERBOSE_PRINT("CActiveRW::DoCancel()");
       
  1607 	// Canceling the transfer requests can be done explicitly
       
  1608 	// for every transfer...
       
  1609 	iPort->WriteCancel(EEndpoint1);
       
  1610 	iPort->ReadCancel(EEndpoint2);
       
  1611 	// or like this:
       
  1612 	iPort->EndpointTransferCancel(~0);
       
  1613 	}
       
  1614 
       
  1615 
       
  1616 TBool CActiveRW::CompareBuffers(TInt aLen)
       
  1617 	{
       
  1618 	TUSB_VERBOSE_PRINT1("CActiveRW::CompareBuffers(%d)", aLen);
       
  1619 	for (TInt i = 0; i < aLen; i++)
       
  1620 		{
       
  1621 		if (iReadBuf[i] != iWriteBuf[i])
       
  1622 			{
       
  1623 			TUSB_VERBOSE_PRINT1("Error: for i = %d:", i);
       
  1624 			TUSB_VERBOSE_PRINT2("iReadBuf: %d != iWriteBuf: %d",
       
  1625 								iReadBuf[i], iWriteBuf[i]);
       
  1626 			return EFalse;
       
  1627 			}
       
  1628 		}
       
  1629 	return ETrue;
       
  1630 	}
       
  1631 
       
  1632 
       
  1633 //
       
  1634 // --- class CActiveStallNotifier ---------------------------------------------------------
       
  1635 //
       
  1636 
       
  1637 CActiveStallNotifier::CActiveStallNotifier(CConsoleBase* aConsole, RDevUsbcClient* aPort,
       
  1638 										   TBool aVerboseOutput)
       
  1639 	: CActive(EPriorityNormal),
       
  1640 	  iConsole(aConsole),
       
  1641 	  iPort(aPort),
       
  1642 	  iEndpointState(0),
       
  1643 	  iVerbose(aVerboseOutput)
       
  1644 	{
       
  1645 	CActiveScheduler::Add(this);
       
  1646 	}
       
  1647 
       
  1648 CActiveStallNotifier* CActiveStallNotifier::NewL(CConsoleBase* aConsole, RDevUsbcClient* aPort,
       
  1649 												 TBool aVerboseOutput)
       
  1650 	{
       
  1651 	CActiveStallNotifier* self = new (ELeave) CActiveStallNotifier(aConsole, aPort, aVerboseOutput);
       
  1652 	CleanupStack::PushL(self);
       
  1653 	self->ConstructL();
       
  1654 	CleanupStack::Pop();									// self
       
  1655 	return self;
       
  1656 	}
       
  1657 
       
  1658 
       
  1659 void CActiveStallNotifier::ConstructL()
       
  1660 	{}
       
  1661 
       
  1662 
       
  1663 CActiveStallNotifier::~CActiveStallNotifier()
       
  1664 	{
       
  1665 	TUSB_VERBOSE_PRINT("CActiveStallNotifier::~CActiveStallNotifier()");
       
  1666 	Cancel();												// base class
       
  1667 	}
       
  1668 
       
  1669 
       
  1670 void CActiveStallNotifier::DoCancel()
       
  1671 	{
       
  1672 	TUSB_VERBOSE_PRINT("CActiveStallNotifier::DoCancel()");
       
  1673 	iPort->EndpointStatusNotifyCancel();
       
  1674 	}
       
  1675 
       
  1676 
       
  1677 void CActiveStallNotifier::RunL()
       
  1678 	{
       
  1679 	// This just displays the bitmap, showing which endpoints (if any) are now stalled.
       
  1680 	// In a real world program, the user could take here appropriate action (cancel a
       
  1681 	// transfer request or whatever).
       
  1682 	TUSB_VERBOSE_PRINT1("StallNotifier: Endpointstate 0x%x\n", iEndpointState);
       
  1683 	Activate();
       
  1684 	}
       
  1685 
       
  1686 
       
  1687 void CActiveStallNotifier::Activate()
       
  1688 	{
       
  1689 	__ASSERT_ALWAYS(!IsActive(), User::Panic(KActivePanic, 666));
       
  1690 	iPort->EndpointStatusNotify(iStatus, iEndpointState);
       
  1691 	SetActive();
       
  1692 	}
       
  1693 
       
  1694 
       
  1695 //
       
  1696 // --- class CActiveDeviceStateNotifier ---------------------------------------------------------
       
  1697 //
       
  1698 
       
  1699 CActiveDeviceStateNotifier::CActiveDeviceStateNotifier(CConsoleBase* aConsole, RDevUsbcClient* aPort,
       
  1700 													   TBool aVerboseOutput)
       
  1701 	: CActive(EPriorityNormal),
       
  1702 	  iConsole(aConsole),
       
  1703 	  iPort(aPort),
       
  1704 	  iDeviceState(0),
       
  1705 	  iVerbose(aVerboseOutput)
       
  1706 	{
       
  1707 	CActiveScheduler::Add(this);
       
  1708 	}
       
  1709 
       
  1710 CActiveDeviceStateNotifier* CActiveDeviceStateNotifier::NewL(CConsoleBase* aConsole, RDevUsbcClient* aPort,
       
  1711 															 TBool aVerboseOutput)
       
  1712 	{
       
  1713 	CActiveDeviceStateNotifier* self = new (ELeave) CActiveDeviceStateNotifier(aConsole, aPort, aVerboseOutput);
       
  1714 	CleanupStack::PushL(self);
       
  1715 	self->ConstructL();
       
  1716 	CleanupStack::Pop();									// self
       
  1717 	return self;
       
  1718 	}
       
  1719 
       
  1720 
       
  1721 void CActiveDeviceStateNotifier::ConstructL()
       
  1722 	{}
       
  1723 
       
  1724 
       
  1725 CActiveDeviceStateNotifier::~CActiveDeviceStateNotifier()
       
  1726 	{
       
  1727 	TUSB_VERBOSE_PRINT("CActiveDeviceStateNotifier::~CActiveDeviceStateNotifier()");
       
  1728 	Cancel();												// base class
       
  1729 	}
       
  1730 
       
  1731 
       
  1732 void CActiveDeviceStateNotifier::DoCancel()
       
  1733 	{
       
  1734 	TUSB_VERBOSE_PRINT("CActiveDeviceStateNotifier::DoCancel()");
       
  1735 	iPort->AlternateDeviceStatusNotifyCancel();
       
  1736 	}
       
  1737 
       
  1738 
       
  1739 void CActiveDeviceStateNotifier::RunL()
       
  1740 	{
       
  1741 	// This displays the device state.
       
  1742 	// In a real world program, the user could take here appropriate action (cancel a
       
  1743 	// transfer request or whatever).
       
  1744 	if (!(iDeviceState & KUsbAlternateSetting) && iVerbose)
       
  1745 		{
       
  1746 		switch (iDeviceState)
       
  1747 			{
       
  1748 		case EUsbcDeviceStateUndefined:
       
  1749 			TUSB_PRINT("Device State notifier: Undefined");
       
  1750 			break;
       
  1751 		case EUsbcDeviceStateAttached:
       
  1752 			TUSB_PRINT("Device State notifier: Attached");
       
  1753 			break;
       
  1754 		case EUsbcDeviceStatePowered:
       
  1755 			TUSB_PRINT("Device State notifier: Powered");
       
  1756 			break;
       
  1757 		case EUsbcDeviceStateDefault:
       
  1758 			TUSB_PRINT("Device State notifier: Default");
       
  1759 			break;
       
  1760 		case EUsbcDeviceStateAddress:
       
  1761 			TUSB_PRINT("Device State notifier: Address");
       
  1762 			break;
       
  1763 		case EUsbcDeviceStateConfigured:
       
  1764 			TUSB_PRINT("Device State notifier: Configured");
       
  1765 			break;
       
  1766 		case EUsbcDeviceStateSuspended:
       
  1767 			TUSB_PRINT("Device State notifier: Suspended");
       
  1768 			break;
       
  1769 		default:
       
  1770 			TUSB_PRINT("Device State notifier: ***BAD***");
       
  1771 			}
       
  1772 		}
       
  1773 	else if (iDeviceState & KUsbAlternateSetting)
       
  1774 		{
       
  1775 		TUSB_PRINT1("Device State notifier: Alternate interface setting has changed: now %d",
       
  1776 					iDeviceState & ~KUsbAlternateSetting);
       
  1777 		}
       
  1778 	Activate();
       
  1779 	}
       
  1780 
       
  1781 
       
  1782 void CActiveDeviceStateNotifier::Activate()
       
  1783 	{
       
  1784 	__ASSERT_ALWAYS(!IsActive(), User::Panic(KActivePanic, 666));
       
  1785 	iPort->AlternateDeviceStatusNotify(iStatus, iDeviceState);
       
  1786 	SetActive();
       
  1787 	}
       
  1788 
       
  1789 
       
  1790 //
       
  1791 // --- class CActiveTimer ---------------------------------------------------------
       
  1792 //
       
  1793 
       
  1794 CActiveTimer::CActiveTimer(CConsoleBase* aConsole, RDevUsbcClient* aPort,
       
  1795 						   TBool aVerboseOutput)
       
  1796 	: CActive(EPriorityNormal),
       
  1797 	  iConsole(aConsole),
       
  1798 	  iPort(aPort),
       
  1799 	  iVerbose(aVerboseOutput)
       
  1800 	{
       
  1801 	CActiveScheduler::Add(this);
       
  1802 	}
       
  1803 
       
  1804 
       
  1805 CActiveTimer* CActiveTimer::NewL(CConsoleBase* aConsole, RDevUsbcClient* aPort,
       
  1806 								 TBool aVerboseOutput)
       
  1807 	{
       
  1808 	CActiveTimer* self = new (ELeave) CActiveTimer(aConsole, aPort, aVerboseOutput);
       
  1809 	CleanupStack::PushL(self);
       
  1810 	self->ConstructL();
       
  1811 	CleanupStack::Pop();									// self
       
  1812 	return self;
       
  1813 	}
       
  1814 
       
  1815 
       
  1816 void CActiveTimer::ConstructL()
       
  1817 	{
       
  1818 	User::LeaveIfError(iTimer.CreateLocal());
       
  1819 	}
       
  1820 
       
  1821 
       
  1822 CActiveTimer::~CActiveTimer()
       
  1823 	{
       
  1824 	TUSB_VERBOSE_PRINT("CActiveTimer::~CActiveTimer()");
       
  1825 	Cancel();												// base class
       
  1826 	iTimer.Close();
       
  1827 	}
       
  1828 
       
  1829 
       
  1830 void CActiveTimer::DoCancel()
       
  1831 	{
       
  1832 	TUSB_VERBOSE_PRINT("CActiveTimer::DoCancel()");
       
  1833 	iTimer.Cancel();
       
  1834 	}
       
  1835 
       
  1836 
       
  1837 void CActiveTimer::RunL()
       
  1838 	{
       
  1839 	TUSB_VERBOSE_PRINT("CActiveTimer::RunL()");
       
  1840 	// Nothing to do here, as we call ReadCancel() after a manual WaitForRequest()
       
  1841 	// (in CActiveRW::ReceiveVersion()).
       
  1842 	}
       
  1843 
       
  1844 
       
  1845 void CActiveTimer::Activate(TTimeIntervalMicroSeconds32 aDelay)
       
  1846 	{
       
  1847 	__ASSERT_ALWAYS(!IsActive(), User::Panic(KActivePanic, 666));
       
  1848 	iTimer.After(iStatus, aDelay);
       
  1849 	SetActive();
       
  1850 	}
       
  1851 
       
  1852 
       
  1853 // -eof-