1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/kernelhwsrv/kerneltest/e32test/device/t_usbco2.cpp Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,1853 @@
1.4 +// Copyright (c) 2000-2009 Nokia Corporation and/or its subsidiary(-ies).
1.5 +// All rights reserved.
1.6 +// This component and the accompanying materials are made available
1.7 +// under the terms of the License "Eclipse Public License v1.0"
1.8 +// which accompanies this distribution, and is available
1.9 +// at the URL "http://www.eclipse.org/legal/epl-v10.html".
1.10 +//
1.11 +// Initial Contributors:
1.12 +// Nokia Corporation - initial contribution.
1.13 +//
1.14 +// Contributors:
1.15 +//
1.16 +// Description:
1.17 +// e32test/device/t_usbco2.cpp
1.18 +// USB Test Program T_USB, functional part.
1.19 +// Device-side part, to work against USBRFLCT running on the host.
1.20 +//
1.21 +//
1.22 +
1.23 +#include <e32hal.h>
1.24 +#include <e32uid.h>
1.25 +#include <hal.h>
1.26 +
1.27 +#include "t_usb.h" // CActiveConsole, CActiveRW
1.28 +#include "t_usblib.h" // Helpers
1.29 +
1.30 +
1.31 +_LIT(KUsbLddFilename, "eusbc"); // .ldd assumed - it's a filename
1.32 +_LIT(KOtgdiLddFilename, "otgdi");
1.33 +_LIT(KUsbDeviceName, "Usbc");
1.34 +_LIT(KFileName, "\\T_USBFILE.BIN");
1.35 +_LIT(KActivePanic, "T_USB");
1.36 +
1.37 +static const TUint32 KTusbVersion = 20070524; // just an edit date really
1.38 +static const TUint8 KUsbrflctVersionMajor = 1; // the version we're compatible with
1.39 +static const TUint8 KUsbrflctVersionMinor = 5;
1.40 +static const TUint8 KUsbrflctVersionMicro = 0;
1.41 +
1.42 +static const TInt KMaxFileSize = 100 * 1024 * 1024; // 100MB (requires at least 128MB card)
1.43 +static const TInt KInitialBufSz = 0;
1.44 +static const TInt stridx1 = 0xCC;
1.45 +static const TInt stridx2 = 0xEE;
1.46 +
1.47 +//
1.48 +// --- class CActiveConsole ---------------------------------------------------------
1.49 +//
1.50 +
1.51 +CActiveConsole::CActiveConsole(CConsoleBase* aConsole, TBool aVerboseOutput)
1.52 + : CActive(EPriorityNormal),
1.53 + iConsole(aConsole),
1.54 + iRW(NULL),
1.55 + iBufferSizeChosen(EFalse),
1.56 + iBandwidthPriorityChosen(EFalse),
1.57 + iDMAChosen(EFalse),
1.58 + iDoubleBufferingChosen(EFalse),
1.59 + iSoftwareConnect(EFalse),
1.60 + iHighSpeed(EFalse),
1.61 + iOtg(EFalse),
1.62 + iVerbose(aVerboseOutput)
1.63 + {}
1.64 +
1.65 +
1.66 +CActiveConsole* CActiveConsole::NewLC(CConsoleBase* aConsole, TBool aVerboseOutput)
1.67 + {
1.68 + CActiveConsole* self = new (ELeave) CActiveConsole(aConsole, aVerboseOutput);
1.69 + CleanupStack::PushL(self);
1.70 + self->ConstructL();
1.71 + return self;
1.72 + }
1.73 +
1.74 +
1.75 +CActiveConsole* CActiveConsole::NewL(CConsoleBase* aConsole, TBool aVerboseOutput)
1.76 + {
1.77 + CActiveConsole* self = NewLC(aConsole, aVerboseOutput);
1.78 + CleanupStack::Pop();
1.79 + return self;
1.80 + }
1.81 +
1.82 +
1.83 +void CActiveConsole::ConstructL()
1.84 + {
1.85 + CActiveScheduler::Add(this);
1.86 +
1.87 + // Load logical driver (LDD)
1.88 + // (There's no physical driver (PDD) with USB: it's a kernel extension DLL which
1.89 + // was already loaded at boot time.)
1.90 + TInt r = User::LoadLogicalDevice(KUsbLddFilename);
1.91 + if (r != KErrNone && r != KErrAlreadyExists)
1.92 + {
1.93 + TUSB_PRINT1("Error %d on loading USB LDD", r);
1.94 + User::Leave(-1);
1.95 + return;
1.96 + }
1.97 + TUSB_PRINT("Successfully loaded USB LDD");
1.98 +
1.99 + // Open USB channel
1.100 + r = iPort.Open(0);
1.101 + if (r != KErrNone)
1.102 + {
1.103 + TUSB_PRINT1("Error %d on opening USB port", r);
1.104 + User::Leave(-1);
1.105 + return;
1.106 + }
1.107 + TUSB_PRINT("Successfully opened USB port");
1.108 +
1.109 + // Create Reader/Writer active object
1.110 + iRW = CActiveRW::NewL(iConsole, &iPort, iVerbose);
1.111 + if (!iRW)
1.112 + {
1.113 + TUSB_PRINT("Failed to create reader/writer");
1.114 + User::Leave(-1);
1.115 + return;
1.116 + }
1.117 + TUSB_PRINT("Created reader/writer");
1.118 +
1.119 + // Check for OTG support
1.120 + TBuf8<KUsbDescSize_Otg> otg_desc;
1.121 + r = iPort.GetOtgDescriptor(otg_desc);
1.122 + if (!(r == KErrNotSupported || r == KErrNone))
1.123 + {
1.124 + TUSB_PRINT1("Error %d while fetching OTG descriptor", r);
1.125 + User::Leave(-1);
1.126 + return;
1.127 + }
1.128 + iOtg = (r != KErrNotSupported) ? ETrue : EFalse;
1.129 +
1.130 + // On an OTG device we have to start the OTG driver, otherwise the Client
1.131 + // stack will remain disabled forever.
1.132 + if (iOtg)
1.133 + {
1.134 + TUSB_PRINT("Running on OTG device: loading OTG driver");
1.135 + r = User::LoadLogicalDevice(KOtgdiLddFilename);
1.136 + if (r != KErrNone)
1.137 + {
1.138 + TUSB_PRINT1("Error %d on loading OTG LDD", r);
1.139 + User::Leave(-1);
1.140 + return;
1.141 + }
1.142 + r = iOtgPort.Open();
1.143 + if (r != KErrNone)
1.144 + {
1.145 + TUSB_PRINT1("Error %d on opening OTG port", r);
1.146 + User::Leave(-1);
1.147 + return;
1.148 + }
1.149 + r = iOtgPort.StartStacks();
1.150 + if (r != KErrNone)
1.151 + {
1.152 + TUSB_PRINT1("Error %d on starting USB stack", r);
1.153 + User::Leave(-1);
1.154 + return;
1.155 + }
1.156 + }
1.157 + }
1.158 +
1.159 +
1.160 +TInt CActiveConsole::SetupInterface()
1.161 + {
1.162 + // Query the USB device/Setup the USB interface
1.163 + TInt r = QueryUsbClientL();
1.164 + if (r != KErrNone)
1.165 + {
1.166 + TUSB_PRINT1("Interface setup failed", r);
1.167 + return r;
1.168 + }
1.169 + TUSB_PRINT("Interface successfully set up");
1.170 +
1.171 + // Change some descriptors to contain suitable values
1.172 + r = SetupDescriptors();
1.173 + if (r != KErrNone)
1.174 + {
1.175 + TUSB_PRINT1("Descriptor setup failed", r);
1.176 + return r;
1.177 + }
1.178 +
1.179 + // Create device state active object
1.180 + iDeviceStateNotifier = CActiveDeviceStateNotifier::NewL(iConsole, &iPort, iVerbose);
1.181 + if (!iDeviceStateNotifier)
1.182 + {
1.183 + TUSB_PRINT("Failed to create device state notifier");
1.184 + return r;
1.185 + }
1.186 + iDeviceStateNotifier->Activate();
1.187 +
1.188 + // Create endpoint stall status active object
1.189 + iStallNotifier = CActiveStallNotifier::NewL(iConsole, &iPort, iVerbose);
1.190 + if (!iStallNotifier)
1.191 + {
1.192 + TUSB_PRINT("Failed to create stall notifier");
1.193 + return r;
1.194 + }
1.195 + iStallNotifier->Activate();
1.196 +
1.197 + return r;
1.198 + }
1.199 +
1.200 +
1.201 +CActiveConsole::~CActiveConsole()
1.202 + {
1.203 + TUSB_VERBOSE_PRINT("CActiveConsole::~CActiveConsole()");
1.204 + Cancel(); // base class cancel -> calls our DoCancel
1.205 + delete iRW; // destroy the reader/writer
1.206 + delete iDeviceStateNotifier;
1.207 + delete iStallNotifier;
1.208 + TInt r = iPort.RemoveStringDescriptor(stridx1);
1.209 + if (r != KErrNone)
1.210 + {
1.211 + TUSB_PRINT1("Error %d on string removal", r);
1.212 + }
1.213 + r = iPort.RemoveStringDescriptor(stridx2);
1.214 + if (r != KErrNone)
1.215 + {
1.216 + TUSB_PRINT1("Error %d on string removal", r);
1.217 + }
1.218 + if (iOtg)
1.219 + {
1.220 + TUSB_PRINT("Running on OTG device: unloading OTG driver");
1.221 + iOtgPort.StopStacks();
1.222 + iOtgPort.Close();
1.223 + r = User::FreeLogicalDevice(RUsbOtgDriver::Name());
1.224 + if (r != KErrNone)
1.225 + {
1.226 + TUSB_PRINT1("Error %d on freeing OTG LDD", r);
1.227 + }
1.228 + }
1.229 + iPort.Close(); // close USB channel
1.230 + r = User::FreeLogicalDevice(KUsbDeviceName);
1.231 + if (r != KErrNone)
1.232 + {
1.233 + TUSB_PRINT1("Error %d during unloading USB LDD", r);
1.234 + User::Leave(-1);
1.235 + return;
1.236 + }
1.237 + TUSB_PRINT("Successfully unloaded USB LDD");
1.238 + }
1.239 +
1.240 +
1.241 +void CActiveConsole::DoCancel()
1.242 + {
1.243 + TUSB_VERBOSE_PRINT("CActiveConsole::DoCancel()");
1.244 + iConsole->ReadCancel();
1.245 + }
1.246 +
1.247 +
1.248 +void CActiveConsole::RunL()
1.249 + {
1.250 + TUSB_VERBOSE_PRINT("CActiveConsole::RunL()");
1.251 + ProcessKeyPressL(static_cast<TChar>(iConsole->KeyCode()));
1.252 + }
1.253 +
1.254 +
1.255 +void CActiveConsole::RequestCharacter()
1.256 + {
1.257 + // A request is issued to the CConsoleBase to accept a character from the keyboard.
1.258 + __ASSERT_ALWAYS(!IsActive(), User::Panic(KActivePanic, 666));
1.259 + if (!iBufferSizeChosen)
1.260 + {
1.261 + iConsole->Printf(_L("\n"));
1.262 + iConsole->Printf(_L("++++ Choose max. Transfer Size ++++\n"));
1.263 + iConsole->Printf(_L(" '0' - Set up USB device for USBCV\n"));
1.264 + iConsole->Printf(_L(" '1' - 32 bytes\n"));
1.265 + iConsole->Printf(_L(" '2' - 1024 bytes\n"));
1.266 + iConsole->Printf(_L(" '3' - 64 kbytes\n"));
1.267 + iConsole->Printf(_L(" '4' - 1 Mbyte\n"));
1.268 + }
1.269 + else if (!iBandwidthPriorityChosen)
1.270 + {
1.271 + iConsole->Printf(_L("\n"));
1.272 + iConsole->Printf(_L("++++ Choose Bandwidth Priority ++++\n"));
1.273 + iConsole->Printf(_L(" '1' - Economical buffering - default\n"));
1.274 + iConsole->Printf(_L(" '2' - More memory than default buffering - Plus1\n"));
1.275 + iConsole->Printf(_L(" '3' - More memory than Plus1 buffering - Plus2\n"));
1.276 + iConsole->Printf(_L(" '4' - Maximum buffering\n"));
1.277 + }
1.278 + else if (!iDMAChosen)
1.279 + {
1.280 + iConsole->Printf(_L("\n"));
1.281 + iConsole->Printf(_L("++++ Choose Endpoint I/O Transfer Mode ++++\n"));
1.282 + iConsole->Printf(_L(" '1' - Interrupt Mode\n"));
1.283 + iConsole->Printf(_L(" '2' - DMA Mode (recommended)\n"));
1.284 + }
1.285 + else if (!iDoubleBufferingChosen)
1.286 + {
1.287 + iConsole->Printf(_L("\n"));
1.288 + iConsole->Printf(_L("++++ Choose Endpoint FIFO Mode ++++\n"));
1.289 + iConsole->Printf(_L(" '1' - Normal Buffering Mode\n"));
1.290 + iConsole->Printf(_L(" '2' - Double Buffering Mode (recommended)\n"));
1.291 + }
1.292 + else
1.293 + {
1.294 + iConsole->Printf(_L("\n"));
1.295 + iConsole->Printf(_L("++++ Select Program Option ++++\n"));
1.296 + iConsole->Printf(_L(" 'L'oop test\n"));
1.297 + iConsole->Printf(_L(" Loop test with data 'C'ompare\n"));
1.298 + iConsole->Printf(_L(" 'R'eceive-only test (we receive, host transmits)\n"));
1.299 + iConsole->Printf(_L(" 'T'ransmit-only test\n"));
1.300 + iConsole->Printf(_L(" Receive and 'P'ut (write) to File\n"));
1.301 + iConsole->Printf(_L(" Transmit and 'G'et (read) from File\n"));
1.302 + iConsole->Printf(_L(" Signal Remote-'W'akeup to the host\n"));
1.303 + iConsole->Printf(_L(" 'S'top current transfer\n"));
1.304 +#ifdef WITH_DUMP_OPTION
1.305 + iConsole->Printf(_L(" 'D'ump USB regs to debugout\n"));
1.306 +#endif
1.307 + iConsole->Printf(_L(" Re'E'numerate device\n"));
1.308 + iConsole->Printf(_L(" 'Q'uit this app\n"));
1.309 + }
1.310 + iConsole->Read(iStatus);
1.311 + SetActive();
1.312 + }
1.313 +
1.314 +
1.315 +void CActiveConsole::ProcessKeyPressL(TChar aChar)
1.316 + {
1.317 + if (aChar == EKeyEscape)
1.318 + {
1.319 + RDebug::Print(_L("CActiveConsole: ESC key pressed -> stopping active scheduler..."));
1.320 + CActiveScheduler::Stop();
1.321 + return;
1.322 + }
1.323 + if (!iBufferSizeChosen)
1.324 + {
1.325 + // Set maximum buffer size from keypress
1.326 + switch (aChar)
1.327 + {
1.328 + case '0':
1.329 + // This is for creating a USB device that just enumerates,
1.330 + // to be used for compliance testing with USBCV.
1.331 + iRW->SetMaxBufSize(0);
1.332 + break;
1.333 + case '1':
1.334 + iRW->SetMaxBufSize(32);
1.335 + break;
1.336 + case '2':
1.337 + iRW->SetMaxBufSize(1024);
1.338 + break;
1.339 + case '3':
1.340 + iRW->SetMaxBufSize(64 * 1024);
1.341 + break;
1.342 + case '4':
1.343 + iRW->SetMaxBufSize(KMaxBufSize);
1.344 + break;
1.345 + default:
1.346 + TUSB_PRINT1("Not a valid input character: %c", aChar.operator TUint());
1.347 + goto request_char;
1.348 + }
1.349 + TUSB_PRINT1("Maximum buffer size set to %d bytes", iRW->MaxBufSize());
1.350 + iBufferSizeChosen = ETrue;
1.351 + }
1.352 + else if (!iBandwidthPriorityChosen)
1.353 + {
1.354 + // Set bandwidth priority from keypress
1.355 + switch (aChar)
1.356 + {
1.357 + case '1':
1.358 + iBandwidthPriority = EUsbcBandwidthOUTDefault | EUsbcBandwidthINDefault;
1.359 + TUSB_PRINT("Bandwith priority set to default");
1.360 + break;
1.361 + case '2':
1.362 + iBandwidthPriority = EUsbcBandwidthOUTPlus1 | EUsbcBandwidthINPlus1;
1.363 + TUSB_PRINT("Bandwith priority set to Plus1");
1.364 + break;
1.365 + case '3':
1.366 + iBandwidthPriority = EUsbcBandwidthOUTPlus2 | EUsbcBandwidthINPlus2;
1.367 + TUSB_PRINT("Bandwith priority set to Plus2");
1.368 + break;
1.369 + case '4':
1.370 + iBandwidthPriority = EUsbcBandwidthINMaximum | EUsbcBandwidthOUTMaximum;
1.371 + TUSB_PRINT("Bandwith priority set to maximum");
1.372 + break;
1.373 + default:
1.374 + TUSB_PRINT1("Not a valid input character: %c", aChar.operator TUint());
1.375 + goto request_char;
1.376 + }
1.377 + TUSB_PRINT1("(Set to 0x%08X)", iBandwidthPriority);
1.378 + iBandwidthPriorityChosen = ETrue;
1.379 +
1.380 + TUSB_PRINT("Configuring interface...");
1.381 + TInt r = SetupInterface();
1.382 + if (r != KErrNone)
1.383 + {
1.384 + TUSB_PRINT1("Error: %d. Stopping active scheduler...", r);
1.385 + CActiveScheduler::Stop();
1.386 + return;
1.387 + }
1.388 + }
1.389 + else if (!iDMAChosen)
1.390 + {
1.391 + // Set DMA mode from keypress
1.392 + switch (aChar)
1.393 + {
1.394 + case '1':
1.395 + TUSB_PRINT("- Trying to deallocate endpoint DMA:\n");
1.396 + DeAllocateEndpointDMA(EEndpoint1);
1.397 + DeAllocateEndpointDMA(EEndpoint2);
1.398 + break;
1.399 + case '2':
1.400 + TUSB_PRINT("- Trying to allocate endpoint DMA:\n");
1.401 + AllocateEndpointDMA(EEndpoint1);
1.402 + AllocateEndpointDMA(EEndpoint2);
1.403 + break;
1.404 + default:
1.405 + TUSB_PRINT1("Not a valid input character: %c", aChar.operator TUint());
1.406 + goto request_char;
1.407 + }
1.408 + iDMAChosen = ETrue;
1.409 + }
1.410 + else if (!iDoubleBufferingChosen)
1.411 + {
1.412 + // Set Double Buffering from keypress
1.413 + switch (aChar)
1.414 + {
1.415 + case '1':
1.416 + TUSB_PRINT("- Trying to deallocate Double Buffering:\n");
1.417 + DeAllocateDoubleBuffering(EEndpoint1);
1.418 + DeAllocateDoubleBuffering(EEndpoint2);
1.419 + break;
1.420 + case '2':
1.421 + TUSB_PRINT("- Trying to allocate Double Buffering:\n");
1.422 + AllocateDoubleBuffering(EEndpoint1);
1.423 + AllocateDoubleBuffering(EEndpoint2);
1.424 + break;
1.425 + default:
1.426 + TUSB_PRINT1("Not a valid input character: %c", aChar.operator TUint());
1.427 + goto request_char;
1.428 + }
1.429 + iDoubleBufferingChosen = ETrue;
1.430 +
1.431 + // Everything chosen, so let's re-enumerate...
1.432 + TUSB_PRINT("Enumeration...");
1.433 + TInt r = ReEnumerate();
1.434 + if (r != KErrNone)
1.435 + {
1.436 + TUSB_PRINT1("Error: %d. Stopping active scheduler...", r);
1.437 + CActiveScheduler::Stop();
1.438 + return;
1.439 + }
1.440 + TUSB_PRINT("Device successfully re-enumerated\n");
1.441 +
1.442 + // Make sure program versions match if testing against USBRFLCT
1.443 + if (iRW->MaxBufSize() != 0)
1.444 + {
1.445 + r = iRW->ExchangeVersions();
1.446 + if (r != KErrNone)
1.447 + {
1.448 + TUSB_PRINT1("Error: %d. Stopping active scheduler...", r);
1.449 + CActiveScheduler::Stop();
1.450 + return;
1.451 + }
1.452 + }
1.453 + }
1.454 + else
1.455 + {
1.456 + // Execute one of the 'proper' program functions
1.457 + switch (aChar)
1.458 + {
1.459 + case 'l': // start loop test
1.460 + case 'L':
1.461 + TUSB_PRINT("-> Loop test selected\n");
1.462 + iRW->SetTransferMode(ELoop);
1.463 + iRW->SendPreamble();
1.464 + break;
1.465 + case 'c': // start loop/compare test
1.466 + case 'C':
1.467 + TUSB_PRINT("-> Loop test with compare selected\n");
1.468 + iRW->SetTransferMode(ELoopComp);
1.469 + iRW->SendPreamble();
1.470 + break;
1.471 + case 'r': // start receive-only test
1.472 + case 'R':
1.473 + TUSB_PRINT("-> Receive-only test selected\n");
1.474 + iRW->SetTransferMode(EReceiveOnly);
1.475 + iRW->SendPreamble();
1.476 + break;
1.477 + case 't': // start transmit-only test
1.478 + case 'T':
1.479 + TUSB_PRINT("-> Transmit-only test selected\n");
1.480 + iRW->SetTransferMode(ETransmitOnly);
1.481 + iRW->SendPreamble();
1.482 + break;
1.483 + case 'g': // start transmit & get-from-file test
1.484 + case 'G':
1.485 + TUSB_PRINT("-> Transmit from file test selected\n");
1.486 + iRW->SetTransferMode(ETransmitOnly);
1.487 + iRW->ReadFromDisk(ETrue);
1.488 + iRW->SendPreamble();
1.489 + break;
1.490 + case 'p': // start receive & put-to-file test
1.491 + case 'P':
1.492 + TUSB_PRINT("-> Receive to file test selected\n");
1.493 + iRW->SetTransferMode(EReceiveOnly);
1.494 + iRW->WriteToDisk(ETrue);
1.495 + iRW->SendPreamble();
1.496 + break;
1.497 + case 'w': // remote-wakeup
1.498 + case 'W':
1.499 + TUSB_PRINT("-> Signal Remote-wakeup selected\n");
1.500 + iPort.SignalRemoteWakeup();
1.501 + break;
1.502 + case 's': // stop either
1.503 + case 'S':
1.504 + TUSB_PRINT("-> Stop transfer selected\n");
1.505 + iRW->Stop();
1.506 + break;
1.507 +#ifdef WITH_DUMP_OPTION
1.508 + case 'd': // dump controller registers
1.509 + case 'D':
1.510 + TUSB_PRINT("-> Dump option selected\n");
1.511 + iPort.DumpRegisters();
1.512 + QueryRxBuffer();
1.513 + break;
1.514 +#endif
1.515 + case 'e': // ReEnumerate()
1.516 + case 'E':
1.517 + TUSB_PRINT("-> Re-enumerate device selected\n");
1.518 + ReEnumerate();
1.519 + break;
1.520 + case 'q': // quit
1.521 + case 'Q':
1.522 + TUSB_PRINT("-> Quit program selected\n");
1.523 + TUSB_VERBOSE_PRINT("CActiveConsole: stopping active scheduler...");
1.524 + CActiveScheduler::Stop();
1.525 + return;
1.526 + default:
1.527 + TUSB_PRINT1("-> Not a valid input character: %c", aChar.operator TUint());
1.528 + goto request_char;
1.529 + }
1.530 + }
1.531 + request_char:
1.532 + RequestCharacter();
1.533 + return;
1.534 + }
1.535 +
1.536 +
1.537 +#ifdef WITH_DUMP_OPTION
1.538 +void CActiveConsole::QueryRxBuffer()
1.539 + {
1.540 + // Let's look whether there's data in the rx buffer
1.541 + TInt bytes = 0;
1.542 + TInt r = iPort.QueryReceiveBuffer(EEndpoint2, bytes);
1.543 + if (r != KErrNone)
1.544 + {
1.545 + RDebug::Print(_L(" Error %d on querying read buffer\n"), r);
1.546 + }
1.547 + else
1.548 + {
1.549 + RDebug::Print(_L(" %d bytes in RX buffer\n"), bytes);
1.550 + }
1.551 + }
1.552 +#endif
1.553 +
1.554 +
1.555 +TInt CActiveConsole::QueryUsbClientL()
1.556 + {
1.557 + // Not really just querying... but rather setting up the whole interface.
1.558 + // It's in fact a bit lengthy, but all these steps are required, once,
1.559 + // and in that order.
1.560 +
1.561 + // Get device/endpoint capabilities
1.562 + //
1.563 + // A TPckg, or TPckBuf was not used in the following, because
1.564 + //
1.565 + // TPckgBuf<TUsbcEndpointData[KUsbcMaxEndpoints]> databuf;
1.566 + //
1.567 + // doesn't work. Also,
1.568 + //
1.569 + // TUsbcEndpointData data[KUsbcMaxEndpoints];
1.570 + // TPckgBuf<TUsbcEndpointData[KUsbcMaxEndpoints]> databuf(data);
1.571 + //
1.572 + // doesn't work. Also,
1.573 + //
1.574 + // TUsbcEndpointData data[KUsbcMaxEndpoints];
1.575 + // TPckgBuf<TUsbcEndpointData[]> databuf(data);
1.576 + //
1.577 + // doesn't work.
1.578 + // So we seem to have to stick to the ugly cast below.
1.579 + //
1.580 + // TUsbcEndpointData data[KUsbcMaxEndpoints];
1.581 + // TPtr8 databuf(reinterpret_cast<TUint8*>(data), sizeof(data), sizeof(data));
1.582 + //
1.583 +
1.584 + // Device
1.585 + TUsbDeviceCaps d_caps;
1.586 + TInt r = iPort.DeviceCaps(d_caps);
1.587 + if (r != KErrNone)
1.588 + {
1.589 + TUSB_PRINT1("Error %d on querying device capabilities", r);
1.590 + return KErrGeneral;
1.591 + }
1.592 + const TInt n = d_caps().iTotalEndpoints;
1.593 +
1.594 + TUSB_PRINT("### USB device capabilities:");
1.595 + TUSB_PRINT1("Number of endpoints: %d", n);
1.596 + TUSB_PRINT1("Supports Software-Connect: %s",
1.597 + d_caps().iConnect ? _S("yes") : _S("no"));
1.598 + TUSB_PRINT1("Device is Self-Powered: %s",
1.599 + d_caps().iSelfPowered ? _S("yes") : _S("no"));
1.600 + TUSB_PRINT1("Supports Remote-Wakeup: %s",
1.601 + d_caps().iRemoteWakeup ? _S("yes") : _S("no"));
1.602 + TUSB_PRINT1("Supports High-speed: %s",
1.603 + d_caps().iHighSpeed ? _S("yes") : _S("no"));
1.604 + TUSB_PRINT1("Supports OTG: %s",
1.605 + iOtg ? _S("yes") : _S("no"));
1.606 + TUSB_PRINT1("Supports unpowered cable detection: %s",
1.607 + (d_caps().iFeatureWord1 & KUsbDevCapsFeatureWord1_CableDetectWithoutPower) ?
1.608 + _S("yes") : _S("no"));
1.609 + TUSB_PRINT1("Supports endpoint resource alloc scheme V2: %s\n",
1.610 + (d_caps().iFeatureWord1 & KUsbDevCapsFeatureWord1_EndpointResourceAllocV2) ?
1.611 + _S("yes") : _S("no"));
1.612 + TUSB_PRINT("");
1.613 +
1.614 + iSoftwareConnect = d_caps().iConnect; // we need to remember this
1.615 +
1.616 + if (n < 2)
1.617 + {
1.618 + TUSB_PRINT1("Error: only %d endpoints available on device", n);
1.619 + return KErrGeneral;
1.620 + }
1.621 +
1.622 + // Endpoints
1.623 + TUsbcEndpointData data[KUsbcMaxEndpoints];
1.624 + TPtr8 dataptr(reinterpret_cast<TUint8*>(data), sizeof(data), sizeof(data));
1.625 + r = iPort.EndpointCaps(dataptr);
1.626 + if (r != KErrNone)
1.627 + {
1.628 + TUSB_PRINT1("Error %d on querying endpoint capabilities", r);
1.629 + return KErrGeneral;
1.630 + }
1.631 + TUSB_PRINT("### USB device endpoint capabilities:");
1.632 + for (TInt i = 0; i < n; i++)
1.633 + {
1.634 + const TUsbcEndpointCaps* caps = &data[i].iCaps;
1.635 + TUSB_PRINT2("Endpoint: SizeMask = 0x%08x TypeDirMask = 0x%08x",
1.636 + caps->iSizes, caps->iTypesAndDir);
1.637 + }
1.638 + TUSB_PRINT("");
1.639 +
1.640 + // Set up the active interface
1.641 + TUsbcInterfaceInfoBuf ifc;
1.642 + TInt ep_found = 0;
1.643 + TBool foundBulkIN = EFalse;
1.644 + TBool foundBulkOUT = EFalse;
1.645 + for (TInt i = 0; i < n; i++)
1.646 + {
1.647 + const TUsbcEndpointCaps* const caps = &data[i].iCaps;
1.648 + const TInt mps = caps->MaxPacketSize();
1.649 + if (!foundBulkIN &&
1.650 + (caps->iTypesAndDir & (KUsbEpTypeBulk | KUsbEpDirIn)) ==
1.651 + (KUsbEpTypeBulk | KUsbEpDirIn))
1.652 + {
1.653 + if (!(mps == 64 || mps == 512))
1.654 + {
1.655 + TUSB_PRINT1("Funny Bulk IN MaxPacketSize: %d - T_USB will probably fail...", mps);
1.656 + }
1.657 + // EEndpoint1 is going to be our Tx (IN) endpoint
1.658 + ifc().iEndpointData[0].iType = KUsbEpTypeBulk;
1.659 + ifc().iEndpointData[0].iDir = KUsbEpDirIn;
1.660 + ifc().iEndpointData[0].iSize = mps;
1.661 + foundBulkIN = ETrue;
1.662 + if (++ep_found == 2)
1.663 + break;
1.664 + }
1.665 + else if (!foundBulkOUT &&
1.666 + (caps->iTypesAndDir & (KUsbEpTypeBulk | KUsbEpDirOut)) ==
1.667 + (KUsbEpTypeBulk | KUsbEpDirOut))
1.668 + {
1.669 + if (!(mps == 64 || mps == 512))
1.670 + {
1.671 + TUSB_PRINT1("Funny Bulk OUT MaxPacketSize: %d - T_USB will probably fail...", mps);
1.672 + }
1.673 + // EEndpoint2 is going to be our Rx (OUT) endpoint
1.674 + ifc().iEndpointData[1].iType = KUsbEpTypeBulk;
1.675 + ifc().iEndpointData[1].iDir = KUsbEpDirOut;
1.676 + ifc().iEndpointData[1].iSize = mps;
1.677 + foundBulkOUT = ETrue;
1.678 + if (++ep_found == 2)
1.679 + break;
1.680 + }
1.681 + }
1.682 + if (ep_found != 2)
1.683 + {
1.684 + TUSB_PRINT1("No suitable endpoints found", r);
1.685 + return KErrGeneral;
1.686 + }
1.687 +
1.688 + _LIT16(ifcname, "T_USB Test Interface (Default Setting 0)");
1.689 + ifc().iString = const_cast<TDesC16*>(&ifcname);
1.690 + ifc().iTotalEndpointsUsed = 2;
1.691 + ifc().iClass.iClassNum = 0xff; // vendor-specific
1.692 + ifc().iClass.iSubClassNum = 0xff; // vendor-specific
1.693 + ifc().iClass.iProtocolNum = 0xff; // vendor-specific
1.694 + r = iPort.SetInterface(0, ifc, iBandwidthPriority);
1.695 + if (r != KErrNone)
1.696 + {
1.697 + TUSB_PRINT1("Error %d on setting active interface", r);
1.698 + }
1.699 +
1.700 + // Find ep's for an alternate ifc setting.
1.701 + // We're not really going to use it, but it gives USBCV et al. more stuff to play with.
1.702 + if (!SupportsAlternateInterfaces())
1.703 + {
1.704 + TUSB_PRINT("Alternate Interfaces not supported - skipping alternate setting setup\n");
1.705 + return KErrNone;
1.706 + }
1.707 + ep_found = 0;
1.708 + TBool foundIsoIN = EFalse;
1.709 + TBool foundIsoOUT = EFalse;
1.710 +
1.711 + // NB! We cannot assume that any specific device has any given set of
1.712 + // capabilities, so whilst we try and set an assortment of endpoint types
1.713 + // we may not get what we want.
1.714 +
1.715 + // Also, note that the endpoint[] array in the interface descriptor
1.716 + // must be filled from ep[0]...ep[n-1].
1.717 +
1.718 + for (TInt i = 0; i < n; i++)
1.719 + {
1.720 + const TUsbcEndpointCaps* const caps = &data[i].iCaps;
1.721 + const TInt mps = caps->MaxPacketSize();
1.722 + if (!foundIsoIN &&
1.723 + (caps->iTypesAndDir & (KUsbEpTypeIsochronous | KUsbEpDirIn)) ==
1.724 + (KUsbEpTypeIsochronous | KUsbEpDirIn))
1.725 + {
1.726 + // This is going to be our Iso TX (IN) endpoint
1.727 + ifc().iEndpointData[ep_found].iType = KUsbEpTypeIsochronous;
1.728 + ifc().iEndpointData[ep_found].iDir = KUsbEpDirIn;
1.729 + ifc().iEndpointData[ep_found].iSize = mps;
1.730 + ifc().iEndpointData[ep_found].iInterval = 0x01; // 2^(bInterval-1)ms, bInterval must be [1..16]
1.731 + ifc().iEndpointData[ep_found].iInterval_Hs = 0x01; // same as for FS
1.732 + ifc().iEndpointData[ep_found].iExtra = 2; // 2 extra bytes for Audio Class EP descriptor
1.733 + foundIsoIN = ETrue;
1.734 + if (++ep_found == 2)
1.735 + break;
1.736 + }
1.737 + else if (!foundIsoOUT &&
1.738 + (caps->iTypesAndDir & (KUsbEpTypeIsochronous | KUsbEpDirOut)) ==
1.739 + (KUsbEpTypeIsochronous | KUsbEpDirOut))
1.740 + {
1.741 + // This is going to be our Iso RX (OUT) endpoint
1.742 + ifc().iEndpointData[ep_found].iType = KUsbEpTypeIsochronous;
1.743 + ifc().iEndpointData[ep_found].iDir = KUsbEpDirOut;
1.744 + ifc().iEndpointData[ep_found].iSize = mps;
1.745 + ifc().iEndpointData[ep_found].iInterval = 0x01; // 2^(bInterval-1)ms, bInterval must be [1..16]
1.746 + ifc().iEndpointData[ep_found].iExtra = 2; // 2 extra bytes for Audio Class EP descriptor
1.747 + foundIsoOUT = ETrue;
1.748 + if (++ep_found == 2)
1.749 + break;
1.750 + }
1.751 + }
1.752 + // Let's try to add Bulk endpoints up to the max # of 2.
1.753 + if (ep_found < 2)
1.754 + {
1.755 + for (TInt i = 0; i < n; i++)
1.756 + {
1.757 + const TUsbcEndpointCaps* const caps = &data[i].iCaps;
1.758 + const TUint mps = caps->MaxPacketSize();
1.759 + if (caps->iTypesAndDir & KUsbEpTypeBulk)
1.760 + {
1.761 + const TUint dir = (caps->iTypesAndDir & KUsbEpDirIn) ? KUsbEpDirIn : KUsbEpDirOut;
1.762 + ifc().iEndpointData[ep_found].iType = KUsbEpTypeBulk;
1.763 + ifc().iEndpointData[ep_found].iDir = dir;
1.764 + ifc().iEndpointData[ep_found].iSize = mps;
1.765 + if (++ep_found == 2)
1.766 + break;
1.767 + }
1.768 + }
1.769 + }
1.770 + if (ep_found == 0)
1.771 + {
1.772 + TUSB_PRINT("Not enough suitable endpoints found for alt ifc");
1.773 + // not a disaster though
1.774 + return KErrNone;
1.775 + }
1.776 +
1.777 + _LIT16(ifcname1, "T_USB Test Interface (Alternate Setting 1)");
1.778 + ifc().iString = const_cast<TDesC16*>(&ifcname1);
1.779 + ifc().iTotalEndpointsUsed = ep_found;
1.780 + ifc().iClass.iClassNum = KUsbAudioInterfaceClassCode;
1.781 + ifc().iClass.iSubClassNum = KUsbAudioInterfaceSubclassCode_Audiostreaming;
1.782 + ifc().iClass.iProtocolNum = KUsbAudioInterfaceProtocolCode_Pr_Protocol_Undefined;
1.783 + // Tell the driver that this setting is not interested in Ep0 requests:
1.784 + ifc().iFeatureWord |= KUsbcInterfaceInfo_NoEp0RequestsPlease;
1.785 + r = iPort.SetInterface(1, ifc);
1.786 + if (r != KErrNone)
1.787 + {
1.788 + TUSB_PRINT1("Error %d on setting alternate interface", r);
1.789 + }
1.790 +
1.791 + return r;
1.792 + }
1.793 +
1.794 +
1.795 +void CActiveConsole::AllocateEndpointDMA(TEndpointNumber aEndpoint)
1.796 + {
1.797 + TInt r = iPort.AllocateEndpointResource(aEndpoint, EUsbcEndpointResourceDMA);
1.798 + if (r == KErrNone)
1.799 + RDebug::Print(_L("DMA allocation on endpoint %d: KErrNone"), aEndpoint);
1.800 + else if (r == KErrInUse)
1.801 + RDebug::Print(_L("DMA allocation on endpoint %d: KErrInUse"), aEndpoint);
1.802 + else if (r == KErrNotSupported)
1.803 + RDebug::Print(_L("DMA allocation on endpoint %d: KErrNotSupported"), aEndpoint);
1.804 + else
1.805 + RDebug::Print(_L("DMA allocation on endpoint %d: unexpected return value %d"),
1.806 + aEndpoint, r);
1.807 + TBool res = iPort.QueryEndpointResourceUse(aEndpoint, EUsbcEndpointResourceDMA);
1.808 + TUSB_PRINT2("DMA on endpoint %d %s\n",
1.809 + aEndpoint, res ? _S("allocated") : _S("not allocated"));
1.810 +
1.811 + if ((r == KErrNone) && !res)
1.812 + RDebug::Print(_L("(Allocation success but negative query result: contradiction!)\n"));
1.813 + else if ((r != KErrNone) && res)
1.814 + RDebug::Print(_L("(Allocation failure but positive query result: contradiction!)\n"));
1.815 + }
1.816 +
1.817 +
1.818 +void CActiveConsole::DeAllocateEndpointDMA(TEndpointNumber aEndpoint)
1.819 + {
1.820 + TInt r = iPort.DeAllocateEndpointResource(aEndpoint, EUsbcEndpointResourceDMA);
1.821 + if (r == KErrNone)
1.822 + RDebug::Print(_L("DMA deallocation on endpoint %d: KErrNone"), aEndpoint);
1.823 + else if (r == KErrNotSupported)
1.824 + RDebug::Print(_L("DMA deallocation on endpoint %d: KErrNotSupported"), aEndpoint);
1.825 + else
1.826 + RDebug::Print(_L("DMA deallocation on endpoint %d: unexpected return value %d"),
1.827 + aEndpoint, r);
1.828 + TBool res = iPort.QueryEndpointResourceUse(aEndpoint, EUsbcEndpointResourceDMA);
1.829 + TUSB_PRINT2("DMA on endpoint %d %s\n",
1.830 + aEndpoint, res ? _S("allocated") : _S("not allocated"));
1.831 + }
1.832 +
1.833 +
1.834 +void CActiveConsole::AllocateDoubleBuffering(TEndpointNumber aEndpoint)
1.835 + {
1.836 + TInt r = iPort.AllocateEndpointResource(aEndpoint, EUsbcEndpointResourceDoubleBuffering);
1.837 + if (r == KErrNone)
1.838 + RDebug::Print(_L("Double Buffering allocation on endpoint %d: KErrNone"), aEndpoint);
1.839 + else if (r == KErrInUse)
1.840 + RDebug::Print(_L("Double Buffering allocation on endpoint %d: KErrInUse"), aEndpoint);
1.841 + else if (r == KErrNotSupported)
1.842 + RDebug::Print(_L("Double Buffering allocation on endpoint %d: KErrNotSupported"), aEndpoint);
1.843 + else
1.844 + RDebug::Print(_L("Double Buffering allocation on endpoint %d: unexpected return value %d"),
1.845 + aEndpoint, r);
1.846 + TBool res = iPort.QueryEndpointResourceUse(aEndpoint, EUsbcEndpointResourceDoubleBuffering);
1.847 + TUSB_PRINT2("Double Buffering on endpoint %d %s\n",
1.848 + aEndpoint, res ? _S("allocated") : _S("not allocated"));
1.849 +
1.850 + if ((r == KErrNone) && !res)
1.851 + RDebug::Print(_L("(Allocation success but negative query result: contradiction!)\n"));
1.852 + else if ((r != KErrNone) && res)
1.853 + RDebug::Print(_L("(Allocation failure but positive query result: contradiction!)\n"));
1.854 + }
1.855 +
1.856 +
1.857 +void CActiveConsole::DeAllocateDoubleBuffering(TEndpointNumber aEndpoint)
1.858 + {
1.859 + TInt r = iPort.DeAllocateEndpointResource(aEndpoint, EUsbcEndpointResourceDoubleBuffering);
1.860 + if (r == KErrNone)
1.861 + RDebug::Print(_L("Double Buffering deallocation on endpoint %d: KErrNone"), aEndpoint);
1.862 + else if (r == KErrNotSupported)
1.863 + RDebug::Print(_L("Double Buffering deallocation on endpoint %d: KErrNotSupported"), aEndpoint);
1.864 + else
1.865 + RDebug::Print(_L("Double Buffering deallocation on endpoint %d: unexpected return value %d"),
1.866 + aEndpoint, r);
1.867 + TBool res = iPort.QueryEndpointResourceUse(aEndpoint, EUsbcEndpointResourceDoubleBuffering);
1.868 + TUSB_PRINT2("Double Buffering on endpoint %d %s\n",
1.869 + aEndpoint, res ? _S("allocated") : _S("not allocated"));
1.870 + }
1.871 +
1.872 +
1.873 +TInt CActiveConsole::ReEnumerate()
1.874 + {
1.875 + TRequestStatus enum_status;
1.876 + iPort.ReEnumerate(enum_status);
1.877 + if (!iSoftwareConnect)
1.878 + {
1.879 + iConsole->Printf(_L("This device does not support software\n"));
1.880 + iConsole->Printf(_L("disconnect/reconnect\n"));
1.881 + iConsole->Printf(_L("Please physically unplug and replug\n"));
1.882 + iConsole->Printf(_L("the USB cable NOW... "));
1.883 + }
1.884 + iConsole->Printf(_L("\n>>> START THE USBRFLCT PROGRAM ON THE HOST SIDE NOW <<<\n"));
1.885 + User::WaitForRequest(enum_status);
1.886 + if (enum_status != KErrNone)
1.887 + {
1.888 + TUSB_PRINT1("Error: Re-enumeration status = %d", enum_status.Int());
1.889 + return KErrGeneral;
1.890 + }
1.891 + TUsbcDeviceState device_state = EUsbcDeviceStateUndefined;
1.892 + TInt r = iPort.DeviceStatus(device_state);
1.893 + if (r != KErrNone)
1.894 + {
1.895 + TUSB_PRINT1("Error %d on querying device state", r);
1.896 + }
1.897 + else
1.898 + {
1.899 + TUSB_PRINT1("Current device state: %s",
1.900 + (device_state == EUsbcDeviceStateUndefined) ? _S("Undefined") :
1.901 + ((device_state == EUsbcDeviceStateAttached) ? _S("Attached") :
1.902 + ((device_state == EUsbcDeviceStatePowered) ? _S("Powered") :
1.903 + ((device_state == EUsbcDeviceStateDefault) ? _S("Default") :
1.904 + ((device_state == EUsbcDeviceStateAddress) ? _S("Address") :
1.905 + ((device_state == EUsbcDeviceStateConfigured) ? _S("Configured") :
1.906 + ((device_state == EUsbcDeviceStateSuspended) ? _S("Suspended") :
1.907 + _S("Unknown"))))))));
1.908 + }
1.909 +
1.910 + // Check the speed of the established physical USB connection
1.911 + iHighSpeed = iPort.CurrentlyUsingHighSpeed();
1.912 + if (iHighSpeed)
1.913 + {
1.914 + TUSB_PRINT("---> USB High-speed Testing\n");
1.915 + // It can only be 512 bytes when using high-speed.
1.916 + iRW->SetMaxPacketSize(512); // iRW already exists at this point
1.917 + }
1.918 + else
1.919 + {
1.920 + TUSB_PRINT("---> USB Full-speed Testing\n");
1.921 + // We only support 64 bytes when using full-speed.
1.922 + iRW->SetMaxPacketSize(64); // iRW already exists at this point
1.923 + }
1.924 +
1.925 + return KErrNone;
1.926 + }
1.927 +
1.928 +
1.929 +#ifdef test
1.930 +#undef test
1.931 +#endif
1.932 +#define test(x) \
1.933 + do { \
1.934 + if (!(x)) \
1.935 + { \
1.936 + TUSB_PRINT1("Failure occurred! - on line %d", __LINE__); \
1.937 + return KErrGeneral; \
1.938 + } \
1.939 + } while (0)
1.940 +
1.941 +
1.942 +TInt CActiveConsole::SetupDescriptors()
1.943 + {
1.944 + // === Device Descriptor
1.945 +
1.946 + TInt deviceDescriptorSize = 0;
1.947 + iPort.GetDeviceDescriptorSize(deviceDescriptorSize);
1.948 + test(static_cast<TUint>(deviceDescriptorSize) == KUsbDescSize_Device);
1.949 +
1.950 + TBuf8<KUsbDescSize_Device> deviceDescriptor;
1.951 + TInt r = iPort.GetDeviceDescriptor(deviceDescriptor);
1.952 + test(r == KErrNone);
1.953 +
1.954 + const TInt KUsbSpecOffset = 2;
1.955 + const TInt KUsbVendorIdOffset = 8;
1.956 + const TInt KUsbProductIdOffset = 10;
1.957 + const TInt KUsbDevReleaseOffset = 12;
1.958 + // Change the USB spec number to 2.00
1.959 + deviceDescriptor[KUsbSpecOffset] = 0x00;
1.960 + deviceDescriptor[KUsbSpecOffset+1] = 0x02;
1.961 + // Change the device vendor ID (VID) to 0x0E22 (Symbian)
1.962 + deviceDescriptor[KUsbVendorIdOffset] = 0x22; // little endian!
1.963 + deviceDescriptor[KUsbVendorIdOffset+1] = 0x0E;
1.964 + // Change the device product ID (PID) to 0x1111
1.965 + deviceDescriptor[KUsbProductIdOffset] = 0x11;
1.966 + deviceDescriptor[KUsbProductIdOffset+1] = 0x11;
1.967 + // Change the device release number to 3.05
1.968 + deviceDescriptor[KUsbDevReleaseOffset] = 0x05;
1.969 + deviceDescriptor[KUsbDevReleaseOffset+1] = 0x03;
1.970 + r = iPort.SetDeviceDescriptor(deviceDescriptor);
1.971 + test(r == KErrNone);
1.972 +
1.973 + const TUint16 Vid = (((TUint16)deviceDescriptor[KUsbVendorIdOffset + 1] << 8) & 0xff00) |
1.974 + deviceDescriptor[KUsbVendorIdOffset];
1.975 + const TUint16 Pid = (((TUint16)deviceDescriptor[KUsbProductIdOffset + 1] << 8) & 0xff00) |
1.976 + deviceDescriptor[KUsbProductIdOffset];
1.977 +
1.978 + TUSB_PRINT6("\nVID = 0x%04X / PID = 0x%04X / DevRel = %d%d.%d%d\n", Vid, Pid,
1.979 + ((deviceDescriptor[KUsbDevReleaseOffset + 1] >> 4) & 0x0f),
1.980 + (deviceDescriptor[KUsbDevReleaseOffset + 1] & 0x0f),
1.981 + ((deviceDescriptor[KUsbDevReleaseOffset] >> 4) & 0x0f),
1.982 + (deviceDescriptor[KUsbDevReleaseOffset] & 0x0f));
1.983 +
1.984 + // === Configuration Descriptor
1.985 +
1.986 + TInt configDescriptorSize = 0;
1.987 + iPort.GetConfigurationDescriptorSize(configDescriptorSize);
1.988 + test(static_cast<TUint>(configDescriptorSize) == KUsbDescSize_Config);
1.989 +
1.990 + TBuf8<KUsbDescSize_Config> configDescriptor;
1.991 + r = iPort.GetConfigurationDescriptor(configDescriptor);
1.992 + test(r == KErrNone);
1.993 +
1.994 + // Change the reported max power to 100mA (= 2 * 0x32),
1.995 + // which is the highest value allowed for a bus-powered device.
1.996 + const TInt KUsbMaxPowerOffset = 8;
1.997 + configDescriptor[KUsbMaxPowerOffset] = 0x32;
1.998 + r = iPort.SetConfigurationDescriptor(configDescriptor);
1.999 + test(r == KErrNone);
1.1000 +
1.1001 + // === String Descriptors
1.1002 +
1.1003 + // Set up two arbitrary string descriptors, which can be queried
1.1004 + // manually from the host side for testing purposes (for instance
1.1005 + // using 'usbcheck').
1.1006 +
1.1007 + _LIT16(string_one, "Arbitrary String Descriptor Test String 1");
1.1008 + TBuf16<KUsbStringDescStringMaxSize / 2> wr_str(string_one);
1.1009 + r = iPort.SetStringDescriptor(stridx1, wr_str);
1.1010 + test(r == KErrNone);
1.1011 +
1.1012 + _LIT16(string_two, "Another Arbitrary String Descriptor Test String");
1.1013 + wr_str.FillZ(wr_str.MaxLength());
1.1014 + wr_str = string_two;
1.1015 + r = iPort.SetStringDescriptor(stridx2, wr_str);
1.1016 + test(r == KErrNone);
1.1017 +
1.1018 + return KErrNone;
1.1019 + }
1.1020 +
1.1021 +
1.1022 +//
1.1023 +// --- class CActiveRW ---------------------------------------------------------
1.1024 +//
1.1025 +
1.1026 +CActiveRW::CActiveRW(CConsoleBase* aConsole, RDevUsbcClient* aPort, TBool aVerboseOutput)
1.1027 + : CActive(EPriorityNormal),
1.1028 + iConsole(aConsole),
1.1029 + iPort(aPort),
1.1030 + iBufSz(KInitialBufSz),
1.1031 + iMaxBufSz(KInitialBufSz),
1.1032 + iMaxPktSz(0),
1.1033 + iCurrentXfer(ENone),
1.1034 + iXferMode(::ENone),
1.1035 + iDoStop(EFalse),
1.1036 + iPktNum(~0),
1.1037 + iVerbose(aVerboseOutput)
1.1038 + {
1.1039 + TUSB_VERBOSE_PRINT("CActiveRW::CActiveRW()");
1.1040 + }
1.1041 +
1.1042 +
1.1043 +CActiveRW* CActiveRW::NewL(CConsoleBase* aConsole, RDevUsbcClient* aPort, TBool aVerboseOutput)
1.1044 + {
1.1045 + CActiveRW* self = new (ELeave) CActiveRW(aConsole, aPort, aVerboseOutput);
1.1046 + CleanupStack::PushL(self);
1.1047 + self->ConstructL();
1.1048 + CActiveScheduler::Add(self);
1.1049 + CleanupStack::Pop(); // self
1.1050 + return self;
1.1051 + }
1.1052 +
1.1053 +
1.1054 +void CActiveRW::ConstructL()
1.1055 + {
1.1056 + TUSB_VERBOSE_PRINT("CActiveRW::ConstructL()");
1.1057 +
1.1058 + User::LeaveIfError(iFs.Connect());
1.1059 +
1.1060 + // Prepare Preamble buffer
1.1061 + iPreambleBuf.SetMax();
1.1062 + iPreambleBuf.FillZ();
1.1063 +
1.1064 + // Prepare IN data buffer
1.1065 + iWriteBuf.SetMax();
1.1066 + for (TInt i = 0; i < iWriteBuf.MaxSize(); i++)
1.1067 + {
1.1068 + iWriteBuf[i] = i;
1.1069 + }
1.1070 +
1.1071 + // Prepare OUT data buffer
1.1072 + iReadBuf.SetMax();
1.1073 +
1.1074 + // Create read timeout timer active object (but don't activate it yet)
1.1075 + iTimeoutTimer = CActiveTimer::NewL(iConsole, iPort, iVerbose);
1.1076 + if (!iTimeoutTimer)
1.1077 + {
1.1078 + TUSB_PRINT("Failed to create timeout timer");
1.1079 + }
1.1080 + }
1.1081 +
1.1082 +
1.1083 +CActiveRW::~CActiveRW()
1.1084 + {
1.1085 + TUSB_VERBOSE_PRINT("CActiveRW::~CActiveRW()");
1.1086 + Cancel(); // base class
1.1087 + delete iTimeoutTimer;
1.1088 + iFile.Close();
1.1089 + iFs.Close();
1.1090 + }
1.1091 +
1.1092 +
1.1093 +void CActiveRW::SetMaxBufSize(TInt aBufSz)
1.1094 + {
1.1095 + if (aBufSz > KMaxBufSize)
1.1096 + {
1.1097 + TUSB_PRINT2("SetMaxBufSize(): too large: %d! (using %d)", aBufSz, KMaxBufSize);
1.1098 + aBufSz = KMaxBufSize;
1.1099 + }
1.1100 + iMaxBufSz = aBufSz;
1.1101 + }
1.1102 +
1.1103 +
1.1104 +void CActiveRW::SetMaxPacketSize(TInt aPktSz)
1.1105 + {
1.1106 + iMaxPktSz = aPktSz;
1.1107 + }
1.1108 +
1.1109 +
1.1110 +TInt CActiveRW::MaxBufSize() const
1.1111 + {
1.1112 + return iMaxBufSz;
1.1113 + }
1.1114 +
1.1115 +
1.1116 +void CActiveRW::SetTransferMode(TXferMode aMode)
1.1117 + {
1.1118 + iXferMode = aMode;
1.1119 + if (aMode == EReceiveOnly || aMode == ETransmitOnly)
1.1120 + {
1.1121 + // For streaming transfers we do this only once.
1.1122 + iBufSz = iMaxBufSz;
1.1123 + }
1.1124 + }
1.1125 +
1.1126 +
1.1127 +void CActiveRW::RunL()
1.1128 + {
1.1129 + TUSB_VERBOSE_PRINT("CActiveRW::RunL()");
1.1130 + if (iStatus != KErrNone)
1.1131 + {
1.1132 + TUSB_PRINT1("Error %d in RunL", iStatus.Int());
1.1133 + }
1.1134 + if (iDoStop)
1.1135 + {
1.1136 + TUSB_PRINT("Stopped");
1.1137 + iDoStop = EFalse;
1.1138 + return;
1.1139 + }
1.1140 + switch (iCurrentXfer)
1.1141 + {
1.1142 + case EPreamble:
1.1143 + if (iXferMode != EReceiveOnly)
1.1144 + SendData(); // next we write data
1.1145 + else
1.1146 + ReadData(); // or we read data
1.1147 + break;
1.1148 + case EWriteXfer:
1.1149 + if (iXferMode == ETransmitOnly)
1.1150 + SendData(); // next we send data
1.1151 + else
1.1152 + ReadData(); // or we read data
1.1153 + break;
1.1154 + case EReadXfer:
1.1155 + if (iXferMode == EReceiveOnly)
1.1156 + {
1.1157 + const TUint32 num = *reinterpret_cast<const TUint32*>(iReadBuf.Ptr());
1.1158 + if (num != ++iPktNum)
1.1159 + {
1.1160 + TUSB_PRINT2("*** rcv'd wrong pkt number: 0x%x (expected: 0x%x)", num, iPktNum);
1.1161 + // Update the packet number with the received number, so that
1.1162 + // if a single packet is duplicated or lost then a single error occurs
1.1163 + iPktNum = num;
1.1164 + }
1.1165 + if (iDiskAccessEnabled)
1.1166 + {
1.1167 + // Write out to disk previous completed Read
1.1168 + TUSB_VERBOSE_PRINT2("iMaxBufSz = %d (iReadBuf.Size(): %d)",
1.1169 + iMaxBufSz, iReadBuf.Size());
1.1170 + WriteBufferToDisk(iReadBuf, iMaxBufSz);
1.1171 + }
1.1172 + ReadData(); // next we read data
1.1173 + break;
1.1174 + }
1.1175 + if (iXferMode == ELoopComp)
1.1176 + {
1.1177 + if (!CompareBuffers(iBufSz))
1.1178 + {
1.1179 + TUSB_PRINT1("Error while comparing tx & rx buffers for packet 0x%x", iPktNum);
1.1180 + }
1.1181 + }
1.1182 + else if (iBufSz > 3)
1.1183 + {
1.1184 + const TUint32 num = *reinterpret_cast<const TUint32*>(iReadBuf.Ptr());
1.1185 + if (num != iPktNum)
1.1186 + {
1.1187 + TUSB_PRINT2("*** rcv'd wrong pkt number: 0x%x (expected: 0x%x)", num, iPktNum);
1.1188 + }
1.1189 + }
1.1190 + if (iBufSz == iMaxBufSz)
1.1191 + {
1.1192 + iBufSz = KInitialBufSz;
1.1193 + }
1.1194 + else
1.1195 + {
1.1196 + ++iBufSz;
1.1197 + }
1.1198 + SendPreamble(); // next we send the length
1.1199 + break;
1.1200 + default:
1.1201 + TUSB_PRINT("Oops. (Shouldn't end up here...)");
1.1202 + break;
1.1203 + }
1.1204 + return;
1.1205 + }
1.1206 +
1.1207 +
1.1208 +TInt CActiveRW::SendVersion()
1.1209 + {
1.1210 + TUSB_VERBOSE_PRINT("CActiveRW::SendVersion()");
1.1211 + if (iXferMode != ::ENone)
1.1212 + {
1.1213 + TUSB_PRINT1("Error : wrong state: %d", iXferMode);
1.1214 + return KErrGeneral;
1.1215 + }
1.1216 + // Here we send our version packet to the host.
1.1217 + // (We can use the preamble buffer because we only need it
1.1218 + // once and that's also before the preamble uses.)
1.1219 + TUSB_PRINT1("Sending T_USB version: %d\n", KTusbVersion);
1.1220 + iPreambleBuf.FillZ();
1.1221 + *reinterpret_cast<TUint32*>(&iPreambleBuf[0]) = SWAP_BYTES_32(KTusbVersion);
1.1222 + // A 'magic' string so that USBRFLCT doesn't interpret the first 4 bytes
1.1223 + // of a data preamble packet of an old T_USB as the version number.
1.1224 + iPreambleBuf[4] = 'V';
1.1225 + iPreambleBuf[5] = 'e';
1.1226 + iPreambleBuf[6] = 'r';
1.1227 + iPreambleBuf[7] = 's';
1.1228 + TRequestStatus send_status;
1.1229 + iPort->Write(send_status, EEndpoint1, iPreambleBuf, KPreambleLength);
1.1230 + TUSB_VERBOSE_PRINT("Waiting for write request to complete...");
1.1231 + User::WaitForRequest(send_status);
1.1232 + TUSB_VERBOSE_PRINT("...done.\n");
1.1233 + return send_status.Int();
1.1234 + }
1.1235 +
1.1236 +
1.1237 +TInt CActiveRW::ReceiveVersion()
1.1238 + {
1.1239 + TUSB_VERBOSE_PRINT("CActiveRW::ReceiveVersion()");
1.1240 + if (iXferMode != ::ENone)
1.1241 + {
1.1242 + TUSB_PRINT1("Error : wrong state: %d", iXferMode);
1.1243 + return KErrGeneral;
1.1244 + }
1.1245 + // Here we try to receive a version packet from the host.
1.1246 + // (We can use the preamble buffer because we only need it
1.1247 + // once and that's also before the preamble uses.)
1.1248 + TUSB_PRINT("Getting host program versions...");
1.1249 + iPreambleBuf.FillZ();
1.1250 + TRequestStatus receive_status;
1.1251 + iPort->Read(receive_status, EEndpoint2, iPreambleBuf, KPreambleLength);
1.1252 + TUSB_VERBOSE_PRINT("Waiting for read request to complete...");
1.1253 + iTimeoutTimer->Activate(5000000); // Host gets 5s
1.1254 + User::WaitForRequest(receive_status, iTimeoutTimer->iStatus);
1.1255 + if (receive_status == KRequestPending)
1.1256 + {
1.1257 + // Read() still pending...
1.1258 + TUSB_PRINT("Cancelling USB Read(): no response from host.\n");
1.1259 + iPort->ReadCancel(EEndpoint2);
1.1260 + TUSB_PRINT("THIS COULD BE DUE TO AN OLD VERSION OF USBRFLCT ON THE PC:");
1.1261 + TUSB_PRINT3("PLEASE CHECK THE VERSION THERE - WE NEED AT LEAST V%d.%d.%d!\n",
1.1262 + KUsbrflctVersionMajor, KUsbrflctVersionMinor, KUsbrflctVersionMicro);
1.1263 + TUSB_PRINT("When updating an existing USBRFLCT installation <= v1.3.1,\n" \
1.1264 + L"the following three things will need to be done:\n");
1.1265 + TUSB_PRINT("1. Connect the device to the PC & start T_USB (just as now),\n" \
1.1266 + L"then find the USB device in the Windows Device Manager\n" \
1.1267 + L"('Control Panel'->'System'->'Hardware'->'Device Manager').\n" \
1.1268 + L"Right click on the device name and choose 'Uninstall...'.\n");
1.1269 + TUSB_PRINT("2. In c:\\winnt\\inf\\, find (by searching for \"Symbian\") and\n" \
1.1270 + L"delete the *.INF file that was used to install the existing\n" \
1.1271 + L"version of USBRFLCT.SYS. Make sure to also delete the\n" \
1.1272 + L"precompiled version of that file (<samename>.PNF).\n");
1.1273 + TUSB_PRINT("3. In c:\\winnt\\system32\\drivers\\, delete the file USBRFLCT.SYS.\n");
1.1274 + TUSB_PRINT("Then unplug & reconnect the USB device and, when prompted, install\n" \
1.1275 + L"the new USBRFLCT.SYS driver using the .INF file from this distribution.\n" \
1.1276 + L"(All files can be found under e32test\\win32\\usbrflct_distribution\\.)\n");
1.1277 + TUSB_PRINT("Use the new USBRFLCT.EXE from this distribution.\n");
1.1278 + }
1.1279 + else
1.1280 + {
1.1281 + TUSB_VERBOSE_PRINT("...done.");
1.1282 + // Timeout not needed any longer
1.1283 + TUSB_VERBOSE_PRINT("Cancelling timeout timer: USB Read() completed.\n");
1.1284 + iTimeoutTimer->Cancel();
1.1285 + }
1.1286 + return receive_status.Int();
1.1287 + }
1.1288 +
1.1289 +
1.1290 +TInt CActiveRW::ExchangeVersions()
1.1291 + {
1.1292 + TUSB_VERBOSE_PRINT("CActiveRW::ExchangeVersions()");
1.1293 + // First check the version of USBRFLCT that's running on the host
1.1294 + TInt r = ReceiveVersion();
1.1295 + if (r != KErrNone)
1.1296 + {
1.1297 + return KErrGeneral;
1.1298 + }
1.1299 + TUint8 usbrflct_ver_major = iPreambleBuf[0];
1.1300 + TUint8 usbrflct_ver_minor = iPreambleBuf[1];
1.1301 + TUint8 usbrflct_ver_micro = iPreambleBuf[2];
1.1302 + TUint8 usbio_ver_major = iPreambleBuf[3];
1.1303 + TUint8 usbio_ver_minor = iPreambleBuf[4];
1.1304 + TUSB_PRINT5("Host-side: USBRFLCT v%d.%d.%d USBIO v%d.%d\n",
1.1305 + usbrflct_ver_major, usbrflct_ver_minor, usbrflct_ver_micro,
1.1306 + usbio_ver_major, usbio_ver_minor);
1.1307 + if (usbrflct_ver_major < KUsbrflctVersionMajor)
1.1308 + {
1.1309 + TUSB_PRINT1("USBRFLCT version not sufficient (need at least v%d.x.x)\n",
1.1310 + KUsbrflctVersionMajor);
1.1311 + return KErrGeneral;
1.1312 + }
1.1313 + // Just using '<' instead of the seemingly absurd '<= && !==' doesn't work without
1.1314 + // GCC compiler warning because Kxxx can also be zero (in which case there's no '<').
1.1315 + else if ((usbrflct_ver_minor <= KUsbrflctVersionMinor) &&
1.1316 + !(usbrflct_ver_minor == KUsbrflctVersionMinor))
1.1317 + {
1.1318 + TUSB_PRINT2("USBRFLCT version not sufficient (need at least v%d.%d.x)\n",
1.1319 + KUsbrflctVersionMajor, KUsbrflctVersionMinor);
1.1320 + return KErrGeneral;
1.1321 + }
1.1322 + // Just using '<' instead of the seemingly absurd '<= && !==' doesn't work without
1.1323 + // GCC compiler warning because Kxxx can also be zero (in which case there's no '<').
1.1324 + else if ((usbrflct_ver_micro <= KUsbrflctVersionMicro) &&
1.1325 + !(usbrflct_ver_micro == KUsbrflctVersionMicro))
1.1326 + {
1.1327 + TUSB_PRINT3("USBRFLCT version not sufficient (need at least v%d.%d.%d)\n",
1.1328 + KUsbrflctVersionMajor, KUsbrflctVersionMinor, KUsbrflctVersionMicro);
1.1329 + return KErrGeneral;
1.1330 + }
1.1331 + // Now we send T_USB's version to the host
1.1332 + r = SendVersion();
1.1333 + if (r != KErrNone)
1.1334 + {
1.1335 + return KErrGeneral;
1.1336 + }
1.1337 + return KErrNone;
1.1338 + }
1.1339 +
1.1340 +
1.1341 +void CActiveRW::SendPreamble()
1.1342 + {
1.1343 + TUSB_VERBOSE_PRINT("CActiveRW::SendPreamble()");
1.1344 + __ASSERT_ALWAYS(!IsActive(), User::Panic(KActivePanic, 666));
1.1345 + TUSB_VERBOSE_PRINT1("Sending data length: %d bytes", iBufSz);
1.1346 + *reinterpret_cast<TUint32*>(&iPreambleBuf[0]) = SWAP_BYTES_32(iBufSz);
1.1347 + iPort->Write(iStatus, EEndpoint1, iPreambleBuf, KPreambleLength);
1.1348 + iCurrentXfer = EPreamble;
1.1349 + SetActive();
1.1350 + }
1.1351 +
1.1352 +
1.1353 +void CActiveRW::SendData()
1.1354 + {
1.1355 + TUSB_VERBOSE_PRINT("CActiveRW::SendData()");
1.1356 + __ASSERT_ALWAYS(!IsActive(), User::Panic(KActivePanic, 666));
1.1357 + if (iDiskAccessEnabled)
1.1358 + {
1.1359 + ReadBufferFromDisk(iWriteBuf, iBufSz);
1.1360 + }
1.1361 + ++iPktNum;
1.1362 + if (iBufSz > 3)
1.1363 + {
1.1364 + *reinterpret_cast<TUint32*>(const_cast<TUint8*>(iWriteBuf.Ptr())) = iPktNum;
1.1365 + }
1.1366 + if (iXferMode == ELoopComp)
1.1367 + {
1.1368 + for (TInt i = 4; i < iBufSz; i++)
1.1369 + {
1.1370 + iWriteBuf[i] = static_cast<TUint8>(iPktNum & 0x000000ff);
1.1371 + }
1.1372 + }
1.1373 + TUSB_VERBOSE_PRINT1("Sending data: %d bytes", iBufSz);
1.1374 + iPort->Write(iStatus, EEndpoint1, iWriteBuf, iBufSz);
1.1375 + iCurrentXfer = EWriteXfer;
1.1376 + SetActive();
1.1377 + }
1.1378 +
1.1379 +
1.1380 +TInt CActiveRW::SelectDrive()
1.1381 + {
1.1382 + TDriveList driveList;
1.1383 + TInt r = iFs.DriveList(driveList);
1.1384 + if (r != KErrNone)
1.1385 + {
1.1386 + TUSB_PRINT1("RFs::DriveList() returned %d", r);
1.1387 + return r;
1.1388 + }
1.1389 + TUSB_PRINT("Available drives:");
1.1390 + for (TInt n = 0; n < KMaxDrives; n++)
1.1391 + {
1.1392 + if (driveList[n] != 0)
1.1393 + {
1.1394 + TVolumeInfo volumeInfo;
1.1395 + r = iFs.Volume(volumeInfo, n);
1.1396 + if (r == KErrNone)
1.1397 + {
1.1398 + TPtr name(volumeInfo.iName.Des());
1.1399 + TUSB_PRINT2("Drive %c: %- 16S", 'A' + n, &name);
1.1400 + if (volumeInfo.iDrive.iMediaAtt & KMediaAttWriteProtected)
1.1401 + TUSB_PRINT(" (read-only)");
1.1402 + TUSB_PRINT("");
1.1403 + }
1.1404 + }
1.1405 + }
1.1406 + iConsole->Printf(_L("Please select a drive letter (or 'Q' to quit)..."));
1.1407 + TChar driveLetter;
1.1408 + TInt driveNumber;
1.1409 + TVolumeInfo volumeInfo;
1.1410 + do
1.1411 + {
1.1412 + driveLetter = (TUint)iConsole->Getch();
1.1413 + driveLetter.UpperCase();
1.1414 + if (driveLetter == 'Q')
1.1415 + {
1.1416 + return KErrCancel;
1.1417 + }
1.1418 + driveNumber = (TUint)driveLetter - 'A';
1.1419 + r = iFs.Volume(volumeInfo, driveNumber);
1.1420 + }
1.1421 + while ((driveNumber < 0) ||
1.1422 + (driveNumber >= KMaxDrives) ||
1.1423 + (r) ||
1.1424 + (driveList[driveNumber] == 0) ||
1.1425 + (volumeInfo.iDrive.iMediaAtt & KMediaAttWriteProtected));
1.1426 +
1.1427 + iFileName.Format(_L("%c:"), driveLetter.operator TUint());
1.1428 + iFileName.Append(KFileName);
1.1429 + TUSB_PRINT1("\nFilename = %S", &iFileName);
1.1430 + TUSB_PRINT1("File size: %d", KMaxFileSize);
1.1431 + return r;
1.1432 + }
1.1433 +
1.1434 +
1.1435 +TInt CActiveRW::WriteToDisk(TBool aEnable)
1.1436 + {
1.1437 + iDiskAccessEnabled = aEnable;
1.1438 + TInt r = KErrNone;
1.1439 +
1.1440 + if (iDiskAccessEnabled)
1.1441 + {
1.1442 + r = SelectDrive();
1.1443 + if (r != KErrNone)
1.1444 + {
1.1445 + iDiskAccessEnabled = EFalse;
1.1446 + return r;
1.1447 + }
1.1448 + // open the record file
1.1449 + r = iFile.Replace(iFs, iFileName, EFileWrite);
1.1450 + iFileOffset = 0;
1.1451 + }
1.1452 + return r;
1.1453 + }
1.1454 +
1.1455 +
1.1456 +TInt CActiveRW::ReadFromDisk(TBool aEnable)
1.1457 + {
1.1458 + iDiskAccessEnabled = aEnable;
1.1459 + TInt r = KErrNone;
1.1460 +
1.1461 + if (iDiskAccessEnabled)
1.1462 + {
1.1463 + r = SelectDrive();
1.1464 + if (r != KErrNone)
1.1465 + {
1.1466 + iDiskAccessEnabled = EFalse;
1.1467 + return r;
1.1468 + }
1.1469 + // First create the file & fill it
1.1470 + r = iFile.Replace(iFs, iFileName, EFileWrite);
1.1471 + if (r != KErrNone)
1.1472 + {
1.1473 + TUSB_PRINT1("RFile::Replace() returned %d", r);
1.1474 + iDiskAccessEnabled = EFalse;
1.1475 + return r;
1.1476 + }
1.1477 + const TInt KBufferSize = 4 * 1024;
1.1478 + TBuf8<KBufferSize> buffer;
1.1479 + buffer.SetLength(KBufferSize);
1.1480 + for (TInt n = 0; n < KBufferSize; n++)
1.1481 + {
1.1482 + buffer[n] = static_cast<TUint8>(n & 0x000000ff);
1.1483 + }
1.1484 + TUSB_PRINT("Writing data to file (this may take some minutes...)");
1.1485 + for (TInt n = 0; n < KMaxFileSize; n += KBufferSize)
1.1486 + {
1.1487 + r = iFile.Write(buffer, KBufferSize);
1.1488 + if (r != KErrNone)
1.1489 + {
1.1490 + TUSB_PRINT1("RFile::Write() returned %d (disk full?)", r);
1.1491 + iFile.Close();
1.1492 + iDiskAccessEnabled = EFalse;
1.1493 + return r;
1.1494 + }
1.1495 + }
1.1496 + TUSB_PRINT("Done.");
1.1497 + iFile.Close();
1.1498 + // Now open the file for reading
1.1499 + r = iFile.Open(iFs, iFileName, EFileRead);
1.1500 + if (r != KErrNone)
1.1501 + {
1.1502 + TUSB_PRINT1("RFile::Open() returned %d", r);
1.1503 + iDiskAccessEnabled = EFalse;
1.1504 + return r;
1.1505 + }
1.1506 + iFileOffset = 0;
1.1507 + }
1.1508 + return r;
1.1509 + }
1.1510 +
1.1511 +
1.1512 +void CActiveRW::WriteBufferToDisk(TDes8& aBuffer, TInt aLen)
1.1513 + {
1.1514 + TUSB_VERBOSE_PRINT1("CActiveRW::WriteBufferToDisk(), len = %d", aLen);
1.1515 + TInt r = iFile.Write(aBuffer, aLen);
1.1516 + if (r != KErrNone)
1.1517 + {
1.1518 + TUSB_PRINT2("Error writing to %S (%d)", &iFileName, r);
1.1519 + iDiskAccessEnabled = EFalse;
1.1520 + return;
1.1521 + }
1.1522 + iFileOffset += aLen;
1.1523 + if (iFileOffset >= KMaxFileSize)
1.1524 + {
1.1525 + iFileOffset = 0;
1.1526 + iFile.Seek(ESeekStart, iFileOffset);
1.1527 + }
1.1528 + }
1.1529 +
1.1530 +
1.1531 +void CActiveRW::ReadBufferFromDisk(TDes8& aBuffer, TInt aLen)
1.1532 + {
1.1533 + if (iFileOffset + aLen >= KMaxFileSize)
1.1534 + {
1.1535 + iFileOffset = 0;
1.1536 + iFile.Seek(ESeekStart, iFileOffset);
1.1537 + }
1.1538 + const TInt r = iFile.Read(aBuffer, aLen);
1.1539 + if (r != KErrNone)
1.1540 + {
1.1541 + TUSB_PRINT2("Error reading from %S (%d)", &iFileName, r);
1.1542 + iDiskAccessEnabled = EFalse;
1.1543 + return;
1.1544 + }
1.1545 + TInt readLen = aBuffer.Length();
1.1546 + TUSB_VERBOSE_PRINT1("CActiveRW::ReadBufferFromDisk(), len = %d\n", readLen);
1.1547 + if (readLen < aLen)
1.1548 + {
1.1549 + TUSB_PRINT3("Only %d bytes of %d read from file %S)",
1.1550 + readLen, aLen, &iFileName);
1.1551 + iDiskAccessEnabled = EFalse;
1.1552 + return;
1.1553 + }
1.1554 + iFileOffset += aLen;
1.1555 + }
1.1556 +
1.1557 +
1.1558 +void CActiveRW::ReadData()
1.1559 + {
1.1560 + TUSB_VERBOSE_PRINT("CActiveRW::ReadData()");
1.1561 + __ASSERT_ALWAYS(!IsActive(), User::Panic(KActivePanic, 666));
1.1562 + TUSB_VERBOSE_PRINT1("Reading data: %d bytes", iBufSz);
1.1563 + if (iXferMode == EReceiveOnly)
1.1564 + {
1.1565 + TUSB_VERBOSE_PRINT(" (rx only)");
1.1566 + iPort->Read(iStatus, EEndpoint2, iReadBuf, iBufSz);
1.1567 + }
1.1568 + else if (iBufSz == iMaxPktSz)
1.1569 + {
1.1570 + // we also want to test the packet version of Read()
1.1571 + TUSB_VERBOSE_PRINT(" (a single packet)");
1.1572 + iPort->ReadPacket(iStatus, EEndpoint2, iReadBuf, iBufSz);
1.1573 + }
1.1574 + else if (iBufSz == iReadBuf.MaxSize())
1.1575 + {
1.1576 + // or we could perhaps test the three-parameter version
1.1577 + TUSB_VERBOSE_PRINT(" (w/o length)");
1.1578 + iPort->Read(iStatus, EEndpoint2, iReadBuf);
1.1579 + }
1.1580 + else
1.1581 + {
1.1582 + // otherwise, we use the universal default version
1.1583 + TUSB_VERBOSE_PRINT(" (normal)");
1.1584 + iPort->Read(iStatus, EEndpoint2, iReadBuf, iBufSz);
1.1585 + }
1.1586 + iCurrentXfer = EReadXfer;
1.1587 + SetActive();
1.1588 + }
1.1589 +
1.1590 +
1.1591 +void CActiveRW::Stop()
1.1592 + {
1.1593 + if (!IsActive())
1.1594 + {
1.1595 + TUSB_PRINT("CActiveRW::Stop(): Not active");
1.1596 + return;
1.1597 + }
1.1598 + TUSB_PRINT("Cancelling outstanding transfer requests\n");
1.1599 + iBufSz = KInitialBufSz;
1.1600 + iPktNum = ~0;
1.1601 + iDoStop = ETrue;
1.1602 + iCurrentXfer = ENone;
1.1603 + Cancel();
1.1604 + }
1.1605 +
1.1606 +
1.1607 +void CActiveRW::DoCancel()
1.1608 + {
1.1609 + TUSB_VERBOSE_PRINT("CActiveRW::DoCancel()");
1.1610 + // Canceling the transfer requests can be done explicitly
1.1611 + // for every transfer...
1.1612 + iPort->WriteCancel(EEndpoint1);
1.1613 + iPort->ReadCancel(EEndpoint2);
1.1614 + // or like this:
1.1615 + iPort->EndpointTransferCancel(~0);
1.1616 + }
1.1617 +
1.1618 +
1.1619 +TBool CActiveRW::CompareBuffers(TInt aLen)
1.1620 + {
1.1621 + TUSB_VERBOSE_PRINT1("CActiveRW::CompareBuffers(%d)", aLen);
1.1622 + for (TInt i = 0; i < aLen; i++)
1.1623 + {
1.1624 + if (iReadBuf[i] != iWriteBuf[i])
1.1625 + {
1.1626 + TUSB_VERBOSE_PRINT1("Error: for i = %d:", i);
1.1627 + TUSB_VERBOSE_PRINT2("iReadBuf: %d != iWriteBuf: %d",
1.1628 + iReadBuf[i], iWriteBuf[i]);
1.1629 + return EFalse;
1.1630 + }
1.1631 + }
1.1632 + return ETrue;
1.1633 + }
1.1634 +
1.1635 +
1.1636 +//
1.1637 +// --- class CActiveStallNotifier ---------------------------------------------------------
1.1638 +//
1.1639 +
1.1640 +CActiveStallNotifier::CActiveStallNotifier(CConsoleBase* aConsole, RDevUsbcClient* aPort,
1.1641 + TBool aVerboseOutput)
1.1642 + : CActive(EPriorityNormal),
1.1643 + iConsole(aConsole),
1.1644 + iPort(aPort),
1.1645 + iEndpointState(0),
1.1646 + iVerbose(aVerboseOutput)
1.1647 + {
1.1648 + CActiveScheduler::Add(this);
1.1649 + }
1.1650 +
1.1651 +CActiveStallNotifier* CActiveStallNotifier::NewL(CConsoleBase* aConsole, RDevUsbcClient* aPort,
1.1652 + TBool aVerboseOutput)
1.1653 + {
1.1654 + CActiveStallNotifier* self = new (ELeave) CActiveStallNotifier(aConsole, aPort, aVerboseOutput);
1.1655 + CleanupStack::PushL(self);
1.1656 + self->ConstructL();
1.1657 + CleanupStack::Pop(); // self
1.1658 + return self;
1.1659 + }
1.1660 +
1.1661 +
1.1662 +void CActiveStallNotifier::ConstructL()
1.1663 + {}
1.1664 +
1.1665 +
1.1666 +CActiveStallNotifier::~CActiveStallNotifier()
1.1667 + {
1.1668 + TUSB_VERBOSE_PRINT("CActiveStallNotifier::~CActiveStallNotifier()");
1.1669 + Cancel(); // base class
1.1670 + }
1.1671 +
1.1672 +
1.1673 +void CActiveStallNotifier::DoCancel()
1.1674 + {
1.1675 + TUSB_VERBOSE_PRINT("CActiveStallNotifier::DoCancel()");
1.1676 + iPort->EndpointStatusNotifyCancel();
1.1677 + }
1.1678 +
1.1679 +
1.1680 +void CActiveStallNotifier::RunL()
1.1681 + {
1.1682 + // This just displays the bitmap, showing which endpoints (if any) are now stalled.
1.1683 + // In a real world program, the user could take here appropriate action (cancel a
1.1684 + // transfer request or whatever).
1.1685 + TUSB_VERBOSE_PRINT1("StallNotifier: Endpointstate 0x%x\n", iEndpointState);
1.1686 + Activate();
1.1687 + }
1.1688 +
1.1689 +
1.1690 +void CActiveStallNotifier::Activate()
1.1691 + {
1.1692 + __ASSERT_ALWAYS(!IsActive(), User::Panic(KActivePanic, 666));
1.1693 + iPort->EndpointStatusNotify(iStatus, iEndpointState);
1.1694 + SetActive();
1.1695 + }
1.1696 +
1.1697 +
1.1698 +//
1.1699 +// --- class CActiveDeviceStateNotifier ---------------------------------------------------------
1.1700 +//
1.1701 +
1.1702 +CActiveDeviceStateNotifier::CActiveDeviceStateNotifier(CConsoleBase* aConsole, RDevUsbcClient* aPort,
1.1703 + TBool aVerboseOutput)
1.1704 + : CActive(EPriorityNormal),
1.1705 + iConsole(aConsole),
1.1706 + iPort(aPort),
1.1707 + iDeviceState(0),
1.1708 + iVerbose(aVerboseOutput)
1.1709 + {
1.1710 + CActiveScheduler::Add(this);
1.1711 + }
1.1712 +
1.1713 +CActiveDeviceStateNotifier* CActiveDeviceStateNotifier::NewL(CConsoleBase* aConsole, RDevUsbcClient* aPort,
1.1714 + TBool aVerboseOutput)
1.1715 + {
1.1716 + CActiveDeviceStateNotifier* self = new (ELeave) CActiveDeviceStateNotifier(aConsole, aPort, aVerboseOutput);
1.1717 + CleanupStack::PushL(self);
1.1718 + self->ConstructL();
1.1719 + CleanupStack::Pop(); // self
1.1720 + return self;
1.1721 + }
1.1722 +
1.1723 +
1.1724 +void CActiveDeviceStateNotifier::ConstructL()
1.1725 + {}
1.1726 +
1.1727 +
1.1728 +CActiveDeviceStateNotifier::~CActiveDeviceStateNotifier()
1.1729 + {
1.1730 + TUSB_VERBOSE_PRINT("CActiveDeviceStateNotifier::~CActiveDeviceStateNotifier()");
1.1731 + Cancel(); // base class
1.1732 + }
1.1733 +
1.1734 +
1.1735 +void CActiveDeviceStateNotifier::DoCancel()
1.1736 + {
1.1737 + TUSB_VERBOSE_PRINT("CActiveDeviceStateNotifier::DoCancel()");
1.1738 + iPort->AlternateDeviceStatusNotifyCancel();
1.1739 + }
1.1740 +
1.1741 +
1.1742 +void CActiveDeviceStateNotifier::RunL()
1.1743 + {
1.1744 + // This displays the device state.
1.1745 + // In a real world program, the user could take here appropriate action (cancel a
1.1746 + // transfer request or whatever).
1.1747 + if (!(iDeviceState & KUsbAlternateSetting) && iVerbose)
1.1748 + {
1.1749 + switch (iDeviceState)
1.1750 + {
1.1751 + case EUsbcDeviceStateUndefined:
1.1752 + TUSB_PRINT("Device State notifier: Undefined");
1.1753 + break;
1.1754 + case EUsbcDeviceStateAttached:
1.1755 + TUSB_PRINT("Device State notifier: Attached");
1.1756 + break;
1.1757 + case EUsbcDeviceStatePowered:
1.1758 + TUSB_PRINT("Device State notifier: Powered");
1.1759 + break;
1.1760 + case EUsbcDeviceStateDefault:
1.1761 + TUSB_PRINT("Device State notifier: Default");
1.1762 + break;
1.1763 + case EUsbcDeviceStateAddress:
1.1764 + TUSB_PRINT("Device State notifier: Address");
1.1765 + break;
1.1766 + case EUsbcDeviceStateConfigured:
1.1767 + TUSB_PRINT("Device State notifier: Configured");
1.1768 + break;
1.1769 + case EUsbcDeviceStateSuspended:
1.1770 + TUSB_PRINT("Device State notifier: Suspended");
1.1771 + break;
1.1772 + default:
1.1773 + TUSB_PRINT("Device State notifier: ***BAD***");
1.1774 + }
1.1775 + }
1.1776 + else if (iDeviceState & KUsbAlternateSetting)
1.1777 + {
1.1778 + TUSB_PRINT1("Device State notifier: Alternate interface setting has changed: now %d",
1.1779 + iDeviceState & ~KUsbAlternateSetting);
1.1780 + }
1.1781 + Activate();
1.1782 + }
1.1783 +
1.1784 +
1.1785 +void CActiveDeviceStateNotifier::Activate()
1.1786 + {
1.1787 + __ASSERT_ALWAYS(!IsActive(), User::Panic(KActivePanic, 666));
1.1788 + iPort->AlternateDeviceStatusNotify(iStatus, iDeviceState);
1.1789 + SetActive();
1.1790 + }
1.1791 +
1.1792 +
1.1793 +//
1.1794 +// --- class CActiveTimer ---------------------------------------------------------
1.1795 +//
1.1796 +
1.1797 +CActiveTimer::CActiveTimer(CConsoleBase* aConsole, RDevUsbcClient* aPort,
1.1798 + TBool aVerboseOutput)
1.1799 + : CActive(EPriorityNormal),
1.1800 + iConsole(aConsole),
1.1801 + iPort(aPort),
1.1802 + iVerbose(aVerboseOutput)
1.1803 + {
1.1804 + CActiveScheduler::Add(this);
1.1805 + }
1.1806 +
1.1807 +
1.1808 +CActiveTimer* CActiveTimer::NewL(CConsoleBase* aConsole, RDevUsbcClient* aPort,
1.1809 + TBool aVerboseOutput)
1.1810 + {
1.1811 + CActiveTimer* self = new (ELeave) CActiveTimer(aConsole, aPort, aVerboseOutput);
1.1812 + CleanupStack::PushL(self);
1.1813 + self->ConstructL();
1.1814 + CleanupStack::Pop(); // self
1.1815 + return self;
1.1816 + }
1.1817 +
1.1818 +
1.1819 +void CActiveTimer::ConstructL()
1.1820 + {
1.1821 + User::LeaveIfError(iTimer.CreateLocal());
1.1822 + }
1.1823 +
1.1824 +
1.1825 +CActiveTimer::~CActiveTimer()
1.1826 + {
1.1827 + TUSB_VERBOSE_PRINT("CActiveTimer::~CActiveTimer()");
1.1828 + Cancel(); // base class
1.1829 + iTimer.Close();
1.1830 + }
1.1831 +
1.1832 +
1.1833 +void CActiveTimer::DoCancel()
1.1834 + {
1.1835 + TUSB_VERBOSE_PRINT("CActiveTimer::DoCancel()");
1.1836 + iTimer.Cancel();
1.1837 + }
1.1838 +
1.1839 +
1.1840 +void CActiveTimer::RunL()
1.1841 + {
1.1842 + TUSB_VERBOSE_PRINT("CActiveTimer::RunL()");
1.1843 + // Nothing to do here, as we call ReadCancel() after a manual WaitForRequest()
1.1844 + // (in CActiveRW::ReceiveVersion()).
1.1845 + }
1.1846 +
1.1847 +
1.1848 +void CActiveTimer::Activate(TTimeIntervalMicroSeconds32 aDelay)
1.1849 + {
1.1850 + __ASSERT_ALWAYS(!IsActive(), User::Panic(KActivePanic, 666));
1.1851 + iTimer.After(iStatus, aDelay);
1.1852 + SetActive();
1.1853 + }
1.1854 +
1.1855 +
1.1856 +// -eof-