1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/kernelhwsrv/kerneltest/e32test/device/t_usbapi.cpp Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,2013 @@
1.4 +// Copyright (c) 2003-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_usbapi.cpp
1.18 +// Overview:
1.19 +// USB API Test Program (a standalone USB test program).
1.20 +// API Information:
1.21 +// Details:
1.22 +// - Query whether the platform is operating HS (or it is connected to a HS host) or not,
1.23 +// and executes the appropiate tests in each case (see RunTests() for the actual code,
1.24 +// state machine enclosed for clarity):
1.25 +// - Load and open an EUSBC device driver (logical device)
1.26 +// - Setup the USB interface: query device capabilities, setup interface.
1.27 +// - Test allocating DMA and double buffering resources with
1.28 +// AllocateEndpointResource results in their use being correctly reported by
1.29 +// QueryEndpointResourceUse
1.30 +// - Test descriptor manipulation: validate the device, configuration,
1.31 +// interface, alternate interface, endpoint and string descriptor
1.32 +// manipulation.
1.33 +// HS: device_qualifier and other_speed_configuation descriptors.
1.34 +// - Check and validate the EndpointZeroMaxPacketSizes.
1.35 +// - Quick test that calling the following APIs doesn't generate errors: device
1.36 +// control, AlternateDeviceStatusNotify, EndpointStatusNotify
1.37 +// - Test HaltEndpoint and ClearHaltEndpoint correctly result in endpoint
1.38 +// status being reported as stalled/not stalled.
1.39 +// - Test OTG extensions: OTG descriptor manipulations; set/get OTG feature
1.40 +// - Close and free the logical device.
1.41 +// Platforms/Drives/Compatibility:
1.42 +// All.
1.43 +// Assumptions/Requirement/Pre-requisites:
1.44 +// Failures and causes:
1.45 +// Base Port information:
1.46 +//
1.47 +//
1.48 +
1.49 +
1.50 +#include <e32test.h>
1.51 +#include <e32debug.h>
1.52 +#include <hal.h>
1.53 +#include <d32usbc.h>
1.54 +#include <d32otgdi.h>
1.55 +
1.56 +#include "t_usblib.h"
1.57 +
1.58 +
1.59 +// --- Local Top Level Variables
1.60 +
1.61 +static RTest test(_L("T_USBAPI"));
1.62 +static RDevUsbcClient gPort;
1.63 +static RUsbOtgDriver gOTG;
1.64 +static TBool gSupportsOtg;
1.65 +static TBool gSupportsHighSpeed;
1.66 +static TBool gUsingHighSpeed;
1.67 +static TBool gSoak;
1.68 +static TChar gKeychar = 'a';
1.69 +
1.70 +// Store the actual endpoint number(s) of our alternate interface
1.71 +static TInt INT_IN_ep = -1;
1.72 +
1.73 +_LIT(KUsbLddFilename, "eusbc");
1.74 +_LIT(KOtgdiLddFilename, "otgdi");
1.75 +_LIT(KUsbDeviceName, "Usbc");
1.76 +
1.77 +
1.78 +// --- Local Constants
1.79 +
1.80 +static const TInt KUsbDesc_SizeOffset = 0;
1.81 +static const TInt KUsbDesc_TypeOffset = 1;
1.82 +
1.83 +static const TInt KDevDesc_SpecOffset = 2;
1.84 +static const TInt KDevDesc_DevClassOffset = 4;
1.85 +static const TInt KDevDesc_DevSubClassOffset = 5;
1.86 +static const TInt KDevDesc_DevProtocolOffset = 6;
1.87 +static const TInt KDevDesc_Ep0SizeOffset = 7;
1.88 +static const TInt KDevDesc_VendorIdOffset = 8;
1.89 +static const TInt KDevDesc_ProductIdOffset = 10;
1.90 +static const TInt KDevDesc_DevReleaseOffset = 12;
1.91 +
1.92 +static const TInt KConfDesc_AttribOffset = 7;
1.93 +static const TInt KConfDesc_MaxPowerOffset = 8;
1.94 +
1.95 +static const TInt KIfcDesc_SettingOffset = 2;
1.96 +static const TInt KIfcDesc_ProtocolOffset = 7;
1.97 +
1.98 +static const TInt KEpDesc_PacketSizeOffset = 4;
1.99 +static const TInt KEpDesc_IntervalOffset = 6;
1.100 +static const TInt KEpDesc_SynchAddressOffset = 8;
1.101 +
1.102 +
1.103 +//
1.104 +// Helper.
1.105 +//
1.106 +static TEndpointState QueryEndpointState(TEndpointNumber aEndpoint)
1.107 + {
1.108 + TEndpointState ep_state = EEndpointStateUnknown;
1.109 + TInt r = gPort.EndpointStatus(aEndpoint, ep_state);
1.110 + test(r == KErrNone);
1.111 + test.Printf(_L("Endpoint %d state: %s\n"), aEndpoint,
1.112 + (ep_state == EEndpointStateNotStalled) ? _S("Not stalled") :
1.113 + ((ep_state == EEndpointStateStalled) ? _S("Stalled") :
1.114 + _S("Unknown...")));
1.115 + return ep_state;
1.116 + }
1.117 +
1.118 +
1.119 +// --- Class CActiveKeypressNotifier
1.120 +
1.121 +class CActiveKeypressNotifier : public CActive
1.122 + {
1.123 +public:
1.124 + static CActiveKeypressNotifier* NewL(CConsoleBase* aConsole);
1.125 + ~CActiveKeypressNotifier();
1.126 + void RequestCharacter();
1.127 + void ProcessKeyPressL(TChar aChar);
1.128 +private:
1.129 + virtual void DoCancel();
1.130 + virtual void RunL();
1.131 + CActiveKeypressNotifier(CConsoleBase* aConsole);
1.132 + void ConstructL() {};
1.133 +private:
1.134 + CConsoleBase* iConsole;
1.135 + };
1.136 +
1.137 +
1.138 +CActiveKeypressNotifier* CActiveKeypressNotifier::NewL(CConsoleBase* aConsole)
1.139 + {
1.140 + CActiveKeypressNotifier* self = new (ELeave) CActiveKeypressNotifier(aConsole);
1.141 + CleanupStack::PushL(self);
1.142 + self->ConstructL();
1.143 + CActiveScheduler::Add(self);
1.144 + CleanupStack::Pop();
1.145 + return self;
1.146 + }
1.147 +
1.148 +
1.149 +CActiveKeypressNotifier::CActiveKeypressNotifier(CConsoleBase* aConsole)
1.150 + : CActive(EPriorityNormal), iConsole(aConsole)
1.151 + {}
1.152 +
1.153 +
1.154 +CActiveKeypressNotifier::~CActiveKeypressNotifier()
1.155 + {
1.156 + Cancel(); // base class cancel -> calls our DoCancel
1.157 + }
1.158 +
1.159 +
1.160 +void CActiveKeypressNotifier::RunL()
1.161 + {
1.162 + gKeychar = (static_cast<TChar>(iConsole->KeyCode()));
1.163 + RequestCharacter();
1.164 + }
1.165 +
1.166 +
1.167 +void CActiveKeypressNotifier::DoCancel()
1.168 + {
1.169 + iConsole->ReadCancel();
1.170 + }
1.171 +
1.172 +
1.173 +void CActiveKeypressNotifier::RequestCharacter()
1.174 + {
1.175 + // A request is issued to the CConsoleBase to accept a character from the keyboard.
1.176 + if (IsActive())
1.177 + {
1.178 + return;
1.179 + }
1.180 + iConsole->Read(iStatus);
1.181 + SetActive();
1.182 + }
1.183 +
1.184 +
1.185 +// --- Actual Test Functions
1.186 +
1.187 +// 2nd Thread helper function
1.188 +static TInt TestThreadFunction(TAny* aPtr)
1.189 + {
1.190 + RThread* other = static_cast<RThread*>(aPtr);
1.191 + RDevUsbcClient port = gPort;
1.192 + // Now try to duplicate the USB channel handle
1.193 + TInt r = port.Duplicate(*other);
1.194 + // Wait for 1 second
1.195 + User::After(1000000);
1.196 + return r;
1.197 + }
1.198 +
1.199 +
1.200 +static void OpenChannel()
1.201 + {
1.202 + test.Start(_L("Open Channel"));
1.203 +
1.204 + test.Next(_L("Load USB LDD"));
1.205 + TInt r = User::LoadLogicalDevice(KUsbLddFilename);
1.206 + test(r == KErrNone || r == KErrAlreadyExists);
1.207 +
1.208 + RDevUsbcClient port1;
1.209 + test.Next(_L("Open local USB channel 1"));
1.210 + r = port1.Open(0);
1.211 + test(r == KErrNone);
1.212 +
1.213 + test.Next(_L("Open global USB channel"));
1.214 + r = gPort.Open(0);
1.215 + test(r == KErrNone);
1.216 +
1.217 + RDevUsbcClient port2;
1.218 + test.Next(_L("Open local USB channel 2"));
1.219 + r = port2.Open(0);
1.220 + test(r == KErrNone);
1.221 +
1.222 + test.Next(_L("Close USB channel 1"));
1.223 + port1.Close();
1.224 +
1.225 + RDevUsbcClient port3;
1.226 + test.Next(_L("Open local USB channel 3"));
1.227 + r = port3.Open(0);
1.228 + test(r == KErrNone);
1.229 +
1.230 + test.Next(_L("Close USB channel 2"));
1.231 + port2.Close();
1.232 +
1.233 + test.Next(_L("Close USB channel 3"));
1.234 + port3.Close();
1.235 +
1.236 + // Check for OTG support
1.237 + TBuf8<KUsbDescSize_Otg> otg_desc;
1.238 + r = gPort.GetOtgDescriptor(otg_desc);
1.239 + test(r == KErrNotSupported || r == KErrNone);
1.240 + gSupportsOtg = (r != KErrNotSupported) ? ETrue : EFalse;
1.241 +
1.242 + // On an OTG device we have to start the OTG driver, otherwise the Client
1.243 + // stack will remain disabled forever.
1.244 + if (gSupportsOtg)
1.245 + {
1.246 + test.Printf(_L("Running on OTG device: loading OTG driver\n"));
1.247 + test.Next(_L("Load OTG LDD"));
1.248 + r = User::LoadLogicalDevice(KOtgdiLddFilename);
1.249 + test((r == KErrNone) || (r == KErrAlreadyExists));
1.250 +
1.251 + test.Next(_L("Open OTG channel"));
1.252 + r = gOTG.Open();
1.253 + test(r == KErrNone);
1.254 +
1.255 + test.Next(_L("Start OTG stack"));
1.256 + r = gOTG.StartStacks();
1.257 + test(r == KErrNone);
1.258 + }
1.259 +
1.260 + // Try duplicating channel handle in a second thread
1.261 + // (which should not work because we don't support it)
1.262 +
1.263 + test.Next(_L("Create 2nd Thread"));
1.264 + RThread me;
1.265 + TThreadId me_id = me.Id();
1.266 + // We need to open the RThread object, otherwise we'll only get the
1.267 + // 'special' handle 0xFFFF8001.
1.268 + test(me.Open(me_id) == KErrNone);
1.269 + RThread test_thread;
1.270 + TBuf<17> name = _L("tusbapitestthread");
1.271 + test(test_thread.Create(name, TestThreadFunction, 0x1000, NULL, &me) == KErrNone);
1.272 + test.Next(_L("Logon to 2nd Thread"));
1.273 + TRequestStatus stat;
1.274 + test_thread.Logon(stat);
1.275 + test(stat == KRequestPending);
1.276 + test_thread.Resume();
1.277 + test.Next(_L("Wait for 2nd Thread to exit"));
1.278 + User::WaitForRequest(stat);
1.279 + // Check correct return value of RDevUsbcClient::Duplicate()
1.280 + test(stat == KErrAccessDenied);
1.281 + test.Next(_L("Close 2nd Thread"));
1.282 + test_thread.Close();
1.283 +
1.284 + test.End();
1.285 + }
1.286 +
1.287 +
1.288 +static void TestResourceAllocation()
1.289 + {
1.290 + test.Start(_L("Test Endpoint Resource Allocation"));
1.291 +
1.292 + test.Next(_L("Request DMA resource"));
1.293 + const TInt dma = gPort.AllocateEndpointResource(EEndpoint1, EUsbcEndpointResourceDMA);
1.294 + TBool res = gPort.QueryEndpointResourceUse(EEndpoint1, EUsbcEndpointResourceDMA);
1.295 + test.Printf(_L("DMA on endpoint 1 %s\n"),
1.296 + res ? _S("now allocated") : _S("not allocated"));
1.297 + if (dma == KErrNone)
1.298 + // Only if DMA resource was successfully allocated should we expect truth here:
1.299 + test(res);
1.300 + else
1.301 + test(!res);
1.302 +
1.303 + test.Next(_L("Request Double Buffering resource"));
1.304 + const TInt db = gPort.AllocateEndpointResource(EEndpoint1, EUsbcEndpointResourceDoubleBuffering);
1.305 + res = gPort.QueryEndpointResourceUse(EEndpoint1, EUsbcEndpointResourceDoubleBuffering);
1.306 + test.Printf(_L("Double Buffering on endpoint 1 %s\n"),
1.307 + res ? _S("now allocated") : _S("not allocated"));
1.308 + if (db == KErrNone)
1.309 + // Only if DB resource was successfully allocated should we expect truth here:
1.310 + test(res);
1.311 + else
1.312 + test(!res);
1.313 +
1.314 + test.Next(_L("Deallocate Double Buffering resource"));
1.315 + TInt r = gPort.DeAllocateEndpointResource(EEndpoint1, EUsbcEndpointResourceDoubleBuffering);
1.316 + // Whether DB is dynamic or permanent - deallocation (if supported) should always return success:
1.317 + if (db == KErrNone)
1.318 + test(r == KErrNone);
1.319 + else
1.320 + test(r != KErrNone);
1.321 + res = gPort.QueryEndpointResourceUse(EEndpoint1, EUsbcEndpointResourceDoubleBuffering);
1.322 + test.Printf(_L("Double Buffering on endpoint 1 %s\n"),
1.323 + res ? _S("still allocated") : _S("not (longer) allocated"));
1.324 +
1.325 + test.Next(_L("Deallocate DMA resource"));
1.326 + r = gPort.DeAllocateEndpointResource(EEndpoint1, EUsbcEndpointResourceDMA);
1.327 + // Whether DMA is dynamic or permanent - deallocation (if supported) should always return success:
1.328 + if (dma == KErrNone)
1.329 + test(r == KErrNone);
1.330 + else
1.331 + test(r != KErrNone);
1.332 + res = gPort.QueryEndpointResourceUse(EEndpoint1, EUsbcEndpointResourceDMA);
1.333 + test.Printf(_L("DMA on endpoint 1 %s\n"),
1.334 + res ? _S("still allocated") : _S("not (longer) allocated"));
1.335 +
1.336 + test.End();
1.337 + }
1.338 +
1.339 +
1.340 +static void SetupInterface()
1.341 + {
1.342 + test.Start(_L("Query USB device caps and set up interface"));
1.343 +
1.344 + // Device caps
1.345 + test.Next(_L("Query USB device caps"));
1.346 + TUsbDeviceCaps d_caps;
1.347 + TInt r = gPort.DeviceCaps(d_caps);
1.348 + test(r == KErrNone);
1.349 + TInt n = d_caps().iTotalEndpoints;
1.350 +
1.351 + // Global variable - we'll need this value later
1.352 + gSupportsHighSpeed = d_caps().iHighSpeed;
1.353 +
1.354 + test.Printf(_L("### USB device capabilities:\n"));
1.355 + test.Printf(_L("Number of endpoints: %d\n"), n);
1.356 + test.Printf(_L("Supports Software-Connect: %s\n"),
1.357 + d_caps().iConnect ? _S("yes") : _S("no"));
1.358 + test.Printf(_L("Device is Self-Powered: %s\n"),
1.359 + d_caps().iSelfPowered ? _S("yes") : _S("no"));
1.360 + test.Printf(_L("Supports Remote-Wakeup: %s\n"),
1.361 + d_caps().iRemoteWakeup ? _S("yes") : _S("no"));
1.362 + test.Printf(_L("Supports High-speed: %s\n"),
1.363 + gSupportsHighSpeed ? _S("yes") : _S("no"));
1.364 + test.Printf(_L("Supports OTG: %s\n"),
1.365 + gSupportsOtg ? _S("yes") : _S("no"));
1.366 + test.Printf(_L("Supports unpowered cable detection: %s\n"),
1.367 + (d_caps().iFeatureWord1 & KUsbDevCapsFeatureWord1_CableDetectWithoutPower) ?
1.368 + _S("yes") : _S("no"));
1.369 + test.Printf(_L("Supports endpoint resource alloc scheme V2: %s\n"),
1.370 + (d_caps().iFeatureWord1 & KUsbDevCapsFeatureWord1_EndpointResourceAllocV2) ?
1.371 + _S("yes") : _S("no"));
1.372 +
1.373 + test(n >= 2);
1.374 + test.Printf(_L("(Device has sufficient endpoints.)\n"));
1.375 +
1.376 + // Endpoint caps
1.377 + test.Next(_L("Query USB endpoint caps"));
1.378 + TUsbcEndpointData data[KUsbcMaxEndpoints];
1.379 + TPtr8 dataptr(reinterpret_cast<TUint8*>(data), sizeof(data), sizeof(data));
1.380 + r = gPort.EndpointCaps(dataptr);
1.381 + test(r == KErrNone);
1.382 +
1.383 + test.Printf(_L("### USB device endpoint capabilities:\n"));
1.384 + for (TInt i = 0; i < n; i++)
1.385 + {
1.386 + const TUsbcEndpointCaps* caps = &data[i].iCaps;
1.387 + test.Printf(_L("Endpoint: SizeMask = 0x%08x TypeDirMask = 0x%08x\n"),
1.388 + caps->iSizes, caps->iTypesAndDir);
1.389 + if (caps->iHighBandwidth)
1.390 + {
1.391 + test.Printf(_L(" (high-speed, high bandwidth endpoint)\n"));
1.392 + // Must be HS Int or Iso ep
1.393 + test(gSupportsHighSpeed);
1.394 + test(caps->iTypesAndDir & (KUsbEpTypeIsochronous | KUsbEpTypeInterrupt));
1.395 + }
1.396 + }
1.397 +
1.398 + test.Next(_L("Looking for suitable endpoints"));
1.399 + // Set the active interface
1.400 + TUsbcInterfaceInfoBuf ifc;
1.401 + TInt ep_found = 0;
1.402 + TBool foundBulkIN = EFalse;
1.403 + TBool foundBulkOUT = EFalse;
1.404 + for (TInt i = 0; i < n; i++)
1.405 + {
1.406 + const TUsbcEndpointCaps* caps = &data[i].iCaps;
1.407 + const TInt mps = caps->MaxPacketSize();
1.408 + if (!foundBulkIN &&
1.409 + (caps->iTypesAndDir & (KUsbEpTypeBulk | KUsbEpDirIn)) ==
1.410 + (KUsbEpTypeBulk | KUsbEpDirIn))
1.411 + {
1.412 + // EEndpoint1 is going to be our TX (IN, write) endpoint
1.413 + ifc().iEndpointData[0].iType = KUsbEpTypeBulk;
1.414 + ifc().iEndpointData[0].iDir = KUsbEpDirIn;
1.415 + ifc().iEndpointData[0].iSize = mps;
1.416 + foundBulkIN = ETrue;
1.417 + if (++ep_found == 2)
1.418 + break;
1.419 + }
1.420 + else if (!foundBulkOUT &&
1.421 + (caps->iTypesAndDir & (KUsbEpTypeBulk | KUsbEpDirOut)) ==
1.422 + (KUsbEpTypeBulk | KUsbEpDirOut))
1.423 + {
1.424 + // EEndpoint2 is going to be our RX (OUT, read) endpoint
1.425 + ifc().iEndpointData[1].iType = KUsbEpTypeBulk;
1.426 + ifc().iEndpointData[1].iDir = KUsbEpDirOut;
1.427 + ifc().iEndpointData[1].iSize = mps;
1.428 + foundBulkOUT = ETrue;
1.429 + if (++ep_found == 2)
1.430 + break;
1.431 + }
1.432 + }
1.433 + test(ep_found == 2);
1.434 +
1.435 + test.Next(_L("Setting up main interface"));
1.436 + _LIT16(string, "T_USBAPI Test Interface (Setting 0)");
1.437 + ifc().iString = const_cast<TDesC16*>(&string);
1.438 + ifc().iTotalEndpointsUsed = 2;
1.439 + ifc().iClass.iClassNum = 0xff;
1.440 + ifc().iClass.iSubClassNum = 0xff;
1.441 + ifc().iClass.iProtocolNum = 0xff;
1.442 + // Set up the interface.
1.443 + r = gPort.SetInterface(0, ifc);
1.444 + test(r == KErrNone);
1.445 +
1.446 + TInt ifc_no = -1;
1.447 + r = gPort.GetAlternateSetting(ifc_no);
1.448 + test(r == KErrUsbDeviceNotConfigured);
1.449 +
1.450 + // Some UDCs won't allow endpoint resource manipulation once the hardware has been
1.451 + // configured and turned on. So we do it here & now:
1.452 + TestResourceAllocation();
1.453 +
1.454 + // On the other hand, since some UDCs won't let us test many features which require
1.455 + // register access until the USB hardware is powered up (and because it might start
1.456 + // out unpowered), we should turn it on here explicitly.
1.457 + // (It will be turned off automatically by the PIL after all tests have been run,
1.458 + // when the interface gets deleted.)
1.459 + test.Next(_L("Powering up UDC (1)"));
1.460 + r = gPort.PowerUpUdc();
1.461 + if (!gSupportsOtg)
1.462 + {
1.463 + test(r == KErrNone);
1.464 + }
1.465 + else
1.466 + {
1.467 + test((r == KErrNone) || (r == KErrNotReady));
1.468 + }
1.469 + if (gSupportsOtg && (r == KErrNotReady))
1.470 + {
1.471 + test.Printf(_L("OTG device but not connected to Host, stopping subtest here.\n"));
1.472 + test.End();
1.473 + return;
1.474 + }
1.475 + // The board might be attached to a PC with HS controller, thus enabling us
1.476 + // to test some HS-specific features. For that to work we have to connect
1.477 + // the board to the PC. The "Found new device" box that may pop up on the PC
1.478 + // in response to this can be ignored (i.e. just closed).
1.479 + test.Next(_L("Connecting to Host (1)"));
1.480 + r = gPort.DeviceConnectToHost();
1.481 + test(r == KErrNone);
1.482 + // Suspend thread to let things get stable on the bus.
1.483 + test.Printf(_L("Waiting a short moment..."));
1.484 + User::After(2000000);
1.485 + test.Printf(_L(" done.\n"));
1.486 +
1.487 + // Check the speed of the physical connection (if any).
1.488 + gUsingHighSpeed = gPort.CurrentlyUsingHighSpeed();
1.489 + if (gUsingHighSpeed)
1.490 + {
1.491 + test(gSupportsHighSpeed); // sane?
1.492 + test.Printf(_L("---> USB High-speed Testing\n"));
1.493 + }
1.494 + else
1.495 + {
1.496 + test.Printf(_L("---> USB Full-speed Testing\n"));
1.497 + }
1.498 +
1.499 + // By pulling down the interface/connection and bringing them up again we
1.500 + // simulate a starting/stopping of the USB service by a control app.
1.501 +
1.502 + test.Next(_L("Disconnecting from Host"));
1.503 + r = gPort.DeviceDisconnectFromHost();
1.504 + test(r == KErrNone);
1.505 +
1.506 + test.Next(_L("Releasing interface"));
1.507 + r = gPort.ReleaseInterface(0);
1.508 + test(r == KErrNone);
1.509 +
1.510 + test.Next(_L("Setting interface"));
1.511 + r = gPort.SetInterface(0, ifc);
1.512 + test(r == KErrNone);
1.513 +
1.514 + // Suspend thread before connecting again.
1.515 + test.Printf(_L("Waiting a short moment..."));
1.516 + User::After(1000000);
1.517 + test.Printf(_L(" done.\n"));
1.518 +
1.519 + test.Next(_L("Powering up UDC (2)"));
1.520 + r = gPort.PowerUpUdc();
1.521 + if (!gSupportsOtg)
1.522 + {
1.523 + test(r == KErrNone);
1.524 + }
1.525 + else
1.526 + {
1.527 + test((r == KErrNone) || (r == KErrNotReady));
1.528 + }
1.529 + if (gSupportsOtg && (r == KErrNotReady))
1.530 + {
1.531 + test.Printf(_L("OTG device but not connected to Host, stopping subtest here.\n"));
1.532 + test.End();
1.533 + return;
1.534 + }
1.535 +
1.536 + test.Next(_L("Connecting to Host (2)"));
1.537 + r = gPort.DeviceConnectToHost();
1.538 + test(r == KErrNone);
1.539 + // Suspend thread to let things get stable on the bus.
1.540 + User::After(2000000);
1.541 +
1.542 + test.End();
1.543 + }
1.544 +
1.545 +
1.546 +static void TestDeviceDescriptor()
1.547 + {
1.548 + test.Start(_L("Device Descriptor Manipulation"));
1.549 +
1.550 + test.Next(_L("GetDeviceDescriptorSize()"));
1.551 + TInt desc_size = 0;
1.552 + gPort.GetDeviceDescriptorSize(desc_size);
1.553 + test(static_cast<TUint>(desc_size) == KUsbDescSize_Device);
1.554 +
1.555 + test.Next(_L("GetDeviceDescriptor()"));
1.556 + TBuf8<KUsbDescSize_Device> descriptor;
1.557 + TInt r = gPort.GetDeviceDescriptor(descriptor);
1.558 + test(r == KErrNone);
1.559 +
1.560 + test.Next(_L("SetDeviceDescriptor()"));
1.561 + // Change the USB spec number to 2.30
1.562 + descriptor[KDevDesc_SpecOffset] = 0x30;
1.563 + descriptor[KDevDesc_SpecOffset+1] = 0x02;
1.564 + // Change the device vendor ID (VID) to 0x1234
1.565 + descriptor[KDevDesc_VendorIdOffset] = 0x34; // little endian
1.566 + descriptor[KDevDesc_VendorIdOffset+1] = 0x12;
1.567 + // Change the device product ID (PID) to 0x1111
1.568 + descriptor[KDevDesc_ProductIdOffset] = 0x11;
1.569 + descriptor[KDevDesc_ProductIdOffset+1] = 0x11;
1.570 + // Change the device release number to 3.05
1.571 + descriptor[KDevDesc_DevReleaseOffset] = 0x05;
1.572 + descriptor[KDevDesc_DevReleaseOffset+1] = 0x03;
1.573 + r = gPort.SetDeviceDescriptor(descriptor);
1.574 + test(r == KErrNone);
1.575 +
1.576 + test.Next(_L("GetDeviceDescriptor()"));
1.577 + TBuf8<KUsbDescSize_Device> descriptor2;
1.578 + r = gPort.GetDeviceDescriptor(descriptor2);
1.579 + test(r == KErrNone);
1.580 +
1.581 + test.Next(_L("Compare device descriptor with value set"));
1.582 + r = descriptor2.Compare(descriptor);
1.583 + test(r == KErrNone);
1.584 +
1.585 + if (gUsingHighSpeed)
1.586 + {
1.587 + // HS only allows one possible packet size.
1.588 + test(descriptor[KDevDesc_Ep0SizeOffset] == 64);
1.589 + }
1.590 +
1.591 + test.End();
1.592 + }
1.593 +
1.594 +
1.595 +static void TestDeviceQualifierDescriptor()
1.596 + {
1.597 + test.Start(_L("Device_Qualifier Descriptor Manipulation"));
1.598 +
1.599 + if (!gSupportsHighSpeed)
1.600 + {
1.601 + test.Printf(_L("*** Not supported - skipping Device_Qualifier descriptor tests\n"));
1.602 + test.End();
1.603 + return;
1.604 + }
1.605 +
1.606 + test.Next(_L("GetDeviceQualifierDescriptor()"));
1.607 + TBuf8<KUsbDescSize_DeviceQualifier> descriptor;
1.608 + TInt r = gPort.GetDeviceQualifierDescriptor(descriptor);
1.609 + test(r == KErrNone);
1.610 +
1.611 + test.Next(_L("SetDeviceQualifierDescriptor()"));
1.612 + // Change the USB spec number to 3.00
1.613 + descriptor[KDevDesc_SpecOffset] = 0x00;
1.614 + descriptor[KDevDesc_SpecOffset+1] = 0x03;
1.615 + // Change the device class, subclass and protocol codes
1.616 + descriptor[KDevDesc_DevClassOffset] = 0xA1;
1.617 + descriptor[KDevDesc_DevSubClassOffset] = 0xB2;
1.618 + descriptor[KDevDesc_DevProtocolOffset] = 0xC3;
1.619 + r = gPort.SetDeviceQualifierDescriptor(descriptor);
1.620 + test(r == KErrNone);
1.621 +
1.622 + test.Next(_L("GetDeviceQualifierDescriptor()"));
1.623 + TBuf8<KUsbDescSize_DeviceQualifier> descriptor2;
1.624 + r = gPort.GetDeviceQualifierDescriptor(descriptor2);
1.625 + test(r == KErrNone);
1.626 +
1.627 + test.Next(_L("Compare Device_Qualifier desc with value set"));
1.628 + r = descriptor2.Compare(descriptor);
1.629 + test(r == 0);
1.630 +
1.631 + if (!gUsingHighSpeed)
1.632 + {
1.633 + // HS only allows one possible packet size.
1.634 + test(descriptor[KDevDesc_Ep0SizeOffset] == 64);
1.635 + }
1.636 +
1.637 + test.End();
1.638 + }
1.639 +
1.640 +
1.641 +static void TestConfigurationDescriptor()
1.642 + {
1.643 + test.Start(_L("Configuration Descriptor Manipulation"));
1.644 +
1.645 + test.Next(_L("GetConfigurationDescriptorSize()"));
1.646 + TInt desc_size = 0;
1.647 + gPort.GetConfigurationDescriptorSize(desc_size);
1.648 + test(static_cast<TUint>(desc_size) == KUsbDescSize_Config);
1.649 +
1.650 + test.Next(_L("GetConfigurationDescriptor()"));
1.651 + TBuf8<KUsbDescSize_Config> descriptor;
1.652 + TInt r = gPort.GetConfigurationDescriptor(descriptor);
1.653 + test(r == KErrNone);
1.654 +
1.655 + test.Next(_L("SetConfigurationDescriptor()"));
1.656 + // Invert Remote-Wakup support
1.657 + descriptor[KConfDesc_AttribOffset] = (descriptor[KConfDesc_AttribOffset] ^ KUsbDevAttr_RemoteWakeup);
1.658 + // Change the reported max power to 200mA (2 * 0x64)
1.659 + descriptor[KConfDesc_MaxPowerOffset] = 0x64;
1.660 + r = gPort.SetConfigurationDescriptor(descriptor);
1.661 + test(r == KErrNone);
1.662 +
1.663 + test.Next(_L("GetConfigurationDescriptor()"));
1.664 + TBuf8<KUsbDescSize_Config> descriptor2;
1.665 + r = gPort.GetConfigurationDescriptor(descriptor2);
1.666 + test(r == KErrNone);
1.667 +
1.668 + test.Next(_L("Compare configuration desc with value set"));
1.669 + r = descriptor2.Compare(descriptor);
1.670 + test(r == KErrNone);
1.671 +
1.672 + test.End();
1.673 + }
1.674 +
1.675 +
1.676 +static void TestOtherSpeedConfigurationDescriptor()
1.677 + {
1.678 + test.Start(_L("Other_Speed_Configuration Desc Manipulation"));
1.679 +
1.680 + if (!gSupportsHighSpeed)
1.681 + {
1.682 + test.Printf(_L("*** Not supported - skipping Other_Speed_Configuration desc tests\n"));
1.683 + test.End();
1.684 + return;
1.685 + }
1.686 +
1.687 + test.Next(_L("GetOtherSpeedConfigurationDescriptor()"));
1.688 + TBuf8<KUsbDescSize_OtherSpeedConfig> descriptor;
1.689 + TInt r = gPort.GetOtherSpeedConfigurationDescriptor(descriptor);
1.690 + test(r == KErrNone);
1.691 +
1.692 + test.Next(_L("SetOtherSpeedConfigurationDescriptor()"));
1.693 + // Invert Remote-Wakup support
1.694 + descriptor[KConfDesc_AttribOffset] = (descriptor[KConfDesc_AttribOffset] ^ KUsbDevAttr_RemoteWakeup);
1.695 + // Change the reported max power to 330mA (2 * 0xA5)
1.696 + descriptor[KConfDesc_MaxPowerOffset] = 0xA5;
1.697 + r = gPort.SetOtherSpeedConfigurationDescriptor(descriptor);
1.698 + test(r == KErrNone);
1.699 +
1.700 + test.Next(_L("GetOtherSpeedConfigurationDescriptor()"));
1.701 + TBuf8<KUsbDescSize_OtherSpeedConfig> descriptor2;
1.702 + r = gPort.GetOtherSpeedConfigurationDescriptor(descriptor2);
1.703 + test(r == KErrNone);
1.704 +
1.705 + test.Next(_L("Compare O_S_Config desc with value set"));
1.706 + r = descriptor2.Compare(descriptor);
1.707 + test(r == KErrNone);
1.708 +
1.709 + test.End();
1.710 + }
1.711 +
1.712 +
1.713 +static void TestInterfaceDescriptor()
1.714 + {
1.715 + test.Start(_L("Interface Descriptor Manipulation"));
1.716 +
1.717 + // First the standard Interface descriptor
1.718 +
1.719 + test.Next(_L("GetInterfaceDescriptorSize()"));
1.720 + TInt desc_size = 0;
1.721 + TInt r = gPort.GetInterfaceDescriptorSize(0, desc_size);
1.722 + test(r == KErrNone);
1.723 + test(static_cast<TUint>(desc_size) == KUsbDescSize_Interface);
1.724 +
1.725 + test.Next(_L("GetInterfaceDescriptor()"));
1.726 + TBuf8<KUsbDescSize_Interface> descriptor;
1.727 + r = gPort.GetInterfaceDescriptor(0, descriptor);
1.728 + test(r == KErrNone);
1.729 +
1.730 + test.Next(_L("SetInterfaceDescriptor()"));
1.731 + // Change the interface protocol to 0x78(+)
1.732 + TUint8 prot = 0x78;
1.733 + if (descriptor[KIfcDesc_ProtocolOffset] == prot)
1.734 + prot++;
1.735 + descriptor[KIfcDesc_ProtocolOffset] = prot;
1.736 + r = gPort.SetInterfaceDescriptor(0, descriptor);
1.737 + test(r == KErrNone);
1.738 +
1.739 + test.Next(_L("GetInterfaceDescriptor()"));
1.740 + TBuf8<KUsbDescSize_Interface> descriptor2;
1.741 + r = gPort.GetInterfaceDescriptor(0, descriptor2);
1.742 + test(r == KErrNone);
1.743 +
1.744 + test.Next(_L("Compare interface descriptor with value set"));
1.745 + r = descriptor2.Compare(descriptor);
1.746 + test(r == KErrNone);
1.747 +
1.748 + test.End();
1.749 + }
1.750 +
1.751 +
1.752 +static void TestClassSpecificDescriptors()
1.753 + {
1.754 + test.Start(_L("Class-specific Descriptor Manipulation"));
1.755 +
1.756 + // First a class-specific Interface descriptor
1.757 +
1.758 + test.Next(_L("SetCSInterfaceDescriptorBlock()"));
1.759 + // choose arbitrary new descriptor size
1.760 + const TInt KUsbDescSize_CS_Interface = KUsbDescSize_Interface + 10;
1.761 + TBuf8<KUsbDescSize_CS_Interface> cs_ifc_descriptor;
1.762 + cs_ifc_descriptor.FillZ(cs_ifc_descriptor.MaxLength());
1.763 + cs_ifc_descriptor[KUsbDesc_SizeOffset] = KUsbDescSize_CS_Interface;
1.764 + cs_ifc_descriptor[KUsbDesc_TypeOffset] = KUsbDescType_CS_Interface;
1.765 + TInt r = gPort.SetCSInterfaceDescriptorBlock(0, cs_ifc_descriptor);
1.766 + test(r == KErrNone);
1.767 +
1.768 + test.Next(_L("GetCSInterfaceDescriptorBlockSize()"));
1.769 + TInt desc_size = 0;
1.770 + r = gPort.GetCSInterfaceDescriptorBlockSize(0, desc_size);
1.771 + test(r == KErrNone);
1.772 + test(desc_size == KUsbDescSize_CS_Interface);
1.773 +
1.774 + test.Next(_L("GetCSInterfaceDescriptorBlock()"));
1.775 + TBuf8<KUsbDescSize_CS_Interface> descriptor;
1.776 + r = gPort.GetCSInterfaceDescriptorBlock(0, descriptor);
1.777 + test(r == KErrNone);
1.778 +
1.779 + test.Next(_L("Compare CS ifc descriptor with value set"));
1.780 + r = descriptor.Compare(cs_ifc_descriptor);
1.781 + test(r == KErrNone);
1.782 +
1.783 + // Next a class-specific Endpoint descriptor
1.784 +
1.785 + test.Next(_L("SetCSEndpointDescriptorBlock()"));
1.786 + // choose arbitrary new descriptor size
1.787 + const TInt KUsbDescSize_CS_Endpoint = KUsbDescSize_Endpoint + 5;
1.788 + TBuf8<KUsbDescSize_CS_Endpoint> cs_ep_descriptor;
1.789 + cs_ep_descriptor.FillZ(cs_ep_descriptor.MaxLength());
1.790 + cs_ep_descriptor[KUsbDesc_SizeOffset] = KUsbDescSize_CS_Endpoint;
1.791 + cs_ep_descriptor[KUsbDesc_TypeOffset] = KUsbDescType_CS_Endpoint;
1.792 + r = gPort.SetCSEndpointDescriptorBlock(0, 2, cs_ep_descriptor);
1.793 + test(r == KErrNone);
1.794 +
1.795 + test.Next(_L("GetCSEndpointDescriptorBlockSize()"));
1.796 + r = gPort.GetCSEndpointDescriptorBlockSize(0, 2, desc_size);
1.797 + test(r == KErrNone);
1.798 + test(desc_size == KUsbDescSize_CS_Endpoint);
1.799 +
1.800 + test.Next(_L("GetCSEndpointDescriptorBlock()"));
1.801 + TBuf8<KUsbDescSize_CS_Endpoint> descriptor2;
1.802 + r = gPort.GetCSEndpointDescriptorBlock(0, 2, descriptor2);
1.803 + test(r == KErrNone);
1.804 +
1.805 + test.Next(_L("Compare CS ep descriptor with value set"));
1.806 + r = descriptor2.Compare(cs_ep_descriptor);
1.807 + test(r == KErrNone);
1.808 +
1.809 + test.End();
1.810 + }
1.811 +
1.812 +
1.813 +static void TestAlternateInterfaceManipulation()
1.814 + {
1.815 + test.Start(_L("Alternate Interface Setting Manipulation"));
1.816 +
1.817 + if (!SupportsAlternateInterfaces())
1.818 + {
1.819 + test.Printf(_L("*** Not supported - skipping alternate interface settings tests\n"));
1.820 + test.End();
1.821 + return;
1.822 + }
1.823 +
1.824 + // Fetch endpoint data (again)
1.825 + test.Next(_L("Get endpoint capabilities"));
1.826 + TUsbDeviceCaps d_caps;
1.827 + TInt r = gPort.DeviceCaps(d_caps);
1.828 + test(r == KErrNone);
1.829 + const TInt n = d_caps().iTotalEndpoints;
1.830 + TUsbcEndpointData data[KUsbcMaxEndpoints];
1.831 + TPtr8 dataptr(reinterpret_cast<TUint8*>(data), sizeof(data), sizeof(data));
1.832 + r = gPort.EndpointCaps(dataptr);
1.833 + test(r == KErrNone);
1.834 +
1.835 + // Find ep's for alternate ifc setting
1.836 + test.Next(_L("Find suitable endpoints"));
1.837 + TInt ep_found = 0;
1.838 + TBool foundIsoIN = EFalse;
1.839 + TBool foundIsoOUT = EFalse;
1.840 + TBool foundIntIN = EFalse;
1.841 + TUsbcInterfaceInfoBuf ifc;
1.842 +
1.843 + // NB! We cannot assume that any specific device has any given set of
1.844 + // capabilities, so whilst we try and set an assortment of endpoint types
1.845 + // we may not get what we want.
1.846 +
1.847 + // Also, note that the endpoint[] array in the interface descriptor
1.848 + // must be filled from ep[0]...ep[n-1].
1.849 +
1.850 + for (TInt i = 0; i < n; i++)
1.851 + {
1.852 + const TUsbcEndpointCaps* const caps = &data[i].iCaps;
1.853 + const TInt mps = caps->MaxPacketSize();
1.854 + if (!foundIsoIN &&
1.855 + (caps->iTypesAndDir & (KUsbEpTypeIsochronous | KUsbEpDirIn)) ==
1.856 + (KUsbEpTypeIsochronous | KUsbEpDirIn))
1.857 + {
1.858 + // This is going to be our Iso TX (IN) endpoint
1.859 + ifc().iEndpointData[ep_found].iType = KUsbEpTypeIsochronous;
1.860 + ifc().iEndpointData[ep_found].iDir = KUsbEpDirIn;
1.861 + ifc().iEndpointData[ep_found].iSize = mps;
1.862 + ifc().iEndpointData[ep_found].iInterval = 0x01; // 2^(bInterval-1)ms, bInterval must be [1..16]
1.863 + ifc().iEndpointData[ep_found].iInterval_Hs = 0x01; // same as for FS
1.864 + test.Printf(_L("ISO IN size = %4d (ep %d)\n"), mps, ep_found + 1);
1.865 + foundIsoIN = ETrue;
1.866 + if (++ep_found == 3)
1.867 + break;
1.868 + }
1.869 + else if (!foundIsoOUT &&
1.870 + (caps->iTypesAndDir & (KUsbEpTypeIsochronous | KUsbEpDirOut)) ==
1.871 + (KUsbEpTypeIsochronous | KUsbEpDirOut))
1.872 + {
1.873 + // This is going to be our Iso RX (OUT) endpoint
1.874 + ifc().iEndpointData[ep_found].iType = KUsbEpTypeIsochronous;
1.875 + ifc().iEndpointData[ep_found].iDir = KUsbEpDirOut;
1.876 + ifc().iEndpointData[ep_found].iSize = mps;
1.877 + ifc().iEndpointData[ep_found].iInterval = 0x01; // 2^(bInterval-1)ms, bInterval must be [1..16]
1.878 + test.Printf(_L("ISO OUT size = %4d (ep %d)\n"), mps, ep_found + 1);
1.879 + foundIsoOUT = ETrue;
1.880 + if (++ep_found == 3)
1.881 + break;
1.882 + }
1.883 + else if (!foundIntIN &&
1.884 + (caps->iTypesAndDir & (KUsbEpTypeInterrupt | KUsbEpDirIn)) ==
1.885 + (KUsbEpTypeInterrupt | KUsbEpDirIn))
1.886 + {
1.887 + // This is going to be our Interrupt TX (IN) endpoint
1.888 + ifc().iEndpointData[ep_found].iType = KUsbEpTypeInterrupt;
1.889 + ifc().iEndpointData[ep_found].iDir = KUsbEpDirIn;
1.890 + ifc().iEndpointData[ep_found].iSize = mps;
1.891 + ifc().iEndpointData[ep_found].iInterval = 10; // interval = 10ms, valid range [1..255]
1.892 + ifc().iEndpointData[ep_found].iInterval_Hs = 4; // interval = 2^(bInterval-1)ms = 8ms
1.893 + ifc().iEndpointData[ep_found].iExtra = 2; // 2 extra bytes for Audio Class EP descriptor
1.894 + test.Printf(_L("INT IN size = %4d (ep %d)\n"), mps, ep_found + 1);
1.895 + foundIntIN = ETrue;
1.896 + INT_IN_ep = ep_found + 1;
1.897 + if (++ep_found == 3)
1.898 + break;
1.899 + }
1.900 + }
1.901 +
1.902 + // Let's try to add some more Bulk endpoints up to the max # of 5.
1.903 + for (TInt i = 0; i < n; i++)
1.904 + {
1.905 + TUsbcEndpointCaps& caps = data[i].iCaps;
1.906 + const TUint mps = caps.MaxPacketSize();
1.907 + if (caps.iTypesAndDir & KUsbEpTypeBulk)
1.908 + {
1.909 + const TUint dir = (caps.iTypesAndDir & KUsbEpDirIn) ? KUsbEpDirIn : KUsbEpDirOut;
1.910 + ifc().iEndpointData[ep_found].iType = KUsbEpTypeBulk;
1.911 + ifc().iEndpointData[ep_found].iDir = dir;
1.912 + if (gUsingHighSpeed)
1.913 + {
1.914 + test.Printf(_L("Checking if correct Bulk packet size is reported in HS case\n"));
1.915 + test(mps == KUsbEpSize512); // sane?
1.916 + }
1.917 + // The PSL should in any case also offer the 'legacy' FS size:
1.918 + test(caps.iSizes & KUsbEpSize64);
1.919 + ifc().iEndpointData[ep_found].iSize = mps;
1.920 + test.Printf(_L("BULK %s size = %4d (ep %d)\n"),
1.921 + dir == KUsbEpDirIn ? _S("IN ") : _S("OUT"), mps, ep_found + 1);
1.922 + if (++ep_found == 5)
1.923 + break;
1.924 + }
1.925 + }
1.926 +
1.927 + test.Printf(_L("Total: %d endpoints found for the alt. ifc setting\n"), ep_found);
1.928 + if (ep_found < 3)
1.929 + {
1.930 + test.Printf(_L("(3 endpoints are at least required. Skipping test...)\n"));
1.931 + test.End();
1.932 + return;
1.933 + }
1.934 +
1.935 + if (!foundIsoIN && !foundIsoOUT)
1.936 + {
1.937 + test.Printf(_L("(No Isochronous endpoints found)\n"));
1.938 + }
1.939 +
1.940 + if (!foundIntIN)
1.941 + {
1.942 + test.Printf(_L("(No Interrupt endpoint found)\n"));
1.943 + test.Printf(_L("Adjusting endpoint size for later test\n"));
1.944 + // We want to make sure that at least one descriptor has the 2 extra bytes.
1.945 + // It doesn't matter that this ep could be a Bulk one, or that the 2 Iso ep's might be missing -
1.946 + // we just want to test some functionality and we're not going to use this interface in earnest.
1.947 + ifc().iEndpointData[2].iExtra = 2; // 2 extra bytes for Audio Class Ep descriptor
1.948 + INT_IN_ep = 3; // pretend it's an INT ep
1.949 + }
1.950 +
1.951 + test.Next(_L("Create alternate interface setting"));
1.952 + _LIT16(string, "T_USBAPI Test Interface (Setting 1: Audio)");
1.953 + ifc().iString = const_cast<TDesC16*>(&string);
1.954 + ifc().iTotalEndpointsUsed = ep_found;
1.955 + ifc().iClass.iClassNum = KUsbAudioInterfaceClassCode;
1.956 + ifc().iClass.iSubClassNum = KUsbAudioInterfaceSubclassCode_Audiostreaming;
1.957 + ifc().iClass.iProtocolNum = KUsbAudioInterfaceProtocolCode_Pr_Protocol_Undefined;
1.958 + r = gPort.SetInterface(1, ifc);
1.959 + test(r == KErrNone);
1.960 +
1.961 + test.Next(_L("Set alternate setting number to 8"));
1.962 + TBuf8<KUsbDescSize_Interface> descriptor;
1.963 + r = gPort.GetInterfaceDescriptor(1, descriptor);
1.964 + test(r == KErrNone);
1.965 + descriptor[KIfcDesc_SettingOffset] = 8;
1.966 + r = gPort.SetInterfaceDescriptor(1, descriptor);
1.967 + test(r != KErrNone);
1.968 +
1.969 + test.Next(_L("Change ifc # in def setting whith alt ifcs"));
1.970 + r = gPort.GetInterfaceDescriptor(0, descriptor);
1.971 + test(r == KErrNone);
1.972 + descriptor[KIfcDesc_SettingOffset] = 8;
1.973 + r = gPort.SetInterfaceDescriptor(0, descriptor);
1.974 + test(r != KErrNone);
1.975 +
1.976 + test.Next(_L("Change the ifc # in default setting to 8"));
1.977 + r = gPort.ReleaseInterface(1);
1.978 + test(r == KErrNone);
1.979 + r = gPort.SetInterfaceDescriptor(0, descriptor);
1.980 + test(r == KErrNone);
1.981 +
1.982 + test.Next(_L("Create new setting - this should also get #8"));
1.983 + r = gPort.SetInterface(1, ifc);
1.984 + test(r == KErrNone);
1.985 + r = gPort.GetInterfaceDescriptor(1, descriptor);
1.986 + test(r == KErrNone);
1.987 + test(descriptor[KIfcDesc_SettingOffset] == 8);
1.988 +
1.989 + test.Next(_L("Change the ifc # in default setting to 0"));
1.990 + r = gPort.ReleaseInterface(1);
1.991 + test(r == KErrNone);
1.992 + r = gPort.GetInterfaceDescriptor(0, descriptor);
1.993 + test(r == KErrNone);
1.994 + descriptor[KIfcDesc_SettingOffset] = 0;
1.995 + r = gPort.SetInterfaceDescriptor(0, descriptor);
1.996 + test(r == KErrNone);
1.997 +
1.998 + test.Next(_L("Create new setting - this should also get #0"));
1.999 + r = gPort.SetInterface(1, ifc);
1.1000 + test(r == KErrNone);
1.1001 + r = gPort.GetInterfaceDescriptor(1, descriptor);
1.1002 + test(r == KErrNone);
1.1003 + test(descriptor[KIfcDesc_SettingOffset] == 0);
1.1004 +
1.1005 + test.End();
1.1006 + }
1.1007 +
1.1008 +
1.1009 +static void TestEndpointDescriptor()
1.1010 + {
1.1011 + test.Start(_L("Endpoint Descriptor Manipulation"));
1.1012 +
1.1013 + test.Next(_L("GetEndpointDescriptorSize(1)"));
1.1014 + TInt epNumber = 1;
1.1015 + TInt desc_size = 0;
1.1016 + TInt r = gPort.GetEndpointDescriptorSize(0, epNumber, desc_size);
1.1017 + test(r == KErrNone);
1.1018 + test(static_cast<TUint>(desc_size) == KUsbDescSize_Endpoint);
1.1019 +
1.1020 + test.Next(_L("GetEndpointDescriptor(1)"));
1.1021 + TBuf8<KUsbDescSize_Endpoint> descriptor;
1.1022 + r = gPort.GetEndpointDescriptor(0, epNumber, descriptor);
1.1023 + test(r == KErrNone);
1.1024 +
1.1025 + test.Next(_L("SetEndpointDescriptor(1)"));
1.1026 + // Change the endpoint poll interval
1.1027 + TUint8 ival = 0x66;
1.1028 + if (descriptor[KEpDesc_IntervalOffset] == ival)
1.1029 + ival++;
1.1030 + descriptor[KEpDesc_IntervalOffset] = ival;
1.1031 + r = gPort.SetEndpointDescriptor(0, epNumber, descriptor);
1.1032 + test(r == KErrNone);
1.1033 +
1.1034 + test.Next(_L("GetEndpointDescriptor(1)"));
1.1035 + TBuf8<KUsbDescSize_Endpoint> descriptor2;
1.1036 + r = gPort.GetEndpointDescriptor(0, epNumber, descriptor2);
1.1037 + test(r == KErrNone);
1.1038 +
1.1039 + test.Next(_L("Compare endpoint descriptor with value set"));
1.1040 + r = descriptor2.Compare(descriptor);
1.1041 + test(r == KErrNone);
1.1042 +
1.1043 + test.Next(_L("Check endpoint max packet size"));
1.1044 + const TUint16 ep_size = EpSize(descriptor[KEpDesc_PacketSizeOffset],
1.1045 + descriptor[KEpDesc_PacketSizeOffset+1]);
1.1046 + test.Printf(_L(" Size: %d\n"), ep_size);
1.1047 + if (gUsingHighSpeed)
1.1048 + {
1.1049 + // HS Bulk ep can only have one possible packet size.
1.1050 + test(ep_size == 512);
1.1051 + }
1.1052 + else
1.1053 + {
1.1054 + // FS Bulk ep cannot be larger than 64 bytes.
1.1055 + test(ep_size <= 64);
1.1056 + }
1.1057 +
1.1058 + test.End();
1.1059 + }
1.1060 +
1.1061 +
1.1062 +static void TestExtendedEndpointDescriptor()
1.1063 + {
1.1064 + test.Start(_L("Extended Endpoint Descriptor Manipulation"));
1.1065 +
1.1066 + if (!SupportsAlternateInterfaces())
1.1067 + {
1.1068 + test.Printf(_L("*** Not supported - skipping Extended Endpoint descriptor tests\n"));
1.1069 + test.End();
1.1070 + return;
1.1071 + }
1.1072 +
1.1073 + // Extended Endpoint Descriptor manipulation (Audio class endpoint)
1.1074 +
1.1075 + test.Next(_L("GetEndpointDescriptorSize()"));
1.1076 + TInt epNumber = INT_IN_ep;
1.1077 + TInt desc_size = 0;
1.1078 + TInt r = gPort.GetEndpointDescriptorSize(1, epNumber, desc_size);
1.1079 + test(r == KErrNone);
1.1080 + test(static_cast<TUint>(desc_size) == KUsbDescSize_AudioEndpoint);
1.1081 +
1.1082 + test.Next(_L("GetEndpointDescriptor()"));
1.1083 + TBuf8<KUsbDescSize_AudioEndpoint> descriptor;
1.1084 + r = gPort.GetEndpointDescriptor(1, epNumber, descriptor);
1.1085 + test(r == KErrNone);
1.1086 +
1.1087 + test.Next(_L("SetEndpointDescriptor()"));
1.1088 + // Change the Audio Endpoint bSynchAddress field
1.1089 + TUint8 addr = 0x85; // bogus address
1.1090 + if (descriptor[KEpDesc_SynchAddressOffset] == addr)
1.1091 + addr++;
1.1092 + descriptor[KEpDesc_SynchAddressOffset] = addr;
1.1093 + r = gPort.SetEndpointDescriptor(1, epNumber, descriptor);
1.1094 + test(r == KErrNone);
1.1095 +
1.1096 + test.Next(_L("GetEndpointDescriptor()"));
1.1097 + TBuf8<KUsbDescSize_AudioEndpoint> descriptor2;
1.1098 + r = gPort.GetEndpointDescriptor(1, epNumber, descriptor2);
1.1099 + test(r == KErrNone);
1.1100 +
1.1101 + test.Next(_L("Compare endpoint descriptor with value set"));
1.1102 + r = descriptor2.Compare(descriptor);
1.1103 + test(r == KErrNone);
1.1104 +
1.1105 + test.Next(_L("Check endpoint max packet size"));
1.1106 + const TUint16 ep_size = EpSize(descriptor[KEpDesc_PacketSizeOffset],
1.1107 + descriptor[KEpDesc_PacketSizeOffset+1]);
1.1108 + if (gUsingHighSpeed)
1.1109 + {
1.1110 + // HS Interrupt ep.
1.1111 + test(ep_size <= 1024);
1.1112 + }
1.1113 + else
1.1114 + {
1.1115 + // FS Interrupt ep cannot be larger than 64 bytes.
1.1116 + test(ep_size <= 64);
1.1117 + }
1.1118 +
1.1119 + test.End();
1.1120 + }
1.1121 +
1.1122 +
1.1123 +static void TestStandardStringDescriptors()
1.1124 + {
1.1125 + test.Start(_L("String Descriptor Manipulation"));
1.1126 +
1.1127 + //
1.1128 + // --- LANGID code
1.1129 + //
1.1130 +
1.1131 + test.Next(_L("GetStringDescriptorLangId()"));
1.1132 + TUint16 rd_langid_orig;
1.1133 + TInt r = gPort.GetStringDescriptorLangId(rd_langid_orig);
1.1134 + test(r == KErrNone);
1.1135 + test.Printf(_L("Original LANGID code: 0x%04X\n"), rd_langid_orig);
1.1136 +
1.1137 + test.Next(_L("SetStringDescriptorLangId()"));
1.1138 + TUint16 wr_langid = 0x0809; // English (UK) Language ID
1.1139 + if (wr_langid == rd_langid_orig)
1.1140 + wr_langid = 0x0444; // Tatar Language ID
1.1141 + r = gPort.SetStringDescriptorLangId(wr_langid);
1.1142 + test(r == KErrNone);
1.1143 +
1.1144 + test.Next(_L("GetStringDescriptorLangId()"));
1.1145 + TUint16 rd_langid;
1.1146 + r = gPort.GetStringDescriptorLangId(rd_langid);
1.1147 + test(r == KErrNone);
1.1148 + test.Printf(_L("New LANGID code: 0x%04X\n"), rd_langid);
1.1149 +
1.1150 + test.Next(_L("Compare LANGID codes"));
1.1151 + test(rd_langid == wr_langid);
1.1152 +
1.1153 + test.Next(_L("Restore original LANGID code"));
1.1154 + r = gPort.SetStringDescriptorLangId(rd_langid_orig);
1.1155 + test(r == KErrNone);
1.1156 + r = gPort.GetStringDescriptorLangId(rd_langid);
1.1157 + test(r == KErrNone);
1.1158 + test(rd_langid == rd_langid_orig);
1.1159 +
1.1160 + //
1.1161 + // --- Manufacturer string
1.1162 + //
1.1163 +
1.1164 + test.Next(_L("GetManufacturerStringDescriptor()"));
1.1165 + TBuf16<KUsbStringDescStringMaxSize / 2> rd_str_orig;
1.1166 + r = gPort.GetManufacturerStringDescriptor(rd_str_orig);
1.1167 + test(r == KErrNone || r == KErrNotFound);
1.1168 + TBool restore_string;
1.1169 + if (r == KErrNone)
1.1170 + {
1.1171 + test.Printf(_L("Original Manufacturer string: \"%lS\"\n"), &rd_str_orig);
1.1172 + restore_string = ETrue;
1.1173 + }
1.1174 + else
1.1175 + {
1.1176 + test.Printf(_L("No Manufacturer string set\n"));
1.1177 + restore_string = EFalse;
1.1178 + }
1.1179 +
1.1180 + test.Next(_L("SetManufacturerStringDescriptor()"));
1.1181 + _LIT16(manufacturer, "Manufacturer Which Manufactures Devices");
1.1182 + TBuf16<KUsbStringDescStringMaxSize / 2> wr_str(manufacturer);
1.1183 + r = gPort.SetManufacturerStringDescriptor(wr_str);
1.1184 + test(r == KErrNone);
1.1185 +
1.1186 + test.Next(_L("GetManufacturerStringDescriptor()"));
1.1187 + TBuf16<KUsbStringDescStringMaxSize / 2> rd_str;
1.1188 + r = gPort.GetManufacturerStringDescriptor(rd_str);
1.1189 + test(r == KErrNone);
1.1190 + test.Printf(_L("New Manufacturer string: \"%lS\"\n"), &rd_str);
1.1191 +
1.1192 + test.Next(_L("Compare Manufacturer strings"));
1.1193 + r = rd_str.Compare(wr_str);
1.1194 + test(r == KErrNone);
1.1195 +
1.1196 + test.Next(_L("SetManufacturerStringDescriptor()"));
1.1197 + _LIT16(manufacturer2, "Different Manufacturer Which Manufactures Different Devices");
1.1198 + wr_str.FillZ(wr_str.MaxLength());
1.1199 + wr_str = manufacturer2;
1.1200 + r = gPort.SetManufacturerStringDescriptor(wr_str);
1.1201 + test(r == KErrNone);
1.1202 +
1.1203 + test.Next(_L("GetManufacturerStringDescriptor()"));
1.1204 + rd_str.FillZ(rd_str.MaxLength());
1.1205 + r = gPort.GetManufacturerStringDescriptor(rd_str);
1.1206 + test(r == KErrNone);
1.1207 + test.Printf(_L("New Manufacturer string: \"%lS\"\n"), &rd_str);
1.1208 +
1.1209 + test.Next(_L("Compare Manufacturer strings"));
1.1210 + r = rd_str.Compare(wr_str);
1.1211 + test(r == KErrNone);
1.1212 +
1.1213 + test.Next(_L("RemoveManufacturerStringDescriptor()"));
1.1214 + r = gPort.RemoveManufacturerStringDescriptor();
1.1215 + test(r == KErrNone);
1.1216 + r = gPort.GetManufacturerStringDescriptor(rd_str);
1.1217 + test(r == KErrNotFound);
1.1218 +
1.1219 + if (restore_string)
1.1220 + {
1.1221 + test.Next(_L("Restore original string"));
1.1222 + r = gPort.SetManufacturerStringDescriptor(rd_str_orig);
1.1223 + test(r == KErrNone);
1.1224 + r = gPort.GetManufacturerStringDescriptor(rd_str);
1.1225 + test(r == KErrNone);
1.1226 + r = rd_str.Compare(rd_str_orig);
1.1227 + test(r == KErrNone);
1.1228 + }
1.1229 +
1.1230 + //
1.1231 + // --- Product string
1.1232 + //
1.1233 +
1.1234 + test.Next(_L("GetProductStringDescriptor()"));
1.1235 + rd_str_orig.FillZ(rd_str.MaxLength());
1.1236 + r = gPort.GetProductStringDescriptor(rd_str_orig);
1.1237 + test(r == KErrNone || r == KErrNotFound);
1.1238 + if (r == KErrNone)
1.1239 + {
1.1240 + test.Printf(_L("Old Product string: \"%lS\"\n"), &rd_str_orig);
1.1241 + restore_string = ETrue;
1.1242 + }
1.1243 + else
1.1244 + restore_string = EFalse;
1.1245 +
1.1246 + test.Next(_L("SetProductStringDescriptor()"));
1.1247 + _LIT16(product, "Product That Was Produced By A Manufacturer");
1.1248 + wr_str.FillZ(wr_str.MaxLength());
1.1249 + wr_str = product;
1.1250 + r = gPort.SetProductStringDescriptor(wr_str);
1.1251 + test(r == KErrNone);
1.1252 +
1.1253 + test.Next(_L("GetProductStringDescriptor()"));
1.1254 + rd_str.FillZ(rd_str.MaxLength());
1.1255 + r = gPort.GetProductStringDescriptor(rd_str);
1.1256 + test(r == KErrNone);
1.1257 + test.Printf(_L("New Product string: \"%lS\"\n"), &rd_str);
1.1258 +
1.1259 + test.Next(_L("Compare Product strings"));
1.1260 + r = rd_str.Compare(wr_str);
1.1261 + test(r == KErrNone);
1.1262 +
1.1263 + test.Next(_L("SetProductStringDescriptor()"));
1.1264 + _LIT16(product2, "Different Product That Was Produced By A Different Manufacturer");
1.1265 + wr_str.FillZ(wr_str.MaxLength());
1.1266 + wr_str = product2;
1.1267 + r = gPort.SetProductStringDescriptor(wr_str);
1.1268 + test(r == KErrNone);
1.1269 +
1.1270 + test.Next(_L("GetProductStringDescriptor()"));
1.1271 + rd_str.FillZ(rd_str.MaxLength());
1.1272 + r = gPort.GetProductStringDescriptor(rd_str);
1.1273 + test(r == KErrNone);
1.1274 + test.Printf(_L("New Product string: \"%lS\"\n"), &rd_str);
1.1275 +
1.1276 + test.Next(_L("Compare Product strings"));
1.1277 + r = rd_str.Compare(wr_str);
1.1278 + test(r == KErrNone);
1.1279 +
1.1280 + test.Next(_L("RemoveProductStringDescriptor()"));
1.1281 + r = gPort.RemoveProductStringDescriptor();
1.1282 + test(r == KErrNone);
1.1283 + r = gPort.GetProductStringDescriptor(rd_str);
1.1284 + test(r == KErrNotFound);
1.1285 +
1.1286 + if (restore_string)
1.1287 + {
1.1288 + test.Next(_L("Restore original string"));
1.1289 + r = gPort.SetProductStringDescriptor(rd_str_orig);
1.1290 + test(r == KErrNone);
1.1291 + r = gPort.GetProductStringDescriptor(rd_str);
1.1292 + test(r == KErrNone);
1.1293 + r = rd_str.Compare(rd_str_orig);
1.1294 + test(r == KErrNone);
1.1295 + }
1.1296 +
1.1297 + //
1.1298 + // --- Serial Number string
1.1299 + //
1.1300 +
1.1301 + test.Next(_L("GetSerialNumberStringDescriptor()"));
1.1302 + rd_str_orig.FillZ(rd_str.MaxLength());
1.1303 + r = gPort.GetSerialNumberStringDescriptor(rd_str_orig);
1.1304 + test(r == KErrNone || r == KErrNotFound);
1.1305 + if (r == KErrNone)
1.1306 + {
1.1307 + test.Printf(_L("Old Serial Number: \"%lS\"\n"), &rd_str_orig);
1.1308 + restore_string = ETrue;
1.1309 + }
1.1310 + else
1.1311 + restore_string = EFalse;
1.1312 +
1.1313 + test.Next(_L("SetSerialNumberStringDescriptor()"));
1.1314 + _LIT16(serial, "000666000XYZ");
1.1315 + wr_str.FillZ(wr_str.MaxLength());
1.1316 + wr_str = serial;
1.1317 + r = gPort.SetSerialNumberStringDescriptor(wr_str);
1.1318 + test(r == KErrNone);
1.1319 +
1.1320 + test.Next(_L("GetSerialNumberStringDescriptor()"));
1.1321 + rd_str.FillZ(rd_str.MaxLength());
1.1322 + r = gPort.GetSerialNumberStringDescriptor(rd_str);
1.1323 + test(r == KErrNone);
1.1324 + test.Printf(_L("New Serial Number: \"%lS\"\n"), &rd_str);
1.1325 +
1.1326 + test.Next(_L("Compare Serial Number strings"));
1.1327 + r = rd_str.Compare(wr_str);
1.1328 + test(r == KErrNone);
1.1329 +
1.1330 + test.Next(_L("SetSerialNumberStringDescriptor()"));
1.1331 + _LIT16(serial2, "Y11611193111711111Y");
1.1332 + wr_str.FillZ(wr_str.MaxLength());
1.1333 + wr_str = serial2;
1.1334 + r = gPort.SetSerialNumberStringDescriptor(wr_str);
1.1335 + test(r == KErrNone);
1.1336 +
1.1337 + test.Next(_L("GetSerialNumberStringDescriptor()"));
1.1338 + rd_str.FillZ(rd_str.MaxLength());
1.1339 + r = gPort.GetSerialNumberStringDescriptor(rd_str);
1.1340 + test(r == KErrNone);
1.1341 + test.Printf(_L("New Serial Number: \"%lS\"\n"), &rd_str);
1.1342 +
1.1343 + test.Next(_L("Compare Serial Number strings"));
1.1344 + r = rd_str.Compare(wr_str);
1.1345 + test(r == KErrNone);
1.1346 +
1.1347 + test.Next(_L("RemoveSerialNumberStringDescriptor()"));
1.1348 + r = gPort.RemoveSerialNumberStringDescriptor();
1.1349 + test(r == KErrNone);
1.1350 + r = gPort.GetSerialNumberStringDescriptor(rd_str);
1.1351 + test(r == KErrNotFound);
1.1352 +
1.1353 + if (restore_string)
1.1354 + {
1.1355 + test.Next(_L("Restore original string"));
1.1356 + r = gPort.SetSerialNumberStringDescriptor(rd_str_orig);
1.1357 + test(r == KErrNone);
1.1358 + r = gPort.GetSerialNumberStringDescriptor(rd_str);
1.1359 + test(r == KErrNone);
1.1360 + r = rd_str.Compare(rd_str_orig);
1.1361 + test(r == KErrNone);
1.1362 + }
1.1363 +
1.1364 + //
1.1365 + // --- Configuration string
1.1366 + //
1.1367 +
1.1368 + test.Next(_L("GetConfigurationStringDescriptor()"));
1.1369 + rd_str_orig.FillZ(rd_str.MaxLength());
1.1370 + r = gPort.GetConfigurationStringDescriptor(rd_str_orig);
1.1371 + test(r == KErrNone || r == KErrNotFound);
1.1372 + if (r == KErrNone)
1.1373 + {
1.1374 + test.Printf(_L("Old Configuration string: \"%lS\"\n"), &rd_str_orig);
1.1375 + restore_string = ETrue;
1.1376 + }
1.1377 + else
1.1378 + restore_string = EFalse;
1.1379 +
1.1380 + test.Next(_L("SetConfigurationStringDescriptor()"));
1.1381 + _LIT16(config, "Relatively Simple Configuration That Is Still Useful");
1.1382 + wr_str.FillZ(wr_str.MaxLength());
1.1383 + wr_str = config;
1.1384 + r = gPort.SetConfigurationStringDescriptor(wr_str);
1.1385 + test(r == KErrNone);
1.1386 +
1.1387 + test.Next(_L("GetConfigurationStringDescriptor()"));
1.1388 + rd_str.FillZ(rd_str.MaxLength());
1.1389 + r = gPort.GetConfigurationStringDescriptor(rd_str);
1.1390 + test(r == KErrNone);
1.1391 + test.Printf(_L("New Configuration string: \"%lS\"\n"), &rd_str);
1.1392 +
1.1393 + test.Next(_L("Compare Configuration strings"));
1.1394 + r = rd_str.Compare(wr_str);
1.1395 + test(r == KErrNone);
1.1396 +
1.1397 + test.Next(_L("SetConfigurationStringDescriptor()"));
1.1398 + _LIT16(config2, "Convenient Configuration That Can Be Very Confusing");
1.1399 + wr_str.FillZ(wr_str.MaxLength());
1.1400 + wr_str = config2;
1.1401 + r = gPort.SetConfigurationStringDescriptor(wr_str);
1.1402 + test(r == KErrNone);
1.1403 +
1.1404 + test.Next(_L("GetConfigurationStringDescriptor()"));
1.1405 + rd_str.FillZ(rd_str.MaxLength());
1.1406 + r = gPort.GetConfigurationStringDescriptor(rd_str);
1.1407 + test(r == KErrNone);
1.1408 + test.Printf(_L("New Configuration string: \"%lS\"\n"), &rd_str);
1.1409 +
1.1410 + test.Next(_L("Compare Configuration strings"));
1.1411 + r = rd_str.Compare(wr_str);
1.1412 + test(r == KErrNone);
1.1413 +
1.1414 + test.Next(_L("RemoveConfigurationStringDescriptor()"));
1.1415 + r = gPort.RemoveConfigurationStringDescriptor();
1.1416 + test(r == KErrNone);
1.1417 + r = gPort.GetConfigurationStringDescriptor(rd_str);
1.1418 + test(r == KErrNotFound);
1.1419 +
1.1420 + if (restore_string)
1.1421 + {
1.1422 + test.Next(_L("Restore original string"));
1.1423 + r = gPort.SetConfigurationStringDescriptor(rd_str_orig);
1.1424 + test(r == KErrNone);
1.1425 + r = gPort.GetConfigurationStringDescriptor(rd_str);
1.1426 + test(r == KErrNone);
1.1427 + r = rd_str.Compare(rd_str_orig);
1.1428 + test(r == KErrNone);
1.1429 + }
1.1430 +
1.1431 + test.End();
1.1432 + }
1.1433 +
1.1434 +
1.1435 +//---------------------------------------------
1.1436 +//! @SYMTestCaseID KBASE-T_USBAPI-0041
1.1437 +//! @SYMTestType UT
1.1438 +//! @SYMREQ REQ5662
1.1439 +//! @SYMTestCaseDesc USB Device Driver API extension to support setting of a string descriptor at a specific index
1.1440 +//! @SYMTestActions Tests GetStringDescriptor(), SetStringDescriptor() and RemoveStringDescriptor() to verify
1.1441 +//! the right values are retrieved, set and deleted at specific positions
1.1442 +//! @SYMTestExpectedResults KErrNone in positive testing and KErrNotFound in negative one
1.1443 +//! @SYMTestPriority High
1.1444 +//! @SYMTestStatus Implemented
1.1445 +//---------------------------------------------
1.1446 +static void TestArbitraryStringDescriptors()
1.1447 + {
1.1448 + test.Start(_L("Arbitrary String Descriptor Manipulation"));
1.1449 +
1.1450 + const TUint8 stridx1 = 0xEE;
1.1451 + const TUint8 stridx2 = 0xCC;
1.1452 + const TUint8 stridx3 = 0xDD;
1.1453 + const TUint8 stridx4 = 0xFF;
1.1454 +
1.1455 + // First test string
1.1456 +
1.1457 + test.Next(_L("GetStringDescriptor() 1"));
1.1458 + TBuf16<KUsbStringDescStringMaxSize / 2> rd_str;
1.1459 + TInt r = gPort.GetStringDescriptor(stridx1, rd_str);
1.1460 + test(r == KErrNotFound);
1.1461 +
1.1462 + test.Next(_L("SetStringDescriptor() 1"));
1.1463 + _LIT16(string_one, "Arbitrary String Descriptor Test String 1");
1.1464 + TBuf16<KUsbStringDescStringMaxSize / 2> wr_str(string_one);
1.1465 + r = gPort.SetStringDescriptor(stridx1, wr_str);
1.1466 + test(r == KErrNone);
1.1467 +
1.1468 + test.Next(_L("GetStringDescriptor() 1"));
1.1469 + r = gPort.GetStringDescriptor(stridx1, rd_str);
1.1470 + test(r == KErrNone);
1.1471 + test.Printf(_L("New test string @ idx %d: \"%lS\"\n"), stridx1, &rd_str);
1.1472 +
1.1473 + test.Next(_L("Compare test strings 1"));
1.1474 + r = rd_str.Compare(wr_str);
1.1475 + test(r == KErrNone);
1.1476 +
1.1477 + // Second test string
1.1478 +
1.1479 + test.Next(_L("GetStringDescriptor() 2"));
1.1480 + rd_str.FillZ(rd_str.MaxLength());
1.1481 + r = gPort.GetStringDescriptor(stridx2, rd_str);
1.1482 + test(r == KErrNotFound);
1.1483 +
1.1484 + test.Next(_L("SetStringDescriptor() 2"));
1.1485 + _LIT16(string_two, "Arbitrary String Descriptor Test String 2");
1.1486 + wr_str.FillZ(wr_str.MaxLength());
1.1487 + wr_str = string_two;
1.1488 + r = gPort.SetStringDescriptor(stridx2, wr_str);
1.1489 + test(r == KErrNone);
1.1490 +
1.1491 + // In between we create another interface setting to see what happens
1.1492 + // to the existing string descriptor indices.
1.1493 + // (We don't have to test this on every platform -
1.1494 + // besides, those that don't support alt settings
1.1495 + // are by now very rare.)
1.1496 + if (SupportsAlternateInterfaces())
1.1497 + {
1.1498 + TUsbcInterfaceInfoBuf ifc;
1.1499 + _LIT16(string, "T_USBAPI Bogus Test Interface (Setting 2)");
1.1500 + ifc().iString = const_cast<TDesC16*>(&string);
1.1501 + ifc().iTotalEndpointsUsed = 0;
1.1502 + TInt r = gPort.SetInterface(2, ifc);
1.1503 + test(r == KErrNone);
1.1504 + }
1.1505 +
1.1506 + test.Next(_L("GetStringDescriptor() 2"));
1.1507 + r = gPort.GetStringDescriptor(stridx2, rd_str);
1.1508 + test(r == KErrNone);
1.1509 + test.Printf(_L("New test string @ idx %d: \"%lS\"\n"), stridx2, &rd_str);
1.1510 +
1.1511 + test.Next(_L("Compare test strings 2"));
1.1512 + r = rd_str.Compare(wr_str);
1.1513 + test(r == KErrNone);
1.1514 +
1.1515 + // Third test string
1.1516 +
1.1517 + test.Next(_L("GetStringDescriptor() 3"));
1.1518 + rd_str.FillZ(rd_str.MaxLength());
1.1519 + r = gPort.GetStringDescriptor(stridx3, rd_str);
1.1520 + test(r == KErrNotFound);
1.1521 +
1.1522 + test.Next(_L("SetStringDescriptor() 3"));
1.1523 + _LIT16(string_three, "Arbitrary String Descriptor Test String 3");
1.1524 + wr_str.FillZ(wr_str.MaxLength());
1.1525 + wr_str = string_three;
1.1526 + r = gPort.SetStringDescriptor(stridx3, wr_str);
1.1527 + test(r == KErrNone);
1.1528 +
1.1529 + test.Next(_L("GetStringDescriptor() 3"));
1.1530 + r = gPort.GetStringDescriptor(stridx3, rd_str);
1.1531 + test(r == KErrNone);
1.1532 + test.Printf(_L("New test string @ idx %d: \"%lS\"\n"), stridx3, &rd_str);
1.1533 +
1.1534 + test.Next(_L("Compare test strings 3"));
1.1535 + r = rd_str.Compare(wr_str);
1.1536 + test(r == KErrNone);
1.1537 +
1.1538 + // Remove string descriptors
1.1539 +
1.1540 + test.Next(_L("RemoveStringDescriptor() 4"));
1.1541 + r = gPort.RemoveStringDescriptor(stridx4);
1.1542 + test(r == KErrNotFound);
1.1543 +
1.1544 + test.Next(_L("RemoveStringDescriptor() 3"));
1.1545 + r = gPort.RemoveStringDescriptor(stridx3);
1.1546 + test(r == KErrNone);
1.1547 + r = gPort.GetStringDescriptor(stridx3, rd_str);
1.1548 + test(r == KErrNotFound);
1.1549 +
1.1550 + test.Next(_L("RemoveStringDescriptor() 2"));
1.1551 + r = gPort.RemoveStringDescriptor(stridx2);
1.1552 + test(r == KErrNone);
1.1553 + r = gPort.GetStringDescriptor(stridx2, rd_str);
1.1554 + test(r == KErrNotFound);
1.1555 +
1.1556 + test.Next(_L("RemoveStringDescriptor() 1"));
1.1557 + r = gPort.RemoveStringDescriptor(stridx1);
1.1558 + test(r == KErrNone);
1.1559 + r = gPort.GetStringDescriptor(stridx1, rd_str);
1.1560 + test(r == KErrNotFound);
1.1561 +
1.1562 + test.End();
1.1563 + }
1.1564 +
1.1565 +
1.1566 +static void TestDescriptorManipulation()
1.1567 + {
1.1568 + test.Start(_L("Test USB Descriptor Manipulation"));
1.1569 +
1.1570 + TestDeviceDescriptor();
1.1571 +
1.1572 + TestDeviceQualifierDescriptor();
1.1573 +
1.1574 + TestConfigurationDescriptor();
1.1575 +
1.1576 + TestOtherSpeedConfigurationDescriptor();
1.1577 +
1.1578 + TestInterfaceDescriptor();
1.1579 +
1.1580 + TestClassSpecificDescriptors();
1.1581 +
1.1582 + TestAlternateInterfaceManipulation();
1.1583 +
1.1584 + TestEndpointDescriptor();
1.1585 +
1.1586 + TestExtendedEndpointDescriptor();
1.1587 +
1.1588 + TestStandardStringDescriptors();
1.1589 +
1.1590 + TestArbitraryStringDescriptors();
1.1591 +
1.1592 + test.End();
1.1593 + }
1.1594 +
1.1595 +
1.1596 +//---------------------------------------------
1.1597 +//! @SYMTestCaseID KBASE-T_USBAPI-0040
1.1598 +//! @SYMTestType UT
1.1599 +//! @SYMTestCaseDesc Test OTG extensions
1.1600 +//! @SYMTestExpectedResults All APIs behave as expected
1.1601 +//! @SYMTestPriority Medium
1.1602 +//! @SYMTestStatus Implemented
1.1603 +//---------------------------------------------
1.1604 +static void TestOtgExtensions()
1.1605 + {
1.1606 + test.Start(_L("Test Some OTG API Extensions"));
1.1607 +
1.1608 + // Test OTG descriptor manipulation
1.1609 + test.Next(_L("Get OTG Descriptor Size"));
1.1610 + TInt size;
1.1611 + gPort.GetOtgDescriptorSize(size);
1.1612 + test(static_cast<TUint>(size) == KUsbDescSize_Otg);
1.1613 +
1.1614 + test.Next(_L("Get OTG Descriptor"));
1.1615 + TBuf8<KUsbDescSize_Otg> otgDesc;
1.1616 + TInt r = gPort.GetOtgDescriptor(otgDesc);
1.1617 + test(r == KErrNotSupported || r == KErrNone);
1.1618 +
1.1619 + test.Next(_L("Set OTG Descriptor"));
1.1620 + if (r == KErrNotSupported)
1.1621 + {
1.1622 + r = gPort.SetOtgDescriptor(otgDesc);
1.1623 + test(r == KErrNotSupported);
1.1624 + }
1.1625 + else
1.1626 + {
1.1627 + otgDesc[0] = KUsbDescSize_Otg;
1.1628 + otgDesc[1] = KUsbDescType_Otg;
1.1629 + // The next step is likely to reset KUsbOtgAttr_HnpSupp
1.1630 + otgDesc[2] = KUsbOtgAttr_SrpSupp;
1.1631 + r = gPort.SetOtgDescriptor(otgDesc);
1.1632 + test(r == KErrNone);
1.1633 + TBuf8<KUsbDescSize_Otg> desc;
1.1634 + r = gPort.GetOtgDescriptor(desc);
1.1635 + test(r == KErrNone);
1.1636 + test(desc.Compare(otgDesc) == 0);
1.1637 + }
1.1638 +
1.1639 + // Test get OTG features
1.1640 + test.Next(_L("Get OTG Features"));
1.1641 + TUint8 features;
1.1642 + r = gPort.GetOtgFeatures(features);
1.1643 + if (gSupportsOtg)
1.1644 + {
1.1645 + test(r == KErrNone);
1.1646 + TBool b_HnpEnable = (features & KUsbOtgAttr_B_HnpEnable) ? ETrue : EFalse;
1.1647 + TBool a_HnpSupport = (features & KUsbOtgAttr_A_HnpSupport) ? ETrue : EFalse;
1.1648 + TBool a_AltHnpSupport = (features & KUsbOtgAttr_A_AltHnpSupport) ? ETrue : EFalse;
1.1649 + test.Printf(_L("### OTG Features:\nB_HnpEnable(%d)\nA_HnpSupport(%d)\nA_Alt_HnpSupport(%d)\n"),
1.1650 + b_HnpEnable, a_HnpSupport, a_AltHnpSupport);
1.1651 + }
1.1652 + else
1.1653 + {
1.1654 + test(r == KErrNotSupported);
1.1655 + test.Printf(_L("GetOtgFeatures() not supported\n"));
1.1656 + }
1.1657 +
1.1658 + test.End();
1.1659 +}
1.1660 +
1.1661 +
1.1662 +static void TestEndpoint0MaxPacketSizes()
1.1663 + {
1.1664 + test.Start(_L("Test Endpoint0 MaxPacketSizes"));
1.1665 +
1.1666 + TUint32 sizes = gPort.EndpointZeroMaxPacketSizes();
1.1667 + TInt r = KErrNone;
1.1668 + TBool good;
1.1669 + TInt mpsize = 0;
1.1670 + for (TInt i = 0; i < 32; i++)
1.1671 + {
1.1672 + TUint bit = sizes & (1 << i);
1.1673 + if (bit != 0)
1.1674 + {
1.1675 + switch (bit)
1.1676 + {
1.1677 + case KUsbEpSizeCont:
1.1678 + good = EFalse;
1.1679 + break;
1.1680 + case KUsbEpSize8:
1.1681 + mpsize = 8;
1.1682 + good = ETrue;
1.1683 + break;
1.1684 + case KUsbEpSize16:
1.1685 + mpsize = 16;
1.1686 + good = ETrue;
1.1687 + break;
1.1688 + case KUsbEpSize32:
1.1689 + mpsize = 32;
1.1690 + good = ETrue;
1.1691 + break;
1.1692 + case KUsbEpSize64:
1.1693 + mpsize = 64;
1.1694 + good = ETrue;
1.1695 + break;
1.1696 + case KUsbEpSize128:
1.1697 + case KUsbEpSize256:
1.1698 + case KUsbEpSize512:
1.1699 + case KUsbEpSize1023:
1.1700 + default:
1.1701 + good = EFalse;
1.1702 + break;
1.1703 + }
1.1704 + if (good)
1.1705 + {
1.1706 + test.Printf(_L("Ep0 supports %d bytes MaxPacketSize\n"), mpsize);
1.1707 + }
1.1708 + else
1.1709 + {
1.1710 + test.Printf(_L("Bad Ep0 size: 0x%08x, failure will occur\n"), bit);
1.1711 + r = KErrGeneral;
1.1712 + }
1.1713 + }
1.1714 + }
1.1715 + test(r == KErrNone);
1.1716 +
1.1717 + test.End();
1.1718 + }
1.1719 +
1.1720 +
1.1721 +static void TestDeviceControl()
1.1722 + {
1.1723 + test.Start(_L("Test Device Control"));
1.1724 +
1.1725 + // This is a quick and crude test, to make sure that we don't get a steaming heap
1.1726 + // as a result of calling the device control API's.
1.1727 + test.Next(_L("SetDeviceControl()"));
1.1728 + TInt r = gPort.SetDeviceControl();
1.1729 + test(r == KErrNone);
1.1730 + test.Next(_L("ReleaseDeviceControl()"));
1.1731 + r = gPort.ReleaseDeviceControl();
1.1732 + test(r == KErrNone);
1.1733 +
1.1734 + test.End();
1.1735 + }
1.1736 +
1.1737 +
1.1738 +static void TestAlternateDeviceStatusNotify()
1.1739 + {
1.1740 + test.Start(_L("Test Alternate Device Status Notification"));
1.1741 +
1.1742 + TRequestStatus dev_status;
1.1743 + TUint deviceState = 0xffffffff; // put in a nonsense value
1.1744 + test.Next(_L("AlternateDeviceStatusNotify()"));
1.1745 + gPort.AlternateDeviceStatusNotify(dev_status, deviceState);
1.1746 + test.Next(_L("AlternateDeviceStatusNotifyCancel()"));
1.1747 + gPort.AlternateDeviceStatusNotifyCancel();
1.1748 + User::WaitForRequest(dev_status);
1.1749 + test(dev_status == KErrCancel || dev_status == KErrNone);
1.1750 + if (deviceState & KUsbAlternateSetting)
1.1751 + {
1.1752 + TUint setting = (deviceState & ~KUsbAlternateSetting);
1.1753 + test.Printf(_L("Alternate setting change to setting %d - unexpected"), setting);
1.1754 + test(EFalse);
1.1755 + }
1.1756 + else
1.1757 + {
1.1758 + switch (deviceState)
1.1759 + {
1.1760 + case EUsbcDeviceStateUndefined:
1.1761 + test.Printf(_L("TestAlternateDeviceStatusNotify: Undefined state\n"));
1.1762 + break;
1.1763 + case EUsbcDeviceStateAttached:
1.1764 + test.Printf(_L("TestAlternateDeviceStatusNotify: Attached state\n"));
1.1765 + break;
1.1766 + case EUsbcDeviceStatePowered:
1.1767 + test.Printf(_L("TestAlternateDeviceStatusNotify: Powered state\n"));
1.1768 + break;
1.1769 + case EUsbcDeviceStateDefault:
1.1770 + test.Printf(_L("TestAlternateDeviceStatusNotify: Default state\n"));
1.1771 + break;
1.1772 + case EUsbcDeviceStateAddress:
1.1773 + test.Printf(_L("TestAlternateDeviceStatusNotify: Address state\n"));
1.1774 + break;
1.1775 + case EUsbcDeviceStateConfigured:
1.1776 + test.Printf(_L("TestAlternateDeviceStatusNotify: Configured state\n"));
1.1777 + break;
1.1778 + case EUsbcDeviceStateSuspended:
1.1779 + test.Printf(_L("TestAlternateDeviceStatusNotify: Suspended state\n"));
1.1780 + break;
1.1781 + case EUsbcNoState:
1.1782 + test.Printf(_L("TestAlternateDeviceStatusNotify: State buffering error\n"));
1.1783 + test(EFalse);
1.1784 + break;
1.1785 + default:
1.1786 + test.Printf(_L("TestAlternateDeviceStatusNotify: Unknown state\n"));
1.1787 + test(EFalse);
1.1788 + }
1.1789 + }
1.1790 +
1.1791 + test.End();
1.1792 + }
1.1793 +
1.1794 +
1.1795 +static void TestEndpointStatusNotify()
1.1796 + {
1.1797 + test.Start(_L("Test Endpoint Status Notification"));
1.1798 +
1.1799 + TRequestStatus ep_status;
1.1800 + TUint epStateBitmap = 0xffffffff; // put in a nonsense value
1.1801 + test.Next(_L("EndpointStatusNotify()"));
1.1802 + gPort.EndpointStatusNotify(ep_status, epStateBitmap);
1.1803 + test.Next(_L("EndpointStatusNotifyCancel()"));
1.1804 + gPort.EndpointStatusNotifyCancel();
1.1805 + User::WaitForRequest(ep_status);
1.1806 + test(ep_status.Int() == KErrCancel);
1.1807 + test.Next(_L("Check endpoint state bitmap returned"));
1.1808 + // Our ifc only uses 2 eps + ep0 is automatically granted:
1.1809 + const TUint usedEpBitmap = (1 << EEndpoint0 | 1 << EEndpoint1 | 1 << EEndpoint2);
1.1810 + // Must not return info about non existent Eps:
1.1811 + test((epStateBitmap & ~usedEpBitmap) == 0);
1.1812 + for (TInt i = 0; i <= 2; i++)
1.1813 + {
1.1814 + if ((epStateBitmap & (1 << i)) == EEndpointStateNotStalled)
1.1815 + {
1.1816 + test.Printf(_L("EndpointStatusNotify: Ep %d NOT STALLED\n"), i);
1.1817 + }
1.1818 + else
1.1819 + {
1.1820 + test.Printf(_L("EndpointStatusNotify: Ep %d STALLED\n"), i);
1.1821 + }
1.1822 + }
1.1823 +
1.1824 + test.End();
1.1825 + }
1.1826 +
1.1827 +
1.1828 +static void TestEndpointStallStatus()
1.1829 + {
1.1830 + test.Start(_L("Test Endpoint Stall Status"));
1.1831 +
1.1832 + if (!SupportsEndpointStall())
1.1833 + {
1.1834 + test.Printf(_L("*** Not supported - skipping endpoint stall status tests\n"));
1.1835 + test.End();
1.1836 + return;
1.1837 + }
1.1838 +
1.1839 + test.Next(_L("Endpoint stall status"));
1.1840 + TEndpointState epState = EEndpointStateUnknown;
1.1841 + QueryEndpointState(EEndpoint1);
1.1842 + QueryEndpointState(EEndpoint2);
1.1843 +
1.1844 + test.Next(_L("Stall Ep1"));
1.1845 + gPort.HaltEndpoint(EEndpoint1);
1.1846 + epState = QueryEndpointState(EEndpoint1);
1.1847 + test(epState == EEndpointStateStalled);
1.1848 +
1.1849 + test.Next(_L("Clear Stall Ep1"));
1.1850 + gPort.ClearHaltEndpoint(EEndpoint1);
1.1851 + epState = QueryEndpointState(EEndpoint1);
1.1852 + test(epState == EEndpointStateNotStalled);
1.1853 +
1.1854 + test.Next(_L("Stall Ep2"));
1.1855 + gPort.HaltEndpoint(EEndpoint2);
1.1856 + epState = QueryEndpointState(EEndpoint2);
1.1857 + test(epState == EEndpointStateStalled);
1.1858 +
1.1859 + test.Next(_L("Clear Stall Ep2"));
1.1860 + gPort.ClearHaltEndpoint(EEndpoint2);
1.1861 + epState = QueryEndpointState(EEndpoint2);
1.1862 + test(epState == EEndpointStateNotStalled);
1.1863 +
1.1864 + test.End();
1.1865 + }
1.1866 +
1.1867 +
1.1868 +static void CloseChannel()
1.1869 + {
1.1870 + test.Start(_L("Close Channel"));
1.1871 +
1.1872 + test.Next(_L("Disconnect Device from Host"));
1.1873 + TInt r = gPort.DeviceDisconnectFromHost();
1.1874 + test(r != KErrGeneral);
1.1875 +
1.1876 + if (gSupportsOtg)
1.1877 + {
1.1878 + test.Next(_L("Stop OTG stack"));
1.1879 + gOTG.StopStacks();
1.1880 + test.Next(_L("Close OTG Channel"));
1.1881 + gOTG.Close();
1.1882 + test.Next(_L("Free OTG LDD"));
1.1883 + r = User::FreeLogicalDevice(RUsbOtgDriver::Name());
1.1884 + test(r == KErrNone);
1.1885 + }
1.1886 +
1.1887 + test.Next(_L("Close USB Channel"));
1.1888 + gPort.Close();
1.1889 + test.Next(_L("Free USB LDD"));
1.1890 + r = User::FreeLogicalDevice(KUsbDeviceName);
1.1891 + test(r == KErrNone);
1.1892 +
1.1893 + test.End();
1.1894 + }
1.1895 +
1.1896 +
1.1897 +static const TInt KPrologue = 0;
1.1898 +static const TInt KMain = 1;
1.1899 +static const TInt KEpilogue = 2;
1.1900 +
1.1901 +static TInt RunTests(void* /*aArg*/)
1.1902 + {
1.1903 + static TInt step = KPrologue;
1.1904 + static TReal loops = 0;
1.1905 +
1.1906 + switch (step)
1.1907 + {
1.1908 + case KPrologue:
1.1909 + test.Title();
1.1910 + // outermost test begin
1.1911 + test.Start(_L("Test of USB APIs not requiring a host connection\n"));
1.1912 + if (SupportsUsb())
1.1913 + {
1.1914 + step = KMain;
1.1915 + }
1.1916 + else
1.1917 + {
1.1918 + step = KEpilogue;
1.1919 + test.Printf(_L("*** Test platform does not support USB - skipping all tests\n"));
1.1920 + }
1.1921 + return ETrue;
1.1922 + case KMain:
1.1923 + OpenChannel();
1.1924 + SetupInterface();
1.1925 + TestDescriptorManipulation();
1.1926 + TestOtgExtensions();
1.1927 + TestEndpoint0MaxPacketSizes();
1.1928 + TestDeviceControl();
1.1929 + TestAlternateDeviceStatusNotify();
1.1930 + TestEndpointStatusNotify();
1.1931 + TestEndpointStallStatus();
1.1932 + CloseChannel();
1.1933 + loops++;
1.1934 + if (gSoak && (gKeychar != EKeyEscape))
1.1935 + {
1.1936 + step = KMain;
1.1937 + }
1.1938 + else
1.1939 + {
1.1940 + step = KEpilogue;
1.1941 + }
1.1942 + return ETrue;
1.1943 + case KEpilogue:
1.1944 + test.Printf(_L("USBAPI tests were run %.0f time(s)\n"), loops);
1.1945 + // outermost test end
1.1946 + test.End();
1.1947 + CActiveScheduler::Stop();
1.1948 + return EFalse;
1.1949 + }
1.1950 + return EFalse;
1.1951 + }
1.1952 +
1.1953 +
1.1954 +static void RunAppL()
1.1955 + {
1.1956 + // Create the active scheduler
1.1957 + CActiveScheduler* scheduler = new (ELeave) CActiveScheduler();
1.1958 + // Push active scheduler onto the cleanup stack
1.1959 + CleanupStack::PushL(scheduler);
1.1960 + // Install as the active scheduler
1.1961 + CActiveScheduler::Install(scheduler);
1.1962 +
1.1963 + // Create console handler
1.1964 + CConsoleBase* console =
1.1965 + Console::NewL(_L("T_USBAPI - USB Client Test Program"), TSize(KConsFullScreen, KConsFullScreen));
1.1966 + CleanupStack::PushL(console);
1.1967 + // Make this one also RTest's console
1.1968 + test.SetConsole(console);
1.1969 +
1.1970 + // Create keypress notifier active object
1.1971 + CActiveKeypressNotifier* keypress_notifier = CActiveKeypressNotifier::NewL(console);
1.1972 + test(keypress_notifier != NULL);
1.1973 + CleanupStack::PushL(keypress_notifier);
1.1974 + keypress_notifier->RequestCharacter();
1.1975 +
1.1976 + // Create long-running test task active object
1.1977 + CIdle* active_test = CIdle::NewL(CActive::EPriorityIdle);
1.1978 + test(active_test != NULL);
1.1979 + CleanupStack::PushL(active_test);
1.1980 + active_test->Start(TCallBack(RunTests));
1.1981 +
1.1982 + // Start active scheduler
1.1983 + CActiveScheduler::Start();
1.1984 +
1.1985 + // Suspend thread for a short while
1.1986 + User::After(1000000);
1.1987 +
1.1988 + // active_test, keypress_notifier, console, scheduler
1.1989 + CleanupStack::PopAndDestroy(4);
1.1990 +
1.1991 + return;
1.1992 + }
1.1993 +
1.1994 +
1.1995 +GLDEF_C TInt E32Main()
1.1996 + {
1.1997 +
1.1998 + CTrapCleanup* cleanup = CTrapCleanup::New(); // get clean-up stack
1.1999 +
1.2000 + __UHEAP_MARK;
1.2001 +
1.2002 + _LIT(KArg, "soak");
1.2003 + TBuf<64> c;
1.2004 + User::CommandLine(c);
1.2005 + if (c.CompareF(KArg) == 0)
1.2006 + gSoak = ETrue;
1.2007 + else
1.2008 + gSoak = EFalse;
1.2009 + TRAPD(r, RunAppL());
1.2010 + __ASSERT_ALWAYS(!r, User::Panic(_L("E32EX"), r));
1.2011 +
1.2012 + __UHEAP_MARKEND;
1.2013 +
1.2014 + delete cleanup; // destroy clean-up stack
1.2015 + return KErrNone;
1.2016 + }