diff -r e71858845f73 -r e1758cbb96ac systemswstubs/examplecommonisc/IscDriver/src/IscChannel.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/systemswstubs/examplecommonisc/IscDriver/src/IscChannel.cpp Mon Oct 04 00:04:35 2010 +0300 @@ -0,0 +1,1800 @@ +/* +* Copyright (c) 2005 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: An example implementation for ISC Driver Reference +* +*/ + + + +// INCLUDE FILES +#include +#include +#include "IscChannel.h" +#include "IscDevice.h" +#include "IscChannelContainer.h" +#include "IscQueue.h" +#include "IscTrace.h" + +// EXTERNAL DATA STRUCTURES + +// EXTERNAL FUNCTION PROTOTYPES + +// CONSTANTS +_LIT( KIscDriver, "IscDriver" ); + +// MACROS + +// LOCAL CONSTANTS AND MACROS +const TInt KIscInitializeDfcPriority( 1 ); +const TInt KOneParam( 1 ); +const TInt KTwoParams( 2 ); +const TInt KThreeParams( 3 ); +const TInt KFirstParam( 0 ); +const TInt KSecondParam( 1 ); +const TInt KThirdParam( 2 ); +const TInt KMultiplyByOne( KSecondParam ); +const TInt KMultiplyByThree( KThreeParams ); +const TInt KDivideByFour( 4 ); + +// MODULE DATA STRUCTURES + +// LOCAL FUNCTION PROTOTYPES + +// FORWARD DECLARATIONS + + +// ============================ MEMBER FUNCTIONS =============================== + + +// ----------------------------------------------------------------------------- +// DIscChannel::DIscChannel +// C++ default constructor. +// ( other items were commented in a header ). +// ----------------------------------------------------------------------------- +// +EXPORT_C DIscChannel::DIscChannel( DLogicalDevice* aDevice ) + : iInitializeDfc( NULL ), + iDataTransmissionIniData( NULL ), + iMultiplexerIniData( NULL ), + iMultiplexerBuffer( NULL ), + iDataTransmissionBuffer( NULL ), + iIscDevice( NULL ), + iIscConnectionStatusPtr( NULL ), + iIscFlowControlStatusPtr( NULL ), + iReceiveBufPtr( NULL ), + iDataReceiveBufPtr( NULL ), + iNeededBufLen( NULL ), + iNeededDataBufLen( NULL ), + iChannelNumber( 0 ), + iChannelOpen( EFalse ), + iFrameRx( NULL ), + iFrameRxQueue( NULL ), + iDataFrameRx( NULL ), + iDataFrameRxQueue( NULL ), + iULFlowControlStatus( EIscFlowControlOff ), + iDLFlowControlStatus( EIscFlowControlOff ), + iLastNotifiedULFlowstatus( EIscFlowControlOff ), + iIscChannelHighWaterMark( 0 ), + iIscChannelLowWaterMark( 0 ), + iOverFlow( EFalse ), + iClientPanic( EFalse ), + iDataTransmissionErrorCode( KErrNone ) + { + + iIscDevice = ( DIscDevice * )aDevice; + for ( TInt i( KErrNone ); i < EIscAsyncLast; i++ ) + { + iIscRequests[i] = NULL; + } + iThread = &Kern::CurrentThread(); + TInt r = iThread->Open(); + TRACE_ASSERT( r == KErrNone ); + + } + + +// ----------------------------------------------------------------------------- +// DIscChannel::~DIscChannel +// Destructor +// ( other items were commented in a header ). +// ----------------------------------------------------------------------------- +// +DIscChannel::~DIscChannel() + { + C_TRACE( ( _T( "DIscChannel::~DIscChannel()" ) ) ); + + if ( iChannelNumber < KIscNumberOfUnits ) + { + IscChannelContainer::RemoveChannel( this ); + } + else + { + C_TRACE( ( _T( "DIscChannel::~DIscChannel() re-open" ) ) ); + } + + ChannelDestruction(); + Kern::SafeClose( ( DObject*& )iThread, NULL ); + C_TRACE( ( _T( "DIscChannel::~DIscChannel() SafeClose called" ) ) ); + + } + +// ----------------------------------------------------------------------------- +// DIscChannel::ChannelDestruction +// Destructor +// ( other items were commented in a header ). +// ----------------------------------------------------------------------------- +// +void DIscChannel::ChannelDestruction() + { + C_TRACE( ( _T( "DIscChannel::ChannelDestruction() iChannelNumber (0x%x)" ),iChannelNumber ) ); + + // call DIscMultiplexerBase::CloseDLC and DLFlowControlNotify in case the channel has not been + // properly closed ( e.g. client thread panic etc. ) + if ( iChannelOpen ) + { + iIscDevice->CancelSending( iChannelNumber, this );// Delete pending send frames + iIscDevice->iIscMultiplexerInterface->CloseDLC( iChannelNumber, this ); + iIscDevice->DLFlowControlNotify( EIscFlowControlOff, iChannelNumber, this ); + } + + if ( iFrameRxQueue ) + { + while ( !iFrameRxQueue->Empty() ) + { + TDes8* tempPtr = ( TDes8* ) iFrameRxQueue->GetFirst(); + iFrameRxQueue->DeleteFirst(); + iIscDevice->ReleaseMemoryBlock( tempPtr ); + } + delete iFrameRxQueue; + iFrameRxQueue = NULL; + } + + if ( iFrameRx ) + { + delete [] iFrameRx; + iFrameRx = NULL; + } + + if ( iDataFrameRxQueue ) + { + while ( !iDataFrameRxQueue->Empty() ) + { + TDes8* tempPtr = ( TDes8* ) iDataFrameRxQueue->GetFirst(); + iDataFrameRxQueue->DeleteFirst(); + iIscDevice->ReleaseMemoryBlock( tempPtr ); + } + delete iDataFrameRxQueue; + iDataFrameRxQueue = NULL; + } + + if ( iDataFrameRx ) + { + delete [] iDataFrameRx; + iDataFrameRx = NULL; + } + + if ( iInitializeDfc ) + { + delete iInitializeDfc; + iInitializeDfc = NULL; + } + + if ( iDataTransmissionIniData ) + { + Kern::Free( iDataTransmissionBuffer ); + delete iDataTransmissionIniData; + iDataTransmissionIniData = NULL; + } + + if ( iMultiplexerIniData ) + { + Kern::Free( iMultiplexerBuffer ); + delete iMultiplexerIniData; + iMultiplexerIniData = NULL; + } + + C_TRACE( ( _T( "DIscChannel::ChannelDestruction - return void" ) ) ); + } + +// ----------------------------------------------------------------------------- +// DIscChannel::HandleMsg +// Message handling ( kernel server context ). +// ( other items were commented in a header ). +// ----------------------------------------------------------------------------- +// +void DIscChannel::HandleMsg( + TMessageBase* aMsg ) + { + C_TRACE( ( _T( "DIscChannel::HandleMsg(0x%x)" ), aMsg ) ); + TThreadMessage& m=*( TThreadMessage* )aMsg; + TInt id( m.iValue ); + + if ( id==( TInt )ECloseMsg ) + { + C_TRACE( ( _T( "DIscChannel::HandleMsg ECloseMsg" ) ) ); + m.Complete( KErrNone,EFalse ); + return; + } + + else if ( id==KMaxTInt ) + { + // DoCancel + // Should not come here ever + ASSERT_RESET_ALWAYS( 0,"IscDriver",EIscNotAllowedCallToDoCancel ); + } + + else if ( id<0 ) + { + // DoRequest + // should not come here ever + ASSERT_RESET_ALWAYS( 0,"IscDriver",EIscNotAllowedCallToDoRequest ); + } + + else + { + // DoControl + TUint32 a1[ KThreeParams ]; + TInt r( KErrNone ); + if ( id != EIscSyncClose ) + { + TInt amountOfParams( KErrNone ); + switch( id ) + { + case EIscAsyncInitializeModemInterface: + case EIscAsyncOpen: + amountOfParams = KThreeParams; + break; + default: + ASSERT_RESET_ALWAYS( 0, "NokiaISCDriver", EIscUnknownCommand ); + break; + } + r = Kern::ThreadRawRead( iThread, ( TAny* )m.Ptr0(), a1, + amountOfParams * sizeof( TAny* ) ); + TRACE_ASSERT( r == KErrNone ); + } + if( r == KErrNone ) + { + r=HandleRequest( id,a1,m.Ptr1() ); + } + + m.Complete( r,ETrue ); + } + } + +// ----------------------------------------------------------------------------- +// DIscChannel::Request +// Message handling ( user thread context ). +// ( other items were commented in a header ). +// ----------------------------------------------------------------------------- +// +#ifndef COMPONENT_TRACE_FLAG +TInt DIscChannel::Request( TInt aReqNo, TAny* a1, TAny* ) +#else +TInt DIscChannel::Request( TInt aReqNo, TAny* a1, TAny* a2) +#endif + { + C_TRACE( ( _T( "DIscChannel::Request(0x%x, 0x%x, 0x%x)" ), aReqNo, a1, a2 ) ); + + TInt r( KErrNotFound ); + + if ( aReqNo<( TInt )EMinRequestId ) + C_TRACE( ( _T( "DIscChannel::Request ERROR: False aReqNo %d" ), aReqNo ) ); + + if ( aReqNo >= 0 && aReqNo < EIscAsyncLastKernelServerContext || + aReqNo >= EIscAsyncLast && aReqNo < EIscSyncLastKernelServerContext ) + { + TThreadMessage& m=Kern::Message(); + m.iValue=aReqNo; + m.iArg[ KFirstParam ]=a1; + m.iArg[ KSecondParam ]=NULL; + r = m.SendReceive( &iMsgQ ); + } + else + { + TInt ulen( KErrNotFound ); + switch ( aReqNo ) + { + case EIscCancelAsyncInitialize: + case EIscCancelAsyncReceive: + case EIscCancelAsyncDataReceive: + case EIscSyncGetConnectionStatus: + case EIscCancelAsyncNotifyConnection: + case EIscSyncGetFlowControlStatus: + case EIscCancelAsyncNotifyFlowControl: + case EIscSyncGetMaximunDataSize: + case EIscCancelAsyncCustomOperation1: + case EIscCancelAsyncCustomOperation2: + case EIscCancelAsyncCustomOperation3: + case EIscCancelAsyncCustomOperation4: + case EIscCancelAsyncCustomOperation5: + case EIscCancelAsyncOpen: + case EIscSyncResetBuffers: + case EIscCancelAsyncSend: + case EIscCancelAsyncDataSend: + { + ulen = KErrNone; + break; + } + case EIscSyncSend: + case EIscSyncDataSend: + case EIscSyncCustomOperation1: + case EIscSyncCustomOperation2: + case EIscSyncCustomOperation3: + case EIscSyncCustomOperation4: + case EIscSyncCustomOperation5: + case EIscAsyncClose: + { + ulen = KOneParam; + break; + } + case EIscAsyncSend: + case EIscAsyncDataSend: + case EIscSyncGetChannelInfo: + case EIscAsyncNotifyConnectionStatus: + case EIscAsyncNotifyFlowControlStatus: + case EIscAsyncCustomOperation1: + case EIscAsyncCustomOperation2: + case EIscAsyncCustomOperation3: + case EIscAsyncCustomOperation4: + case EIscAsyncCustomOperation5: + { + ulen = KTwoParams; + break; + } + case EIscAsyncReceive: + case EIscAsyncDataReceive: + { + ulen = KThreeParams; + break; + } + default: + { + TRACE_ASSERT_ALWAYS; + } + } + ASSERT_RESET_ALWAYS( KErrNotFound != ulen, "ISCDriver", EIscUnknownCommand ); + // Maximum number of elements is three!!! + TAny* kptr[ KThreeParams ] = { KErrNone }; + if( ulen > KErrNone ) + { + C_TRACE( ( _T( "DIscChannel::Request ISC kumemget32" ) ) ); + kumemget32( kptr , a1, ( sizeof( TAny* ) ) * ulen ); + } + r = HandleRequest( aReqNo, kptr, NULL ); + } + C_TRACE( ( _T( "DIscChannel::Request ISC return %d CH 0x%x" ), r, iChannelNumber ) ); + return r; + + } + +// ----------------------------------------------------------------------------- +// DIscChannel::DoControl +// Handles requests. +// ( other items were commented in a header ). +// ----------------------------------------------------------------------------- +// +TInt DIscChannel::HandleRequest( + TInt aFunction, + TAny* a1, + TAny* /*a2*/ ) + { + C_TRACE( ( _T( "DIscChannel::DoControl(0x%x, 0x%x) iChannelNumber 0x%x channelPtr 0x%x" ), aFunction, a1, iChannelNumber, this ) ); + + TInt error( KErrNone ); + +#ifdef _DEBUG + // Check if control frame buffer overflow -> panic + if ( iClientPanic ) + { + C_TRACE( ( _T( "DIscChannel::DoControl() BUFFER OVERFLOW: PANIC CLIENT 0x%x" ), iChannelNumber ) ); + TRACE_ASSERT_ALWAYS; + // This panic the user thread only. + Kern::ThreadKill( iThread, EExitPanic, EIscControlBufferOverflow, KIscDriver ); + } +#endif // _DEBUG + + // Handle asynchronous requests + if ( aFunction >= EIscAsyncInitializeModemInterface && + aFunction < EIscAsyncLast ) + { + // if request is already active + if ( iIscRequests[aFunction] ) + { + TUint32* tablePtr = ( TUint32* )a1; + TRequestStatus* requestStatus = ( TRequestStatus* )( tablePtr[ KFirstParam ] ); + Kern::RequestComplete( iThread, requestStatus, KErrAlreadyExists ); + } + else + { + HandleAsyncRequest( aFunction, a1 ); + } + } + // Handle synchronous requests. + else if ( aFunction >= EIscAsyncLast && + aFunction < EIscSyncLast ) + { + error = HandleSyncRequest( aFunction, a1 ); + } + // Handle cancellation requests. + else if ( aFunction >= EIscSyncLast && + aFunction < EIscCancelLast ) + { + error = HandleCancelRequest( aFunction, a1 ); + } + // Undefined request, panic current thread. + else + { + // This panic the user thread only. + Kern::ThreadKill( iThread, EExitPanic, EIscControlBufferOverflow, KIscDriver ); + } + + C_TRACE( ( _T( "DIscChannel::DoControl - return %d" ), error ) ); + + return error; + } + + +// ----------------------------------------------------------------------------- +// DIscChannel::HandleAsyncRequests +// Handles asynchronous client requests +// ( other items were commented in a header ). +// ----------------------------------------------------------------------------- +// +void DIscChannel::HandleAsyncRequest( + TInt aFunction, + TAny* a1 ) + { + C_TRACE( ( _T( "DIscChannel::HandleAsyncRequest(0x%x, 0x%x) channelPtr 0x%x" ), aFunction, a1, this ) ); + + TUint32* tablePtr = ( TUint32* )a1; + + switch ( aFunction ) + { + case EIscAsyncInitializeModemInterface: + { + TInt r = KErrNotFound; + iIscRequests[EIscAsyncInitializeModemInterface] = ( TRequestStatus* )( tablePtr[ KFirstParam ] ); + + iInitializeDfc = new TDfc( InitializeComplete, this, Kern::DfcQue0(), KIscInitializeDfcPriority ); + ASSERT_RESET_ALWAYS( iInitializeDfc, "IscDriver",EIscMemoryAllocationFailure ); + + // Get Data Transmission Driver initialization string + TDesC8* tempPtr = ( TDesC8* )tablePtr[ KThirdParam ]; + iDataTransmissionBuffer = ( TUint8* )Kern::Alloc( KIscIniLineLength ); + ASSERT_RESET_ALWAYS( iDataTransmissionBuffer, "IscDriver",EIscMemoryAllocationFailure ); + + iDataTransmissionIniData = new ( TPtr8 )( iDataTransmissionBuffer, KIscIniLineLength ); + ASSERT_RESET_ALWAYS( iDataTransmissionIniData, "IscDriver",EIscMemoryAllocationFailure ); + + r = Kern::ThreadDesRead( iThread, tempPtr, *iDataTransmissionIniData, 0, KChunkShiftBy0 ); + ASSERT_RESET_ALWAYS( r == KErrNone, "IscDriver",EIscMemoryAllocationFailure ); + + // Get Multiplexer initialization string + tempPtr = ( TDesC8* )tablePtr[1]; + iMultiplexerBuffer = ( TUint8* )Kern::Alloc( KIscIniLineLength ); + ASSERT_RESET_ALWAYS( iMultiplexerBuffer, "IscDriver",EIscMemoryAllocationFailure ); + + iMultiplexerIniData = new ( TPtr8 )( iMultiplexerBuffer, KIscIniLineLength ); + ASSERT_RESET_ALWAYS( iDataTransmissionIniData, "IscDriver",EIscMemoryAllocationFailure ); + + r = Kern::ThreadDesRead( iThread, tempPtr, *iMultiplexerIniData, 0, KChunkShiftBy0 ); + ASSERT_RESET_ALWAYS( r == KErrNone, "IscDriver",EIscMemoryAllocationFailure ); + + // If buffer configuration is given from isc_config.ini as multiplexer configuration string, multiplexer + // needs configuration before datatransmissin driver is initialized + iIscDevice->iIscMultiplexerInterface->SetInitializationParameters( *iMultiplexerIniData ); + + // Allocate buffers and receive queues + iIscDevice->Initialize(); + + iIscDevice->iIscDataTransmissionInterface->InitializeDataTransmission( *iDataTransmissionIniData, + iInitializeDfc, + iDataTransmissionErrorCode ); + break; + } + + case EIscAsyncOpen: + { + iIscRequests[EIscAsyncOpen] = ( TRequestStatus* )( tablePtr[ KFirstParam ] ); + if ( iIscDevice->ConnectionStatus() == EIscConnectionOk ) + { + TDesC8* openInfo = ( TDesC8* )tablePtr[ KThirdParam ]; + // Channel info parameter has to be copied from user side in Epoc Kernel Architecture 2 + TInt length = Kern::ThreadGetDesLength( iThread, ( TDesC8* )tablePtr[ KThirdParam ] ); + TUint8* buffer = NULL; + TPtr8* bufferPtr = NULL; + if ( length > KErrNone ) + { + C_TRACE( ( _T( "DIscChannel::HandleAsyncRequest EIscAsyncOpen channel info got" ) ) ); + buffer = ( TUint8* )Kern::Alloc( length ); + bufferPtr = new ( TPtr8 )( buffer, length ); + TInt r = Kern::ThreadDesRead( iThread, openInfo, *bufferPtr, 0, KChunkShiftBy0 ); + ASSERT_RESET_ALWAYS( r == KErrNone, "IscDriver",EIscMemoryAllocationFailure ); + openInfo = ( TDesC8* )bufferPtr; + } + iIscDevice->iIscMultiplexerInterface->OpenDLC( ( TUint16 )tablePtr[ KSecondParam ], + openInfo, + this ); + + if ( buffer ) + Kern::Free( buffer ); + if ( bufferPtr ) + { + delete bufferPtr; + bufferPtr = NULL; + } + } + else + { + CompleteRequest( aFunction, KErrNotReady ); + } + break; + } + case EIscAsyncSend: + { + iIscRequests[EIscAsyncSend] = ( TRequestStatus* )( tablePtr[ KFirstParam ] ); + if ( iIscDevice->ConnectionStatus() == EIscConnectionOk + && iULFlowControlStatus == EIscFlowControlOff ) + { + TDesC8* ptr = ( TDesC8* ) tablePtr[ KSecondParam ]; + + // No return values check needed. Request completed with error value by multiplexer + iIscDevice->iIscMultiplexerInterface->Send( ( TUint16 )aFunction, + iChannelNumber, + *ptr, + this ); + } + else + { + if ( iULFlowControlStatus != EIscFlowControlOff ) + { + CompleteRequest( aFunction, KErrOverflow ); + } + else + { + CompleteRequest( aFunction, KErrNotReady ); + } + } + break; + } + case EIscAsyncReceive: + { + TRACE_ASSERT( tablePtr[ KFirstParam ] ); + TRACE_ASSERT( tablePtr[ KSecondParam ] ); + TRACE_ASSERT( tablePtr[ KThirdParam ] ); + + // check for descriptor validity + TRACE_ASSERT( Kern::ThreadGetDesMaxLength( iThread, (TPtr8* )tablePtr[KSecondParam] ) > 0 ); + + //Store needed length ptr + iNeededBufLen = ( TPtr8* )tablePtr[ KThirdParam ]; + + //Store msg data ptr + iReceiveBufPtr = ( TPtr8* )tablePtr[ KSecondParam ]; + + iIscRequests[EIscAsyncReceive] = ( TRequestStatus* )( tablePtr[ KFirstParam ] ); + + break; + } + case EIscAsyncDataSend: + { + iIscRequests[EIscAsyncDataSend] = ( TRequestStatus* )( tablePtr[ KFirstParam ] ); + + if ( iIscDevice->ConnectionStatus() == EIscConnectionOk + && iULFlowControlStatus == EIscFlowControlOff ) + { + TDesC8* ptr = ( TDesC8* )tablePtr[ KSecondParam ]; + iIscDevice->iIscMultiplexerInterface->DataSend( ( TUint16 )aFunction, + iChannelNumber, + *ptr, + this ); + } + else + { + if ( iULFlowControlStatus != EIscFlowControlOff ) + { + CompleteRequest( aFunction, KErrOverflow ); + } + else + { + CompleteRequest( aFunction, KErrNotReady ); + } + } + break; + } + case EIscAsyncDataReceive: + { + TRACE_ASSERT( tablePtr[ KFirstParam ] ); + TRACE_ASSERT( tablePtr[ KSecondParam ] ); + TRACE_ASSERT( tablePtr[ KThirdParam ] ); + + // check for descriptor validity + TRACE_ASSERT( Kern::ThreadGetDesMaxLength( iThread, (TPtr8* )tablePtr[KSecondParam] ) > 0 ); + + //Store needed length ptr + iNeededDataBufLen = ( TPtr8* )tablePtr[ KThirdParam ]; + + //Store msg data ptr + iDataReceiveBufPtr = ( TPtr8* )tablePtr[ KSecondParam ]; + + iIscRequests[EIscAsyncDataReceive] = ( TRequestStatus* )( tablePtr[ KFirstParam ] ); + + break; + } + case EIscAsyncNotifyConnectionStatus: + { + iIscConnectionStatusPtr = ( TPtr8* )tablePtr[ KSecondParam ]; + iIscRequests[EIscAsyncNotifyConnectionStatus] = ( TRequestStatus* )( tablePtr[ KFirstParam ] ); + break; + } + case EIscAsyncNotifyFlowControlStatus: + { + iIscFlowControlStatusPtr = reinterpret_cast( tablePtr[ KSecondParam ] ); + iIscRequests[ EIscAsyncNotifyFlowControlStatus ] = reinterpret_cast( tablePtr[ KFirstParam ] ); + C_TRACE( ( _T( "DIscChannel::NotifyFlowControl iLastNotifiedULFlowstatus = %d iULFlowControlStatus = %d" ), iLastNotifiedULFlowstatus, iULFlowControlStatus ) ); + + if( iULFlowControlStatus != iLastNotifiedULFlowstatus ) + { + // Complete immediately. + C_TRACE( ( _T( "DIscChannel::HandleAsyncRequest iULFlowControlStatus != iLastNotifiedULFlowstatus" ) ) ); + NotifyFlowControl( iULFlowControlStatus ); + } + else + { + // None + } + break; + } + case EIscAsyncCustomOperation1: + case EIscAsyncCustomOperation2: + case EIscAsyncCustomOperation3: + case EIscAsyncCustomOperation4: + case EIscAsyncCustomOperation5: + { + iIscRequests[aFunction] = ( TRequestStatus* )( tablePtr[ KFirstParam ] ); + TAny* tempPtr = ( TAny* )tablePtr[ KSecondParam ]; + iIscDevice->iIscMultiplexerInterface->CustomFunction( iChannelNumber, + ( TUint16 )aFunction, + tempPtr, + this ); + break; + } + case EIscAsyncClose: + { + iIscRequests[aFunction] = ( TRequestStatus* )( tablePtr[ KFirstParam ] ); + + ResetBuffers(); + + // Cancel all active requests except asynchronous close + for ( TInt i( KErrNone ); i < EIscAsyncLast; i++ ) + { + // if request is active complete it with KErrCancel + if ( iIscRequests[i] && i != EIscAsyncClose ) + { + iIscDevice->iIscMultiplexerInterface->CancelNotify( iChannelNumber, i, this ); + CompleteRequest( i, KErrCancel ); + } + } + + iChannelOpen = EFalse; + + iIscDevice->iIscMultiplexerInterface->CloseDLC( iChannelNumber, this ); + + break; + } + default: + { + ASSERT_RESET_ALWAYS( 0,"IscDriver",EIscUnknownCommand ); + break; + } + } + + IscChannelContainer::AddDfc(); + + } + + +// ----------------------------------------------------------------------------- +// DIscChannel::HandleSyncRequest +// Handles synchronous client requests +// ( other items were commented in a header ). +// ----------------------------------------------------------------------------- +// +TInt DIscChannel::HandleSyncRequest( + TInt aFunction, + TAny* a1 ) + { + C_TRACE( ( _T( "DIscChannel::HandleSyncRequest(0x%x, 0x%x) channelPtr 0x%x" ), aFunction, a1, this ) ); + + TInt error( KErrNone ); + TUint32* tablePtr = ( TUint32* )a1; + + switch ( aFunction ) + { + case EIscSyncClose: + { + ResetBuffers(); + + iIscDevice->iIscMultiplexerInterface->CloseDLC( iChannelNumber, this ); + + // Cancel all active requests + for ( TInt i( KErrNone ); i < EIscAsyncLast; i++ ) + { + // if request is active complete it with KErrCancel + if ( iIscRequests[i] ) + { + iIscDevice->iIscMultiplexerInterface->CancelNotify( iChannelNumber, i, this ); + CompleteRequest( i, KErrCancel ); + } + } + + error = KErrNone; + iChannelOpen = EFalse; + break; + } + case EIscSyncSend: + { + if ( iIscDevice->ConnectionStatus() == EIscConnectionOk + && iULFlowControlStatus == EIscFlowControlOff ) + { + + TDesC8* ptr = ( TDesC8* ) tablePtr[ KFirstParam ]; + error = iIscDevice->iIscMultiplexerInterface->Send( ( TUint16 )aFunction, + iChannelNumber, + *ptr, + this ); + } + else + { + if ( iULFlowControlStatus != EIscFlowControlOff ) + { + error = KErrOverflow; + } + else + { + error = KErrNotReady; + } + } + break; + } + case EIscSyncDataSend: + { + if ( iIscDevice->ConnectionStatus() == EIscConnectionOk + && iULFlowControlStatus == EIscFlowControlOff ) + { + TDesC8* ptr = ( TDesC8* ) tablePtr[ KFirstParam ]; + error = iIscDevice->iIscMultiplexerInterface->DataSend( ( TUint16 )aFunction, + iChannelNumber, + *ptr, + this ); + } + else + { + if ( iULFlowControlStatus != EIscFlowControlOff ) + { + error = KErrOverflow; + } + else + { + error = KErrNotReady; + } + } + break; + } + case EIscSyncGetConnectionStatus: + { + error = iIscDevice->ConnectionStatus(); + break; + } + case EIscSyncGetFlowControlStatus: + { + error = iULFlowControlStatus; + break; + } + case EIscSyncGetChannelInfo: + { + TDes8* tempPtr = ( TDes8* ) tablePtr[1]; + error = iIscDevice->iIscMultiplexerInterface->GetChannelInfo( ( TUint16 )tablePtr[ KFirstParam ], + *tempPtr ); + break; + } + case EIscSyncGetMaximunDataSize: + { + error = iIscDevice->iIscMultiplexerInterface->MaximumDataSize( iChannelNumber ); + break; + } + case EIscSyncCustomOperation1: + case EIscSyncCustomOperation2: + case EIscSyncCustomOperation3: + case EIscSyncCustomOperation4: + case EIscSyncCustomOperation5: + { + TAny* tempPtr = ( TAny* )tablePtr[ KFirstParam ]; + error = iIscDevice->iIscMultiplexerInterface->CustomFunction( iChannelNumber, + ( TUint16 )aFunction, + tempPtr, + this ); + break; + } + case EIscSyncResetBuffers: + { + ResetBuffers(); + error = KErrNone; + break; + } + default: + { + ASSERT_RESET_ALWAYS( 0,"IscDriver",EIscUnknownCommand ); + break; + } + } + return error; + } + +// ----------------------------------------------------------------------------- +// DIscChannel::HandleCancelRequest +// Cancels active request +// ( other items were commented in a header ). +// ----------------------------------------------------------------------------- +// +TInt DIscChannel::HandleCancelRequest( + TInt aFunction, + TAny* /*a1*/ ) + { + C_TRACE( ( _T( "DIscChannel::HandleCancelRequest(0x%x)" ), aFunction ) ); + + TUint16 operationToCancel( 0 ); + switch ( aFunction ) + { + + case EIscCancelAsyncInitialize: + { + if ( iDataTransmissionIniData ) + { + Kern::Free( iDataTransmissionBuffer ); + delete iDataTransmissionIniData; + iDataTransmissionIniData = NULL; + } + if ( iMultiplexerIniData ) + { + Kern::Free( iMultiplexerBuffer ); + delete iMultiplexerIniData; + iMultiplexerIniData = NULL; + } + + operationToCancel = EIscAsyncInitializeModemInterface; + break; + } + case EIscCancelAsyncOpen: + { + if ( KRequestPending == IsPending( EIscAsyncOpen ) ) + { + iChannelOpen = EFalse; + } + operationToCancel = EIscAsyncOpen; + break; + } + case EIscCancelAsyncSend: + { + operationToCancel = EIscAsyncSend; + // Cancel sending / empty send queues + iIscDevice->CancelSending( iChannelNumber, this ); + break; + } + case EIscCancelAsyncDataSend: + { + operationToCancel = EIscAsyncDataSend; + // Cancel sending / empty send queues + iIscDevice->CancelSending( iChannelNumber, this ); + break; + } + + case EIscCancelAsyncReceive: + { + iReceiveBufPtr = NULL; + iNeededBufLen = NULL; + operationToCancel = EIscAsyncReceive; + break; + } + + case EIscCancelAsyncDataReceive: + { + iDataReceiveBufPtr = NULL; + iNeededDataBufLen = NULL; + operationToCancel = EIscAsyncDataReceive; + break; + } + + case EIscCancelAsyncNotifyConnection: + { + iIscConnectionStatusPtr = NULL; + operationToCancel = EIscAsyncNotifyConnectionStatus; + break; + } + + case EIscCancelAsyncNotifyFlowControl: + { + iIscFlowControlStatusPtr = NULL; + operationToCancel = EIscAsyncNotifyFlowControlStatus; + break; + } + case EIscCancelAsyncCustomOperation1: + { + operationToCancel = EIscAsyncCustomOperation1; + break; + } + case EIscCancelAsyncCustomOperation2: + { + operationToCancel = EIscAsyncCustomOperation2; + break; + } + case EIscCancelAsyncCustomOperation3: + { + operationToCancel = EIscAsyncCustomOperation3; + break; + } + case EIscCancelAsyncCustomOperation4: + { + operationToCancel = EIscAsyncCustomOperation4; + break; + } + case EIscCancelAsyncCustomOperation5: + { + operationToCancel = EIscAsyncCustomOperation5; + break; + } + case EIscCancelAsyncClose: + { + TRACE_ASSERT_ALWAYS; + operationToCancel = EIscAsyncClose; + break; + } + default: + { + ASSERT_RESET_ALWAYS( 0,"IscDriver",EIscUnknownCommand ); + break; + } + } + + iIscDevice->iIscMultiplexerInterface->CancelNotify( iChannelNumber, ( TUint16 )operationToCancel, this ); + CompleteRequest( operationToCancel, KErrCancel ); + + return KErrNone; + } + +// ----------------------------------------------------------------------------- +// DIscChannel::DoCreate +// Secondary initialization of channel +// ( other items were commented in a header ). +// ----------------------------------------------------------------------------- +// +TInt DIscChannel::DoCreate( + TInt aUnit, + const TDesC8* anInfo, + const TVersion& /*aVer*/ ) + { + C_TRACE( ( _T( "DIscChannel::DoCreate(0x%x, 0x%x, 0x%x)" ), aUnit, anInfo, this ) ); + if ( !Kern::CurrentThreadHasCapability( ECapabilityCommDD,__PLATSEC_DIAGNOSTIC_STRING + ( "Checked by ISCDRIVER.LDD ( Inter-System Communication Driver )" ) ) ) + { + return KErrPermissionDenied; + } + TUint16 channelNumber = ( TUint16 )aUnit; + if ( anInfo ) + { + // check for channel number inside anInfo + TUint8 channel = ( TUint8 )( *anInfo )[0]; + if ( channel >= KIscMaxChannelsInLdd ) + { + channelNumber += KIscMaxChannelsInLdd; + } + C_TRACE( ( _T( "DIscChannel::DoCreate channel=0x%x" ), channelNumber ) ); + } + + if ( channelNumber != KIscControlChannel ) + { + TIscConfiguration config; + iIscDevice->iIscMultiplexerInterface->GetConfiguration( config ); + TInt i( KErrNone ); + iFrameRx = new TUint32*[config.channelRcvQueueSize]; + ASSERT_RESET_ALWAYS( iFrameRx, "IscDriver",EIscMemoryAllocationFailure ); + for ( i = KErrNone; i < config.channelRcvQueueSize; i++ ) + { + iFrameRx[i] = 0; + } + + iDataFrameRx = new TUint32*[config.channelDataRcvQueueSize]; + ASSERT_RESET_ALWAYS( iDataFrameRx, "IscDriver",EIscMemoryAllocationFailure ); + for ( i = KErrNone; i < config.channelDataRcvQueueSize; i++ ) + { + iDataFrameRx[i] = 0; + } + + // creating frame queue for incoming frames + iFrameRxQueue = new DIscQueue( iFrameRx, config.channelRcvQueueSize ); + ASSERT_RESET_ALWAYS( iFrameRxQueue, "IscDriver",EIscMemoryAllocationFailure ); + + // creating frame queue for incoming data frames + iDataFrameRxQueue = new DIscQueue( iDataFrameRx, config.channelDataRcvQueueSize ); + ASSERT_RESET_ALWAYS( iDataFrameRxQueue, "IscDriver",EIscMemoryAllocationFailure ); + + // Flowcontrol marks for data frames + iIscChannelHighWaterMark = ( TUint16 )( ( ( ( TUint16 )config.channelDataRcvQueueSize ) * KMultiplyByThree ) / KDivideByFour );// 75% = multiply with 3, divide by 4 + iIscChannelLowWaterMark = ( TUint16 )( ( ( ( TUint16 )config.channelDataRcvQueueSize ) * KMultiplyByOne ) / KDivideByFour );// 25% = multiply with 1, divide by 4 + + TRACE_ASSERT( iIscChannelHighWaterMark != 0 ); + } + +#ifndef ISC_CHANNEL_SHARING_IN_USE + // Remove checking if channel already set to enable channel sharing + //Check if channel already set + if ( IscChannelContainer::Channel( channelNumber, 0 ) ) + { + C_TRACE( ( _T( "DIscChannel::DoCreate channel 0x%x already set!!!!" ), channelNumber ) ); + return KErrAlreadyExists; + } +#endif //ISC_CHANNEL_SHARING_IN_USE + + //Add itself to channel table. + TInt error = IscChannelContainer::SetChannel( ( DIscChannel* )this, channelNumber ); + if ( KErrNone != error ) + { + return error; + } + + iChannelOpen = ETrue; + + // Store channel number. + iChannelNumber = channelNumber; + SetDfcQ( Kern::DfcQue0() ); + iMsgQ.Receive(); + + return KErrNone; + + } + + +// ----------------------------------------------------------------------------- +// DIscChannel::NotifyFlowControl +// Notify user side client that uplink flow control is on/off +// ( other items were commented in a header ). +// ----------------------------------------------------------------------------- +// +void DIscChannel::NotifyFlowControl + ( + const TInt aFlowControlStatus + ) + { + C_TRACE( ( _T( "DIscChannel::NotifyFlowControl(0x%x) iChannelNumber 0x%x channelPtr 0x%x" ), aFlowControlStatus, iChannelNumber, this ) ); + + iULFlowControlStatus = aFlowControlStatus; + if( iIscRequests[ EIscAsyncNotifyFlowControlStatus ] + && iIscFlowControlStatusPtr ) + { + TPtr8 tempDes( reinterpret_cast( &iULFlowControlStatus ), sizeof ( TInt ), sizeof ( TInt ) ); + iLastNotifiedULFlowstatus = aFlowControlStatus; + TInt r = ThreadWrite( static_cast( iIscFlowControlStatusPtr ), &tempDes, 0 ); + TRACE_ASSERT( r == KErrNone ); + CompleteRequest( EIscAsyncNotifyFlowControlStatus, r ); + } + else + { + C_TRACE( ( _T( "DIscChannel::NotifyFlowControl No request pending!" ) ) ); + } + } + +// ----------------------------------------------------------------------------- +// DIscChannel::NotifyConnectionStatus +// Notify user side client that connection status has changed +// ( other items were commented in a header ). +// ----------------------------------------------------------------------------- +// +void DIscChannel::NotifyConnectionStatus( + const TInt aConnectionStatus ) + { + C_TRACE( ( _T( "DIscChannel::NotifyConnectionStatus(0x%x) channelPtr 0x%x" ), aConnectionStatus, this ) ); + + if ( iIscRequests[EIscAsyncNotifyConnectionStatus] + && iIscConnectionStatusPtr ) + { + TInt temp = aConnectionStatus; + TPtr8 tempDes( ( TUint8* )&temp,sizeof ( TInt ),sizeof ( TInt ) ); + TInt r = ThreadWrite( ( TAny* )iIscConnectionStatusPtr, &tempDes, 0 ); + TRACE_ASSERT( r == KErrNone ); + + CompleteRequest( EIscAsyncNotifyConnectionStatus, r ); + } + } + +// ----------------------------------------------------------------------------- +// DIscChannel::IsPending +// Check if asynchronous request is active +// ( other items were commented in a header ). +// ----------------------------------------------------------------------------- +// +TInt DIscChannel::IsPending( + const TUint16 aReqNumber ) + { + TInt error( KErrNone ); + if ( iIscRequests[aReqNumber] ) + { + error = KRequestPending; + } + else + { + // error is KErrNone + } + return error; + } +// ----------------------------------------------------------------------------- +// DIscChannel::CompleteRequest +// Function to complete clients pending asynchronous request +// ( other items were commented in a header ). +// ----------------------------------------------------------------------------- +// +void DIscChannel::CompleteRequest( + TInt aOperation, + TInt aCompleteStatus ) + { + C_TRACE( ( _T( "DIscChannel::CompleteRequest(0x%x, 0x%x) iChannelNumber 0x%x channelPtr 0x%x" ), aOperation, aCompleteStatus, iChannelNumber, this ) ); + + if ( aOperation < EIscAsyncLast ) + { + + TRequestStatus* requestStatus = iIscRequests[aOperation]; + if ( requestStatus ) + { + // In case of higher priority thread, set request to NULL from the request table before actual completing + iIscRequests[aOperation] = NULL; + Kern::RequestComplete( iThread, requestStatus, aCompleteStatus ); + } + } + else + { + // Do nothing + } + + C_TRACE( ( _T( "DIscChannel::CompleteRequest - return void" ) ) ); + + } + +// ----------------------------------------------------------------------------- +// DIscChannel::InitializeComplete +// Initialization complete dfc +// ( other items were commented in a header ). +// ----------------------------------------------------------------------------- +// +void DIscChannel::InitializeComplete( + TAny* aPtr ) + { + C_TRACE( ( _T( "DIscChannel::InitializeComplete(0x%x)" ), aPtr ) ); + + DIscChannel* ThisPtr = ( DIscChannel* )aPtr; + if ( KErrNone == ThisPtr->iDataTransmissionErrorCode ) + { + ThisPtr->DoMultiplexerInitialize(); + } + else + { + ThisPtr->CompleteRequest( EIscAsyncInitializeModemInterface, ThisPtr->iDataTransmissionErrorCode ); + } + C_TRACE( ( _T( "DIscChannel::InitializeComplete - return 0x%x" ) ) ); + + } + +// ----------------------------------------------------------------------------- +// DIscChannel::DoMultiplexerInitialize +// Completes the multiplexer initialization +// ( other items were commented in a header ). +// ----------------------------------------------------------------------------- +// +void DIscChannel::DoMultiplexerInitialize() + { + C_TRACE( ( _T( "DIscChannel::DoMultiplexerInitialize() channelPtr 0x%x" ), this ) ); + + if ( iIscRequests[EIscAsyncInitializeModemInterface] ) + { + + iIscDevice->iIscMultiplexerInterface->InitializeMultiplexer( + EIscAsyncInitializeModemInterface, + *iMultiplexerIniData, + this ); + } + + C_TRACE( ( _T( "DIscChannel::DoMultiplexerInitialize - return void" ) ) ); + } + +// ----------------------------------------------------------------------------- +// DIscChannel::StoreFrame +// Stores the incoming frame to channels receive queue +// ( other items were commented in a header ). +// ----------------------------------------------------------------------------- +// +void DIscChannel::StoreFrame( TDesC8* aData ) + { + C_TRACE( ( _T( "DIscChannel::StoreFrame(0x%x) channelId 0x%x channelPtr 0x%x" ), aData, iChannelNumber, this ) ); + + TInt error( KErrNone ); + + TIscFrameInfo frameInfo; + iIscDevice->iIscMultiplexerInterface->GetFrameInfo( *aData, frameInfo ); + + if ( frameInfo.frameType == EIscDataFrame ) + { + C_TRACE( ( _T( "DIscChannel::StoreFrame dataFrame" ) ) ); + error = iDataFrameRxQueue->Add( ( TAny* )aData ); + if ( error == KErrNone ) + { + if ( iDataFrameRxQueue->Count() >= iIscChannelHighWaterMark + && iDLFlowControlStatus == EIscFlowControlOff ) + { + iIscDevice->DLFlowControlNotify( EIscFlowControlOn, iChannelNumber, this ); + iDLFlowControlStatus = EIscFlowControlOn; + } + else if ( iDataFrameRxQueue->Count() <= iIscChannelLowWaterMark + && iDLFlowControlStatus != EIscFlowControlOff ) + { + iIscDevice->DLFlowControlNotify( EIscFlowControlOff, iChannelNumber, this ); + iDLFlowControlStatus = EIscFlowControlOff; + } + else + { + // Do nothing + } + } + else + { + // Set overflow flag on. Complete next DataReceive with KErrOverFlow + TRACE_ASSERT_ALWAYS; + iOverFlow = ETrue; + iIscDevice->ReleaseMemoryBlock( ( TDes8* )aData ); + } + } + + else + { + C_TRACE( ( _T( "DIscChannel::StoreFrame controlFrame" ) ) ); + error = iFrameRxQueue->Add( ( TAny* )aData ); + if ( error != KErrNone ) + { + C_TRACE( ( _T( "DIscChannel::StoreFrame() CONTROL FRAME OVERFLOW channel %d" ), iChannelNumber ) ); + TRACE_ASSERT_ALWAYS; + iClientPanic = ETrue; + iIscDevice->ReleaseMemoryBlock( ( TDes8* )aData ); + } + } + + C_TRACE( ( _T( "DIscChannel::StoreFrame - return void" ) ) ); + } + +// ----------------------------------------------------------------------------- +// DIscChannel::EmptyBuffers +// Goes through channel's queue and delivers possible frame( s ) to client +// ( other items were commented in a header ). +// ----------------------------------------------------------------------------- +// +void DIscChannel::EmptyBuffers() + { + C_TRACE( ( _T( "DIscChannel::EmptyBuffers() channelId 0x%x channelPtr 0x%x" ),iChannelNumber, this ) ); + + if ( iDataFrameRxQueue->NextBufferLength() > KErrNone ) + { + TDes8* tempPtr = ( TDes8* ) iDataFrameRxQueue->GetFirst(); + TIscFrameInfo frameInfo; + TInt desMaxLen( KErrNone ); + + iIscDevice->iIscMultiplexerInterface->GetFrameInfo( *tempPtr, frameInfo ); + + // frame incoming, and datareceive request active + if ( iIscRequests[EIscAsyncDataReceive] && frameInfo.frameType == EIscDataFrame ) + { + if ( frameInfo.concatenation == EIscNoConcatenation ) + { + desMaxLen = Kern::ThreadGetDesMaxLength( iThread, iDataReceiveBufPtr ); + + C_TRACE( ( _T( "DIscChannel::EmptyBuffers() data desMaxLen %d" ),desMaxLen ) ); + + TRACE_ASSERT( desMaxLen > KErrNone ); + + // check that client's memory block is big enough + if ( desMaxLen >= frameInfo.writeLength ) + { + // create a temporary descriptor for writing since we're + // necessary not writing the whole contents of the + // source descriptor, only the part that ISC Multiplexer + // wants + TPtr8 writePtr( ( TUint8* )( tempPtr->Ptr() + frameInfo.writeStartIndex ), + frameInfo.writeLength, + frameInfo.writeLength ); + + TInt r = ThreadWrite( iDataReceiveBufPtr, &writePtr, 0 ); + + TRACE_ASSERT( r == KErrNone ); + + // remove the pointer from queue and release the memory block + // but only if the ThreadWrite was successfull + if ( r == KErrNone ) + { + iDataFrameRxQueue->DeleteFirst(); + iIscDevice->ReleaseMemoryBlock( tempPtr ); + if ( iOverFlow ) + { + iOverFlow = EFalse; + CompleteRequest( EIscAsyncDataReceive, KErrOverflow ); + } + else + { + CompleteRequest( EIscAsyncDataReceive, KErrNone ); + } + } + else + { + C_TRACE( ( _T( "DIscChannel::EmptyBuffers() data ThreadWrite %d" ), r ) ); + CompleteRequest( EIscAsyncDataReceive, r ); + } + } + // client buffer too small + else + { + TUint16 tempLen( frameInfo.writeLength ); + TPtr8 tempLenDes( ( TUint8* )&tempLen, sizeof ( TUint16 ), sizeof ( TUint16 ) ); + + TInt r = ThreadWrite( ( TAny* )iNeededDataBufLen, &tempLenDes, 0 ); + TRACE_ASSERT( r == KErrNone ); + if ( r != KErrNone ) + { + C_TRACE( ( _T( "DIscChannel::EmptyBuffers() data ThreadWrite %d" ), r ) ); + } + + CompleteRequest( EIscAsyncDataReceive, KErrNoMemory ); + } + } + else + { + HandleConcatenatedDataFrame( tempPtr, frameInfo ); + } + } + } + // no frames in data queue + else + { + C_TRACE( ( _T( "DIscChannel::EmptyBuffers() channelId 0x%x channelPtr No frames in data queue" ), iChannelNumber, this ) ); + } + + // Check if there is frame in queue + if ( iFrameRxQueue->NextBufferLength() > KErrNone ) + { + TDes8* tempPtr = ( TDes8* ) iFrameRxQueue->GetFirst(); + TIscFrameInfo frameInfo; + TInt desMaxLen( KErrNone ); + + iIscDevice->iIscMultiplexerInterface->GetFrameInfo( *tempPtr, frameInfo ); + + // frame incoming and normal receive request active + if ( iIscRequests[EIscAsyncReceive] && frameInfo.frameType == EIscNonDataFrame ) + { + if ( frameInfo.concatenation == EIscNoConcatenation ) + { + desMaxLen = Kern::ThreadGetDesMaxLength( iThread, iReceiveBufPtr ); + + C_TRACE( ( _T( "DIscChannel::EmptyBuffers() desMaxLen %d" ),desMaxLen ) ); + + TRACE_ASSERT( desMaxLen > KErrNone ); + + // check that client's memory block is big enough + if ( desMaxLen >= frameInfo.writeLength ) + { + // create a temporary descriptor for writing since we're + // necessary not writing the whole contents of the + // source descriptor, only the part that ISC Multiplexer + // wants + TPtr8 writePtr( ( TUint8* )( tempPtr->Ptr() + frameInfo.writeStartIndex ), + frameInfo.writeLength, + frameInfo.writeLength ); + + TInt r = ThreadWrite( iReceiveBufPtr, &writePtr, 0 ); + + TRACE_ASSERT( r == KErrNone ); + + // remove the pointer from queue and release the memory block + // but only if the ThreadWrite was successfull + if ( r == KErrNone ) + { + iFrameRxQueue->DeleteFirst(); + iIscDevice->ReleaseMemoryBlock( tempPtr ); + if ( iClientPanic ) + { + iClientPanic = EFalse; + CompleteRequest( EIscAsyncReceive, KErrOverflow ); + } + else + { + CompleteRequest( EIscAsyncReceive, KErrNone ); + } + } + else + { + C_TRACE( ( _T( "DIscChannel::EmptyBuffers() ThreadWrite %d" ), r ) ); + CompleteRequest( EIscAsyncReceive, r ); + } + } + // client buffer too small + else + { + TUint16 tempLen = frameInfo.writeLength; + TPtr8 tempLenDes( ( TUint8* )&tempLen, sizeof ( TUint16 ), sizeof ( TUint16 ) ); + + TInt r = ThreadWrite ( ( TAny* )iNeededBufLen, &tempLenDes, 0 ); + TRACE_ASSERT( r == KErrNone ); + if ( r != KErrNone ) + { + C_TRACE( ( _T( "DIscChannel::EmptyBuffers() ThreadWrite %d" ), r ) ); + } + + CompleteRequest( EIscAsyncReceive, KErrNoMemory ); + } + } + else + { + HandleConcatenatedFrame( tempPtr, frameInfo ); + } + } + } + // no frames in queue + else + { + C_TRACE( ( _T( "DIscChannel::EmptyBuffers() channelId 0x%x channelPtr 0x%x No frames in queue" ), iChannelNumber, this ) ); + } + + // If possible, set flow control off from data frame receiving + if ( iDataFrameRxQueue->Count() <= iIscChannelLowWaterMark + && iDLFlowControlStatus != EIscFlowControlOff ) + { + iIscDevice->DLFlowControlNotify( EIscFlowControlOff, iChannelNumber, this ); + iDLFlowControlStatus = EIscFlowControlOff; + } + + + C_TRACE( ( _T( "DIscChannel::EmptyBuffers - return void" ) ) ); + + } + +// ----------------------------------------------------------------------------- +// DIscChannel::HandleConcatenatedDataFrame +// Copies several data frames to clients buffer if needed before compliting receive request +// ( other items were commented in a header ). +// ----------------------------------------------------------------------------- +// +void DIscChannel::HandleConcatenatedDataFrame( TDes8* aPtr, TIscFrameInfo& aInfo ) + { + C_TRACE( ( _T( "DIscChannel::HandleConcatenatedDataFrame(0x%x, 0x%x) channelPtr 0x%x" ), aPtr, &aInfo, this ) ); + TInt desMaxLen( KErrNone ); + TInt desLen( KErrNone ); + TUint16 totalLength( 0 ); + + desMaxLen = Kern::ThreadGetDesMaxLength( iThread, iDataReceiveBufPtr ); + desLen = Kern::ThreadGetDesLength( iThread, iDataReceiveBufPtr ); + + if ( aInfo.totalLength > KErrNone ) + { + totalLength = aInfo.totalLength; + } + else + { + totalLength = desMaxLen; + } + switch ( aInfo.concatenation ) + { + // first frame of a larger data chunk + case EIscConcatenationDataStart: + { + // check whether the whole data amount will fit into the user buffer + if ( desMaxLen >= ( desLen + aInfo.writeLength ) && desMaxLen >= totalLength ) + { + // create a temporary descriptor for writing since we're + // necessary not writing the whole contents of the + // source descriptor, only the part that ISC Multiplexer + // wants + TPtr8 writePtr( ( TUint8* )( aPtr->Ptr() + aInfo.writeStartIndex ), + aInfo.writeLength, + aInfo.writeLength ); + + // start writing the data at offset 0 since this is the first frame + TInt r = ThreadWrite( iDataReceiveBufPtr, &writePtr, 0 ); + + // remove the pointer from queue and release the memory block + // but only if the ThreadWrite was successfull + // we do not complete the user request until EIscConcatenationDataEnd + if ( r == KErrNone ) + { + iDataFrameRxQueue->DeleteFirst(); + iIscDevice->ReleaseMemoryBlock( aPtr ); + } + else + { + C_TRACE( ( _T( "DIscChannel::HandleConcatenatedDataFrame() ThreadWrite %d" ), r ) ); + TRACE_ASSERT_ALWAYS; + CompleteRequest( EIscAsyncDataReceive, KErrWrite ); + } + } + else // buffer too small + { + TRACE_ASSERT( totalLength >= ( desLen + aInfo.writeLength ) ); + TPtr8 tempLenDes( ( TUint8* )&totalLength, sizeof ( TUint16 ), sizeof ( TUint16 ) ); + TInt r = ThreadWrite ( ( TAny* )iNeededDataBufLen, &tempLenDes, 0 ); + TRACE_ASSERT( r == KErrNone ); + if ( r != KErrNone ) + { + C_TRACE( ( _T( "DIscChannel::HandleConcatenatedDataFrame() data start KErrNoMemory ThreadWrite %d" ), r ) ); + } + + CompleteRequest( EIscAsyncDataReceive, KErrNoMemory ); + } + break; + } + case EIscConcatenationData: + case EIscConcatenationDataEnd: + { + // check whether the next frame fits to the remaining buffer + if ( ( desMaxLen - desLen ) >= aInfo.writeLength ) + { + // create a temporary descriptor for writing since we're + // necessary not writing the whole contents of the + // source descriptor, only the part that ISC Multiplexer + // wants + TPtr8 writePtr( ( TUint8* )( aPtr->Ptr() + aInfo.writeStartIndex ), + aInfo.writeLength, + aInfo.writeLength ); + + // start writing the data at offset desLen + TInt r = ThreadWrite( iDataReceiveBufPtr, &writePtr, desLen ); + TRACE_ASSERT( r == KErrNone ); + // remove the pointer from queue and release the memory block + // but only if the ThreadWrite was successfull + if ( r == KErrNone ) + { + iDataFrameRxQueue->DeleteFirst(); + iIscDevice->ReleaseMemoryBlock( aPtr ); + } + else + { + C_TRACE( ( _T( "DIscChannel::HandleConcatenatedDataFrame() data ThreadWrite %d" ), r ) ); + } + + // complete client request if the frame was the last one + if ( aInfo.concatenation == EIscConcatenationDataEnd ) + { + if ( r == KErrNone ) + { + CompleteRequest( EIscAsyncDataReceive, KErrNone ); + } + else + { + CompleteRequest( EIscAsyncDataReceive, KErrWrite ); + } + } + } + else + { + CompleteRequest( EIscAsyncDataReceive, KErrUnderflow ); + } + break; + } + default: + { + ASSERT_RESET_ALWAYS( 0,"IscDriver",EIscNotAllowedCallToDoCancel ); + break; + } + } + } + +// ----------------------------------------------------------------------------- +// DIscChannel::HandleConcatenatedFrame +// Copies several frames to clients buffer if needed before compliting receive request +// ( other items were commented in a header ). +// ----------------------------------------------------------------------------- +// +void DIscChannel::HandleConcatenatedFrame( TDes8* aPtr, TIscFrameInfo& aInfo ) + { + C_TRACE( ( _T( "DIscChannel::HandleConcatenatedFrame(0x%x, 0x%x) channelPtr 0x%x" ), aPtr, &aInfo, this ) ); + TInt desMaxLen( 0 ); + TInt desLen( 0 ); + TUint16 totalLength( 0 ); + + desMaxLen = Kern::ThreadGetDesMaxLength( iThread, iReceiveBufPtr ); + desLen = Kern::ThreadGetDesLength( iThread, iReceiveBufPtr ); + + if ( aInfo.totalLength > 0 ) + { + totalLength = aInfo.totalLength; + } + else + { + totalLength = desMaxLen; + } + switch ( aInfo.concatenation ) + { + // first frame of a larger data chunk + case EIscConcatenationDataStart: + { + // check whether the whole data amount will fit into the user buffer + if ( desMaxLen >= ( desLen + aInfo.writeLength ) && desMaxLen >= totalLength ) + { + // create a temporary descriptor for writing since we're + // necessary not writing the whole contents of the + // source descriptor, only the part that ISC Multiplexer + // wants + TPtr8 writePtr( ( TUint8* )( aPtr->Ptr() + aInfo.writeStartIndex ), + aInfo.writeLength, + aInfo.writeLength ); + + // start writing the data at offset 0 since this is the first frame + TInt r = ThreadWrite( iReceiveBufPtr, &writePtr, 0 ); + TRACE_ASSERT( r == KErrNone ); + + // remove the pointer from queue and release the memory block + // but only if the ThreadWrite was successfull + // we do not complete the user request until EIscConcatenationDataEnd + if ( r == KErrNone ) + { + iFrameRxQueue->DeleteFirst(); + iIscDevice->ReleaseMemoryBlock( aPtr ); + } + else + { + C_TRACE( ( _T( "DIscChannel::HandleConcatenatedFrame() ThreadWrite %d" ), r ) ); + CompleteRequest( EIscAsyncReceive, KErrWrite ); + } + } + else // buffer too small + { + TRACE_ASSERT( totalLength >= ( desLen + aInfo.writeLength ) ); + TPtr8 tempLenDes( ( TUint8* )&totalLength, sizeof ( TUint16 ), sizeof ( TUint16 ) ); + TInt r = ThreadWrite ( ( TAny* )iNeededBufLen, &tempLenDes, 0 ); + TRACE_ASSERT( r == KErrNone ); + if ( r != KErrNone ) + { + C_TRACE( ( _T( "DIscChannel::HandleConcatenatedFrame() ThreadWrite %d" ), r ) ); + } + + CompleteRequest( EIscAsyncReceive, KErrNoMemory ); + } + break; + } + case EIscConcatenationData: + case EIscConcatenationDataEnd: + { + // check whether the next frame fits to the remaining buffer + if ( ( desMaxLen - desLen ) >= aInfo.writeLength ) + { + // create a temporary descriptor for writing since we're + // necessary not writing the whole contents of the + // source descriptor, only the part that ISC Multiplexer + // wants + TPtr8 writePtr( ( TUint8* )( aPtr->Ptr() + aInfo.writeStartIndex ), + aInfo.writeLength, + aInfo.writeLength ); + + // start writing the data at offset desLen + TInt r = ThreadWrite( iReceiveBufPtr, &writePtr, desLen ); + + if ( r != KErrNone ) + { + C_TRACE( ( _T( "DIscChannel::HandleConcatenatedFrame() ThreadWrite %d" ), r ) ); + } + // remove the pointer from queue and release the memory block + // but only if the ThreadWrite was successfull + if ( r == KErrNone ) + { + iFrameRxQueue->DeleteFirst(); + iIscDevice->ReleaseMemoryBlock( aPtr ); + } + + // complete client request if the frame was the last one + if ( aInfo.concatenation == EIscConcatenationDataEnd ) + { + if ( r == KErrNone ) + { + CompleteRequest( EIscAsyncReceive, KErrNone ); + } + else + { + CompleteRequest( EIscAsyncReceive, KErrWrite ); + } + } + } + else + { + CompleteRequest( EIscAsyncDataReceive, KErrUnderflow ); + } + break; + } + default: + { + ASSERT_RESET_ALWAYS( 0,"IscDriver",EIscUnknownCommand ); + break; + } + } + + } + +// ----------------------------------------------------------------------------- +// DIscChannel::CopyFromUserBuffer +// Copy data from user-thread memory space. +// ( other items were commented in a header ). +// ----------------------------------------------------------------------------- +// +TInt DIscChannel::CopyFromUserBuffer( + const TDesC8& aUserBuffer, + TDes8& aKernelBuffer, + const TInt aOffset ) + { + C_TRACE( ( _T( "DIscChannel::CopyFromUserBuffer(0x%x, 0x%x, 0x%x) channelPtr 0x%x" ), &aUserBuffer, &aKernelBuffer, aOffset, this ) ); + return Kern::ThreadDesRead( iThread, ( TAny* )&aUserBuffer, aKernelBuffer, aOffset, KChunkShiftBy0 ); + + } + +// ----------------------------------------------------------------------------- +// DIscChannel::ThreadWrite +// Writes data/frames to clients buffer +// ( other items were commented in a header ). +// ----------------------------------------------------------------------------- +// +TInt DIscChannel::ThreadWrite( + TAny* dest, + const TDesC8* src, + const TInt aOffset ) + { + C_TRACE( ( _T( "DIscChannel::ThreadWrite(0x%x, 0x%x, 0x%x)" ), dest, src, aOffset ) ); + C_TRACE( ( _T( "DIscChannel::ThreadWrite writeLen 0x%x" ), src->Length() ) ); + + return Kern::ThreadDesWrite( iThread, dest, *src, aOffset, iThread ); + + } + +// ----------------------------------------------------------------------------- +// DIscChannel::ResetBuffers +// Resets buffers +// ( other items were commented in a header ). +// ----------------------------------------------------------------------------- +// +void DIscChannel::ResetBuffers() + { + // Delete pending send frames + iIscDevice->CancelSending( iChannelNumber, this ); + + // Empty receive queue + if ( iFrameRxQueue ) + { + while ( !iFrameRxQueue->Empty() ) + { + TDes8* tempPtr = ( TDes8* ) iFrameRxQueue->GetFirst(); + iFrameRxQueue->DeleteFirst(); + iIscDevice->ReleaseMemoryBlock( tempPtr ); + } + } + + // Empty data receive queue + if ( iDataFrameRxQueue ) + { + while ( !iDataFrameRxQueue->Empty() ) + { + TDes8* tempPtr = ( TDes8* ) iDataFrameRxQueue->GetFirst(); + iDataFrameRxQueue->DeleteFirst(); + iIscDevice->ReleaseMemoryBlock( tempPtr ); + } + } + } + +// End of File