connectivitylayer/isce/isirouter_dll/src/isiuserchannel.cpp
changeset 0 63b37f68c1ce
child 9 8486d82aef45
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/connectivitylayer/isce/isirouter_dll/src/isiuserchannel.cpp	Fri Nov 06 17:28:23 2009 +0000
@@ -0,0 +1,594 @@
+/*
+* 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: 
+*
+*/
+
+
+
+#include <kern_priv.h>              // For DMutex
+#include "isiuserchannel.h"         // For DISIUserChanneel
+#include "isiroutertrace.h"         // For C_TRACE, ASSERT_RESET.. and fault codes
+#include "misichannelrouterif.h"    // For MISIChannelRouterIf
+#include "memapi.h"                 // For MemApi
+#include "isimsgqueue.h"            // For DISIMsgQueue
+
+const TInt KFirstParam( 0 );
+const TInt KSecondParam( 1 );
+const TInt KThirdParam( 2 );
+const TInt KNoParams( 0 );
+const TInt KOneParam( 1 );
+const TInt KTwoParams( 2 );
+const TInt KThreeParams( 3 );
+const TInt KFirstRequest( 0 );
+const TInt KDestStartOffset( 0 );
+
+enum TISIUserChannelFaults
+    {
+    EISIUserChannelMemAllocFail = 0x01,
+    EISIUserChannelMemAllocFail1,
+    EISIUserChannelMemAllocFail2,
+    EISIUserChannelMemAllocFail3,
+    EISIUserChannelWrongRequest,
+    EISIUserChannelWrongRequest1,
+    EISIUserChannelWrongRequest2,
+    EISIUserChannelWrongRequest3,
+    EISIUserChannelWrongRequest4,
+    EISIUserChannelWrongRequest5,
+    EISIUserChannelWrongRequest6,
+    EISIUserChannelReqOverTheLimits,
+    EISIUserChannelDesWriteFailed,
+    EISIUserChannelSameRequest,
+    EISIUserChannelNullParam,
+    EISIUserChannelNullParam2,
+    EISIUserChannelDesReadFailed,
+    EISIUserChannelfNotThreadContext,
+    EISIUserChannelfNotThreadContext2,
+    EISIUserChannelfNotThreadContext3,
+    EISIUserChannelfNotThreadContext4,
+    EISIUserChannelfNotThreadContext5,
+    };
+
+const TInt KISILddEmptyRxQueuePriori( 1 );
+const TInt KISILddCompleteRequestPriori( 1 );
+
+
+// user<> kernel interaction() done in LDD DFC thread
+// 
+// kernel<>kernel interaction() done in Extension DFC thread
+//
+// DEMAND_PAGING
+// Receive (write k>u) is done only in LDD thread context to allow Extension thread to continue when dp swaps.
+// Send ((write u>k) is not done at the moment in LDD thread context only. Check is it possible to happend (not to be in usable memory after send (unlikely?)).
+
+DISIUserChannel::DISIUserChannel(
+        // None
+        ) : iThread( &Kern::CurrentThread()),
+            iObjId( KNotInitializedId ),
+            iUID( KNotInitializedUID )
+    {
+    C_TRACE( ( _T( "DISIUserChannel::DISIUserChannel>" ) ) );
+    iRouterIf = MISIChannelRouterIf::GetIf();
+    ASSERT_RESET_ALWAYS( iRouterIf, ( EISIUserChannelMemAllocFail | EDISIUserChannelTraceId << KClassIdentifierShift ) );
+    iCompletionThread = iRouterIf->GetDfcThread( MISIChannelRouterIf::EISIUserRequestCompletionThread );
+    iEmptyRxQueueDfc = new TDfc( EmptyRxQueueDfc, this, iCompletionThread, KISILddEmptyRxQueuePriori );
+    ASSERT_RESET_ALWAYS( iEmptyRxQueueDfc, ( EISIUserChannelMemAllocFail2 | EDISIUserChannelTraceId << KClassIdentifierShift ) );
+    iCompleteChannelRequestDfc = new TDfc( CompleteChannelRequestDfc, this, iCompletionThread, KISILddCompleteRequestPriori );
+    ASSERT_RESET_ALWAYS( iCompleteChannelRequestDfc, ( EISIUserChannelMemAllocFail3 | EDISIUserChannelTraceId << KClassIdentifierShift ) );
+    iRequests = new DISIUserAsyncRequests( EISILastAsyncRequest );   
+    C_TRACE( ( _T( "DISIUserChannel::DISIUserChannel<" ) ) );
+    }
+
+DISIUserChannel::~DISIUserChannel(
+        // None
+        )
+    {
+    C_TRACE( ( _T( "DISIUserChannel::~DISIUserChannel 0x%x>" ), this ) );
+     // owned starts
+    if( iEmptyRxQueueDfc )
+        {
+        C_TRACE( ( _T( "DISIUserChannel::~DISIUserChannel 0x%x 0x%x iEmptyRxQueueDfc 0x%x" ), this, iObjId, iEmptyRxQueueDfc ) );
+        iEmptyRxQueueDfc->Cancel();
+        delete iEmptyRxQueueDfc;
+        iEmptyRxQueueDfc = NULL;
+        }
+    if( iCompleteChannelRequestDfc )
+        {
+        C_TRACE( ( _T( "DISIUserChannel::~DISIUserChannel 0x%x 0x%x iCompleteChannelRequestDfc 0x%x" ), this, iObjId, iCompleteChannelRequestDfc ) );
+        iCompleteChannelRequestDfc->Cancel();
+        delete iCompleteChannelRequestDfc;
+        iCompleteChannelRequestDfc = NULL;
+        }
+    if( iRx )
+        {
+        C_TRACE( ( _T( "DISIUserChannel::~DISIUserChannel 0x%x 0x%x iRx 0x%x" ), this, iObjId, iRx ) );
+        delete iRx;
+        iRx = NULL;
+        }
+    if( iReceiveBufPtr )
+        {
+        C_TRACE( ( _T( "DISIUserChannel::~DISIUserChannel 0x%x 0x%x iReceiveBufPtr 0x%x" ), this, iObjId, iReceiveBufPtr ) );
+        iReceiveBufPtr = NULL;
+        }
+    if( iRequests )
+        {
+        delete iRequests;
+        iRequests = NULL;
+        }
+    // owned ends
+    iRouterIf = NULL;
+    Kern::SafeClose( reinterpret_cast<DObject*&>(iThread), NULL );    
+    C_TRACE( ( _T( "DISIUserChannel::~DISIUserChannel 0x%x<" ), this ) );
+    }
+
+/*
+* Executed in user thread context thread inside CS, cannot be pre-empted.
+* Channel can not be used before creation, so no need to synch if congesting only btw the creating user thread and one thread.
+*/    
+TInt DISIUserChannel::DoCreate(
+        TInt, //aUnit,              // Not used at the moment
+        const TDesC8*, //anInfo,    // Not used at the moment.
+        const TVersion& // aVer     // Not used at the moment.
+        )
+    {
+    C_TRACE( ( _T( "DISIUserChannel::DoCreate 0x%x 0x%x>" ), this, iObjId ) );
+    if( !Kern::CurrentThreadHasCapability( ECapabilityCommDD, __PLATSEC_DIAGNOSTIC_STRING( "Check by: ISI Router" ) ) ) return KErrPermissionDenied;
+    iRx = new DISIMsgQueue( KISILddRxQueueSize );
+    ASSERT_RESET_ALWAYS( iRx, ( EISIUserChannelMemAllocFail1 | EDISIUserChannelTraceId << KClassIdentifierShift ) );
+    // Other DFC functions handling user<>kernel copying done in ldd DFC. Ldd DFC function priority is 1.
+    iMainThread = iRouterIf->GetDfcThread( MISIChannelRouterIf::EISIUserMainThread );
+    SetDfcQ( iMainThread );
+    iMsgQ.Receive();
+    DObject* thread = reinterpret_cast<DObject*>( iThread );
+    // Open is needed to increase ref count to calling thread that is decreased in Kern::SafeClose
+    // Possible returns KErrNone ? KErrGeneral
+    TInt threadOpen( thread->Open() );
+    TRACE_ASSERT_INFO( threadOpen == KErrNone, iObjId );
+    C_TRACE( ( _T( "DISIUserChannel::DoCreate 0x%x 0x%x<" ), this, iObjId ) );
+    return threadOpen;
+    }
+
+void DISIUserChannel::HandleMsg(
+        TMessageBase* aMsg
+        )
+    {
+    C_TRACE( ( _T( "DISIUserChannel::HandleMsg 0x%x 0x%x 0x%x>" ), this, aMsg, iObjId ) );
+    TThreadMessage& m= *( static_cast< TThreadMessage* >( aMsg ) );
+    TInt id( m.iValue );
+    if( static_cast<TInt>( ECloseMsg ) == id )
+        {
+        C_TRACE( ( _T( "DISIUserChannel::HandleMsg ECloseMsg 0x%x 0x%x" ), this, aMsg ) );
+        m.Complete( HandleSyncRequest( EISIDisconnect, NULL ), EFalse );
+        }
+    else if( KMaxTInt == id )
+        {
+        C_TRACE( ( _T( "DISIUserChannel::HandleMsg cancel 0x%x 0x%x" ), this, aMsg ) );
+        DoCancel( id, m.Int0() );
+        m.Complete( KErrNone, ETrue );
+        }
+    else
+        {
+        ASSERT_RESET_ALWAYS( ( KErrNotFound < id ), ( EISIUserChannelWrongRequest | EDISIUserChannelTraceId << KClassIdentifierShift ) );
+        C_TRACE( ( _T( "DISIUserChannel::HandleMsg request 0x%x %d 0x%x" ), this, id, aMsg ) );
+        TInt completeValue( KErrNone );
+        TInt ulen( KErrNotFound );
+        switch ( id )
+            {
+            case EISIDisconnect:
+                {
+                ulen = KNoParams;
+                break;
+                }
+            case EISISend:
+                {
+                ulen = KOneParam;
+                break;
+                }
+            case EISIConnect:
+                {
+                ulen = KTwoParams;
+                break;
+                }
+            case EISIAsyncReceive:
+                {
+                ulen = KThreeParams;
+                break;
+                }
+            default:
+                {
+                ASSERT_RESET_ALWAYS( 0, ( EISIUserChannelWrongRequest1 | EDISIUserChannelTraceId << KClassIdentifierShift ) );
+                break;
+                }
+            }
+        TUint32* table[ KThreeParams ];
+        completeValue = Kern::ThreadRawRead( iThread, m.Ptr0(), table, ulen * sizeof( TAny* ) );
+        
+        if( completeValue == KErrNone )
+            {
+            switch( id )
+                {
+                // All asynchronous requests.
+                case EISIAsyncReceive:
+                    {
+                    // No need to check return value in async functions, completed to user
+                    HandleAsyncRequest( id, table );
+                    break;
+                    }
+                case EISIDisconnect:
+                case EISIConnect:
+                case EISISend:
+                    {
+                    completeValue = HandleSyncRequest( id, table );
+                    break;
+                    }
+                default:
+                    {
+                    ASSERT_RESET_ALWAYS( 0, ( EISIUserChannelWrongRequest2 | EDISIUserChannelTraceId << KClassIdentifierShift ) );
+                    break;
+                    }
+                }
+            }
+        m.Complete( completeValue, ETrue );
+        }
+    C_TRACE( ( _T( "DISIUserChannel::HandleMsg 0x%x 0x%x 0x%x<" ), this, aMsg, iObjId ) );
+    }
+
+TInt DISIUserChannel::Request(
+        TInt aReqNo,
+        TAny* a1,
+        TAny* //a2
+        )
+    {
+    C_TRACE( ( _T( "DISIUserChannel::Request 0x%x %d 0x%x 0x%x>" ), this, aReqNo, a1, iObjId ) );
+    // Programmer errors.
+    ASSERT_RESET_ALWAYS( aReqNo >= ( TInt ) EMinRequestId, ( EISIUserChannelWrongRequest3 | EDISIUserChannelTraceId << KClassIdentifierShift ) );
+    ASSERT_RESET_ALWAYS( ( aReqNo <= EISILastAsyncRequest || aReqNo == KMaxTInt ), ( EISIUserChannelWrongRequest4 | EDISIUserChannelTraceId << KClassIdentifierShift ) );
+    // Wrong API usage e.g. called function when interface is not open so panic the client thread.
+    TInt result( KErrNotFound );
+    // All request go in kernel context and with ::DoControl call.
+    TThreadMessage& m=Kern::Message();
+    m.iValue = aReqNo;
+    m.iArg[ KFirstParam ] = a1;
+    m.iArg[ KSecondParam ] = NULL;
+    result = m.SendReceive( &iMsgQ );
+    C_TRACE( ( _T( "DISIUserChannel::Request 0x%x %d 0x%x<" ), this, aReqNo, a1, iObjId ) );
+    return result;
+    }
+
+TInt DISIUserChannel::HandleSyncRequest(
+        TInt aRequest,
+        TAny* a1
+        )
+    {
+    C_TRACE( ( _T( "DISIUserChannel::HandleSyncRequest 0x%x %d 0x%x 0x%x>" ), this, aRequest, a1, iObjId ) );
+    ASSERT_THREAD_CONTEXT_ALWAYS( ( EISIUserChannelfNotThreadContext5 | EDISIUserChannelTraceId << KClassIdentifierShift ) );
+    TInt error( KErrNotSupported );
+    switch( aRequest )
+        {
+        case EISIDisconnect:
+            {
+            C_TRACE( ( _T( "DISIUserChannel::HandleSyncRequest 0x%x EISIDisconnect" ), this ) );
+            Disconnect();
+            error = KErrNone;
+            break;
+            }
+        case EISISend:
+            {
+            C_TRACE( ( _T( "DISIUserChannel::HandleSyncRequest 0x%x EISISend" ), this ) );
+            TUint32* tablePtr = reinterpret_cast<TUint32*>( a1 );
+            TAny* firstParam = reinterpret_cast<TAny*>( tablePtr[ KFirstParam ] );
+            TRACE_ASSERT_INFO( firstParam, ( iObjId << KObjIdShift | ( EISIUserChannelNullParam2 | EDISIUserChannelTraceId << KClassIdentifierShift ) ) );
+            TInt msgLength( Kern::ThreadGetDesLength( iThread, firstParam ) );
+            C_TRACE( ( _T( "DISIUserChannel::HandleSyncRequest 0x%x EISISend 0x%x %d" ), this, firstParam, msgLength ) );
+            if( msgLength > 0 && msgLength < KMaxISIMsgSize )
+                {
+                TDes8& sendBlock = MemApi::AllocBlock( msgLength );
+                ASSERT_RESET_ALWAYS( KErrNone == Kern::ThreadDesRead( iThread, firstParam, sendBlock, 0, KChunkShiftBy0 ), ( EISIUserChannelDesReadFailed | EDISIUserChannelTraceId << KClassIdentifierShift ) );
+                TRACE_ASSERT_INFO( sendBlock.Length() == msgLength, iObjId << KObjIdShift );
+                C_TRACE( ( _T( "DISIUserChannel::HandleAsyncRequest EISISend 0x%x 0x%x" ), this, &sendBlock ) );
+                error = iRouterIf->Send( sendBlock, iObjId );
+                }
+            else
+                {
+                error = ( msgLength > KMaxISIMsgSize ) ? KErrNoMemory : KErrBadDescriptor;
+                TRACE_ASSERT_INFO( 0, iObjId << KObjIdShift | (TUint16)msgLength );
+                }
+            break;
+            }
+        case EISIConnect:
+            {
+            TUint32* tablePtr = reinterpret_cast<TUint32*>( a1 );
+            iUID = tablePtr[ KFirstParam ];
+            TUint8* objIdPtr = reinterpret_cast<TUint8*>( tablePtr[ KSecondParam ] );
+            C_TRACE( ( _T( "DISIUserChannel::HandleSyncRequest EISIConnect 0x%x 0x%x 0x%x" ), this, iUID, objIdPtr ) );
+            iRouterIf->Connect( iUID, iObjId, this );
+            C_TRACE( ( _T( "DISIUserChannel::HandleSyncRequest received iObjId is 0x%x" ), iObjId ) );
+            ASSERT_RESET_ALWAYS( KErrNone == Kern::ThreadRawWrite( iThread, objIdPtr, &iObjId, sizeof(TUint8), iThread ), 
+                                   EISIUserChannelDesWriteFailed | iObjId << KObjIdShift | EDISIUserChannelTraceId << KClassIdentifierShift );
+            error = KErrNone;
+            break;            
+            }
+        default:
+            {
+            ASSERT_RESET_ALWAYS( 0, ( EISIUserChannelWrongRequest5 | EDISIUserChannelTraceId << KClassIdentifierShift ) );
+            break;
+            }
+        }
+    C_TRACE( ( _T( "DISIUserChannel::HandleSyncRequest 0x%x %d 0x%x 0x%x<" ), this, aRequest, a1, iObjId ) );
+    return error;
+    }
+
+void DISIUserChannel::HandleAsyncRequest(
+        TInt aRequest,
+        TAny* a1
+        )
+    {
+    C_TRACE( ( _T( "DISIUserChannel::HandleAsyncRequest 0x%x %d 0x%x 0x%x>" ), this, aRequest, a1, iObjId ) );
+    
+    ASSERT_THREAD_CONTEXT_ALWAYS( ( EISIUserChannelfNotThreadContext4 | EDISIUserChannelTraceId << KClassIdentifierShift ) );
+    TUint32* tablePtr = reinterpret_cast<TUint32*>( a1 );
+    TRACE_ASSERT_INFO( tablePtr[ KFirstParam ], (TUint16)aRequest );
+    TRequestStatus* requestStatus = reinterpret_cast<TRequestStatus*>( tablePtr[ KFirstParam ] );
+    if( iRequests->IsPending( aRequest ) )
+        {
+        C_TRACE( ( _T( "DISIUserChannel::HandleAsyncRequest existing 0x%x request 0x%x" ), this, aRequest ) );
+        // Should not give same request object twice before completing the first one.
+        ASSERT_RESET_ALWAYS( 0, ( EISIUserChannelSameRequest | iObjId << KObjIdShift | static_cast<TUint8>( aRequest ) << KExtraInfoShift ) );
+        }
+    else
+        {
+        C_TRACE( ( _T( "DISIUserChannel::HandleAsyncRequest 0x%x handling %d" ), this, aRequest ) );
+        iRequests->SetPending( aRequest, requestStatus );
+        switch( aRequest )
+            {
+            case EISIAsyncReceive:
+                {
+                iReceiveBufPtr = reinterpret_cast<TAny*>( tablePtr[ KSecondParam ] );
+                iNeededBufLen = reinterpret_cast<TUint16*>( tablePtr[ KThirdParam ] );
+                C_TRACE( ( _T( "DISIUserChannel::HandleAsyncRequest 0x%x EISIAsyncReceive 0x%x" ), this, iReceiveBufPtr ) );
+                iEmptyRxQueueDfc->Enque();
+                break;
+                }
+            default:
+                {
+                ASSERT_RESET_ALWAYS( 0, ( EISIUserChannelWrongRequest2 | EDISIUserChannelTraceId << KClassIdentifierShift ) );
+                break;
+                }
+            }
+        }
+    C_TRACE( ( _T( "DISIUserChannel::HandleAsyncRequest 0x%x %d 0x%x 0x%x<" ), this, aRequest, a1, iObjId ) );
+    }
+    	
+
+void DISIUserChannel::DoCancel(
+        TInt aRequest,
+        TInt aMask )
+    {
+    C_TRACE( ( _T( "DISIUserChannel::DoCancel 0x%x %d 0x%x 0x%x>" ), this, aRequest, aMask, iObjId ) );
+    switch( aMask&aRequest )
+        {
+        case EISIAsyncReceive:
+            {
+            C_TRACE( ( _T( "DISIUserChannel::DoCancel 0x%x EISIAsyncReceive 0x%x " ), this, iReceiveBufPtr ) );
+            iReceiveBufPtr = NULL;
+            break;
+            }
+        default:
+            {
+            ASSERT_RESET_ALWAYS( 0, ( EISIUserChannelWrongRequest6 | EDISIUserChannelTraceId << KClassIdentifierShift ) );
+            break;
+            }
+        }
+    EnqueChannelRequestCompleteDfc( aMask&aRequest, KErrCancel );
+    C_TRACE( ( _T( "DISIUserChannel::DoCancel 0x%x %d 0x%x 0x%x<" ), this, aRequest, aMask, iObjId ) );
+    }
+    	
+
+void DISIUserChannel::Disconnect(
+        // None
+        )
+    {
+    C_TRACE( ( _T( "DISIUserChannel::Disconnect 0x%x 0x%x>" ), this, iObjId ) );
+    ResetQueues();
+    for( TInt i( 0 ); i < iRequests->iRequestCompletedList.Count(); ++i )
+        {
+        C_TRACE( ( _T( "DISIUserChannel::CancelRequests req to cancel %d" ), i ) );
+        DoCancel( KMaxTInt, i );
+        }
+    iRouterIf->Disconnect( iObjId );
+    iRouterIf->FreeDfcThread( iMainThread );
+    iRouterIf->FreeDfcThread( iCompletionThread );    
+    C_TRACE( ( _T( "DISIUserChannel::Disconnect 0x%x 0x%x<" ), this, iObjId ) );
+    }
+
+void DISIUserChannel::ResetQueues(
+        // None
+        )
+    {
+    C_TRACE( ( _T( "DISIUserChannel::ResetQueues 0x%x 0x%x>" ), this, iObjId ) );
+    if( iRx )
+        {
+        C_TRACE( ( _T( "DISIUserChannel::ResetQueues 0x%x iRx 0x%x" ), this, iRx ) );
+        while( iRx->Count() )
+            {
+            MemApi::DeallocBlock( iRx->Get() );
+            }
+        }
+    C_TRACE( ( _T( "DISIUserChannel::ResetQueues 0x%x 0x%x<" ), this, iObjId ) );
+    }
+
+// This is called in 1...N thread contextes
+void DISIUserChannel::ReceiveMsg(
+        const TDesC8& aMessage
+        )
+    {
+    C_TRACE( ( _T( "DISIUserChannel::ReceiveMsg 0x%x 0x%x 0x%x>" ), this, &aMessage, iObjId ) );
+    // Can only be called from thread context.
+    ASSERT_THREAD_CONTEXT_ALWAYS( ( EISIUserChannelfNotThreadContext3 | EDISIUserChannelTraceId << KClassIdentifierShift ) );
+    iRx->Add( aMessage );
+    iEmptyRxQueueDfc->Enque();
+    C_TRACE( ( _T( "DISIUserChannel::ReceiveMsg 0x%x 0x%x 0x%x<" ), this, &aMessage, iObjId ) );
+    }
+
+DISIUserChannel::DISIUserAsyncRequests::DISIUserAsyncRequests(
+        const TInt aSize
+        )
+    {
+    C_TRACE( ( _T( "DISIUserAsyncRequests::DISIUserAsyncRequests size %d>" ), aSize ) );
+    iRequestLock = new NFastMutex();
+    C_TRACE( ( _T( "DISIUserAsyncRequests::DISIUserAsyncRequests<" ) ) );
+    }
+
+DISIUserChannel::DISIUserAsyncRequests::~DISIUserAsyncRequests()
+    {
+
+    C_TRACE( ( _T( "DISIUserAsyncRequests::~DISIUserAsyncRequests>" ) ) );
+    iRequestCompletedList.Close();
+    delete iRequestLock;
+    C_TRACE( ( _T( "DISIUserAsyncRequests::~DISIUserAsyncRequests<" ) ) );
+
+    }
+
+TBool DISIUserChannel::DISIUserAsyncRequests::IsPending(
+        const TUint aRequest
+        )
+    {
+    C_TRACE( ( _T( "DISIUserAsyncRequests::IsPending %d>" ), aRequest ) );
+    ASSERT_RESET_ALWAYS( ( EISILastAsyncRequest > aRequest && EISIAsyncReceive <= aRequest ), ( EISIUserChannelReqOverTheLimits | EDISIUserChannelTraceId << KClassIdentifierShift ) );
+    TBool ret( EFalse );
+    NKern::FMWait( iRequestLock );
+    ret = ( iRequestStatusList[ aRequest ] ) ? ETrue : EFalse;
+    NKern::FMSignal( iRequestLock );
+    C_TRACE( ( _T( "DISIUserAsyncRequests::IsPending %d %d<" ), aRequest, ret ) );
+    return ret;
+    }
+
+void DISIUserChannel::DISIUserAsyncRequests::SetPending(
+        const TUint aRequest,
+        TRequestStatus* aStatus
+        )
+    {
+    C_TRACE( ( _T( "DISIUserAsyncRequests::SetPending %d 0x%x>" ), aRequest, aStatus ) );
+    ASSERT_RESET_ALWAYS( aRequest, ( EISIUserChannelNullParam | EDISIUserChannelTraceId << KClassIdentifierShift ) );
+    ASSERT_RESET_ALWAYS( aStatus, ( EISIUserChannelNullParam | EDISIUserChannelTraceId << KClassIdentifierShift ) );
+    ASSERT_RESET_ALWAYS( ( EISILastAsyncRequest > aRequest && EISIAsyncReceive <= aRequest ), ( EISIUserChannelReqOverTheLimits | EDISIUserChannelTraceId << KClassIdentifierShift ) );
+    // Note asserts must be done before holding the lock.
+    NKern::FMWait( iRequestLock );
+    iRequestStatusList[ aRequest ] = aStatus;
+    NKern::FMSignal( iRequestLock );
+    C_TRACE( ( _T( "DISIUserAsyncRequests::SetPending %d 0x%x<" ), aRequest, aStatus ) );
+    }
+
+void DISIUserChannel::EmptyRxQueueDfc(
+        TAny* aPtr // Pointer to self
+        )
+    {
+   	C_TRACE( ( _T( "DISIUserChannel::EmptyRxQueueDfc>" ) ) );
+    DISIUserChannel& chTmp = *reinterpret_cast<DISIUserChannel*>( aPtr );
+    C_TRACE( ( _T( "DISIUserChannel::EmptyRxQueueDfc 0x%x 0x%x>" ), &chTmp, chTmp.iObjId ) );
+    if( chTmp.iRequests->IsPending( EISIAsyncReceive ) && ( chTmp.iRx->Count() > 0 ) )
+        {
+        TDes8& tmpDes = chTmp.iRx->Get();
+        TInt desMaxLen( Kern::ThreadGetDesMaxLength( chTmp.iThread, chTmp.iReceiveBufPtr ) );
+        // If user descriptor legth is enough and length get not failed.
+        if( desMaxLen >= tmpDes.Length() )
+            {
+            // Write to user address space (iReceiveBufPtr) the content of tmpDes starting from zero offset as 8bit descriptor data.
+            TInt writeError( Kern::ThreadDesWrite( chTmp.iThread, chTmp.iReceiveBufPtr, tmpDes, KDestStartOffset, KChunkShiftBy0, chTmp.iThread ) );
+            if( writeError == KErrNone )
+                {
+                C_TRACE( ( _T( "DISIUserChannel::EmptyRxQueueDfc write 0x%x k->u 0x%x ok" ), &tmpDes, chTmp.iReceiveBufPtr ) );
+                chTmp.EnqueChannelRequestCompleteDfc( EISIAsyncReceive, writeError );
+                MemApi::DeallocBlock( tmpDes );
+                }
+            // Write unsuccesfull don't deallocate the block.
+            else
+                {
+                C_TRACE( ( _T( "DISIUserChannel::EmptyRxQueueDfc write 0x%x k->u 0x%x NOK, reason %d" ), &tmpDes, chTmp.iReceiveBufPtr, writeError ) );
+                TRACE_ASSERT_INFO( 0, chTmp.iObjId << KObjIdShift | (TUint16)writeError );
+                // Roll the message back to que.
+                chTmp.iRx->RollBack( tmpDes );
+                chTmp.EnqueChannelRequestCompleteDfc( EISIAsyncReceive, writeError );
+                }
+            }
+        // If descriptor invalid.
+        else
+            {
+            TRACE_WARNING( 0, chTmp.iObjId << KObjIdShift | (TUint16)tmpDes.Length() );
+            // Roll the message back to que.
+            chTmp.iRx->RollBack( tmpDes );
+            // If invalid content.
+            if( KErrBadDescriptor == desMaxLen )
+                {
+                TRACE_ASSERT_INFO( 0, chTmp.iObjId << KObjIdShift | (TUint16)desMaxLen );
+                C_TRACE( ( _T( "DISIUserChannel::EmptyRxQueueDfc invalid descriptor 0x%x" ), chTmp.iObjId ) );
+                chTmp.EnqueChannelRequestCompleteDfc( EISIAsyncReceive, KErrBadDescriptor );
+                }
+            // If length too small (if other assert).
+            else
+                {
+                TUint16 neededLength( tmpDes.Length() );
+                TRACE_WARNING( 0, chTmp.iObjId << KObjIdShift | (TUint16)desMaxLen );
+                C_TRACE( ( _T( "DISAUserChannel::EmptyRxQueueDfc descriptor length too small length %d needed %d" ), desMaxLen, neededLength ) );
+                ASSERT_RESET_ALWAYS( KErrNone == Kern::ThreadRawWrite( chTmp.iThread, chTmp.iNeededBufLen, &neededLength, sizeof(TUint16), chTmp.iThread ), 
+                                        EISIUserChannelDesWriteFailed | chTmp.iObjId << KObjIdShift | EDISIUserChannelTraceId << KClassIdentifierShift );
+                chTmp.EnqueChannelRequestCompleteDfc( EISIAsyncReceive, KErrOverflow );
+                }
+            }
+        }
+    else
+        {
+        C_TRACE( ( _T( "DISIUserChannel::EmptyRxQueueDfc no receive active or no message" ) ) );
+        }
+    C_TRACE( ( _T( "DISIUserChannel::EmptyRxQueueDfc 0x%x<" ), chTmp.iObjId ) );
+    }
+
+// called in router ext context
+void DISIUserChannel::EnqueChannelRequestCompleteDfc(
+        TInt aRequest,
+        TInt aStatusToComplete
+        )
+    {
+    C_TRACE( ( _T( "DISIUserChannel::EnqueChannelRequestCompleteDfc 0x%x %d %d 0x%x>" ), this, aRequest, aStatusToComplete, iObjId ) );
+    ASSERT_THREAD_CONTEXT_ALWAYS( ( EISIUserChannelfNotThreadContext | EDISIUserChannelTraceId << KClassIdentifierShift ) );    
+    //TODO check the error code
+    iRequests->iRequestCompletedList.Append( aRequest ); 
+    iRequests->iRequestCompletionValueList[ aRequest ] = aStatusToComplete;
+    iCompleteChannelRequestDfc->Enque();
+    C_TRACE( ( _T( "DISIUserChannel::EnqueChannelRequestCompleteDfc 0x%x %d %d 0x%x<" ), this, aRequest, aStatusToComplete, iObjId ) );
+    }
+
+// Run in ISI user channel kernel thread context.
+void DISIUserChannel::CompleteChannelRequestDfc(
+        TAny* aPtr
+        )
+    {
+    C_TRACE( ( _T( "DISIUserChannel::CompleteChReqDfc>" ) ) );
+    // Make sure that user side is accessed only by ldd DFCThread.
+    ASSERT_THREAD_CONTEXT_ALWAYS( ( EISIUserChannelfNotThreadContext2 | EDISIUserChannelTraceId << KClassIdentifierShift ) );
+    DISIUserChannel* chPtr = reinterpret_cast<DISIUserChannel*>( aPtr );
+    C_TRACE( ( _T( "DISIUserChannel::CompleteChReqDfc 0x%x 0x%x" ), chPtr, chPtr->iObjId ) );
+    TInt request = chPtr->iRequests->iRequestCompletedList[ KFirstRequest ];
+    TRequestStatus* status( chPtr->iRequests->iRequestStatusList[ request ] );
+    Kern::RequestComplete( chPtr->iThread, status, chPtr->iRequests->iRequestCompletionValueList[ request ] );
+    chPtr->iRequests->iRequestCompletedList.Remove( KFirstRequest );
+    chPtr->iRequests->iRequestStatusList[ request ] = NULL;
+    chPtr->iRequests->iRequestCompletionValueList[ request ] = KNotInitializedStatus;
+    
+    if( chPtr->iRequests->iRequestCompletedList.Count() != 0 )
+        {
+        CompleteChannelRequestDfc( chPtr );
+        }
+    C_TRACE( ( _T( "DISIUserChannel::CompleteChReqDfc 0x%x 0x%x<" ), chPtr, chPtr->iObjId ) );
+    }