os/kernelhwsrv/kerneltest/e32test/device/t_usbco2.cpp
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
     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-