# HG changeset patch # User Shabe Razvi # Date 1272993792 -3600 # Node ID ea2434cf367096cd7ee07ef72ff54e1f9978066e # Parent 466a0df5c15a9462873b7c3eb0a976d8c478309b# Parent 8811011454cf0fed3cedc923314c84a263861c51 Merge diff -r 466a0df5c15a -r ea2434cf3670 kernel/eka/bld.inf --- a/kernel/eka/bld.inf Tue May 04 16:57:20 2010 +0100 +++ b/kernel/eka/bld.inf Tue May 04 18:23:12 2010 +0100 @@ -386,20 +386,20 @@ include/e32utrace.mmh SYMBIAN_OS_LAYER_PUBLIC_EXPORT_PATH(e32utrace.mmh) //Open System Trace API -include/opensystemtrace.h /epoc32/include/platform/ -include/opensystemtrace.inl /epoc32/include/platform/ -include/opensystemtrace_types.h /epoc32/include/platform/ -include/opensystemtrace.mmh /epoc32/include/platform/ +include/opensystemtrace.h SYMBIAN_OS_LAYER_PLATFORM_EXPORT_PATH(opensystemtrace.h) +include/opensystemtrace.inl SYMBIAN_OS_LAYER_PLATFORM_EXPORT_PATH(opensystemtrace.inl) +include/opensystemtrace_types.h SYMBIAN_OS_LAYER_PLATFORM_EXPORT_PATH(opensystemtrace_types.h) +include/opensystemtrace.mmh SYMBIAN_OS_LAYER_PLATFORM_EXPORT_PATH(opensystemtrace.mmh) // ROM building scripts -rombuild/base.iby /epoc32/rom/include/ // -rombuild/PlatSecEnforcement.oby /epoc32/rom/include/ // -rombuild/PlatSecDiagnostics.oby /epoc32/rom/include/ // -rombuild/btrace.iby /epoc32/rom/include/ // +rombuild/base.iby /epoc32/rom/include/ +rombuild/PlatSecEnforcement.oby /epoc32/rom/include/ +rombuild/PlatSecDiagnostics.oby /epoc32/rom/include/ +rombuild/btrace.iby /epoc32/rom/include/ rombuild/kernel.hby /epoc32/rom/include/ rombuild/rm_debug_svr.iby /epoc32/rom/include/ // Run mode debug driver -rombuild/utrace.iby /epoc32/rom/include/ //utrace -rombuild/ost.iby /epoc32/rom/include/ //ost +rombuild/utrace.iby /epoc32/rom/include/ +rombuild/ost.iby /epoc32/rom/include/ // Byte pair compressor include/byte_pair_compress.h SYMBIAN_OS_LAYER_PLATFORM_EXPORT_PATH(byte_pair_compress.h) diff -r 466a0df5c15a -r ea2434cf3670 kernel/eka/bmarm/ekernsmp.def --- a/kernel/eka/bmarm/ekernsmp.def Tue May 04 16:57:20 2010 +0100 +++ b/kernel/eka/bmarm/ekernsmp.def Tue May 04 18:23:12 2010 +0100 @@ -1053,4 +1053,5 @@ Stats__13KernCoreStatsPv @ 1052 NONAME R3UNUSED ; KernCoreStats::Stats(void *) SetNumberOfActiveCpus__5NKerni @ 1053 NONAME SetIdleHandler__3ArmPFPvUlPVv_vPv @ 1054 NONAME R3UNUSED ; Arm::SetIdleHandler(void (*)(void *, unsigned long, void volatile *), void *) + FreeRamZone__4EpocUi @ 1055 NONAME R3UNUSED ; Epoc::FreeRamZone(unsigned int) diff -r 466a0df5c15a -r ea2434cf3670 kernel/eka/bmarm/ekernu.def --- a/kernel/eka/bmarm/ekernu.def Tue May 04 16:57:20 2010 +0100 +++ b/kernel/eka/bmarm/ekernu.def Tue May 04 18:23:12 2010 +0100 @@ -1050,3 +1050,4 @@ Retire__13KernCoreStatsii @ 1049 NONAME R3UNUSED ; KernCoreStats::Retire(int, int) Stats__13KernCoreStatsPv @ 1050 NONAME R3UNUSED ; KernCoreStats::Stats(void *) SetIdleHandler__3ArmPFPvUl_vPv @ 1051 NONAME R3UNUSED ; Arm::SetIdleHandler(void (*)(void *, unsigned long), void *) + FreeRamZone__4EpocUi @ 1052 NONAME R3UNUSED ; Epoc::FreeRamZone(unsigned int) diff -r 466a0df5c15a -r ea2434cf3670 kernel/eka/bx86/ekernsmp.def --- a/kernel/eka/bx86/ekernsmp.def Tue May 04 16:57:20 2010 +0100 +++ b/kernel/eka/bx86/ekernsmp.def Tue May 04 18:23:12 2010 +0100 @@ -1010,4 +1010,5 @@ ?Retire@KernCoreStats@@SAHHH@Z @ 1009 NONAME ; public: static int KernCoreStats::Retire(int, int) ?Stats@KernCoreStats@@SAHPAX@Z @ 1010 NONAME ; public: static int KernCoreStats::Stats(void *) ?SetNumberOfActiveCpus@NKern@@SAXH@Z @ 1011 NONAME ; public: static void __cdecl NKern::SetNumberOfActiveCpus(int) + ?FreeRamZone@Epoc@@SAHI@Z @ 1012 NONAME ; public: static int Epoc::FreeRamZone(unsigned int) diff -r 466a0df5c15a -r ea2434cf3670 kernel/eka/bx86/ekernu.def --- a/kernel/eka/bx86/ekernu.def Tue May 04 16:57:20 2010 +0100 +++ b/kernel/eka/bx86/ekernu.def Tue May 04 18:23:12 2010 +0100 @@ -955,4 +955,5 @@ ?LeaveIdle@KernCoreStats@@SAXI@Z @ 954 NONAME ; public: static void KernCoreStats::LeaveIdle(unsigned int) ?Retire@KernCoreStats@@SAHHH@Z @ 955 NONAME ; public: static int KernCoreStats::Retire(int, int) ?Stats@KernCoreStats@@SAHPAX@Z @ 956 NONAME ; public: static int KernCoreStats::Stats(void *) + ?FreeRamZone@Epoc@@SAHI@Z @ 957 NONAME ; public: static int Epoc::FreeRamZone(unsigned int) diff -r 466a0df5c15a -r ea2434cf3670 kernel/eka/bx86gcc/ekernsmp.def --- a/kernel/eka/bx86gcc/ekernsmp.def Tue May 04 16:57:20 2010 +0100 +++ b/kernel/eka/bx86gcc/ekernsmp.def Tue May 04 18:23:12 2010 +0100 @@ -1098,4 +1098,5 @@ _ZN13KernCoreStats6RetireEii @ 1097 NONAME _ZN13KernCoreStats9ConfigureEj @ 1098 NONAME _ZN5NKern21SetNumberOfActiveCpusEi @ 1099 NONAME + _ZN4Epoc11FreeRamZoneEj @ 1100 NONAME diff -r 466a0df5c15a -r ea2434cf3670 kernel/eka/bx86gcc/ekernu.def --- a/kernel/eka/bx86gcc/ekernu.def Tue May 04 16:57:20 2010 +0100 +++ b/kernel/eka/bx86gcc/ekernu.def Tue May 04 18:23:12 2010 +0100 @@ -1038,4 +1038,5 @@ _ZN13KernCoreStats9ConfigureEj @ 1037 NONAME _ZN13KernCoreStats9EnterIdleEv @ 1038 NONAME _ZN13KernCoreStats9LeaveIdleEj @ 1039 NONAME + _ZN4Epoc11FreeRamZoneEj @ 1040 NONAME diff -r 466a0df5c15a -r ea2434cf3670 kernel/eka/debug/crashMonitor/inc/scmdatasave.h --- a/kernel/eka/debug/crashMonitor/inc/scmdatasave.h Tue May 04 16:57:20 2010 +0100 +++ b/kernel/eka/debug/crashMonitor/inc/scmdatasave.h Tue May 04 18:23:12 2010 +0100 @@ -43,6 +43,7 @@ _LIT8(KKernelHeapChunkName, "ekern.exe::SvHeap"); +_LIT8(KKernelProcessName, "ekern.exe"); /** diff -r 466a0df5c15a -r ea2434cf3670 kernel/eka/debug/crashMonitor/src/scmdatasave.cpp --- a/kernel/eka/debug/crashMonitor/src/scmdatasave.cpp Tue May 04 16:57:20 2010 +0100 +++ b/kernel/eka/debug/crashMonitor/src/scmdatasave.cpp Tue May 04 18:23:12 2010 +0100 @@ -978,11 +978,11 @@ { LOG_CONTEXT - //Get Chunk object container - DObjectCon* objectContainer = Kern::Containers()[EChunk]; + //Get process object container + DObjectCon* objectContainer = Kern::Containers()[EProcess]; if(objectContainer == NULL) { - CLTRACE("\tFailed to get object container for the chunks"); + CLTRACE("\tFailed to get object container for the processes"); return KErrNotFound; } @@ -995,7 +995,39 @@ TInt numObjects = objectContainer->Count(); - for(TInt cnt = 0; cnt< numObjects; cnt ++) + DProcess* kernelProcess = NULL; + for(TInt cnt = 0; cnt < numObjects; cnt ++) + { + DProcess* candidateProcess = (DProcess*)(*objectContainer)[cnt]; + + //Get the objects name + TBuf8 name; + candidateProcess->TraceAppendFullName(name,EFalse); + if(name == KKernelProcessName) + { + kernelProcess = candidateProcess; + } + } + if (!kernelProcess) + return KErrNotFound; + + //Get chunk object container + objectContainer = Kern::Containers()[EChunk]; + if(objectContainer == NULL) + { + CLTRACE("\tFailed to get object container for the chunks"); + return KErrNotFound; + } + + //Must check the mutex on this is ok otherwise the data will be in an inconsistent state + if(objectContainer->Lock()->iHoldCount) + { + CLTRACE("\tChunk Container is in an inconsistant state"); + return KErrCorrupt; + } + + numObjects = objectContainer->Count(); + for(TInt cnt = 0; cnt < numObjects; cnt ++) { DChunk* candidateHeapChunk = (DChunk*)(*objectContainer)[cnt]; @@ -1005,14 +1037,8 @@ if(name == KKernelHeapChunkName) { - #ifndef __MEMMODEL_FLEXIBLE__ - aHeapLocation = (TInt32)candidateHeapChunk->iBase; - #else - aHeapLocation = (TInt32)candidateHeapChunk->iFixedBase; - #endif - - aHeapSize = candidateHeapChunk->iSize; - + aHeapLocation = (TInt32)candidateHeapChunk->Base(kernelProcess); + aHeapSize = candidateHeapChunk->iSize; return KErrNone; } } diff -r 466a0df5c15a -r ea2434cf3670 kernel/eka/debug/securityServer/group/rm_debug_svr.mmp --- a/kernel/eka/debug/securityServer/group/rm_debug_svr.mmp Tue May 04 16:57:20 2010 +0100 +++ b/kernel/eka/debug/securityServer/group/rm_debug_svr.mmp Tue May 04 18:23:12 2010 +0100 @@ -46,3 +46,5 @@ //TCB is added for the RLocalDrive methods. CAPABILITY AllFiles TCB + +SMPSAFE diff -r 466a0df5c15a -r ea2434cf3670 kernel/eka/drivers/debug/group/rm_debug_kerneldriver.mmh --- a/kernel/eka/drivers/debug/group/rm_debug_kerneldriver.mmh Tue May 04 16:57:20 2010 +0100 +++ b/kernel/eka/drivers/debug/group/rm_debug_kerneldriver.mmh Tue May 04 18:23:12 2010 +0100 @@ -51,3 +51,5 @@ EPOCALLOWDLLDATA capability all + +SMPSAFE diff -r 466a0df5c15a -r ea2434cf3670 kernel/eka/drivers/pbus/mmc/sdcard/sdcard3c/sdcard.cpp --- a/kernel/eka/drivers/pbus/mmc/sdcard/sdcard3c/sdcard.cpp Tue May 04 16:57:20 2010 +0100 +++ b/kernel/eka/drivers/pbus/mmc/sdcard/sdcard3c/sdcard.cpp Tue May 04 18:23:12 2010 +0100 @@ -481,6 +481,12 @@ // Before issueing commands, see if there's actually a card present if (!CardDetect(iCxCardCount)) SMF_GOTOS(EStMoreCardsCheck) + + // Card Previously Marked as Corrupt do not re-initialise + if ((CardArray().CardP(iCxCardCount)->iFlags)& KSDCardIsCorrupt) + { + SMF_GOTOS(EStMoreCardsCheck) + } m.SetTraps(KMMCErrResponseTimeOut); SMF_INVOKES(InitialiseMemoryCardSMST, EStSendCIDIssued) @@ -814,6 +820,7 @@ { __KTRACE_OPT2(KPBUS1, KPANIC, Kern::Printf("-sd:ocr busy timed out")); OstTraceFunctionExitExt( DSDSTACK_INITIALISEMEMORYCARDSM_EXIT2, this, (TInt) KMMCErrBusTimeOut ); + (CardArray().CardP(iCxCardCount)->iFlags)|=KSDCardIsCorrupt; return KMMCErrBusTimeOut; } diff -r 466a0df5c15a -r ea2434cf3670 kernel/eka/drivers/power/smppower/idlehelper.cia --- a/kernel/eka/drivers/power/smppower/idlehelper.cia Tue May 04 16:57:20 2010 +0100 +++ b/kernel/eka/drivers/power/smppower/idlehelper.cia Tue May 04 18:23:12 2010 +0100 @@ -1,23 +1,19 @@ -/* -* Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies). -* All rights reserved. -* This component and the accompanying materials are made available -* under the terms of "Eclipse Public License v1.0" -* which accompanies this distribution, and is available -* at the URL "http://www.eclipse.org/legal/epl-v10.html". -* -* Initial Contributors: -* Nokia Corporation - initial contribution. -* -* Contributors: -* -* Description: -* os\kernelhwsrv\kernel\eka\drivers\power\smpidlehelper.cpp -* Impelentation of helper classes required to implement CPU idle -* functionality in a SMP BSP. -* -*/ - +// Copyright (c) 2008-2010 Nokia Corporation and/or its subsidiary(-ies). +// All rights reserved. +// This component and the accompanying materials are made available +// under the terms of the License "Eclipse Public License v1.0" +// which accompanies this distribution, and is available +// at the URL " http://www.eclipse.org/legal/epl-v10.html ". +// +// Initial Contributors: +// Nokia Corporation - initial contribution. +// +// Contributors: +// +// Description: +// os\kernelhwsrv\kernel\eka\drivers\power\smpidlehelper.cpp +// Impelentation of helper classes required to implement CPU idle +// functionality in a SMP BSP. /** @file diff -r 466a0df5c15a -r ea2434cf3670 kernel/eka/drivers/power/smppower/idlehelper.cpp --- a/kernel/eka/drivers/power/smppower/idlehelper.cpp Tue May 04 16:57:20 2010 +0100 +++ b/kernel/eka/drivers/power/smppower/idlehelper.cpp Tue May 04 18:23:12 2010 +0100 @@ -1,23 +1,19 @@ -/* -* Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies). -* All rights reserved. -* This component and the accompanying materials are made available -* under the terms of "Eclipse Public License v1.0" -* which accompanies this distribution, and is available -* at the URL "http://www.eclipse.org/legal/epl-v10.html". -* -* Initial Contributors: -* Nokia Corporation - initial contribution. -* -* Contributors: -* -* Description: -* os\kernelhwsrv\kernel\eka\drivers\power\smppower\idlehelper.cpp -* Impelentation of helper classes required to implement CPU idle -* functionality in a SMP BSP. -* -*/ - +// Copyright (c) 2008-2010 Nokia Corporation and/or its subsidiary(-ies). +// All rights reserved. +// This component and the accompanying materials are made available +// under the terms of the License "Eclipse Public License v1.0" +// which accompanies this distribution, and is available +// at the URL " http://www.eclipse.org/legal/epl-v10.html ". +// +// Initial Contributors: +// Nokia Corporation - initial contribution. +// +// Contributors: +// +// Description: +// os\kernelhwsrv\kernel\eka\drivers\power\smppower\idlehelper.cpp +// Impelentation of helper classes required to implement CPU idle +// functionality in a SMP BSP. /** @file diff -r 466a0df5c15a -r ea2434cf3670 kernel/eka/drivers/power/smppower/idlehelper_lib.mmp --- a/kernel/eka/drivers/power/smppower/idlehelper_lib.mmp Tue May 04 16:57:20 2010 +0100 +++ b/kernel/eka/drivers/power/smppower/idlehelper_lib.mmp Tue May 04 18:23:12 2010 +0100 @@ -1,9 +1,9 @@ -// Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies). +// Copyright (c) 2007-2010 Nokia Corporation and/or its subsidiary(-ies). // All rights reserved. // This component and the accompanying materials are made available -// under the terms of "Eclipse Public License v1.0" +// under the terms of the License "Eclipse Public License v1.0" // which accompanies this distribution, and is available -// at the URL "http://www.eclipse.org/legal/epl-v10.html". +// at the URL " http://www.eclipse.org/legal/epl-v10.html ". // // Initial Contributors: // Nokia Corporation - initial contribution. @@ -14,7 +14,6 @@ // e32\drivers\power\smppower\smpidlehelper_lib.mmp // Helper library required to implement CPU idle // functionality in a SMP BSP. -// #define NO_EKERN_LIB diff -r 466a0df5c15a -r ea2434cf3670 kernel/eka/drivers/power/smppower/sample_idlehandler/smpidlehandler.cpp --- a/kernel/eka/drivers/power/smppower/sample_idlehandler/smpidlehandler.cpp Tue May 04 16:57:20 2010 +0100 +++ b/kernel/eka/drivers/power/smppower/sample_idlehandler/smpidlehandler.cpp Tue May 04 18:23:12 2010 +0100 @@ -1,23 +1,19 @@ -/* -* Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies). -* All rights reserved. -* This component and the accompanying materials are made available -* under the terms of "Eclipse Public License v1.0" -* which accompanies this distribution, and is available -* at the URL "http://www.eclipse.org/legal/epl-v10.html". -* -* Initial Contributors: -* Nokia Corporation - initial contribution. -* -* Contributors: -* -* Description: -* os\kernelhwsrv\kernel\eka\drivers\power\smppower\sample_idlehandler\smpidlehandler.cpp -* implements a basic smp idle handler generic layer that can be derived from -* to create platform specific SMP idle handlers -* -*/ - +// Copyright (c) 2008-2010 Nokia Corporation and/or its subsidiary(-ies). +// All rights reserved. +// This component and the accompanying materials are made available +// under the terms of the License "Eclipse Public License v1.0" +// which accompanies this distribution, and is available +// at the URL " http://www.eclipse.org/legal/epl-v10.html ". +// +// Initial Contributors: +// Nokia Corporation - initial contribution. +// +// Contributors: +// +// Description: +// os\kernelhwsrv\kernel\eka\drivers\power\smppower\sample_idlehandler\smpidlehandler.cpp +// implements a basic smp idle handler generic layer that can be derived from +// to create platform specific SMP idle handlers /** @file diff -r 466a0df5c15a -r ea2434cf3670 kernel/eka/drivers/power/smppower/sample_idlehandler/smpidlehandler_lib.mmp --- a/kernel/eka/drivers/power/smppower/sample_idlehandler/smpidlehandler_lib.mmp Tue May 04 16:57:20 2010 +0100 +++ b/kernel/eka/drivers/power/smppower/sample_idlehandler/smpidlehandler_lib.mmp Tue May 04 18:23:12 2010 +0100 @@ -1,9 +1,9 @@ // Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies). // All rights reserved. // This component and the accompanying materials are made available -// under the terms of "Eclipse Public License v1.0" +// under the terms of the License "Eclipse Public License v1.0" // which accompanies this distribution, and is available -// at the URL "http://www.eclipse.org/legal/epl-v10.html". +// at the URL " http://www.eclipse.org/legal/epl-v10.html ". // // Initial Contributors: // Nokia Corporation - initial contribution. @@ -14,7 +14,6 @@ // eka\drivers\power\smppower\sample_idlehandler\smpidlehandler_lib.mmp // Helper library required to implement CPU idle // functionality in a SMP BSP. -// #define NO_EKERN_LIB diff -r 466a0df5c15a -r ea2434cf3670 kernel/eka/drivers/usbc/usbdma.cpp --- a/kernel/eka/drivers/usbc/usbdma.cpp Tue May 04 16:57:20 2010 +0100 +++ b/kernel/eka/drivers/usbc/usbdma.cpp Tue May 04 18:23:12 2010 +0100 @@ -619,7 +619,14 @@ { if (iEndpointType == KUsbEpTypeBulk) { - isShortPacket = (size < iMaxPacketSize) || (size & maxPacketSizeMask); + if(iExtractOffset & maxPacketSizeMask) + { + isShortPacket = ((size+iExtractOffset) < iMaxPacketSize) || ((size+iExtractOffset) & maxPacketSizeMask); + } + else + { + isShortPacket = (size < iMaxPacketSize) || (size & maxPacketSizeMask); + } } else { @@ -830,17 +837,7 @@ if (iEndpointType == KUsbEpTypeBulk) { const TInt mask = iMaxPacketSize - 1; - if (iTotalRxBytesAvail & mask) - return ETrue; - // residue==0; this can be because - // zlps exist, or short packets combine to n * max_packet_size - // This means spadework - const TInt s = iCurrentPacketSizeArray[iCurrentPacket] - iExtractOffset; - if ((s == 0) || (s & mask)) - { - return ETrue; - } for (TInt i = 0; i < iNumberofBuffers; i++) { diff -r 466a0df5c15a -r ea2434cf3670 kernel/eka/drivers/usbho/usbdescriptors/base_drivers_usbdescriptors.mrp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kernel/eka/drivers/usbho/usbdescriptors/base_drivers_usbdescriptors.mrp Tue May 04 18:23:12 2010 +0100 @@ -0,0 +1,27 @@ +# +# Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +# All rights reserved. +# This component and the accompanying materials are made available +# under the terms of "Eclipse Public License v1.0" +# which accompanies this distribution, and is available +# at the URL "http://www.eclipse.org/legal/epl-v10.html". +# +# Initial Contributors: +# Nokia Corporation - initial contribution. +# +# Contributors: +# +# Description: +# +# component name "USB Descriptors" + +component base_drivers_usbdescriptors + +source \sf\os\kernelhwsrv\kernel\eka\drivers\usbho\usbdescriptors + +binary \sf\os\kernelhwsrv\kernel\eka\drivers\usbho\usbdescriptors all + +notes_source \component_defs\release.src + +ipr E + diff -r 466a0df5c15a -r ea2434cf3670 kernel/eka/drivers/usbho/usbdescriptors/bld.inf --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kernel/eka/drivers/usbho/usbdescriptors/bld.inf Tue May 04 18:23:12 2010 +0100 @@ -0,0 +1,46 @@ +// Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). +// All rights reserved. +// This component and the accompanying materials are made available +// under the terms of the License "Eclipse Public License v1.0" +// which accompanies this distribution, and is available +// at the URL "http://www.eclipse.org/legal/epl-v10.html". +// +// Initial Contributors: +// Nokia Corporation - initial contribution. +// +// Contributors: +// +// Description: +// e32/drivers/usbho/usbdescriptors/bld.inf +// +// + +/** + @file +*/ + + +PRJ_PLATFORMS + +ARMV5 ARMV5SMP + + +PRJ_MMPFILES + +#ifndef GCCXML +#if defined(GENERIC_MARM) || !defined(WINS) || defined(GENERIC_X86) +#if !defined(MARM_THUMB) && !defined(MARM_ARMI) + +#if !defined(WINS) +#if !defined(X86) +#if defined(SYMBIAN_ENABLE_USB_OTG_HOST) + +usbdescriptors + +#endif +#endif +#endif + +#endif +#endif +#endif diff -r 466a0df5c15a -r ea2434cf3670 kernel/eka/drivers/usbho/usbdescriptors/usbdescparser.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kernel/eka/drivers/usbho/usbdescriptors/usbdescparser.cpp Tue May 04 18:23:12 2010 +0100 @@ -0,0 +1,379 @@ +// Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies). +// All rights reserved. +// This component and the accompanying materials are made available +// under the terms of the License "Eclipse Public License v1.0" +// which accompanies this distribution, and is available +// at the URL "http://www.eclipse.org/legal/epl-v10.html". +// +// Initial Contributors: +// Nokia Corporation - initial contribution. +// +// Description: +// Symbian USBDI Descriptor Parsing Framework. +// +// + +/** + @file + @internalComponent +*/ + +#include +#include "usbdescutils.h" + + +// --------------------- +// UsbDescriptorParser +// --------------------- + +/** +The main parsing function of the USB descriptor parsing framework. + +This will perform a best effort parse of a USB descriptor tree. It is best effort in the +fact that upon encountering a form of syntatic corruption in the source data it will error +the parse attempt, but also return the incomplete descriptor tree up to the parsing error. + +@param aUsbDes The source data that will be parsed. +@param aDesc The pointer that will be updated to the top-level descriptor. + +@return KErrNone if successful, a system-wide error code otherwise. + +@publishedPartner +@prototype +*/ +EXPORT_C /*static*/ TInt UsbDescriptorParser::Parse(const TDesC8& aUsbDes, TUsbGenericDescriptor*& aDesc) + { + TInt ret = KErrNone; + aDesc = NULL; + TPtrC8 des(aUsbDes); + + // First we must find the top level descriptor (the one we will return to the caller). + TRAP(ret, aDesc = FindParserAndParseAndCheckL(des, NULL)); + if(ret == KErrNone) + { + if(!aDesc) + { + ret = KErrNotFound; + } + else + { + // Now we have a top level descriptor - we now try to build up the descriptor + // tree if there are more descriptors available. + TRAP(ret, ParseDescriptorTreeL(des, *aDesc)); + } + } + + // Ensure that all the data has been parsed if successful. + if(ret == KErrNone && des.Length() > 0) + { + // If no parser was found for some data then we should have been errored with KErrNotFound. + __ASSERT_DEBUG(EFalse, UsbDescFault(UsbdiFaults::EUsbDescSuccessButDataLeftUnparsed)); + ret = KErrUnknown; + } + + // release the allocated descriptor if there was an error + if(ret != KErrNone && aDesc) + { + delete aDesc; + aDesc = NULL; + } + + return ret; + } + +/** +The function to register a custom parsing routine in the USB descriptor parser framework. + +The routine is registered locally to the current thread, and so if an application wishes +to perform the same custom parsing in multiple threads, it must call this function with +the appropriate routine in each thread context. + +If the custom routine becomes unapplicable after being registered, the application may +unregister it using the UsbDescriptorParser::UnregisterCustomParser function. +@see UsbDescriptorParser::UnregisterCustomParser + +@param aParserFunc The routine which will be added to the USB descriptor parsing framework. + +@publishedPartner +@prototype +*/ +EXPORT_C /*static*/ void UsbDescriptorParser::RegisterCustomParserL(TUsbDescriptorParserL aParserFunc) + { + TBool newlyCreatedList = EFalse; + CUsbCustomDescriptorParserList* parserList = static_cast(Dll::Tls()); + if(!parserList) + { + parserList = CUsbCustomDescriptorParserList::NewL(); + newlyCreatedList = ETrue; + CleanupStack::PushL(parserList); + } + + parserList->RegisterParserL(aParserFunc); + + if(newlyCreatedList) + { + Dll::SetTls(parserList); + CleanupStack::Pop(parserList); + } + } + +/** +The function to unregister a custom parsing routine in the USB descriptor parser framework. + +This routine will only unregister the routine from the current thread context. If the routine +is registered in multiple threads and it is no longer wanted in any thread, an application +must call this function in each thread context that the routine is registered. + +It is safe to call this function even if RegisterCustomParserL has never been called successfully. + +@see UsbDescriptorParser::RegisterCustomParserL + +@param aParserFunc The routine which will be removed from the USB descriptor parsing framework. + +@publishedPartner +@prototype +*/ +EXPORT_C /*static*/ void UsbDescriptorParser::UnregisterCustomParser(TUsbDescriptorParserL aParserFunc) + { + CUsbCustomDescriptorParserList* parserList = static_cast(Dll::Tls()); + if(parserList) + { + parserList->UnregisterParser(aParserFunc); + if(parserList->NumOfRegisteredParsers() <= 0) + { + Dll::FreeTls(); + delete parserList; + } + } + } + +/*static*/ TUsbGenericDescriptor* UsbDescriptorParser::FindParserAndParseAndCheckL(TPtrC8& aUsbDes, TUsbGenericDescriptor* aPreviousDesc) + { + TUsbGenericDescriptor* ret = FindParserAndParseL(aUsbDes, aPreviousDesc); + // We need to ensure that the parsers have correctly initialised the USB descriptor objects. + // It is important that we check as it is possible that a custom parser did the parsing. + __ASSERT_ALWAYS(!ret || (!ret->iParent && !ret->iFirstChild && !ret->iNextPeer), + UsbDescPanic(UsbdiPanics::EUsbDescNonNullPointersAfterParsing)); + return ret; + } + +// Utility macro to tidy up the parsing routine. +#define RETURN_IF_PARSEDL(aRet, aParserL, aUsbDes, aPreviousDesc)\ + {\ + aRet = aParserL(aUsbDes, aPreviousDesc);\ + if(aRet)\ + {\ + return aRet;\ + }\ + } + +/*static*/ TUsbGenericDescriptor* UsbDescriptorParser::FindParserAndParseL(TPtrC8& aUsbDes, TUsbGenericDescriptor* aPreviousDesc) + { + // Special termination case. + if(aUsbDes.Length() == 0) + { + return NULL; + } + + TUsbGenericDescriptor* des; + + // Try the default parsing routines. + RETURN_IF_PARSEDL(des, TUsbDeviceDescriptor::ParseL, aUsbDes, aPreviousDesc); + RETURN_IF_PARSEDL(des, TUsbDeviceQualifierDescriptor::ParseL, aUsbDes, aPreviousDesc); + RETURN_IF_PARSEDL(des, TUsbConfigurationDescriptor::ParseL, aUsbDes, aPreviousDesc); + RETURN_IF_PARSEDL(des, TUsbOtherSpeedDescriptor::ParseL, aUsbDes, aPreviousDesc); + RETURN_IF_PARSEDL(des, TUsbInterfaceAssociationDescriptor::ParseL, aUsbDes, aPreviousDesc); + RETURN_IF_PARSEDL(des, TUsbInterfaceDescriptor::ParseL, aUsbDes, aPreviousDesc); + RETURN_IF_PARSEDL(des, TUsbEndpointDescriptor::ParseL, aUsbDes, aPreviousDesc); + RETURN_IF_PARSEDL(des, TUsbOTGDescriptor::ParseL, aUsbDes, aPreviousDesc); + RETURN_IF_PARSEDL(des, TUsbStringDescriptor::ParseL, aUsbDes, aPreviousDesc); + + // Then we try the custom parsers that have been registered. + const CUsbCustomDescriptorParserList* parserList = static_cast(Dll::Tls()); + if(parserList) + { + TInt numOfParsers = parserList->NumOfRegisteredParsers()-1; + for(TInt index=0; indexRegisteredParser(index); + RETURN_IF_PARSEDL(des, parserL, aUsbDes, aPreviousDesc); + } + } + + // Then we try the unknown descriptor parser. + RETURN_IF_PARSEDL(des, UnknownUsbDescriptorParserL, aUsbDes, aPreviousDesc); + + // Otherwise we haven't found anybody to parse the binary data. + User::Leave(KErrNotFound); // inform caller that there is no parser for the data. + return NULL; + } + +/*static*/ void UsbDescriptorParser::ParseDescriptorTreeL(TPtrC8& aUsbDes, TUsbGenericDescriptor& aPreviousDesc) + { + TUsbGenericDescriptor* desc = &aPreviousDesc; + while(desc) + { + TUsbGenericDescriptor* preDesc = desc; + desc = FindParserAndParseAndCheckL(aUsbDes, desc); + if(desc) + { + CleanupStack::PushL(desc); + BuildTreeL(*desc, *preDesc); + CleanupStack::Pop(desc); + } + } + } + +/*static*/ void UsbDescriptorParser::BuildTreeL(TUsbGenericDescriptor& aNewDesc, TUsbGenericDescriptor& aPreviousDesc) + { + // We assume that the new descriptor has been properly initialised with NULL pointers. + __ASSERT_DEBUG(!aNewDesc.iFirstChild && !aNewDesc.iNextPeer && !aNewDesc.iParent, + UsbDescFault(UsbdiFaults::EUsbDescTreePointersAlreadySet)); + + // Find first "top" parent claiming this new descriptor as a child. + TUsbGenericDescriptor* parent = &aPreviousDesc; + TUsbGenericDescriptor* topLevel = &aPreviousDesc; + while(parent) + { + if(aNewDesc.IsParent(*parent) || parent->IsChild(aNewDesc)) + { + break; // we have found a parent. + } + topLevel = parent; // Save the current one for use if we cannot find a parent + parent = parent->iParent; // Scroll back up the tree. + } + __ASSERT_DEBUG(topLevel, UsbDescFault(UsbdiFaults::EUsbDescNoTopLevelDescriptorFound)); + + if(parent) + { + // We should be able to place the descriptor directly as a child of this descriptor, + // however it is not that simple because of IADs (Interface Association Descriptors). + // The ECN states "All of the interface numbers in the set of associated interfaces must be + // contiguous" meaning that if an IAD has two interfaces starting at 1 then the configuration + // bundle may have interface descriptors in '1 then 3 then 2' order. As such we need to be able + // to go backwards to find the most suitable binding. The general way for doing this is to + // find the right-most, lowest descriptor that descriptor considers a parent. + // Where the tree is arranged with peers horizontally linked left to + // right, with children linked vertically top to bottom. + TUsbGenericDescriptor& suitableParent = FindSuitableParentL(aNewDesc, *parent); + + TUsbGenericDescriptor* peer = suitableParent.iFirstChild; + if(peer) + { + TUsbGenericDescriptor* lastPeer; + do + { + lastPeer = peer; + peer = peer->iNextPeer; + } + while(peer); + lastPeer->iNextPeer = &aNewDesc; + } + else + { + // we are the first child so just update. + suitableParent.iFirstChild = &aNewDesc; + } + aNewDesc.iParent = &suitableParent; + } + else if(aNewDesc.IsPeer(*topLevel) || topLevel->IsPeer(aNewDesc)) + { + // There is no explicit parent in the tree so, we may just have a group of top-level peers + // in the bundle. If the previous descriptor is a peer then we shall just tag on its tier. + TUsbGenericDescriptor* lastPeer; + TUsbGenericDescriptor* peer = topLevel; + do + { + lastPeer = peer; + peer = peer->iNextPeer; + } + while(peer); + lastPeer->iNextPeer = &aNewDesc; + } + else + { + // The descriptor could not be bound into the tree, indicating that the bundle of descriptors + // is unvalid. + User::Leave(KErrUsbBadDescriptorTopology); + } + } + +/*static*/ TUsbGenericDescriptor& UsbDescriptorParser::FindSuitableParentL(TUsbGenericDescriptor& aNewDesc, TUsbGenericDescriptor& aTopParent) + { + // This implements the algorithm to search down from the top parent found in the tree to the right most, lowest descriptor + // that will accept the new descriptor as a child. + + TUsbGenericDescriptor* bestMatch = &aTopParent; + + TUsbGenericDescriptor* desc = aTopParent.iFirstChild; + if(desc) + { + // Do a depth first search. + FOREVER + { + // First see if the descriptor is suitable. + __ASSERT_DEBUG(desc, UsbDescFault(UsbdiFaults::EUsbDescRunOffTree)); + if(aNewDesc.IsParent(*desc) || desc->IsChild(aNewDesc)) + { + bestMatch = desc; + } + // Now walk to the next point in the tree. + if(desc->iFirstChild) + { + desc = desc->iFirstChild; + } + else if(desc->iNextPeer) + { + desc = desc->iNextPeer; + } + else + { + // We've run to the end of a bottom tier, so go back up. + do + { + __ASSERT_DEBUG(desc->iParent, UsbDescFault(UsbdiFaults::EUsbDescTreeMemberHasNoParent)); + desc = desc->iParent; + } + while(!desc->iNextPeer && desc != &aTopParent); + if(desc == &aTopParent) + { + // This means that we must have got back to the original + // parent. So we don't do any more. + break; + } + desc = desc->iNextPeer; + } + } + } + return *bestMatch; + } + +/*static*/ TUsbGenericDescriptor* UsbDescriptorParser::UnknownUsbDescriptorParserL(TPtrC8& aUsbDes, TUsbGenericDescriptor* /*aPreviousDesc*/) + { + TUsbGenericDescriptor* unknownDes = NULL; + + const TInt KMinUnknownDesLength = 2; // Length and type fields + if( aUsbDes.Length() >= KMinUnknownDesLength) + { + // We require unknown descriptors to have at least the length and type fields. + // Any more exotic descriptors should have a custom parser for the framework to use. + TUint8 unknownDesLen = aUsbDes[TUsbGenericDescriptor::KbLengthOffset]; + + // Robustness check - check the length field is valid. + if(aUsbDes.Length() < unknownDesLen || unknownDesLen < KMinUnknownDesLength) + { + User::Leave(KErrCorrupt); + } + + unknownDes = new(ELeave) TUsbGenericDescriptor; + // Set the standard fields + unknownDes->ibLength = unknownDesLen; + unknownDes->ibDescriptorType = aUsbDes[TUsbGenericDescriptor::KbDescriptorTypeOffset] ; + // Set the blob appropriately + unknownDes->iBlob.Set(aUsbDes.Left(unknownDesLen)); + // Update the data-left-to-parse Symbian descriptor + aUsbDes.Set(aUsbDes.Mid(unknownDesLen)); + } + + return unknownDes; + } diff -r 466a0df5c15a -r ea2434cf3670 kernel/eka/drivers/usbho/usbdescriptors/usbdescriptors.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kernel/eka/drivers/usbho/usbdescriptors/usbdescriptors.cpp Tue May 04 18:23:12 2010 +0100 @@ -0,0 +1,1356 @@ +// Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies). +// All rights reserved. +// This component and the accompanying materials are made available +// under the terms of the License "Eclipse Public License v1.0" +// which accompanies this distribution, and is available +// at the URL "http://www.eclipse.org/legal/epl-v10.html". +// +// Initial Contributors: +// Nokia Corporation - initial contribution. +// +// Description: +// Symbian USBDI Descriptors Parsing Routines. +// +// + +/** + @file + @publishedPartner +*/ + +#include +#include "usbdescutils.h" + + +// ---------------- +// TUsbGenericDescriptor +// ---------------- + +EXPORT_C TUsbGenericDescriptor::TUsbGenericDescriptor() + : iRecognisedAndParsed(EUnrecognised) + , iNextPeer(NULL) + , iFirstChild(NULL) + , iParent(NULL) + { + } + +/** +Deletes all child and peer descriptors. Does not delete this descriptor, the caller is responsible for +doing this separately. +*/ +EXPORT_C void TUsbGenericDescriptor::DestroyTree() + { + // Store the tree pointers + TUsbGenericDescriptor* child = this->iFirstChild; + TUsbGenericDescriptor* peer = this->iNextPeer; + + // Now we chop off the tree from the root node, by doing this + // we don't need to NULL pointers as we go down (which makes + // the iterative algorithm more efficient). + this->iFirstChild = NULL; + this->iNextPeer = NULL; + + // Now we walk and destroy the tree from the two pointers + // we have + WalkAndDelete(child); + WalkAndDelete(peer); + } + +void TUsbGenericDescriptor::WalkAndDelete(TUsbGenericDescriptor* aDesc) + { + if(!aDesc) + { + return; + } + + TUsbGenericDescriptor* topLevel = aDesc->iParent; + do + { + if(aDesc->iFirstChild) + { + // walk down the tree depth first. + aDesc = aDesc->iFirstChild; + } + else if(aDesc->iNextPeer) + { + // Walk along each peer at the "bottom" + TUsbGenericDescriptor* peer = aDesc->iNextPeer; + delete aDesc; + aDesc = peer; + } + else + { + // End of bottom tier, so we go back up to the parent + // and null the first child pointer so we don't go back + // down again. + TUsbGenericDescriptor* parent = aDesc->iParent; + delete aDesc; + aDesc = parent; + if(aDesc) + { + aDesc->iFirstChild = NULL; + } + + // if we have gone up to the top level for destruction then we don't + // do anymore. + if(aDesc == topLevel) + { + break; + } + } + } + while(aDesc); + } + +/** +Utility method to retrieve a TUint8 value from a given offset in the descriptor. +@param aOffset The offset in the binary blob at which to retrieve the value. +@return The value from the descriptor. +*/ +EXPORT_C TUint8 TUsbGenericDescriptor::TUint8At(TInt aOffset) const + { + return ParseTUint8(iBlob, aOffset); + } + +/** +Utility method to retrieve a TUint16 value from a given offset in the descriptor. +@param aOffset The offset in the binary blob at which to retrieve the value. +@return The value from the descriptor. +*/ +EXPORT_C TUint16 TUsbGenericDescriptor::TUint16At(TInt aOffset) const + { + return ParseTUint16(iBlob, aOffset); + } + +/** +Utility method to retrieve a TUint32 value from a given offset in the descriptor. +@param aOffset The offset in the binary blob at which to retrieve the value. +@return The value from the descriptor. +*/ +EXPORT_C TUint32 TUsbGenericDescriptor::TUint32At(TInt aOffset) const + { + return ParseTUint32(iBlob, aOffset); + } + +/** +Assignment operator to fill in the TUsbGenericDescriptor fields from a TUsbGenericDescriptor. +Note that if a TUsbGenericDescriptor derived class has additional member fields then +they should define a specialised assignment overload for that type. +*/ +EXPORT_C TUsbGenericDescriptor& TUsbGenericDescriptor::operator=(const TUsbGenericDescriptor& aDescriptor) + { + ibLength = aDescriptor.ibLength; + ibDescriptorType = aDescriptor.ibDescriptorType; + iRecognisedAndParsed = aDescriptor.iRecognisedAndParsed; + iNextPeer = aDescriptor.iNextPeer; + iFirstChild = aDescriptor.iFirstChild; + iParent = aDescriptor.iParent; + iBlob.Set(aDescriptor.iBlob); + return *this; + } + +/** +This function determines whether the given USB descriptor is a parent +of the descriptor the method is called on. The implementation may be +specialised for each type of descriptor to ensure the tree is correctly +built up. +@param aPotentialRelative The USB descriptor that is being queried to see if it is a parent or peer. +@return TBool Efalse if the given USB descriptor is a parent of this USB descriptor, ETrue if a peer of this descriptor +*/ +/*virtual*/ TBool TUsbGenericDescriptor::IsParent(TUsbGenericDescriptor& aPotentialParent) + { + // As generic descriptors we consider all other "unknown" descriptors as peers, and + // all "known" descriptors as parents of the descriptor. + switch(aPotentialParent.ibDescriptorType) + { + case EDevice: + case EConfiguration: + case EString: + case EInterface: + case EEndpoint: + case EDeviceQualifier: + case EOtherSpeedConfiguration: + case EInterfacePower: + case EOTG: + case EDebug: + case EInterfaceAssociation: + return ETrue; + default: + return EFalse; + } + } + +/** +This function determines whether the given USB descriptor is a peer +of the descriptor the method is called on. The implementation may be +specialised for each type of descriptor to ensure the tree is correctly +built up. +@param aPotentialPeer The USB descriptor that is being queried to see if it is a peer. +@return TBool EFalse if the given USB descriptor is a parent of this USB descriptor, ETrue if a peer of this descriptor +*/ +/*virtual*/ TBool TUsbGenericDescriptor::IsPeer(TUsbGenericDescriptor& /*aPotentialPeer*/) + { + // As generic descriptors we are very permissive in binding peers. + return ETrue; + } + +/** +This function determines whether the given USB descriptor is a child +of the descriptor the method is called on. The implementation may be +specialised for each type of descriptor to ensure the tree is correctly +built up. +@param aPotentialChild The USB descriptor that is being queried to see if it is a child. +@return TBool ETrue if the given USB descriptor is a child of this USB descriptor, ETrue if a peer of this descriptor +*/ +/*virtual*/ TBool TUsbGenericDescriptor::IsChild(TUsbGenericDescriptor& /*aPotentialChild*/) + { + // We just use the logic in the IsParent. + return EFalse; + } + +/** +Ensures no memory is leaked if an owned TUsbGenericDescriptor is no longer needed. +@param aPtr The TUsbGenericDescriptor that is to be cleaned up. +@internalComponent +*/ +EXPORT_C /*static*/ void TUsbGenericDescriptor::Cleanup(TAny* aPtr) + { + TUsbGenericDescriptor* ptr = static_cast(aPtr); + ptr->DestroyTree(); // belt and braces really. + delete ptr; + } + + +// ---------------------- +// TUsbDeviceDescriptor +// See section 9.6.1 of the USB 2.0 specification. +// ---------------------- + +EXPORT_C TUsbDeviceDescriptor::TUsbDeviceDescriptor() + { + } + +EXPORT_C /*static*/ TUsbDeviceDescriptor* TUsbDeviceDescriptor::Cast(TUsbGenericDescriptor* aOriginal) + { + TUsbDeviceDescriptor* ret = NULL; + // Only cast if correctly indentified as device descriptor + if( aOriginal && + aOriginal->ibDescriptorType == EDevice && + aOriginal->ibLength == TUsbDeviceDescriptor::KSizeInOctets && + aOriginal->iRecognisedAndParsed == ERecognised) + { + ret = static_cast(aOriginal); + } + return ret; + } + +EXPORT_C TUint16 TUsbDeviceDescriptor::USBBcd() const + { + return ParseTUint16(iBlob, EbcdUSB); + } + +EXPORT_C TUint8 TUsbDeviceDescriptor::DeviceClass() const + { + return ParseTUint8(iBlob, EbDeviceClass); + } + +EXPORT_C TUint8 TUsbDeviceDescriptor::DeviceSubClass() const + { + return ParseTUint8(iBlob, EbDeviceSubClass); + } + +EXPORT_C TUint8 TUsbDeviceDescriptor::DeviceProtocol() const + { + return ParseTUint8(iBlob, EbDeviceProtocol); + } + +EXPORT_C TUint8 TUsbDeviceDescriptor::MaxPacketSize0() const + { + return ParseTUint8(iBlob, EbMaxPacketSize0); + } + +EXPORT_C TUint16 TUsbDeviceDescriptor::VendorId() const + { + return ParseTUint16(iBlob, EidVendor); + } + +EXPORT_C TUint16 TUsbDeviceDescriptor::ProductId() const + { + return ParseTUint16(iBlob, EidProduct); + } + +EXPORT_C TUint16 TUsbDeviceDescriptor::DeviceBcd() const + { + return ParseTUint16(iBlob, EbcdDevice); + } + +EXPORT_C TUint8 TUsbDeviceDescriptor::ManufacturerIndex() const + { + return ParseTUint8(iBlob, EiManufacturer); + } + +EXPORT_C TUint8 TUsbDeviceDescriptor::ProductIndex() const + { + return ParseTUint8(iBlob, EiProduct); + } + +EXPORT_C TUint8 TUsbDeviceDescriptor::SerialNumberIndex() const + { + return ParseTUint8(iBlob, EiSerialNumber); + } + +EXPORT_C TUint8 TUsbDeviceDescriptor::NumConfigurations() const + { + return ParseTUint8(iBlob, EbNumConfigurations); + } + +/** +The parsing routine for device descriptors. +Here the previous descriptor parameter is ignored - because logically a device descriptor can be neither a peer +nor a child. + +@internalComponent +*/ +/*static*/ TUsbDeviceDescriptor* TUsbDeviceDescriptor::ParseL(TPtrC8& aUsbDes, TUsbGenericDescriptor* aPreviousDesc) + { + TUsbDeviceDescriptor* devDes = NULL; + + const TInt KMinDeviceDesDecisionLength = 2; + if( aUsbDes.Length() >= KMinDeviceDesDecisionLength && + aUsbDes[KbDescriptorTypeOffset] == EDevice && + aUsbDes[KbLengthOffset] == TUsbDeviceDescriptor::KSizeInOctets) + { + // Robustness check - check the length field is valid, and that we have enough data. + if(aUsbDes.Length() < TUsbDeviceDescriptor::KSizeInOctets) + { + User::Leave(KErrCorrupt); + } + + // Robustness check - check that the device descriptor is the first to be parsed. + if(aPreviousDesc) + { + User::Leave(KErrCorrupt); + } + + // Looks ok to be a device descriptor. + devDes = new(ELeave) TUsbDeviceDescriptor; + // Set the standard fields + devDes->ibLength = TUsbDeviceDescriptor::KSizeInOctets; + devDes->ibDescriptorType = EDevice; + // Set the blob appropriately + devDes->iBlob.Set(aUsbDes.Left(TUsbDeviceDescriptor::KSizeInOctets)); + + devDes->iRecognisedAndParsed = ERecognised; + + // Update the data-left-to-parse Symbian descriptor + aUsbDes.Set(aUsbDes.Mid(TUsbDeviceDescriptor::KSizeInOctets)); + } + + return devDes; + } + +/** +@internalComponent +*/ +/*virtual*/ TBool TUsbDeviceDescriptor::IsParent(TUsbGenericDescriptor& /*aPotentialParent*/) + { + // The device descriptor should only come by itself in a bundle, so must be top-level. + return EFalse; + } + +/** +@internalComponent +*/ +/*virtual*/ TBool TUsbDeviceDescriptor::IsPeer(TUsbGenericDescriptor& /*aPotentialPeer*/) + { + // The device descriptor should only come by itself in a bundle, so no other peers. + return EFalse; + } + + +// ------------------------------ +// TUsbDeviceQualifierDescriptor +// See section 9.6.2 of the USB 2.0 specification. +// ------------------------------ + +EXPORT_C TUsbDeviceQualifierDescriptor::TUsbDeviceQualifierDescriptor() + { + } + +EXPORT_C /*static*/ TUsbDeviceQualifierDescriptor* TUsbDeviceQualifierDescriptor::Cast(TUsbGenericDescriptor* aOriginal) + { + TUsbDeviceQualifierDescriptor* ret = NULL; + // Only cast if correctly indentified as device qualifier descriptor + if( aOriginal && + aOriginal->ibDescriptorType == EDeviceQualifier && + aOriginal->ibLength == TUsbDeviceQualifierDescriptor::KSizeInOctets && + aOriginal->iRecognisedAndParsed == ERecognised) + { + ret = static_cast(aOriginal); + } + return ret; + } + +EXPORT_C TUint16 TUsbDeviceQualifierDescriptor::USBBcd() const + { + return ParseTUint16(iBlob, EbcdUSB); + } + +EXPORT_C TUint8 TUsbDeviceQualifierDescriptor::DeviceClass() const + { + return ParseTUint8(iBlob, EbDeviceClass); + } + +EXPORT_C TUint8 TUsbDeviceQualifierDescriptor::DeviceSubClass() const + { + return ParseTUint8(iBlob, EbDeviceSubClass); + } + +EXPORT_C TUint8 TUsbDeviceQualifierDescriptor::DeviceProtocol() const + { + return ParseTUint8(iBlob, EbDeviceProtocol); + } + +EXPORT_C TUint8 TUsbDeviceQualifierDescriptor::MaxPacketSize0() const + { + return ParseTUint8(iBlob, EbMaxPacketSize0); + } + +EXPORT_C TUint8 TUsbDeviceQualifierDescriptor::NumConfigurations() const + { + return ParseTUint8(iBlob, EbNumConfigurations); + } + +EXPORT_C TUint8 TUsbDeviceQualifierDescriptor::Reserved() const + { + return ParseTUint8(iBlob, EbReserved); + } + +/** +The parsing routine for device qualifier descriptors. + +@internalComponent +*/ +/*static*/ TUsbDeviceQualifierDescriptor* TUsbDeviceQualifierDescriptor::ParseL(TPtrC8& aUsbDes, TUsbGenericDescriptor* /*aPreviousDesc*/) + { + TUsbDeviceQualifierDescriptor* devQualDes = NULL; + + const TInt KMinDevQualDesDecisionLength = 2; + if( aUsbDes.Length() >= KMinDevQualDesDecisionLength && + aUsbDes[KbDescriptorTypeOffset] == EDeviceQualifier && + aUsbDes[KbLengthOffset] == TUsbDeviceQualifierDescriptor::KSizeInOctets) + { + // Robustness check - check the length field is valid, and that we have enough data. + if(aUsbDes.Length() < TUsbDeviceQualifierDescriptor::KSizeInOctets) + { + User::Leave(KErrCorrupt); + } + + // Looks ok to be a device quialifier descriptor. + devQualDes = new(ELeave) TUsbDeviceQualifierDescriptor; + // Set the standard fields + devQualDes->ibLength = TUsbDeviceQualifierDescriptor::KSizeInOctets; + devQualDes->ibDescriptorType = EDeviceQualifier; + // Set the blob appropriately + devQualDes->iBlob.Set(aUsbDes.Left(TUsbDeviceQualifierDescriptor::KSizeInOctets)); + + devQualDes->iRecognisedAndParsed = ERecognised; + + // Update the data-left-to-parse Symbian descriptor + aUsbDes.Set(aUsbDes.Mid(TUsbDeviceQualifierDescriptor::KSizeInOctets)); + } + + return devQualDes; + } + +/** +@internalComponent +*/ +/*virtual*/ TBool TUsbDeviceQualifierDescriptor::IsParent(TUsbGenericDescriptor& /*aPotentialParent*/) + { + // Like a device descriptor, they should be top-level. + return EFalse; + } + +/** +@internalComponent +*/ +/*virtual*/ TBool TUsbDeviceQualifierDescriptor::IsPeer(TUsbGenericDescriptor& /*aPotentialPeer*/) + { + // Like a device descriptor, they should come by themselves. + return EFalse; + } + + +// ---------------------------- +// TUsbConfigurationDescriptor +// See section 9.6.3 of the USB 2.0 specification. +// ---------------------------- + +EXPORT_C TUsbConfigurationDescriptor::TUsbConfigurationDescriptor() + { + } + +EXPORT_C /*static*/ TUsbConfigurationDescriptor* TUsbConfigurationDescriptor::Cast(TUsbGenericDescriptor* aOriginal) + { + TUsbConfigurationDescriptor* ret = NULL; + // Only cast if correctly indentified as configuration descriptor + if( aOriginal && + aOriginal->ibDescriptorType == EConfiguration && + aOriginal->ibLength == TUsbConfigurationDescriptor::KSizeInOctets && + aOriginal->iRecognisedAndParsed == ERecognised) + { + ret = static_cast(aOriginal); + } + return ret; + } + +EXPORT_C TUint16 TUsbConfigurationDescriptor::TotalLength() const + { + return ParseTUint16(iBlob, EwTotalLength); + } + +EXPORT_C TUint8 TUsbConfigurationDescriptor::NumInterfaces() const + { + return ParseTUint8(iBlob, EbNumInterfaces); + } + +EXPORT_C TUint8 TUsbConfigurationDescriptor::ConfigurationValue() const + { + return ParseTUint8(iBlob, EbConfigurationValue); + } + +EXPORT_C TUint8 TUsbConfigurationDescriptor::ConfigurationIndex() const + { + return ParseTUint8(iBlob, EiConfiguration); + } + +EXPORT_C TUint8 TUsbConfigurationDescriptor::Attributes() const + { + return ParseTUint8(iBlob, EbmAttributes); + } + +EXPORT_C TUint8 TUsbConfigurationDescriptor::MaxPower() const + { + return ParseTUint8(iBlob, EbMaxPower); + } + +/** +The parsing routine for configuration descriptors. + +@internalComponent +*/ +/*static*/ TUsbConfigurationDescriptor* TUsbConfigurationDescriptor::ParseL(TPtrC8& aUsbDes, TUsbGenericDescriptor* /*aPreviousDesc*/) + { + TUsbConfigurationDescriptor* configDes = NULL; + + const TInt KMinConfigDesDecisionLength = 2; + if( aUsbDes.Length() >= KMinConfigDesDecisionLength && + aUsbDes[KbDescriptorTypeOffset] == EConfiguration && + aUsbDes[KbLengthOffset] == TUsbConfigurationDescriptor::KSizeInOctets) + { + // Robustness check - check the length field is valid, and that we have enough data. + if(aUsbDes.Length() < TUsbConfigurationDescriptor::KSizeInOctets) + { + User::Leave(KErrCorrupt); + } + + // Robustness check - check that there is sufficient data for whole bundle (wTotalLength) + const TInt KwTotalLengthOffset = 2; + if(aUsbDes.Length() < ParseTUint16(aUsbDes, KwTotalLengthOffset)) + { + User::Leave(KErrCorrupt); + } + + // Looks ok to be a configuration descriptor. + configDes = new(ELeave) TUsbConfigurationDescriptor; + // Set the standard fields + configDes->ibLength = TUsbConfigurationDescriptor::KSizeInOctets; + configDes->ibDescriptorType = EConfiguration; + // Set the blob appropriately + configDes->iBlob.Set(aUsbDes.Left(TUsbConfigurationDescriptor::KSizeInOctets)); + + configDes->iRecognisedAndParsed = ERecognised; + + // Update the data-left-to-parse Symbian descriptor + aUsbDes.Set(aUsbDes.Mid(TUsbConfigurationDescriptor::KSizeInOctets)); + } + + return configDes; + } + +/** +@internalComponent +*/ +/*virtual*/ TBool TUsbConfigurationDescriptor::IsParent(TUsbGenericDescriptor& /*aPotentialParent*/) + { + // A configuration descriptor should always be the top-level descriptor in a configuration + // bundle. + return EFalse; + } + +/** +@internalComponent +*/ +/*virtual*/ TBool TUsbConfigurationDescriptor::IsPeer(TUsbGenericDescriptor& /*aPotentialPeer*/) + { + // There should only ever be one configuration descriptor in a bundle. + return EFalse; + } + + +// -------------------------- +// TUsbOtherSpeedDescriptor +// See section 9.6.4 of the USB 2.0 specification. +// -------------------------- + +EXPORT_C TUsbOtherSpeedDescriptor::TUsbOtherSpeedDescriptor() + { + } + +EXPORT_C /*static*/ TUsbOtherSpeedDescriptor* TUsbOtherSpeedDescriptor::Cast(TUsbGenericDescriptor* aOriginal) + { + TUsbOtherSpeedDescriptor* ret = NULL; + // Only cast if correctly indentified as other speed descriptor + if( aOriginal && + aOriginal->ibDescriptorType == EOtherSpeedConfiguration && + aOriginal->ibLength == TUsbOtherSpeedDescriptor::KSizeInOctets && + aOriginal->iRecognisedAndParsed == ERecognised) + { + ret = static_cast(aOriginal); + } + return ret; + } + +EXPORT_C TUint16 TUsbOtherSpeedDescriptor::TotalLength() const + { + return ParseTUint16(iBlob, EwTotalLength); + } + +EXPORT_C TUint8 TUsbOtherSpeedDescriptor::NumInterfaces() const + { + return ParseTUint8(iBlob, EbNumInterfaces); + } + +EXPORT_C TUint8 TUsbOtherSpeedDescriptor::ConfigurationValue() const + { + return ParseTUint8(iBlob, EbConfigurationValue); + } + +EXPORT_C TUint8 TUsbOtherSpeedDescriptor::ConfigurationIndex() const + { + return ParseTUint8(iBlob, EiConfiguration); + } + +EXPORT_C TUint8 TUsbOtherSpeedDescriptor::Attributes() const + { + return ParseTUint8(iBlob, EbmAttributes); + } + +EXPORT_C TUint8 TUsbOtherSpeedDescriptor::MaxPower() const + { + return ParseTUint8(iBlob, EbMaxPower); + } + +/** +The parsing routine for other speed descriptors. + +@internalComponent +*/ +/*static*/ TUsbOtherSpeedDescriptor* TUsbOtherSpeedDescriptor::ParseL(TPtrC8& aUsbDes, TUsbGenericDescriptor* /*aPreviousDesc*/) + { + TUsbOtherSpeedDescriptor* oSpeedDes = NULL; + + const TInt KMinOtherSpeedDesDecisionLength = 2; + if( aUsbDes.Length() >= KMinOtherSpeedDesDecisionLength && + aUsbDes[KbDescriptorTypeOffset] == EOtherSpeedConfiguration && + aUsbDes[KbLengthOffset] == TUsbOtherSpeedDescriptor::KSizeInOctets) + { + // Robustness check - check the length field is valid, and that we have enough data. + if(aUsbDes.Length() < TUsbOtherSpeedDescriptor::KSizeInOctets) + { + User::Leave(KErrCorrupt); + } + + // Robustness check - check that there is sufficient data for whole bundle (wTotalLength) + const TInt KwTotalLengthOffset = 2; + if(aUsbDes.Length() < ParseTUint16(aUsbDes, KwTotalLengthOffset)) + { + User::Leave(KErrCorrupt); + } + + // Looks ok to be an other speed descriptor. + oSpeedDes = new(ELeave) TUsbOtherSpeedDescriptor; + // Set the standard fields + oSpeedDes->ibLength = TUsbOtherSpeedDescriptor::KSizeInOctets; + oSpeedDes->ibDescriptorType = EOtherSpeedConfiguration; + // Set the blob appropriately + oSpeedDes->iBlob.Set(aUsbDes.Left(TUsbOtherSpeedDescriptor::KSizeInOctets)); + + oSpeedDes->iRecognisedAndParsed = ERecognised; + + // Update the data-left-to-parse Symbian descriptor + aUsbDes.Set(aUsbDes.Mid(TUsbOtherSpeedDescriptor::KSizeInOctets)); + } + + return oSpeedDes; + } + +/** +@internalComponent +*/ +/*virtual*/ TBool TUsbOtherSpeedDescriptor::IsParent(TUsbGenericDescriptor& /*aPotentialParent*/) + { + // Other speed descriptor is like a configuration descriptor, in that it should + // not have any parents in a bundle. + return EFalse; + } + +/** +@internalComponent +*/ +/*virtual*/ TBool TUsbOtherSpeedDescriptor::IsPeer(TUsbGenericDescriptor& /*aPotentialPeer*/) + { + // There should only ever be one other speed descriptor in a bundle. + return EFalse; + } + + +// ------------------------------------ +// TUsbInterfaceAssociationDescriptor +// See the USB IAD ECN. +// ------------------------------------ + +EXPORT_C TUsbInterfaceAssociationDescriptor::TUsbInterfaceAssociationDescriptor() + { + } + +EXPORT_C /*static*/ TUsbInterfaceAssociationDescriptor* TUsbInterfaceAssociationDescriptor::Cast(TUsbGenericDescriptor* aOriginal) + { + TUsbInterfaceAssociationDescriptor* ret = NULL; + // Only cast if correctly indentified as interface association descriptor + if( aOriginal && + aOriginal->ibDescriptorType == EInterfaceAssociation && + aOriginal->ibLength == TUsbInterfaceAssociationDescriptor::KSizeInOctets && + aOriginal->iRecognisedAndParsed == ERecognised) + { + ret = static_cast(aOriginal); + } + return ret; + } + +EXPORT_C TUint8 TUsbInterfaceAssociationDescriptor::FirstInterface() const + { + return ParseTUint8(iBlob, EbFirstInterface); + } + +EXPORT_C TUint8 TUsbInterfaceAssociationDescriptor::InterfaceCount() const + { + return ParseTUint8(iBlob, EbInterfaceCount); + } + +EXPORT_C TUint8 TUsbInterfaceAssociationDescriptor::FunctionClass() const + { + return ParseTUint8(iBlob, EbFunctionClass); + } + +EXPORT_C TUint8 TUsbInterfaceAssociationDescriptor::FunctionSubClass() const + { + return ParseTUint8(iBlob, EbFunctionSubClass); + } + +EXPORT_C TUint8 TUsbInterfaceAssociationDescriptor::FunctionProtocol() const + { + return ParseTUint8(iBlob, EbFunctionProtocol); + } + +EXPORT_C TUint8 TUsbInterfaceAssociationDescriptor::FunctionIndex() const + { + return ParseTUint8(iBlob, EiFunction); + } + +/*static*/ TUsbInterfaceAssociationDescriptor* TUsbInterfaceAssociationDescriptor::ParseL(TPtrC8& aUsbDes, TUsbGenericDescriptor* /*aPreviousDesc*/) + { + TUsbInterfaceAssociationDescriptor* intAssocDes = NULL; + + const TInt KMinIntAssocDesDecisionLength = 2; + if( aUsbDes.Length() >= KMinIntAssocDesDecisionLength && + aUsbDes[KbDescriptorTypeOffset] == EInterfaceAssociation && + aUsbDes[KbLengthOffset] == TUsbInterfaceAssociationDescriptor::KSizeInOctets) + { + // Robustness check - check the length field is valid, and that we have enough data. + if(aUsbDes.Length() < TUsbInterfaceAssociationDescriptor::KSizeInOctets) + { + User::Leave(KErrCorrupt); + } + + // Looks ok to be a interface association descriptor. + intAssocDes = new(ELeave) TUsbInterfaceAssociationDescriptor; + // Set the standard fields + intAssocDes->ibLength = TUsbInterfaceAssociationDescriptor::KSizeInOctets; + intAssocDes->ibDescriptorType = EInterfaceAssociation; + // Set the blob appropriately + intAssocDes->iBlob.Set(aUsbDes.Left(TUsbInterfaceAssociationDescriptor::KSizeInOctets)); + + intAssocDes->iRecognisedAndParsed = ERecognised; + + // Update the data-left-to-parse Symbian descriptor + aUsbDes.Set(aUsbDes.Mid(TUsbInterfaceAssociationDescriptor::KSizeInOctets)); + } + + return intAssocDes; + } + +/** +@internalComponent +*/ +/*virtual*/ TBool TUsbInterfaceAssociationDescriptor::IsParent(TUsbGenericDescriptor& aPotentialParent) + { + switch(aPotentialParent.ibDescriptorType) + { + case EConfiguration: + return ETrue; + case EOtherSpeedConfiguration: + return ETrue; // I think this should be EFalse by my reading of the USB spec - however + // it is not explicitly clear, so play it safe. + default: + return EFalse; + } + } + +/** +@internalComponent +*/ +/*virtual*/ TBool TUsbInterfaceAssociationDescriptor::IsPeer(TUsbGenericDescriptor& aPotentialPeer) + { + switch(aPotentialPeer.ibDescriptorType) + { + case EInterfaceAssociation: + return ETrue; + case EInterface: + // Only interfaces are peers of IADs. + { + TUsbInterfaceDescriptor* intDesc = TUsbInterfaceDescriptor::Cast(&aPotentialPeer); + if(intDesc) + { + TInt intNum = intDesc->InterfaceNumber(); + intNum -= FirstInterface(); + if(intNum < 0 || intNum >= InterfaceCount()) + { + // The interface number is outside the IAD region. + return ETrue; + } + } + return EFalse; + } + default: + return EFalse; + } + } + +/*virtual*/ TBool TUsbInterfaceAssociationDescriptor::IsChild(TUsbGenericDescriptor& aPotentialChild) + { + switch(aPotentialChild.ibDescriptorType) + { + case EInterface: + // Only interfaces are children of IADs. And only if they are special. + { + TUsbInterfaceDescriptor* intDesc = TUsbInterfaceDescriptor::Cast(&aPotentialChild); + if(intDesc) + { + TInt intNum = intDesc->InterfaceNumber(); + intNum -= FirstInterface(); + if(intNum >= 0 && intNum < InterfaceCount()) + { + // The interface number is within the IAD region required. + return ETrue; + } + } + return EFalse; + } + default: + return EFalse; + } + } + + +// ------------------------- +// TUsbInterfaceDescriptor +// See section 9.6.5 of the USB 2.0 specification. +// ------------------------- + +EXPORT_C TUsbInterfaceDescriptor::TUsbInterfaceDescriptor() + { + } + +EXPORT_C /*static*/ TUsbInterfaceDescriptor* TUsbInterfaceDescriptor::Cast(TUsbGenericDescriptor* aOriginal) + { + TUsbInterfaceDescriptor* ret = NULL; + // Only cast if correctly indentified as interface descriptor + if( aOriginal && + aOriginal->ibDescriptorType == EInterface && + aOriginal->ibLength == TUsbInterfaceDescriptor::KSizeInOctets && + aOriginal->iRecognisedAndParsed == ERecognised) + { + ret = static_cast(aOriginal); + } + return ret; + } + +EXPORT_C TUint8 TUsbInterfaceDescriptor::InterfaceNumber() const + { + return ParseTUint8(iBlob, EbInterfaceNumber); + } + +EXPORT_C TUint8 TUsbInterfaceDescriptor::AlternateSetting() const + { + return ParseTUint8(iBlob, EbAlternateSetting); + } + +EXPORT_C TUint8 TUsbInterfaceDescriptor::NumEndpoints() const + { + return ParseTUint8(iBlob, EbNumEndpoints); + } + +EXPORT_C TUint8 TUsbInterfaceDescriptor::InterfaceClass() const + { + return ParseTUint8(iBlob, EbInterfaceClass); + } + +EXPORT_C TUint8 TUsbInterfaceDescriptor::InterfaceSubClass() const + { + return ParseTUint8(iBlob, EbInterfaceSubClass); + } + +EXPORT_C TUint8 TUsbInterfaceDescriptor::InterfaceProtocol() const + { + return ParseTUint8(iBlob, EbInterfaceProtocol); + } + +EXPORT_C TUint8 TUsbInterfaceDescriptor::Interface() const + { + return ParseTUint8(iBlob, EiInterface); + } + +/** +The parsing routine for interface descriptors. + +@internalComponent +*/ +/*static*/ TUsbInterfaceDescriptor* TUsbInterfaceDescriptor::ParseL(TPtrC8& aUsbDes, TUsbGenericDescriptor* /*aPreviousDesc*/) + { + TUsbInterfaceDescriptor* intDes = NULL; + + const TInt KMinInterfaceDesDecisionLength = 2; + if( aUsbDes.Length() >= KMinInterfaceDesDecisionLength && + aUsbDes[KbDescriptorTypeOffset] == EInterface && + aUsbDes[KbLengthOffset] == TUsbInterfaceDescriptor::KSizeInOctets) + { + // Robustness check - check the length field is valid, and that we have enough data. + if(aUsbDes.Length() < TUsbInterfaceDescriptor::KSizeInOctets) + { + User::Leave(KErrCorrupt); + } + + // Looks ok to be an interface descriptor. + intDes = new(ELeave) TUsbInterfaceDescriptor; + // Set the standard fields + intDes->ibLength = TUsbInterfaceDescriptor::KSizeInOctets; + intDes->ibDescriptorType = EInterface; + // Set the blob appropriately + intDes->iBlob.Set(aUsbDes.Left(TUsbInterfaceDescriptor::KSizeInOctets)); + + intDes->iRecognisedAndParsed = ERecognised; + + // Update the data-left-to-parse Symbian descriptor + aUsbDes.Set(aUsbDes.Mid(TUsbInterfaceDescriptor::KSizeInOctets)); + } + + return intDes; + } + +/** +@internalComponent +*/ +/*virtual*/ TBool TUsbInterfaceDescriptor::IsParent(TUsbGenericDescriptor& aPotentialParent) + { + switch(aPotentialParent.ibDescriptorType) + { + case EConfiguration: + return ETrue; + case EOtherSpeedConfiguration: + return ETrue; // I think this should be EFalse by my reading of the USB spec - however + // it is not explicitly clear, so play it safe. + // case EInterfaceAssociation: + // We let the IAD descriptor handle the logic of how we bind to it. + default: + return EFalse; + } + } + +/** +@internalComponent +*/ +/*virtual*/ TBool TUsbInterfaceDescriptor::IsPeer(TUsbGenericDescriptor& aPotentialPeer) + { + switch(aPotentialPeer.ibDescriptorType) + { + //case EInterfaceAssociation: + // We let the IAD descriptor handle the logic of how we bind to it. + case EInterface: + // If another interface descriptor then it is a peer not child. + return ETrue; + default: + // Any other descriptors are ignored. + return EFalse; + } + } + + +// ------------------------ +// TUsbEndpointDescriptor +// See section 9.6.6 of the USB 2.0 specification. +// ------------------------ + +EXPORT_C TUsbEndpointDescriptor::TUsbEndpointDescriptor() + { + } + +EXPORT_C /*static*/ TUsbEndpointDescriptor* TUsbEndpointDescriptor::Cast(TUsbGenericDescriptor* aOriginal) + { + TUsbEndpointDescriptor* ret = NULL; + // Only cast if correctly indentified as endpoint descriptor + if( aOriginal && + aOriginal->ibDescriptorType == EEndpoint && + aOriginal->ibLength == TUsbEndpointDescriptor::KSizeInOctets && + aOriginal->iRecognisedAndParsed == ERecognised) + { + ret = static_cast(aOriginal); + } + return ret; + } + +EXPORT_C TUint8 TUsbEndpointDescriptor::EndpointAddress() const + { + return ParseTUint8(iBlob, EbEndpointAddress); + } + +EXPORT_C TUint8 TUsbEndpointDescriptor::Attributes() const + { + return ParseTUint8(iBlob, EbmAttributes); + } + +EXPORT_C TUint16 TUsbEndpointDescriptor::MaxPacketSize() const + { + return ParseTUint16(iBlob, EwMaxPacketSize); + } + +EXPORT_C TUint8 TUsbEndpointDescriptor::Interval() const + { + return ParseTUint8(iBlob, EbInterval); + } + +/** +The parsing routine for endpoint descriptors. + +@internalComponent +*/ +/*static*/ TUsbEndpointDescriptor* TUsbEndpointDescriptor::ParseL(TPtrC8& aUsbDes, TUsbGenericDescriptor* /*aPreviousDesc*/) + { + TUsbEndpointDescriptor* endDes = NULL; + + const TInt KMinEndpointDesDecisionLength = 2; + if( aUsbDes.Length() >= KMinEndpointDesDecisionLength && + aUsbDes[KbDescriptorTypeOffset] == EEndpoint && + aUsbDes[KbLengthOffset] == TUsbEndpointDescriptor::KSizeInOctets) + { + // Robustness check - check the length field is valid, and that we have enough data. + if(aUsbDes.Length() < TUsbEndpointDescriptor::KSizeInOctets) + { + User::Leave(KErrCorrupt); + } + + // Looks ok to be an endpoint descriptor. + endDes = new(ELeave) TUsbEndpointDescriptor; + // Set the standard fields + endDes->ibLength = TUsbEndpointDescriptor::KSizeInOctets; + endDes->ibDescriptorType = EEndpoint; + // Set the blob appropriately + endDes->iBlob.Set(aUsbDes.Left(TUsbEndpointDescriptor::KSizeInOctets)); + + endDes->iRecognisedAndParsed = ERecognised; + + // Update the data-left-to-parse Symbian descriptor + aUsbDes.Set(aUsbDes.Mid(TUsbEndpointDescriptor::KSizeInOctets)); + } + + return endDes; + } + +/** +@internalComponent +*/ +/*virtual*/ TBool TUsbEndpointDescriptor::IsParent(TUsbGenericDescriptor& aPotentialParent) + { + switch(aPotentialParent.ibDescriptorType) + { + case EInterface: + return ETrue; + default: + return EFalse; + } + } + +/** +@internalComponent +*/ +/*virtual*/ TBool TUsbEndpointDescriptor::IsPeer(TUsbGenericDescriptor& aPotentialPeer) + { + switch(aPotentialPeer.ibDescriptorType) + { + case EEndpoint: + return ETrue; + default: + return EFalse; + } + } + +// ------------------------ +// TUsbOTGDescriptor +// See section 6.4 of the USB 2.0 On-The-Go Supplement Revision 1.3 +// ------------------------ + +EXPORT_C TUsbOTGDescriptor::TUsbOTGDescriptor() + { + } + +EXPORT_C /*static*/ TUsbOTGDescriptor* TUsbOTGDescriptor::Cast(TUsbGenericDescriptor* aOriginal) + { + TUsbOTGDescriptor* ret = NULL; + // Only cast if correctly indentified as otg descriptor + if( aOriginal && + aOriginal->ibDescriptorType == EOTG && + aOriginal->ibLength == TUsbOTGDescriptor::KSizeInOctets && + aOriginal->iRecognisedAndParsed == ERecognised) + { + ret = static_cast(aOriginal); + } + return ret; + } + +EXPORT_C TUint8 TUsbOTGDescriptor::Attributes() const + { + return ParseTUint8(iBlob, EbmAttributes); + } + +EXPORT_C TBool TUsbOTGDescriptor::HNPSupported() const + { + return (ParseTUint8(iBlob, EbmAttributes) & 0x02) == 0x02; + } + +EXPORT_C TBool TUsbOTGDescriptor::SRPSupported() const + { + // Note: an illegal device (see 6.4.2 of the OTG specification) could + // incorrectly return False for SRP and True for HNP + // However this function just extracts the bit rather than attempting to + // fix up a broken device. Devices broken in this way wouldn't be expected on + // the TPL. + return (ParseTUint8(iBlob, EbmAttributes) & 0x01) == 0x01; + } + +/** +The parsing routine for OTG descriptors. + +@internalComponent +*/ +/*static*/ TUsbOTGDescriptor* TUsbOTGDescriptor::ParseL(TPtrC8& aUsbDes, TUsbGenericDescriptor* /*aPreviousDesc*/) + { + TUsbOTGDescriptor* endDes = NULL; + + const TInt KMinOTGDesDecisionLength = 2; + if( aUsbDes.Length() >= KMinOTGDesDecisionLength && + aUsbDes[KbDescriptorTypeOffset] == EOTG && + aUsbDes[KbLengthOffset] == TUsbOTGDescriptor::KSizeInOctets) + { + // Robustness check - check the length field is valid, and that we have enough data. + if(aUsbDes.Length() < TUsbOTGDescriptor::KSizeInOctets) + { + User::Leave(KErrCorrupt); + } + + // Looks ok to be an OTG descriptor. + endDes = new(ELeave) TUsbOTGDescriptor; + // Set the standard fields + endDes->ibLength = TUsbOTGDescriptor::KSizeInOctets; + endDes->ibDescriptorType = EOTG; + // Set the blob appropriately + endDes->iBlob.Set(aUsbDes.Left(TUsbOTGDescriptor::KSizeInOctets)); + + // Null the pointers + endDes->iFirstChild = NULL; + endDes->iNextPeer = NULL; + endDes->iParent = NULL; + + endDes->iRecognisedAndParsed = ERecognised; + + // Update the data-left-to-parse Symbian descriptor + aUsbDes.Set(aUsbDes.Mid(TUsbOTGDescriptor::KSizeInOctets)); + } + + return endDes; + } + +/** +@internalComponent +*/ +/*virtual*/ TBool TUsbOTGDescriptor::IsParent(TUsbGenericDescriptor& aPotentialParent) + { + switch(aPotentialParent.ibDescriptorType) + { + case EConfiguration: // we are part of a configuration descriptor, or standalone + return ETrue; + default: + return EFalse; + } + } + +/** +@internalComponent +*/ +/*virtual*/ TBool TUsbOTGDescriptor::IsPeer(TUsbGenericDescriptor& aPotentialPeer) + { + switch(aPotentialPeer.ibDescriptorType) + { + //case EInterfaceAssociation: + // We let the IAD descriptor handle the logic of how we bind to it. + case EInterface: + // If another interface descriptor then it is a peer not child. + return ETrue; + default: + // Any other descriptors are ignored. + return EFalse; + } + } + + +// ---------------------- +// TUsbStringDescriptor +// See section 9.6.7 of the USB 2.0 specification. +// ---------------------- + +// The length of the header in a string descriptor (i.e. the same as every other standard USB descriptor). +static const TInt KStringDescriptorHeaderFieldLength = 2; + +EXPORT_C TUsbStringDescriptor::TUsbStringDescriptor() + { + } + +EXPORT_C /*static*/ TUsbStringDescriptor* TUsbStringDescriptor::Cast(TUsbGenericDescriptor* aOriginal) + { + TUsbStringDescriptor* ret = NULL; + // Only cast if correctly indentified as string descriptor + if( aOriginal && + aOriginal->ibDescriptorType == EString && + aOriginal->ibLength >= KStringDescriptorHeaderFieldLength && + aOriginal->iRecognisedAndParsed == ERecognised) + { + ret = static_cast(aOriginal); + } + return ret; + } + +/** +For string descriptor zero, this function allows a means to iterate through the list of supported languages +for strings on this device. + +@param aIndex Index into language ID table. +@return The language ID at the requested index, or KErrNotFound if the end of the list has been reached. +Note that the language IDs are unsigned 16-bit numbers, while the return from this function is signed 32-bit. +*/ +EXPORT_C TInt TUsbStringDescriptor::GetLangId(TInt aIndex) const + { + __ASSERT_ALWAYS(aIndex >= 0, UsbDescPanic(UsbdiPanics::EUsbDescNegativeIndexToLangId)); + const TUint8 KSizeOfLangIdField = 2; + + TInt offset = KStringDescriptorHeaderFieldLength + KSizeOfLangIdField * aIndex; + if(offset >= ibLength) + { + return KErrNotFound; + } + return ParseTUint16(iBlob, offset); + } + +/** +Writes the string data into a Symbian descriptor of sufficient size. + +@param aString The Symbian descriptor that will have the string data written into it. +*/ +EXPORT_C void TUsbStringDescriptor::StringData(TDes16& aString) const + { + const TUint8 KUnicodeCharacterWidth = 2; + aString.Zero(); + + TInt index = KStringDescriptorHeaderFieldLength; + while(index+KUnicodeCharacterWidth <= ibLength) + { + aString.Append(ParseTUint16(iBlob, index)); + index += KUnicodeCharacterWidth; + } + } + + +/*static*/ TUsbStringDescriptor* TUsbStringDescriptor::ParseL(TPtrC8& aUsbDes, TUsbGenericDescriptor* /*aPreviousDesc*/) + { + TUsbStringDescriptor* stringDes = NULL; + + if( aUsbDes.Length() >= KStringDescriptorHeaderFieldLength && + aUsbDes[KbDescriptorTypeOffset] == EString) + { + TUint8 stringDesLen = aUsbDes[KbLengthOffset]; + + // Robustness check - check the length field is valid + if(aUsbDes.Length() < stringDesLen || stringDesLen < KStringDescriptorHeaderFieldLength) + { + User::Leave(KErrCorrupt); + } + // Robustness check - check the length is a multiple of two. + if(stringDesLen % 2 != 0) + { + User::Leave(KErrCorrupt); + } + + // Looks ok to be a string descriptor. + stringDes = new(ELeave) TUsbStringDescriptor; + // Set the standard fields + stringDes->ibLength = stringDesLen; + stringDes->ibDescriptorType = EString; + // Set the blob appropriately + stringDes->iBlob.Set(aUsbDes.Left(stringDesLen)); + + stringDes->iRecognisedAndParsed = ERecognised; + + // Update the data-left-to-parse Symbian descriptor + aUsbDes.Set(aUsbDes.Mid(stringDesLen)); + } + + return stringDes; + } + +/** +@internalComponent +*/ +/*virtual*/ TBool TUsbStringDescriptor::IsParent(TUsbGenericDescriptor& /*aPotentialParent*/) + { + // String descriptors have no parents - they are standalone. + return EFalse; + } + +/** +@internalComponent +*/ +/*virtual*/ TBool TUsbStringDescriptor::IsPeer(TUsbGenericDescriptor& /*aPotentialPeer*/) + { + // String descriptors have no peers - they are standalone. + return EFalse; + } + diff -r 466a0df5c15a -r ea2434cf3670 kernel/eka/drivers/usbho/usbdescriptors/usbdescriptors.mmp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kernel/eka/drivers/usbho/usbdescriptors/usbdescriptors.mmp Tue May 04 18:23:12 2010 +0100 @@ -0,0 +1,31 @@ +// Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies). +// All rights reserved. +// This component and the accompanying materials are made available +// under the terms of the License "Eclipse Public License v1.0" +// which accompanies this distribution, and is available +// at the URL "http://www.eclipse.org/legal/epl-v10.html". +// +// Initial Contributors: +// Nokia Corporation - initial contribution. +// +// Description: +// + +TARGET usbdescriptors.dll +TARGETTYPE dll +CAPABILITY All -Tcb +VENDORID 0x70000001 + +DEFFILE ../../../~/usbdescriptors.def + +OS_LAYER_SYSTEMINCLUDE_SYMBIAN +USERINCLUDE . + +SOURCEPATH . +SOURCE usbdescriptors.cpp +SOURCE usbdescparser.cpp +SOURCE usbdescutils.cpp + +LIBRARY euser.lib + +SMPSAFE \ No newline at end of file diff -r 466a0df5c15a -r ea2434cf3670 kernel/eka/drivers/usbho/usbdescriptors/usbdescutils.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kernel/eka/drivers/usbho/usbdescriptors/usbdescutils.cpp Tue May 04 18:23:12 2010 +0100 @@ -0,0 +1,55 @@ +// Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies). +// All rights reserved. +// This component and the accompanying materials are made available +// under the terms of the License "Eclipse Public License v1.0" +// which accompanies this distribution, and is available +// at the URL "http://www.eclipse.org/legal/epl-v10.html". +// +// Initial Contributors: +// Nokia Corporation - initial contribution. +// +// Description: +// + +#include "usbdescutils.h" + +/** +@file +@internalComponent +*/ + +/*static*/ CUsbCustomDescriptorParserList* CUsbCustomDescriptorParserList::NewL() + { + CUsbCustomDescriptorParserList* self = new(ELeave) CUsbCustomDescriptorParserList; + return self; + } + +CUsbCustomDescriptorParserList::~CUsbCustomDescriptorParserList() + { + iParserList.Close(); + } + +void CUsbCustomDescriptorParserList::RegisterParserL(UsbDescriptorParser::TUsbDescriptorParserL aParserFunc) + { + iParserList.AppendL(aParserFunc); + } + +void CUsbCustomDescriptorParserList::UnregisterParser(UsbDescriptorParser::TUsbDescriptorParserL aParserFunc) + { + TInt res = iParserList.Find(aParserFunc); + if(res != KErrNotFound) + { + iParserList.Remove(res); + } + } + +TInt CUsbCustomDescriptorParserList::NumOfRegisteredParsers() const + { + return iParserList.Count(); + } + +UsbDescriptorParser::TUsbDescriptorParserL CUsbCustomDescriptorParserList::RegisteredParser(TInt aIndex) const + { + return iParserList[aIndex]; + } + diff -r 466a0df5c15a -r ea2434cf3670 kernel/eka/drivers/usbho/usbdescriptors/usbdescutils.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kernel/eka/drivers/usbho/usbdescriptors/usbdescutils.h Tue May 04 18:23:12 2010 +0100 @@ -0,0 +1,94 @@ +// Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies). +// All rights reserved. +// This component and the accompanying materials are made available +// under the terms of the License "Eclipse Public License v1.0" +// which accompanies this distribution, and is available +// at the URL "http://www.eclipse.org/legal/epl-v10.html". +// +// Initial Contributors: +// Nokia Corporation - initial contribution. +// +// Description: +// + +/** + @file + @internalComponent +*/ + +#ifndef USBDESCUTILS_H +#define USBDESCUTILS_H + +#include +#include + +inline void UsbDescFault(UsbdiFaults::TUsbDescFaults aFault) + { + User::Panic(UsbdiFaults::KUsbDescFaultCat, aFault); + } + +inline void UsbDescPanic(UsbdiPanics::TUsbDescPanics aPanic) + { + User::Panic(UsbdiPanics::KUsbDescPanicCat, aPanic); + } + +/** +Utility function for retrieving a TUint8 from a Little Endian USB descriptor. +@param aDes The descriptor to parse. +@param aOffset The offset in the descriptor where to parse. +@return The TUint8 value parsed. +*/ +inline TUint8 ParseTUint8(TPtrC8 aDes, TInt aOffset) + { + return aDes[aOffset]; + } + +/** +Utility function for retrieving a TUint16 from a Little Endian USB descriptor. +@param aDes The descriptor to parse. +@param aOffset The offset in the descriptor where to parse. +@return The TUint16 value parsed. +*/ +inline TUint16 ParseTUint16(TPtrC8 aDes, TInt aOffset) + { + return ((TUint16)aDes[aOffset]) | ( ((TUint16)aDes[aOffset+1]) << 8 ); + } + +/** +Utility function for retrieving a TUint32 from a Little Endian USB descriptor. +@param aDes The descriptor to parse. +@param aOffset The offset in the descriptor where to parse. +@return The TUint32 value parsed. +*/ +inline TUint32 ParseTUint32(TPtrC8 aDes, TInt aOffset) + { + // Put enough brackets to ensure that all casting is correct + // and the expression looks symmetrical + return ( ((TUint32)(aDes[aOffset])) ) | + ( ((TUint32)(aDes[aOffset + 1])) << 8 ) | + ( ((TUint32)(aDes[aOffset + 2])) << 16 ) | + ( ((TUint32)(aDes[aOffset + 3])) << 24 ); + } + +/** +A utility class to store the custom descriptor parsers. +The USBDI descriptor parsing framework creates and stores an instance +of this class in TLS when a custom parse is registered. +*/ +NONSHARABLE_CLASS(CUsbCustomDescriptorParserList) : public CBase + { +public: + static CUsbCustomDescriptorParserList* NewL(); + ~CUsbCustomDescriptorParserList(); + + void RegisterParserL(UsbDescriptorParser::TUsbDescriptorParserL aParserFunc); + void UnregisterParser(UsbDescriptorParser::TUsbDescriptorParserL aParserFunc); + TInt NumOfRegisteredParsers() const; + UsbDescriptorParser::TUsbDescriptorParserL RegisteredParser(TInt aIndex) const; + +private: + RArray iParserList; + }; + + +#endif // USBDESCUTILS_H diff -r 466a0df5c15a -r ea2434cf3670 kernel/eka/drivers/usbho/usbdi_utils/base_drivers_usbdi_utils.mrp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kernel/eka/drivers/usbho/usbdi_utils/base_drivers_usbdi_utils.mrp Tue May 04 18:23:12 2010 +0100 @@ -0,0 +1,27 @@ +# +# Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +# All rights reserved. +# This component and the accompanying materials are made available +# under the terms of "Eclipse Public License v1.0" +# which accompanies this distribution, and is available +# at the URL "http://www.eclipse.org/legal/epl-v10.html". +# +# Initial Contributors: +# Nokia Corporation - initial contribution. +# +# Contributors: +# +# Description: +# +# component name "USB DI Utils" + +component base_drivers_usbdi_utils + +source \sf\os\kernelhwsrv\kernel\eka\drivers\usbho\usbdi_utils + +binary \sf\os\kernelhwsrv\kernel\eka\drivers\usbho\usbdi_utils all + +notes_source \component_defs\release.src + +ipr E + diff -r 466a0df5c15a -r ea2434cf3670 kernel/eka/drivers/usbho/usbdi_utils/bld.inf --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kernel/eka/drivers/usbho/usbdi_utils/bld.inf Tue May 04 18:23:12 2010 +0100 @@ -0,0 +1,46 @@ +// Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). +// All rights reserved. +// This component and the accompanying materials are made available +// under the terms of the License "Eclipse Public License v1.0" +// which accompanies this distribution, and is available +// at the URL "http://www.eclipse.org/legal/epl-v10.html". +// +// Initial Contributors: +// Nokia Corporation - initial contribution. +// +// Contributors: +// +// Description: +// e32/drivers/usbho/usbdi_utils/bld.inf +// +// + +/** + @file +*/ + + +PRJ_PLATFORMS + +ARMV5 ARMV5SMP + + +PRJ_MMPFILES + +#ifndef GCCXML +#if defined(GENERIC_MARM) || !defined(WINS) || defined(GENERIC_X86) +#if !defined(MARM_THUMB) && !defined(MARM_ARMI) + +#if !defined(WINS) +#if !defined(X86) +#if defined(SYMBIAN_ENABLE_USB_OTG_HOST) + +usbdi_utils + +#endif +#endif +#endif + +#endif +#endif +#endif diff -r 466a0df5c15a -r ea2434cf3670 kernel/eka/drivers/usbho/usbdi_utils/usbdi_utils.mmp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kernel/eka/drivers/usbho/usbdi_utils/usbdi_utils.mmp Tue May 04 18:23:12 2010 +0100 @@ -0,0 +1,37 @@ +// Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies). +// All rights reserved. +// This component and the accompanying materials are made available +// under the terms of the License "Eclipse Public License v1.0" +// which accompanies this distribution, and is available +// at the URL "http://www.eclipse.org/legal/epl-v10.html". +// +// Initial Contributors: +// Nokia Corporation - initial contribution. +// +// Contributors: +// +// Description: +// + +target usbdi_utils.dll +targettype dll +capability All -Tcb +vendorid 0x70000001 + +deffile ../../../~/usbdi_utils.def + +OS_LAYER_SYSTEMINCLUDE_SYMBIAN +userinclude . + +sourcepath . +source usbtransfers.cpp +source usbtransferstrategy.cpp +source usbinterface.cpp +source usbpipe.cpp +source usbdiutils.cpp +source zerocopytransferstrategy.cpp + +library euser.lib +library usbdescriptors.lib + +SMPSAFE \ No newline at end of file diff -r 466a0df5c15a -r ea2434cf3670 kernel/eka/drivers/usbho/usbdi_utils/usbdiutils.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kernel/eka/drivers/usbho/usbdi_utils/usbdiutils.cpp Tue May 04 18:23:12 2010 +0100 @@ -0,0 +1,28 @@ +// Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies). +// All rights reserved. +// This component and the accompanying materials are made available +// under the terms of the License "Eclipse Public License v1.0" +// which accompanies this distribution, and is available +// at the URL "http://www.eclipse.org/legal/epl-v10.html". +// +// Initial Contributors: +// Nokia Corporation - initial contribution. +// +// Contributors: +// +// Description: +// + +#include "usbdiutils.h" + + +void UsbdiUtils::Panic(UsbdiPanics::TUsbdiPanics aPanic) + { + User::Panic(UsbdiPanics::KUsbdiPanicCat, aPanic); + } + + +void UsbdiUtils::Fault(UsbdiFaults::TUsbdiFaults aFault) + { + User::Panic(UsbdiFaults::KUsbdiFaultCat, aFault); + } diff -r 466a0df5c15a -r ea2434cf3670 kernel/eka/drivers/usbho/usbdi_utils/usbdiutils.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kernel/eka/drivers/usbho/usbdi_utils/usbdiutils.h Tue May 04 18:23:12 2010 +0100 @@ -0,0 +1,34 @@ +// Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies). +// All rights reserved. +// This component and the accompanying materials are made available +// under the terms of the License "Eclipse Public License v1.0" +// which accompanies this distribution, and is available +// at the URL "http://www.eclipse.org/legal/epl-v10.html". +// +// Initial Contributors: +// Nokia Corporation - initial contribution. +// +// Contributors: +// +// Description: +// + +/** + @file + @internalComponent +*/ + +#ifndef USBDIUTILS_H +#define USBDIUTILS_H + +#include + + +NONSHARABLE_CLASS(UsbdiUtils) + { +public: + static void Panic(UsbdiPanics::TUsbdiPanics aPanic); + static void Fault(UsbdiFaults::TUsbdiFaults aFault); + }; + +#endif // USBDIUTILS_H diff -r 466a0df5c15a -r ea2434cf3670 kernel/eka/drivers/usbho/usbdi_utils/usbinterface.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kernel/eka/drivers/usbho/usbdi_utils/usbinterface.cpp Tue May 04 18:23:12 2010 +0100 @@ -0,0 +1,154 @@ +// Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies). +// All rights reserved. +// This component and the accompanying materials are made available +// under the terms of the License "Eclipse Public License v1.0" +// which accompanies this distribution, and is available +// at the URL "http://www.eclipse.org/legal/epl-v10.html". +// +// Initial Contributors: +// Nokia Corporation - initial contribution. +// +// Contributors: +// +// Description: +// + +#include + +#include +#include "usbtransferstrategy.h" +#include "zerocopytransferstrategy.h" + + +/** +Opens an interface identified by a token. When the hub driver loads a driver (via function driver +framework), this token is generated to allow the driver to open the interface. + +This also causes the interface's descriptors to be parsed for future reference. + +@param[in] aToken The token for the interface to open. +@return System-wide error code. +*/ +EXPORT_C TInt RUsbInterface::Open(TUint32 aToken, TOwnerType aType) + { + TPckgC token(aToken); + TInt err = DoCreate(Name(), VersionRequired(), KNullUnit, NULL, &token, aType); + if(err == KErrNone) + { + // Create a transfer strategy + iTransferStrategy = new RUsbZeroCopyTransferStrategy; + if(!iTransferStrategy) + { + Close(); + return KErrNoMemory; + } + + // Get descriptor size + TInt interfaceDescSize = 0; + err = DoControl(EGetInterfaceDescriptorSize, &interfaceDescSize); + if(err != KErrNone) + { + Close(); + return err; + } + iInterfaceDescriptorData = HBufC8::New(interfaceDescSize); + + if(!iInterfaceDescriptorData) + { + Close(); + return KErrNoMemory; + } + + // Get descriptor data + TPtr8 interfaceDesc = iInterfaceDescriptorData->Des(); + err = DoControl(EGetInterfaceDescriptor, &interfaceDesc); + if(err != KErrNone) + { + Close(); + return err; + } + + // Parse descriptor + TUsbGenericDescriptor* parsed = NULL; + err = UsbDescriptorParser::Parse(*iInterfaceDescriptorData, parsed); + if(err != KErrNone) + { + if(parsed) + { + parsed->DestroyTree(); //or however much has been completed + delete parsed; + } + Close(); + return err; + } + + iHeadInterfaceDescriptor = TUsbInterfaceDescriptor::Cast(parsed); + if(!iHeadInterfaceDescriptor) + { + if(parsed) + { + parsed->DestroyTree(); + delete parsed; + } + Close(); + return KErrCorrupt; + } + } + + return err; + } + +/** +Close handle to interface. + +Closes any pipe handles still open. +*/ +EXPORT_C void RUsbInterface::Close() + { + iAlternateSetting = 0; + if(iHeadInterfaceDescriptor) + { + iHeadInterfaceDescriptor->DestroyTree(); + delete iHeadInterfaceDescriptor; + iHeadInterfaceDescriptor = NULL; + } + if(iInterfaceDescriptorData) + { + delete iInterfaceDescriptorData; + iInterfaceDescriptorData = NULL; + } + if(iTransferStrategy) + { + iTransferStrategy->Close(); + delete iTransferStrategy; + iTransferStrategy = NULL; + } + RBusLogicalChannel::Close(); + } + + +EXPORT_C TInt RUsbInterface::RegisterTransferDescriptor(RUsbTransferDescriptor& aTransfer) + { + TTransferMemoryDetails details; + details.iType = aTransfer.iType; + details.iSize = aTransfer.iMaxSize; + details.iMaxPackets = aTransfer.iMaxNumPackets; + TInt err = DoControl(EGetSizeAndAlignment, &details); + if(err != KErrNone) + { + return err; + } + return iTransferStrategy->RegisterTransferDescriptor(aTransfer, details.iSize, details.iAlignment, details.iMaxPackets); + } + +EXPORT_C void RUsbInterface::ResetTransferDescriptors() + { + iTransferStrategy->ResetTransferDescriptors(); + } + +EXPORT_C TInt RUsbInterface::InitialiseTransferDescriptors() + { + return iTransferStrategy->InitialiseTransferDescriptors(*this); + } + + diff -r 466a0df5c15a -r ea2434cf3670 kernel/eka/drivers/usbho/usbdi_utils/usbpipe.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kernel/eka/drivers/usbho/usbdi_utils/usbpipe.cpp Tue May 04 18:23:12 2010 +0100 @@ -0,0 +1,31 @@ +// Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies). +// All rights reserved. +// This component and the accompanying materials are made available +// under the terms of the License "Eclipse Public License v1.0" +// which accompanies this distribution, and is available +// at the URL "http://www.eclipse.org/legal/epl-v10.html". +// +// Initial Contributors: +// Nokia Corporation - initial contribution. +// +// Contributors: +// +// Description: +// + +#include +#include + +#include "usbtransferstrategy.h" + + +/** +Queue a transfer. +@param[in] aTransfer The transfer descriptor to execute. +@param[out] aRequest Holds completion status of the transfer. +*/ +EXPORT_C void RUsbPipe::Transfer(RUsbTransferDescriptor& aTransfer, TRequestStatus& aRequest) + { + IssueTransfer(aTransfer.iHandle, aRequest); + } + diff -r 466a0df5c15a -r ea2434cf3670 kernel/eka/drivers/usbho/usbdi_utils/usbtransfers.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kernel/eka/drivers/usbho/usbdi_utils/usbtransfers.cpp Tue May 04 18:23:12 2010 +0100 @@ -0,0 +1,205 @@ +// Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies). +// All rights reserved. +// This component and the accompanying materials are made available +// under the terms of the License "Eclipse Public License v1.0" +// which accompanies this distribution, and is available +// at the URL "http://www.eclipse.org/legal/epl-v10.html". +// +// Initial Contributors: +// Nokia Corporation - initial contribution. +// +// Contributors: +// +// Description: +// + +#include + +#include +#include "usbtransferstrategy.h" +#include "usbdiutils.h" + + +// ======================== +// RUsbTransferDescriptor +// ======================== + +/** +Constructor protected to as this class is only intended as a base class. +*/ +RUsbTransferDescriptor::RUsbTransferDescriptor(TTransferType aType, TInt aMaxSize, TInt aMaxNumPackets) + : iHandle(KInvalidHandle) + , iType(aType) + , iMaxSize(aMaxSize) + , iMaxNumPackets(aMaxNumPackets) + { + } + +/** +Releases resources allocated to this transfer descriptor. +*/ +EXPORT_C void RUsbTransferDescriptor::Close() + { + // Do nothing - the buffer is owned by the {R,D}UsbInterface. + // This is provided in case the descriptor owns resources in future. + } + + +// ============================ +// RUsbIsocTransferDescriptor +// ============================ + +EXPORT_C RUsbIsocTransferDescriptor::RUsbIsocTransferDescriptor(TInt aMaxSize, TInt aMaxNumPackets) + : RUsbTransferDescriptor(EIsochronous, aMaxSize, aMaxNumPackets) + , iWriteHandle(KInvalidHandle) + { + } + +EXPORT_C void RUsbIsocTransferDescriptor::Reset() + { + __ASSERT_ALWAYS(iHandle != KInvalidHandle, UsbdiUtils::Panic(UsbdiPanics::EBadIsocTransferDescriptorHandle)); + iWriteHandle = iHandle; + iTransferStrategy->IsocReset(iHandle); + } + +EXPORT_C TPacketLengths RUsbIsocTransferDescriptor::Lengths() + { + __ASSERT_ALWAYS(iHandle != KInvalidHandle, UsbdiUtils::Panic(UsbdiPanics::EBadIsocTransferDescriptorHandle)); + return iTransferStrategy->IsocLengths(iHandle); + } + +EXPORT_C TPacketResults RUsbIsocTransferDescriptor::Results() + { + __ASSERT_ALWAYS(iHandle != KInvalidHandle, UsbdiUtils::Panic(UsbdiPanics::EBadIsocTransferDescriptorHandle)); + return iTransferStrategy->IsocResults(iHandle); + } + +EXPORT_C TInt RUsbIsocTransferDescriptor::MaxPacketSize() + { + __ASSERT_ALWAYS(iHandle != KInvalidHandle, UsbdiUtils::Panic(UsbdiPanics::EBadIsocTransferDescriptorHandle)); + return iTransferStrategy->IsocMaxPacketSize(iHandle); + } + +EXPORT_C TPtr8 RUsbIsocTransferDescriptor::WritablePackets(TInt aNumPacketsRequested, TInt& aMaxNumOfPacketsAbleToWrite) + { + __ASSERT_ALWAYS(iHandle != KInvalidHandle, UsbdiUtils::Panic(UsbdiPanics::EBadIsocTransferDescriptorHandle)); + if(iWriteHandle == KInvalidHandle) + { + return TPtr8(NULL, 0); + } + return iTransferStrategy->IsocWritablePackets(iHandle, iWriteHandle, aNumPacketsRequested, aMaxNumOfPacketsAbleToWrite); + } + +EXPORT_C void RUsbIsocTransferDescriptor::SaveMultiple(TInt aNumOfPackets) + { + __ASSERT_ALWAYS(iHandle != KInvalidHandle, UsbdiUtils::Panic(UsbdiPanics::EBadIsocTransferDescriptorHandle)); + __ASSERT_ALWAYS(iWriteHandle != KInvalidHandle, UsbdiUtils::Panic(UsbdiPanics::EBadIsocTransferDescriptorWriteHandle)); + TInt writeHandle = iTransferStrategy->IsocSaveMultiple(iHandle, iWriteHandle, aNumOfPackets); + iWriteHandle = (writeHandle < 0) ? KInvalidHandle : writeHandle; + } + +EXPORT_C TPtrC8 RUsbIsocTransferDescriptor::Packets(TInt aFirstPacketIndex, TInt aNumPacketsRequested, TInt& aNumOfPacketsReturned) const + { + __ASSERT_ALWAYS(iHandle != KInvalidHandle, UsbdiUtils::Panic(UsbdiPanics::EBadIsocTransferDescriptorHandle)); + return iTransferStrategy->IsocPackets(iHandle, aFirstPacketIndex, aNumPacketsRequested, aNumOfPacketsReturned); + } + +EXPORT_C void RUsbIsocTransferDescriptor::ReceivePackets(TInt aNumOfPackets) + { + __ASSERT_ALWAYS(iHandle != KInvalidHandle, UsbdiUtils::Panic(UsbdiPanics::EBadIsocTransferDescriptorHandle)); + iTransferStrategy->IsocReceivePackets(iHandle, aNumOfPackets); + } + + +// ============================ +// RUsbBulkTransferDescriptor +// ============================ + +EXPORT_C RUsbBulkTransferDescriptor::RUsbBulkTransferDescriptor(TInt aMaxSize) + : RUsbTransferDescriptor(EBulk, aMaxSize, 0) + { + } + +/** +@return A modifiable pointer to the entire data buffer. +*/ +EXPORT_C TPtr8 RUsbBulkTransferDescriptor::WritableBuffer() + { + __ASSERT_ALWAYS(iHandle != KInvalidHandle, UsbdiUtils::Panic(UsbdiPanics::EBadBulkTransferDescriptorHandle)); + return iTransferStrategy->BulkWritableBuffer(iHandle); + } + +/** +Update the transfer descriptor given the length of data supplied. +@param[in] aLength Length of data to write or expect. +*/ +EXPORT_C void RUsbBulkTransferDescriptor::SaveData(TInt aLength) + { + __ASSERT_ALWAYS(iHandle != KInvalidHandle, UsbdiUtils::Panic(UsbdiPanics::EBadBulkTransferDescriptorHandle)); + iTransferStrategy->BulkSaveData(iHandle, aLength); + } + +/** +@return A non-modifiable pointer to the entire data buffer. +*/ +EXPORT_C TPtrC8 RUsbBulkTransferDescriptor::Buffer() const + { + __ASSERT_ALWAYS(iHandle != KInvalidHandle, UsbdiUtils::Panic(UsbdiPanics::EBadBulkTransferDescriptorHandle)); + return iTransferStrategy->BulkBuffer(iHandle); + } + +/** +@param aZlpStatus the ZLP type to use for the transfer +*/ +EXPORT_C void RUsbBulkTransferDescriptor::SetZlpStatus(TZlpStatus aZlpStatus) + { + __ASSERT_ALWAYS(iHandle != KInvalidHandle, UsbdiUtils::Panic(UsbdiPanics::EBadBulkTransferDescriptorHandle)); + iTransferStrategy->BulkSetZlpStatus(iHandle, aZlpStatus); + } + + +// ============================ +// RUsbIntrTransferDescriptor +// ============================ + +EXPORT_C RUsbIntrTransferDescriptor::RUsbIntrTransferDescriptor(TInt aMaxSize) + : RUsbTransferDescriptor(EInterrupt, aMaxSize, 0) + { + } + +/** +@return A modifiable pointer to the entire data buffer. +*/ +EXPORT_C TPtr8 RUsbIntrTransferDescriptor::WritableBuffer() + { + __ASSERT_ALWAYS(iHandle != KInvalidHandle, UsbdiUtils::Panic(UsbdiPanics::EBadIntrTransferDescriptorHandle)); + return iTransferStrategy->IntrWritableBuffer(iHandle); + } + +/** +Update the transfer descriptor given the length of data supplied. +@param[in] aLength Length of data to write or expect. +*/ +EXPORT_C void RUsbIntrTransferDescriptor::SaveData(TInt aLength) + { + __ASSERT_ALWAYS(iHandle != KInvalidHandle, UsbdiUtils::Panic(UsbdiPanics::EBadIntrTransferDescriptorHandle)); + iTransferStrategy->IntrSaveData(iHandle, aLength); + } + +/** +@return A non-modifiable pointer to the entire data buffer. +*/ +EXPORT_C TPtrC8 RUsbIntrTransferDescriptor::Buffer() const + { + __ASSERT_ALWAYS(iHandle != KInvalidHandle, UsbdiUtils::Panic(UsbdiPanics::EBadIntrTransferDescriptorHandle)); + return iTransferStrategy->IntrBuffer(iHandle); + } + +/** +@param aZlpStatus the ZLP type to use for the transfer +*/ +EXPORT_C void RUsbIntrTransferDescriptor::SetZlpStatus(TZlpStatus aZlpStatus) + { + __ASSERT_ALWAYS(iHandle != KInvalidHandle, UsbdiUtils::Panic(UsbdiPanics::EBadIntrTransferDescriptorHandle)); + return iTransferStrategy->IntrSetZlpStatus(iHandle, aZlpStatus); + } diff -r 466a0df5c15a -r ea2434cf3670 kernel/eka/drivers/usbho/usbdi_utils/usbtransferstrategy.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kernel/eka/drivers/usbho/usbdi_utils/usbtransferstrategy.cpp Tue May 04 18:23:12 2010 +0100 @@ -0,0 +1,114 @@ +// Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies). +// All rights reserved. +// This component and the accompanying materials are made available +// under the terms of the License "Eclipse Public License v1.0" +// which accompanies this distribution, and is available +// at the URL "http://www.eclipse.org/legal/epl-v10.html". +// +// Initial Contributors: +// Nokia Corporation - initial contribution. +// +// Contributors: +// +// Description: +// + +#include "usbtransferstrategy.h" + +#include +#include +#include "usbdiutils.h" + + +TPacketLengths::TPacketLengths(TUint16* aRecvPtr, TUint16* aReqPtr, TInt& aMaxNumPackets) + : iRecvPtr(aRecvPtr) + , iReqPtr(aReqPtr) + , iMaxNumPackets(aMaxNumPackets) + {} + +EXPORT_C TPacketLengths::TLength TPacketLengths::At(TInt aIndex) + { + __ASSERT_ALWAYS(aIndex >= 0 && aIndex < iMaxNumPackets, UsbdiUtils::Panic(UsbdiPanics::EOutOfBoundsOfLengthArray)); + return TPacketLengths::TLength(*(iRecvPtr + aIndex), *(iReqPtr + aIndex)); + } + +EXPORT_C const TPacketLengths::TLength TPacketLengths::At(TInt aIndex) const + { + __ASSERT_ALWAYS(aIndex >= 0 && aIndex < iMaxNumPackets, UsbdiUtils::Panic(UsbdiPanics::EOutOfBoundsOfLengthArray)); + return TPacketLengths::TLength(*(iRecvPtr + aIndex), *(iReqPtr + aIndex)); + } + +EXPORT_C TPacketLengths::TLength TPacketLengths::operator[](TInt aIndex) + { + return At(aIndex); + } + +EXPORT_C const TPacketLengths::TLength TPacketLengths::operator[](TInt aIndex) const + { + return At(aIndex); + } + +EXPORT_C TInt TPacketLengths::MaxNumPackets() + { + return iMaxNumPackets; + } + +EXPORT_C TUint16 TPacketLengths::TLength::operator=(TUint16 aValue) + { + iRecv = aValue; + iReq = aValue; + return aValue; + } + +EXPORT_C TPacketLengths::TLength::operator TUint16() const + { + return iRecv; + } + +TPacketLengths::TLength::TLength(TUint16& aRecv, TUint16& aReq) + : iRecv(aRecv) + , iReq(aReq) + { + } + + +TPacketResults::TPacketResults(TInt* aResPtr, TInt& aMaxNumPackets) + : iResPtr(aResPtr) + , iMaxNumPackets(aMaxNumPackets) + { + } + +EXPORT_C TInt TPacketResults::At(TInt aIndex) const + { + __ASSERT_ALWAYS(aIndex >= 0 && aIndex < iMaxNumPackets, UsbdiUtils::Panic(UsbdiPanics::EOutOfBoundsOfResultArray)); + return *(iResPtr + aIndex); + } + +EXPORT_C TInt TPacketResults::operator[](TInt aIndex) const + { + return At(aIndex); + } + +EXPORT_C TInt TPacketResults::MaxNumPackets() + { + return iMaxNumPackets; + } + + + +void RUsbTransferStrategy::Close() + { + // Doesn't currently own any resources. + } + +void RUsbTransferStrategy::SetTransferHandle(RUsbTransferDescriptor& aTransfer, TInt aHandle) const + { + aTransfer.iHandle = aHandle; + aTransfer.iTransferStrategy = const_cast(this); + if(aTransfer.iType == RUsbTransferDescriptor::EIsochronous) + { + static_cast(aTransfer).iWriteHandle = aHandle; + } + } + + diff -r 466a0df5c15a -r ea2434cf3670 kernel/eka/drivers/usbho/usbdi_utils/usbtransferstrategy.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kernel/eka/drivers/usbho/usbdi_utils/usbtransferstrategy.h Tue May 04 18:23:12 2010 +0100 @@ -0,0 +1,64 @@ +// Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies). +// All rights reserved. +// This component and the accompanying materials are made available +// under the terms of the License "Eclipse Public License v1.0" +// which accompanies this distribution, and is available +// at the URL "http://www.eclipse.org/legal/epl-v10.html". +// +// Initial Contributors: +// Nokia Corporation - initial contribution. +// +// Contributors: +// +// Description: +// + +/** + @file + @internalComponent +*/ + +#ifndef USBTRANSFERSTRATEGY_H +#define USBTRANSFERSTRATEGY_H + +#include +#include + + +NONSHARABLE_CLASS(RUsbTransferStrategy) + { +public: + virtual void Close(); + + virtual TInt RegisterTransferDescriptor(RUsbTransferDescriptor& aTransferDesc, TInt aRequiredSize, TUint aStartAlignment, TInt aRequiredMaxPackets) =0; + virtual void ResetTransferDescriptors() =0; + virtual TInt InitialiseTransferDescriptors(RUsbInterface& aInterface) =0; + +public: // Interrupt transfer descriptor methods + virtual TPtr8 IntrWritableBuffer(TInt aHandle) =0; + virtual void IntrSaveData(TInt aHandle, TInt aLength) =0; + virtual void IntrSetZlpStatus(TInt aHandle, RUsbTransferDescriptor::TZlpStatus aZlpStatus) =0; + virtual TPtrC8 IntrBuffer(TInt aHandle) const =0; + +public: // Bulk transfer descriptor methods + virtual TPtr8 BulkWritableBuffer(TInt aHandle) =0; + virtual void BulkSaveData(TInt aHandle, TInt aLength) =0; + virtual void BulkSetZlpStatus(TInt aHandle, RUsbTransferDescriptor::TZlpStatus aZlpStatus) =0; + virtual TPtrC8 BulkBuffer(TInt aHandle) const =0; + +public: // Isochronous transfer descriptor methods + virtual void IsocReset(TInt aHandle) =0; + virtual TPacketLengths IsocLengths(TInt aHandle) =0; + virtual TPacketResults IsocResults(TInt aHandle) =0; + virtual TInt IsocMaxPacketSize(TInt aHandle) =0; + virtual TPtr8 IsocWritablePackets(TInt aHandle, TInt aWriteHandle, TInt aNumPacketsRequested, TInt& aMaxNumPacketsAbleToWrite) =0; + virtual TInt IsocSaveMultiple(TInt aHandle, TInt aWriteHandle, TInt aNumOfPackets) =0; + virtual TPtrC8 IsocPackets(TInt aHandle, TInt aFirstPacketIndex, TInt aNumPacketsRequested, TInt& aNumPacketsReturned) const =0; + virtual void IsocReceivePackets(TInt aHandle, TInt aNumOfPackets) =0; + +protected: + void SetTransferHandle(RUsbTransferDescriptor& aTransfer, TInt aHandle) const; + }; + + +#endif // USBTRANSFERSTRATEGY_H diff -r 466a0df5c15a -r ea2434cf3670 kernel/eka/drivers/usbho/usbdi_utils/zerocopymetadata.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kernel/eka/drivers/usbho/usbdi_utils/zerocopymetadata.h Tue May 04 18:23:12 2010 +0100 @@ -0,0 +1,152 @@ +// Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies). +// All rights reserved. +// This component and the accompanying materials are made available +// under the terms of the License "Eclipse Public License v1.0" +// which accompanies this distribution, and is available +// at the URL "http://www.eclipse.org/legal/epl-v10.html". +// +// Initial Contributors: +// Nokia Corporation - initial contribution. +// +// Description: +// + +/** + @file + @internalComponent +*/ + +#ifndef ZEROCOPYMETADATA_H +#define ZEROCOPYMETADATA_H + +#include + +// The type used to represent an address various betwen user and kernel +// mode. To aid us we use a macro to produce only one definition. +#ifndef __KERNEL_MODE__ +#define TAddrType TUint8* +#else // __KERNEL_MODE__ +#define TAddrType TLinAddr +#endif // __KERNEL_MODE__ + + +NONSHARABLE_CLASS(UsbZeroCopyChunkHeaderBase) + { +public: + static inline RUsbTransferDescriptor::TTransferType& TransferType(TAddrType aBase, TInt aHeaderOffset); +protected: + enum THeaderBaseSizes + { + ETransferTypeSize = sizeof(RUsbTransferDescriptor::TTransferType) + }; + enum THeaderBaseLayout + { + ETransferType = 0, + // End of fields + EHeaderBaseSize = ETransferType + ETransferTypeSize + }; + }; + + +NONSHARABLE_CLASS(UsbZeroCopyBulkIntrChunkHeader) : public UsbZeroCopyChunkHeaderBase + { +public: + static inline TInt HeaderSize(); + + static inline TInt& DataOffset(TAddrType aBase, TInt aHeaderOffset); + static inline TInt& DataLength(TAddrType aBase, TInt aHeaderOffset); + static inline TInt& DataMaxLength(TAddrType aBase, TInt aHeaderOffset); + static inline RUsbTransferDescriptor::TZlpStatus& ZlpStatus(TAddrType aBase, TInt aHeaderOffset); +private: + enum THeaderSizes + { + EDataOffsetSize = sizeof(TInt), + EDataLengthSize = sizeof(TInt), + EDataMaxLengthSize = sizeof(TInt), + EZlpStatusSize = sizeof(RUsbTransferDescriptor::TZlpStatus) + }; + enum THeaderLayout + { + EDataOffset = EHeaderBaseSize, + EDataLength = EDataOffset + EDataOffsetSize, + EDataMaxLength = EDataLength + EDataLengthSize, + EZlpStatus = EDataMaxLength + EDataMaxLengthSize, + // End of fields + EHeaderSize = EZlpStatus + EZlpStatusSize + }; + }; + + +NONSHARABLE_CLASS(UsbZeroCopyIsocChunkHeader) : public UsbZeroCopyChunkHeaderBase + { +public: // Lengths Array constants + static const TInt KLengthsElementSize = sizeof(TUint16); + static const TInt KResultsElementSize = sizeof(TInt); +public: + static inline TInt HeaderSize(); + + static inline TInt& FirstElementOffset(TAddrType aBase, TInt aHeaderOffset); + static inline TInt& MaxNumPackets(TAddrType aBase, TInt aHeaderOffset); + static inline TInt& MaxPacketSize(TAddrType aBase, TInt aHeaderOffset); + static inline TInt& LengthsOffset(TAddrType aBase, TInt aHeaderOffset); + static inline TInt& ReqLenOffset(TAddrType aBase, TInt aHeaderOffset); + static inline TInt& ResultsOffset(TAddrType aBase, TInt aHeaderOffset); +private: + enum THeaderSizes + { + EFirstElementOffsetSize = sizeof(TInt), + EMaxNumPacketsSize = sizeof(TInt), + EMaxPacketSizeSize = sizeof(TInt), + ELengthsOffsetSize = sizeof(TInt), + EReqLenOffsetSize = sizeof(TInt), + EResultsOffsetSize = sizeof(TInt) + }; + enum THeaderLayout + { + EFirstElementOffset = EHeaderBaseSize, + EMaxNumPackets = EFirstElementOffset + EFirstElementOffsetSize, + EMaxPacketSize = EMaxNumPackets + EMaxNumPacketsSize, + ELengthsOffset = EMaxPacketSize + EMaxPacketSizeSize, + EReqLenOffset = ELengthsOffset + ELengthsOffsetSize, + EResultsOffset = EReqLenOffset + EReqLenOffsetSize, + // End of fields + EHeaderSize = EResultsOffset + EResultsOffsetSize + }; + }; + + +NONSHARABLE_CLASS(UsbZeroCopyIsocChunkElement) + { +public: + // NumOfPackets constants + static const TInt KInvalidElement = -1; + // NextElementOffset constants + static const TInt KEndOfList = -1; +public: + static inline TInt ElementSize(); + + static inline TInt& DataOffset(TAddrType aBase, TInt aHeaderOffset); + static inline TInt& NumPackets(TAddrType aBase, TInt aHeaderOffset); + static inline TInt& NextElementOffset(TAddrType aBase, TInt aHeaderOffset); +private: + enum THeaderSizes + { + EDataOffsetSize = sizeof(TInt), + ENumPacketsSize = sizeof(TInt), + ENextElementOffsetSize = sizeof(TInt), + }; + enum THeaderLayout + { + EDataOffset = 0, + ENumPackets = EDataOffset + EDataOffsetSize, + ENextElementOffset = ENumPackets + ENumPacketsSize, + // End of fields + EElementSize = ENextElementOffset + ENextElementOffsetSize + }; + }; + +#include "zerocopymetadata.inl" + +#undef TAddrType // Prevent the macro from leaking outside this header + +#endif // ZEROCOPYMETADATA_H diff -r 466a0df5c15a -r ea2434cf3670 kernel/eka/drivers/usbho/usbdi_utils/zerocopymetadata.inl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kernel/eka/drivers/usbho/usbdi_utils/zerocopymetadata.inl Tue May 04 18:23:12 2010 +0100 @@ -0,0 +1,141 @@ +// Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies). +// All rights reserved. +// This component and the accompanying materials are made available +// under the terms of the License "Eclipse Public License v1.0" +// which accompanies this distribution, and is available +// at the URL "http://www.eclipse.org/legal/epl-v10.html". +// +// Initial Contributors: +// Nokia Corporation - initial contribution. +// +// Description: +// + +/** + @file + @internalComponent +*/ + + +template +inline XReturnType& Field(TAddrType aBase, TInt aHeaderOffset) + { + TInt offset = aHeaderOffset + XFieldOffset; + return *reinterpret_cast(aBase + offset); + } + + +// +// UsbZeroCopyChunkHeaderBase +// + +inline RUsbTransferDescriptor::TTransferType& UsbZeroCopyChunkHeaderBase::TransferType(TAddrType aBase, TInt aHeaderOffset) + { + return Field(aBase, aHeaderOffset); + } + + + +// +// UsbZeroCopyBulkIntrChunkHeader +// + +inline TInt UsbZeroCopyBulkIntrChunkHeader::HeaderSize() + { + __ASSERT_COMPILE(EHeaderSize % sizeof(TInt) == 0); + return EHeaderSize; + } + + +inline TInt& UsbZeroCopyBulkIntrChunkHeader::DataOffset(TAddrType aBase, TInt aHeaderOffset) + { + return Field(aBase, aHeaderOffset); + } + +inline TInt& UsbZeroCopyBulkIntrChunkHeader::DataLength(TAddrType aBase, TInt aHeaderOffset) + { + return Field(aBase, aHeaderOffset); + } + +inline TInt& UsbZeroCopyBulkIntrChunkHeader::DataMaxLength(TAddrType aBase, TInt aHeaderOffset) + { + return Field(aBase, aHeaderOffset); + } + +inline RUsbTransferDescriptor::TZlpStatus& UsbZeroCopyBulkIntrChunkHeader::ZlpStatus(TAddrType aBase, TInt aHeaderOffset) + { + return Field(aBase, aHeaderOffset); + } + + + +// +// UsbZeroCopyIsocChunkHeader +// + +inline TInt UsbZeroCopyIsocChunkHeader::HeaderSize() + { + __ASSERT_COMPILE(EHeaderSize % sizeof(TInt) == 0); + return EHeaderSize; + } + + +inline TInt& UsbZeroCopyIsocChunkHeader::FirstElementOffset(TAddrType aBase, TInt aHeaderOffset) + { + return Field(aBase, aHeaderOffset); + } + +inline TInt& UsbZeroCopyIsocChunkHeader::MaxNumPackets(TAddrType aBase, TInt aHeaderOffset) + { + return Field(aBase, aHeaderOffset); + } + +inline TInt& UsbZeroCopyIsocChunkHeader::MaxPacketSize(TAddrType aBase, TInt aHeaderOffset) + { + return Field(aBase, aHeaderOffset); + } + +inline TInt& UsbZeroCopyIsocChunkHeader::LengthsOffset(TAddrType aBase, TInt aHeaderOffset) + { + return Field(aBase, aHeaderOffset); + } + +inline TInt& UsbZeroCopyIsocChunkHeader::ReqLenOffset(TAddrType aBase, TInt aHeaderOffset) + { + return Field(aBase, aHeaderOffset); + } + +inline TInt& UsbZeroCopyIsocChunkHeader::ResultsOffset(TAddrType aBase, TInt aHeaderOffset) + { + return Field(aBase, aHeaderOffset); + } + + + +// +// UsbZeroCopyIsocChunkHeader +// + +inline TInt UsbZeroCopyIsocChunkElement::ElementSize() + { + __ASSERT_COMPILE(EElementSize % sizeof(TInt) == 0); + return EElementSize; + } + + +inline TInt& UsbZeroCopyIsocChunkElement::DataOffset(TAddrType aBase, TInt aHeaderOffset) + { + return Field(aBase, aHeaderOffset); + } + +inline TInt& UsbZeroCopyIsocChunkElement::NumPackets(TAddrType aBase, TInt aHeaderOffset) + { + return Field(aBase, aHeaderOffset); + } + +inline TInt& UsbZeroCopyIsocChunkElement::NextElementOffset(TAddrType aBase, TInt aHeaderOffset) + { + return Field(aBase, aHeaderOffset); + } + + diff -r 466a0df5c15a -r ea2434cf3670 kernel/eka/drivers/usbho/usbdi_utils/zerocopytransferstrategy.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kernel/eka/drivers/usbho/usbdi_utils/zerocopytransferstrategy.cpp Tue May 04 18:23:12 2010 +0100 @@ -0,0 +1,982 @@ +// Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies). +// All rights reserved. +// This component and the accompanying materials are made available +// under the terms of the License "Eclipse Public License v1.0" +// which accompanies this distribution, and is available +// at the URL "http://www.eclipse.org/legal/epl-v10.html". +// +// Initial Contributors: +// Nokia Corporation - initial contribution. +// +// Contributors: +// +// Description: +// + +#include "zerocopytransferstrategy.h" + +#include +#include +#include +#include "zerocopymetadata.h" +#include "usbdiutils.h" + + +RUsbZeroCopyTransferStrategy::TUsbTransferDescriptorDetails::TUsbTransferDescriptorDetails(RUsbTransferDescriptor& aTransferDesc, TInt aRequiredSize, TUint aRequiredAlignment, TInt aRequiredMaxPackets) + : iTransferDesc(aTransferDesc) + , iRequiredSize(aRequiredSize) + , iRequiredAlignment(aRequiredAlignment) + , iRequiredMaxPackets(aRequiredMaxPackets) + { + } + +RUsbZeroCopyTransferStrategy::RUsbZeroCopyTransferStrategy() + : iInterfaceHandle(NULL) + { + } + + +void RUsbZeroCopyTransferStrategy::Close() + { + iInterfaceHandle = NULL; + iChunk.Close(); + iRegisteredTransfers.Close(); + RUsbTransferStrategy::Close(); + } + + +TInt RUsbZeroCopyTransferStrategy::RegisterTransferDescriptor(RUsbTransferDescriptor& aTransferDesc, TInt aRequiredSize, TUint aStartAlignment, TInt aRequiredMaxPackets) + { + __ASSERT_ALWAYS(!iInterfaceHandle, UsbdiUtils::Panic(UsbdiPanics::ETransferDescriptorsAlreadyRegistered)); + if (iRegisteredTransfers.Find(aTransferDesc, CompareTransferDescriptor) != KErrNotFound) + { + return KErrAlreadyExists; + } + return iRegisteredTransfers.Append(TUsbTransferDescriptorDetails(aTransferDesc, aRequiredSize, aStartAlignment, aRequiredMaxPackets)); + } + +TBool RUsbZeroCopyTransferStrategy::CompareTransferDescriptor(const RUsbTransferDescriptor* aTransferDesc, const TUsbTransferDescriptorDetails& aDetails) + { + return aTransferDesc == &aDetails.iTransferDesc; + } + + +void RUsbZeroCopyTransferStrategy::ResetTransferDescriptors() + { + __ASSERT_ALWAYS(!iInterfaceHandle, UsbdiUtils::Panic(UsbdiPanics::ETransferDescriptorsAlreadyRegistered)); + iRegisteredTransfers.Reset(); + } + + +TInt RUsbZeroCopyTransferStrategy::InitialiseTransferDescriptors(RUsbInterface& aInterface) + { + __ASSERT_ALWAYS(!iInterfaceHandle, UsbdiUtils::Panic(UsbdiPanics::ETransferDescriptorsAlreadyRegistered)); + + // This is the equivilent of a standard R-class Open() method, so initialise the references + // we are going to use. + iInterfaceHandle = &aInterface; + + // First get the page-size as we will need this for isoc transfer calculations. + TInt hcdPageSize = 0; + TInt err = aInterface.GetHcdPageSize(hcdPageSize); + if (err != KErrNone) + { + Close(); // roll back + return err; + } + iPageSize = hcdPageSize; + + TInt currentOffset = 0; + TInt numStandardTransfers = 0; + TInt numIsocTransfers = 0; + TInt numIsocElements = 0; + err = CalculateDataLayout(currentOffset, numStandardTransfers, numIsocTransfers, numIsocElements); + if (err != KErrNone) + { + Close(); // roll back + return err; + } + + TInt metaDataStart = 0; + CalculateMetaDataLayout(currentOffset, metaDataStart, numStandardTransfers, numIsocTransfers, numIsocElements); + + // currentOffset should now be just past the region required for all the data and meta data. + // Therefore it equals the total size of the buffer we need to hold them all. + err = iInterfaceHandle->AllocateSharedChunk(iChunk, currentOffset, iBaseOffset); + if (err != KErrNone) + { + Close(); // roll back + return err; + } + + InitialiseMetaData(metaDataStart, numStandardTransfers, numIsocTransfers, numIsocElements); + + return KErrNone; + } + +TInt RUsbZeroCopyTransferStrategy::CalculateDataLayout(TInt& aCurrentOffset, TInt& aNumStandardTransfers, TInt& aNumIsocTransfers, TInt& aNumIsocElements) + { + const TUint32 pageAddrBits = iPageSize-1; + const TUint32 pageTableMask = ~pageAddrBits; + + //Get the maximum wMaxPacketSize of the associated interface for Bulk/Interrupt EPs + TInt maxMaxBulk = 0; + TInt maxMaxInterrupt = 0; + TInt err = GetMaximumMaxPacketSize(maxMaxBulk, maxMaxInterrupt); + if (err != KErrNone) + { + return err; + } + + // Work out where to place the transfers, and how much space is needed. + TInt numTransfers = iRegisteredTransfers.Count(); + for (TInt i=0; i < numTransfers; ++i) + { + TUsbTransferDescriptorDetails& details = iRegisteredTransfers[i]; + + err = CaculateAdditionalAlignment(aCurrentOffset, maxMaxBulk, maxMaxInterrupt, details); + if (err != KErrNone) + { + return err; + } + + // only allow intra-page alignment requests that are powers of 2 (so offset agnostic). + __ASSERT_ALWAYS(details.iRequiredAlignment <= iPageSize, UsbdiUtils::Panic(UsbdiPanics::ETransferDescriptorAlignmentOverPageBoundary)); + __ASSERT_ALWAYS(IsPowerOfTwo(details.iRequiredAlignment), UsbdiUtils::Panic(UsbdiPanics::ETransferDescriptorAlignmentNotPowerOfTwo)); + + TInt alignPad = IncNeededToAlign(aCurrentOffset, details.iRequiredAlignment); + __ASSERT_DEBUG(alignPad < iPageSize, UsbdiUtils::Fault(UsbdiFaults::EUsbTransferDescriptorBadAlignment)); // just re-asserting what should be guarded above + aCurrentOffset += alignPad; // Align to the start of transfer buffer + + // There are stark differences between isoc transfers and transfer of other types. + if (details.iTransferDesc.iType == RUsbTransferDescriptor::EIsochronous) + { + // First do some Isoc specific checks + __ASSERT_ALWAYS(details.iRequiredMaxPackets > 0, UsbdiUtils::Panic(UsbdiPanics::ETransferDescriptorNoPacketsRequested)); + + // For the allocation we have to consider the worse case - that is that the max + // number of packets at the max packet size. + // We are constrained by the USB stack to not allow transfers across page boundaries. + + // As such we calculate how many packets we can fit into a page to determine the + // number of pages for data we need. + const TInt packetsPerPage = iPageSize/details.iRequiredSize; + + // Assign the start to an appropriate point. + details.iAssignedOffset = aCurrentOffset; + TInt packetsToStore = details.iRequiredMaxPackets; + TInt numElements = 0; // for counting up the number of pages we need meta-data for. + + // The size requried to hold a length array for the descriptor + const TInt lengthsArrayLength = UsbZeroCopyIsocChunkHeader::KLengthsElementSize * details.iRequiredMaxPackets; + // The size required to hold a result array for the descriptor + const TInt resultsArrayLength = UsbZeroCopyIsocChunkHeader::KResultsElementSize * details.iRequiredMaxPackets; + + // Determine how much we can fit into the remaining space of the current page. + TBool samePage = (pageTableMask & aCurrentOffset) == (pageTableMask & (aCurrentOffset - alignPad)); + if (samePage) + { + TInt remainingSpace = iPageSize - (pageAddrBits & aCurrentOffset); + TInt packetsThatFit = remainingSpace / details.iRequiredSize; + if (packetsThatFit >= packetsToStore) + { + // We can fit it in this page so we finish here - this is the special case. + aCurrentOffset += packetsToStore * details.iRequiredSize; + ++aNumIsocElements; + ++aNumIsocTransfers; + details.iNumElements = 1; + // Do the lengths array + aCurrentOffset += IncNeededToAlign(aCurrentOffset, UsbZeroCopyIsocChunkHeader::KLengthsElementSize); + details.iLengthsOffset = aCurrentOffset; + aCurrentOffset += lengthsArrayLength; + // The dual lengths array should be implicitly alligned + details.iReqLenOffset = aCurrentOffset; + aCurrentOffset += lengthsArrayLength; + // Now handle the results array + aCurrentOffset += IncNeededToAlign(aCurrentOffset, UsbZeroCopyIsocChunkHeader::KResultsElementSize); + details.iResultsOffset = aCurrentOffset; + aCurrentOffset += resultsArrayLength; + continue; + } + aCurrentOffset = (pageTableMask & aCurrentOffset) + iPageSize; // Advance to next page + packetsToStore -= packetsThatFit; + ++numElements; + } + __ASSERT_DEBUG(packetsToStore > 0, UsbdiUtils::Fault(UsbdiFaults::EUsbTransferDescriptorNoPacketsLeftToStore)); + + // Determine the number of pages extra that are needed (minus one) + TInt pagesRequired = packetsToStore / packetsPerPage; + + // Determine how much of the last page is actually needed. + TInt trailingPackets = packetsToStore % packetsPerPage; + TInt usedSpace = trailingPackets * details.iRequiredSize; + + // Commit the amount for the buffers. + aCurrentOffset += usedSpace + pagesRequired*iPageSize; + numElements += pagesRequired + /*the final page*/1; // We have already included the first page (if already partially used) + aNumIsocElements += numElements; + ++aNumIsocTransfers; + + // Used to ensure only allocate an appropriate number per-descriptor. + details.iNumElements = numElements; + + // We also need an array of lengths for each packet that we use (need to align to even bytes). + aCurrentOffset += IncNeededToAlign(aCurrentOffset, UsbZeroCopyIsocChunkHeader::KLengthsElementSize); + details.iLengthsOffset = aCurrentOffset; + aCurrentOffset += lengthsArrayLength; + // Dual length array should be implicitly aligned + details.iReqLenOffset = aCurrentOffset; + aCurrentOffset += lengthsArrayLength; + // Now handle the results array + aCurrentOffset += IncNeededToAlign(aCurrentOffset, UsbZeroCopyIsocChunkHeader::KResultsElementSize); + details.iResultsOffset = aCurrentOffset; + aCurrentOffset += resultsArrayLength; + } + else + { + details.iAssignedOffset = aCurrentOffset; + aCurrentOffset += details.iRequiredSize; + ++aNumStandardTransfers; + } + } + + return KErrNone; + } + + +void RUsbZeroCopyTransferStrategy::CalculateMetaDataLayout(TInt& aCurrentOffset, TInt& aMetaDataStart, TInt aNumStandardTransfers, TInt aNumIsocTransfers, TInt aNumIsocElements) + { + // Round up to 4 byte alignment for handling the meta-data correctly. + aCurrentOffset += IncNeededToAlign(aCurrentOffset, sizeof(TInt)); + + aMetaDataStart = aCurrentOffset; + + // Now calculate the size required for the transfer meta-data. + aCurrentOffset += aNumStandardTransfers * UsbZeroCopyBulkIntrChunkHeader::HeaderSize(); + aCurrentOffset += aNumIsocTransfers * UsbZeroCopyIsocChunkHeader::HeaderSize(); + aCurrentOffset += aNumIsocElements * UsbZeroCopyIsocChunkElement::ElementSize(); + } + +void RUsbZeroCopyTransferStrategy::InitialiseMetaData(TInt aMetaDataOffset, TInt aNumStandardTransfers, TInt aNumIsocTransfers, TInt aNumIsocElements) + { + const TUint32 pageAddrBits = iPageSize-1; + const TUint32 pageTableMask = ~pageAddrBits; + + TUint8* chunkBase = iChunk.Base() + iBaseOffset; + + TInt numTransfers = iRegisteredTransfers.Count(); + for (TInt i=0; i < numTransfers; ++i) + { + TUsbTransferDescriptorDetails details = iRegisteredTransfers[i]; + + if (details.iTransferDesc.iType == RUsbTransferDescriptor::EIsochronous) + { + // Initialise Meta-data (minus elements). + UsbZeroCopyIsocChunkHeader::TransferType(chunkBase, aMetaDataOffset) = details.iTransferDesc.iType; + UsbZeroCopyIsocChunkHeader::MaxNumPackets(chunkBase, aMetaDataOffset) = details.iRequiredMaxPackets; + UsbZeroCopyIsocChunkHeader::MaxPacketSize(chunkBase, aMetaDataOffset) = details.iRequiredSize; + // Double check that the length array is aligned correctly. + __ASSERT_DEBUG(details.iLengthsOffset % UsbZeroCopyIsocChunkHeader::KLengthsElementSize == 0, + UsbdiUtils::Fault(UsbdiFaults::EUsbTransferDescriptorLengthsArrayBadAlignment)); + UsbZeroCopyIsocChunkHeader::LengthsOffset(chunkBase, aMetaDataOffset) = details.iLengthsOffset; + UsbZeroCopyIsocChunkHeader::ReqLenOffset(chunkBase, aMetaDataOffset) = details.iReqLenOffset; + // Double check that the result array is aligned correctly. + __ASSERT_DEBUG(details.iResultsOffset % UsbZeroCopyIsocChunkHeader::KResultsElementSize == 0, + UsbdiUtils::Fault(UsbdiFaults::EUsbTransferDescriptorResultsArrayBadAlignment)); + UsbZeroCopyIsocChunkHeader::ResultsOffset(chunkBase, aMetaDataOffset) = details.iResultsOffset; + // Initialise transfer descriptor + SetTransferHandle(details.iTransferDesc, aMetaDataOffset); + // Move on to next meta-data slot + TInt prevMetaOffset = aMetaDataOffset; + aMetaDataOffset += UsbZeroCopyIsocChunkHeader::HeaderSize(); + + // Initialise elements for transfers + UsbZeroCopyIsocChunkHeader::FirstElementOffset(chunkBase, prevMetaOffset) = aMetaDataOffset; + + TInt isocElementsUnmapped = details.iNumElements; + // First element could be anywhere, the others are at the start of (virtually) contiguous pages + TInt offset = details.iAssignedOffset; + while (isocElementsUnmapped > 0) + { + // Update the data references + UsbZeroCopyIsocChunkElement::DataOffset(chunkBase, aMetaDataOffset) = offset; + UsbZeroCopyIsocChunkElement::NumPackets(chunkBase, aMetaDataOffset) = 0; // Default value. + // Move on to the next element and bind it to the chain. + prevMetaOffset = aMetaDataOffset; + aMetaDataOffset += UsbZeroCopyIsocChunkElement::ElementSize(); + UsbZeroCopyIsocChunkElement::NextElementOffset(chunkBase, prevMetaOffset) = aMetaDataOffset; + // Move to the next page + offset = (pageTableMask&offset)+iPageSize; + --isocElementsUnmapped; + --aNumIsocElements; + } + // We have reached the end of the list so we should update the next element offset for the + // last element to indicate that it is the terminator. + UsbZeroCopyIsocChunkElement::NextElementOffset(chunkBase, prevMetaOffset) = UsbZeroCopyIsocChunkElement::KEndOfList; + --aNumIsocTransfers; + } + else + { + // Initialise Meta-data. + UsbZeroCopyBulkIntrChunkHeader::TransferType(chunkBase, aMetaDataOffset) = details.iTransferDesc.iType; + UsbZeroCopyBulkIntrChunkHeader::DataOffset(chunkBase, aMetaDataOffset) = details.iAssignedOffset; + UsbZeroCopyBulkIntrChunkHeader::DataLength(chunkBase, aMetaDataOffset) = 0; + UsbZeroCopyBulkIntrChunkHeader::DataMaxLength(chunkBase, aMetaDataOffset) = details.iRequiredSize; + UsbZeroCopyBulkIntrChunkHeader::ZlpStatus(chunkBase, aMetaDataOffset) = RUsbTransferDescriptor::ESendZlpIfRequired; + // Initialise transfer descriptor + SetTransferHandle(details.iTransferDesc, aMetaDataOffset); + // Move on to next meta-data slot + aMetaDataOffset += UsbZeroCopyBulkIntrChunkHeader::HeaderSize(); + --aNumStandardTransfers; + } + } + + __ASSERT_DEBUG(aNumStandardTransfers == 0, UsbdiUtils::Fault(UsbdiFaults::EUsbTransferDescriptorIncompleteInitialisation)); + __ASSERT_DEBUG(aNumIsocTransfers == 0, UsbdiUtils::Fault(UsbdiFaults::EUsbTransferDescriptorIncompleteInitialisation)); + __ASSERT_DEBUG(aNumIsocElements == 0, UsbdiUtils::Fault(UsbdiFaults::EUsbTransferDescriptorIncompleteInitialisation)); + } + + +TBool RUsbZeroCopyTransferStrategy::IsPowerOfTwo(TUint aNumber) + { + return aNumber && !(aNumber & (aNumber - 1)); //this returns true if the integer is a power of two + } + + +TInt RUsbZeroCopyTransferStrategy::IncNeededToAlign(TInt aOffset, TUint aAlignment) + { + if (aAlignment == 0) + { + return 0; + } + TInt remain = aOffset % aAlignment; + return (aAlignment - remain) % aAlignment; + } + + +// Standard Methods + +TPtr8 RUsbZeroCopyTransferStrategy::WritableBuffer(TInt aHandle) + { + __ASSERT_DEBUG(aHandle >= 0, UsbdiUtils::Fault(UsbdiFaults::EUsbTransferDescriptorBadHandle)); + + TUint8* chunkBase = iChunk.Base() + iBaseOffset; + + TUint8* dataPtr = chunkBase + UsbZeroCopyBulkIntrChunkHeader::DataOffset(chunkBase, aHandle); + TInt maxLength = UsbZeroCopyBulkIntrChunkHeader::DataMaxLength(chunkBase, aHandle); + + return TPtr8(dataPtr, 0, maxLength); + } + +void RUsbZeroCopyTransferStrategy::SaveData(TInt aHandle, TInt aLength) + { + __ASSERT_DEBUG(aHandle >= 0, UsbdiUtils::Fault(UsbdiFaults::EUsbTransferDescriptorBadHandle)); + + TUint8* chunkBase = iChunk.Base() + iBaseOffset; + + TInt maxLength = UsbZeroCopyBulkIntrChunkHeader::DataMaxLength(chunkBase, aHandle); + __ASSERT_ALWAYS(aLength <= maxLength, UsbdiUtils::Panic(UsbdiPanics::ETransferDescriptorSavedToMuchData)); + + UsbZeroCopyBulkIntrChunkHeader::DataLength(chunkBase, aHandle) = aLength; + } + +void RUsbZeroCopyTransferStrategy::SetZlpStatus(TInt aHandle, RUsbTransferDescriptor::TZlpStatus aZlpStatus) + { + __ASSERT_DEBUG(aHandle >= 0, UsbdiUtils::Fault(UsbdiFaults::EUsbTransferDescriptorBadHandle)); + + TUint8* chunkBase = iChunk.Base() + iBaseOffset; + + UsbZeroCopyBulkIntrChunkHeader::ZlpStatus(chunkBase, aHandle) = aZlpStatus; + } + +TPtrC8 RUsbZeroCopyTransferStrategy::Buffer(TInt aHandle) const + { + __ASSERT_DEBUG(aHandle >= 0, UsbdiUtils::Fault(UsbdiFaults::EUsbTransferDescriptorBadHandle)); + + TUint8* chunkBase = iChunk.Base() + iBaseOffset; + + TUint8* dataPtr = chunkBase + UsbZeroCopyBulkIntrChunkHeader::DataOffset(chunkBase, aHandle); + TInt length = UsbZeroCopyBulkIntrChunkHeader::DataLength(chunkBase, aHandle); + + return TPtrC8(dataPtr, length); + } + + + + +// Isochronous Methods + +void RUsbZeroCopyTransferStrategy::Reset(TInt aHandle) + { + __ASSERT_DEBUG(aHandle >= 0, UsbdiUtils::Fault(UsbdiFaults::EUsbTransferDescriptorBadHandle)); + + TUint8* chunkBase = iChunk.Base() + iBaseOffset; + + // Loop through and reset number of packets in each element as 0 + TInt elementOffset = UsbZeroCopyIsocChunkHeader::FirstElementOffset(chunkBase, aHandle); + while (elementOffset != UsbZeroCopyIsocChunkElement::KEndOfList) + { + UsbZeroCopyIsocChunkElement::NumPackets(chunkBase, elementOffset) = 0; + elementOffset = UsbZeroCopyIsocChunkElement::NextElementOffset(chunkBase, elementOffset); + } + } + +TPacketLengths RUsbZeroCopyTransferStrategy::Lengths(TInt aHandle) + { + __ASSERT_DEBUG(aHandle >= 0, UsbdiUtils::Fault(UsbdiFaults::EUsbTransferDescriptorBadHandle)); + + TUint8* chunkBase = iChunk.Base() + iBaseOffset; + + TInt lengthsOffset = UsbZeroCopyIsocChunkHeader::LengthsOffset(chunkBase, aHandle); + TUint16* lengthsPtr = reinterpret_cast(chunkBase + lengthsOffset); + + TInt reqLenOffset = UsbZeroCopyIsocChunkHeader::ReqLenOffset(chunkBase, aHandle); + TUint16* reqLenPtr = reinterpret_cast(chunkBase + reqLenOffset); + + TInt& maxNumPackets = UsbZeroCopyIsocChunkHeader::MaxNumPackets(chunkBase, aHandle); + + return TPacketLengths(lengthsPtr, reqLenPtr, maxNumPackets); + } + +TPacketResults RUsbZeroCopyTransferStrategy::Results(TInt aHandle) + { + __ASSERT_DEBUG(aHandle >= 0, UsbdiUtils::Fault(UsbdiFaults::EUsbTransferDescriptorBadHandle)); + + TUint8* chunkBase = iChunk.Base() + iBaseOffset; + + TInt resultsOffset = UsbZeroCopyIsocChunkHeader::ResultsOffset(chunkBase, aHandle); + TInt* resultsPtr = reinterpret_cast(chunkBase + resultsOffset); + + TInt& maxNumPackets = UsbZeroCopyIsocChunkHeader::MaxNumPackets(chunkBase, aHandle); + + return TPacketResults(resultsPtr, maxNumPackets); + } + +TInt RUsbZeroCopyTransferStrategy::MaxPacketSize(TInt aHandle) + { + __ASSERT_DEBUG(aHandle >= 0, UsbdiUtils::Fault(UsbdiFaults::EUsbTransferDescriptorBadHandle)); + + TUint8* chunkBase = iChunk.Base() + iBaseOffset; + + TInt maxPacketSize = UsbZeroCopyIsocChunkHeader::MaxPacketSize(chunkBase, aHandle); + + return maxPacketSize; + } + +TPtr8 RUsbZeroCopyTransferStrategy::WritablePackets(TInt aHandle, TInt aWriteHandle, TInt aNumPacketsRequested, TInt& aMaxNumPacketsAbleToWrite) + { + __ASSERT_DEBUG(aHandle >= 0, UsbdiUtils::Fault(UsbdiFaults::EUsbTransferDescriptorBadHandle)); + __ASSERT_DEBUG(aWriteHandle >= 0, UsbdiUtils::Fault(UsbdiFaults::EUsbTransferDescriptorBadWriteHandle)); + + TUint8* chunkBase = iChunk.Base() + iBaseOffset; + + const TUint32 pageAddrBits = iPageSize-1; + const TUint32 pageTableMask = ~pageAddrBits; + + if (aHandle == aWriteHandle) + { + // The initial write handle will be the same as the standard handle so we need to find the actual + // element to work correctly. + aWriteHandle = UsbZeroCopyIsocChunkHeader::FirstElementOffset(chunkBase, aHandle); + } + + // Now we have two cases - the number of packets requested is contained in one page, or it crosses the page. + // 1) If we cross the page then we get the buffer for upto the end of the page, and inform the user of the number + // of packets they are able to write into it (normally this will be quite high as we can consider 0 length + // packets.) + // 2) If we are on one page then we provide a buffer to the end of the page and return the number of packets + // the requested as the max they can write. However we also now mark it so that an attempt to get a subsequent + // writable buffer will return a 0 max length TPtr8 and 0 max number of packets to write. If they want write + // more they need to reset the descriptor and start again. + + if (UsbZeroCopyIsocChunkElement::NumPackets(chunkBase, aWriteHandle) == UsbZeroCopyIsocChunkElement::KInvalidElement) + { + // Here we are testing the second case, if we previously marked an element as invalid then we must not + // return a valid buffer. + aMaxNumPacketsAbleToWrite = 0; + return TPtr8(NULL, 0); + } + + TInt dataOffset = UsbZeroCopyIsocChunkElement::DataOffset(chunkBase, aWriteHandle); + + TUint8* dataPtr = chunkBase + dataOffset; + TInt totalMaxSize = aNumPacketsRequested * UsbZeroCopyIsocChunkHeader::MaxPacketSize(chunkBase, aHandle); + // The USB stack requires isoc transfer to be limited to a page (not allowed to cross the boundary). + TUint32 dataAddr = reinterpret_cast(dataPtr); + TBool samePage = (pageTableMask & dataAddr) == (pageTableMask & (dataAddr + totalMaxSize)); + TInt allowableSize = samePage ? totalMaxSize : iPageSize - (pageAddrBits & dataAddr); + + TInt numPacketsRemaining = UsbZeroCopyIsocChunkHeader::MaxNumPackets(chunkBase, aHandle) - UsedPackets(aHandle); + + if (aNumPacketsRequested < numPacketsRemaining) + { + // This is the 2nd case as documented in the comment. So we mark the next packet as invalid. + aMaxNumPacketsAbleToWrite = aNumPacketsRequested; + TInt nextElement = UsbZeroCopyIsocChunkElement::NextElementOffset(chunkBase, aWriteHandle); + if (nextElement != UsbZeroCopyIsocChunkElement::KEndOfList) + { + UsbZeroCopyIsocChunkElement::NumPackets(chunkBase, nextElement) = UsbZeroCopyIsocChunkElement::KInvalidElement; // Mark as invalid. + } + // else we are at the end of the list anyway + } + else + { + aMaxNumPacketsAbleToWrite = numPacketsRemaining; + } + + return TPtr8(dataPtr, allowableSize); + } + +TInt RUsbZeroCopyTransferStrategy::SaveMultiple(TInt aHandle, TInt aWriteHandle, TInt aNumPackets) + { + __ASSERT_DEBUG(aHandle >= 0, UsbdiUtils::Fault(UsbdiFaults::EUsbTransferDescriptorBadHandle)); + __ASSERT_DEBUG(aWriteHandle >= 0, UsbdiUtils::Fault(UsbdiFaults::EUsbTransferDescriptorBadWriteHandle)); + __ASSERT_ALWAYS(aNumPackets > 0, UsbdiUtils::Panic(UsbdiPanics::ETransferDescriptorNoPacketsToSave)); + + TUint8* chunkBase = iChunk.Base() + iBaseOffset; + + if (aHandle == aWriteHandle) + { + aWriteHandle = UsbZeroCopyIsocChunkHeader::FirstElementOffset(chunkBase, aHandle); + } + + // if marked invalid then they shouldn't try to save it (they haven't been able to write anything into the data anyway). + __ASSERT_ALWAYS(UsbZeroCopyIsocChunkElement::NumPackets(chunkBase, aWriteHandle) != UsbZeroCopyIsocChunkElement::KInvalidElement, + UsbdiUtils::Panic(UsbdiPanics::ETransferDescriptorInvalidSaveCall)); + + // Ensure they've not tried to write in too many packets + TInt usedPackets = UsedPackets(aHandle); + __ASSERT_ALWAYS(aNumPackets + usedPackets <= UsbZeroCopyIsocChunkHeader::MaxNumPackets(chunkBase, aHandle), + UsbdiUtils::Panic(UsbdiPanics::ETransferDescriptorSavedTooManyPackets)); + + // Check that the length values have not exceeded the maximum. + TInt maxPacketSize = UsbZeroCopyIsocChunkHeader::MaxPacketSize(chunkBase, aHandle); + TInt lengthsOffset = UsbZeroCopyIsocChunkHeader::LengthsOffset(chunkBase, aHandle); + TUint16* lengthsPtr = reinterpret_cast(chunkBase + lengthsOffset); +#ifdef _DEBUG + // The requested length is only functionally needed for IN transfers, but it provides an + // extra check that the length values that were requested by the user are those that are + // been requested on the USB stack. + TInt reqLenOffset = UsbZeroCopyIsocChunkHeader::ReqLenOffset(chunkBase, aHandle); + TUint16* reqLenPtr = reinterpret_cast(chunkBase + reqLenOffset); +#endif // _DEBUG + for (TInt i=0; i < aNumPackets; ++i) + { + __ASSERT_ALWAYS(lengthsPtr[usedPackets + i] <= maxPacketSize, UsbdiUtils::Panic(UsbdiPanics::ETransferDescriptorSavingTooLargeAPacket)); + __ASSERT_DEBUG(lengthsPtr[usedPackets + i] == reqLenPtr[usedPackets + i], UsbdiUtils::Panic(UsbdiPanics::ETransferDescriptorRequestedLengthDiffers)); // Belt 'n' Braces + } + + // Commit the packets to the transfer descriptor. + UsbZeroCopyIsocChunkElement::NumPackets(chunkBase, aWriteHandle) = aNumPackets; + TInt headerOffset = UsbZeroCopyIsocChunkElement::NextElementOffset(chunkBase, aWriteHandle); + + // Return the handle to the next region for writing. + return (headerOffset == UsbZeroCopyIsocChunkElement::KEndOfList) ? KErrEof : headerOffset; + } + +/** +Used to walk the elements to total up the number of packets that have been saved in the transfer descriptor. +*/ +TInt RUsbZeroCopyTransferStrategy::UsedPackets(TInt aHeaderOffset) + { + __ASSERT_DEBUG(aHeaderOffset >= 0, UsbdiUtils::Fault(UsbdiFaults::EUsbTransferDescriptorInvalidHeaderOffset)); + + TUint8* chunkBase = iChunk.Base() + iBaseOffset; + TInt elementOffset = UsbZeroCopyIsocChunkHeader::FirstElementOffset(chunkBase, aHeaderOffset); + TInt totalNumPackets = 0; + while (elementOffset != UsbZeroCopyIsocChunkElement::KEndOfList) + { + TInt numPackets = UsbZeroCopyIsocChunkElement::NumPackets(chunkBase, elementOffset); + if (numPackets == 0 || numPackets == UsbZeroCopyIsocChunkElement::KInvalidElement) + { + break; + } + totalNumPackets += numPackets; + elementOffset = UsbZeroCopyIsocChunkElement::NextElementOffset(chunkBase, elementOffset); + } + return totalNumPackets; + } + +/** +Used to read packets out from the transfer descriptor. +Note that some of the panics are belt'n'braces, and are used to sanity test result that has been +provided. These should be correct (as the results are set by the kernel), however because the user +has access to length array (for writing out packets) it is possible for them to 'corrupt' the result. +We panic explicitly in UDEB builds, in UREL the guards are not present and the user may get returned +a bad descriptor. +*/ +TPtrC8 RUsbZeroCopyTransferStrategy::Packets(TInt aHandle, TInt aFirstPacketIndex, TInt aNumPacketsRequested, TInt& aNumPacketsReturned) const + { + __ASSERT_DEBUG(aHandle >= 0, UsbdiUtils::Fault(UsbdiFaults::EUsbTransferDescriptorBadHandle)); + __ASSERT_ALWAYS(aFirstPacketIndex >= 0, UsbdiUtils::Panic(UsbdiPanics::ETransferDescriptorPacketNotInBounds)); + __ASSERT_ALWAYS(aNumPacketsRequested > 0, UsbdiUtils::Panic(UsbdiPanics::ETransferDescriptorTooFewPacketsRequested)); + + TUint8* chunkBase = iChunk.Base() + iBaseOffset; + + __ASSERT_ALWAYS(aNumPacketsRequested <= UsbZeroCopyIsocChunkHeader::MaxNumPackets(chunkBase, aHandle), + UsbdiUtils::Panic(UsbdiPanics::ETransferDescriptorTooManyPacketsRequested)); + +#ifdef _DEBUG + const TUint32 pageAddrBits = iPageSize-1; + const TUint32 pageTableMask = ~pageAddrBits; +#endif // _DEBUG + const TInt maxPacketSize = UsbZeroCopyIsocChunkHeader::MaxPacketSize(chunkBase, aHandle); + + TInt elementOffset = UsbZeroCopyIsocChunkHeader::FirstElementOffset(chunkBase, aHandle); + TInt packetCount = 0; + while (elementOffset != UsbZeroCopyIsocChunkElement::KEndOfList) + { + TInt numPackets = UsbZeroCopyIsocChunkElement::NumPackets(chunkBase, elementOffset); + if (numPackets == 0 || numPackets == UsbZeroCopyIsocChunkElement::KInvalidElement) + { + // We've got to the end of the elements and not found the packets we are after. + break; + } + TInt previousPacketCount = packetCount; + packetCount += numPackets; + if (aFirstPacketIndex < packetCount) // If true then start packet must be in this element + { + TInt intraElementIndex = aFirstPacketIndex - previousPacketCount; + TInt maxPacketsForReturn = packetCount - aFirstPacketIndex; + + TInt lengthsOffset = UsbZeroCopyIsocChunkHeader::LengthsOffset(chunkBase, aHandle); + TUint16* lengthsPtr = reinterpret_cast(chunkBase + lengthsOffset + previousPacketCount * sizeof(TUint16)); + TInt reqLenOffset = UsbZeroCopyIsocChunkHeader::ReqLenOffset(chunkBase, aHandle); + TUint16* reqLenPtr = reinterpret_cast(chunkBase + reqLenOffset + previousPacketCount * sizeof(TUint16)); + + aNumPacketsReturned = (aNumPacketsRequested < maxPacketsForReturn) ? aNumPacketsRequested : maxPacketsForReturn; + + TInt distanceToReqPacket = 0; + for (TInt i=0; i < intraElementIndex; ++i) + { + TUint16 reqLen = reqLenPtr[i]; + __ASSERT_DEBUG(reqLen <= maxPacketSize, + UsbdiUtils::Panic(UsbdiPanics::ETransferDescriptorReceivedTooLargeAPacket)); // Belt'n'Braces + distanceToReqPacket += reqLen; + } + TInt dataOffset = UsbZeroCopyIsocChunkElement::DataOffset(chunkBase, elementOffset); + TUint8* dataPtr = chunkBase + dataOffset + distanceToReqPacket; + + TInt totalLengthPackets = 0; + for (TInt i=0; i < aNumPacketsReturned; ++i) + { + TUint16 len = lengthsPtr[intraElementIndex + i]; + TUint16 reqLen = reqLenPtr[intraElementIndex + i]; + __ASSERT_DEBUG(len <= maxPacketSize, + UsbdiUtils::Panic(UsbdiPanics::ETransferDescriptorReceivedTooLargeAPacket)); // Belt'n'Braces + + totalLengthPackets += len; + + // Here we handle the potential gaps that may appear in the data stream if a short + // packet is received. + if (len < reqLen) + { + // if here then we received a short packet, as such we can only return up to here + aNumPacketsReturned = i+1; + break; + } + // Otherwise we expect them to be equal (if we got more than requested then something odd has happened. + __ASSERT_DEBUG(len == reqLen, UsbdiUtils::Panic(UsbdiPanics::ETransferDescriptorRequestedLengthDiffers)); // Belt 'n' Braces + } + + // The USB stack requires isoc transfer to be limited to a page (not allowed to cross the boundary). + // Therefore one of our elements must have data only on one page. +#ifdef _DEBUG + TUint32 dataAddr = reinterpret_cast(dataPtr); + TBool samePage = (totalLengthPackets == 0) || (pageTableMask & dataAddr) == (pageTableMask & (dataAddr + totalLengthPackets - 1)); + __ASSERT_DEBUG(samePage, UsbdiUtils::Panic(UsbdiPanics::EIsocTransferResultCrossesPageBoundary)); // Belt'n'Braces +#endif // _DEBUG + + return TPtrC8(dataPtr, totalLengthPackets); + } + + // No luck so far, move on to try the next element + elementOffset = UsbZeroCopyIsocChunkElement::NextElementOffset(chunkBase, elementOffset); + } + + // No suitable packet range found. + aNumPacketsReturned = 0; + return TPtrC8(NULL, 0); + } + +void RUsbZeroCopyTransferStrategy::ReceivePackets(TInt aHandle, TInt aNumPackets) + { + __ASSERT_DEBUG(aHandle >= 0, UsbdiUtils::Fault(UsbdiFaults::EUsbTransferDescriptorBadHandle)); + __ASSERT_ALWAYS(aNumPackets > 0, UsbdiUtils::Panic(UsbdiPanics::ETransferDescriptorTooFewPacketsRequested)); + + TUint8* chunkBase = iChunk.Base() + iBaseOffset; + + __ASSERT_ALWAYS(aNumPackets <= UsbZeroCopyIsocChunkHeader::MaxNumPackets(chunkBase, aHandle), + UsbdiUtils::Panic(UsbdiPanics::ETransferDescriptorTooManyPacketsRequested)); + + const TUint32 pageAddrBits = iPageSize-1; + const TUint32 pageTableMask = ~pageAddrBits; + const TInt maxPacketSize = UsbZeroCopyIsocChunkHeader::MaxPacketSize(chunkBase, aHandle); + +#ifdef _DEBUG + // Here we make the best check we can that the user has set-up the requested lengths they require. + // If there is a difference, they have either a corrupted metadata chunk, or they are reusing a + // previous buffer without setting the lengths requested. + TInt lengthsOffset = UsbZeroCopyIsocChunkHeader::LengthsOffset(chunkBase, aHandle); + TUint16* lengthsPtr = reinterpret_cast(chunkBase + lengthsOffset); + TInt reqLenOffset = UsbZeroCopyIsocChunkHeader::ReqLenOffset(chunkBase, aHandle); + TUint16* reqLenPtr = reinterpret_cast(chunkBase + reqLenOffset); + for (TInt i=0; i < aNumPackets; ++i) + { + __ASSERT_DEBUG(lengthsPtr[i] == reqLenPtr[i], + UsbdiUtils::Panic(UsbdiPanics::ETransferDescriptorRequestedLengthDiffers)); // Belt 'n' Braces + } +#endif // _DEBUG + + TInt elementOffset = UsbZeroCopyIsocChunkHeader::FirstElementOffset(chunkBase, aHandle); + while (aNumPackets) + { + __ASSERT_DEBUG(elementOffset != UsbZeroCopyIsocChunkElement::KEndOfList, + UsbdiUtils::Fault(UsbdiFaults::EUsbTransferDescriptorUnexpectedEndOfIsocList)); + + TInt totalMaxSize = aNumPackets * maxPacketSize; + + TInt dataOffset = UsbZeroCopyIsocChunkElement::DataOffset(chunkBase, elementOffset); + TUint8* dataPtr = chunkBase + dataOffset; + TUint32 dataAddr = reinterpret_cast(dataPtr); + TBool samePage = (pageTableMask & dataAddr) == (pageTableMask & (dataAddr + totalMaxSize)); + TInt allowableSize = samePage ? totalMaxSize : iPageSize - (pageAddrBits & dataAddr); + TInt numPackets = allowableSize / maxPacketSize; + + // TODO We could assert here in debug as a double check using UsedPackets() + + __ASSERT_DEBUG(numPackets > 0, + UsbdiUtils::Fault(UsbdiFaults::EUsbTransferDescriptorUnfillableElement)); + + UsbZeroCopyIsocChunkElement::NumPackets(chunkBase, elementOffset) = numPackets; + aNumPackets -= numPackets; + + elementOffset = UsbZeroCopyIsocChunkElement::NextElementOffset(chunkBase, elementOffset); + } + + if (elementOffset != UsbZeroCopyIsocChunkElement::KEndOfList) + { + UsbZeroCopyIsocChunkElement::NumPackets(chunkBase, elementOffset) = UsbZeroCopyIsocChunkElement::KInvalidElement; // Mark as invalid. + } + } + + + + + +TPtr8 RUsbZeroCopyTransferStrategy::IntrWritableBuffer(TInt aHandle) + { + return WritableBuffer(aHandle); + } + +void RUsbZeroCopyTransferStrategy::IntrSaveData(TInt aHandle, TInt aLength) + { + SaveData(aHandle, aLength); + } + +void RUsbZeroCopyTransferStrategy::IntrSetZlpStatus(TInt aHandle, RUsbTransferDescriptor::TZlpStatus aZlpStatus) + { + SetZlpStatus(aHandle, aZlpStatus); + } + +TPtrC8 RUsbZeroCopyTransferStrategy::IntrBuffer(TInt aHandle) const + { + return Buffer(aHandle); + } + +TPtr8 RUsbZeroCopyTransferStrategy::BulkWritableBuffer(TInt aHandle) + { + return WritableBuffer(aHandle); + } + +void RUsbZeroCopyTransferStrategy::BulkSaveData(TInt aHandle, TInt aLength) + { + SaveData(aHandle, aLength); + } + +void RUsbZeroCopyTransferStrategy::BulkSetZlpStatus(TInt aHandle, RUsbTransferDescriptor::TZlpStatus aZlpStatus) + { + SetZlpStatus(aHandle, aZlpStatus); + } + +TPtrC8 RUsbZeroCopyTransferStrategy::BulkBuffer(TInt aHandle) const + { + return Buffer(aHandle); + } + +void RUsbZeroCopyTransferStrategy::IsocReset(TInt aHandle) + { + Reset(aHandle); + } + +TPacketLengths RUsbZeroCopyTransferStrategy::IsocLengths(TInt aHandle) + { + return Lengths(aHandle); + } + +TPacketResults RUsbZeroCopyTransferStrategy::IsocResults(TInt aHandle) + { + return Results(aHandle); + } + +TInt RUsbZeroCopyTransferStrategy::IsocMaxPacketSize(TInt aHandle) + { + return MaxPacketSize(aHandle); + } + +TPtr8 RUsbZeroCopyTransferStrategy::IsocWritablePackets(TInt aHandle, TInt aWriteHandle, TInt aNumPacketsRequested, TInt& aMaxNumPacketsAbleToWrite) + { + return WritablePackets(aHandle, aWriteHandle, aNumPacketsRequested, aMaxNumPacketsAbleToWrite); + } + +TInt RUsbZeroCopyTransferStrategy::IsocSaveMultiple(TInt aHandle, TInt aWriteHandle, TInt aNumOfPackets) + { + return SaveMultiple(aHandle, aWriteHandle, aNumOfPackets); + } + +TPtrC8 RUsbZeroCopyTransferStrategy::IsocPackets(TInt aHandle, TInt aFirstPacketIndex, TInt aNumPacketsRequested, TInt& aNumPacketsReturned) const + { + return Packets(aHandle, aFirstPacketIndex, aNumPacketsRequested, aNumPacketsReturned); + } + +void RUsbZeroCopyTransferStrategy::IsocReceivePackets(TInt aHandle, TInt aNumOfPackets) + { + ReceivePackets(aHandle, aNumOfPackets); + } + + +//Calculate-alignment related methods + +/** + Scan through all the bulk/interrupt endpoints associated with the particular interface + (and all its alternate settings) to find the maximum bMaxPacketSize across all of these. + For Interrupt, if there is EP of which the maxPacketSize is not power of 2, + the maxmaxpaceketsize will be assigned the first maxPacketSize which is not power of 2. +*/ +TInt RUsbZeroCopyTransferStrategy::GetMaximumMaxPacketSize(TInt& aMaxMaxBulk, TInt& aMaxMaxInterrupt) + { + TUsbInterfaceDescriptor interfaceDesc; + TInt err = iInterfaceHandle->GetInterfaceDescriptor(interfaceDesc); + if (KErrNone != err) + { + return err; + } + + const TUint8 KEPTransferTypeBulk = 0x02; + const TUint8 KEPTransferTypeInterrupt = 0x03; + const TUint8 KEPTransferTypeMask = 0x03; + + TBool ignoreInterruptEP = EFalse; + //Traverse all related interface alternate settings + TUsbGenericDescriptor* descriptor = &interfaceDesc; + while (descriptor) + { + TUsbInterfaceDescriptor* interface = TUsbInterfaceDescriptor::Cast(descriptor); + + if (interface) + { + //Traverse all endpoint descriptor in the interface + TUsbGenericDescriptor* subDescriptor = interface->iFirstChild; + + while (subDescriptor) + { + TUsbEndpointDescriptor* endpoint = TUsbEndpointDescriptor::Cast(subDescriptor); + + if (endpoint) + { + TBool isBulkEP = ((endpoint->Attributes() & KEPTransferTypeMask) == KEPTransferTypeBulk); + TBool isInterruptEP = ((endpoint->Attributes() & KEPTransferTypeMask) == KEPTransferTypeInterrupt); + TUint maxPacketSize = endpoint->MaxPacketSize(); + + //Caculate the maximum maxPacketSize + if (isBulkEP) + { + if (maxPacketSize > aMaxMaxBulk) + { + aMaxMaxBulk = maxPacketSize; + } + } + else if(isInterruptEP && !ignoreInterruptEP) + { + if (!IsPowerOfTwo(maxPacketSize)) + { + aMaxMaxInterrupt = maxPacketSize; + ignoreInterruptEP = ETrue; + } + + if (maxPacketSize > aMaxMaxInterrupt) + { + aMaxMaxInterrupt = maxPacketSize; + } + } + } + + subDescriptor = subDescriptor->iNextPeer; + } + } + + descriptor = descriptor->iNextPeer; + } + + return KErrNone; + } + +/** +Calculate the additional alignment requirement on bulk and interrupt transfer. +For Bulk transfer, + Scan through all the bulk/interrupt endpoints associated with the particular interface + to find the maximum wMaxPacketSize across all of these. The new alignment for the transfer + is the maximum between the maximum bMaxPacketSize and the original alignment +For Interrupt transfer, + Check if there is endpoints of which the wMaxPacketSize is not power of 2, + if no, do the same as bulk; + if yes, the size of transfer data is limited to one page size, and the additional alignment + calcualted to make the transfer data not to span page boundary + +*/ +TInt RUsbZeroCopyTransferStrategy::CaculateAdditionalAlignment(TInt aCurrentOffset, TInt aMaxMaxBulk, TInt aMaxMaxInterrupt, TUsbTransferDescriptorDetails& aTransferDetails) + { + RUsbTransferDescriptor::TTransferType transferType = aTransferDetails.iTransferDesc.iType; + TBool isBulkTransfer = (transferType == RUsbTransferDescriptor::EBulk); + TBool isInterruptTransfer = (transferType == RUsbTransferDescriptor::EInterrupt); + + if (isBulkTransfer) + { + if (aMaxMaxBulk > aTransferDetails.iRequiredAlignment) + { + aTransferDetails.iRequiredAlignment = aMaxMaxBulk; + } + } + else if (isInterruptTransfer) + { + if (IsPowerOfTwo(aMaxMaxInterrupt)) + { + if (aMaxMaxInterrupt > aTransferDetails.iRequiredAlignment) + { + aTransferDetails.iRequiredAlignment = aMaxMaxInterrupt; + } + } + else + { + if (aTransferDetails.iRequiredSize > iPageSize) + { + //The transfer data can not span the page boundary + //if there is EP of which wMaxPacketSize is not power-of-2, + return KErrNotSupported; + } + else + { + TInt sizeLeftOfCurrentPage = IncNeededToAlign(aCurrentOffset,iPageSize); + TInt alignPad = IncNeededToAlign(aCurrentOffset, aTransferDetails.iRequiredAlignment); + + //The transfer data can't fit into the current page + //Align the trasfer data to the next page + if ( sizeLeftOfCurrentPage < (alignPad + aTransferDetails.iRequiredSize) ) + { + aTransferDetails.iRequiredAlignment = iPageSize; + } + } + } + } + return KErrNone; + } diff -r 466a0df5c15a -r ea2434cf3670 kernel/eka/drivers/usbho/usbdi_utils/zerocopytransferstrategy.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kernel/eka/drivers/usbho/usbdi_utils/zerocopytransferstrategy.h Tue May 04 18:23:12 2010 +0100 @@ -0,0 +1,112 @@ +// Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies). +// All rights reserved. +// This component and the accompanying materials are made available +// under the terms of the License "Eclipse Public License v1.0" +// which accompanies this distribution, and is available +// at the URL "http://www.eclipse.org/legal/epl-v10.html". +// +// Initial Contributors: +// Nokia Corporation - initial contribution. +// +// Contributors: +// +// Description: +// + +/** + @file + @internalComponent +*/ + +#ifndef ZEROCOPYTRANSFERSTRATEGY_H +#define ZEROCOPYTRANSFERSTRATEGY_H + +#include "usbtransferstrategy.h" + + +NONSHARABLE_CLASS(RUsbZeroCopyTransferStrategy) : public RUsbTransferStrategy + { +public: + RUsbZeroCopyTransferStrategy(); + virtual TInt RegisterTransferDescriptor(RUsbTransferDescriptor& aTransferDesc, TInt aRequiredSize, TUint aStartAlignment, TInt aRequiredMaxPackets); + virtual void ResetTransferDescriptors(); + virtual TInt InitialiseTransferDescriptors(RUsbInterface& aInterface); + + virtual void Close(); + +public: // Interrupt transfer descriptor methods + virtual TPtr8 IntrWritableBuffer(TInt aHandle); + virtual void IntrSaveData(TInt aHandle, TInt aLength); + virtual void IntrSetZlpStatus(TInt aHandle, RUsbTransferDescriptor::TZlpStatus aZlpStatus); + virtual TPtrC8 IntrBuffer(TInt aHandle) const; +public: // Bulk transfer descriptor methods + virtual TPtr8 BulkWritableBuffer(TInt aHandle); + virtual void BulkSaveData(TInt aHandle, TInt aLength); + virtual void BulkSetZlpStatus(TInt aHandle, RUsbTransferDescriptor::TZlpStatus aZlpStatus); + virtual TPtrC8 BulkBuffer(TInt aHandle) const; +public: // Isochronous transfer descriptor methods + virtual void IsocReset(TInt aHandle); + virtual TPacketLengths IsocLengths(TInt aHandle); + virtual TPacketResults IsocResults(TInt aHandle); + virtual TInt IsocMaxPacketSize(TInt aHandle); + virtual TPtr8 IsocWritablePackets(TInt aHandle, TInt aWriteHandle, TInt aNumPacketsRequested, TInt& aMaxNumPacketsAbleToWrite); + virtual TInt IsocSaveMultiple(TInt aHandle, TInt aWriteHandle, TInt aNumOfPackets); + virtual TPtrC8 IsocPackets(TInt aHandle, TInt aFirstPacketIndex, TInt aNumPacketsRequested, TInt& aNumPacketsReturned) const; + virtual void IsocReceivePackets(TInt aHandle, TInt aNumOfPackets); + + +private: // Standard (Bulk, Ctrl and Intr) Buffer methods + TPtr8 WritableBuffer(TInt aHandle); + void SaveData(TInt aHandle, TInt aLength); + void SetZlpStatus(TInt aHandle, RUsbTransferDescriptor::TZlpStatus aZlpStatus); + TPtrC8 Buffer(TInt aHandle) const; + +private: // Isoc Buffer methods + void Reset(TInt aHandle); + TPacketLengths Lengths(TInt aHandle); + TPacketResults Results(TInt aHandle); + TInt MaxPacketSize(TInt aHandle); + TPtr8 WritablePackets(TInt aHandle, TInt aWriteHandle, TInt aNumPacketsRequested, TInt& aMaxNumPacketsAbleToWrite); + TInt SaveMultiple(TInt aHandle, TInt aWriteHandle, TInt aNumOfPackets); + TPtrC8 Packets(TInt aHandle, TInt aFirstPacketIndex, TInt aNumPacketsRequested, TInt& aNumPacketsReturned) const; + void ReceivePackets(TInt aHandle, TInt aNumOfPackets); + +private: + NONSHARABLE_STRUCT(TUsbTransferDescriptorDetails) + { + TUsbTransferDescriptorDetails(RUsbTransferDescriptor&, TInt, TUint, TInt); + RUsbTransferDescriptor& iTransferDesc; + const TInt iRequiredSize; + TUint iRequiredAlignment; + const TInt iRequiredMaxPackets; + // Members to aid internal logic + TInt iAssignedOffset; + TInt iLengthsOffset; // Only applicable to isoc + TInt iReqLenOffset; // Only applicable to isoc + TInt iResultsOffset; // Only applicable to isoc + TInt iNumElements; // Only applicable to isoc + }; + +private: + TInt CalculateDataLayout(TInt& aCurrentOffset, TInt& aNumStandardTransfers, TInt& aNumIsocTransfers, TInt& aNumIsocElements); + void CalculateMetaDataLayout(TInt& aCurrentOffset, TInt& aMetaDataStart, TInt aNumStandardTransfers, TInt aNumIsocTransfers, TInt aNumIsocElements); + void InitialiseMetaData(TInt aMetaDataOffset, TInt aNumStandardTransfers, TInt aNumIsocTransfers, TInt aNumIsocElements); + TInt UsedPackets(TInt aHeaderOffset); + TBool IsPowerOfTwo(TUint aNumber); + TInt IncNeededToAlign(TInt aOffset, TUint aAlignment); + static TBool CompareTransferDescriptor(const RUsbTransferDescriptor* aTransferDesc, const TUsbTransferDescriptorDetails& aDetails); + +private: //Calculate additional alignment related methods + TInt GetMaximumMaxPacketSize(TInt& aMaxMaxBulk, TInt& aMaxMaxInterrupt); + TInt CaculateAdditionalAlignment(TInt aCurrentOffset, TInt aMaxMaxBulk, TInt aMaxMaxInterrupt, TUsbTransferDescriptorDetails& aTransferDetails); +private: + RArray iRegisteredTransfers; + +private: + RUsbInterface* iInterfaceHandle; + RChunk iChunk; + TInt iBaseOffset; + TInt iPageSize; + }; + +#endif // ZEROCOPYTRANSFERSTRATEGY_H diff -r 466a0df5c15a -r ea2434cf3670 kernel/eka/eabi/ekernsmp.def --- a/kernel/eka/eabi/ekernsmp.def Tue May 04 16:57:20 2010 +0100 +++ b/kernel/eka/eabi/ekernsmp.def Tue May 04 18:23:12 2010 +0100 @@ -1187,4 +1187,5 @@ _ZN13KernCoreStats9ConfigureEj @ 1186 NONAME _ZN5NKern21SetNumberOfActiveCpusEi @ 1187 NONAME _ZN3Arm14SetIdleHandlerEPFvPvmPVvES0_ @ 1188 NONAME + _ZN4Epoc11FreeRamZoneEj @ 1189 NONAME diff -r 466a0df5c15a -r ea2434cf3670 kernel/eka/eabi/ekernu.def --- a/kernel/eka/eabi/ekernu.def Tue May 04 16:57:20 2010 +0100 +++ b/kernel/eka/eabi/ekernu.def Tue May 04 18:23:12 2010 +0100 @@ -1179,4 +1179,5 @@ _ZN13KernCoreStats9EnterIdleEv @ 1178 NONAME _ZN13KernCoreStats9LeaveIdleEj @ 1179 NONAME _ZN3Arm14SetIdleHandlerEPFvPvmES0_ @ 1180 NONAME + _ZN4Epoc11FreeRamZoneEj @ 1181 NONAME diff -r 466a0df5c15a -r ea2434cf3670 kernel/eka/eabi/usbdi_utilsu.def --- a/kernel/eka/eabi/usbdi_utilsu.def Tue May 04 16:57:20 2010 +0100 +++ b/kernel/eka/eabi/usbdi_utilsu.def Tue May 04 18:23:12 2010 +0100 @@ -37,4 +37,5 @@ _ZN26RUsbIsocTransferDescriptor7ResultsEv @ 36 NONAME _ZNK14TPacketResults2AtEi @ 37 NONAME _ZNK14TPacketResultsixEi @ 38 NONAME + _ZN22RUsbTransferDescriptor5CloseEv @ 39 NONAME diff -r 466a0df5c15a -r ea2434cf3670 kernel/eka/euser/us_ksvr.cpp --- a/kernel/eka/euser/us_ksvr.cpp Tue May 04 16:57:20 2010 +0100 +++ b/kernel/eka/euser/us_ksvr.cpp Tue May 04 18:23:12 2010 +0100 @@ -3469,16 +3469,17 @@ be invoked on this TThreadCreateInfo to set the type of the thread to be created before being passed as a paramter to RThread::Create(). -@param aName The name to be assigned to the thread. +@param aName The name to be assigned to the thread. KNullDesC, to create an anonymous thread. -@param aFunction A pointer to a function. Control passes to this function - when the thread is first resumed, i.e. when the thread - is initially scheduled to run. -@param aStackSize The size of the new thread's stack. -@param aPtr A pointer to data to be passed as a parameter to - the thread function when the thread is initially scheduled - to run. If the thread function does not need any data then - this pointer can be NULL. +@param aFunction A pointer to a function. Control passes to this function + when the thread is first resumed, i.e. when the thread + is initially scheduled to run. +@param aStackSize The size of the new thread's stack. This must be at least + 512 bytes, otherwise RThread::Create() will fail with KErrArgument. +@param aPtr A pointer to data to be passed as a parameter to + the thread function when the thread is initially scheduled + to run. If the thread function does not need any data then + this pointer can be NULL. */ EXPORT_C TThreadCreateInfo::TThreadCreateInfo(const TDesC &aName, TThreadFunction aFunction, TInt aStackSize, TAny* aPtr) : @@ -3604,25 +3605,27 @@ If KNullDesC is specified for the name, then an anonymous thread will be created. Anonymous threads are not global, and cannot be opened by other processes. -@param aName The name to be assigned to this thread. +@param aName The name to be assigned to this thread. KNullDesC, to create an anonymous thread. -@param aFunction A pointer to a function.. Control passes to this function - when the thread is first resumed, i.e. when the thread - is initially scheduled to run. -@param aStackSize The size of the new thread's stack. +@param aFunction A pointer to a function.. Control passes to this function + when the thread is first resumed, i.e. when the thread + is initially scheduled to run. +@param aStackSize The size of the new thread's stack. This must be at least + 512 bytes, otherwise this method will fail with KErrArgument. @param aHeapMinSize The minimum size for the new thread's heap. @param aHeapMaxSize The maximum size for the new thread's heap. -@param aPtr A pointer to data to be passed as a parameter to - the thread function when the thread is initially scheduled - to run. If the thread function does not need any data then - this pointer can be NULL. It must be ensured that the memory - pointed to by this pointer is still valid when accessed by - the new thread, e.g. if aPtr points to data on the stack. -@param aType An enumeration whose enumerators define the ownership of - this thread handle. If not explicitly specified, - EOwnerProcess is taken as default. +@param aPtr A pointer to data to be passed as a parameter to + the thread function when the thread is initially scheduled + to run. If the thread function does not need any data then + this pointer can be NULL. It must be ensured that the memory + pointed to by this pointer is still valid when accessed by + the new thread, e.g. if aPtr points to data on the stack. +@param aType An enumeration whose enumerators define the ownership of + this thread handle. If not explicitly specified, + EOwnerProcess is taken as default. @return KErrNone if successful, otherwise one of the other system-wide error codes. + KErrArgument if aStackSize is less than 512 bytes. KErrAlreadyExists will be returned if there is another thread in this process with the specified name. @@ -3630,7 +3633,10 @@ @panic USER 110 if aHeapMinSize is less than KMinHeapSize. @panic USER 111 if aHeapMaxSize is less than aHeapMinSize. */ - { + {// This must be true otherwise the comment on aStackSize will be incorrect and BC + // break will occur. See ExecHandler::ThreadCreate() for details. + __ASSERT_COMPILE(KMaxThreadCreateInfo == 256); + TThreadCreateInfo createInfo(aName, aFunction, aStackSize, aPtr); createInfo.SetOwner(aType); createInfo.SetCreateHeap(aHeapMinSize, aHeapMaxSize); @@ -3655,25 +3661,27 @@ If KNullDesC is specified for the name, then an anonymous thread will be created. Anonymous threads are not global, and cannot be opened by other processes. -@param aName The name to be assigned to this thread. - KNullDesC, to create an anonymous thread. -@param aFunction A pointer to a function. Control passes to this function when - the thread is first resumed, i.e. when the thread is - initially scheduled to run. -@param aStackSize The size of the new thread's stack. -@param aAllocator A pointer to the handle of the heap belonging to another thread - which this thread is to use. -@param aPtr A pointer to data to be passed as a parameter to the thread - function when the thread is initially scheduled to run. - If the thread function does not need any data, - then this pointer can be NULL. It must be ensured that the - memory pointed to by this pointer is still valid when accessed - by the new thread, e.g. if aPtr points to data on the stack. -@param aType An enumeration whose enumerators define the ownership of this - thread handle. If not explicitly specified, EOwnerProcess is - taken as default. +@param aName The name to be assigned to this thread. + KNullDesC, to create an anonymous thread. +@param aFunction A pointer to a function. Control passes to this function when + the thread is first resumed, i.e. when the thread is + initially scheduled to run. +@param aStackSize The size of the new thread's stack. This must be at least + 512 bytes, otherwise this method will fail with KErrArgument. +@param aAllocator A pointer to the handle of the heap belonging to another thread + which this thread is to use. +@param aPtr A pointer to data to be passed as a parameter to the thread + function when the thread is initially scheduled to run. + If the thread function does not need any data, + then this pointer can be NULL. It must be ensured that the + memory pointed to by this pointer is still valid when accessed + by the new thread, e.g. if aPtr points to data on the stack. +@param aType An enumeration whose enumerators define the ownership of this + thread handle. If not explicitly specified, EOwnerProcess is + taken as default. @return KErrNone if successful otherwise one of the other system-wide error codes. + KErrArgument if aStackSize is less than 512 bytes. KErrAlreadyExists will be returned if there is another thread in this process with the specified name. diff -r 466a0df5c15a -r ea2434cf3670 kernel/eka/include/d32otgdi.h --- a/kernel/eka/include/d32otgdi.h Tue May 04 16:57:20 2010 +0100 +++ b/kernel/eka/include/d32otgdi.h Tue May 04 18:23:12 2010 +0100 @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies). +// Copyright (c) 2007-2010 Nokia Corporation and/or its subsidiary(-ies). // All rights reserved. // This component and the accompanying materials are made available // under the terms of the License "Eclipse Public License v1.0" @@ -348,7 +348,13 @@ EMessageVbusPowerDownNotPermitted = KErrUsbOtgVbusPowerDownNotPermitted, EMessageVbusClearErrorNotPermitted = KErrUsbOtgVbusClearErrorNotPermitted, EMessageHnpNotResponding = KErrUsbOtgHnpNotResponding, - EMessageHnpBusDrop = KErrUsbOtgHnpBusDrop + EMessageHnpBusDrop = KErrUsbOtgHnpBusDrop, + + /** + Bad device attach/detach message + */ + EMessageBadDeviceAttached = KErrUsbOtgBadDeviceAttached, + EMessageBadDeviceDetached = KEventUsbOtgBadDeviceDetached }; public: diff -r 466a0df5c15a -r ea2434cf3670 kernel/eka/include/d32otgdi_errors.h --- a/kernel/eka/include/d32otgdi_errors.h Tue May 04 16:57:20 2010 +0100 +++ b/kernel/eka/include/d32otgdi_errors.h Tue May 04 18:23:12 2010 +0100 @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies). +// Copyright (c) 2007-2010 Nokia Corporation and/or its subsidiary(-ies). // All rights reserved. // This component and the accompanying materials are made available // under the terms of the License "Eclipse Public License v1.0" @@ -36,8 +36,13 @@ const TInt KErrUsbOtgStateQueueOverflow = -6671; const TInt KErrUsbOtgMessageQueueOverflow = -6672; +const TInt KErrUsbOtgBadDeviceAttached = -6673; +const TInt KEventUsbOtgBadDeviceDetached = -6674; + const TInt KErrUsbOtgBadState = -6675; +const TInt KErrUsbOtgInOPTTestingMode = -6676; + const TInt KErrUsbOtgStackNotStarted = -6680; const TInt KErrUsbOtgVbusAlreadyRaised = -6681; const TInt KErrUsbOtgSrpForbidden = -6682; diff -r 466a0df5c15a -r ea2434cf3670 kernel/eka/include/d32usbdi.h --- a/kernel/eka/include/d32usbdi.h Tue May 04 16:57:20 2010 +0100 +++ b/kernel/eka/include/d32usbdi.h Tue May 04 18:23:12 2010 +0100 @@ -180,7 +180,7 @@ // Some utility functions // inline TInt GetBusId(TUsbBusId& aBusId); - inline TInt HcdPageSize(); + inline TInt GetHcdPageSize(TInt& aHcdPageSize); inline TInt GetDeviceSpeed(TDeviceSpeed& aDeviceSpeed); private: diff -r 466a0df5c15a -r ea2434cf3670 kernel/eka/include/d32usbdi.inl --- a/kernel/eka/include/d32usbdi.inl Tue May 04 16:57:20 2010 +0100 +++ b/kernel/eka/include/d32usbdi.inl Tue May 04 18:23:12 2010 +0100 @@ -414,11 +414,12 @@ /** Returns the size of pages used by the HCD. @internalComponent -@return The HCD's page size. +@param aHcdPageSize on success provides the HCD's page size. +@return KErrNone on success, otherwise a system-wide error code. */ -TInt RUsbInterface::HcdPageSize() +TInt RUsbInterface::GetHcdPageSize(TInt& aHcdPageSize) { - return DoControl(EHcdPageSize); + return DoControl(EHcdPageSize, &aHcdPageSize); } /** diff -r 466a0df5c15a -r ea2434cf3670 kernel/eka/include/d32usbtransfers.h --- a/kernel/eka/include/d32usbtransfers.h Tue May 04 16:57:20 2010 +0100 +++ b/kernel/eka/include/d32usbtransfers.h Tue May 04 18:23:12 2010 +0100 @@ -54,7 +54,7 @@ friend class RUsbTransferStrategy; public: - virtual void Close(); + IMPORT_C virtual void Close(); protected: RUsbTransferDescriptor(TTransferType aType, TInt aMaxSize, TInt aMaxNumPackets); diff -r 466a0df5c15a -r ea2434cf3670 kernel/eka/include/drivers/sdcard.h --- a/kernel/eka/include/drivers/sdcard.h Tue May 04 16:57:20 2010 +0100 +++ b/kernel/eka/include/drivers/sdcard.h Tue May 04 18:23:12 2010 +0100 @@ -44,6 +44,7 @@ const TUint32 KSDSwitchFunctionHighSpeed = 0x80FFFF01; const TUint32 KSDCardIsSDCard = KBit16; // KMMCardFirstCustomFlag +const TUint32 KSDCardIsCorrupt = KBit17; const TUint32 KSDCardFirstCustomFlag = KBit24; const TUint KSDDTClk25MHz = 25000; //25000KHz diff -r 466a0df5c15a -r ea2434cf3670 kernel/eka/include/e32ver.h --- a/kernel/eka/include/e32ver.h Tue May 04 16:57:20 2010 +0100 +++ b/kernel/eka/include/e32ver.h Tue May 04 18:23:12 2010 +0100 @@ -28,7 +28,7 @@ const TInt KE32MajorVersionNumber=2; const TInt KE32MinorVersionNumber=0; -const TInt KE32BuildVersionNumber=3040; +const TInt KE32BuildVersionNumber=3053; const TInt KMachineConfigurationMajorVersionNumber=1; const TInt KMachineConfigurationMinorVersionNumber=0; diff -r 466a0df5c15a -r ea2434cf3670 kernel/eka/include/kernel/kerncorestats.h --- a/kernel/eka/include/kernel/kerncorestats.h Tue May 04 16:57:20 2010 +0100 +++ b/kernel/eka/include/kernel/kerncorestats.h Tue May 04 18:23:12 2010 +0100 @@ -1,7 +1,7 @@ // Copyright (c) 1994-2009 Nokia Corporation and/or its subsidiary(-ies). // All rights reserved. // This component and the accompanying materials are made available -// under the terms of "Eclipse Public License v1.0" +// under the terms of the License "Eclipse Public License v1.0" // which accompanies this distribution, and is available // at the URL "http://www.eclipse.org/legal/epl-v10.html". // diff -r 466a0df5c15a -r ea2434cf3670 kernel/eka/include/memmodel/epoc/mmubase/mmubase.h --- a/kernel/eka/include/memmodel/epoc/mmubase/mmubase.h Tue May 04 16:57:20 2010 +0100 +++ b/kernel/eka/include/memmodel/epoc/mmubase/mmubase.h Tue May 04 18:23:12 2010 +0100 @@ -410,6 +410,7 @@ TInt ZoneAllocPhysicalRam(TUint* aZoneIdList, TUint aZoneIdCount, TInt aNumPages, TPhysAddr* aPageList); TInt FreePhysicalRam(TPhysAddr aPhysAddr, TInt aSize); TInt FreePhysicalRam(TInt aNumPages, TPhysAddr* aPageList); + TInt FreeRamZone(TUint aZoneId, TPhysAddr& aZoneBase, TUint& aZoneBytes); TInt ClaimPhysicalRam(TPhysAddr aPhysAddr, TInt aSize); TInt GetPageTableId(TPhysAddr aPtPhys); void MapRamPage(TLinAddr aAddr, TPhysAddr aPage, TPte aPtePerm); diff -r 466a0df5c15a -r ea2434cf3670 kernel/eka/include/memmodel/epoc/mmubase/ramalloc.h --- a/kernel/eka/include/memmodel/epoc/mmubase/ramalloc.h Tue May 04 16:57:20 2010 +0100 +++ b/kernel/eka/include/memmodel/epoc/mmubase/ramalloc.h Tue May 04 18:23:12 2010 +0100 @@ -153,7 +153,7 @@ TInt GetZonePageCount(TUint aId, SRamZonePageCount& aPageData); void ChangePageType(SPageInfo* aPageInfo, TZonePageType aOldType, TZonePageType aNewType); #ifdef BTRACE_RAM_ALLOCATOR - void SendInitialBtraceLogs(void); + void DoBTracePrime(void); #endif TInt GetZoneAddress(TUint aZoneId, TPhysAddr& aPhysBase, TUint& aNumPages); TInt HalFunction(TInt aFunction, TAny* a1, TAny* a2); diff -r 466a0df5c15a -r ea2434cf3670 kernel/eka/include/memmodel/epoc/platform.h --- a/kernel/eka/include/memmodel/epoc/platform.h Tue May 04 16:57:20 2010 +0100 +++ b/kernel/eka/include/memmodel/epoc/platform.h Tue May 04 18:23:12 2010 +0100 @@ -382,6 +382,7 @@ IMPORT_C static TInt ZoneAllocPhysicalRam(TUint* aZoneIdList, TUint aZoneIdCount, TInt aNumPages, TPhysAddr* aPageList); IMPORT_C static TInt FreePhysicalRam(TPhysAddr aPhysAddr, TInt aSize); IMPORT_C static TInt FreePhysicalRam(TInt aNumPages, TPhysAddr* aPageList); + IMPORT_C static TInt FreeRamZone(TUint aZoneId); IMPORT_C static TInt ClaimPhysicalRam(TPhysAddr aPhysAddr, TInt aSize); IMPORT_C static TPhysAddr LinearToPhysical(TLinAddr aLinAddr); IMPORT_C static void RomProcessInfo(TProcessCreateInfo& aInfo, const TRomImageHeader& aRomImageHeader); /**< @internalComponent */ diff -r 466a0df5c15a -r ea2434cf3670 kernel/eka/kernel/arm/cipc.cia --- a/kernel/eka/kernel/arm/cipc.cia Tue May 04 16:57:20 2010 +0100 +++ b/kernel/eka/kernel/arm/cipc.cia Tue May 04 18:23:12 2010 +0100 @@ -57,7 +57,7 @@ __NAKED__ void ExecHandler::MessageComplete(RMessageK* /*aMsg*/, TInt /*aReason*/) { - asm("ldr ip, [r0, #%a0]" : : "i" _FOFF(RMessageK, iFunction)); // get iFunction, as per preprocessor + asm("ldr ip, [r0, #%a0]" : : "i" _FOFF(RMessageK, iFunction)); // get iFunction, as per preprocessor // Subroutine MessageComplete // Complete an IPC message @@ -69,65 +69,73 @@ #ifdef BTRACE_CLIENT_SERVER asm("stmfd sp!,{r0,r1,ip,lr}"); - asm("mov r2,r1"); // arg2 = aReason - asm("mov r1,r0"); // arg1 = aMsg - asm("ldr r0,_messageCompleteTraceHeader"); // arg0 = header + asm("mov r2,r1"); // arg2 = aReason + asm("mov r1,r0"); // arg1 = aMsg + asm("ldr r0,_messageCompleteTraceHeader"); // arg0 = header asm("bl " CSM_ZN6BTrace4OutXEmmmm); asm("ldmfd sp!,{r0,r1,ip,lr}"); #endif asm("cmp ip, #%a0" : : "i" (RMessage2::EDisConnect)); asm("ldreq r0, [r0, #%a0]" : : "i" _FOFF(RMessageK,iSession)); - asm("beq " CSM_ZN8DSession19CloseFromDisconnectEv ); // if disconnect, do it in C++ - asm("mov r2, r1 "); // r2=aReason + asm("beq " CSM_ZN8DSession19CloseFromDisconnectEv ); // if disconnect, do it in C++ + + asm("mov r2, r1 "); // r2 = aReason ASM_DEBUG2(Complete,r0,r2); - asm("ldr r3, [r0, #%a0]" : : "i" _FOFF(RMessageK, iSession)); // r3=iSession - - asm("subs r1, ip, #%a0" : : "i" (RMessage2::EConnect)); // (m.iFunction == RMessage2::EConnect)? - asm("streq r1, [r3, #%a0] " : : "i" _FOFF(DSession, iConnectMsgPtr)); // iSession->iConnectMsgPtr = NULL - - asm("ldr r1, [r3, #%a0]" : : "i" _FOFF(DSession,iAccessCount)); // r1=iSession->iAccessCount - asm("cmp r1, #0 "); // iAccessCount = 0? + asm("ldr r3, [r0, #%a0]" : : "i" _FOFF(RMessageK, iSession)); // r3 = iSession + asm("subs r1, ip, #%a0" : : "i" (RMessage2::EConnect)); // (m.iFunction == RMessage2::EConnect)? + asm("streq r1, [r3, #%a0] " : : "i" _FOFF(DSession, iConnectMsgPtr)); // iSession->iConnectMsgPtr = NULL + asm("ldr r1, [r3, #%a0]" : : "i" _FOFF(DSession,iAccessCount)); // r1 = iSession->iAccessCount + asm("cmp r1, #0 "); // iAccessCount = 0? asm("beq 2f "); - // if (!s->IsClosing()) - asm("mov r1, r0"); // r1 = RMessageK ptr - asm("ldr r0, [r0, #%a0] " : : "i" _FOFF(RMessageK,iClient)); // r0=iClient + // !s->IsClosing() + asm("mov r1, r0"); // r1 = RMessageK ptr + asm("ldr r0, [r0, #%a0] " : : "i" _FOFF(RMessageK,iClient)); // r0 = iClient + asm("ldrb ip, [r0, #%a0] " : : "i" _FOFF(DThread,iMState)); // ip = iClient->iMState + asm("cmp ip, #%a0" : : "i" (DThread::EDead)); // (iMState == EDead)? + asm("beq 1f "); + + // if (!s->IsClosing() && m.iClient->iMState != DThread::EDead) asm("mov ip, #1"); - asm("str ip, [r1, #%a0]" : : "i" _FOFF(RMessageK, iServerLink.iNext)); // iServerLink.iNext=1 - asm("b " CSM_ZN4Kern20QueueRequestCompleteEP7DThreadP14TClientRequesti); + asm("str ip, [r1, #%a0]" : : "i" _FOFF(RMessageK, iServerLink.iNext)); // iServerLink.iNext=1 + asm("b " CSM_ZN4Kern20QueueRequestCompleteEP7DThreadP14TClientRequesti); // tail call - // if (s->IsClosing()) + // m.iClient->iMState == DThread::EDead + asm("1: "); // shuffle RMessageK and iFunction back to expected registers + asm("ldr ip, [r1, #%a0]" : : "i" _FOFF(RMessageK, iFunction)); // refetch iFunction + asm("mov r0, r1"); // r0 = RMessageK ptr + + // else (closing or dead) asm("2: "); - asm("cmp ip, #%a0" : : "i" (RMessage2::EConnect)); // (m.iFunction == RMessage2::EConnect)? - asm("beq 4f "); - asm("3: "); - asm("stmfd sp!, {r0,lr} "); - asm("bl " CSM_ZN14TClientRequest5ResetEv); - asm("ldmfd sp!, {r0,lr} "); - asm("b " CSM_ZN9RMessageK8CloseRefEv); + asm("cmp ip, #%a0" : : "i" (RMessage2::EConnect)); // (m.iFunction == RMessage2::EConnect)? + asm("bne 3f "); - asm("4: "); - // if closing & connect msg - asm("ldr r2, [r3, #%a0] " : : "i" _FOFF(DSession, iSessionCookie)); // r2=iSession->iSessionCookie + // (closing or dead) and it's a connect msg + asm("ldr r2, [r3, #%a0] " : : "i" _FOFF(DSession, iSessionCookie)); // r2=iSession->iSessionCookie asm("teq r2, #0"); #ifdef _DEBUG asm("beq nosession "); - asm("ldr r1, [r3, #%a0] " : : "i" _FOFF(DSession, iServer)); // r1=iSession->iServer + asm("ldr r1, [r3, #%a0] " : : "i" _FOFF(DSession, iServer)); // r1=iSession->iServer asm("cmp r1, #0 "); asm("beq noserver "); - asm("ldr r2, [r3, #%a0] " : : "i" (_FOFF(DSession, iDisconnectMsgPtr))); // r2=iSession->iDisconnectMsgPtr + asm("ldr r2, [r3, #%a0] " : : "i" (_FOFF(DSession, iDisconnectMsgPtr))); // r2=iSession->iDisconnectMsgPtr asm("ldr r2, [r2, #%a0] " : : "i" (_FOFF(RMessageK, iServerLink.iNext))); // r2=iDisconnectMsgPtr->iServerLink.iNext asm("cmp r2, #0 "); - asm("beq __FaultMsgCompleteDiscNotSent "); // die if a session has been created and no disc msg sent - asm("ldr r2, [r3, #%a0] " : : "i" _FOFF(DSession, iSessionCookie)); // r2=iSession->iSessionCookie + asm("beq __FaultMsgCompleteDiscNotSent "); // tail call to die if a session has been created and no disc msg sent + asm("ldr r2, [r3, #%a0] " : : "i" _FOFF(DSession, iSessionCookie)); // r2=iSession->iSessionCookie asm("noserver: "); asm("teq r2, #0"); asm("nosession: "); #endif //_DEBUG asm("moveq r0, r3 "); - asm("beq __SendDiscMsg "); // if no session object to clean up, send disc msg in C++ - asm("b 3b "); // return + asm("beq __SendDiscMsg "); // if no session object to clean up, tail call to send disc msg in C++ + + asm("3: "); + asm("stmfd sp!, {r0,lr} "); + asm("bl " CSM_ZN14TClientRequest5ResetEv); + asm("ldmfd sp!, {r0,lr} "); + asm("b " CSM_ZN9RMessageK8CloseRefEv); // tail call #ifdef BTRACE_CLIENT_SERVER asm("_messageCompleteTraceHeader:"); diff -r 466a0df5c15a -r ea2434cf3670 kernel/eka/kernel/kerncorestats.cpp --- a/kernel/eka/kernel/kerncorestats.cpp Tue May 04 16:57:20 2010 +0100 +++ b/kernel/eka/kernel/kerncorestats.cpp Tue May 04 18:23:12 2010 +0100 @@ -1,7 +1,7 @@ // Copyright (c) 1994-2009 Nokia Corporation and/or its subsidiary(-ies). // All rights reserved. // This component and the accompanying materials are made available -// under the terms of "Eclipse Public License v1.0" +// under the terms of the License "Eclipse Public License v1.0" // which accompanies this distribution, and is available // at the URL "http://www.eclipse.org/legal/epl-v10.html". // diff -r 466a0df5c15a -r ea2434cf3670 kernel/eka/kernel/sexec.cpp --- a/kernel/eka/kernel/sexec.cpp Tue May 04 16:57:20 2010 +0100 +++ b/kernel/eka/kernel/sexec.cpp Tue May 04 18:23:12 2010 +0100 @@ -758,7 +758,7 @@ __KTRACE_OPT(KEXEC,Kern::Printf("Exec::ThreadRequestSignal")); if(aThread->iOwningProcess!=TheCurrentThread->iOwningProcess) - K::ProcessIsolationFailure(__PLATSEC_DIAGNOSTIC_STRING("Attempt to use RThread::RequestComplete on a thread in another process")); + K::ProcessIsolationFailure(__PLATSEC_DIAGNOSTIC_STRING("Attempt to use RThread::RequestComplete or RThread::RequestSignal on a thread in another process")); NKern::ThreadRequestSignal(&aThread->iNThread, SYSTEM_LOCK); } diff -r 466a0df5c15a -r ea2434cf3670 kernel/eka/kernel/sipc.cpp --- a/kernel/eka/kernel/sipc.cpp Tue May 04 16:57:20 2010 +0100 +++ b/kernel/eka/kernel/sipc.cpp Tue May 04 18:23:12 2010 +0100 @@ -1144,7 +1144,7 @@ if(m->IsDelivered() || m->IsAccepted()) { - if (!IsClosing()) + if (!IsClosing() && t->iMState != DThread::EDead) { m->SetCompleting(); Kern::QueueRequestComplete(t, m, aReason); @@ -1752,7 +1752,7 @@ s->iConnectMsgPtr = NULL; __KTRACE_OPT(KIPC,Kern::Printf("MsgCo: M:%d r:%d %O->%O", m.iFunction, aReason, TheCurrentThread, m.iClient)); - if (!s->IsClosing()) + if (!s->IsClosing() && m.iClient->iMState != DThread::EDead) { m.SetCompleting(); Kern::QueueRequestComplete(m.iClient, &m, aReason); diff -r 466a0df5c15a -r ea2434cf3670 kernel/eka/kernel/sthread.cpp --- a/kernel/eka/kernel/sthread.cpp Tue May 04 16:57:20 2010 +0100 +++ b/kernel/eka/kernel/sthread.cpp Tue May 04 18:23:12 2010 +0100 @@ -114,8 +114,23 @@ iTls.Close(); if (iSyncMsgPtr) { - __KTRACE_OPT(KSERVER,Kern::Printf("DThread::Destruct(%08X) freeing sync message at %08X", this, iSyncMsgPtr)); - iSyncMsgPtr->ReleaseMessagePool(RMessageK::ESync, 1); + // The sync message might still be outstanding; in particular it may be + // on the kernel server's list of messages to be cleaned up on behalf of + // dead clients. So we only release it here if it's free; otherwise, we + // mutate the type, so that cleanup will return it to the Global pool. + NKern::LockSystem(); + if (iSyncMsgPtr->IsFree()) + { + NKern::UnlockSystem(); + __KTRACE_OPT(KSERVER,Kern::Printf("DThread::Destruct(%08X) releasing sync message at %08X", this, iSyncMsgPtr)); + iSyncMsgPtr->ReleaseMessagePool(RMessageK::ESync, 1); + } + else + { + __KTRACE_OPT(KSERVER,Kern::Printf("DThread::Destruct(%08X) mutating sync message at %08X", this, iSyncMsgPtr)); + iSyncMsgPtr->iMsgType = RMessageK::EGlobal; + NKern::UnlockSystem(); + } iSyncMsgPtr = NULL; } FreeSupervisorStack(); diff -r 466a0df5c15a -r ea2434cf3670 kernel/eka/memmodel/epoc/direct/mutils.cpp --- a/kernel/eka/memmodel/epoc/direct/mutils.cpp Tue May 04 16:57:20 2010 +0100 +++ b/kernel/eka/memmodel/epoc/direct/mutils.cpp Tue May 04 18:23:12 2010 +0100 @@ -474,6 +474,32 @@ /** +Free a RAM zone which was previously allocated by one of these methods: +Epoc::AllocPhysicalRam(), Epoc::ZoneAllocPhysicalRam() or +TRamDefragRequest::ClaimRamZone(). + +All of the pages in the RAM zone must be allocated and only via one of the methods +listed above, otherwise a system panic will occur. + +@param aZoneId The ID of the RAM zone to free. +@return KErrNone If the operation was successful. + KErrArgument If a RAM zone with ID aZoneId was not found. + +@pre Calling thread must be in a critical section. +@pre Interrupts must be enabled. +@pre Kernel must be unlocked. +@pre No fast mutex can be held. +@pre Call in a thread context. +@pre Can be used in a device driver. +*/ +EXPORT_C TInt Epoc::FreeRamZone(TUint aZoneId) + { + CHECK_PRECONDITIONS(MASK_THREAD_CRITICAL,"Epoc::FreeRamZone"); + return KErrNotSupported; + } + + +/** @pre Call in a thread context. @pre Interrupts must be enabled. @pre Kernel must be unlocked. diff -r 466a0df5c15a -r ea2434cf3670 kernel/eka/memmodel/epoc/flexible/mmu/mcodepaging.cpp --- a/kernel/eka/memmodel/epoc/flexible/mmu/mcodepaging.cpp Tue May 04 16:57:20 2010 +0100 +++ b/kernel/eka/memmodel/epoc/flexible/mmu/mcodepaging.cpp Tue May 04 18:23:12 2010 +0100 @@ -64,7 +64,7 @@ */ static DCodePagedMemoryManager TheManager; - friend DPagingDevice* CodePagingDevice(TInt aDiveNum); + friend DPagingDevice* CodePagingDevice(TInt aDriveNum); }; @@ -207,11 +207,11 @@ TInt DCodePagedMemoryManager::CleanPage(DMemoryObject* aMemory, SPageInfo* aPageInfo, TPhysAddr*& aPageArrayEntry) { - if(aPageInfo->IsDirty()==false) + if(!aPageInfo->IsDirty()) return KErrNone; // shouldn't be asked to clean a page which is writable... - __NK_ASSERT_DEBUG(aPageInfo->IsWritable()==false); + __NK_ASSERT_DEBUG(!aPageInfo->IsWritable()); // Note, memory may have been modified by the CodeModifier class. diff -r 466a0df5c15a -r ea2434cf3670 kernel/eka/memmodel/epoc/flexible/mmu/mcodepaging.h --- a/kernel/eka/memmodel/epoc/flexible/mmu/mcodepaging.h Tue May 04 16:57:20 2010 +0100 +++ b/kernel/eka/memmodel/epoc/flexible/mmu/mcodepaging.h Tue May 04 18:23:12 2010 +0100 @@ -21,6 +21,6 @@ #ifndef MCODEPAGING_H #define MCODEPAGING_H -extern DPagingDevice* CodePagingDevice(TInt aDiveNum); +extern DPagingDevice* CodePagingDevice(TInt aDriveNum); #endif diff -r 466a0df5c15a -r ea2434cf3670 kernel/eka/memmodel/epoc/flexible/mmu/mexport.cpp --- a/kernel/eka/memmodel/epoc/flexible/mmu/mexport.cpp Tue May 04 16:57:20 2010 +0100 +++ b/kernel/eka/memmodel/epoc/flexible/mmu/mexport.cpp Tue May 04 18:23:12 2010 +0100 @@ -16,7 +16,7 @@ #include "memmodel.h" #include "mm.h" #include "mmu.h" - +#include "mpager.h" #include "mrom.h" /** Returns the amount of free RAM currently available. @@ -510,6 +510,35 @@ /** +Free a RAM zone which was previously allocated by one of these methods: +Epoc::AllocPhysicalRam(), Epoc::ZoneAllocPhysicalRam() or +TRamDefragRequest::ClaimRamZone(). + +All of the pages in the RAM zone must be allocated and only via one of the methods +listed above, otherwise a system panic will occur. + +@param aZoneId The ID of the RAM zone to free. +@return KErrNone If the operation was successful. + KErrArgument If a RAM zone with ID aZoneId was not found. + +@pre Calling thread must be in a critical section. +@pre Interrupts must be enabled. +@pre Kernel must be unlocked. +@pre No fast mutex can be held. +@pre Call in a thread context. +@pre Can be used in a device driver. +*/ +EXPORT_C TInt Epoc::FreeRamZone(TUint aZoneId) + { + CHECK_PRECONDITIONS(MASK_THREAD_CRITICAL,"Epoc::FreeRamZone"); + RamAllocLock::Lock(); + TInt r = TheMmu.FreeRamZone(aZoneId); + RamAllocLock::Unlock(); + return r; + } + + +/** Allocate a specific block of physically contiguous RAM, specified by physical base address and size. If and when the RAM is no longer required it should be freed using @@ -607,13 +636,29 @@ } -#ifdef BTRACE_KERNEL_MEMORY void M::BTracePrime(TUint aCategory) { - // TODO: + (void)aCategory; + +#ifdef BTRACE_KERNEL_MEMORY + // Must check for -1 as that is the default value of aCategory for + // BTrace::Prime() which is intended to prime all categories that are + // currently enabled via a single invocation of BTrace::Prime(). + if(aCategory == BTrace::EKernelMemory || (TInt)aCategory == -1) + { + NKern::ThreadEnterCS(); + RamAllocLock::Lock(); + BTrace4(BTrace::EKernelMemory, BTrace::EKernelMemoryInitialFree, TheSuperPage().iTotalRamSize); + BTrace4(BTrace::EKernelMemory, BTrace::EKernelMemoryCurrentFree, Kern::FreeRamInBytes()); + BTrace4(BTrace::EKernelMemory, BTrace::EKernelMemoryMiscAlloc, Epoc::KernelMiscPages << KPageShift); + BTrace4(BTrace::EKernelMemory, BTrace::EKernelMemoryDemandPagingCache, ThePager.MinimumPageCount() << KPageShift); + BTrace8(BTrace::EKernelMemory, BTrace::EKernelMemoryDrvPhysAlloc, Epoc::DriverAllocdPhysRam, -1); + RamAllocLock::Unlock(); + NKern::ThreadLeaveCS(); + } +#endif + TheMmu.BTracePrime(aCategory); } -#endif - // diff -r 466a0df5c15a -r ea2434cf3670 kernel/eka/memmodel/epoc/flexible/mmu/mm.cpp --- a/kernel/eka/memmodel/epoc/flexible/mmu/mm.cpp Tue May 04 16:57:20 2010 +0100 +++ b/kernel/eka/memmodel/epoc/flexible/mmu/mm.cpp Tue May 04 18:23:12 2010 +0100 @@ -394,7 +394,7 @@ } -TInt MM::MemoryAddPages(DMemoryObject* aMemory, TUint aIndex, TUint aCount, TPhysAddr* aPages) +TInt MM::MemoryAddPages(DMemoryObject* aMemory, TUint aIndex, TUint aCount, const TPhysAddr* aPages) { TRACE(("MM::MemoryAddPages(0x%08x,0x%08x,0x%08x,?)",aMemory,aIndex,aCount)); MemoryObjectLock::Lock(aMemory); diff -r 466a0df5c15a -r ea2434cf3670 kernel/eka/memmodel/epoc/flexible/mmu/mm.h --- a/kernel/eka/memmodel/epoc/flexible/mmu/mm.h Tue May 04 16:57:20 2010 +0100 +++ b/kernel/eka/memmodel/epoc/flexible/mmu/mm.h Tue May 04 18:23:12 2010 +0100 @@ -84,6 +84,9 @@ EMemoryObjectMovable but with the additional option of marking pages as 'discardable'. Discardable pages may be reclaimed (remove) by the system at any time, this state is controlled using the functions: + - MM::MemoryAlloc + - MM::MemoryAllocContiguous + - MM::MemoryFree - MM::MemoryAllowDiscard - MM::MemoryDisallowDiscard */ @@ -485,7 +488,7 @@ KErrNotSupported, if the memory object doesn't support this operation; otherwise another of the system wide error codes. */ - static TInt MemoryAddPages(DMemoryObject* aMemory, TUint aIndex, TUint aCount, TPhysAddr* aPages); + static TInt MemoryAddPages(DMemoryObject* aMemory, TUint aIndex, TUint aCount, const TPhysAddr* aPages); /** Add a contiguous range of pages to a region in a memory object. diff -r 466a0df5c15a -r ea2434cf3670 kernel/eka/memmodel/epoc/flexible/mmu/mmanager.cpp --- a/kernel/eka/memmodel/epoc/flexible/mmu/mmanager.cpp Tue May 04 16:57:20 2010 +0100 +++ b/kernel/eka/memmodel/epoc/flexible/mmu/mmanager.cpp Tue May 04 18:23:12 2010 +0100 @@ -66,7 +66,7 @@ } -TInt DMemoryManager::AddPages(DMemoryObject* /*aMemory*/, TUint /*aIndex*/, TUint /*aCount*/, TPhysAddr* /*aPages*/) +TInt DMemoryManager::AddPages(DMemoryObject* /*aMemory*/, TUint /*aIndex*/, TUint /*aCount*/, const TPhysAddr* /*aPages*/) { return KErrNotSupported; } @@ -1161,7 +1161,7 @@ public: // from DMemoryManager... virtual void Destruct(DMemoryObject* aMemory); - virtual TInt AddPages(DMemoryObject* aMemory, TUint aIndex, TUint aCount, TPhysAddr* aPages); + virtual TInt AddPages(DMemoryObject* aMemory, TUint aIndex, TUint aCount, const TPhysAddr* aPages); virtual TInt AddContiguous(DMemoryObject* aMemory, TUint aIndex, TUint aCount, TPhysAddr aPhysAddr); virtual TInt RemovePages(DMemoryObject* aMemory, TUint aIndex, TUint aCount, TPhysAddr* aPages); virtual TInt Pin(DMemoryObject* aMemory, DMemoryMappingBase* aMapping, TPinArgs& aPinArgs); @@ -1226,14 +1226,14 @@ } -TInt DHardwareMemoryManager::AddPages(DMemoryObject* aMemory, TUint aIndex, TUint aCount, TPhysAddr* aPages) +TInt DHardwareMemoryManager::AddPages(DMemoryObject* aMemory, TUint aIndex, TUint aCount, const TPhysAddr* aPages) { TRACE2(("DHardwareMemoryManager::AddPages(0x%08x,0x%x,0x%x,?)",aMemory, aIndex, aCount)); __NK_ASSERT_DEBUG(MemoryObjectLock::IsHeld(aMemory)); // validate arguments... - TPhysAddr* pages = aPages; - TPhysAddr* pagesEnd = aPages+aCount; + const TPhysAddr* pages = aPages; + const TPhysAddr* pagesEnd = aPages+aCount; TPhysAddr checkMask = 0; do checkMask |= *pages++; while(pagesType()==SPageInfo::EUnused) pi->SetFixed(); +#ifdef BTRACE_KERNEL_MEMORY + if(r == KErrNone) + ++Epoc::KernelMiscPages; +#endif } } } @@ -500,21 +505,24 @@ r = K::MutexCreate(iPhysMemSyncMutex, KLitPhysMemSync, NULL, EFalse, KMutexOrdSyncPhysMem); if(r!=KErrNone) Panic(EPhysMemSyncMutexCreateFailed); -// VerifyRam(); + +#ifdef FMM_VERIFY_RAM + VerifyRam(); +#endif } void Mmu::Init2FinalCommon() { __KTRACE_OPT2(KBOOT,KMMU,Kern::Printf("Mmu::Init2FinalCommon")); - // hack, reduce free memory to <2GB... + // Reduce free memory to <2GB... while(FreeRamInPages()>=0x80000000/KPageSize) { TPhysAddr dummyPage; TInt r = iRamPageAllocator->AllocRamPages(&dummyPage,1, EPageFixed); __NK_ASSERT_ALWAYS(r==KErrNone); } - // hack, reduce total RAM to <2GB... + // Reduce total RAM to <2GB... if(TheSuperPage().iTotalRamSize<0) TheSuperPage().iTotalRamSize = 0x80000000-KPageSize; @@ -540,6 +548,27 @@ iDefrag->Init3(TheMmu.iRamPageAllocator); } + +void Mmu::BTracePrime(TUint aCategory) + { + (void)aCategory; + +#ifdef BTRACE_RAM_ALLOCATOR + // Must check for -1 as that is the default value of aCategory for + // BTrace::Prime() which is intended to prime all categories that are + // currently enabled via a single invocation of BTrace::Prime(). + if(aCategory==BTrace::ERamAllocator || (TInt)aCategory == -1) + { + NKern::ThreadEnterCS(); + RamAllocLock::Lock(); + iRamPageAllocator->DoBTracePrime(); + RamAllocLock::Unlock(); + NKern::ThreadLeaveCS(); + } +#endif + } + + // // Utils // @@ -619,18 +648,7 @@ PagesAllocated(aPageList, aNumPages, (Mmu::TRamAllocFlags)EMemAttStronglyOrdered); // update page infos... - TUint flash = 0; - TPhysAddr* pageEnd = aPageList + aNumPages; - MmuLock::Lock(); - TPhysAddr* page = aPageList; - while (page < pageEnd) - { - MmuLock::Flash(flash,KMaxPageInfoUpdatesInOneGo/2); - TPhysAddr pagePhys = *page++; - __NK_ASSERT_DEBUG(pagePhys != KPhysAddrInvalid); - SPageInfo::FromPhysAddr(pagePhys)->SetPhysAlloc(); - } - MmuLock::Unlock(); + SetAllocPhysRam(aPageList, aNumPages); } __KTRACE_OPT(KMMU,Kern::Printf("Mmu::ZoneAllocPhysicalRam returns %d",r)); return r; @@ -963,19 +981,7 @@ return r; // update page infos... - TPhysAddr* pages = aPages; - TPhysAddr* pagesEnd = pages+aCount; - MmuLock::Lock(); - TUint flash = 0; - while(pagesSetPhysAlloc(); - } - MmuLock::Unlock(); + SetAllocPhysRam(aPages, aCount); return KErrNone; } @@ -1004,6 +1010,19 @@ MmuLock::Unlock(); iRamPageAllocator->FreeRamPages(aPages,aCount, EPageFixed); + +#ifdef BTRACE_KERNEL_MEMORY + if (BTrace::CheckFilter(BTrace::EKernelMemory)) + {// Only loop round each page if EKernelMemory tracing is enabled + pages = aPages; + pagesEnd = aPages + aCount; + while (pages < pagesEnd) + { + BTrace8(BTrace::EKernelMemory, BTrace::EKernelMemoryDrvPhysFree, KPageSize, *pages++); + Epoc::DriverAllocdPhysRam -= KPageSize; + } + } +#endif } @@ -1015,17 +1034,7 @@ return r; // update page infos... - SPageInfo* pi = SPageInfo::FromPhysAddr(aPhysAddr); - SPageInfo* piEnd = pi+aCount; - TUint flash = 0; - MmuLock::Lock(); - while(piSetPhysAlloc(); - ++pi; - } - MmuLock::Unlock(); + SetAllocPhysRam(aPhysAddr, aCount); return KErrNone; } @@ -1050,7 +1059,25 @@ } MmuLock::Unlock(); - iRamPageAllocator->FreePhysicalRam(aPhysAddr, aCount << KPageShift); + TUint bytes = aCount << KPageShift; + iRamPageAllocator->FreePhysicalRam(aPhysAddr, bytes); + +#ifdef BTRACE_KERNEL_MEMORY + BTrace8(BTrace::EKernelMemory, BTrace::EKernelMemoryDrvPhysFree, bytes, aPhysAddr); + Epoc::DriverAllocdPhysRam -= bytes; +#endif + } + + +TInt Mmu::FreeRamZone(TUint aZoneId) + { + TPhysAddr zoneBase; + TUint zonePages; + TInt r = iRamPageAllocator->GetZoneAddress(aZoneId, zoneBase, zonePages); + if (r != KErrNone) + return r; + FreePhysicalRam(zoneBase, zonePages); + return KErrNone; } @@ -1058,25 +1085,11 @@ { __KTRACE_OPT(KMMU,Kern::Printf("Mmu::ClaimPhysicalRam(0x%08x,0x%x,0x%08x)",aPhysAddr,aCount,aFlags)); aPhysAddr &= ~KPageMask; - TInt r = iRamPageAllocator->ClaimPhysicalRam(aPhysAddr,(aCount << KPageShift)); - if(r!=KErrNone) + TInt r = iRamPageAllocator->ClaimPhysicalRam(aPhysAddr, aCount << KPageShift); + if(r != KErrNone) return r; - PagesAllocated((TPhysAddr*)(aPhysAddr|1), aCount, aFlags); - - // update page infos... - SPageInfo* pi = SPageInfo::FromPhysAddr(aPhysAddr); - SPageInfo* piEnd = pi+aCount; - TUint flash = 0; - MmuLock::Lock(); - while(piSetPhysAlloc(); - ++pi; - } - MmuLock::Unlock(); - + AllocatedPhysicalRam(aPhysAddr, aCount, aFlags); return KErrNone; } @@ -1088,17 +1101,59 @@ PagesAllocated((TPhysAddr*)(aPhysAddr|1), aCount, aFlags); // update page infos... + SetAllocPhysRam(aPhysAddr, aCount); + } + + +void Mmu::SetAllocPhysRam(TPhysAddr aPhysAddr, TUint aCount) + { SPageInfo* pi = SPageInfo::FromPhysAddr(aPhysAddr); SPageInfo* piEnd = pi+aCount; TUint flash = 0; MmuLock::Lock(); while(piSetPhysAlloc(); ++pi; } MmuLock::Unlock(); + +#ifdef BTRACE_KERNEL_MEMORY + TUint bytes = aCount << KPageShift; + BTrace8(BTrace::EKernelMemory, BTrace::EKernelMemoryDrvPhysAlloc, bytes, aPhysAddr); + Epoc::DriverAllocdPhysRam += bytes; +#endif + } + + +void Mmu::SetAllocPhysRam(TPhysAddr* aPageList, TUint aNumPages) + { + TPhysAddr* page = aPageList; + TPhysAddr* pageEnd = aPageList + aNumPages; + TUint flash = 0; + MmuLock::Lock(); + while (page < pageEnd) + { + MmuLock::Flash(flash, KMaxPageInfoUpdatesInOneGo / 2); + TPhysAddr pagePhys = *page++; + __NK_ASSERT_DEBUG(pagePhys != KPhysAddrInvalid); + SPageInfo::FromPhysAddr(pagePhys)->SetPhysAlloc(); + } + MmuLock::Unlock(); + +#ifdef BTRACE_KERNEL_MEMORY + if (BTrace::CheckFilter(BTrace::EKernelMemory)) + {// Only loop round each page if EKernelMemory tracing is enabled + TPhysAddr* pAddr = aPageList; + TPhysAddr* pAddrEnd = aPageList + aNumPages; + while (pAddr < pAddrEnd) + { + BTrace8(BTrace::EKernelMemory, BTrace::EKernelMemoryDrvPhysAlloc, KPageSize, *pAddr++); + Epoc::DriverAllocdPhysRam += KPageSize; + } + } +#endif } @@ -1187,20 +1242,10 @@ __NK_ASSERT_DEBUG(iSize>=1); __NK_ASSERT_DEBUG(iCount==0); - TUint colour = aColour&KPageColourMask; - TLinAddr addr = iLinAddr+(colour<=1); __NK_ASSERT_DEBUG(iCount==0); - - TUint colour = aColour&KPageColourMask; - TLinAddr addr = iLinAddr+(colour<iNext; - if(link==head) - return false; + if(link == aHead) + return EFalse; } link = link->iNext; - if(link!=head) - return false; - - head = &iYoungList.iA; - n = iYoungCount; - link = head; - while(n--) - { - link = link->iNext; - if(link==head) - return false; - } - link = link->iNext; - if(link!=head) - return false; - -// TRACEP(("DP: y=%d o=%d f=%d",iYoungCount,iOldCount,iNumberOfFreePages)); -#endif -// TraceCounts(); + if(link != aHead) + return EFalse; + return ETrue; + } +#endif // #ifdef FMM_PAGER_CHECK_LISTS + +TBool DPager::CheckLists() + { +#ifdef FMM_PAGER_CHECK_LISTS + __NK_ASSERT_DEBUG(MmuLock::IsHeld()); + if (!CheckList(&iOldList.iA, iOldCount)) + return EFalse; + if (!CheckList(&iYoungList.iA, iYoungCount)) + return EFalse; + if (!CheckList(&iOldestCleanList.iA, iOldestCleanCount)) + return EFalse; + if (!CheckList(&iOldestDirtyList.iA, iOldestDirtyCount)) + return EFalse; + TRACEP(("DP: y=%d o=%d oc=%d od=%d f=%d", iYoungCount, iOldCount, + iOldestCleanCount, iOldestDirtyCount, iNumberOfFreePages)); + TraceCounts(); +#endif // #ifdef FMM_PAGER_CHECK_LISTS return true; } void DPager::TraceCounts() { - TRACEP(("DP: y=%d o=%d f=%d min=%d max=%d ml=%d res=%d", - iYoungCount,iOldCount,iNumberOfFreePages,iMinimumPageCount, - iMaximumPageCount,iMinimumPageLimit,iReservePageCount)); + TRACEP(("DP: y=%d o=%d oc=%d od=%d f=%d min=%d max=%d ml=%d res=%d", + iYoungCount, iOldCount, iOldestCleanCount, iOldestDirtyCount, + iNumberOfFreePages, iMinimumPageCount, iMaximumPageCount, + iMinimumPageLimit, iReservePageCount)); } - -#endif +#endif //#ifdef _DEBUG TBool DPager::HaveTooManyPages() @@ -1984,7 +1983,7 @@ MmuLock::Lock(); - __NK_ASSERT_ALWAYS(iYoungOldRatio!=0); + __NK_ASSERT_ALWAYS(iYoungOldRatio); // Make sure aMinimumPageCount is not less than absolute minimum we can cope with... iMinimumPageLimit = iMinYoungPages * (1 + iYoungOldRatio) / iYoungOldRatio @@ -1997,9 +1996,8 @@ aMaximumPageCount=aMinimumPageCount; // Increase iMaximumPageCount? - TInt extra = aMaximumPageCount-iMaximumPageCount; - if(extra>0) - iMaximumPageCount += extra; + if(aMaximumPageCount > iMaximumPageCount) + iMaximumPageCount = aMaximumPageCount; // Reduce iMinimumPageCount? TInt spare = iMinimumPageCount-aMinimumPageCount; @@ -2837,15 +2835,15 @@ EXPORT_C TInt DDemandPagingLock::Lock(DThread* aThread, TLinAddr aStart, TInt aSize) { // TRACEP(("DDemandPagingLock[0x%08x]::Lock(0x%08x,0x%08x,0x%08x)",this,aThread,aStart,aSize)); - if(iLockedPageCount) - __NK_ASSERT_ALWAYS(0); // lock already used + __NK_ASSERT_ALWAYS(!iLockedPageCount); // lock already used // calculate the number of pages that need to be locked... TUint mask=KPageMask; TUint offset=aStart&mask; TInt numPages = (aSize+offset+mask)>>KPageShift; - if(numPages>iMaxPageCount) - __NK_ASSERT_ALWAYS(0); + + // Should never be asked to lock more pages than are allocated to this object. + __NK_ASSERT_ALWAYS(numPages <= iMaxPageCount); NKern::ThreadEnterCS(); diff -r 466a0df5c15a -r ea2434cf3670 kernel/eka/memmodel/epoc/flexible/mmu/mpager.h --- a/kernel/eka/memmodel/epoc/flexible/mmu/mpager.h Tue May 04 16:57:20 2010 +0100 +++ b/kernel/eka/memmodel/epoc/flexible/mmu/mpager.h Tue May 04 18:23:12 2010 +0100 @@ -57,6 +57,11 @@ MmuLock::Unlock(); return ret; } + + FORCE_INLINE TUint MinimumPageCount() + { + return iMinimumPageCount; + } FORCE_INLINE void SetWritable(SPageInfo& aPageInfo) { diff -r 466a0df5c15a -r ea2434cf3670 kernel/eka/memmodel/epoc/flexible/mmu/mpdalloc.cpp --- a/kernel/eka/memmodel/epoc/flexible/mmu/mpdalloc.cpp Tue May 04 16:57:20 2010 +0100 +++ b/kernel/eka/memmodel/epoc/flexible/mmu/mpdalloc.cpp Tue May 04 18:23:12 2010 +0100 @@ -134,7 +134,14 @@ RamAllocLock::Lock(); TInt r = m.AllocContiguousRam(pdPhys, KLocalPdPages, KLocalPdShift-KPageShift, iPageDirectoryMemory->RamAllocFlags()); if(r==KErrNone) + { AssignPages(offset>>KPageShift,KLocalPdPages,pdPhys); + +#ifdef BTRACE_KERNEL_MEMORY + BTrace4(BTrace::EKernelMemory, BTrace::EKernelMemoryMiscAlloc, KLocalPdPages << KPageShift); + Epoc::KernelMiscPages += KLocalPdPages; +#endif + } RamAllocLock::Unlock(); if(r==KErrNone) @@ -147,6 +154,11 @@ { RamAllocLock::Lock(); m.FreeContiguousRam(pdPhys,KLocalPdPages); + +#ifdef BTRACE_KERNEL_MEMORY + BTrace4(BTrace::EKernelMemory, BTrace::EKernelMemoryMiscFree, KLocalPdPages << KPageShift); + Epoc::KernelMiscPages -= KLocalPdPages; +#endif RamAllocLock::Unlock(); } else @@ -206,6 +218,11 @@ Mmu& m = TheMmu; // Page directories are fixed. m.FreeRam(pages, KLocalPdPages, EPageFixed); + +#ifdef BTRACE_KERNEL_MEMORY + BTrace4(BTrace::EKernelMemory, BTrace::EKernelMemoryMiscFree, KLocalPdPages << KPageShift); + Epoc::KernelMiscPages -= KLocalPdPages; +#endif RamAllocLock::Unlock(); } diff -r 466a0df5c15a -r ea2434cf3670 kernel/eka/memmodel/epoc/flexible/mmu/mptalloc.cpp --- a/kernel/eka/memmodel/epoc/flexible/mmu/mptalloc.cpp Tue May 04 16:57:20 2010 +0100 +++ b/kernel/eka/memmodel/epoc/flexible/mmu/mptalloc.cpp Tue May 04 18:23:12 2010 +0100 @@ -177,6 +177,14 @@ else {// Allocate fixed paged as page tables aren't movable. r = TheMmu.AllocRam(&pagePhys, 1, aMemory->RamAllocFlags(), EPageFixed); + +#ifdef BTRACE_KERNEL_MEMORY + if (r == KErrNone) + { + BTrace4(BTrace::EKernelMemory, BTrace::EKernelMemoryMiscAlloc, KPageSize); + ++Epoc::KernelMiscPages; + } +#endif } RamAllocLock::Unlock(); @@ -241,7 +249,14 @@ if(aDemandPaged) ThePager.PageInFreePages(&pagePhys,1); else + { TheMmu.FreeRam(&pagePhys, 1, EPageFixed); + +#ifdef BTRACE_KERNEL_MEMORY + BTrace4(BTrace::EKernelMemory, BTrace::EKernelMemoryMiscFree, KPageSize); + --Epoc::KernelMiscPages; +#endif + } r = 1; } @@ -362,11 +377,8 @@ { iReserveCount = aReserveCount; iDemandPaged = aDemandPaged; - while(iFreeCountAllocReserve(*this)) - { - __NK_ASSERT_ALWAYS(0); - } + while(iFreeCount < aReserveCount) + __NK_ASSERT_ALWAYS(aAllocator->AllocReserve(*this)); } diff -r 466a0df5c15a -r ea2434cf3670 kernel/eka/memmodel/epoc/flexible/mmu/mrom.cpp --- a/kernel/eka/memmodel/epoc/flexible/mmu/mrom.cpp Tue May 04 16:57:20 2010 +0100 +++ b/kernel/eka/memmodel/epoc/flexible/mmu/mrom.cpp Tue May 04 18:23:12 2010 +0100 @@ -969,6 +969,11 @@ MmuLock::Lock(); SPageInfo::FromPhysAddr(iNewPage)->SetShadow(aIndex,aMemory->PageInfoFlags()); MmuLock::Unlock(); + +#ifdef BTRACE_KERNEL_MEMORY + BTrace4(BTrace::EKernelMemory, BTrace::EKernelMemoryMiscAlloc, KPageSize); + ++Epoc::KernelMiscPages; +#endif } RamAllocLock::Unlock(); @@ -992,6 +997,11 @@ { RamAllocLock::Lock(); TheMmu.FreeRam(&iNewPage, 1, EPageFixed); + +#ifdef BTRACE_KERNEL_MEMORY + BTrace4(BTrace::EKernelMemory, BTrace::EKernelMemoryMiscFree, KPageSize); + --Epoc::KernelMiscPages; +#endif RamAllocLock::Unlock(); } if(IsAttached()) diff -r 466a0df5c15a -r ea2434cf3670 kernel/eka/memmodel/epoc/flexible/mmu/mvalloc.cpp --- a/kernel/eka/memmodel/epoc/flexible/mmu/mvalloc.cpp Tue May 04 16:57:20 2010 +0100 +++ b/kernel/eka/memmodel/epoc/flexible/mmu/mvalloc.cpp Tue May 04 18:23:12 2010 +0100 @@ -688,7 +688,7 @@ RVirtualAllocSlabSet* RVirtualAllocSlabSet::New(RVirtualAllocator* aAllocator, TUint aNumSlabTypes, DMutex*& aWriteLock) { - TUint size = sizeof(RVirtualAllocSlabSet)+sizeof(((RVirtualAllocSlabSet*)0x100)->iSlabs)*(aNumSlabTypes-1); + TUint size = sizeof(RVirtualAllocSlabSet) + sizeof(SDblQue) * (aNumSlabTypes - 1); RVirtualAllocSlabSet* set = (RVirtualAllocSlabSet*)Kern::AllocZ(size); if(set) new (set) RVirtualAllocSlabSet(aAllocator,aNumSlabTypes,aWriteLock); @@ -764,8 +764,9 @@ if(!slab) return KErrNoMemory; TLinAddr addr = slab->Alloc(aSizeShift); - if(!addr) - return KErrNoMemory; + // Shouldn't ever fail as we've just allocated an empty slab and we can't + // attempt to allocate more than a whole slab. + __NK_ASSERT_DEBUG(addr); aAddr = addr; return KErrNone; } @@ -830,8 +831,8 @@ RVirtualAllocator::~RVirtualAllocator() { __NK_ASSERT_DEBUG(iAllocator==0 || iAllocator->iAvail==iAllocator->iSize); // should be empty - Kern::Free(iAllocator); - Kern::Free(iSlabSet); + delete iAllocator; + delete iSlabSet; } diff -r 466a0df5c15a -r ea2434cf3670 kernel/eka/memmodel/epoc/mmubase/defragbase.cpp --- a/kernel/eka/memmodel/epoc/mmubase/defragbase.cpp Tue May 04 16:57:20 2010 +0100 +++ b/kernel/eka/memmodel/epoc/mmubase/defragbase.cpp Tue May 04 18:23:12 2010 +0100 @@ -405,7 +405,7 @@ BTrace4(BTrace::ERamAllocator, BTrace::ERamAllocClaimZone, zone->iId); #endif -#ifdef BTRACE_KERNEL_MEMORY +#if defined(BTRACE_KERNEL_MEMORY) && !defined(__MEMMODEL_FLEXIBLE__) TUint size = zone->iPhysPages << M::PageShift(); BTrace8(BTrace::EKernelMemory, BTrace::EKernelMemoryDrvPhysAlloc, size, zone->iPhysBase); Epoc::DriverAllocdPhysRam += size; diff -r 466a0df5c15a -r ea2434cf3670 kernel/eka/memmodel/epoc/mmubase/mmubase.cpp --- a/kernel/eka/memmodel/epoc/mmubase/mmubase.cpp Tue May 04 16:57:20 2010 +0100 +++ b/kernel/eka/memmodel/epoc/mmubase/mmubase.cpp Tue May 04 18:23:12 2010 +0100 @@ -651,6 +651,17 @@ } +TInt MmuBase::FreeRamZone(TUint aZoneId, TPhysAddr& aZoneBase, TUint& aZoneBytes) + { + TUint zonePages; + TInt r = iRamPageAllocator->GetZoneAddress(aZoneId, aZoneBase, zonePages); + if (r != KErrNone) + return r; + aZoneBytes = zonePages << KPageShift; + return MmuBase::FreePhysicalRam(aZoneBase, aZoneBytes); + } + + TInt MmuBase::ClaimPhysicalRam(TPhysAddr aPhysAddr, TInt aSize) { __KTRACE_OPT(KMMU,Kern::Printf("Mmu::ClaimPhysicalRam(%08x,%x)",aPhysAddr,aSize)); @@ -1263,14 +1274,14 @@ #endif #ifdef BTRACE_RAM_ALLOCATOR - // Must check for -1 as that is the default value of aCategroy for + // Must check for -1 as that is the default value of aCategory for // BTrace::Prime() which is intended to prime all categories that are // currently enabled via a single invocation of BTrace::Prime(). if(aCategory==BTrace::ERamAllocator || (TInt)aCategory == -1) { NKern::ThreadEnterCS(); Mmu::Wait(); - Mmu::Get().iRamPageAllocator->SendInitialBtraceLogs(); + Mmu::Get().iRamPageAllocator->DoBTracePrime(); Mmu::Signal(); NKern::ThreadLeaveCS(); } @@ -2051,6 +2062,45 @@ /** +Free a RAM zone which was previously allocated by one of these methods: +Epoc::AllocPhysicalRam(), Epoc::ZoneAllocPhysicalRam() or +TRamDefragRequest::ClaimRamZone(). + +All of the pages in the RAM zone must be allocated and only via one of the methods +listed above, otherwise a system panic will occur. + +@param aZoneId The ID of the RAM zone to free. +@return KErrNone If the operation was successful. + KErrArgument If a RAM zone with ID aZoneId was not found. + +@pre Calling thread must be in a critical section. +@pre Interrupts must be enabled. +@pre Kernel must be unlocked. +@pre No fast mutex can be held. +@pre Call in a thread context. +@pre Can be used in a device driver. +*/ +EXPORT_C TInt Epoc::FreeRamZone(TUint aZoneId) + { + CHECK_PRECONDITIONS(MASK_THREAD_CRITICAL,"Epoc::FreeRamZone"); + MmuBase& m = *MmuBase::TheMmu; + MmuBase::Wait(); + TPhysAddr zoneBase; + TUint zoneBytes; + TInt r = m.FreeRamZone(aZoneId, zoneBase, zoneBytes); +#ifdef BTRACE_KERNEL_MEMORY + if (r == KErrNone) + { + BTrace8(BTrace::EKernelMemory, BTrace::EKernelMemoryDrvPhysFree, zoneBytes, zoneBase); + Epoc::DriverAllocdPhysRam -= zoneBytes; + } +#endif + MmuBase::Signal(); + return r; + } + + +/** Translate a virtual address to the corresponding physical address. @param aLinAddr The virtual address to be translated. diff -r 466a0df5c15a -r ea2434cf3670 kernel/eka/memmodel/epoc/mmubase/ramalloc.cpp --- a/kernel/eka/memmodel/epoc/mmubase/ramalloc.cpp Tue May 04 16:57:20 2010 +0100 +++ b/kernel/eka/memmodel/epoc/mmubase/ramalloc.cpp Tue May 04 18:23:12 2010 +0100 @@ -2852,7 +2852,7 @@ It outputs the zone configuration and the base addresses of any contiguous block of allocated pages. */ -void DRamAllocator::SendInitialBtraceLogs(void) +void DRamAllocator::DoBTracePrime(void) { M::RamAllocIsLocked(); CHECK_PRECONDITIONS(MASK_THREAD_CRITICAL, "DRamAllocator::SendInitialBtraceLogs"); diff -r 466a0df5c15a -r ea2434cf3670 kernel/eka/release.txt --- a/kernel/eka/release.txt Tue May 04 16:57:20 2010 +0100 +++ b/kernel/eka/release.txt Tue May 04 18:23:12 2010 +0100 @@ -1,3 +1,155 @@ +Version 2.00.3053 +================= +(Made by vfebvre 26/03/2010) + +1. jimmzhou + 1. ou1cimx1#320634 [kernelmcl]Phone Crash when USB MobileTV device CU-14A is connected + +2. kmetherm + 1. REQ 417-57581 RVCT 4 compatible software codebase (SSS) + PackageReleaseID=476546 FeaturePlanID=444184 + + +Version 2.00.3052 +================= +(Made by vfebvre 25/03/2010) + +1. gavguo + 1. REQ:417-57581:RVCT 4 compatible software codebase + PackageReleaseID=462344 FeaturePlanID=444184 + + +Version 2.00.3051 +================= +(Made by vfebvre 25/03/2010) + +1. lanerobe + 1. PDEF145143 KHS Documentation is not contributed to the Symbian Foundation + + +Version 2.00.3050 +================= +(Made by vfebvre 23/03/2010) + +1. josezhou + 1. ou1cimx1#312908 : RUsbHubDriver interface can only be called by FDF, but multiple clients might have conflict requests to the interfaces + +2. lanerobe + 1. DEF145040 E32TEST T_THREAD test failure investigation + + +Version 2.00.3049 +================= +(Made by vfebvre 22/03/2010) + +1. lanerobe + 1. DEF145041 E32TEST T_TIMER test failure investigation + + +Version 2.00.3048 +================= +(Made by vfebvre 22/03/2010) + +1. lanerobe + 1. DEF145039 E32TEST T_SDRIVERS test failure investigation + 2. PDEF144928 Symbian Foundation build error due to missing usb components + + +Version 2.00.3047 +================= +(Made by vfebvre 19/03/2010) + +1. jimmzhou + 1. ou1cimx1#310882: BELS-7YXDRY RDevUsbcClient::ReadUntilShort complete unexpected + +2. lanerobe + 1. DEF144874 Intermittent E32TEST T_MSTIM test failures on the H4 (line 371) + +3. fagortz + 1. DEF144667 WDP: t_medch crashes the system if a page out happens + + +Version 2.00.3046 +================= +(Made by vfebvre 18/03/2010) + +1. lanerobe + 1. DEF145036 T_CONTEXT test failure investigation + +2. ferporta + 1. DEF145026 Remove SCM memory model dependency + 2. DEF144875 E32TEST T_RMDEBUG2_OEM failing on UREL SMP configurations + +3. genwei + 1. ou1cimx1#301181: The device under test exits the high-speed host electrical test mode without operator action + + +Version 2.00.3045 +================= +(Made by vfebvre 17/03/2010) + +1. lanerobe + 1. MINOR_CHANGE Fix copyright notices on power management code + +2. martai + 1. PDEF145027 FMM - BTrace messages EKernelMemory are missing from the flexible memory model + + +Version 2.00.3044 +================= +(Made by vfebvre 15/03/2010) + +1. jimmzhou + 1. CR ou1cimx1#300759: kernel_mcl: A malfunctioning peripheral still cannot be reported to the UI, breaking the "no silent failures" policy of USB OTG + TKEA-836MEU + +2. martai + 1. PDEF144923 FMM - The virtual address space manager allocates incorrect size heap cells + 2. DEF144936 It is not possible to free a RAM zone via its ID + + +Version 2.00.3043 +================= +(Made by vfebvre 12/03/2010) + +1. seolney + 1. DEF144850 E32TEST T_DMASIM fails on x86pc (level 012) + +2. necliffo + 1. PDEF144977 EMOL-83CGYT: SPB 10.1: Device freeze when corrupted memory card is used. + +3. mmaksymi + 1. DEF144804 OST Kernel Code Doesn't Comply with Header Relocation Rules + + +Version 2.00.3042 +================= +(Made by vfebvre 11/03/2010) + +1. jimmzhou + 1. DEF144836: for submission to MCL: TSW defect TSW YXIO-82ZBP + +2. gcochran + 1. PDEF144935 MMEG-83F9A8 - Misleading error message in ExecHandler::ThreadRequestSignal + +3. tommarti + 1. DEF144920 Wrong license in some FMM source files + + +Version 2.00.3041 +================= +(Made by vfebvre 10/03/2010) + +1. gayarama + 1. PDEF144756 t_tbus_datapaging test fails on Vasco/TB9.2 due to fileserver api issue + +2. martai + 1. DEF144781: MMEG-8369AQ RThread::Create documentation doesn't mention the minimum stack size + +3. davegord + 1. DEF144743 Kernel Message Pool corrupted by delayed DeadClientCleanup + + Version 2.00.3040 ================= (Made by vfebvre 09/03/2010) diff -r 466a0df5c15a -r ea2434cf3670 kernelhwsrv_info/doc_pub/base_how_to_64bit_file_server_client_porting_guide.doc Binary file kernelhwsrv_info/doc_pub/base_how_to_64bit_file_server_client_porting_guide.doc has changed diff -r 466a0df5c15a -r ea2434cf3670 kernelhwsrv_info/doc_pub/base_how_to_64bit_file_server_file_system_plugin_porting_guide.doc Binary file kernelhwsrv_info/doc_pub/base_how_to_64bit_file_server_file_system_plugin_porting_guide.doc has changed diff -r 466a0df5c15a -r ea2434cf3670 kernelhwsrv_info/doc_pub/base_how_to_align_partitions_to_media_block_boundaries_for_optimised_performance.doc Binary file kernelhwsrv_info/doc_pub/base_how_to_align_partitions_to_media_block_boundaries_for_optimised_performance.doc has changed diff -r 466a0df5c15a -r ea2434cf3670 kernelhwsrv_info/doc_pub/base_how_to_armv7_cache_and_access_remapping_-_design.doc Binary file kernelhwsrv_info/doc_pub/base_how_to_armv7_cache_and_access_remapping_-_design.doc has changed diff -r 466a0df5c15a -r ea2434cf3670 kernelhwsrv_info/doc_pub/base_how_to_btrace.doc Binary file kernelhwsrv_info/doc_pub/base_how_to_btrace.doc has changed diff -r 466a0df5c15a -r ea2434cf3670 kernelhwsrv_info/doc_pub/base_how_to_configure_platform_security_settings.doc Binary file kernelhwsrv_info/doc_pub/base_how_to_configure_platform_security_settings.doc has changed diff -r 466a0df5c15a -r ea2434cf3670 kernelhwsrv_info/doc_pub/base_how_to_crash_logging.doc Binary file kernelhwsrv_info/doc_pub/base_how_to_crash_logging.doc has changed diff -r 466a0df5c15a -r ea2434cf3670 kernelhwsrv_info/doc_pub/base_how_to_debug_nonxip_problems.doc Binary file kernelhwsrv_info/doc_pub/base_how_to_debug_nonxip_problems.doc has changed diff -r 466a0df5c15a -r ea2434cf3670 kernelhwsrv_info/doc_pub/base_how_to_estart.doc Binary file kernelhwsrv_info/doc_pub/base_how_to_estart.doc has changed diff -r 466a0df5c15a -r ea2434cf3670 kernelhwsrv_info/doc_pub/base_how_to_file_caching.doc Binary file kernelhwsrv_info/doc_pub/base_how_to_file_caching.doc has changed diff -r 466a0df5c15a -r ea2434cf3670 kernelhwsrv_info/doc_pub/base_how_to_handle_sharing.doc Binary file kernelhwsrv_info/doc_pub/base_how_to_handle_sharing.doc has changed diff -r 466a0df5c15a -r ea2434cf3670 kernelhwsrv_info/doc_pub/base_how_to_impacts_of_demand_paging_on_kernel-side_code.doc Binary file kernelhwsrv_info/doc_pub/base_how_to_impacts_of_demand_paging_on_kernel-side_code.doc has changed diff -r 466a0df5c15a -r ea2434cf3670 kernelhwsrv_info/doc_pub/base_how_to_ipc.doc Binary file kernelhwsrv_info/doc_pub/base_how_to_ipc.doc has changed diff -r 466a0df5c15a -r ea2434cf3670 kernelhwsrv_info/doc_pub/base_how_to_message_queues.doc Binary file kernelhwsrv_info/doc_pub/base_how_to_message_queues.doc has changed diff -r 466a0df5c15a -r ea2434cf3670 kernelhwsrv_info/doc_pub/base_how_to_migrate_device_drivers_to_paging_environment.doc Binary file kernelhwsrv_info/doc_pub/base_how_to_migrate_device_drivers_to_paging_environment.doc has changed diff -r 466a0df5c15a -r ea2434cf3670 kernelhwsrv_info/doc_pub/base_how_to_migrate_media_drivers_to_support_demand_paging.doc Binary file kernelhwsrv_info/doc_pub/base_how_to_migrate_media_drivers_to_support_demand_paging.doc has changed diff -r 466a0df5c15a -r ea2434cf3670 kernelhwsrv_info/doc_pub/base_how_to_migrate_to_client-server_v2_apis.doc Binary file kernelhwsrv_info/doc_pub/base_how_to_migrate_to_client-server_v2_apis.doc has changed diff -r 466a0df5c15a -r ea2434cf3670 kernelhwsrv_info/doc_pub/base_how_to_mmc_direct_physical_addressing.doc Binary file kernelhwsrv_info/doc_pub/base_how_to_mmc_direct_physical_addressing.doc has changed diff -r 466a0df5c15a -r ea2434cf3670 kernelhwsrv_info/doc_pub/base_how_to_mmc_double_buffering.doc Binary file kernelhwsrv_info/doc_pub/base_how_to_mmc_double_buffering.doc has changed diff -r 466a0df5c15a -r ea2434cf3670 kernelhwsrv_info/doc_pub/base_how_to_persisting_a_custom_restart_reason.doc Binary file kernelhwsrv_info/doc_pub/base_how_to_persisting_a_custom_restart_reason.doc has changed diff -r 466a0df5c15a -r ea2434cf3670 kernelhwsrv_info/doc_pub/base_how_to_port_emmc_controller.doc Binary file kernelhwsrv_info/doc_pub/base_how_to_port_emmc_controller.doc has changed diff -r 466a0df5c15a -r ea2434cf3670 kernelhwsrv_info/doc_pub/base_how_to_port_sdio_controller_supplement.doc Binary file kernelhwsrv_info/doc_pub/base_how_to_port_sdio_controller_supplement.doc has changed diff -r 466a0df5c15a -r ea2434cf3670 kernelhwsrv_info/doc_pub/base_how_to_publish_and_subscribe.doc Binary file kernelhwsrv_info/doc_pub/base_how_to_publish_and_subscribe.doc has changed diff -r 466a0df5c15a -r ea2434cf3670 kernelhwsrv_info/doc_pub/base_how_to_share_file_handles.doc Binary file kernelhwsrv_info/doc_pub/base_how_to_share_file_handles.doc has changed diff -r 466a0df5c15a -r ea2434cf3670 kernelhwsrv_info/doc_pub/base_how_to_usb_client_porting_and_test.doc Binary file kernelhwsrv_info/doc_pub/base_how_to_usb_client_porting_and_test.doc has changed diff -r 466a0df5c15a -r ea2434cf3670 kernelhwsrv_info/doc_pub/base_how_to_usb_mass_storage_app.doc Binary file kernelhwsrv_info/doc_pub/base_how_to_usb_mass_storage_app.doc has changed diff -r 466a0df5c15a -r ea2434cf3670 kernelhwsrv_info/doc_pub/base_how_to_usb_mass_storage_double_buffering.doc Binary file kernelhwsrv_info/doc_pub/base_how_to_usb_mass_storage_double_buffering.doc has changed diff -r 466a0df5c15a -r ea2434cf3670 kernelhwsrv_info/doc_pub/base_how_to_use_cfileman_test_framework.doc Binary file kernelhwsrv_info/doc_pub/base_how_to_use_cfileman_test_framework.doc has changed diff -r 466a0df5c15a -r ea2434cf3670 kernelhwsrv_info/doc_pub/base_how_to_use_dma_for_sdio_data_transfers.doc Binary file kernelhwsrv_info/doc_pub/base_how_to_use_dma_for_sdio_data_transfers.doc has changed diff -r 466a0df5c15a -r ea2434cf3670 kernelhwsrv_info/doc_pub/base_how_to_use_t_fatcharsetconv_framework.doc Binary file kernelhwsrv_info/doc_pub/base_how_to_use_t_fatcharsetconv_framework.doc has changed diff -r 466a0df5c15a -r ea2434cf3670 kernelhwsrv_info/doc_pub/base_how_to_vfp_support.doc Binary file kernelhwsrv_info/doc_pub/base_how_to_vfp_support.doc has changed diff -r 466a0df5c15a -r ea2434cf3670 kernelhwsrv_info/doc_pub/base_migrating_device_drivers_dfc_q.doc Binary file kernelhwsrv_info/doc_pub/base_migrating_device_drivers_dfc_q.doc has changed diff -r 466a0df5c15a -r ea2434cf3670 kernelhwsrv_info/doc_pub/base_migrating_media_drivers_dma.doc Binary file kernelhwsrv_info/doc_pub/base_migrating_media_drivers_dma.doc has changed diff -r 466a0df5c15a -r ea2434cf3670 kernelhwsrv_info/doc_pub/base_smp_driver_migration_guide.doc Binary file kernelhwsrv_info/doc_pub/base_smp_driver_migration_guide.doc has changed diff -r 466a0df5c15a -r ea2434cf3670 kernelhwsrv_info/doc_pub/base_smp_user_side_migration_guide.doc Binary file kernelhwsrv_info/doc_pub/base_smp_user_side_migration_guide.doc has changed diff -r 466a0df5c15a -r ea2434cf3670 kernelhwsrv_info/doc_pub/kernelhwsrv_doc_pub.mrp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kernelhwsrv_info/doc_pub/kernelhwsrv_doc_pub.mrp Tue May 04 18:23:12 2010 +0100 @@ -0,0 +1,26 @@ +# +# Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +# All rights reserved. +# This component and the accompanying materials are made available +# under the terms of "Eclipse Public License v1.0" +# which accompanies this distribution, and is available +# at the URL "http://www.eclipse.org/legal/epl-v10.html". +# +# Initial Contributors: +# Nokia Corporation - initial contribution. +# +# Contributors: +# +# Description: +# +# component name "Kernel and Hardware Services Documentation" + +component kernelhwsrv_doc_pub + +source \sf\os\kernelhwsrv\kernelhwsrv_info\doc_pub\ + +notes_source \component_defs\release.src + + +ipr E + diff -r 466a0df5c15a -r ea2434cf3670 kerneltest/e32test/debug/t_context.cpp --- a/kerneltest/e32test/debug/t_context.cpp Tue May 04 16:57:20 2010 +0100 +++ b/kerneltest/e32test/debug/t_context.cpp Tue May 04 18:23:12 2010 +0100 @@ -408,6 +408,7 @@ // run again only after it is blocked on its request semaphore. t.SetPriority(EPriorityMore); t.Resume(); + User::After(500000); if (aCallback != ENoCallback) { diff -r 466a0df5c15a -r ea2434cf3670 kerneltest/e32test/defrag/d_ramdefrag.cpp --- a/kerneltest/e32test/defrag/d_ramdefrag.cpp Tue May 04 16:57:20 2010 +0100 +++ b/kerneltest/e32test/defrag/d_ramdefrag.cpp Tue May 04 18:23:12 2010 +0100 @@ -72,6 +72,7 @@ TInt ZoneAllocToMany2(TInt aZoneIndex, TInt aNumPages); TInt AllocContiguous(TUint aNumBytes); TInt FreeZone(TInt aNumPages); + TInt FreeZoneId(TUint aZoneId); TInt FreeFromAllZones(); TInt FreeFromAddr(TInt aNumPages, TUint32 aAddr); TInt PageCount(TUint aId, STestUserSidePageCount* aPageData); @@ -389,6 +390,10 @@ retVal = DRamDefragFuncTestChannel::FreeZone((TInt)a1); break; + case RRamDefragFuncTestLdd::EFreeZoneId: + retVal = DRamDefragFuncTestChannel::FreeZoneId((TUint)a1); + break; + case RRamDefragFuncTestLdd::EFreeFromAllZones: retVal = DRamDefragFuncTestChannel::FreeFromAllZones(); break; @@ -1512,6 +1517,30 @@ } // +// FreeZoneId +// +// Call Epoc::FreeRamZone() +// +TInt DRamDefragFuncTestChannel::FreeZoneId(TUint aZoneId) + { + NKern::ThreadEnterCS(); + + TInt r = Epoc::FreeRamZone(aZoneId); + if (r == KErrNone) + { + if (iContigAddr == KPhysAddrInvalid) + { + Kern::Printf("Error some how freed a RAM zone that wasn't previously claimed"); + NKern::ThreadLeaveCS(); + return KErrGeneral; + } + iContigAddr = KPhysAddrInvalid; + } + NKern::ThreadLeaveCS(); + return r; + } + +// // FreeFromAllZones // // Call the overloaded Epoc::FreePhysicalRam function diff -r 466a0df5c15a -r ea2434cf3670 kerneltest/e32test/defrag/t_ramdefrag.cpp --- a/kerneltest/e32test/defrag/t_ramdefrag.cpp Tue May 04 16:57:20 2010 +0100 +++ b/kerneltest/e32test/defrag/t_ramdefrag.cpp Tue May 04 18:23:12 2010 +0100 @@ -7073,16 +7073,20 @@ //! @SYMPREQ PREQ308 //! @SYMTestPriority High //! @SYMTestActions -//! 1. Allocate fixed pages and call function to free all fixed pages allocated. +//! 1. Allocate fixed pages and call function to free all fixed pages allocated. +//! 2. Claim a RAM zone and then free it via Epoc::FreeRamZone(). +//! 3. Invoke Epoc::FreeRamZone() with an invalid RAM zone ID. //! //! @SYMTestExpectedResults //! 1. KErrNone +//! 2. KErrNone +//! 3. KErrArgument //--------------------------------------------------------------------------------------------------------------------- TInt TestFreeZone() { TInt r = 0; TUint zoneID = 0; - test.Start(_L("Test1: Free allocated pages")); + test.Start(_L("Test1: Freeing allocated pages")); TestStart(); TInt pages = 50; @@ -7128,7 +7132,58 @@ } } TestEnd(); - + test.End(); + + test.Start(_L("Test2: Epoc::FreeRamZone() on a claimed RAM zone")); + TestStart(); + GetAllPageInfo(); + TUint zoneIndex = 0; + while (zoneIndex < gZoneCount) + { + if (gZoneUtilArray[zoneIndex].iFreePages == gZoneUtilArray[zoneIndex].iPhysPages) + break; + zoneIndex++; + } + if (zoneIndex >= gZoneCount) + { + test.Printf(_L("Cannot find zone to perform test, Skipping test step...\n")); + goto Test2End; + } + zoneID = gZoneConfigArray[zoneIndex].iZoneId; + r = Ldd.CallDefrag(DEFRAG_TYPE_CLAIM, DEFRAG_VER_SYNC, zoneID); + if (r != KErrNone) + { + test.Printf(_L("Fail: r = %d, expected = %d\n"), r, KErrNone); + TEST_FAIL; + } + GetAllPageInfo(); + if (gZoneUtilArray[zoneIndex].iPhysPages != gZoneUtilArray[zoneIndex].iAllocFixed) + { + test.Printf(_L("Fail: RAM zone ID %d not claimed successfully"), zoneID); + TEST_FAIL; + } + r = Ldd.FreeZoneId(zoneID); + GetAllPageInfo(); + if (r != KErrNone || + gZoneUtilArray[zoneIndex].iPhysPages != gZoneUtilArray[zoneIndex].iFreePages) + { + test.Printf(_L("Fail: RAM zone ID %d not freed successfully r=%d"), zoneID, r); + TEST_FAIL; + } +Test2End: + TestEnd(); + test.End(); + + test.Start(_L("Test2: Epoc::FreeRamZone() on an invalid RAM zone")); + TestStart(); + r = Ldd.FreeZoneId(KInvalidZoneID); + if (r != KErrArgument) + { + test.Printf(_L("Fail: Error RAM zone ID %d r=%d"), KInvalidZoneID, r); + TEST_FAIL; + } + + TestEnd(); test.End(); return KErrNone; } diff -r 466a0df5c15a -r ea2434cf3670 kerneltest/e32test/defrag/t_ramdefrag.h --- a/kerneltest/e32test/defrag/t_ramdefrag.h Tue May 04 16:57:20 2010 +0100 +++ b/kerneltest/e32test/defrag/t_ramdefrag.h Tue May 04 18:23:12 2010 +0100 @@ -139,6 +139,7 @@ EZoneAllocToMany2, EAllocContiguous, EFreeZone, + EFreeZoneId, EFreeFromAllZones, EFreeFromAddr, ECheckCancel, @@ -224,6 +225,8 @@ inline TInt FreeFromAllZones() { return DoControl(EFreeFromAllZones,(TAny*)NULL, (TAny*)NULL); } + inline TInt FreeZoneId(TUint aZoneId) + { return DoControl(EFreeZoneId, (TAny*)aZoneId); } inline TInt CheckCancel(TInt aDefragType, TUint aID = 0) { diff -r 466a0df5c15a -r ea2434cf3670 kerneltest/e32test/demandpaging/t_tbus_datapaging.cpp --- a/kerneltest/e32test/demandpaging/t_tbus_datapaging.cpp Tue May 04 16:57:20 2010 +0100 +++ b/kerneltest/e32test/demandpaging/t_tbus_datapaging.cpp Tue May 04 18:23:12 2010 +0100 @@ -79,6 +79,7 @@ LOCAL_D RFs TheFs; TInt gFsDriveNumber = -1; +TBool gMediaIsRam = EFalse; RTest test(_L("T_TBUS_DATAPAGING")); _LIT(KChunkName, "t_datapaging chunk"); @@ -698,6 +699,9 @@ continue; TPtrC mediaType = GetMediaType(di.iType); + if (di.iType == EMediaRam) + gMediaIsRam = ETrue; + test.Printf(_L("Drive %C Type %S DriveAtt 0x%x MediaAtt 0x%x FileSysId %S SerialNum %S\n"), 'A' + n, &mediaType, di.iDriveAtt, di.iMediaAtt, &fsName, &GetSerialNumber(serialNum)); @@ -794,11 +798,13 @@ __DECLARE_VAR_IN_CHUNK(TBusLocalDrive, &drive) TInt driveSize = TestDriveConnectAndCaps(drive, fatDriveNumber); - TestDriveSizeRelatedMethods(drive, 0x00001000, driveSize); + if (!gMediaIsRam) // If media is RAM then the tests are invalid + TestDriveSizeRelatedMethods(drive, 0x00001000, driveSize); TestWriteReadRelatedMethods(drive); - TestFormatRelatedMethods(drive, driveSize); + if (!gMediaIsRam) + TestFormatRelatedMethods(drive, driveSize); if(callPasswordRelated) { diff -r 466a0df5c15a -r ea2434cf3670 kerneltest/e32test/dma/t_dma.cpp --- a/kerneltest/e32test/dma/t_dma.cpp Tue May 04 16:57:20 2010 +0100 +++ b/kerneltest/e32test/dma/t_dma.cpp Tue May 04 18:23:12 2010 +0100 @@ -348,7 +348,7 @@ TBuf<16> name; name = _L("TESTER-"); name.AppendNum(aIdx); - test(iThread.Create(name, ThreadFunction, 0x1000, NULL, this) == KErrNone); + test(iThread.Create(name, ThreadFunction, 0x2000, NULL, this) == KErrNone); iThread.SetPriority(EPriorityLess); iThread.Logon(iStatus); SetActive(); diff -r 466a0df5c15a -r ea2434cf3670 kerneltest/e32test/group/d_kerncorestats.mmp --- a/kerneltest/e32test/group/d_kerncorestats.mmp Tue May 04 16:57:20 2010 +0100 +++ b/kerneltest/e32test/group/d_kerncorestats.mmp Tue May 04 18:23:12 2010 +0100 @@ -1,7 +1,7 @@ -// Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies). +// Copyright (c) 2008-2010 Nokia Corporation and/or its subsidiary(-ies). // All rights reserved. // This component and the accompanying materials are made available -// under the terms of "Eclipse Public License v1.0" +// under the terms of the License "Eclipse Public License v1.0" // which accompanies this distribution, and is available // at the URL "http://www.eclipse.org/legal/epl-v10.html". // diff -r 466a0df5c15a -r ea2434cf3670 kerneltest/e32test/group/t_kerncorestats.mmp --- a/kerneltest/e32test/group/t_kerncorestats.mmp Tue May 04 16:57:20 2010 +0100 +++ b/kerneltest/e32test/group/t_kerncorestats.mmp Tue May 04 18:23:12 2010 +0100 @@ -1,7 +1,7 @@ -// Copyright (c) 2005-2009 Nokia Corporation and/or its subsidiary(-ies). +// Copyright (c) 2008-2010 Nokia Corporation and/or its subsidiary(-ies). // All rights reserved. // This component and the accompanying materials are made available -// under the terms of "Eclipse Public License v1.0" +// under the terms of the License "Eclipse Public License v1.0" // which accompanies this distribution, and is available // at the URL "http://www.eclipse.org/legal/epl-v10.html". // diff -r 466a0df5c15a -r ea2434cf3670 kerneltest/e32test/misc/d_testkerncorestats.cpp --- a/kerneltest/e32test/misc/d_testkerncorestats.cpp Tue May 04 16:57:20 2010 +0100 +++ b/kerneltest/e32test/misc/d_testkerncorestats.cpp Tue May 04 18:23:12 2010 +0100 @@ -1,7 +1,7 @@ -// Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies). +// Copyright (c) 2008-2010 Nokia Corporation and/or its subsidiary(-ies). // All rights reserved. // This component and the accompanying materials are made available -// under the terms of "Eclipse Public License v1.0" +// under the terms of the License "Eclipse Public License v1.0" // which accompanies this distribution, and is available // at the URL "http://www.eclipse.org/legal/epl-v10.html". // diff -r 466a0df5c15a -r ea2434cf3670 kerneltest/e32test/misc/d_testkerncorestats.h --- a/kerneltest/e32test/misc/d_testkerncorestats.h Tue May 04 16:57:20 2010 +0100 +++ b/kerneltest/e32test/misc/d_testkerncorestats.h Tue May 04 18:23:12 2010 +0100 @@ -1,7 +1,7 @@ -// Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies). +// Copyright (c) 2008-2010 Nokia Corporation and/or its subsidiary(-ies). // All rights reserved. // This component and the accompanying materials are made available -// under the terms of "Eclipse Public License v1.0" +// under the terms of the License "Eclipse Public License v1.0" // which accompanies this distribution, and is available // at the URL "http://www.eclipse.org/legal/epl-v10.html". // diff -r 466a0df5c15a -r ea2434cf3670 kerneltest/e32test/misc/t_kerncorestats.cpp --- a/kerneltest/e32test/misc/t_kerncorestats.cpp Tue May 04 16:57:20 2010 +0100 +++ b/kerneltest/e32test/misc/t_kerncorestats.cpp Tue May 04 18:23:12 2010 +0100 @@ -1,7 +1,7 @@ -// Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies). +// Copyright (c) 2008-2010 Nokia Corporation and/or its subsidiary(-ies). // All rights reserved. // This component and the accompanying materials are made available -// under the terms of "Eclipse Public License v1.0" +// under the terms of the License "Eclipse Public License v1.0" // which accompanies this distribution, and is available // at the URL "http://www.eclipse.org/legal/epl-v10.html". // diff -r 466a0df5c15a -r ea2434cf3670 kerneltest/e32test/pccd/t_medch.cpp --- a/kerneltest/e32test/pccd/t_medch.cpp Tue May 04 16:57:20 2010 +0100 +++ b/kerneltest/e32test/pccd/t_medch.cpp Tue May 04 18:23:12 2010 +0100 @@ -50,6 +50,9 @@ const TInt KPowerUpTimeOut = 5000000; // Give the card 5 seconds to power up +const TUint KDriveAttMask = KDriveAttLocal | KDriveAttRom | KDriveAttRemote; +const TUint KMediaAttMask = KMediaAttVariableSize | KMediaAttDualDensity | KMediaAttLockable | KMediaAttLocked | KMediaAttHasPassword | KMediaAttReadWhileWrite; + LOCAL_D RTest test(_L("Media change test")); LOCAL_D TBusLocalDrive TheDrive; @@ -57,6 +60,129 @@ LOCAL_D TRequestStatus TheMediaStatus; LOCAL_D TBool TheChangedFlag; +LOCAL_C TInt FindDataPagingDrive() +/** +Find the drive containing the swap partition. + +@return Local drive identifier or KErrNotFound if not found +*/ + { + TInt drive = KErrNotFound; + + RLocalDrive d; + TBool change = EFalse; + TLocalDriveCapsV5 driveCaps; + TPckg capsPack(driveCaps); + + for(TInt i = 0; i < KMaxLocalDrives && drive < 0; ++i) + { + if(d.Connect(i, change) == KErrNone) + { + if(d.Caps(capsPack) == KErrNone) + { + if ((driveCaps.iMediaAtt & KMediaAttPageable) && + (driveCaps.iPartitionType == KPartitionTypePagedData)) + { + drive = i; + } + } + d.Close(); + } + } + + if(drive == KErrNotFound) + { + test.Printf(_L("No data paging drive found\n")); + } + + return drive; + } + +LOCAL_C TInt DataPagingMediaCaps(TLocalDriveCapsV5 &aCaps) +/** +Return the caps of the media containing a swap partition. + +@return Error code, on success aCaps contains the capabilities of the paging drive +*/ + { + TInt dataPagingDrive = FindDataPagingDrive(); + + if (dataPagingDrive == KErrNotFound) + { + return KErrNotFound; + } + + RLocalDrive dpDrive; + TBool change = EFalse; + + TInt r = dpDrive.Connect(dataPagingDrive, change); + test(r == KErrNone); + + TLocalDriveCapsV5 dpDriveCaps; + TPckg capsPack(dpDriveCaps); + r = dpDrive.Caps(capsPack); + test(r == KErrNone); + + if((dpDriveCaps.iDriveAtt & KDriveAttHidden) == 0) + { + test.Printf(_L("Paging partition is not hidden! Assuming it is correct anyway!\n")); + } + + aCaps = dpDriveCaps; + + return KErrNone; + } + +LOCAL_C TBool IsDriveOnPagingMedia(TInt aDrive, TLocalDriveCapsV5 &aPagingMediaCaps) +/** +Determines whether a drive is on the same media as the paging media by comparing +media characteristics + +@return ETrue if (likely) to be on the same media, EFalse if not. +*/ { + RLocalDrive drive; + TBool change = EFalse; + + TInt r = drive.Connect(aDrive, change); + test(r == KErrNone); + + TLocalDriveCapsV5 driveCaps; + TPckg capsPack(driveCaps); + r = drive.Caps(capsPack); + test(r == KErrNone); + + // Check media serial number + if(aPagingMediaCaps.iSerialNumLength > 0) + { + if((driveCaps.iSerialNumLength > 0) && + ((memcompare(driveCaps.iSerialNum, driveCaps.iSerialNumLength, + aPagingMediaCaps.iSerialNum, aPagingMediaCaps.iSerialNumLength)) == 0)) + { + // serial numbers equal, so drive in question is on same media as paging drive + test.Printf(_L("Based on serial number match, drive %d shares the same media as paging drive\n"), aDrive); + return ETrue; + } + } + else + { + // Turn off bits which may be different + aPagingMediaCaps.iDriveAtt &= KDriveAttMask; + aPagingMediaCaps.iMediaAtt &= KMediaAttMask; + driveCaps.iDriveAtt &= KDriveAttMask; + driveCaps.iMediaAtt &= KMediaAttMask; + + if ((driveCaps.iType == aPagingMediaCaps.iType) && + (driveCaps.iDriveAtt == aPagingMediaCaps.iDriveAtt) && + (driveCaps.iMediaAtt == aPagingMediaCaps.iMediaAtt)) + { + test.Printf(_L("Based on media characteristics match, drive %d shares the same media as paging drive\n"), aDrive); + return ETrue; + } + } + + return EFalse; + } + LOCAL_C TBool SetupDrivesForPlatform(TInt& aDrive, TInt& aSocket) /** @@ -75,11 +201,26 @@ aDrive = -1; aSocket = -1; + TLocalDriveCapsV5 pagingMediaCaps; + TBool pagingMediaCheck = EFalse; + if(DataPagingMediaCaps(pagingMediaCaps) == KErrNone) + { + pagingMediaCheck = ETrue; + } + for(aDrive=0; aDrive < di.iTotalSupportedDrives; aDrive++) { test.Printf(_L(" Drive %d - %S\r\n"), aDrive, &di.iDriveName[aDrive]); if(di.iDriveName[aDrive].MatchF(_L("MultiMediaCard0")) == KErrNone) - break; + { + if(pagingMediaCheck) + { + if( ! IsDriveOnPagingMedia(aDrive, pagingMediaCaps)) + { + break; + } + } + } } if(aDrive == di.iTotalSupportedDrives) @@ -172,14 +313,14 @@ */ { test.Console()->SetPos(20, 25); - test.Printf(_L("%S [%d cycles]"), &aTitle, aCycles); + test.Printf(_L("%S [%d cycles]\n"), &aTitle, aCycles); #ifdef __MANUAL_TEST__ test.Console()->SetPos(20, 27); - test.Printf(_L("")); + test.Printf(_L("\n")); test.Getch(); #endif } - + GLDEF_C TInt E32Main() /** * Test Entry Point for T_MEDCH. @@ -213,6 +354,7 @@ */ TInt drive; TInt socket; + if(SetupDrivesForPlatform(drive, socket)) { b.Format(_L("Connect to local drive %d"), drive); diff -r 466a0df5c15a -r ea2434cf3670 kerneltest/e32test/prime/t_timer.cpp --- a/kerneltest/e32test/prime/t_timer.cpp Tue May 04 16:57:20 2010 +0100 +++ b/kerneltest/e32test/prime/t_timer.cpp Tue May 04 18:23:12 2010 +0100 @@ -290,16 +290,17 @@ t2.HomeTime(); } while (t2==t1); -#if defined(_DEBUG) - TDateTime dt=t2.DateTime(); - test.Printf(_L("%d:%d\r\n"),dt.Second(),dt.MicroSecond()); -#endif - test(t2>t1); + + if (t2 <= t1) + { + test.Printf(_L("Time comparison failed\r\n")); + test.Printf(_L("Before: 0x%lx\r\n"), t1.Int64()); + test.Printf(_L("After: 0x%lx\r\n"), t2.Int64()); + test(t2>t1); + } + t1=t2; } -#if defined(_DEBUG) - test.Printf(_L("\r\n")); -#endif } TInt AtTwice(TAny*) diff -r 466a0df5c15a -r ea2434cf3670 kerneltest/e32test/rm_debug/basic_tests/t_rmdebug2.cpp --- a/kerneltest/e32test/rm_debug/basic_tests/t_rmdebug2.cpp Tue May 04 16:57:20 2010 +0100 +++ b/kerneltest/e32test/rm_debug/basic_tests/t_rmdebug2.cpp Tue May 04 18:23:12 2010 +0100 @@ -400,28 +400,49 @@ test(KErrNone == iServSession.AttachExecutable(iFileName, EFalse)); test(KErrNone == iServSession.SuspendThread(iThreadID)); - //test getting the global list, ETrue as should find the target debug thread - DoTestGetThreadList(ETrue, EScopeGlobal); - - //test getting this thread's thread list, ETrue as should find the target debug thread - DoTestGetThreadList(ETrue, EScopeThreadSpecific, RThread().Id().Id()); - - //test getting this process's thread list, ETrue as should find the target debug thread - DoTestGetThreadList(ETrue, EScopeProcessSpecific, RProcess().Id().Id()); + TBool found = EFalse; + + /* We need these loops because on some system the kernel run mode debugger does not + immediately present the thread in the thread list. + */ + + for(TInt retryCount = 0; retryCount < 10 && !found; retryCount++ ) + { + //test getting this process's thread list, ETrue as should find the target debug thread + User::After(50000); + found = DoTestGetThreadList(ETrue, EScopeProcessSpecific, RProcess().Id().Id()); + } + test( found ); + found = EFalse; + + for(TInt retryCount = 0; retryCount < 10 && !found; retryCount++ ) + { + //test getting the global list, ETrue as should find the target debug thread + User::After(50000); + found = DoTestGetThreadList(ETrue, EScopeGlobal); + } + test( found ); + + found = EFalse; + for(TInt retryCount = 0; retryCount < 10 && !found; retryCount++ ) + { + //test getting this thread's thread list, ETrue as should find the target debug thread + User::After(50000); + found = DoTestGetThreadList(ETrue, EScopeThreadSpecific, RThread().Id().Id()); + } + test( found ); test(KErrNone == iServSession.ResumeThread(iThreadID)); test(KErrNone == iServSession.DetachExecutable(iFileName)); } - -void CRunModeAgent::DoTestGetThreadList(const TBool aShouldPass, const TListScope aListScope, const TUint64 aTargetId) + +TBool CRunModeAgent::DoTestGetThreadList(const TBool aShouldPass, const TListScope aListScope, const TUint64 aTargetId) { - test.Next(_L("DoTestGetThreadList\n")); - //create data to pass RBuf8 buffer; TUint32 size = 0; - //perform the call to get the Code segs + //perform the call to get the thread list DoGetList(EThreads, aListScope, buffer, size, aTargetId); //initialise data about the target debug thread to compare the kernel's data against @@ -438,22 +459,22 @@ { TThreadListEntry* entry = (TThreadListEntry*)ptr; TPtr entryName(&(entry->iName[0]), entry->iNameLength, entry->iNameLength); + if( (threadId == entry->iThreadId) && (processId == entry->iProcessId) && (0 == name.CompareF(entryName)) ) { test(entry->iSupervisorStackBaseValid); test(entry->iSupervisorStackSizeValid); //if all match then we've found it found = ETrue; + break; } ptr += Align4(entry->GetSize()); } - //check whether the expected result happened - test(found == aShouldPass); - //clean up buffer.Close(); + return found; } @@ -582,6 +603,12 @@ } + +/** + * Get a list from the run mode debug system. Most list calls will initially return KErrTooBig, + * since the initial size of the buffer is 0. However it is sometimes valid for a list to be empty + * given its filtering and scope. These calls should return KErrNone. + */ void CRunModeAgent::DoGetList(const TListId aListId, const TListScope aListScope, RBuf8& aBuffer, TUint32& aSize, const TUint64 aTargetId) { //close the buffer in case there's stuff allocated in it @@ -589,19 +616,20 @@ //initialise it to be one byte big, which will guarantee data won't fit in it test(KErrNone == aBuffer.Create(1)); aSize = 0; - + + TInt ret = KErrNone; //should pass this test (assuming we've passed in sensible arguments above...) if(EScopeGlobal == aListScope) { - test(KErrTooBig == iServSession.GetList(aListId, aBuffer, aSize)); + ret = iServSession.GetList(aListId, aBuffer, aSize); } else if(EScopeThreadSpecific == aListScope) { - test(KErrTooBig == iServSession.GetList((TThreadId)aTargetId, aListId, aBuffer, aSize)); + ret = iServSession.GetList((TThreadId)aTargetId, aListId, aBuffer, aSize); } else if(EScopeProcessSpecific == aListScope) { - test(KErrTooBig == iServSession.GetList((TProcessId)aTargetId, aListId, aBuffer, aSize)); + ret = iServSession.GetList((TProcessId)aTargetId, aListId, aBuffer, aSize); } else { @@ -609,6 +637,17 @@ test(0); } + if( KErrNone == ret ) + { + /* In the case that there is no data, just return and let the caller check + the buffer. It is valid for a caller to not expect any data to be returned. + */ + return; + } + + // The only other allowed return is KErrTooBig + test( ret == KErrTooBig ); + //keep allocating larger buffers, beginning with the aSize returned by the above call, //and hopefully we'll eventually make a large enough one test(KErrNone == aBuffer.ReAlloc(aSize)); @@ -2727,9 +2766,9 @@ /* Wait a little while and try again, just in case the process is still being removed. This can happen on a very busy system or when a popup for the events is still active */ - RDebug::Printf("CRunModeAgent::TestEventsWithExtraThreads. ProcessExists(id=%d), waiting for it to exit %d", + RDebug::Printf("CRunModeAgent::TestEventsWithExtraThreads. ProcessExists(id=%d), waiting count exit=%d", I64LOW(processId), waitCount); - User::After(500); + User::After(50000); } test(!ProcessExists(processId)); } @@ -2738,34 +2777,37 @@ // helper function to check whether a thread with id aThreadId exists in the process with id aProcessId TBool CRunModeAgent::ThreadExistsForProcess(const TThreadId aThreadId, const TProcessId aProcessId) { - TUint32 size; - RBuf8 buffer; - test(KErrNone == buffer.Create(1024)); - TInt err = iServSession.GetList(aProcessId, EThreads, buffer, size); - while(KErrTooBig == err) + RThread lThread; + TInt ret = lThread.Open( aThreadId.Id() ); + + if( ret != KErrNone ) { - size*=2; - test(size<=16*1024); - test(KErrNone == buffer.ReAlloc(size)); - err = iServSession.GetList(aProcessId, EThreads, buffer, size); + RDebug::Printf("ThreadExistsForProcess: thread id=%d opening returned %d", + I64LOW( aThreadId.Id() ), ret ); + lThread.Close(); + return EFalse; } - test(KErrNone == err); - - //look through the buffer and check if the target debug thread is there - TUint8* ptr = (TUint8*)buffer.Ptr(); - const TUint8* ptrEnd = ptr + size; - while(ptr < ptrEnd) + + RProcess lProcess; + ret = lThread.Process( lProcess ); + + lThread.Close(); + + if( ret != KErrNone ) { - TThreadListEntry& entry = *(TThreadListEntry*)ptr; - if(aThreadId.Id() == entry.iThreadId) - { - buffer.Close(); - return ETrue; - } - ptr += Align4(entry.GetSize()); + RDebug::Printf("ThreadExistsForProcess: proc opening returned %d", ret ); + ret = KErrNotFound; } - buffer.Close(); - return EFalse; + else if( lProcess.Id() != aProcessId ) + { + RDebug::Printf("ThreadExistsForProcess: lProcess.Id()(%d)!= aProcessId(%d)", + I64LOW(lProcess.Id().Id()), I64LOW(aProcessId.Id())); + ret = KErrNotFound; + } + + lProcess.Close(); + + return ( ret == KErrNone ); } // helper function to check whether a process with id aProcessId exists diff -r 466a0df5c15a -r ea2434cf3670 kerneltest/e32test/rm_debug/basic_tests/t_rmdebug2.h --- a/kerneltest/e32test/rm_debug/basic_tests/t_rmdebug2.h Tue May 04 16:57:20 2010 +0100 +++ b/kerneltest/e32test/rm_debug/basic_tests/t_rmdebug2.h Tue May 04 18:23:12 2010 +0100 @@ -71,7 +71,7 @@ void TestGetXipLibrariesList(); void TestGetListInvalidData(); - void DoTestGetThreadList(const TBool aShouldPass, const Debug::TListScope aListScope, const TUint64 aTargetId=0); + TBool DoTestGetThreadList(const TBool aShouldPass, const Debug::TListScope aListScope, const TUint64 aTargetId=0); void DoTestGetCodeSegsList(const TBool aShouldPass, const Debug::TListScope aListScope, const TUint64 aTargetId=0); void DoGetList(const Debug::TListId aListId, const Debug::TListScope aListScope, RBuf8& aBuffer, TUint32& aSize, const TUint64 aTargetId=0); diff -r 466a0df5c15a -r ea2434cf3670 kerneltest/e32test/rm_debug/common/t_target_launcher.cpp --- a/kerneltest/e32test/rm_debug/common/t_target_launcher.cpp Tue May 04 16:57:20 2010 +0100 +++ b/kerneltest/e32test/rm_debug/common/t_target_launcher.cpp Tue May 04 18:23:12 2010 +0100 @@ -192,6 +192,8 @@ } } + launchMutex.Wait( 500000 ); + CleanupStack::PopAndDestroy( &launchMutex ); if( commandLine ) @@ -202,6 +204,8 @@ GLDEF_C TInt E32Main() { + RProcess thisProcess; + thisProcess.Rendezvous(KErrNone); RDebug::Printf( ">Launcher Process()" ); CTrapCleanup* trap = CTrapCleanup::New(); diff -r 466a0df5c15a -r ea2434cf3670 kerneltest/e32test/rm_debug/debug_targets/t_rmdebug_app.cpp --- a/kerneltest/e32test/rm_debug/debug_targets/t_rmdebug_app.cpp Tue May 04 16:57:20 2010 +0100 +++ b/kerneltest/e32test/rm_debug/debug_targets/t_rmdebug_app.cpp Tue May 04 18:23:12 2010 +0100 @@ -352,6 +352,8 @@ TInt E32Main() { + + RDebug::Printf("t_rmdebug_app tid=%d,pid=%d", I64LOW(RThread().Id().Id()), I64LOW(RProcess().Id().Id()) ) ; // setup heap checking and clean up trap __UHEAP_MARK; CTrapCleanup* cleanup=CTrapCleanup::New(); diff -r 466a0df5c15a -r ea2434cf3670 kerneltest/e32test/rm_debug/multi_target_tests/t_multi_target.cpp --- a/kerneltest/e32test/rm_debug/multi_target_tests/t_multi_target.cpp Tue May 04 16:57:20 2010 +0100 +++ b/kerneltest/e32test/rm_debug/multi_target_tests/t_multi_target.cpp Tue May 04 18:23:12 2010 +0100 @@ -110,14 +110,16 @@ // Performs each test in turn // { + test.Start(_L("ClientAppL")); TInt err = iServSession.Connect(securityServerVersion); if (err != KErrNone) { User::Panic(_L("Can't open server session"), err); } - + SetupDebugServerL(); LaunchTargetsInOrderL(); RDebug::Printf( "returning from CMultiTargetAgent::ClientAppL" ); + test.End(); } /** @@ -158,7 +160,7 @@ void CMultiTargetAgent::SetupDebugServerL() { RDebug::Printf( "CMultiTargetAgent::SetupDebugServerL" ); - + test.Next(_L("SetupDebugServerL\n")); iTargets.ReserveL( KNumApps ); RBuf targetName; @@ -235,8 +237,7 @@ TBool thisLaunchCompleted; - SetupDebugServerL(); - + test.Next(_L("LaunchTargetsInOrderL\n")); for( TInt numLaunches = KNumLaunches; numLaunches > 0; numLaunches-- ) { for( TInt numApps = KNumApps; numApps > 0; numApps-- ) @@ -362,17 +363,19 @@ } } - CleanupStack::PopAndDestroy( &launchSemaphore ); // launchSemaphore - - for( TInt i = iTargets.Count()-1; i>=0; i-- ) - { - RDebug::Printf( "Closing target %d", i ); - iTargets[ i ].Close(); - } + launchSemaphore.Signal(); + + CleanupStack::PopAndDestroy( &launchSemaphore ); // launchSemaphore + + for( TInt i = iTargets.Count()-1; i>=0; i-- ) + { + RDebug::Printf( "Closing target %d", i ); + iTargets[ i ].Close(); + } - iTargets.Close(); - - return KErrNone; + iTargets.Close(); + + return KErrNone; } diff -r 466a0df5c15a -r ea2434cf3670 kerneltest/e32test/secure/t_sdrivers.cpp --- a/kerneltest/e32test/secure/t_sdrivers.cpp Tue May 04 16:57:20 2010 +0100 +++ b/kerneltest/e32test/secure/t_sdrivers.cpp Tue May 04 18:23:12 2010 +0100 @@ -367,7 +367,7 @@ // get another thread to try and call device GetCaps with descriptor in kernel memory... test.Next(_L("Check GetCaps with bad descriptor 2")); - r = thread.Create(_L("TestGetCapsThread"),TestGetCapsThread,KDefaultStackSize,0x2000,0x2000,(TAny*)kernelPtr); + r = thread.Create(_L("TestGetCapsThread2"),TestGetCapsThread,KDefaultStackSize,0x2000,0x2000,(TAny*)kernelPtr); test_KErrNone(r); thread.Logon(ls); thread.Rendezvous(rs); diff -r 466a0df5c15a -r ea2434cf3670 kerneltest/e32test/system/t_mstim.cpp --- a/kerneltest/e32test/system/t_mstim.cpp Tue May 04 16:57:20 2010 +0100 +++ b/kerneltest/e32test/system/t_mstim.cpp Tue May 04 18:23:12 2010 +0100 @@ -84,7 +84,7 @@ TInt r=mstim.GetInfo(aId,info); CHECK(r); TEST(info.iCount==1); - return info.iMin/1000; + return (info.iMin+500)/1000; } GLDEF_C TInt E32Main() diff -r 466a0df5c15a -r ea2434cf3670 kerneltest/e32test/thread/t_thread.cpp --- a/kerneltest/e32test/thread/t_thread.cpp Tue May 04 16:57:20 2010 +0100 +++ b/kerneltest/e32test/thread/t_thread.cpp Tue May 04 18:23:12 2010 +0100 @@ -601,7 +601,8 @@ test(thread.ExitCategory()==_L("panic")); test(thread.ExitReason()==123); test(thread.ExitType()==EExitPanic); - CLOSE_AND_WAIT(thread); + r = RTest::CloseHandleAndWaitForDestruction(thread); + test_KErrNone(r); } test.Next(_L("Internal exit")); diff -r 466a0df5c15a -r ea2434cf3670 kerneltest/f32test/server/t_ext1.cpp --- a/kerneltest/f32test/server/t_ext1.cpp Tue May 04 16:57:20 2010 +0100 +++ b/kerneltest/f32test/server/t_ext1.cpp Tue May 04 18:23:12 2010 +0100 @@ -448,6 +448,19 @@ test.Start(_L("Starting Test - T_EXT1")); test(err==KErrNone); + // Check that the drive supports extensions. + TBool extensionsSupported = EFalse; + TPckg dataBuf(extensionsSupported); + err = TheFs.QueryVolumeInfoExt(drive,EFSysExtensionsSupported,dataBuf); + test(err==KErrNone); + if(!extensionsSupported) + { + test.Printf(_L("Drive %d does not support file sys extensions. Skipping test."), drive); + test.End(); + test.Close(); + return; + } + PrintDrvInfo(TheFs, drive); //Do not run this test on the NAND drive, as diff -r 466a0df5c15a -r ea2434cf3670 kerneltest/f32test/server/t_rcache.cpp --- a/kerneltest/f32test/server/t_rcache.cpp Tue May 04 16:57:20 2010 +0100 +++ b/kerneltest/f32test/server/t_rcache.cpp Tue May 04 18:23:12 2010 +0100 @@ -1446,7 +1446,7 @@ */ LOCAL_C void TestReadAhead() -{ + { TInt r = 0,tcreate; RFile fileRead; HBufC8* dummy = NULL; @@ -1454,28 +1454,6 @@ TUint32 initTicks = 0; TUint32 finalTicks = 0; - TTimeIntervalMicroSeconds timeTakenReadFirst(0); - TTimeIntervalMicroSeconds timeTakenReadSubsequent(0); - - // On NAND/FAT and NOR/LFFS drives, due to the lack of DMA support, the read-ahead is likely to happen - // BEFORE control is returned to this test app - for NAND this could be fixed by adding - // "FileCacheReadAsync OFF" to the estart.txt file, but we can't do this on the integrator as it has no - // estart.txt file. Also, we can't set "FileCacheReadAsync OFF" for LFFS as it kills the LFFS background - // processing (!) - // So... it's only really worth testing on MMC. - _LIT(KFATName,"FAT"); - TDriveInfo driveInfo; - test(TheFs.Drive(driveInfo, gDrive) == KErrNone); - TFileName fileSystem; - r = TheFs.FileSystemName(fileSystem, gDrive); - fileSystem.UpperCase(); - test((r==KErrNone)||(r==KErrNotFound)); - // ONLY test on MMC - if ((driveInfo.iType != EMediaHardDisk) || (fileSystem.Compare(KFATName) != 0)) - { - test.Printf(_L("Skipping read-ahead testing (drive is not MMC)...\n")); - return; - } //--Find out if the drive is sync/async at this point and print information TPckgBuf drvSyncBuf; @@ -1514,82 +1492,81 @@ r = fileRead.Open(TheFs,gFirstFile,EFileShareAny|EFileRead|EFileReadBuffered|EFileReadAheadOn); test_KErrNone(r); - // Read #1 - test.Printf(_L("Issuing read #1...\n")); - initTicks = User::FastCounter(); - r = fileRead.Read(dummyPtr); - finalTicks = User::FastCounter(); +#if defined(_DEBUG) || defined(_DEBUG_RELEASE) + TFileCacheStats fileCacheStats; + r = controlIo(TheFs,gDrive, KControlIoFileCacheStats, fileCacheStats); test_KErrNone(r); + TInt totalBytesRead = fileCacheStats.iUncachedBytesRead; + test.Printf(_L("totalBytesRead %d\n"), totalBytesRead); + TInt bytesRead = 0; + TInt filePos = 0; +#endif - timeTakenReadFirst = TicksToMsec(initTicks, finalTicks, fastCounterFreq); - test.Printf(_L("first read time %d \n"), I64LOW(timeTakenReadFirst.Int64())); + const TInt KReadCount = 6; + #define PAGE_ROUND_UP(x) ((x + 4095) & (-4096)) + TInt expectedBytesRead[KReadCount] = + { + PAGE_ROUND_UP(KReadLen), // read #0 from media + PAGE_ROUND_UP(KReadLen), // read #1 from media + PAGE_ROUND_UP(KReadLen*2), // read #2 from media, read-ahead #1 of length KReadLen + PAGE_ROUND_UP(KReadLen*2), // read #3 from cache, read-ahead #2 of length KReadLen * 2 + PAGE_ROUND_UP(KReadLen*4), // read #4 from cache, read-ahead #3 of length KReadLen * 4 + 0, // read #5 from cache, no read-ahead + }; + TTimeIntervalMicroSeconds readTimes[KReadCount]; - // Read #2 - test.Printf(_L("Issuing read #2...\n")); - r = fileRead.Read(dummyPtr); + for (TInt n=0; n= 2) + { + test.Printf(_L("Wait %u uS for read-ahead ...\n"), readAheadTime); + User::After(readAheadTime); + } - test.Printf(_L("Issuing read #4...resulting in read-ahead #2\n")); - initTicks = User::FastCounter(); - r = fileRead.Read(dummyPtr); - finalTicks = User::FastCounter(); - test_KErrNone(r); - timeTakenReadSubsequent = TicksToMsec(initTicks, finalTicks, fastCounterFreq); +#if defined(_DEBUG) || defined(_DEBUG_RELEASE) + // check the number of bytes read from the media is as expected. i.e. including the read-ahead length + // Keep waiting if it's not for up to 10 seconds + const TInt KMaxWaitTime = 10000000; // 10 secs + TInt waitTime; + for (waitTime=0; waitTime = 3) + { + if (readTimes[n].Int64() >= readTimes[0].Int64()) + test.Printf(_L("WARNING: Subsequent read not faster despite read-ahead !!!\n")); + } #endif - - // The read ahead #2 should now be in progress - this should be approx KReadLen * 2 - // so this read will take result in the next read taking longer than normal (about double) - test.Printf(_L("Issuing read #5......resulting in read-ahead #3\n")); - initTicks = User::FastCounter(); - r = fileRead.Read(dummyPtr); - finalTicks = User::FastCounter(); - test_KErrNone(r); - timeTakenReadSubsequent = TicksToMsec(initTicks, finalTicks, fastCounterFreq); - test.Printf(_L("read time: %d\n"), I64LOW(timeTakenReadSubsequent.Int64())); - - - // this read should take a long time, so don't test -//#if !defined(__WINS__) -// test(gTimeTakenReadBlockFile.Int64() < gTimeTakenBigFile.Int64()); -//#endif - - // The third read should be very quick as the previous read-ahead should have already buffered the data - test.Printf(_L("Issuing read #6......resulting in read-ahead #4\n")); - initTicks = User::FastCounter(); - r = fileRead.Read(dummyPtr); - finalTicks = User::FastCounter(); - test_KErrNone(r); - timeTakenReadSubsequent = TicksToMsec(initTicks, finalTicks, fastCounterFreq); - test.Printf(_L("read time: %d\n"), I64LOW(timeTakenReadSubsequent.Int64())); - - -#if !defined(__WINS__) - if (gPagedRom) - test.Printf(_L("Skipping timing test on paged ROM\n")); - else - test(timeTakenReadSubsequent.Int64() < timeTakenReadFirst.Int64()); -#endif - - + } fileRead.Close(); r = DeleteAll(gSessionPath); @@ -1597,8 +1574,7 @@ delete dummy; test.End(); - -} + } /** Main tests function */ diff -r 466a0df5c15a -r ea2434cf3670 package_definition.xml --- a/package_definition.xml Tue May 04 16:57:20 2010 +0100 +++ b/package_definition.xml Tue May 04 18:23:12 2010 +0100 @@ -61,6 +61,14 @@ + + + + + + + + @@ -133,6 +141,9 @@ + + + diff -r 466a0df5c15a -r ea2434cf3670 userlibandfileserver/fileserver/group/release.txt --- a/userlibandfileserver/fileserver/group/release.txt Tue May 04 16:57:20 2010 +0100 +++ b/userlibandfileserver/fileserver/group/release.txt Tue May 04 18:23:12 2010 +0100 @@ -1,3 +1,44 @@ +Version 2.00.3024 +================= +(Made by vfebvre 22/03/2010) + +1. migubarr + 1. DEF144423 Frequent T_RCACHE failures on the H2/H6 (line 1556) + +2. michcox + 1. PDEF145110 File server does not check return result of some User::ReAlloc()'s + + +Version 2.00.3023 +================= +(Made by vfebvre 15/03/2010) + +1. niccox + 1. DEF145021 Improper Mass Storage Error Code for Empty Drive case + +2. shamaden + 1. PDEF144922 TRAI-82RJFS Crash when usb memory is dismounted during copy + + +Version 2.00.3022 +================= +(Made by vfebvre 12/03/2010) + +1. famustaf + 1. MINOR_CHANGE Updated RFs::ScanDrive and RFs::CheckDisk Documentation + +2. michcox + 1. DEF144912 T_EXT1 fails under platsim as it doesn't support fsys extensions + + +Version 2.00.3021 +================= +(Made by vfebvre 11/03/2010) + +1. frhofman + 1. PDEF144919: SALM-82WCVK: efile.exe crashes in dynamic dir cache code when out-of-memory + + Version 2.00.3020 ================= (Made by vfebvre 08/03/2010) diff -r 466a0df5c15a -r ea2434cf3670 userlibandfileserver/fileserver/inc/f32file.h --- a/userlibandfileserver/fileserver/inc/f32file.h Tue May 04 16:57:20 2010 +0100 +++ b/userlibandfileserver/fileserver/inc/f32file.h Tue May 04 18:23:12 2010 +0100 @@ -680,6 +680,15 @@ ETrue value means that the drive is finalised */ EIsDriveFinalised, + + /** + Query the volume to ascertain whether File system extensions + are supported on this volume. + A boolean value is returned within the buffer defined as TPckgBuf. + ETrue value means that extensions are supported. + EFalse means they are not supported. + */ + EFSysExtensionsSupported, }; /** diff -r 466a0df5c15a -r ea2434cf3670 userlibandfileserver/fileserver/inc/f32ver.h --- a/userlibandfileserver/fileserver/inc/f32ver.h Tue May 04 16:57:20 2010 +0100 +++ b/userlibandfileserver/fileserver/inc/f32ver.h Tue May 04 18:23:12 2010 +0100 @@ -58,6 +58,6 @@ @see TVersion */ -const TInt KF32BuildVersionNumber=3020; +const TInt KF32BuildVersionNumber=3024; // #endif diff -r 466a0df5c15a -r ea2434cf3670 userlibandfileserver/fileserver/sfat32/sl_dir_cache.cpp --- a/userlibandfileserver/fileserver/sfat32/sl_dir_cache.cpp Tue May 04 16:57:20 2010 +0100 +++ b/userlibandfileserver/fileserver/sfat32/sl_dir_cache.cpp Tue May 04 18:23:12 2010 +0100 @@ -27,9 +27,9 @@ The static cache page creation function. Cache page objects are not supposed to be created on the stack, so this factory function is required. */ -TDynamicDirCachePage* TDynamicDirCachePage::NewL(CDynamicDirCache* aOwnerCache, TInt64 aStartMedPos, TUint8* aStartRamAddr) +TDynamicDirCachePage* TDynamicDirCachePage::CreateCachePage(CDynamicDirCache* aOwnerCache, TInt64 aStartMedPos, TUint8* aStartRamAddr) { - return new(ELeave) TDynamicDirCachePage(aOwnerCache, aStartMedPos, aStartRamAddr); + return new TDynamicDirCachePage(aOwnerCache, aStartMedPos, aStartRamAddr); } /** @@ -158,7 +158,7 @@ // allocate as many permanently locked pages as there are threads - plus one // otherwise DoMakePageMRU() won't work properly with only one thread - //-- At present moment the size of TDrive thread pool is 1 (1 drive thread in a pool) + //-- At present moment the size of TDrive thread pool is 1 (1 drive thread in a pool) const TUint KThreadCount = 1; iPermanentlyAllocatedPageCount = KThreadCount + 1; @@ -167,7 +167,10 @@ for (TUint n=0; nIsValid()); + if (pPage) + { + ASSERT(pPage->IsValid()); // lock page before make it MRU - if (pPage->PageType() == TDynamicDirCachePage::EUnlocked) - { - ASSERT(!pPage->IsLocked()); - if (LockPage(pPage) == NULL) - { - DeQueue(pPage); - LookupTblRemove(pPage->StartPos()); - DecommitPage(pPage); - delete pPage; - pPage = NULL; - } - } - else - { - // error checking: page should either be locked or active - ASSERT(LockPage(pPage) != NULL); - } - } + if (pPage->PageType() == TDynamicDirCachePage::EUnlocked) + { + ASSERT(!pPage->IsLocked()); + if (LockPage(pPage) == NULL) + { + DeQueue(pPage); + LookupTblRemove(pPage->StartPos()); + DecommitPage(pPage); + delete pPage; + pPage = NULL; + } + } + else + { + // error checking: page should either be locked or active + ASSERT(LockPage(pPage) != NULL); + } + } - // if page not found or page data not valid anymore, use active page to read data - if (!pPage) - { - TRAPD(err, pPage = UpdateActivePageL(aPos)); - if (err != KErrNone) - { - // problem occurred reading active page, return immediately. - return; - } - } + // if page not found or page data not valid anymore, use active page to read data + if (!pPage) + { + TRAPD(err, pPage = UpdateActivePageL(aPos)); + if (err != KErrNone) + { + // problem occurred reading active page, return immediately. + return; + } + } - // by now, the page is either locked or active page + // by now, the page is either locked or active page ASSERT(pPage && pPage->IsValid() && pPage->IsLocked()); - - TBool allocateNewPage = pPage == iLockedQ.Last() && !CacheIsFull(); - + // if we used the active page (last on the queue), try to grow the cache. + TBool growCache = pPage == iLockedQ.Last(); switch (pPage->PageType()) { @@ -762,24 +764,24 @@ ASSERT(0); } - if (allocateNewPage) - { - TDynamicDirCachePage* nPage = NULL; - TRAPD(err, nPage = AllocateAndLockNewPageL(0)); - if (err == KErrNone) - { + if (CacheIsFull() || !growCache) + return; + + // attempt to grow the cache by appending a clean, new page at the end of the LRU list. + // This can fail when out of memory; the LRU mechanism then makes sure the oldest page will be re-used. + TDynamicDirCachePage* nPage = AllocateAndLockNewPage(0); + if (!nPage) + return; - // about to add a page to end of locked queue, so lie about iLockedQCount - iLockedQCount++; - CheckThresholds(); - iLockedQCount--; + // about to add a page to end of locked queue, so lie about iLockedQCount + iLockedQCount++; + CheckThresholds(); + iLockedQCount--; - iLockedQ.AddLast(*nPage); - nPage->SetPageType(TDynamicDirCachePage::ELocked); - ++iLockedQCount; - LookupTblAdd(nPage); - } - } + iLockedQ.AddLast(*nPage); + nPage->SetPageType(TDynamicDirCachePage::ELocked); + ++iLockedQCount; + LookupTblAdd(nPage); } /** @@ -898,21 +900,28 @@ @param aStartMedPos the starting media address of the page to be created. @pre aStartMedPos should not already be existing in the cache. */ -TDynamicDirCachePage* CDynamicDirCache::AllocateAndLockNewPageL(TInt64 aStartMedPos) +TDynamicDirCachePage* CDynamicDirCache::AllocateAndLockNewPage(TInt64 aStartMedPos) { - __PRINT1(_L("CDynamicDirCache::AllocateAndLockNewPageL(aStartMedPos=%lx)"), aStartMedPos); + __PRINT1(_L("CDynamicDirCache::AllocateAndLockNewPage(aStartMedPos=%lx)"), aStartMedPos); TUint8* startRamAddr = iCacheMemoryClient->AllocateAndLockSegments(PageSizeInSegs()); - if (startRamAddr) + + if (!startRamAddr) + return NULL; + + TDynamicDirCachePage* pPage = TDynamicDirCachePage::CreateCachePage(this, aStartMedPos, startRamAddr); + + // Failure would mean the cache chunk was able to grow but we've run out of heap. + // This seems extremely unlikely, but decommit the now-unmanageable cache segment just in case. + if (!pPage) { - // create new page and return - TDynamicDirCachePage* pPage = TDynamicDirCachePage::NewL(this, aStartMedPos, startRamAddr); - pPage->SetLocked(ETrue); - pPage->SetValid(EFalse); - return pPage; + iCacheMemoryClient->DecommitSegments(startRamAddr, PageSizeInSegs()); + return NULL; } - return NULL; + pPage->SetLocked(ETrue); + pPage->SetValid(EFalse); + return pPage; } #ifdef _DEBUG diff -r 466a0df5c15a -r ea2434cf3670 userlibandfileserver/fileserver/sfat32/sl_dir_cache.h --- a/userlibandfileserver/fileserver/sfat32/sl_dir_cache.h Tue May 04 16:57:20 2010 +0100 +++ b/userlibandfileserver/fileserver/sfat32/sl_dir_cache.h Tue May 04 18:23:12 2010 +0100 @@ -47,7 +47,7 @@ public: ~TDynamicDirCachePage(); - static TDynamicDirCachePage* NewL(CDynamicDirCache* aOwnerCache, TInt64 aStartMedPos, TUint8* aStartRamAddr); + static TDynamicDirCachePage* CreateCachePage(CDynamicDirCache* aOwnerCache, TInt64 aStartMedPos, TUint8* aStartRamAddr); inline void SetLocked(TBool); inline TBool IsLocked() const; @@ -145,7 +145,7 @@ TDynamicDirCachePage* FindPageByPos(TInt64 aPos); TDynamicDirCachePage* UpdateActivePageL(TInt64 aPos); - TDynamicDirCachePage* AllocateAndLockNewPageL(TInt64 aStartMedPos); + TDynamicDirCachePage* AllocateAndLockNewPage(TInt64 aStartMedPos); TUint8* LockPage(TDynamicDirCachePage* aPage); TInt UnlockPage(TDynamicDirCachePage* aPage); TInt DecommitPage(TDynamicDirCachePage* aPage); diff -r 466a0df5c15a -r ea2434cf3670 userlibandfileserver/fileserver/sfat32/sl_drv.cpp --- a/userlibandfileserver/fileserver/sfat32/sl_drv.cpp Tue May 04 16:57:20 2010 +0100 +++ b/userlibandfileserver/fileserver/sfat32/sl_drv.cpp Tue May 04 18:23:12 2010 +0100 @@ -1,4 +1,4 @@ -// Copyright (c) 1996-2009 Nokia Corporation and/or its subsidiary(-ies). +// Copyright (c) 1996-2010 Nokia Corporation and/or its subsidiary(-ies). // All rights reserved. // This component and the accompanying materials are made available // under the terms of the License "Eclipse Public License v1.0" @@ -46,12 +46,11 @@ Close the interface to the media driver */ void TDriveInterface::Close() -{ - if(iMount) +{ + if((iMount != NULL) && (iMount->LocalDrive() != NULL)) { iMount->LocalDrive()->SetMount(NULL); - } - + } iMount = NULL; } diff -r 466a0df5c15a -r ea2434cf3670 userlibandfileserver/fileserver/sfat32/sl_scan32.cpp --- a/userlibandfileserver/fileserver/sfat32/sl_scan32.cpp Tue May 04 16:57:20 2010 +0100 +++ b/userlibandfileserver/fileserver/sfat32/sl_scan32.cpp Tue May 04 18:23:12 2010 +0100 @@ -94,7 +94,7 @@ //---------------------------------------------------------------------------------------------------- /** FAT type-agnostic parser. Reads whole FAT and sets up a bit vector. - for FAT12/16 it's OK, because the FAT12/16 is fully cached. + For FAT12/16 it's OK, because the FAT12/16 is fully cached. */ void CScanDrive::DoParseFatL() { @@ -255,8 +255,9 @@ //---------------------------------------------------------------------------------------------------- /** - Start the scanner. The this calss description about what it actually does. - @param aMode specifies the operational mode. + Starts the scanner. + + @param aMode Specifies the operational mode. */ void CScanDrive::StartL(TScanDriveMode aMode) { @@ -946,7 +947,6 @@ Read the "Rugged FAT" ID, stored in reserved2 in the Dos entry or associated with the Dos entry of the Entry at the position passed in. This is used to find which version of two matching entries should be kept. - @param aVFatPos Position of an entry to read ID from @leave System wide error codes @return The ID found in reserved2 field of dos entry diff -r 466a0df5c15a -r ea2434cf3670 userlibandfileserver/fileserver/sfile/sf_cache.cpp --- a/userlibandfileserver/fileserver/sfile/sf_cache.cpp Tue May 04 16:57:20 2010 +0100 +++ b/userlibandfileserver/fileserver/sfile/sf_cache.cpp Tue May 04 18:23:12 2010 +0100 @@ -610,8 +610,11 @@ if(r==KErrNoMemory) return r; + iCache = (TFileCacheRecord**)User::ReAlloc(pIndexes,sizeof(TFileCacheRecord*)*currentIndex); + if(!iCache) + return KErrNoMemory; + iNotPresent = EFalse; - iCache = (TFileCacheRecord**)User::ReAlloc(pIndexes,sizeof(TFileCacheRecord*)*currentIndex); iRecordCount = currentIndex; if (currentIndex>1) { diff -r 466a0df5c15a -r ea2434cf3670 userlibandfileserver/fileserver/sfile/sf_obj.cpp --- a/userlibandfileserver/fileserver/sfile/sf_obj.cpp Tue May 04 16:57:20 2010 +0100 +++ b/userlibandfileserver/fileserver/sfile/sf_obj.cpp Tue May 04 18:23:12 2010 +0100 @@ -129,7 +129,13 @@ if (newAlloc!=iAllocated) { if (newAlloc) + { iContainers=(CFsObjectCon**)User::ReAlloc(iContainers,newAlloc*sizeof(CFsObjectCon*)); + if(!iContainers) + { + Fault(EContainerHeapCorruptionOnRemove); + } + } else { delete iContainers; @@ -489,7 +495,13 @@ if (newAlloc!=iAllocated) { if (newAlloc) + { iObjects=(SFsObjectIxRec*)User::ReAlloc(iObjects,newAlloc*sizeof(SFsObjectIxRec)); + if(!iObjects) + { + Fault(EContainerHeapCorruptionOnRemove); + } + } else { delete iObjects; @@ -679,7 +691,13 @@ if (newAlloc!=iAllocated) { if (newAlloc) + { iObjects=(CFsObject**)User::ReAlloc(iObjects,newAlloc*sizeof(CFsObject*)); + if(!iObjects) + { + Fault(EContainerHeapCorruptionOnRemove); + } + } else { delete iObjects; diff -r 466a0df5c15a -r ea2434cf3670 userlibandfileserver/fileserver/sfile/sf_std.h --- a/userlibandfileserver/fileserver/sfile/sf_std.h Tue May 04 16:57:20 2010 +0100 +++ b/userlibandfileserver/fileserver/sfile/sf_std.h Tue May 04 18:23:12 2010 +0100 @@ -235,7 +235,7 @@ enum TFsPanic { - ELdrImportedOrdinalDoesNotExist + ELdrImportedOrdinalDoesNotExist }; // enum TFsFault @@ -443,7 +443,8 @@ ETraceLddLoadFailure, //200 ETooManyDrivesPerSocket, ENotificationFault, - EFsObjectOpen + EFsObjectOpen, + EContainerHeapCorruptionOnRemove }; diff -r 466a0df5c15a -r ea2434cf3670 userlibandfileserver/fileserver/sfile/sf_svr.cpp --- a/userlibandfileserver/fileserver/sfile/sf_svr.cpp Tue May 04 16:57:20 2010 +0100 +++ b/userlibandfileserver/fileserver/sfile/sf_svr.cpp Tue May 04 18:23:12 2010 +0100 @@ -1314,8 +1314,13 @@ return KErrNone; } - - + case EFSysExtensionsSupported: + { + TBool supported = pDrive->GetFSys()->IsExtensionSupported(); + TPckgBuf data(supported); + aRequest->WriteL(KMsgPtr2,data); + return KErrNone; + } default: { return KErrNotSupported; diff -r 466a0df5c15a -r ea2434cf3670 userlibandfileserver/fileserver/sfsrv/cl_cli.cpp --- a/userlibandfileserver/fileserver/sfsrv/cl_cli.cpp Tue May 04 16:57:20 2010 +0100 +++ b/userlibandfileserver/fileserver/sfsrv/cl_cli.cpp Tue May 04 18:23:12 2010 +0100 @@ -2630,29 +2630,37 @@ } - /** -Checks the integrity of the disk on the specified drive. -On FAT, this checks if a cluster number is invalid, if a cluster is allocated to -more than one file entry, if an unallocated cluster is not set free, and if size -of an entry is invalid. - -@param aDrive Path indicating the drive which contains the disk to be checked. If the drive - information is not specified the current session drive is taken by default. - Checkdisk is performed on the requested drive irrespective of the correctness or - existance of the given path. - -@return KErrNone, if successful; - 1, if successful but a file cluster contains a bad value; - 2, if successful but two files are linked to the same cluster; - 3, if successful but an unallocated cluster contains a value; - 4, if successful but the size of a file is not equal to the number of clusters in chain; - KErrNotReady, if the specified drive is empty; - KErrNotSupported, if the drive cannot handle this request; - KErrPermissionDenied, if the caller doesn't have DiskAdmin capability; - Other system wide error codes may also be returned. - -@capability DiskAdmin +Checks the integrity of the File System mounted on the specified drive. +The behaviour of this API and return codes are File System specific, +dependent on how the File System implements its CheckDisk functionality. +Note that CheckDisk does not fix any errors that may be found, +it just reports the first problem it has found. + +@param aDrive Path containing the drive to be checked. + If the drive letter is not specified, the current session drive is taken by default. + +@return KErrNone If CheckDisk has not found any errors it knows about. + KErrNotReady If the specified drive is not ready. + KErrNotSupported If this functionality is not supported. + KErrPermissionDenied If the caller does not have DiskAdmin capability. + Other system-wide error codes. + +@capability DiskAdmin + +FAT File System specific information: + +CheckDisk checks for a limited amount of possible corruption cases such as +invalid cluster numbers in the FAT table, lost and cross-linked cluster chains, +various errors within the directory entry etc. + +If CheckDisk returns KErrNone, this means that there are no errors that CheckDisk on FAT is aware of. + +Error codes returned by the FAT version of CheckDisk include: + 1 Bad cluster value in FAT table detected. + 2 Cross-linked cluster chain detected. + 3 Lost cluster chain detected. + 4 File size does not correspond to the number of clusters reported in the FAT table. */ EFSRV_EXPORT_C TInt RFs::CheckDisk(const TDesC& aDrive) const { @@ -2668,24 +2676,42 @@ EFSRV_EXPORT_C TInt RFs::ScanDrive(const TDesC& aDrive) const /** -Checks the specified drive for errors and corrects them. Specifically, it -checks if long file name entries' IDs are in sequence and short name is valid, -and file's allocated clusters are not used by other files. - -This does not run on the internal RAM drive, and only applies to a -FAT file system. - -@param aDrive Path indicating the drive which contains the disk to be checked. If the drive - information is not specified the current session drive is taken by default. - ScanDrive is performed on the requested drive irrespective of the correctness or - existance of the given path. - -@return KErrNone if successful, - KErrPermissionDenied if caller doesn't have capability DiskAdmin, - KErrInUse if drive is in use, - otherwise one of the other system-wide error codes - -@capability DiskAdmin +Checks the integrity of the File System mounted on the specified drive +and attempts to correct some known File System errors. +The behaviour of this API and return codes are File System specific, +dependent on how the File System implements its ScanDrive functionality. + +ScanDrive will not run on drives that have files or directories opened. + +@param aDrive Path indicating the drive which contains the disk to be checked. + If the drive letter is not specified, the current session drive is taken by default. + +@return KErrNone On success. + KErrInUse If drive is in use (i.e. if there are files and/or directories opened in the drive). + KErrCorrupt If ScanDrive has detected a file system corruption that it cannot fix. + KErrNotSupported If this functionality is not supported. + KErrPermissionDenied If the caller does not have DiskAdmin capability. + Other system-wide error codes. + +@capability DiskAdmin + +FAT File System specific information: + +ScanDrive is intended to be run ONLY on "Rugged-FAT" file system +which is applicable to internal non-removable drives. +Internal RAM drives are not supported. + +The "Rugged FAT" file system is designed in such a way that only a limited number +of known cases of corruption can be caused by sudden power loss. +All of these known cases can be corrected by ScanDrive. +Hence, running ScanDrive on "Rugged FAT" file system will result in: + KErrNone If there was no File System corruption or ScanDrive has successfully repaired the File System. + KErrCorrupt If ScanDrive has found a File System error that it cannot repair. + Other system-wide error codes, see above. + +Running ScanDrive on removable media or media that has FAT file system not in +"Rugged FAT" mode is not practical, because ScanDrive is not designed for this. +Therefore, do not treat ScanDrive on removable media as a generic "disk repair utility". */ { TRACEMULT2(UTF::EBorder, UTraceModuleEfsrv::EFsScanDrive, MODULEUID, Handle(), aDrive); diff -r 466a0df5c15a -r ea2434cf3670 userlibandfileserver/fileserver/shostmassstorage/msproxy/hostusbmsproxy.cpp --- a/userlibandfileserver/fileserver/shostmassstorage/msproxy/hostusbmsproxy.cpp Tue May 04 16:57:20 2010 +0100 +++ b/userlibandfileserver/fileserver/shostmassstorage/msproxy/hostusbmsproxy.cpp Tue May 04 18:23:12 2010 +0100 @@ -1,24 +1,18 @@ -/* -* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). -* All rights reserved. -* This component and the accompanying materials are made available -* under the terms of the License "Eclipse Public License v1.0" -* which accompanies this distribution, and is available -* at the URL "http://www.eclipse.org/legal/epl-v10.html". -* -* Initial Contributors: -* Nokia Corporation - initial contribution. -* -* Contributors: -* -* Description: -* -*/ +// Copyright (c) 2008-2010 Nokia Corporation and/or its subsidiary(-ies). +// All rights reserved. +// This component and the accompanying materials are made available +// under the terms of the License "Eclipse Public License v1.0" +// which accompanies this distribution, and is available +// at the URL "http://www.eclipse.org/legal/epl-v10.html". // -// hostusbmsproxy.cpp +// Initial Contributors: +// Nokia Corporation - initial contribution. // -// This file system extension provides a way to access a drive on the MS system in "raw format". -// It can be used to test large files / drives +// Contributors: +// +// Description: +// This file system extension provides a way to access a drive on the MS system +// in "raw format". It can be used to test large files / drives // /** @file @@ -486,6 +480,7 @@ return KErrNone; } + /** Write to the proxy drive and pass flags to driver @@ -521,6 +516,7 @@ return iUsbHostMsLun.Write(iMsDataMemMap.GetDataPos(aPos), aSrc.Length(), aSrc); } + /** Get the proxy drive's capabilities information. @@ -566,19 +562,22 @@ capsInfo.iNumberOfBlocks, capsInfo.iBlockLength, caps().iSize, caps().iMediaAtt); } - else + else if (KErrNotReady) { __HOSTPRINT(_L("<<< HOST Caps Media Not Present")); - c.iType = EMediaNotPresent; - if(r != KErrNotReady) - r = KErrUnknown; + c.iType = EMediaNotPresent; + r = KErrNone; + } + else + { + __HOSTPRINT(_L("<<< HOST Caps Unknown Error")); + r = KErrUnknown; } anInfo = caps.Left(Min(caps.Length(),anInfo.MaxLength())); return r; } - /** Format the proxy drive. The drive is assumed to be a single partition. The partition size is equivalent to the size of the media. diff -r 466a0df5c15a -r ea2434cf3670 userlibandfileserver/fileserver/shostmassstorage/server/protocol/cscsiprotocol.cpp --- a/userlibandfileserver/fileserver/shostmassstorage/server/protocol/cscsiprotocol.cpp Tue May 04 16:57:20 2010 +0100 +++ b/userlibandfileserver/fileserver/shostmassstorage/server/protocol/cscsiprotocol.cpp Tue May 04 18:23:12 2010 +0100 @@ -1,4 +1,4 @@ -// Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies). +// Copyright (c) 2008-2010 Nokia Corporation and/or its subsidiary(-ies). // All rights reserved. // This component and the accompanying materials are made available // under the terms of the License "Eclipse Public License v1.0" @@ -26,8 +26,6 @@ #include "shared.h" #include "msgservice.h" -#include "mscutils.h" - #include "mtransport.h" #include "mprotocol.h" #include "tscsiclientreq.h" @@ -45,7 +43,6 @@ #include "usbmshostpanic.h" - /** Create the CScsiProtocol object. @@ -68,8 +65,8 @@ void CScsiProtocol::ConstructL(TLun aLun) { __MSFNLOG + // iState = EEntry; iFsm = CMassStorageFsm::NewL(*this); - iState = EDisconnected; const TInt blockLength = 0x200; @@ -99,6 +96,7 @@ void CScsiProtocol::InitialiseUnitL() { __MSFNLOG + iState = EDisconnected; // A device may take time to mount the media. If the device fails attempt to // retry the connection for a number of seconds @@ -107,10 +105,9 @@ { retryCounter--; iFsm->ConnectLogicalUnitL(); - iState = iFsm->IsConnected() ? EConnected: EDisconnected; - - if (iState == EConnected) + if (iFsm->IsConnected()) { + iState = EConnected; break; } User::After(1000 * 200); // 200 mS @@ -162,8 +159,7 @@ if (err) { __SCSIPRINT1(_L("READ(10) Err=%d"), err); - DoCheckConditionL(); - User::LeaveIfError(KErrAbort); + User::LeaveIfError(DoCheckConditionL()); } // handle residue @@ -189,8 +185,7 @@ TInt err = iSbcInterface->Read10L(aPos/blockLen, aCopybuf, len); if (err) { - DoCheckConditionL(); - User::LeaveIfError(KErrAbort); + User::LeaveIfError(DoCheckConditionL()); } } } @@ -217,8 +212,7 @@ TInt err = iSbcInterface->Write10L(aPos/blockLen, aCopybuf, aOffset, len); if (err) { - DoCheckConditionL(); - User::LeaveIfError(KErrAbort); + User::LeaveIfError(DoCheckConditionL()); } while (len != aLen) @@ -242,8 +236,7 @@ TInt err = iSbcInterface->Write10L(aPos/blockLen, buf, aOffset, len); if (err) { - DoCheckConditionL(); - User::LeaveIfError(KErrAbort); + User::LeaveIfError(DoCheckConditionL()); } } } @@ -268,15 +261,11 @@ err = iSbcInterface->ReadCapacity10L(lastLba, blockLength); } while (err == KErrCommandStalled && stallCounter-- > 0); - if (err) { - if (err == KErrCommandFailed) - { - // Clear sense error - DoCheckConditionL(); - } - User::LeaveIfError(KErrAbort); + // DoCheckConditionL clears sense error + // Media not present will return KErrNotReady so leave here + User::LeaveIfError(DoCheckConditionL()); } // update iWriteProtect @@ -286,14 +275,24 @@ if (err == KErrCommandFailed) { // Clear sense error - DoCheckConditionL(); + err = DoCheckConditionL(); + // ignore error if unsupported + if (err != KErrUnknown) + { + User::LeaveIfError(err); + } } err = MsModeSense6L(); if (err == KErrCommandFailed) { // Clear sense error - DoCheckConditionL(); + err = DoCheckConditionL(); + // ignore error if unsupported + if (err != KErrUnknown) + { + User::LeaveIfError(err); + } } } @@ -481,33 +480,49 @@ } -void CScsiProtocol::DoCheckConditionL() +TInt CScsiProtocol::DoCheckConditionL() { __MSFNLOG User::LeaveIfError(MsRequestSenseL()); + TInt err; + // Check if init is needed if (iSenseInfo.iSenseCode == TSenseInfo::ENotReady && iSenseInfo.iAdditional == TSenseInfo::EAscLogicalUnitNotReady && iSenseInfo.iQualifier == TSenseInfo::EAscqInitializingCommandRequired) { // start unit - TInt err = iSbcInterface->StartStopUnitL(ETrue); - + err = iSbcInterface->StartStopUnitL(ETrue); if (err) { User::LeaveIfError(MsRequestSenseL()); } - } - TInt r = GetSystemWideSenseError(iSenseInfo); + err = GetSystemWideSenseError(iSenseInfo); - if (((r == KErrNotReady) && (iState == EConnected)) || - r == KErrDisconnected) - { - CompleteNotifyChangeL(); + TScsiState nextState = iState; + if (err == KErrDisconnected) + { + nextState = EDisconnected; + } + else if (err == KErrNotReady) + { + nextState = EMediaNotPresent; } + else + { + // no state change; + } + + if (nextState != iState) + { + iMediaChangeNotifier.DoNotifyL(); + iState = nextState; + } + + return err; } @@ -730,7 +745,7 @@ __MSFNLOG TInt err = KErrNone; - if(iFsm->IsRemovableMedia() || iState == EDisconnected) + if(iFsm->IsRemovableMedia() || iState != EConnected) { iFsm->SetStatusCheck(); TRAP(err, iFsm->ConnectLogicalUnitL()); @@ -760,18 +775,6 @@ } } -void CScsiProtocol::CompleteNotifyChangeL() - { - __MSFNLOG - if (!iFsm->IsStatusCheck()) - { - if (iState == EConnected) - { - iState = EDisconnected; - iMediaChangeNotifier.DoNotifyL(); - } - } - } RMediaChangeNotifier::RMediaChangeNotifier() : iRegistered(EFalse) diff -r 466a0df5c15a -r ea2434cf3670 userlibandfileserver/fileserver/shostmassstorage/server/protocol/include/cscsiprotocol.h --- a/userlibandfileserver/fileserver/shostmassstorage/server/protocol/include/cscsiprotocol.h Tue May 04 16:57:20 2010 +0100 +++ b/userlibandfileserver/fileserver/shostmassstorage/server/protocol/include/cscsiprotocol.h Tue May 04 18:23:12 2010 +0100 @@ -1,4 +1,4 @@ -// Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies). +// Copyright (c) 2008-2010 Nokia Corporation and/or its subsidiary(-ies). // All rights reserved. // This component and the accompanying materials are made available // under the terms of the License "Eclipse Public License v1.0" @@ -36,7 +36,7 @@ void DoCancelL(); private: - void CompleteNotifierL(TInt); + void CompleteNotifierL(TInt aReason); private: /** Notification service */ @@ -55,6 +55,8 @@ /** SCSI state */ enum TScsiState { + EEntry, + EMediaNotPresent, EConnected, EDisconnected }; @@ -88,8 +90,8 @@ void NotifyChange(const RMessage2& aMessage); void ForceCompleteNotifyChangeL(); void CancelChangeNotifierL(); - void CompleteNotifyChangeL(); - void SuspendL(); + + void SuspendL(); void ResumeL(); TBool IsConnected(); @@ -116,7 +118,7 @@ private: void ResetSbc(); - void DoCheckConditionL(); + TInt DoCheckConditionL(); TInt GetSystemWideSenseError(const TSenseInfo& aSenseInfo); TInt ProcessAsCodes(const TSenseInfo& aSenseInfo);