/*
* 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 <kern_priv.h>
#include <IscDataTransmissionBase.h>
#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<TPtr8*>( tablePtr[ KSecondParam ] );
iIscRequests[ EIscAsyncNotifyFlowControlStatus ] = reinterpret_cast<TRequestStatus*>( 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<TUint8*>( &iULFlowControlStatus ), sizeof ( TInt ), sizeof ( TInt ) );
iLastNotifiedULFlowstatus = aFlowControlStatus;
TInt r = ThreadWrite( static_cast<TAny*>( 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