sl@0: // Copyright (c) 2003-2009 Nokia Corporation and/or its subsidiary(-ies). sl@0: // All rights reserved. sl@0: // This component and the accompanying materials are made available sl@0: // under the terms of the License "Eclipse Public License v1.0" sl@0: // which accompanies this distribution, and is available sl@0: // at the URL "http://www.eclipse.org/legal/epl-v10.html". sl@0: // sl@0: // Initial Contributors: sl@0: // Nokia Corporation - initial contribution. sl@0: // sl@0: // Contributors: sl@0: // sl@0: // Description: sl@0: // e32test/device/t_usbapi.cpp sl@0: // Overview: sl@0: // USB API Test Program (a standalone USB test program). sl@0: // API Information: sl@0: // Details: sl@0: // - Query whether the platform is operating HS (or it is connected to a HS host) or not, sl@0: // and executes the appropiate tests in each case (see RunTests() for the actual code, sl@0: // state machine enclosed for clarity): sl@0: // - Load and open an EUSBC device driver (logical device) sl@0: // - Setup the USB interface: query device capabilities, setup interface. sl@0: // - Test allocating DMA and double buffering resources with sl@0: // AllocateEndpointResource results in their use being correctly reported by sl@0: // QueryEndpointResourceUse sl@0: // - Test descriptor manipulation: validate the device, configuration, sl@0: // interface, alternate interface, endpoint and string descriptor sl@0: // manipulation. sl@0: // HS: device_qualifier and other_speed_configuation descriptors. sl@0: // - Check and validate the EndpointZeroMaxPacketSizes. sl@0: // - Quick test that calling the following APIs doesn't generate errors: device sl@0: // control, AlternateDeviceStatusNotify, EndpointStatusNotify sl@0: // - Test HaltEndpoint and ClearHaltEndpoint correctly result in endpoint sl@0: // status being reported as stalled/not stalled. sl@0: // - Test OTG extensions: OTG descriptor manipulations; set/get OTG feature sl@0: // - Close and free the logical device. sl@0: // Platforms/Drives/Compatibility: sl@0: // All. sl@0: // Assumptions/Requirement/Pre-requisites: sl@0: // Failures and causes: sl@0: // Base Port information: sl@0: // sl@0: // sl@0: sl@0: sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: sl@0: #include "t_usblib.h" sl@0: sl@0: sl@0: // --- Local Top Level Variables sl@0: sl@0: static RTest test(_L("T_USBAPI")); sl@0: static RDevUsbcClient gPort; sl@0: static RUsbOtgDriver gOTG; sl@0: static TBool gSupportsOtg; sl@0: static TBool gSupportsHighSpeed; sl@0: static TBool gUsingHighSpeed; sl@0: static TBool gSoak; sl@0: static TChar gKeychar = 'a'; sl@0: sl@0: // Store the actual endpoint number(s) of our alternate interface sl@0: static TInt INT_IN_ep = -1; sl@0: sl@0: _LIT(KUsbLddFilename, "eusbc"); sl@0: _LIT(KOtgdiLddFilename, "otgdi"); sl@0: _LIT(KUsbDeviceName, "Usbc"); sl@0: sl@0: sl@0: // --- Local Constants sl@0: sl@0: static const TInt KUsbDesc_SizeOffset = 0; sl@0: static const TInt KUsbDesc_TypeOffset = 1; sl@0: sl@0: static const TInt KDevDesc_SpecOffset = 2; sl@0: static const TInt KDevDesc_DevClassOffset = 4; sl@0: static const TInt KDevDesc_DevSubClassOffset = 5; sl@0: static const TInt KDevDesc_DevProtocolOffset = 6; sl@0: static const TInt KDevDesc_Ep0SizeOffset = 7; sl@0: static const TInt KDevDesc_VendorIdOffset = 8; sl@0: static const TInt KDevDesc_ProductIdOffset = 10; sl@0: static const TInt KDevDesc_DevReleaseOffset = 12; sl@0: sl@0: static const TInt KConfDesc_AttribOffset = 7; sl@0: static const TInt KConfDesc_MaxPowerOffset = 8; sl@0: sl@0: static const TInt KIfcDesc_SettingOffset = 2; sl@0: static const TInt KIfcDesc_ProtocolOffset = 7; sl@0: sl@0: static const TInt KEpDesc_PacketSizeOffset = 4; sl@0: static const TInt KEpDesc_IntervalOffset = 6; sl@0: static const TInt KEpDesc_SynchAddressOffset = 8; sl@0: sl@0: sl@0: // sl@0: // Helper. sl@0: // sl@0: static TEndpointState QueryEndpointState(TEndpointNumber aEndpoint) sl@0: { sl@0: TEndpointState ep_state = EEndpointStateUnknown; sl@0: TInt r = gPort.EndpointStatus(aEndpoint, ep_state); sl@0: test(r == KErrNone); sl@0: test.Printf(_L("Endpoint %d state: %s\n"), aEndpoint, sl@0: (ep_state == EEndpointStateNotStalled) ? _S("Not stalled") : sl@0: ((ep_state == EEndpointStateStalled) ? _S("Stalled") : sl@0: _S("Unknown..."))); sl@0: return ep_state; sl@0: } sl@0: sl@0: sl@0: // --- Class CActiveKeypressNotifier sl@0: sl@0: class CActiveKeypressNotifier : public CActive sl@0: { sl@0: public: sl@0: static CActiveKeypressNotifier* NewL(CConsoleBase* aConsole); sl@0: ~CActiveKeypressNotifier(); sl@0: void RequestCharacter(); sl@0: void ProcessKeyPressL(TChar aChar); sl@0: private: sl@0: virtual void DoCancel(); sl@0: virtual void RunL(); sl@0: CActiveKeypressNotifier(CConsoleBase* aConsole); sl@0: void ConstructL() {}; sl@0: private: sl@0: CConsoleBase* iConsole; sl@0: }; sl@0: sl@0: sl@0: CActiveKeypressNotifier* CActiveKeypressNotifier::NewL(CConsoleBase* aConsole) sl@0: { sl@0: CActiveKeypressNotifier* self = new (ELeave) CActiveKeypressNotifier(aConsole); sl@0: CleanupStack::PushL(self); sl@0: self->ConstructL(); sl@0: CActiveScheduler::Add(self); sl@0: CleanupStack::Pop(); sl@0: return self; sl@0: } sl@0: sl@0: sl@0: CActiveKeypressNotifier::CActiveKeypressNotifier(CConsoleBase* aConsole) sl@0: : CActive(EPriorityNormal), iConsole(aConsole) sl@0: {} sl@0: sl@0: sl@0: CActiveKeypressNotifier::~CActiveKeypressNotifier() sl@0: { sl@0: Cancel(); // base class cancel -> calls our DoCancel sl@0: } sl@0: sl@0: sl@0: void CActiveKeypressNotifier::RunL() sl@0: { sl@0: gKeychar = (static_cast(iConsole->KeyCode())); sl@0: RequestCharacter(); sl@0: } sl@0: sl@0: sl@0: void CActiveKeypressNotifier::DoCancel() sl@0: { sl@0: iConsole->ReadCancel(); sl@0: } sl@0: sl@0: sl@0: void CActiveKeypressNotifier::RequestCharacter() sl@0: { sl@0: // A request is issued to the CConsoleBase to accept a character from the keyboard. sl@0: if (IsActive()) sl@0: { sl@0: return; sl@0: } sl@0: iConsole->Read(iStatus); sl@0: SetActive(); sl@0: } sl@0: sl@0: sl@0: // --- Actual Test Functions sl@0: sl@0: // 2nd Thread helper function sl@0: static TInt TestThreadFunction(TAny* aPtr) sl@0: { sl@0: RThread* other = static_cast(aPtr); sl@0: RDevUsbcClient port = gPort; sl@0: // Now try to duplicate the USB channel handle sl@0: TInt r = port.Duplicate(*other); sl@0: // Wait for 1 second sl@0: User::After(1000000); sl@0: return r; sl@0: } sl@0: sl@0: sl@0: static void OpenChannel() sl@0: { sl@0: test.Start(_L("Open Channel")); sl@0: sl@0: test.Next(_L("Load USB LDD")); sl@0: TInt r = User::LoadLogicalDevice(KUsbLddFilename); sl@0: test(r == KErrNone || r == KErrAlreadyExists); sl@0: sl@0: RDevUsbcClient port1; sl@0: test.Next(_L("Open local USB channel 1")); sl@0: r = port1.Open(0); sl@0: test(r == KErrNone); sl@0: sl@0: test.Next(_L("Open global USB channel")); sl@0: r = gPort.Open(0); sl@0: test(r == KErrNone); sl@0: sl@0: RDevUsbcClient port2; sl@0: test.Next(_L("Open local USB channel 2")); sl@0: r = port2.Open(0); sl@0: test(r == KErrNone); sl@0: sl@0: test.Next(_L("Close USB channel 1")); sl@0: port1.Close(); sl@0: sl@0: RDevUsbcClient port3; sl@0: test.Next(_L("Open local USB channel 3")); sl@0: r = port3.Open(0); sl@0: test(r == KErrNone); sl@0: sl@0: test.Next(_L("Close USB channel 2")); sl@0: port2.Close(); sl@0: sl@0: test.Next(_L("Close USB channel 3")); sl@0: port3.Close(); sl@0: sl@0: // Check for OTG support sl@0: TBuf8 otg_desc; sl@0: r = gPort.GetOtgDescriptor(otg_desc); sl@0: test(r == KErrNotSupported || r == KErrNone); sl@0: gSupportsOtg = (r != KErrNotSupported) ? ETrue : EFalse; sl@0: sl@0: // On an OTG device we have to start the OTG driver, otherwise the Client sl@0: // stack will remain disabled forever. sl@0: if (gSupportsOtg) sl@0: { sl@0: test.Printf(_L("Running on OTG device: loading OTG driver\n")); sl@0: test.Next(_L("Load OTG LDD")); sl@0: r = User::LoadLogicalDevice(KOtgdiLddFilename); sl@0: test((r == KErrNone) || (r == KErrAlreadyExists)); sl@0: sl@0: test.Next(_L("Open OTG channel")); sl@0: r = gOTG.Open(); sl@0: test(r == KErrNone); sl@0: sl@0: test.Next(_L("Start OTG stack")); sl@0: r = gOTG.StartStacks(); sl@0: test(r == KErrNone); sl@0: } sl@0: sl@0: // Try duplicating channel handle in a second thread sl@0: // (which should not work because we don't support it) sl@0: sl@0: test.Next(_L("Create 2nd Thread")); sl@0: RThread me; sl@0: TThreadId me_id = me.Id(); sl@0: // We need to open the RThread object, otherwise we'll only get the sl@0: // 'special' handle 0xFFFF8001. sl@0: test(me.Open(me_id) == KErrNone); sl@0: RThread test_thread; sl@0: TBuf<17> name = _L("tusbapitestthread"); sl@0: test(test_thread.Create(name, TestThreadFunction, 0x1000, NULL, &me) == KErrNone); sl@0: test.Next(_L("Logon to 2nd Thread")); sl@0: TRequestStatus stat; sl@0: test_thread.Logon(stat); sl@0: test(stat == KRequestPending); sl@0: test_thread.Resume(); sl@0: test.Next(_L("Wait for 2nd Thread to exit")); sl@0: User::WaitForRequest(stat); sl@0: // Check correct return value of RDevUsbcClient::Duplicate() sl@0: test(stat == KErrAccessDenied); sl@0: test.Next(_L("Close 2nd Thread")); sl@0: test_thread.Close(); sl@0: sl@0: test.End(); sl@0: } sl@0: sl@0: sl@0: static void TestResourceAllocation() sl@0: { sl@0: test.Start(_L("Test Endpoint Resource Allocation")); sl@0: sl@0: test.Next(_L("Request DMA resource")); sl@0: const TInt dma = gPort.AllocateEndpointResource(EEndpoint1, EUsbcEndpointResourceDMA); sl@0: TBool res = gPort.QueryEndpointResourceUse(EEndpoint1, EUsbcEndpointResourceDMA); sl@0: test.Printf(_L("DMA on endpoint 1 %s\n"), sl@0: res ? _S("now allocated") : _S("not allocated")); sl@0: if (dma == KErrNone) sl@0: // Only if DMA resource was successfully allocated should we expect truth here: sl@0: test(res); sl@0: else sl@0: test(!res); sl@0: sl@0: test.Next(_L("Request Double Buffering resource")); sl@0: const TInt db = gPort.AllocateEndpointResource(EEndpoint1, EUsbcEndpointResourceDoubleBuffering); sl@0: res = gPort.QueryEndpointResourceUse(EEndpoint1, EUsbcEndpointResourceDoubleBuffering); sl@0: test.Printf(_L("Double Buffering on endpoint 1 %s\n"), sl@0: res ? _S("now allocated") : _S("not allocated")); sl@0: if (db == KErrNone) sl@0: // Only if DB resource was successfully allocated should we expect truth here: sl@0: test(res); sl@0: else sl@0: test(!res); sl@0: sl@0: test.Next(_L("Deallocate Double Buffering resource")); sl@0: TInt r = gPort.DeAllocateEndpointResource(EEndpoint1, EUsbcEndpointResourceDoubleBuffering); sl@0: // Whether DB is dynamic or permanent - deallocation (if supported) should always return success: sl@0: if (db == KErrNone) sl@0: test(r == KErrNone); sl@0: else sl@0: test(r != KErrNone); sl@0: res = gPort.QueryEndpointResourceUse(EEndpoint1, EUsbcEndpointResourceDoubleBuffering); sl@0: test.Printf(_L("Double Buffering on endpoint 1 %s\n"), sl@0: res ? _S("still allocated") : _S("not (longer) allocated")); sl@0: sl@0: test.Next(_L("Deallocate DMA resource")); sl@0: r = gPort.DeAllocateEndpointResource(EEndpoint1, EUsbcEndpointResourceDMA); sl@0: // Whether DMA is dynamic or permanent - deallocation (if supported) should always return success: sl@0: if (dma == KErrNone) sl@0: test(r == KErrNone); sl@0: else sl@0: test(r != KErrNone); sl@0: res = gPort.QueryEndpointResourceUse(EEndpoint1, EUsbcEndpointResourceDMA); sl@0: test.Printf(_L("DMA on endpoint 1 %s\n"), sl@0: res ? _S("still allocated") : _S("not (longer) allocated")); sl@0: sl@0: test.End(); sl@0: } sl@0: sl@0: sl@0: static void SetupInterface() sl@0: { sl@0: test.Start(_L("Query USB device caps and set up interface")); sl@0: sl@0: // Device caps sl@0: test.Next(_L("Query USB device caps")); sl@0: TUsbDeviceCaps d_caps; sl@0: TInt r = gPort.DeviceCaps(d_caps); sl@0: test(r == KErrNone); sl@0: TInt n = d_caps().iTotalEndpoints; sl@0: sl@0: // Global variable - we'll need this value later sl@0: gSupportsHighSpeed = d_caps().iHighSpeed; sl@0: sl@0: test.Printf(_L("### USB device capabilities:\n")); sl@0: test.Printf(_L("Number of endpoints: %d\n"), n); sl@0: test.Printf(_L("Supports Software-Connect: %s\n"), sl@0: d_caps().iConnect ? _S("yes") : _S("no")); sl@0: test.Printf(_L("Device is Self-Powered: %s\n"), sl@0: d_caps().iSelfPowered ? _S("yes") : _S("no")); sl@0: test.Printf(_L("Supports Remote-Wakeup: %s\n"), sl@0: d_caps().iRemoteWakeup ? _S("yes") : _S("no")); sl@0: test.Printf(_L("Supports High-speed: %s\n"), sl@0: gSupportsHighSpeed ? _S("yes") : _S("no")); sl@0: test.Printf(_L("Supports OTG: %s\n"), sl@0: gSupportsOtg ? _S("yes") : _S("no")); sl@0: test.Printf(_L("Supports unpowered cable detection: %s\n"), sl@0: (d_caps().iFeatureWord1 & KUsbDevCapsFeatureWord1_CableDetectWithoutPower) ? sl@0: _S("yes") : _S("no")); sl@0: test.Printf(_L("Supports endpoint resource alloc scheme V2: %s\n"), sl@0: (d_caps().iFeatureWord1 & KUsbDevCapsFeatureWord1_EndpointResourceAllocV2) ? sl@0: _S("yes") : _S("no")); sl@0: sl@0: test(n >= 2); sl@0: test.Printf(_L("(Device has sufficient endpoints.)\n")); sl@0: sl@0: // Endpoint caps sl@0: test.Next(_L("Query USB endpoint caps")); sl@0: TUsbcEndpointData data[KUsbcMaxEndpoints]; sl@0: TPtr8 dataptr(reinterpret_cast(data), sizeof(data), sizeof(data)); sl@0: r = gPort.EndpointCaps(dataptr); sl@0: test(r == KErrNone); sl@0: sl@0: test.Printf(_L("### USB device endpoint capabilities:\n")); sl@0: for (TInt i = 0; i < n; i++) sl@0: { sl@0: const TUsbcEndpointCaps* caps = &data[i].iCaps; sl@0: test.Printf(_L("Endpoint: SizeMask = 0x%08x TypeDirMask = 0x%08x\n"), sl@0: caps->iSizes, caps->iTypesAndDir); sl@0: if (caps->iHighBandwidth) sl@0: { sl@0: test.Printf(_L(" (high-speed, high bandwidth endpoint)\n")); sl@0: // Must be HS Int or Iso ep sl@0: test(gSupportsHighSpeed); sl@0: test(caps->iTypesAndDir & (KUsbEpTypeIsochronous | KUsbEpTypeInterrupt)); sl@0: } sl@0: } sl@0: sl@0: test.Next(_L("Looking for suitable endpoints")); sl@0: // Set the active interface sl@0: TUsbcInterfaceInfoBuf ifc; sl@0: TInt ep_found = 0; sl@0: TBool foundBulkIN = EFalse; sl@0: TBool foundBulkOUT = EFalse; sl@0: for (TInt i = 0; i < n; i++) sl@0: { sl@0: const TUsbcEndpointCaps* caps = &data[i].iCaps; sl@0: const TInt mps = caps->MaxPacketSize(); sl@0: if (!foundBulkIN && sl@0: (caps->iTypesAndDir & (KUsbEpTypeBulk | KUsbEpDirIn)) == sl@0: (KUsbEpTypeBulk | KUsbEpDirIn)) sl@0: { sl@0: // EEndpoint1 is going to be our TX (IN, write) endpoint sl@0: ifc().iEndpointData[0].iType = KUsbEpTypeBulk; sl@0: ifc().iEndpointData[0].iDir = KUsbEpDirIn; sl@0: ifc().iEndpointData[0].iSize = mps; sl@0: foundBulkIN = ETrue; sl@0: if (++ep_found == 2) sl@0: break; sl@0: } sl@0: else if (!foundBulkOUT && sl@0: (caps->iTypesAndDir & (KUsbEpTypeBulk | KUsbEpDirOut)) == sl@0: (KUsbEpTypeBulk | KUsbEpDirOut)) sl@0: { sl@0: // EEndpoint2 is going to be our RX (OUT, read) endpoint sl@0: ifc().iEndpointData[1].iType = KUsbEpTypeBulk; sl@0: ifc().iEndpointData[1].iDir = KUsbEpDirOut; sl@0: ifc().iEndpointData[1].iSize = mps; sl@0: foundBulkOUT = ETrue; sl@0: if (++ep_found == 2) sl@0: break; sl@0: } sl@0: } sl@0: test(ep_found == 2); sl@0: sl@0: test.Next(_L("Setting up main interface")); sl@0: _LIT16(string, "T_USBAPI Test Interface (Setting 0)"); sl@0: ifc().iString = const_cast(&string); sl@0: ifc().iTotalEndpointsUsed = 2; sl@0: ifc().iClass.iClassNum = 0xff; sl@0: ifc().iClass.iSubClassNum = 0xff; sl@0: ifc().iClass.iProtocolNum = 0xff; sl@0: // Set up the interface. sl@0: r = gPort.SetInterface(0, ifc); sl@0: test(r == KErrNone); sl@0: sl@0: TInt ifc_no = -1; sl@0: r = gPort.GetAlternateSetting(ifc_no); sl@0: test(r == KErrUsbDeviceNotConfigured); sl@0: sl@0: // Some UDCs won't allow endpoint resource manipulation once the hardware has been sl@0: // configured and turned on. So we do it here & now: sl@0: TestResourceAllocation(); sl@0: sl@0: // On the other hand, since some UDCs won't let us test many features which require sl@0: // register access until the USB hardware is powered up (and because it might start sl@0: // out unpowered), we should turn it on here explicitly. sl@0: // (It will be turned off automatically by the PIL after all tests have been run, sl@0: // when the interface gets deleted.) sl@0: test.Next(_L("Powering up UDC (1)")); sl@0: r = gPort.PowerUpUdc(); sl@0: if (!gSupportsOtg) sl@0: { sl@0: test(r == KErrNone); sl@0: } sl@0: else sl@0: { sl@0: test((r == KErrNone) || (r == KErrNotReady)); sl@0: } sl@0: if (gSupportsOtg && (r == KErrNotReady)) sl@0: { sl@0: test.Printf(_L("OTG device but not connected to Host, stopping subtest here.\n")); sl@0: test.End(); sl@0: return; sl@0: } sl@0: // The board might be attached to a PC with HS controller, thus enabling us sl@0: // to test some HS-specific features. For that to work we have to connect sl@0: // the board to the PC. The "Found new device" box that may pop up on the PC sl@0: // in response to this can be ignored (i.e. just closed). sl@0: test.Next(_L("Connecting to Host (1)")); sl@0: r = gPort.DeviceConnectToHost(); sl@0: test(r == KErrNone); sl@0: // Suspend thread to let things get stable on the bus. sl@0: test.Printf(_L("Waiting a short moment...")); sl@0: User::After(2000000); sl@0: test.Printf(_L(" done.\n")); sl@0: sl@0: // Check the speed of the physical connection (if any). sl@0: gUsingHighSpeed = gPort.CurrentlyUsingHighSpeed(); sl@0: if (gUsingHighSpeed) sl@0: { sl@0: test(gSupportsHighSpeed); // sane? sl@0: test.Printf(_L("---> USB High-speed Testing\n")); sl@0: } sl@0: else sl@0: { sl@0: test.Printf(_L("---> USB Full-speed Testing\n")); sl@0: } sl@0: sl@0: // By pulling down the interface/connection and bringing them up again we sl@0: // simulate a starting/stopping of the USB service by a control app. sl@0: sl@0: test.Next(_L("Disconnecting from Host")); sl@0: r = gPort.DeviceDisconnectFromHost(); sl@0: test(r == KErrNone); sl@0: sl@0: test.Next(_L("Releasing interface")); sl@0: r = gPort.ReleaseInterface(0); sl@0: test(r == KErrNone); sl@0: sl@0: test.Next(_L("Setting interface")); sl@0: r = gPort.SetInterface(0, ifc); sl@0: test(r == KErrNone); sl@0: sl@0: // Suspend thread before connecting again. sl@0: test.Printf(_L("Waiting a short moment...")); sl@0: User::After(1000000); sl@0: test.Printf(_L(" done.\n")); sl@0: sl@0: test.Next(_L("Powering up UDC (2)")); sl@0: r = gPort.PowerUpUdc(); sl@0: if (!gSupportsOtg) sl@0: { sl@0: test(r == KErrNone); sl@0: } sl@0: else sl@0: { sl@0: test((r == KErrNone) || (r == KErrNotReady)); sl@0: } sl@0: if (gSupportsOtg && (r == KErrNotReady)) sl@0: { sl@0: test.Printf(_L("OTG device but not connected to Host, stopping subtest here.\n")); sl@0: test.End(); sl@0: return; sl@0: } sl@0: sl@0: test.Next(_L("Connecting to Host (2)")); sl@0: r = gPort.DeviceConnectToHost(); sl@0: test(r == KErrNone); sl@0: // Suspend thread to let things get stable on the bus. sl@0: User::After(2000000); sl@0: sl@0: test.End(); sl@0: } sl@0: sl@0: sl@0: static void TestDeviceDescriptor() sl@0: { sl@0: test.Start(_L("Device Descriptor Manipulation")); sl@0: sl@0: test.Next(_L("GetDeviceDescriptorSize()")); sl@0: TInt desc_size = 0; sl@0: gPort.GetDeviceDescriptorSize(desc_size); sl@0: test(static_cast(desc_size) == KUsbDescSize_Device); sl@0: sl@0: test.Next(_L("GetDeviceDescriptor()")); sl@0: TBuf8 descriptor; sl@0: TInt r = gPort.GetDeviceDescriptor(descriptor); sl@0: test(r == KErrNone); sl@0: sl@0: test.Next(_L("SetDeviceDescriptor()")); sl@0: // Change the USB spec number to 2.30 sl@0: descriptor[KDevDesc_SpecOffset] = 0x30; sl@0: descriptor[KDevDesc_SpecOffset+1] = 0x02; sl@0: // Change the device vendor ID (VID) to 0x1234 sl@0: descriptor[KDevDesc_VendorIdOffset] = 0x34; // little endian sl@0: descriptor[KDevDesc_VendorIdOffset+1] = 0x12; sl@0: // Change the device product ID (PID) to 0x1111 sl@0: descriptor[KDevDesc_ProductIdOffset] = 0x11; sl@0: descriptor[KDevDesc_ProductIdOffset+1] = 0x11; sl@0: // Change the device release number to 3.05 sl@0: descriptor[KDevDesc_DevReleaseOffset] = 0x05; sl@0: descriptor[KDevDesc_DevReleaseOffset+1] = 0x03; sl@0: r = gPort.SetDeviceDescriptor(descriptor); sl@0: test(r == KErrNone); sl@0: sl@0: test.Next(_L("GetDeviceDescriptor()")); sl@0: TBuf8 descriptor2; sl@0: r = gPort.GetDeviceDescriptor(descriptor2); sl@0: test(r == KErrNone); sl@0: sl@0: test.Next(_L("Compare device descriptor with value set")); sl@0: r = descriptor2.Compare(descriptor); sl@0: test(r == KErrNone); sl@0: sl@0: if (gUsingHighSpeed) sl@0: { sl@0: // HS only allows one possible packet size. sl@0: test(descriptor[KDevDesc_Ep0SizeOffset] == 64); sl@0: } sl@0: sl@0: test.End(); sl@0: } sl@0: sl@0: sl@0: static void TestDeviceQualifierDescriptor() sl@0: { sl@0: test.Start(_L("Device_Qualifier Descriptor Manipulation")); sl@0: sl@0: if (!gSupportsHighSpeed) sl@0: { sl@0: test.Printf(_L("*** Not supported - skipping Device_Qualifier descriptor tests\n")); sl@0: test.End(); sl@0: return; sl@0: } sl@0: sl@0: test.Next(_L("GetDeviceQualifierDescriptor()")); sl@0: TBuf8 descriptor; sl@0: TInt r = gPort.GetDeviceQualifierDescriptor(descriptor); sl@0: test(r == KErrNone); sl@0: sl@0: test.Next(_L("SetDeviceQualifierDescriptor()")); sl@0: // Change the USB spec number to 3.00 sl@0: descriptor[KDevDesc_SpecOffset] = 0x00; sl@0: descriptor[KDevDesc_SpecOffset+1] = 0x03; sl@0: // Change the device class, subclass and protocol codes sl@0: descriptor[KDevDesc_DevClassOffset] = 0xA1; sl@0: descriptor[KDevDesc_DevSubClassOffset] = 0xB2; sl@0: descriptor[KDevDesc_DevProtocolOffset] = 0xC3; sl@0: r = gPort.SetDeviceQualifierDescriptor(descriptor); sl@0: test(r == KErrNone); sl@0: sl@0: test.Next(_L("GetDeviceQualifierDescriptor()")); sl@0: TBuf8 descriptor2; sl@0: r = gPort.GetDeviceQualifierDescriptor(descriptor2); sl@0: test(r == KErrNone); sl@0: sl@0: test.Next(_L("Compare Device_Qualifier desc with value set")); sl@0: r = descriptor2.Compare(descriptor); sl@0: test(r == 0); sl@0: sl@0: if (!gUsingHighSpeed) sl@0: { sl@0: // HS only allows one possible packet size. sl@0: test(descriptor[KDevDesc_Ep0SizeOffset] == 64); sl@0: } sl@0: sl@0: test.End(); sl@0: } sl@0: sl@0: sl@0: static void TestConfigurationDescriptor() sl@0: { sl@0: test.Start(_L("Configuration Descriptor Manipulation")); sl@0: sl@0: test.Next(_L("GetConfigurationDescriptorSize()")); sl@0: TInt desc_size = 0; sl@0: gPort.GetConfigurationDescriptorSize(desc_size); sl@0: test(static_cast(desc_size) == KUsbDescSize_Config); sl@0: sl@0: test.Next(_L("GetConfigurationDescriptor()")); sl@0: TBuf8 descriptor; sl@0: TInt r = gPort.GetConfigurationDescriptor(descriptor); sl@0: test(r == KErrNone); sl@0: sl@0: test.Next(_L("SetConfigurationDescriptor()")); sl@0: // Invert Remote-Wakup support sl@0: descriptor[KConfDesc_AttribOffset] = (descriptor[KConfDesc_AttribOffset] ^ KUsbDevAttr_RemoteWakeup); sl@0: // Change the reported max power to 200mA (2 * 0x64) sl@0: descriptor[KConfDesc_MaxPowerOffset] = 0x64; sl@0: r = gPort.SetConfigurationDescriptor(descriptor); sl@0: test(r == KErrNone); sl@0: sl@0: test.Next(_L("GetConfigurationDescriptor()")); sl@0: TBuf8 descriptor2; sl@0: r = gPort.GetConfigurationDescriptor(descriptor2); sl@0: test(r == KErrNone); sl@0: sl@0: test.Next(_L("Compare configuration desc with value set")); sl@0: r = descriptor2.Compare(descriptor); sl@0: test(r == KErrNone); sl@0: sl@0: test.End(); sl@0: } sl@0: sl@0: sl@0: static void TestOtherSpeedConfigurationDescriptor() sl@0: { sl@0: test.Start(_L("Other_Speed_Configuration Desc Manipulation")); sl@0: sl@0: if (!gSupportsHighSpeed) sl@0: { sl@0: test.Printf(_L("*** Not supported - skipping Other_Speed_Configuration desc tests\n")); sl@0: test.End(); sl@0: return; sl@0: } sl@0: sl@0: test.Next(_L("GetOtherSpeedConfigurationDescriptor()")); sl@0: TBuf8 descriptor; sl@0: TInt r = gPort.GetOtherSpeedConfigurationDescriptor(descriptor); sl@0: test(r == KErrNone); sl@0: sl@0: test.Next(_L("SetOtherSpeedConfigurationDescriptor()")); sl@0: // Invert Remote-Wakup support sl@0: descriptor[KConfDesc_AttribOffset] = (descriptor[KConfDesc_AttribOffset] ^ KUsbDevAttr_RemoteWakeup); sl@0: // Change the reported max power to 330mA (2 * 0xA5) sl@0: descriptor[KConfDesc_MaxPowerOffset] = 0xA5; sl@0: r = gPort.SetOtherSpeedConfigurationDescriptor(descriptor); sl@0: test(r == KErrNone); sl@0: sl@0: test.Next(_L("GetOtherSpeedConfigurationDescriptor()")); sl@0: TBuf8 descriptor2; sl@0: r = gPort.GetOtherSpeedConfigurationDescriptor(descriptor2); sl@0: test(r == KErrNone); sl@0: sl@0: test.Next(_L("Compare O_S_Config desc with value set")); sl@0: r = descriptor2.Compare(descriptor); sl@0: test(r == KErrNone); sl@0: sl@0: test.End(); sl@0: } sl@0: sl@0: sl@0: static void TestInterfaceDescriptor() sl@0: { sl@0: test.Start(_L("Interface Descriptor Manipulation")); sl@0: sl@0: // First the standard Interface descriptor sl@0: sl@0: test.Next(_L("GetInterfaceDescriptorSize()")); sl@0: TInt desc_size = 0; sl@0: TInt r = gPort.GetInterfaceDescriptorSize(0, desc_size); sl@0: test(r == KErrNone); sl@0: test(static_cast(desc_size) == KUsbDescSize_Interface); sl@0: sl@0: test.Next(_L("GetInterfaceDescriptor()")); sl@0: TBuf8 descriptor; sl@0: r = gPort.GetInterfaceDescriptor(0, descriptor); sl@0: test(r == KErrNone); sl@0: sl@0: test.Next(_L("SetInterfaceDescriptor()")); sl@0: // Change the interface protocol to 0x78(+) sl@0: TUint8 prot = 0x78; sl@0: if (descriptor[KIfcDesc_ProtocolOffset] == prot) sl@0: prot++; sl@0: descriptor[KIfcDesc_ProtocolOffset] = prot; sl@0: r = gPort.SetInterfaceDescriptor(0, descriptor); sl@0: test(r == KErrNone); sl@0: sl@0: test.Next(_L("GetInterfaceDescriptor()")); sl@0: TBuf8 descriptor2; sl@0: r = gPort.GetInterfaceDescriptor(0, descriptor2); sl@0: test(r == KErrNone); sl@0: sl@0: test.Next(_L("Compare interface descriptor with value set")); sl@0: r = descriptor2.Compare(descriptor); sl@0: test(r == KErrNone); sl@0: sl@0: test.End(); sl@0: } sl@0: sl@0: sl@0: static void TestClassSpecificDescriptors() sl@0: { sl@0: test.Start(_L("Class-specific Descriptor Manipulation")); sl@0: sl@0: // First a class-specific Interface descriptor sl@0: sl@0: test.Next(_L("SetCSInterfaceDescriptorBlock()")); sl@0: // choose arbitrary new descriptor size sl@0: const TInt KUsbDescSize_CS_Interface = KUsbDescSize_Interface + 10; sl@0: TBuf8 cs_ifc_descriptor; sl@0: cs_ifc_descriptor.FillZ(cs_ifc_descriptor.MaxLength()); sl@0: cs_ifc_descriptor[KUsbDesc_SizeOffset] = KUsbDescSize_CS_Interface; sl@0: cs_ifc_descriptor[KUsbDesc_TypeOffset] = KUsbDescType_CS_Interface; sl@0: TInt r = gPort.SetCSInterfaceDescriptorBlock(0, cs_ifc_descriptor); sl@0: test(r == KErrNone); sl@0: sl@0: test.Next(_L("GetCSInterfaceDescriptorBlockSize()")); sl@0: TInt desc_size = 0; sl@0: r = gPort.GetCSInterfaceDescriptorBlockSize(0, desc_size); sl@0: test(r == KErrNone); sl@0: test(desc_size == KUsbDescSize_CS_Interface); sl@0: sl@0: test.Next(_L("GetCSInterfaceDescriptorBlock()")); sl@0: TBuf8 descriptor; sl@0: r = gPort.GetCSInterfaceDescriptorBlock(0, descriptor); sl@0: test(r == KErrNone); sl@0: sl@0: test.Next(_L("Compare CS ifc descriptor with value set")); sl@0: r = descriptor.Compare(cs_ifc_descriptor); sl@0: test(r == KErrNone); sl@0: sl@0: // Next a class-specific Endpoint descriptor sl@0: sl@0: test.Next(_L("SetCSEndpointDescriptorBlock()")); sl@0: // choose arbitrary new descriptor size sl@0: const TInt KUsbDescSize_CS_Endpoint = KUsbDescSize_Endpoint + 5; sl@0: TBuf8 cs_ep_descriptor; sl@0: cs_ep_descriptor.FillZ(cs_ep_descriptor.MaxLength()); sl@0: cs_ep_descriptor[KUsbDesc_SizeOffset] = KUsbDescSize_CS_Endpoint; sl@0: cs_ep_descriptor[KUsbDesc_TypeOffset] = KUsbDescType_CS_Endpoint; sl@0: r = gPort.SetCSEndpointDescriptorBlock(0, 2, cs_ep_descriptor); sl@0: test(r == KErrNone); sl@0: sl@0: test.Next(_L("GetCSEndpointDescriptorBlockSize()")); sl@0: r = gPort.GetCSEndpointDescriptorBlockSize(0, 2, desc_size); sl@0: test(r == KErrNone); sl@0: test(desc_size == KUsbDescSize_CS_Endpoint); sl@0: sl@0: test.Next(_L("GetCSEndpointDescriptorBlock()")); sl@0: TBuf8 descriptor2; sl@0: r = gPort.GetCSEndpointDescriptorBlock(0, 2, descriptor2); sl@0: test(r == KErrNone); sl@0: sl@0: test.Next(_L("Compare CS ep descriptor with value set")); sl@0: r = descriptor2.Compare(cs_ep_descriptor); sl@0: test(r == KErrNone); sl@0: sl@0: test.End(); sl@0: } sl@0: sl@0: sl@0: static void TestAlternateInterfaceManipulation() sl@0: { sl@0: test.Start(_L("Alternate Interface Setting Manipulation")); sl@0: sl@0: if (!SupportsAlternateInterfaces()) sl@0: { sl@0: test.Printf(_L("*** Not supported - skipping alternate interface settings tests\n")); sl@0: test.End(); sl@0: return; sl@0: } sl@0: sl@0: // Fetch endpoint data (again) sl@0: test.Next(_L("Get endpoint capabilities")); sl@0: TUsbDeviceCaps d_caps; sl@0: TInt r = gPort.DeviceCaps(d_caps); sl@0: test(r == KErrNone); sl@0: const TInt n = d_caps().iTotalEndpoints; sl@0: TUsbcEndpointData data[KUsbcMaxEndpoints]; sl@0: TPtr8 dataptr(reinterpret_cast(data), sizeof(data), sizeof(data)); sl@0: r = gPort.EndpointCaps(dataptr); sl@0: test(r == KErrNone); sl@0: sl@0: // Find ep's for alternate ifc setting sl@0: test.Next(_L("Find suitable endpoints")); sl@0: TInt ep_found = 0; sl@0: TBool foundIsoIN = EFalse; sl@0: TBool foundIsoOUT = EFalse; sl@0: TBool foundIntIN = EFalse; sl@0: TUsbcInterfaceInfoBuf ifc; sl@0: sl@0: // NB! We cannot assume that any specific device has any given set of sl@0: // capabilities, so whilst we try and set an assortment of endpoint types sl@0: // we may not get what we want. sl@0: sl@0: // Also, note that the endpoint[] array in the interface descriptor sl@0: // must be filled from ep[0]...ep[n-1]. sl@0: sl@0: for (TInt i = 0; i < n; i++) sl@0: { sl@0: const TUsbcEndpointCaps* const caps = &data[i].iCaps; sl@0: const TInt mps = caps->MaxPacketSize(); sl@0: if (!foundIsoIN && sl@0: (caps->iTypesAndDir & (KUsbEpTypeIsochronous | KUsbEpDirIn)) == sl@0: (KUsbEpTypeIsochronous | KUsbEpDirIn)) sl@0: { sl@0: // This is going to be our Iso TX (IN) endpoint sl@0: ifc().iEndpointData[ep_found].iType = KUsbEpTypeIsochronous; sl@0: ifc().iEndpointData[ep_found].iDir = KUsbEpDirIn; sl@0: ifc().iEndpointData[ep_found].iSize = mps; sl@0: ifc().iEndpointData[ep_found].iInterval = 0x01; // 2^(bInterval-1)ms, bInterval must be [1..16] sl@0: ifc().iEndpointData[ep_found].iInterval_Hs = 0x01; // same as for FS sl@0: test.Printf(_L("ISO IN size = %4d (ep %d)\n"), mps, ep_found + 1); sl@0: foundIsoIN = ETrue; sl@0: if (++ep_found == 3) sl@0: break; sl@0: } sl@0: else if (!foundIsoOUT && sl@0: (caps->iTypesAndDir & (KUsbEpTypeIsochronous | KUsbEpDirOut)) == sl@0: (KUsbEpTypeIsochronous | KUsbEpDirOut)) sl@0: { sl@0: // This is going to be our Iso RX (OUT) endpoint sl@0: ifc().iEndpointData[ep_found].iType = KUsbEpTypeIsochronous; sl@0: ifc().iEndpointData[ep_found].iDir = KUsbEpDirOut; sl@0: ifc().iEndpointData[ep_found].iSize = mps; sl@0: ifc().iEndpointData[ep_found].iInterval = 0x01; // 2^(bInterval-1)ms, bInterval must be [1..16] sl@0: test.Printf(_L("ISO OUT size = %4d (ep %d)\n"), mps, ep_found + 1); sl@0: foundIsoOUT = ETrue; sl@0: if (++ep_found == 3) sl@0: break; sl@0: } sl@0: else if (!foundIntIN && sl@0: (caps->iTypesAndDir & (KUsbEpTypeInterrupt | KUsbEpDirIn)) == sl@0: (KUsbEpTypeInterrupt | KUsbEpDirIn)) sl@0: { sl@0: // This is going to be our Interrupt TX (IN) endpoint sl@0: ifc().iEndpointData[ep_found].iType = KUsbEpTypeInterrupt; sl@0: ifc().iEndpointData[ep_found].iDir = KUsbEpDirIn; sl@0: ifc().iEndpointData[ep_found].iSize = mps; sl@0: ifc().iEndpointData[ep_found].iInterval = 10; // interval = 10ms, valid range [1..255] sl@0: ifc().iEndpointData[ep_found].iInterval_Hs = 4; // interval = 2^(bInterval-1)ms = 8ms sl@0: ifc().iEndpointData[ep_found].iExtra = 2; // 2 extra bytes for Audio Class EP descriptor sl@0: test.Printf(_L("INT IN size = %4d (ep %d)\n"), mps, ep_found + 1); sl@0: foundIntIN = ETrue; sl@0: INT_IN_ep = ep_found + 1; sl@0: if (++ep_found == 3) sl@0: break; sl@0: } sl@0: } sl@0: sl@0: // Let's try to add some more Bulk endpoints up to the max # of 5. sl@0: for (TInt i = 0; i < n; i++) sl@0: { sl@0: TUsbcEndpointCaps& caps = data[i].iCaps; sl@0: const TUint mps = caps.MaxPacketSize(); sl@0: if (caps.iTypesAndDir & KUsbEpTypeBulk) sl@0: { sl@0: const TUint dir = (caps.iTypesAndDir & KUsbEpDirIn) ? KUsbEpDirIn : KUsbEpDirOut; sl@0: ifc().iEndpointData[ep_found].iType = KUsbEpTypeBulk; sl@0: ifc().iEndpointData[ep_found].iDir = dir; sl@0: if (gUsingHighSpeed) sl@0: { sl@0: test.Printf(_L("Checking if correct Bulk packet size is reported in HS case\n")); sl@0: test(mps == KUsbEpSize512); // sane? sl@0: } sl@0: // The PSL should in any case also offer the 'legacy' FS size: sl@0: test(caps.iSizes & KUsbEpSize64); sl@0: ifc().iEndpointData[ep_found].iSize = mps; sl@0: test.Printf(_L("BULK %s size = %4d (ep %d)\n"), sl@0: dir == KUsbEpDirIn ? _S("IN ") : _S("OUT"), mps, ep_found + 1); sl@0: if (++ep_found == 5) sl@0: break; sl@0: } sl@0: } sl@0: sl@0: test.Printf(_L("Total: %d endpoints found for the alt. ifc setting\n"), ep_found); sl@0: if (ep_found < 3) sl@0: { sl@0: test.Printf(_L("(3 endpoints are at least required. Skipping test...)\n")); sl@0: test.End(); sl@0: return; sl@0: } sl@0: sl@0: if (!foundIsoIN && !foundIsoOUT) sl@0: { sl@0: test.Printf(_L("(No Isochronous endpoints found)\n")); sl@0: } sl@0: sl@0: if (!foundIntIN) sl@0: { sl@0: test.Printf(_L("(No Interrupt endpoint found)\n")); sl@0: test.Printf(_L("Adjusting endpoint size for later test\n")); sl@0: // We want to make sure that at least one descriptor has the 2 extra bytes. sl@0: // It doesn't matter that this ep could be a Bulk one, or that the 2 Iso ep's might be missing - sl@0: // we just want to test some functionality and we're not going to use this interface in earnest. sl@0: ifc().iEndpointData[2].iExtra = 2; // 2 extra bytes for Audio Class Ep descriptor sl@0: INT_IN_ep = 3; // pretend it's an INT ep sl@0: } sl@0: sl@0: test.Next(_L("Create alternate interface setting")); sl@0: _LIT16(string, "T_USBAPI Test Interface (Setting 1: Audio)"); sl@0: ifc().iString = const_cast(&string); sl@0: ifc().iTotalEndpointsUsed = ep_found; sl@0: ifc().iClass.iClassNum = KUsbAudioInterfaceClassCode; sl@0: ifc().iClass.iSubClassNum = KUsbAudioInterfaceSubclassCode_Audiostreaming; sl@0: ifc().iClass.iProtocolNum = KUsbAudioInterfaceProtocolCode_Pr_Protocol_Undefined; sl@0: r = gPort.SetInterface(1, ifc); sl@0: test(r == KErrNone); sl@0: sl@0: test.Next(_L("Set alternate setting number to 8")); sl@0: TBuf8 descriptor; sl@0: r = gPort.GetInterfaceDescriptor(1, descriptor); sl@0: test(r == KErrNone); sl@0: descriptor[KIfcDesc_SettingOffset] = 8; sl@0: r = gPort.SetInterfaceDescriptor(1, descriptor); sl@0: test(r != KErrNone); sl@0: sl@0: test.Next(_L("Change ifc # in def setting whith alt ifcs")); sl@0: r = gPort.GetInterfaceDescriptor(0, descriptor); sl@0: test(r == KErrNone); sl@0: descriptor[KIfcDesc_SettingOffset] = 8; sl@0: r = gPort.SetInterfaceDescriptor(0, descriptor); sl@0: test(r != KErrNone); sl@0: sl@0: test.Next(_L("Change the ifc # in default setting to 8")); sl@0: r = gPort.ReleaseInterface(1); sl@0: test(r == KErrNone); sl@0: r = gPort.SetInterfaceDescriptor(0, descriptor); sl@0: test(r == KErrNone); sl@0: sl@0: test.Next(_L("Create new setting - this should also get #8")); sl@0: r = gPort.SetInterface(1, ifc); sl@0: test(r == KErrNone); sl@0: r = gPort.GetInterfaceDescriptor(1, descriptor); sl@0: test(r == KErrNone); sl@0: test(descriptor[KIfcDesc_SettingOffset] == 8); sl@0: sl@0: test.Next(_L("Change the ifc # in default setting to 0")); sl@0: r = gPort.ReleaseInterface(1); sl@0: test(r == KErrNone); sl@0: r = gPort.GetInterfaceDescriptor(0, descriptor); sl@0: test(r == KErrNone); sl@0: descriptor[KIfcDesc_SettingOffset] = 0; sl@0: r = gPort.SetInterfaceDescriptor(0, descriptor); sl@0: test(r == KErrNone); sl@0: sl@0: test.Next(_L("Create new setting - this should also get #0")); sl@0: r = gPort.SetInterface(1, ifc); sl@0: test(r == KErrNone); sl@0: r = gPort.GetInterfaceDescriptor(1, descriptor); sl@0: test(r == KErrNone); sl@0: test(descriptor[KIfcDesc_SettingOffset] == 0); sl@0: sl@0: test.End(); sl@0: } sl@0: sl@0: sl@0: static void TestEndpointDescriptor() sl@0: { sl@0: test.Start(_L("Endpoint Descriptor Manipulation")); sl@0: sl@0: test.Next(_L("GetEndpointDescriptorSize(1)")); sl@0: TInt epNumber = 1; sl@0: TInt desc_size = 0; sl@0: TInt r = gPort.GetEndpointDescriptorSize(0, epNumber, desc_size); sl@0: test(r == KErrNone); sl@0: test(static_cast(desc_size) == KUsbDescSize_Endpoint); sl@0: sl@0: test.Next(_L("GetEndpointDescriptor(1)")); sl@0: TBuf8 descriptor; sl@0: r = gPort.GetEndpointDescriptor(0, epNumber, descriptor); sl@0: test(r == KErrNone); sl@0: sl@0: test.Next(_L("SetEndpointDescriptor(1)")); sl@0: // Change the endpoint poll interval sl@0: TUint8 ival = 0x66; sl@0: if (descriptor[KEpDesc_IntervalOffset] == ival) sl@0: ival++; sl@0: descriptor[KEpDesc_IntervalOffset] = ival; sl@0: r = gPort.SetEndpointDescriptor(0, epNumber, descriptor); sl@0: test(r == KErrNone); sl@0: sl@0: test.Next(_L("GetEndpointDescriptor(1)")); sl@0: TBuf8 descriptor2; sl@0: r = gPort.GetEndpointDescriptor(0, epNumber, descriptor2); sl@0: test(r == KErrNone); sl@0: sl@0: test.Next(_L("Compare endpoint descriptor with value set")); sl@0: r = descriptor2.Compare(descriptor); sl@0: test(r == KErrNone); sl@0: sl@0: test.Next(_L("Check endpoint max packet size")); sl@0: const TUint16 ep_size = EpSize(descriptor[KEpDesc_PacketSizeOffset], sl@0: descriptor[KEpDesc_PacketSizeOffset+1]); sl@0: test.Printf(_L(" Size: %d\n"), ep_size); sl@0: if (gUsingHighSpeed) sl@0: { sl@0: // HS Bulk ep can only have one possible packet size. sl@0: test(ep_size == 512); sl@0: } sl@0: else sl@0: { sl@0: // FS Bulk ep cannot be larger than 64 bytes. sl@0: test(ep_size <= 64); sl@0: } sl@0: sl@0: test.End(); sl@0: } sl@0: sl@0: sl@0: static void TestExtendedEndpointDescriptor() sl@0: { sl@0: test.Start(_L("Extended Endpoint Descriptor Manipulation")); sl@0: sl@0: if (!SupportsAlternateInterfaces()) sl@0: { sl@0: test.Printf(_L("*** Not supported - skipping Extended Endpoint descriptor tests\n")); sl@0: test.End(); sl@0: return; sl@0: } sl@0: sl@0: // Extended Endpoint Descriptor manipulation (Audio class endpoint) sl@0: sl@0: test.Next(_L("GetEndpointDescriptorSize()")); sl@0: TInt epNumber = INT_IN_ep; sl@0: TInt desc_size = 0; sl@0: TInt r = gPort.GetEndpointDescriptorSize(1, epNumber, desc_size); sl@0: test(r == KErrNone); sl@0: test(static_cast(desc_size) == KUsbDescSize_AudioEndpoint); sl@0: sl@0: test.Next(_L("GetEndpointDescriptor()")); sl@0: TBuf8 descriptor; sl@0: r = gPort.GetEndpointDescriptor(1, epNumber, descriptor); sl@0: test(r == KErrNone); sl@0: sl@0: test.Next(_L("SetEndpointDescriptor()")); sl@0: // Change the Audio Endpoint bSynchAddress field sl@0: TUint8 addr = 0x85; // bogus address sl@0: if (descriptor[KEpDesc_SynchAddressOffset] == addr) sl@0: addr++; sl@0: descriptor[KEpDesc_SynchAddressOffset] = addr; sl@0: r = gPort.SetEndpointDescriptor(1, epNumber, descriptor); sl@0: test(r == KErrNone); sl@0: sl@0: test.Next(_L("GetEndpointDescriptor()")); sl@0: TBuf8 descriptor2; sl@0: r = gPort.GetEndpointDescriptor(1, epNumber, descriptor2); sl@0: test(r == KErrNone); sl@0: sl@0: test.Next(_L("Compare endpoint descriptor with value set")); sl@0: r = descriptor2.Compare(descriptor); sl@0: test(r == KErrNone); sl@0: sl@0: test.Next(_L("Check endpoint max packet size")); sl@0: const TUint16 ep_size = EpSize(descriptor[KEpDesc_PacketSizeOffset], sl@0: descriptor[KEpDesc_PacketSizeOffset+1]); sl@0: if (gUsingHighSpeed) sl@0: { sl@0: // HS Interrupt ep. sl@0: test(ep_size <= 1024); sl@0: } sl@0: else sl@0: { sl@0: // FS Interrupt ep cannot be larger than 64 bytes. sl@0: test(ep_size <= 64); sl@0: } sl@0: sl@0: test.End(); sl@0: } sl@0: sl@0: sl@0: static void TestStandardStringDescriptors() sl@0: { sl@0: test.Start(_L("String Descriptor Manipulation")); sl@0: sl@0: // sl@0: // --- LANGID code sl@0: // sl@0: sl@0: test.Next(_L("GetStringDescriptorLangId()")); sl@0: TUint16 rd_langid_orig; sl@0: TInt r = gPort.GetStringDescriptorLangId(rd_langid_orig); sl@0: test(r == KErrNone); sl@0: test.Printf(_L("Original LANGID code: 0x%04X\n"), rd_langid_orig); sl@0: sl@0: test.Next(_L("SetStringDescriptorLangId()")); sl@0: TUint16 wr_langid = 0x0809; // English (UK) Language ID sl@0: if (wr_langid == rd_langid_orig) sl@0: wr_langid = 0x0444; // Tatar Language ID sl@0: r = gPort.SetStringDescriptorLangId(wr_langid); sl@0: test(r == KErrNone); sl@0: sl@0: test.Next(_L("GetStringDescriptorLangId()")); sl@0: TUint16 rd_langid; sl@0: r = gPort.GetStringDescriptorLangId(rd_langid); sl@0: test(r == KErrNone); sl@0: test.Printf(_L("New LANGID code: 0x%04X\n"), rd_langid); sl@0: sl@0: test.Next(_L("Compare LANGID codes")); sl@0: test(rd_langid == wr_langid); sl@0: sl@0: test.Next(_L("Restore original LANGID code")); sl@0: r = gPort.SetStringDescriptorLangId(rd_langid_orig); sl@0: test(r == KErrNone); sl@0: r = gPort.GetStringDescriptorLangId(rd_langid); sl@0: test(r == KErrNone); sl@0: test(rd_langid == rd_langid_orig); sl@0: sl@0: // sl@0: // --- Manufacturer string sl@0: // sl@0: sl@0: test.Next(_L("GetManufacturerStringDescriptor()")); sl@0: TBuf16 rd_str_orig; sl@0: r = gPort.GetManufacturerStringDescriptor(rd_str_orig); sl@0: test(r == KErrNone || r == KErrNotFound); sl@0: TBool restore_string; sl@0: if (r == KErrNone) sl@0: { sl@0: test.Printf(_L("Original Manufacturer string: \"%lS\"\n"), &rd_str_orig); sl@0: restore_string = ETrue; sl@0: } sl@0: else sl@0: { sl@0: test.Printf(_L("No Manufacturer string set\n")); sl@0: restore_string = EFalse; sl@0: } sl@0: sl@0: test.Next(_L("SetManufacturerStringDescriptor()")); sl@0: _LIT16(manufacturer, "Manufacturer Which Manufactures Devices"); sl@0: TBuf16 wr_str(manufacturer); sl@0: r = gPort.SetManufacturerStringDescriptor(wr_str); sl@0: test(r == KErrNone); sl@0: sl@0: test.Next(_L("GetManufacturerStringDescriptor()")); sl@0: TBuf16 rd_str; sl@0: r = gPort.GetManufacturerStringDescriptor(rd_str); sl@0: test(r == KErrNone); sl@0: test.Printf(_L("New Manufacturer string: \"%lS\"\n"), &rd_str); sl@0: sl@0: test.Next(_L("Compare Manufacturer strings")); sl@0: r = rd_str.Compare(wr_str); sl@0: test(r == KErrNone); sl@0: sl@0: test.Next(_L("SetManufacturerStringDescriptor()")); sl@0: _LIT16(manufacturer2, "Different Manufacturer Which Manufactures Different Devices"); sl@0: wr_str.FillZ(wr_str.MaxLength()); sl@0: wr_str = manufacturer2; sl@0: r = gPort.SetManufacturerStringDescriptor(wr_str); sl@0: test(r == KErrNone); sl@0: sl@0: test.Next(_L("GetManufacturerStringDescriptor()")); sl@0: rd_str.FillZ(rd_str.MaxLength()); sl@0: r = gPort.GetManufacturerStringDescriptor(rd_str); sl@0: test(r == KErrNone); sl@0: test.Printf(_L("New Manufacturer string: \"%lS\"\n"), &rd_str); sl@0: sl@0: test.Next(_L("Compare Manufacturer strings")); sl@0: r = rd_str.Compare(wr_str); sl@0: test(r == KErrNone); sl@0: sl@0: test.Next(_L("RemoveManufacturerStringDescriptor()")); sl@0: r = gPort.RemoveManufacturerStringDescriptor(); sl@0: test(r == KErrNone); sl@0: r = gPort.GetManufacturerStringDescriptor(rd_str); sl@0: test(r == KErrNotFound); sl@0: sl@0: if (restore_string) sl@0: { sl@0: test.Next(_L("Restore original string")); sl@0: r = gPort.SetManufacturerStringDescriptor(rd_str_orig); sl@0: test(r == KErrNone); sl@0: r = gPort.GetManufacturerStringDescriptor(rd_str); sl@0: test(r == KErrNone); sl@0: r = rd_str.Compare(rd_str_orig); sl@0: test(r == KErrNone); sl@0: } sl@0: sl@0: // sl@0: // --- Product string sl@0: // sl@0: sl@0: test.Next(_L("GetProductStringDescriptor()")); sl@0: rd_str_orig.FillZ(rd_str.MaxLength()); sl@0: r = gPort.GetProductStringDescriptor(rd_str_orig); sl@0: test(r == KErrNone || r == KErrNotFound); sl@0: if (r == KErrNone) sl@0: { sl@0: test.Printf(_L("Old Product string: \"%lS\"\n"), &rd_str_orig); sl@0: restore_string = ETrue; sl@0: } sl@0: else sl@0: restore_string = EFalse; sl@0: sl@0: test.Next(_L("SetProductStringDescriptor()")); sl@0: _LIT16(product, "Product That Was Produced By A Manufacturer"); sl@0: wr_str.FillZ(wr_str.MaxLength()); sl@0: wr_str = product; sl@0: r = gPort.SetProductStringDescriptor(wr_str); sl@0: test(r == KErrNone); sl@0: sl@0: test.Next(_L("GetProductStringDescriptor()")); sl@0: rd_str.FillZ(rd_str.MaxLength()); sl@0: r = gPort.GetProductStringDescriptor(rd_str); sl@0: test(r == KErrNone); sl@0: test.Printf(_L("New Product string: \"%lS\"\n"), &rd_str); sl@0: sl@0: test.Next(_L("Compare Product strings")); sl@0: r = rd_str.Compare(wr_str); sl@0: test(r == KErrNone); sl@0: sl@0: test.Next(_L("SetProductStringDescriptor()")); sl@0: _LIT16(product2, "Different Product That Was Produced By A Different Manufacturer"); sl@0: wr_str.FillZ(wr_str.MaxLength()); sl@0: wr_str = product2; sl@0: r = gPort.SetProductStringDescriptor(wr_str); sl@0: test(r == KErrNone); sl@0: sl@0: test.Next(_L("GetProductStringDescriptor()")); sl@0: rd_str.FillZ(rd_str.MaxLength()); sl@0: r = gPort.GetProductStringDescriptor(rd_str); sl@0: test(r == KErrNone); sl@0: test.Printf(_L("New Product string: \"%lS\"\n"), &rd_str); sl@0: sl@0: test.Next(_L("Compare Product strings")); sl@0: r = rd_str.Compare(wr_str); sl@0: test(r == KErrNone); sl@0: sl@0: test.Next(_L("RemoveProductStringDescriptor()")); sl@0: r = gPort.RemoveProductStringDescriptor(); sl@0: test(r == KErrNone); sl@0: r = gPort.GetProductStringDescriptor(rd_str); sl@0: test(r == KErrNotFound); sl@0: sl@0: if (restore_string) sl@0: { sl@0: test.Next(_L("Restore original string")); sl@0: r = gPort.SetProductStringDescriptor(rd_str_orig); sl@0: test(r == KErrNone); sl@0: r = gPort.GetProductStringDescriptor(rd_str); sl@0: test(r == KErrNone); sl@0: r = rd_str.Compare(rd_str_orig); sl@0: test(r == KErrNone); sl@0: } sl@0: sl@0: // sl@0: // --- Serial Number string sl@0: // sl@0: sl@0: test.Next(_L("GetSerialNumberStringDescriptor()")); sl@0: rd_str_orig.FillZ(rd_str.MaxLength()); sl@0: r = gPort.GetSerialNumberStringDescriptor(rd_str_orig); sl@0: test(r == KErrNone || r == KErrNotFound); sl@0: if (r == KErrNone) sl@0: { sl@0: test.Printf(_L("Old Serial Number: \"%lS\"\n"), &rd_str_orig); sl@0: restore_string = ETrue; sl@0: } sl@0: else sl@0: restore_string = EFalse; sl@0: sl@0: test.Next(_L("SetSerialNumberStringDescriptor()")); sl@0: _LIT16(serial, "000666000XYZ"); sl@0: wr_str.FillZ(wr_str.MaxLength()); sl@0: wr_str = serial; sl@0: r = gPort.SetSerialNumberStringDescriptor(wr_str); sl@0: test(r == KErrNone); sl@0: sl@0: test.Next(_L("GetSerialNumberStringDescriptor()")); sl@0: rd_str.FillZ(rd_str.MaxLength()); sl@0: r = gPort.GetSerialNumberStringDescriptor(rd_str); sl@0: test(r == KErrNone); sl@0: test.Printf(_L("New Serial Number: \"%lS\"\n"), &rd_str); sl@0: sl@0: test.Next(_L("Compare Serial Number strings")); sl@0: r = rd_str.Compare(wr_str); sl@0: test(r == KErrNone); sl@0: sl@0: test.Next(_L("SetSerialNumberStringDescriptor()")); sl@0: _LIT16(serial2, "Y11611193111711111Y"); sl@0: wr_str.FillZ(wr_str.MaxLength()); sl@0: wr_str = serial2; sl@0: r = gPort.SetSerialNumberStringDescriptor(wr_str); sl@0: test(r == KErrNone); sl@0: sl@0: test.Next(_L("GetSerialNumberStringDescriptor()")); sl@0: rd_str.FillZ(rd_str.MaxLength()); sl@0: r = gPort.GetSerialNumberStringDescriptor(rd_str); sl@0: test(r == KErrNone); sl@0: test.Printf(_L("New Serial Number: \"%lS\"\n"), &rd_str); sl@0: sl@0: test.Next(_L("Compare Serial Number strings")); sl@0: r = rd_str.Compare(wr_str); sl@0: test(r == KErrNone); sl@0: sl@0: test.Next(_L("RemoveSerialNumberStringDescriptor()")); sl@0: r = gPort.RemoveSerialNumberStringDescriptor(); sl@0: test(r == KErrNone); sl@0: r = gPort.GetSerialNumberStringDescriptor(rd_str); sl@0: test(r == KErrNotFound); sl@0: sl@0: if (restore_string) sl@0: { sl@0: test.Next(_L("Restore original string")); sl@0: r = gPort.SetSerialNumberStringDescriptor(rd_str_orig); sl@0: test(r == KErrNone); sl@0: r = gPort.GetSerialNumberStringDescriptor(rd_str); sl@0: test(r == KErrNone); sl@0: r = rd_str.Compare(rd_str_orig); sl@0: test(r == KErrNone); sl@0: } sl@0: sl@0: // sl@0: // --- Configuration string sl@0: // sl@0: sl@0: test.Next(_L("GetConfigurationStringDescriptor()")); sl@0: rd_str_orig.FillZ(rd_str.MaxLength()); sl@0: r = gPort.GetConfigurationStringDescriptor(rd_str_orig); sl@0: test(r == KErrNone || r == KErrNotFound); sl@0: if (r == KErrNone) sl@0: { sl@0: test.Printf(_L("Old Configuration string: \"%lS\"\n"), &rd_str_orig); sl@0: restore_string = ETrue; sl@0: } sl@0: else sl@0: restore_string = EFalse; sl@0: sl@0: test.Next(_L("SetConfigurationStringDescriptor()")); sl@0: _LIT16(config, "Relatively Simple Configuration That Is Still Useful"); sl@0: wr_str.FillZ(wr_str.MaxLength()); sl@0: wr_str = config; sl@0: r = gPort.SetConfigurationStringDescriptor(wr_str); sl@0: test(r == KErrNone); sl@0: sl@0: test.Next(_L("GetConfigurationStringDescriptor()")); sl@0: rd_str.FillZ(rd_str.MaxLength()); sl@0: r = gPort.GetConfigurationStringDescriptor(rd_str); sl@0: test(r == KErrNone); sl@0: test.Printf(_L("New Configuration string: \"%lS\"\n"), &rd_str); sl@0: sl@0: test.Next(_L("Compare Configuration strings")); sl@0: r = rd_str.Compare(wr_str); sl@0: test(r == KErrNone); sl@0: sl@0: test.Next(_L("SetConfigurationStringDescriptor()")); sl@0: _LIT16(config2, "Convenient Configuration That Can Be Very Confusing"); sl@0: wr_str.FillZ(wr_str.MaxLength()); sl@0: wr_str = config2; sl@0: r = gPort.SetConfigurationStringDescriptor(wr_str); sl@0: test(r == KErrNone); sl@0: sl@0: test.Next(_L("GetConfigurationStringDescriptor()")); sl@0: rd_str.FillZ(rd_str.MaxLength()); sl@0: r = gPort.GetConfigurationStringDescriptor(rd_str); sl@0: test(r == KErrNone); sl@0: test.Printf(_L("New Configuration string: \"%lS\"\n"), &rd_str); sl@0: sl@0: test.Next(_L("Compare Configuration strings")); sl@0: r = rd_str.Compare(wr_str); sl@0: test(r == KErrNone); sl@0: sl@0: test.Next(_L("RemoveConfigurationStringDescriptor()")); sl@0: r = gPort.RemoveConfigurationStringDescriptor(); sl@0: test(r == KErrNone); sl@0: r = gPort.GetConfigurationStringDescriptor(rd_str); sl@0: test(r == KErrNotFound); sl@0: sl@0: if (restore_string) sl@0: { sl@0: test.Next(_L("Restore original string")); sl@0: r = gPort.SetConfigurationStringDescriptor(rd_str_orig); sl@0: test(r == KErrNone); sl@0: r = gPort.GetConfigurationStringDescriptor(rd_str); sl@0: test(r == KErrNone); sl@0: r = rd_str.Compare(rd_str_orig); sl@0: test(r == KErrNone); sl@0: } sl@0: sl@0: test.End(); sl@0: } sl@0: sl@0: sl@0: //--------------------------------------------- sl@0: //! @SYMTestCaseID KBASE-T_USBAPI-0041 sl@0: //! @SYMTestType UT sl@0: //! @SYMREQ REQ5662 sl@0: //! @SYMTestCaseDesc USB Device Driver API extension to support setting of a string descriptor at a specific index sl@0: //! @SYMTestActions Tests GetStringDescriptor(), SetStringDescriptor() and RemoveStringDescriptor() to verify sl@0: //! the right values are retrieved, set and deleted at specific positions sl@0: //! @SYMTestExpectedResults KErrNone in positive testing and KErrNotFound in negative one sl@0: //! @SYMTestPriority High sl@0: //! @SYMTestStatus Implemented sl@0: //--------------------------------------------- sl@0: static void TestArbitraryStringDescriptors() sl@0: { sl@0: test.Start(_L("Arbitrary String Descriptor Manipulation")); sl@0: sl@0: const TUint8 stridx1 = 0xEE; sl@0: const TUint8 stridx2 = 0xCC; sl@0: const TUint8 stridx3 = 0xDD; sl@0: const TUint8 stridx4 = 0xFF; sl@0: sl@0: // First test string sl@0: sl@0: test.Next(_L("GetStringDescriptor() 1")); sl@0: TBuf16 rd_str; sl@0: TInt r = gPort.GetStringDescriptor(stridx1, rd_str); sl@0: test(r == KErrNotFound); sl@0: sl@0: test.Next(_L("SetStringDescriptor() 1")); sl@0: _LIT16(string_one, "Arbitrary String Descriptor Test String 1"); sl@0: TBuf16 wr_str(string_one); sl@0: r = gPort.SetStringDescriptor(stridx1, wr_str); sl@0: test(r == KErrNone); sl@0: sl@0: test.Next(_L("GetStringDescriptor() 1")); sl@0: r = gPort.GetStringDescriptor(stridx1, rd_str); sl@0: test(r == KErrNone); sl@0: test.Printf(_L("New test string @ idx %d: \"%lS\"\n"), stridx1, &rd_str); sl@0: sl@0: test.Next(_L("Compare test strings 1")); sl@0: r = rd_str.Compare(wr_str); sl@0: test(r == KErrNone); sl@0: sl@0: // Second test string sl@0: sl@0: test.Next(_L("GetStringDescriptor() 2")); sl@0: rd_str.FillZ(rd_str.MaxLength()); sl@0: r = gPort.GetStringDescriptor(stridx2, rd_str); sl@0: test(r == KErrNotFound); sl@0: sl@0: test.Next(_L("SetStringDescriptor() 2")); sl@0: _LIT16(string_two, "Arbitrary String Descriptor Test String 2"); sl@0: wr_str.FillZ(wr_str.MaxLength()); sl@0: wr_str = string_two; sl@0: r = gPort.SetStringDescriptor(stridx2, wr_str); sl@0: test(r == KErrNone); sl@0: sl@0: // In between we create another interface setting to see what happens sl@0: // to the existing string descriptor indices. sl@0: // (We don't have to test this on every platform - sl@0: // besides, those that don't support alt settings sl@0: // are by now very rare.) sl@0: if (SupportsAlternateInterfaces()) sl@0: { sl@0: TUsbcInterfaceInfoBuf ifc; sl@0: _LIT16(string, "T_USBAPI Bogus Test Interface (Setting 2)"); sl@0: ifc().iString = const_cast(&string); sl@0: ifc().iTotalEndpointsUsed = 0; sl@0: TInt r = gPort.SetInterface(2, ifc); sl@0: test(r == KErrNone); sl@0: } sl@0: sl@0: test.Next(_L("GetStringDescriptor() 2")); sl@0: r = gPort.GetStringDescriptor(stridx2, rd_str); sl@0: test(r == KErrNone); sl@0: test.Printf(_L("New test string @ idx %d: \"%lS\"\n"), stridx2, &rd_str); sl@0: sl@0: test.Next(_L("Compare test strings 2")); sl@0: r = rd_str.Compare(wr_str); sl@0: test(r == KErrNone); sl@0: sl@0: // Third test string sl@0: sl@0: test.Next(_L("GetStringDescriptor() 3")); sl@0: rd_str.FillZ(rd_str.MaxLength()); sl@0: r = gPort.GetStringDescriptor(stridx3, rd_str); sl@0: test(r == KErrNotFound); sl@0: sl@0: test.Next(_L("SetStringDescriptor() 3")); sl@0: _LIT16(string_three, "Arbitrary String Descriptor Test String 3"); sl@0: wr_str.FillZ(wr_str.MaxLength()); sl@0: wr_str = string_three; sl@0: r = gPort.SetStringDescriptor(stridx3, wr_str); sl@0: test(r == KErrNone); sl@0: sl@0: test.Next(_L("GetStringDescriptor() 3")); sl@0: r = gPort.GetStringDescriptor(stridx3, rd_str); sl@0: test(r == KErrNone); sl@0: test.Printf(_L("New test string @ idx %d: \"%lS\"\n"), stridx3, &rd_str); sl@0: sl@0: test.Next(_L("Compare test strings 3")); sl@0: r = rd_str.Compare(wr_str); sl@0: test(r == KErrNone); sl@0: sl@0: // Remove string descriptors sl@0: sl@0: test.Next(_L("RemoveStringDescriptor() 4")); sl@0: r = gPort.RemoveStringDescriptor(stridx4); sl@0: test(r == KErrNotFound); sl@0: sl@0: test.Next(_L("RemoveStringDescriptor() 3")); sl@0: r = gPort.RemoveStringDescriptor(stridx3); sl@0: test(r == KErrNone); sl@0: r = gPort.GetStringDescriptor(stridx3, rd_str); sl@0: test(r == KErrNotFound); sl@0: sl@0: test.Next(_L("RemoveStringDescriptor() 2")); sl@0: r = gPort.RemoveStringDescriptor(stridx2); sl@0: test(r == KErrNone); sl@0: r = gPort.GetStringDescriptor(stridx2, rd_str); sl@0: test(r == KErrNotFound); sl@0: sl@0: test.Next(_L("RemoveStringDescriptor() 1")); sl@0: r = gPort.RemoveStringDescriptor(stridx1); sl@0: test(r == KErrNone); sl@0: r = gPort.GetStringDescriptor(stridx1, rd_str); sl@0: test(r == KErrNotFound); sl@0: sl@0: test.End(); sl@0: } sl@0: sl@0: sl@0: static void TestDescriptorManipulation() sl@0: { sl@0: test.Start(_L("Test USB Descriptor Manipulation")); sl@0: sl@0: TestDeviceDescriptor(); sl@0: sl@0: TestDeviceQualifierDescriptor(); sl@0: sl@0: TestConfigurationDescriptor(); sl@0: sl@0: TestOtherSpeedConfigurationDescriptor(); sl@0: sl@0: TestInterfaceDescriptor(); sl@0: sl@0: TestClassSpecificDescriptors(); sl@0: sl@0: TestAlternateInterfaceManipulation(); sl@0: sl@0: TestEndpointDescriptor(); sl@0: sl@0: TestExtendedEndpointDescriptor(); sl@0: sl@0: TestStandardStringDescriptors(); sl@0: sl@0: TestArbitraryStringDescriptors(); sl@0: sl@0: test.End(); sl@0: } sl@0: sl@0: sl@0: //--------------------------------------------- sl@0: //! @SYMTestCaseID KBASE-T_USBAPI-0040 sl@0: //! @SYMTestType UT sl@0: //! @SYMTestCaseDesc Test OTG extensions sl@0: //! @SYMTestExpectedResults All APIs behave as expected sl@0: //! @SYMTestPriority Medium sl@0: //! @SYMTestStatus Implemented sl@0: //--------------------------------------------- sl@0: static void TestOtgExtensions() sl@0: { sl@0: test.Start(_L("Test Some OTG API Extensions")); sl@0: sl@0: // Test OTG descriptor manipulation sl@0: test.Next(_L("Get OTG Descriptor Size")); sl@0: TInt size; sl@0: gPort.GetOtgDescriptorSize(size); sl@0: test(static_cast(size) == KUsbDescSize_Otg); sl@0: sl@0: test.Next(_L("Get OTG Descriptor")); sl@0: TBuf8 otgDesc; sl@0: TInt r = gPort.GetOtgDescriptor(otgDesc); sl@0: test(r == KErrNotSupported || r == KErrNone); sl@0: sl@0: test.Next(_L("Set OTG Descriptor")); sl@0: if (r == KErrNotSupported) sl@0: { sl@0: r = gPort.SetOtgDescriptor(otgDesc); sl@0: test(r == KErrNotSupported); sl@0: } sl@0: else sl@0: { sl@0: otgDesc[0] = KUsbDescSize_Otg; sl@0: otgDesc[1] = KUsbDescType_Otg; sl@0: // The next step is likely to reset KUsbOtgAttr_HnpSupp sl@0: otgDesc[2] = KUsbOtgAttr_SrpSupp; sl@0: r = gPort.SetOtgDescriptor(otgDesc); sl@0: test(r == KErrNone); sl@0: TBuf8 desc; sl@0: r = gPort.GetOtgDescriptor(desc); sl@0: test(r == KErrNone); sl@0: test(desc.Compare(otgDesc) == 0); sl@0: } sl@0: sl@0: // Test get OTG features sl@0: test.Next(_L("Get OTG Features")); sl@0: TUint8 features; sl@0: r = gPort.GetOtgFeatures(features); sl@0: if (gSupportsOtg) sl@0: { sl@0: test(r == KErrNone); sl@0: TBool b_HnpEnable = (features & KUsbOtgAttr_B_HnpEnable) ? ETrue : EFalse; sl@0: TBool a_HnpSupport = (features & KUsbOtgAttr_A_HnpSupport) ? ETrue : EFalse; sl@0: TBool a_AltHnpSupport = (features & KUsbOtgAttr_A_AltHnpSupport) ? ETrue : EFalse; sl@0: test.Printf(_L("### OTG Features:\nB_HnpEnable(%d)\nA_HnpSupport(%d)\nA_Alt_HnpSupport(%d)\n"), sl@0: b_HnpEnable, a_HnpSupport, a_AltHnpSupport); sl@0: } sl@0: else sl@0: { sl@0: test(r == KErrNotSupported); sl@0: test.Printf(_L("GetOtgFeatures() not supported\n")); sl@0: } sl@0: sl@0: test.End(); sl@0: } sl@0: sl@0: sl@0: static void TestEndpoint0MaxPacketSizes() sl@0: { sl@0: test.Start(_L("Test Endpoint0 MaxPacketSizes")); sl@0: sl@0: TUint32 sizes = gPort.EndpointZeroMaxPacketSizes(); sl@0: TInt r = KErrNone; sl@0: TBool good; sl@0: TInt mpsize = 0; sl@0: for (TInt i = 0; i < 32; i++) sl@0: { sl@0: TUint bit = sizes & (1 << i); sl@0: if (bit != 0) sl@0: { sl@0: switch (bit) sl@0: { sl@0: case KUsbEpSizeCont: sl@0: good = EFalse; sl@0: break; sl@0: case KUsbEpSize8: sl@0: mpsize = 8; sl@0: good = ETrue; sl@0: break; sl@0: case KUsbEpSize16: sl@0: mpsize = 16; sl@0: good = ETrue; sl@0: break; sl@0: case KUsbEpSize32: sl@0: mpsize = 32; sl@0: good = ETrue; sl@0: break; sl@0: case KUsbEpSize64: sl@0: mpsize = 64; sl@0: good = ETrue; sl@0: break; sl@0: case KUsbEpSize128: sl@0: case KUsbEpSize256: sl@0: case KUsbEpSize512: sl@0: case KUsbEpSize1023: sl@0: default: sl@0: good = EFalse; sl@0: break; sl@0: } sl@0: if (good) sl@0: { sl@0: test.Printf(_L("Ep0 supports %d bytes MaxPacketSize\n"), mpsize); sl@0: } sl@0: else sl@0: { sl@0: test.Printf(_L("Bad Ep0 size: 0x%08x, failure will occur\n"), bit); sl@0: r = KErrGeneral; sl@0: } sl@0: } sl@0: } sl@0: test(r == KErrNone); sl@0: sl@0: test.End(); sl@0: } sl@0: sl@0: sl@0: static void TestDeviceControl() sl@0: { sl@0: test.Start(_L("Test Device Control")); sl@0: sl@0: // This is a quick and crude test, to make sure that we don't get a steaming heap sl@0: // as a result of calling the device control API's. sl@0: test.Next(_L("SetDeviceControl()")); sl@0: TInt r = gPort.SetDeviceControl(); sl@0: test(r == KErrNone); sl@0: test.Next(_L("ReleaseDeviceControl()")); sl@0: r = gPort.ReleaseDeviceControl(); sl@0: test(r == KErrNone); sl@0: sl@0: test.End(); sl@0: } sl@0: sl@0: sl@0: static void TestAlternateDeviceStatusNotify() sl@0: { sl@0: test.Start(_L("Test Alternate Device Status Notification")); sl@0: sl@0: TRequestStatus dev_status; sl@0: TUint deviceState = 0xffffffff; // put in a nonsense value sl@0: test.Next(_L("AlternateDeviceStatusNotify()")); sl@0: gPort.AlternateDeviceStatusNotify(dev_status, deviceState); sl@0: test.Next(_L("AlternateDeviceStatusNotifyCancel()")); sl@0: gPort.AlternateDeviceStatusNotifyCancel(); sl@0: User::WaitForRequest(dev_status); sl@0: test(dev_status == KErrCancel || dev_status == KErrNone); sl@0: if (deviceState & KUsbAlternateSetting) sl@0: { sl@0: TUint setting = (deviceState & ~KUsbAlternateSetting); sl@0: test.Printf(_L("Alternate setting change to setting %d - unexpected"), setting); sl@0: test(EFalse); sl@0: } sl@0: else sl@0: { sl@0: switch (deviceState) sl@0: { sl@0: case EUsbcDeviceStateUndefined: sl@0: test.Printf(_L("TestAlternateDeviceStatusNotify: Undefined state\n")); sl@0: break; sl@0: case EUsbcDeviceStateAttached: sl@0: test.Printf(_L("TestAlternateDeviceStatusNotify: Attached state\n")); sl@0: break; sl@0: case EUsbcDeviceStatePowered: sl@0: test.Printf(_L("TestAlternateDeviceStatusNotify: Powered state\n")); sl@0: break; sl@0: case EUsbcDeviceStateDefault: sl@0: test.Printf(_L("TestAlternateDeviceStatusNotify: Default state\n")); sl@0: break; sl@0: case EUsbcDeviceStateAddress: sl@0: test.Printf(_L("TestAlternateDeviceStatusNotify: Address state\n")); sl@0: break; sl@0: case EUsbcDeviceStateConfigured: sl@0: test.Printf(_L("TestAlternateDeviceStatusNotify: Configured state\n")); sl@0: break; sl@0: case EUsbcDeviceStateSuspended: sl@0: test.Printf(_L("TestAlternateDeviceStatusNotify: Suspended state\n")); sl@0: break; sl@0: case EUsbcNoState: sl@0: test.Printf(_L("TestAlternateDeviceStatusNotify: State buffering error\n")); sl@0: test(EFalse); sl@0: break; sl@0: default: sl@0: test.Printf(_L("TestAlternateDeviceStatusNotify: Unknown state\n")); sl@0: test(EFalse); sl@0: } sl@0: } sl@0: sl@0: test.End(); sl@0: } sl@0: sl@0: sl@0: static void TestEndpointStatusNotify() sl@0: { sl@0: test.Start(_L("Test Endpoint Status Notification")); sl@0: sl@0: TRequestStatus ep_status; sl@0: TUint epStateBitmap = 0xffffffff; // put in a nonsense value sl@0: test.Next(_L("EndpointStatusNotify()")); sl@0: gPort.EndpointStatusNotify(ep_status, epStateBitmap); sl@0: test.Next(_L("EndpointStatusNotifyCancel()")); sl@0: gPort.EndpointStatusNotifyCancel(); sl@0: User::WaitForRequest(ep_status); sl@0: test(ep_status.Int() == KErrCancel); sl@0: test.Next(_L("Check endpoint state bitmap returned")); sl@0: // Our ifc only uses 2 eps + ep0 is automatically granted: sl@0: const TUint usedEpBitmap = (1 << EEndpoint0 | 1 << EEndpoint1 | 1 << EEndpoint2); sl@0: // Must not return info about non existent Eps: sl@0: test((epStateBitmap & ~usedEpBitmap) == 0); sl@0: for (TInt i = 0; i <= 2; i++) sl@0: { sl@0: if ((epStateBitmap & (1 << i)) == EEndpointStateNotStalled) sl@0: { sl@0: test.Printf(_L("EndpointStatusNotify: Ep %d NOT STALLED\n"), i); sl@0: } sl@0: else sl@0: { sl@0: test.Printf(_L("EndpointStatusNotify: Ep %d STALLED\n"), i); sl@0: } sl@0: } sl@0: sl@0: test.End(); sl@0: } sl@0: sl@0: sl@0: static void TestEndpointStallStatus() sl@0: { sl@0: test.Start(_L("Test Endpoint Stall Status")); sl@0: sl@0: if (!SupportsEndpointStall()) sl@0: { sl@0: test.Printf(_L("*** Not supported - skipping endpoint stall status tests\n")); sl@0: test.End(); sl@0: return; sl@0: } sl@0: sl@0: test.Next(_L("Endpoint stall status")); sl@0: TEndpointState epState = EEndpointStateUnknown; sl@0: QueryEndpointState(EEndpoint1); sl@0: QueryEndpointState(EEndpoint2); sl@0: sl@0: test.Next(_L("Stall Ep1")); sl@0: gPort.HaltEndpoint(EEndpoint1); sl@0: epState = QueryEndpointState(EEndpoint1); sl@0: test(epState == EEndpointStateStalled); sl@0: sl@0: test.Next(_L("Clear Stall Ep1")); sl@0: gPort.ClearHaltEndpoint(EEndpoint1); sl@0: epState = QueryEndpointState(EEndpoint1); sl@0: test(epState == EEndpointStateNotStalled); sl@0: sl@0: test.Next(_L("Stall Ep2")); sl@0: gPort.HaltEndpoint(EEndpoint2); sl@0: epState = QueryEndpointState(EEndpoint2); sl@0: test(epState == EEndpointStateStalled); sl@0: sl@0: test.Next(_L("Clear Stall Ep2")); sl@0: gPort.ClearHaltEndpoint(EEndpoint2); sl@0: epState = QueryEndpointState(EEndpoint2); sl@0: test(epState == EEndpointStateNotStalled); sl@0: sl@0: test.End(); sl@0: } sl@0: sl@0: sl@0: static void CloseChannel() sl@0: { sl@0: test.Start(_L("Close Channel")); sl@0: sl@0: test.Next(_L("Disconnect Device from Host")); sl@0: TInt r = gPort.DeviceDisconnectFromHost(); sl@0: test(r != KErrGeneral); sl@0: sl@0: if (gSupportsOtg) sl@0: { sl@0: test.Next(_L("Stop OTG stack")); sl@0: gOTG.StopStacks(); sl@0: test.Next(_L("Close OTG Channel")); sl@0: gOTG.Close(); sl@0: test.Next(_L("Free OTG LDD")); sl@0: r = User::FreeLogicalDevice(RUsbOtgDriver::Name()); sl@0: test(r == KErrNone); sl@0: } sl@0: sl@0: test.Next(_L("Close USB Channel")); sl@0: gPort.Close(); sl@0: test.Next(_L("Free USB LDD")); sl@0: r = User::FreeLogicalDevice(KUsbDeviceName); sl@0: test(r == KErrNone); sl@0: sl@0: test.End(); sl@0: } sl@0: sl@0: sl@0: static const TInt KPrologue = 0; sl@0: static const TInt KMain = 1; sl@0: static const TInt KEpilogue = 2; sl@0: sl@0: static TInt RunTests(void* /*aArg*/) sl@0: { sl@0: static TInt step = KPrologue; sl@0: static TReal loops = 0; sl@0: sl@0: switch (step) sl@0: { sl@0: case KPrologue: sl@0: test.Title(); sl@0: // outermost test begin sl@0: test.Start(_L("Test of USB APIs not requiring a host connection\n")); sl@0: if (SupportsUsb()) sl@0: { sl@0: step = KMain; sl@0: } sl@0: else sl@0: { sl@0: step = KEpilogue; sl@0: test.Printf(_L("*** Test platform does not support USB - skipping all tests\n")); sl@0: } sl@0: return ETrue; sl@0: case KMain: sl@0: OpenChannel(); sl@0: SetupInterface(); sl@0: TestDescriptorManipulation(); sl@0: TestOtgExtensions(); sl@0: TestEndpoint0MaxPacketSizes(); sl@0: TestDeviceControl(); sl@0: TestAlternateDeviceStatusNotify(); sl@0: TestEndpointStatusNotify(); sl@0: TestEndpointStallStatus(); sl@0: CloseChannel(); sl@0: loops++; sl@0: if (gSoak && (gKeychar != EKeyEscape)) sl@0: { sl@0: step = KMain; sl@0: } sl@0: else sl@0: { sl@0: step = KEpilogue; sl@0: } sl@0: return ETrue; sl@0: case KEpilogue: sl@0: test.Printf(_L("USBAPI tests were run %.0f time(s)\n"), loops); sl@0: // outermost test end sl@0: test.End(); sl@0: CActiveScheduler::Stop(); sl@0: return EFalse; sl@0: } sl@0: return EFalse; sl@0: } sl@0: sl@0: sl@0: static void RunAppL() sl@0: { sl@0: // Create the active scheduler sl@0: CActiveScheduler* scheduler = new (ELeave) CActiveScheduler(); sl@0: // Push active scheduler onto the cleanup stack sl@0: CleanupStack::PushL(scheduler); sl@0: // Install as the active scheduler sl@0: CActiveScheduler::Install(scheduler); sl@0: sl@0: // Create console handler sl@0: CConsoleBase* console = sl@0: Console::NewL(_L("T_USBAPI - USB Client Test Program"), TSize(KConsFullScreen, KConsFullScreen)); sl@0: CleanupStack::PushL(console); sl@0: // Make this one also RTest's console sl@0: test.SetConsole(console); sl@0: sl@0: // Create keypress notifier active object sl@0: CActiveKeypressNotifier* keypress_notifier = CActiveKeypressNotifier::NewL(console); sl@0: test(keypress_notifier != NULL); sl@0: CleanupStack::PushL(keypress_notifier); sl@0: keypress_notifier->RequestCharacter(); sl@0: sl@0: // Create long-running test task active object sl@0: CIdle* active_test = CIdle::NewL(CActive::EPriorityIdle); sl@0: test(active_test != NULL); sl@0: CleanupStack::PushL(active_test); sl@0: active_test->Start(TCallBack(RunTests)); sl@0: sl@0: // Start active scheduler sl@0: CActiveScheduler::Start(); sl@0: sl@0: // Suspend thread for a short while sl@0: User::After(1000000); sl@0: sl@0: // active_test, keypress_notifier, console, scheduler sl@0: CleanupStack::PopAndDestroy(4); sl@0: sl@0: return; sl@0: } sl@0: sl@0: sl@0: GLDEF_C TInt E32Main() sl@0: { sl@0: sl@0: CTrapCleanup* cleanup = CTrapCleanup::New(); // get clean-up stack sl@0: sl@0: __UHEAP_MARK; sl@0: sl@0: _LIT(KArg, "soak"); sl@0: TBuf<64> c; sl@0: User::CommandLine(c); sl@0: if (c.CompareF(KArg) == 0) sl@0: gSoak = ETrue; sl@0: else sl@0: gSoak = EFalse; sl@0: TRAPD(r, RunAppL()); sl@0: __ASSERT_ALWAYS(!r, User::Panic(_L("E32EX"), r)); sl@0: sl@0: __UHEAP_MARKEND; sl@0: sl@0: delete cleanup; // destroy clean-up stack sl@0: return KErrNone; sl@0: }