# HG changeset patch # User Dremov Kirill (Nokia-D-MSW/Tampere) # Date 1263842598 -7200 # Node ID b4a7eebaaebfc8c13feb1713721a8f6ac7402b0b # Parent 29b1cd4cb562e944365de4e5473231664542d43a Revision: 201001 Kit: 201003 diff -r 29b1cd4cb562 -r b4a7eebaaebf atext/client/src/atextclient.cpp --- a/atext/client/src/atextclient.cpp Fri Jan 15 08:13:17 2010 +0200 +++ b/atext/client/src/atextclient.cpp Mon Jan 18 21:23:18 2010 +0200 @@ -467,11 +467,11 @@ const TUidType serverUid( KNullUid, KNullUid, KATExtSrvUid3 ); RProcess server; TInt retTemp = server.Create( KATExtSrvExe, KNullDesC, serverUid ); - server.SetPriority( EPriorityHigh ); if ( retTemp != KErrNone ) { return retTemp; } + server.SetPriority( EPriorityHigh ); TRequestStatus status; server.Rendezvous( status ); if ( status != KRequestPending ) diff -r 29b1cd4cb562 -r b4a7eebaaebf atext/client/src/atextcommon.cpp --- a/atext/client/src/atextcommon.cpp Fri Jan 15 08:13:17 2010 +0200 +++ b/atext/client/src/atextcommon.cpp Mon Jan 18 21:23:18 2010 +0200 @@ -203,11 +203,11 @@ const TUidType serverUid( KNullUid, KNullUid, KATExtSrvUid3 ); RProcess server; TInt retTemp = server.Create( KATExtCommonSrvExe, KNullDesC, serverUid ); - server.SetPriority( EPriorityHigh ); if ( retTemp != KErrNone ) { return retTemp; } + server.SetPriority( EPriorityHigh ); TRequestStatus status; server.Rendezvous( status ); if ( status != KRequestPending ) diff -r 29b1cd4cb562 -r b4a7eebaaebf atext/server/inc/atextmetadata.h --- a/atext/server/inc/atextmetadata.h Fri Jan 15 08:13:17 2010 +0200 +++ b/atext/server/inc/atextmetadata.h Mon Jan 18 21:23:18 2010 +0200 @@ -15,7 +15,6 @@ * */ - #ifndef C_CATEXTMETADATA_H #define C_CATEXTMETADATA_H @@ -26,13 +25,20 @@ class CATExtPluginBase; class CATExtListen; -/** Support types supported by RSS file (M|P|S) */ +/** Panic categories */ +enum TATExtPanicCategories + { + EPanicCategoryFaultyMaster = 1, + EPanicCategoryPluginType = 2 + }; + +/** Support types supported by RSS file (M|P|O) */ enum TATExtSupportType { ESupportTypeUndefined = KErrNotFound, ESupportTypeMaster = 0, - ESupportTypePrimary, - ESupportTypeSecondary + ESupportTypePartial, + ESupportTypeObserver }; /** Operation types, either for command handling or for URC receiving */ @@ -128,25 +134,25 @@ public: - TATExtSearchHelper() : iPrimaryIndex( KErrNotFound ), - iSecondaryIndex( KErrNotFound ) {} + TATExtSearchHelper() : iPartialIndex( KErrNotFound ), + iObserverIndex( KErrNotFound ) {} /** - * Index to the primary entry + * Index to the partial entry */ - TInt iPrimaryIndex; + TInt iPartialIndex; /** - * Index to the secondary entry + * Index to the observer entry */ - TInt iSecondaryIndex; + TInt iObserverIndex; }; /** * Class to store data needed for one AT command support. * This includes the support's type and the plugin entry. - * Thus one plugin's RSS file may contain multiple M|P|S entries. + * Thus one plugin's RSS file may contain multiple M|P|O entries. * * @since S60 v5.0 */ @@ -156,7 +162,7 @@ public: /** - * Support's type (M|P|S) + * Support's type (M|P|O) */ TATExtSupportType iSupportType; @@ -313,7 +319,10 @@ CArrayFixFlat* aSupport ) : iAtCmdFull( aAtCmdFull ), iMessage( aMessage ), - iSupport( aSupport ) {} + iSupport( aSupport ), + iEntry( NULL ), + iStartIndex( KErrNotFound ), + iSupportFound( EFalse ){} /** * Full AT command for which to check the support @@ -328,7 +337,7 @@ /** * AT command's plugin entry support data. - * Used by SendToMultipleSecondaryL() and FindFirstSecondarySupportL(). + * Used by SendToMultipleObserverL() and FindFirstObserverSupportL(). */ CArrayFixFlat* iSupport; @@ -338,11 +347,16 @@ TATExtPluginEntry* iEntry; /** - * Starts index for searches with HandlePrimaryPluginSupportL() and - * HandleSecondaryPluginSupportL() + * Start index for searches with HandlePartialAndMasterPluginSupportL() and + * HandleObserverPluginSupportL() */ TInt iStartIndex; + /** + * Found plugin support for HandlePartialAndMasterPluginSupportL(). + */ + TBool iSupportFound; + }; /** @@ -835,7 +849,7 @@ * @param aCommands Command buffer from where to extract the next subcommand * @param aStartIndex Start index for the found command * @param aEndIndex End index for the found command - * @param aSupportType Support's type (M|P|S) + * @param aSupportType Support's type (M|P|O) * @return Symbian error code on error, KErrNone otherwise */ TInt ExtractNextCommand( const TDesC8& aCommands, @@ -855,7 +869,7 @@ * @param aAtCmdBase Base AT command which to add to support data * (base part without parameters) * @param aPluginUid Plugin's UID to find from plugin data - * @param aSupportType Support's type (M|P|S) + * @param aSupportType Support's type (M|P|O) * @param aCleanupInfo Cleanup information * @return None */ @@ -870,7 +884,7 @@ * @since S60 5.0 * @param aEntries Plugin entries for support * @param aEntryIndex Plugin index entry - * @param aSupportType Support's type (M|P|S) + * @param aSupportType Support's type (M|P|O) * @param aSearchHelper The search helper * @return Index to the added entry, KErrNotSupported otherwise */ @@ -893,26 +907,26 @@ TATExtOneCmdSupport& aOneCmdSupport ); /** - * Adds new primary plugin entry link from plugin support entry to plugin + * Adds new partial plugin entry link from plugin support entry to plugin * entry * * @since S60 5.0 * @return Index to the added entry, KErrNotSupported otherwise */ - TInt AddNewPrimaryMetadataEntryLinkL( + TInt AddNewPartialMetadataEntryLinkL( CArrayFixFlat* aEntries, TATExtSearchHelper& aSearchHelper, TATExtOneCmdSupport& aOneCmdSupport ); /** - * Adds new secondary plugin entry link from plugin support entry to plugin - * entry. Search starts from the front as there could be multiple S plugins + * Adds new observer plugin entry link from plugin support entry to plugin + * entry. Search starts from the front as there could be multiple O plugins * but only one or two M/P plugins. * * @since S60 5.0 * @return Index to the added entry, KErrNotSupported otherwise */ - TInt AddNewSecondaryMetadataEntryLinkL( + TInt AddNewObserverMetadataEntryLinkL( CArrayFixFlat* aEntries, TATExtSearchHelper& aSearchHelper, TATExtOneCmdSupport& aOneCmdSupport ); @@ -1054,56 +1068,50 @@ void CreateSelfReplyData( const RMessage2& aMessage ); /** - * Handles support when a master plugin is detected in the plugin data - * via support data's link (support for a full AT command). If a master - * plugin is detected then reply is detected from that plugin. No further - * sending to primary or secondary plugins is repformed. + * Handles support when a master or partial plugin is detected in the plugin + * data via support data's link. If a partial or master plugin is detected + * then reply is expected from that plugin. Also if one or more observer + * plugins are detected then no reply is expected from them. * * @since S60 5.0 - * @param aEntrySupport Support data to the first found master plugin - * @param aReplyExpected ETrue if reply is expected from the master plugin, - * EFalse if no reply is expected from the master plugin, + * @param aEntrySupport Support data to the first found partial or master plugin + * @param aStartIndex Start index to search the next observer plugin + * @param aReplyExpected ETrue if reply is expected from the partial or master plugin, + * EFalse if no reply is expected from the partial or master plugin, * (i.e. no support found) * @return ETrue if support found, EFalse otherwise */ - TBool HandleMasterPluginSupportL( TATExtEntrySupport& aEntrySupport, - TBool& aReplyExpected ); + TBool HandleMasterAndPartialPluginSupportL( + TATExtEntrySupport& aEntrySupport, + TInt aStartIndex, + TBool& aReplyExpected ); /** - * Handles support when a primary plugin is detect in the plugin data - * via support data's link. If a primary plugin is detected then reply is - * expected from that plugin. Also if one or more secondary plugins are - * detected then no reply is expected from them. - * - * @since S60 5.0 - * @param aEntrySupport Support data to the first found primary plugin - * @param aStartIndex Start index to search the next secondary plugin - * @param aReplyExpected ETrue if reply is expected from the primary plugin, - * EFalse if no reply is expected from the primary plugin, - * (i.e. no support found) - * @return ETrue if support found, EFalse otherwise - */ - TBool HandlePrimaryPluginSupportL( TATExtEntrySupport& aEntrySupport, - TInt aStartIndex, - TBool& aReplyExpected ); - - /** - * Handles support when a secondary plugin is detected in the plugin data - * via support data's link. If only one secondary plugin is detected then - * reply is expected from that plugin. Instead, if more than one secondary + * Handles support when a observer plugin is detected in the plugin data + * via support data's link. If only one observer plugin is detected then + * reply is expected from that plugin. Instead, if more than one observer * plugins are detected then no reply is expected from them. * * @since S60 5.0 - * @param aEntrySupport Support data to the first found secondary plugin + * @param aEntrySupport Support data to the first found observer plugin * entry - * @param aStartIndex Start index to search the next secondary plugin + * @param aStartIndex Start index to search the next observer plugin * @param aReplyExpected ETrue if reply is expected from one or more plugins, * EFalse if no reply is expected from any of the plugins * @return ETrue if support found, EFalse otherwise */ - TBool HandleSecondaryPluginSupportL( TATExtEntrySupport& aEntrySupport, - TInt aStartIndex, - TBool& aReplyExpected ); + TBool HandleObserverPluginSupportL( TATExtEntrySupport& aEntrySupport, + TInt aStartIndex, + TBool& aReplyExpected ); + + /** + * Finds exclusive partial plugin support + * + * @since S60 5.0 + * @param aEntrySupport Support data to the first found partial plugin entry + * @return ETrue if exclusive support found, EFalse otherwise + */ + TBool FindExclusivePartialSupportL( TATExtEntrySupport& aEntrySupport ); /** * Finds support entries from support data for a given base AT command @@ -1173,27 +1181,27 @@ const TDesC8* aAtCmdFull=NULL ); /** - * Sends an AT commands to multiple secondary plugins, starting from a + * Sends an AT commands to multiple observer plugins, starting from a * given position. * * @since S60 5.0 * @param aEntrySupport Entry support data to position from where to start - * sending to the found secondary plugins + * sending to the found observer plugins * @param aAtCmdFull Full AT command to send (base part + parameters) * @return None */ - void SendToMultipleSecondaryL( TATExtEntrySupport& aEntrySupport, + void SendToMultipleObserverL( TATExtEntrySupport& aEntrySupport, const TDesC8* aAtCmdFull ); /** - * Finds the first secondary plugin support from a given starting position + * Finds the first observer plugin support from a given starting position * * @since S60 5.0 * @param aEntrySupport Entry support data to the next entry after the found - * secondary plugin entry; marks the start for search + * observer plugin entry; marks the start for search * @return ETrue if support found, EFalse otherwise */ - TBool FindFirstSecondarySupportL( TATExtEntrySupport& aEntrySupport ); + TBool FindFirstObserverSupportL( TATExtEntrySupport& aEntrySupport ); /** * Extracts one NVRAM entry from a pipe-character delimited NVRAM buffer diff -r 29b1cd4cb562 -r b4a7eebaaebf atext/server/src/atextmetadata.cpp --- a/atext/server/src/atextmetadata.cpp Fri Jan 15 08:13:17 2010 +0200 +++ b/atext/server/src/atextmetadata.cpp Mon Jan 18 21:23:18 2010 +0200 @@ -21,21 +21,21 @@ * future needs: * * Three types of support: - * 1) Master (M): Does not send to S if support found. - * 2) Primary (P): Sends to all S if support found. - * 3) Secondary (S): Process the command and give or not give reply, based on + * 1) Master (M): Sends to all O if support found. Panics if > 1 M. + * 2) Partial (P): Sends to all O if support found. Replies "ERROR" if two P supports. + * 3) Observer (O): Process the command and give or not give reply, based on * the following logic: * - * => [If] M found, handle command and send reply, stop, [else] - * [If] P found, handle command and send reply + send to N S {no reply}, stop, [else] - * [If] > 1 S found, send to N S {no reply}, stop, [else] - * [If] only 1 S found, handle command and send reply, stop, [else] + * => [If] M found, handle command and send reply + send to N O {no reply}, stop, [else] + * [If] P found, handle command and send reply + send to N O {no reply}, stop, [else] + * [If] > 1 O found, send to N O {no reply}, stop, [else] + * [If] only 1 O found, handle command and send reply, stop, [else] * Write "ERROR" to client, complete message with KErrNone * * When incoming reply: * => If reply from M, write to client, stop, [else] * If reply from P, write to client, stop, [else] - * If reply from S and M, P nor other S exist, write to client, stop, [else] + * If reply from O and M, P nor other O exist, write to client, stop, [else] * Complete message with KErrNone and empty string * * Note: Empty string and "ERROR" string are managed already in HandleCommand() @@ -1359,14 +1359,17 @@ case 'm': aSupportType = ESupportTypeMaster; break; - case 'P': // Primary plugin + case 'P': // Partial plugin case 'p': - aSupportType = ESupportTypePrimary; + aSupportType = ESupportTypePartial; break; - case 'S': // Secondary plugin - case 's': - aSupportType = ESupportTypeSecondary; + case 'O': // Observer plugin + case 'o': + aSupportType = ESupportTypeObserver; break; + default: + _LIT( KPluginType, "PluginType" ); + User::Panic( KPluginType, EPanicCategoryPluginType ); } i++; if ( i >= count ) @@ -1519,18 +1522,18 @@ oneCmdSupport ); } break; - case ESupportTypePrimary: + case ESupportTypePartial: { - retVal = AddNewPrimaryMetadataEntryLinkL( aEntries, + retVal = AddNewPartialMetadataEntryLinkL( aEntries, aSearchHelper, oneCmdSupport ); } break; - case ESupportTypeSecondary: + case ESupportTypeObserver: { - retVal = AddNewSecondaryMetadataEntryLinkL( aEntries, - aSearchHelper, - oneCmdSupport ); + retVal = AddNewObserverMetadataEntryLinkL( aEntries, + aSearchHelper, + oneCmdSupport ); } break; default: @@ -1552,79 +1555,88 @@ TATExtOneCmdSupport& aOneCmdSupport ) { TRACE_FUNC_ENTRY + if ( aEntries->Count() > 0 ) + { + TATExtOneCmdSupport& oneCmdSupport = (*aEntries)[0]; + if ( oneCmdSupport.iSupportType == ESupportTypeMaster ) + { + _LIT( KFaultyMaster, "FaultyMaster" ); + User::Panic( KFaultyMaster, EPanicCategoryFaultyMaster ); + } + } aEntries->InsertL( 0, aOneCmdSupport ); - if ( aSearchHelper.iPrimaryIndex >= 0 ) + if ( aSearchHelper.iPartialIndex >= 0 ) { - aSearchHelper.iPrimaryIndex++; + aSearchHelper.iPartialIndex++; } - if ( aSearchHelper.iSecondaryIndex >= 0 ) + if ( aSearchHelper.iObserverIndex >= 0 ) { - aSearchHelper.iSecondaryIndex++; + aSearchHelper.iObserverIndex++; } TRACE_FUNC_EXIT return 0; } // --------------------------------------------------------------------------- -// Adds new primary plugin entry link from plugin support entry to plugin +// Adds new partial plugin entry link from plugin support entry to plugin // entry // --------------------------------------------------------------------------- // -TInt CATExtMetadata::AddNewPrimaryMetadataEntryLinkL( +TInt CATExtMetadata::AddNewPartialMetadataEntryLinkL( CArrayFixFlat* aEntries, TATExtSearchHelper& aSearchHelper, TATExtOneCmdSupport& aOneCmdSupport ) { TRACE_FUNC_ENTRY - TInt i = aSearchHelper.iPrimaryIndex; + TInt i = aSearchHelper.iPartialIndex; if ( i < 0 ) { TInt count = aEntries->Count(); for ( i=0; iInsertL( i, aOneCmdSupport ); - if ( aSearchHelper.iSecondaryIndex >= 0 ) + if ( aSearchHelper.iObserverIndex >= 0 ) { - aSearchHelper.iSecondaryIndex++; + aSearchHelper.iObserverIndex++; } TRACE_FUNC_EXIT return i; } // --------------------------------------------------------------------------- -// Adds new secondary plugin entry link from plugin support entry to plugin -// entry. Search starts from the front as there could be multiple S plugins +// Adds new observer plugin entry link from plugin support entry to plugin +// entry. Search starts from the front as there could be multiple O plugins // but only one or two M/P plugins. // --------------------------------------------------------------------------- // -TInt CATExtMetadata::AddNewSecondaryMetadataEntryLinkL( +TInt CATExtMetadata::AddNewObserverMetadataEntryLinkL( CArrayFixFlat* aEntries, TATExtSearchHelper& aSearchHelper, TATExtOneCmdSupport& aOneCmdSupport ) { TRACE_FUNC_ENTRY - TInt i = aSearchHelper.iSecondaryIndex; + TInt i = aSearchHelper.iObserverIndex; if ( i < 0 ) { TInt count = aEntries->Count(); for ( i=0; iInsertL( i, aOneCmdSupport ); TRACE_FUNC_EXIT @@ -1974,20 +1986,26 @@ entrySupport.iEntry = &(*iPluginData)[oneCmdSupport.iEntryIndex]; if ( oneCmdSupport.iSupportType == ESupportTypeMaster ) { - supported = HandleMasterPluginSupportL( - entrySupport, - aComplInfo.iReplyExpected ); - } - else if ( oneCmdSupport.iSupportType == ESupportTypePrimary ) - { - supported = HandlePrimaryPluginSupportL( + supported = HandleMasterAndPartialPluginSupportL( entrySupport, i+1, aComplInfo.iReplyExpected ); } - else if ( oneCmdSupport.iSupportType == ESupportTypeSecondary ) + else if ( oneCmdSupport.iSupportType == ESupportTypePartial ) { - supported = HandleSecondaryPluginSupportL( + supported = FindExclusivePartialSupportL( entrySupport ); + if ( !supported ) + { + break; + } + supported = HandleMasterAndPartialPluginSupportL( + entrySupport, + i+1, + aComplInfo.iReplyExpected ); + } + else if ( oneCmdSupport.iSupportType == ESupportTypeObserver ) + { + supported = HandleObserverPluginSupportL( entrySupport, i+1, aComplInfo.iReplyExpected ); @@ -2022,50 +2040,27 @@ } // --------------------------------------------------------------------------- -// Handles support when a master plugin is detected in the plugin data via -// support data's link (support for a full AT command). If a master plugin is -// detected then reply is detected from that plugin. No further sending to -// primary or secondary plugins is repformed. +// Handles support when a master or partial plugin is detected in the plugin +// data via support data's link. If a partial or master plugin is detected +// then reply is expected from that plugin. Also if one or more observer +// plugins are detected then no reply is expected from them. // --------------------------------------------------------------------------- // -TBool CATExtMetadata::HandleMasterPluginSupportL( - TATExtEntrySupport& aEntrySupport, - TBool& aReplyExpected ) - { - TRACE_FUNC_ENTRY - aReplyExpected = EFalse; - TBool supported = HandleCommandSupportL( aEntrySupport ); - if ( !supported ) - { - TRACE_FUNC_EXIT - return EFalse; - } - iCmdData.iReplyExpected = ETrue; // Set before HandleCommandL() - HandleCommandL( aEntrySupport, ETrue ); - aReplyExpected = ETrue; - TRACE_FUNC_EXIT - return ETrue; - } - -// --------------------------------------------------------------------------- -// Handles support when a primary plugin is detect in the plugin data via -// support data's link. If a primary plugin is detected then reply is expected -// from that plugin. Also if one or more secondary plugins are detected then -// no reply is expected from them. -// --------------------------------------------------------------------------- -// -TBool CATExtMetadata::HandlePrimaryPluginSupportL( +TBool CATExtMetadata::HandleMasterAndPartialPluginSupportL( TATExtEntrySupport& aEntrySupport, TInt aStartIndex, TBool& aReplyExpected ) { TRACE_FUNC_ENTRY aReplyExpected = EFalse; - TBool supported = HandleCommandSupportL( aEntrySupport ); - if ( !supported ) + if ( !aEntrySupport.iSupportFound ) { - TRACE_FUNC_EXIT - return EFalse; + TBool supported = HandleCommandSupportL( aEntrySupport ); + if ( !supported ) + { + TRACE_FUNC_EXIT + return EFalse; + } } // If HandleCommand() is implemented synchronously, the command must be // saved before executing as CompleteCommandMessage() closes the string @@ -2076,7 +2071,7 @@ iCmdData.iReplyExpected = ETrue; // Set before HandleCommandL() HandleCommandL( aEntrySupport, ETrue ); aEntrySupport.iStartIndex = aStartIndex; - SendToMultipleSecondaryL( aEntrySupport, atCmdFull ); + SendToMultipleObserverL( aEntrySupport, atCmdFull ); CleanupStack::PopAndDestroy( atCmdFull ); aReplyExpected = ETrue; TRACE_FUNC_EXIT @@ -2084,28 +2079,31 @@ } // --------------------------------------------------------------------------- -// Handles support when a secondary plugin is detected in the plugin data via -// support data's link. If only one secondary plugin is detected then reply is -// expected from that plugin. Instead, if more than one secondary plugins are +// Handles support when a observer plugin is detected in the plugin data via +// support data's link. If only one observer plugin is detected then reply is +// expected from that plugin. Instead, if more than one observer plugins are // detected then no reply is expected from them. // --------------------------------------------------------------------------- // -TBool CATExtMetadata::HandleSecondaryPluginSupportL( +TBool CATExtMetadata::HandleObserverPluginSupportL( TATExtEntrySupport& aEntrySupport, TInt aStartIndex, TBool& aReplyExpected ) { TRACE_FUNC_ENTRY aReplyExpected = EFalse; - TBool supported = HandleCommandSupportL( aEntrySupport ); - if ( !supported ) + if ( !aEntrySupport.iSupportFound ) { - TRACE_FUNC_EXIT - return EFalse; + TBool supported = HandleCommandSupportL( aEntrySupport ); + if ( !supported ) + { + TRACE_FUNC_EXIT + return EFalse; + } } TATExtEntrySupport nextSupport = aEntrySupport; nextSupport.iStartIndex = aStartIndex; - TBool entryFound = FindFirstSecondarySupportL( nextSupport ); + TBool entryFound = FindFirstObserverSupportL( nextSupport ); if ( entryFound ) { // Entry found; send all without reply request @@ -2116,7 +2114,7 @@ atCmdFullPtr.Copy( aEntrySupport.iAtCmdFull ); // Now execute the HandleCommand() HandleCommandL( aEntrySupport, EFalse ); - SendToMultipleSecondaryL( nextSupport, atCmdFull ); + SendToMultipleObserverL( nextSupport, atCmdFull ); CleanupStack::PopAndDestroy( atCmdFull ); } else @@ -2131,6 +2129,41 @@ } // --------------------------------------------------------------------------- +// Finds exclusive partial plugin support +// --------------------------------------------------------------------------- +// +TBool CATExtMetadata::FindExclusivePartialSupportL( + TATExtEntrySupport& aEntrySupport ) + { + TRACE_FUNC_ENTRY + TInt i; + TInt supports; + TInt count = aEntrySupport.iSupport->Count(); + for ( i=0,supports=0; iiPluginUid, aReplyNeeded )); @@ -2311,11 +2344,11 @@ } // --------------------------------------------------------------------------- -// Sends an AT commands to multiple secondary plugins, starting from a given +// Sends an AT commands to multiple observer plugins, starting from a given // position. // --------------------------------------------------------------------------- // -void CATExtMetadata::SendToMultipleSecondaryL( +void CATExtMetadata::SendToMultipleObserverL( TATExtEntrySupport& aEntrySupport, const TDesC8* aAtCmdFull ) { @@ -2330,25 +2363,34 @@ for ( i=aEntrySupport.iStartIndex; i #include #include +#include /** This class represents a QDP that is relevant for hardware that is perfect, @@ -37,69 +38,59 @@ public: static CHCISymbianQdp* NewL(); +private: // from CHCICmdQueueDecisionPlugin virtual TAny* Interface(TUid aUid); - // virtuals from MHCICmdQueueDecisionInterface +private: // virtuals from MHCICmdQueueDecisionInterface TBool MhcqdiDoesCommandRequireWorkaround(const CHCICommandQItem& aParent); - CHCICommandQItem* MhcqdiGetPreChildCommand(const CHCICommandQItem& aParent, const CHCICommandQItem* const aPreviousWorkaroundCmd, const THCIEventBase* const aPreviousCmdResult); - CHCICommandQItem* MhcqdiGetPostChildCommand(const CHCICommandQItem& aParent, const CHCICommandQItem* const aPreviousPostChild, const THCIEventBase* aPreviousCmdResult); - THCIEventBase* MhcqdiGetFakedUnsolicitedEvent(const CHCICommandQItem& aParent, const THCIEventBase* aPreviousFakedEvent); - void MhcqdiCommandAboutToBeDeleted(const CHCICommandQItem& aDyingCmd); - TInt MhcqdiCanSend(CHCICommandQItem& aCommand, const TDblQue& aSentCommands); - TUint MhcqdiTimeoutRequired(const CHCICommandQItem& aCmdAboutToBeSent); - void MhcqdiMatchedEventReceived(const THCIEventBase& aEvent, const CHCICommandQItem& aRelatedCommand); - TCommandErroredAction MhcqdiMatchedErrorEventReceived(const THCIEventBase& aErrorEvent, const CHCICommandQItem& aRelatedCommand); - void MhcqdiUnmatchedEventReceived(const THCIEventBase& aEvent); - TCommandTimedOutAction MhcqdiCommandTimedOut(const CHCICommandQItem& aCommand, const TDblQue& aSentCommands, TUint aCurrentCommandCredits, TUint& aCreditsToBeRefunded); - void MhcqdiSetPhysicalLinksState(const MPhysicalLinksState& aPhysicalLinkState); - void MhcqdiSetHardResetInitiator(const MHardResetInitiator& aHardResetInitiator); - void MhcqdiSetHCICommandQueue(MHCICommandQueue& aHCICommandQueue); - void MhcqdiSetTimeouts(TUint aQueueStarvationTimeout, TUint aMaxHciCommandTimeout); - TUint MhcqdiReset(); +private: // from MHCICmdQueueEventModifierInterface void MhcqemiMatchedEventReceived(THCIEventBase& aEvent, const CHCICommandQItem& aRelatedCommand); - void MhcqemiUnmatchedEventReceived(THCIEventBase& aEvent); +private: // from MHCICmdQueueUtilityUser void MhcquuSetUtilitiesProvider(MHCICmdQueueUtilities& aProvider); + private: // The initial number of command credits for the HCI Command Queue. const static TInt KHCIDefaultCmdCredits = 1; - // Workarounds for broken firmware - void FirmwareFixIgnoreErrorOnSetEventMaskForCasira(THCIEventBase& aEvent); - void FirmwareFixFakeCompletionEventsOnDisconnectionForBelkin(THCIEventBase& aEvent); - + // Workarounds for controller problems + void FixIgnoreInvalidHciParameterErrorOnSetEventMaskOnVersion1_1(THCIEventBase& aEvent); + void FixFakeCompletionEventsOnDisconnection(THCIEventBase& aEvent); + void FixAddConnectionHandleForTruncatedInvalidConnectionHandleErrorEvents(THCIEventBase& aEvent, const CHCICommandQItem* aRelatedCommand); + private: CHCISymbianQdp(); private: MHCICmdQueueUtilities* iProvider; TUint8 iHCIVersion; + TBuf8 iEventModBuffer; // utility buffer for the backend of modified/injected events }; #endif // HCISYMBIANQDP_H diff -r 29b1cd4cb562 -r b4a7eebaaebf bthci/hci2implementations/qdps/symbian/src/hcieventmodifiable.cpp --- a/bthci/hci2implementations/qdps/symbian/src/hcieventmodifiable.cpp Fri Jan 15 08:13:17 2010 +0200 +++ b/bthci/hci2implementations/qdps/symbian/src/hcieventmodifiable.cpp Mon Jan 18 21:23:18 2010 +0200 @@ -26,6 +26,11 @@ iErrorCode = aErrorCode; } +TPtrC8& THCIEventModifiable::EventData() + { + return iEventData; + } + THCIEventModifiable::THCIEventModifiable() : THCIEventBase(KNullDesC8) { diff -r 29b1cd4cb562 -r b4a7eebaaebf bthci/hci2implementations/qdps/symbian/src/hcisymbianqdp.cpp --- a/bthci/hci2implementations/qdps/symbian/src/hcisymbianqdp.cpp Fri Jan 15 08:13:17 2010 +0200 +++ b/bthci/hci2implementations/qdps/symbian/src/hcisymbianqdp.cpp Mon Jan 18 21:23:18 2010 +0200 @@ -30,12 +30,43 @@ #include #include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + #include #ifdef __FLOG_ACTIVE _LIT8(KLogComponent, LOG_COMPONENT_QDP_SYMBIAN); #endif +#ifdef _DEBUG +PANICCATEGORY("qdpsymbia"); +#endif // _DEBUG + +void AppendConnectionHandle(TDes8& aDes, THCIConnectionHandle aConnectionHandle) + { + LOG_STATIC_FUNC + THCIConnHandle connHandle = aConnectionHandle.ConnHandle(); + LOG1(_L8("Appending connection handle = 0x%04x"), connHandle); + TUint8 val[2] = {connHandle & 0xff, connHandle >> 8}; + aDes.Append(val, 2); + } + /*static*/ CHCISymbianQdp* CHCISymbianQdp::NewL() { LOG_STATIC_FUNC @@ -121,25 +152,28 @@ { LOG_FUNC - if (!aSentCommands.IsEmpty()) - { - // Def088959 - The following unhandled commands are blocked to avoid operational errors. - // Note: This workaround currently resides in this Symbian QDP, but may require further - // modification or placement depending on target hardware characteristics. This workaround - // may not be required for all controllers. - - THCIOpcode opcode=aSentCommands.Last()->Command().Opcode(); - if (opcode == KHoldModeOpcode || - opcode == KSniffModeOpcode || - opcode == KExitSniffModeOpcode || - opcode == KSwitchRoleOpcode || - opcode == KParkModeOpcode || - opcode == KExitParkModeOpcode) - { - return EBlock; - } - } - //otherwise allow command queue to proceed +#ifdef SERIAL_LOW_POWER_MODE_REQUESTS + if (!aSentCommands.IsEmpty()) + { + THCIOpcode opcode = aSentCommands.Last()->Command().Opcode(); + // The following commands are blocked to avoid ambiguity in matching mode change + // events. This ensures they are issued serially to the controller to prevent any confusion. + // Note: This workaround currently resides in this Symbian QDP, but may require further + // modification or placement depending on target hardware characteristics. This workaround + // may not be required for all controllers. + if(opcode == KHoldModeOpcode + || opcode == KSniffModeOpcode + || opcode == KExitSniffModeOpcode + || opcode == KSwitchRoleOpcode + || opcode == KParkModeOpcode + || opcode == KExitParkModeOpcode) + { + return EBlock; + } + } +#endif // SERIAL_LOW_POWER_MODE_REQUESTS + + // if no other issue then allow command queue to proceed return EContinue; } @@ -157,8 +191,8 @@ // Cache the HCI version number of the controller. This allows // us to ignore errors from specific versions of controllers - if ( aEvent.EventCode() == ECommandCompleteEvent - && THCICommandCompleteEvent::Cast(aEvent).CommandOpcode() == KReadLocalVersionInfoOpcode) + if(aEvent.EventCode() == ECommandCompleteEvent + && THCICommandCompleteEvent::Cast(aEvent).CommandOpcode() == KReadLocalVersionInfoOpcode) { const TReadLocalVersionInfoCompleteEvent& readLocalVersionCompleteEvent = TReadLocalVersionInfoCompleteEvent::Cast(aEvent); iHCIVersion = readLocalVersionCompleteEvent.Version(); @@ -169,14 +203,19 @@ { LOG_FUNC -#ifdef BROKEN_CASIRA_1_1 - FirmwareFixIgnoreErrorOnSetEventMaskForCasira(aEvent); -#endif // BROKEN_CASIRA_1_1 +#ifdef IGNORE_INVALID_HCI_PARAMETER_ERROR_ON_SET_EVENT_MASK_ON_VERSION_1_1 + FixIgnoreInvalidHciParameterErrorOnSetEventMaskOnVersion1_1(aEvent); +#endif // IGNORE_INVALID_HCI_PARAMETER_ERROR_ON_SET_EVENT_MASK_ON_VERSION_1_1 -#ifdef BROKEN_BELKIN_2_1 - FirmwareFixFakeCompletionEventsOnDisconnectionForBelkin(aEvent); -#endif // BROKEN_BELKIN_2_1 +#ifdef FAKE_COMPLETION_EVENTS_ON_DISCONNECTION + FixFakeCompletionEventsOnDisconnection(aEvent); +#endif // FAKE_COMPLETION_EVENTS_ON_DISCONNECTION +#ifdef ADD_CONNECTION_HANDLE_FOR_TRUNCATED_INVALID_CONNECTION_HANDLE_ERROR_EVENTS + FixAddConnectionHandleForTruncatedInvalidConnectionHandleErrorEvents(aEvent, &aRelatedCommand); +#endif // ADD_CONNECTION_HANDLE_FOR_TRUNCATED_INVALID_CONNECTION_HANDLE_ERROR_EVENTS + + // Don't forget to call the non-modifiable version of this function too MhcqdiMatchedEventReceived(aEvent, aRelatedCommand); } @@ -197,54 +236,171 @@ // Notification function. No need to do anything. } -void CHCISymbianQdp::FirmwareFixIgnoreErrorOnSetEventMaskForCasira(THCIEventBase& aEvent) +void CHCISymbianQdp::FixIgnoreInvalidHciParameterErrorOnSetEventMaskOnVersion1_1(THCIEventBase& aEvent) { LOG_FUNC - // Casiras with 1.1 firmware return an EInvalidHCIParameter error - // when SetEventMask is called. We still want to call SetEventMask but - // on this (old/buggy) firmware, ignore the returned EInvalidHCIParameter + // Some controllers supporting Bluetooth 1.1 return an EInvalidHCIParameter error + // when SetEventMask is called. We still want to call SetEventMask and catch any actual + // error in the stack (since it means that stack start up has failed). + // In this case, stack start-up is fine, just ignore the returned EInvalidHCIParameter - if ( aEvent.ErrorCode() == EInvalidHCIParameter - && aEvent.EventCode() == ECommandCompleteEvent - && KSetEventMaskOpcode == THCICommandCompleteEvent::Cast(aEvent).CommandOpcode() - && iHCIVersion == EHWHCIv1_1) + if(aEvent.ErrorCode() == EInvalidHCIParameter + && aEvent.EventCode() == ECommandCompleteEvent + && KSetEventMaskOpcode == THCICommandCompleteEvent::Cast(aEvent).CommandOpcode() + && iHCIVersion == EHWHCIv1_1) { - THCIEventBase& modevent = const_cast(aEvent); - THCIEventModifiable& event = reinterpret_cast(modevent); + LOG(_L8("Ignoring Invalid HCI Parameter error for Set Event Mask")); + THCIEventModifiable& event = static_cast(aEvent); event.SetErrorCode(EOK); } } -void CHCISymbianQdp::FirmwareFixFakeCompletionEventsOnDisconnectionForBelkin(THCIEventBase& aEvent) +void CHCISymbianQdp::FixFakeCompletionEventsOnDisconnection(THCIEventBase& aEvent) { LOG_FUNC - // For Belkin 2.1 controllers, if we receive a "Disconnection Complete Event" - // then look for a "Authentication Requested" command or "Read Clock Offset" on - // the sent queue, and if found, then fake up an completion event (with reason - // code copied from the Disconnection Complete Event) and inject this into the - // queue. This is because the Belkin 2.1 controllers fail to send a completion - // event for "Read Clock Offset" and "Request Authentication" (and maybe others) - // themselves (i.e. these are firmware bugs we're working around) + // Some controllers fail to follow the HCI specification w.r.t. events on disconnection. + // The specification indicates outstanding data on a connection handle to be considered + // removed when a disconnection occurs. Events however are not guarded by such text + // and should always be returned (with an appropriate error code). + // The command queue expects these events (as it is programmed to the spec) so if a + // controller fails to perform the task, we have to make up the shortfall. Currently + // the following events are the ones that fail to be generated in the controllers. + // This issue has been observed with: + // + // * Authentication_Complete + // * Read_Clock_Offset - if (aEvent.EventCode() == EDisconnectionCompleteEvent && iHCIVersion == EHWHCIv2_1) + if(aEvent.EventCode() == EDisconnectionCompleteEvent) { const TDisconnectionCompleteEvent& disconnEvent = TDisconnectionCompleteEvent::Cast(aEvent); THCIConnectionHandle handle = disconnEvent.ConnectionHandle(); THCIErrorCode reason = static_cast(disconnEvent.Reason()); - if (iProvider->FindOutstandingCommand(KAuthenticationRequestedOpcode) != NULL) + if(iProvider->FindOutstandingCommand(KAuthenticationRequestedOpcode)) { - TBuf8 eventBuf1; - TAuthenticationCompleteEvent authenticationCompleteEvent(reason, handle, eventBuf1); + LOG(_L8("Injecting Authentication Complete Event")); + TAuthenticationCompleteEvent authenticationCompleteEvent(reason, handle, iEventModBuffer); iProvider->InjectEvent(authenticationCompleteEvent); } - if (iProvider->FindOutstandingCommand(KReadClockOffsetOpcode) != NULL) + if(iProvider->FindOutstandingCommand(KReadClockOffsetOpcode)) + { + LOG(_L8("Injecting Read Clock Offset Complete Event")); + THCIClockOffset clockOffset = 0; + TReadClockOffsetEvent readClockOffsetEvent(reason, handle, clockOffset, iEventModBuffer); + iProvider->InjectEvent(readClockOffsetEvent); + } + } + } + +/** +Utility template class for FixAddConnectionHandleForTruncatedInvalidConnectionHandleErrorEvents function. +*/ +template +struct AttemptToFixCommandCompleteEvent + { + static void CheckAndFix(THCICommandCompleteEvent& aEvent, const CHCICommandQItem* aRelatedCommand, TDes8& aNewBuffer, TInt aCorrectSize, TInt aExpectedSizeMissing) + { + LOG_STATIC_FUNC + THCIEventModifiable& event = static_cast(static_cast(aEvent)); + // Check to see if the data is truncated - only apply the fix if it is + if(event.EventData().Length() == (aCorrectSize-aExpectedSizeMissing)) { - TBuf8 eventBuf2; - THCIClockOffset clockOffset = 0; - TReadClockOffsetEvent readClockOffsetEvent(reason, handle, clockOffset, eventBuf2); - iProvider->InjectEvent(readClockOffsetEvent); + // This is actually a best effort guess that the connection handle is missing. Fixing this isn't simple because + // we need a bigger buffer than we may have - so we have to create our own backing buffer for the event. + LOG1(_L8("Modifying Command Complete event (opcode = 0x%04x) to add Connection Handle"), aEvent.CommandOpcode()); + aNewBuffer.FillZ(aCorrectSize); // ensure buffer is clean + aNewBuffer.Copy(event.EventData()); + if(aRelatedCommand) + { + const XCommandCompleteCommandClass& cmd = static_cast(aRelatedCommand->Command()); + AppendConnectionHandle(aNewBuffer, cmd.ConnectionHandle()); + } + else + { + // we have no connection handle to insert in, so pick one that can + // never be valid. + AppendConnectionHandle(aNewBuffer, KInvalidConnectionHandle); + } + aNewBuffer.SetLength(aCorrectSize); + event.EventData().Set(aNewBuffer); // update event to point to new buffer + } + // Ensure that now the event is correct. + ASSERT_DEBUG(event.EventData().Length() == aCorrectSize); + } + }; + +void CHCISymbianQdp::FixAddConnectionHandleForTruncatedInvalidConnectionHandleErrorEvents(THCIEventBase& aEvent, const CHCICommandQItem* aRelatedCommand) + { + LOG_FUNC + // Some controllers do not follow the HCI specification in that they do not always return + // an event of the correct size - in this case controllers omit a connection handle field when + // erroring with "invalid connection handle" error code. One can argue about this but the + // command queue is designed with the spec in mind so just adjust the events as appropriate. + // + // Notably command complete events are the events with issues; if a command status is used + // then the error code is communicated without any other parameters, and the resulting events will + // not generally be generated (see FixFakeCompletionEventsOnDisconnection). + // Current events that have observed (^) this issue (or could potentially have this issue (*)) are: + // + // ^ Command_Complete (Write_Link_Policy_Settings) + // ^ Command_Complete (Read_Link_Policy_Settings) + // * Command_Complete (Read_LMP_Handle) + // ^ Command_Complete (Role_Discovery) + // ^ Command_Complete (Sniff_Subrating) + // * Command_Complete (Flush) + // * Command_Complete (Read_Auto_Flush_Timeout) + // * Command_Complete (Write_Auto_Flush_Timeout) + // * Command_Complete (Read_Transmit_Power_Level) + // * Command_Complete (Read_Link_Supervision_Timeout) + // * Command_Complete (Write_Link_Supervision_Timeout) + // * Command_Complete (Read_Failed_Contact_Counter) + // * Command_Complete (Reset_Failed_Contact_Counter) + // * Command_Complete (Read_Link_Quality) + // * Command_Complete (Read_RSSI) + // * Command_Complete (Read_AFH_Channel_Map) + // * Command_Complete (Read_Clock) + // + // Only those actually observed as issues are included - the others are commented out for reference + + if(aEvent.ErrorCode() == ENoConnection) + { + if(aEvent.EventCode() == ECommandCompleteEvent) + { + THCICommandCompleteEvent& completeEvent = THCICommandCompleteEvent::Cast(aEvent); + // Macro to make the code more concise + #define _CHECK_AND_FIX(_COMMAND_NAME, _CORRECT_SIZE, _MISSING_SIZE) \ + case K##_COMMAND_NAME##Opcode:\ + AttemptToFixCommandCompleteEvent::CheckAndFix(completeEvent, aRelatedCommand, iEventModBuffer, (_CORRECT_SIZE), (_MISSING_SIZE));\ + break + switch(completeEvent.CommandOpcode()) + { + _CHECK_AND_FIX(WriteLinkPolicySettings, 8, sizeof(THCIConnHandle)); + _CHECK_AND_FIX(ReadLinkPolicySettings, 10, sizeof(THCIConnHandle) + sizeof(TUint16)); + _CHECK_AND_FIX(RoleDiscovery, 9, sizeof(THCIConnHandle) + sizeof(TUint8)); + _CHECK_AND_FIX(SniffSubrating, 8, sizeof(THCIConnHandle)); + + // These below are included as they potentially could have the same problem, + // however in practice this issue has not been observed. + // _CHECK_AND_FIX(ReadLMPHandle, 13, sizeof(THCIConnHandle) + sizeof(TUint8) + sizeof(TUint32)); + // _CHECK_AND_FIX(Flush, 8, sizeof(THCIConnHandle) + sizeof(TUint8) + sizeof(TUint32)); + // _CHECK_AND_FIX(ReadAutomaticFlushTimeout, 10, sizeof(THCIConnHandle) + sizeof(TUint16)); + // _CHECK_AND_FIX(WriteAutomaticFlushTimeout, 8, sizeof(THCIConnHandle)); + // _CHECK_AND_FIX(ReadTransmitPowerLevel, 9, sizeof(THCIConnHandle) + sizeof(TUint8)); + // _CHECK_AND_FIX(ReadLinkSupervisionTimeout, 10, sizeof(THCIConnHandle) + sizeof(TUint16)); + // _CHECK_AND_FIX(WriteLinkSupervisionTimeout, 8, sizeof(THCIConnHandle)); + // _CHECK_AND_FIX(ReadFailedContactCounter, 10, sizeof(THCIConnHandle) + sizeof(TUint16)); + // _CHECK_AND_FIX(ResetFailedContactCounter, 8, sizeof(THCIConnHandle)); + // _CHECK_AND_FIX(ReadLinkQuality, 9, sizeof(THCIConnHandle)); + // _CHECK_AND_FIX(ReadRSSI, 9, sizeof(THCIConnHandle) + sizeof(TUint8)); + // _CHECK_AND_FIX(ReadAFHChannelMap, 19, sizeof(THCIConnHandle) + sizeof(TUint8) + 10); + // _CHECK_AND_FIX(ReadClock, 14, sizeof(THCIConnHandle) + sizeof(TUint32) + sizeof(TUint16)); + + default: + // just ignore + break; + } + #undef _CHECK_AND_FIX } } } @@ -253,9 +409,9 @@ { LOG_FUNC -#ifdef BROKEN_BELKIN_2_1 - FirmwareFixFakeCompletionEventsOnDisconnectionForBelkin(aEvent); -#endif // BROKEN_BELKIN_2_1 +#ifdef FAKE_COMPLETION_EVENTS_ON_DISCONNECTION + FixFakeCompletionEventsOnDisconnection(aEvent); +#endif // FAKE_COMPLETION_EVENTS_ON_DISCONNECTION MhcqdiUnmatchedEventReceived(aEvent); } @@ -288,7 +444,7 @@ } void CHCISymbianQdp::MhcqdiSetTimeouts(TUint /*aQueueStarvationTimeout*/, - TUint /*aMaxHciCommandTimeout*/) + TUint /*aMaxHciCommandTimeout*/) { LOG_FUNC } diff -r 29b1cd4cb562 -r b4a7eebaaebf layers.sysdef.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/layers.sysdef.xml Mon Jan 18 21:23:18 2010 +0200 @@ -0,0 +1,14 @@ + + +]> + + + + + + + + + + diff -r 29b1cd4cb562 -r b4a7eebaaebf package_definition.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/package_definition.xml Mon Jan 18 21:23:18 2010 +0200 @@ -0,0 +1,82 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff -r 29b1cd4cb562 -r b4a7eebaaebf sysdef_1_4_0.dtd --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sysdef_1_4_0.dtd Mon Jan 18 21:23:18 2010 +0200 @@ -0,0 +1,86 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +