systemswstubs/examplecommonisc/IscDriver/src/IscDevice.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Mon, 04 Oct 2010 00:04:35 +0300
changeset 46 e1758cbb96ac
parent 0 0ce1b5ce9557
permissions -rw-r--r--
Revision: 201039 Kit: 201039

/*
* 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 <kernel.h>
#include <kern_priv.h>
#include <IscDataTransmissionBase.h>
#include <IscMultiplexerBase.h>

#include "IscMainRcvBuffer.h"
#include "IscQueue.h"
#include "IscSendQueue.h"
#include "IscDevice.h"
#include "IscChannel.h"
#include "IscChannelContainer.h"
#include "IscTrace.h"

#ifdef __WINS__
#include <windows.h>
#endif


// EXTERNAL DATA STRUCTURES

// EXTERNAL FUNCTION PROTOTYPES  

// CONSTANTS
_LIT( KIscDriverName, "IscDriver" );

// MACROS

// LOCAL CONSTANTS AND MACROS
const TInt KSendDfcPriority( 4 );
const TInt KNotifyDfcPriority( 5 );
const TInt KIscInterruptLevelTwo( 2 );

// MODULE DATA STRUCTURES

// LOCAL FUNCTION PROTOTYPES

// FORWARD DECLARATIONS


DIscDataTransmissionBase* DIscDevice::iIscDataTransmissionInterface = NULL;
DIscMultiplexerBase* DIscDevice::iIscMultiplexerInterface = NULL;
DIscSendQueue* DIscDevice::iSendQueue=NULL;
DIscSendQueue* DIscDevice::iTempQueue=NULL;
DIscSendQueue* DIscDevice::iControlSendQueue=NULL;
TDfc* DIscDevice::iSendDfc = NULL;
TDfc* DIscDevice::iNotifyDfc = NULL;
TInt DIscDevice::iConnectionStatus = EIscConnectionNotOk;

#ifdef __WINS__
CRITICAL_SECTION g_IscDTBCriticalSection;
#endif

// ============================ MEMBER FUNCTIONS ===============================


// -----------------------------------------------------------------------------
// DIscDevice::DIscDevice
// C++ default constructor
// ( other items were commented in a header ).
// -----------------------------------------------------------------------------
//
EXPORT_C DIscDevice::DIscDevice()
    :DLogicalDevice(),
    iSend( NULL ),
    iTempSend( NULL ),
    iControlSend( NULL ),
    iSendFrameParameters( NULL ),
    iTempFrameParameters( NULL ),
    iControlFrameParameters( NULL ),
    iIscMainRcvBuffer( NULL )     
    {
    C_TRACE( ( _T( "DIscDevice::DIscDevice()" ) ) );

    iVersion = TVersion( KMajorVersionNumber, KMinorVersionNumber,
    KBuildVersionNumber );
    iParseMask |= KDeviceAllowUnit;
    iParseMask |= KDeviceAllowInfo;

#ifdef __WINS__
     InitializeCriticalSection( &g_IscDTBCriticalSection );
#endif 
    }

// Destructor
EXPORT_C DIscDevice::~DIscDevice()
    {
    C_TRACE( ( _T( "DIscDevice::~DIscDevice()" ) ) );

    IscChannelContainer::DeActivate();
    
    if ( iIscMainRcvBuffer )
        {
        delete iIscMainRcvBuffer;
        iIscMainRcvBuffer = NULL;
        }


    iIscDataTransmissionInterface = NULL;
    iIscMultiplexerInterface = NULL;

    delete iTempSend;
    delete iControlSend;
    delete iSendQueue;
    delete iTempQueue;
    delete iControlSendQueue;
    delete iSendDfc;
    delete iNotifyDfc;

#ifdef __WINS__
     DeleteCriticalSection( &g_IscDTBCriticalSection );
#endif
        
    }


// -----------------------------------------------------------------------------
// DIscDevice::Install
// Complete the installation of driver
// ( other items were commented in a header ).
// -----------------------------------------------------------------------------
//
TInt DIscDevice::Install()
    {
    C_TRACE( ( _T( "DIscDevice::Install()" ) ) );

    // Dfc for sending frames
    iSendDfc = new TDfc( Flush, this, Kern::DfcQue0(), KSendDfcPriority );
    iNotifyDfc = new TDfc( NotifyConnection, this, Kern::DfcQue0(), KNotifyDfcPriority );        
    ASSERT_RESET_ALWAYS( iSendDfc, "IscDriver",EIscMemoryAllocationFailure );

    //Initialize IscChannelContainer
    IscChannelContainer::Initialize();
    
    // connect to multiplexer and data transmission driver
    TInt r = InitializeLdd2LddInterface();
    if ( r != KErrNone )
        {
        TRACE_ASSERT_ALWAYS;
        return r;
        }

    return ( SetName( &KIscDriverName ) );
    }

// -----------------------------------------------------------------------------
// DIscDevice::Initialize
// Complete the initialization of driver
// ( other items were commented in a header ).
// -----------------------------------------------------------------------------
//
void DIscDevice::Initialize()
    {
    C_TRACE( ( _T( "DIscDevice::Initialize()" ) ) );

    TInt i( 0 );

    // Get buffer configuration data from multiplexer
    TIscConfiguration configData;
    iIscMultiplexerInterface->GetConfiguration( configData );

    // Create main buffer  
    iIscMainRcvBuffer = new DIscMainRcvBuffer( this, configData.mainRcvQueueSize );
    ASSERT_RESET_ALWAYS( iIscMainRcvBuffer, "IscDriver",EIscMemoryAllocationFailure );
    
    // Do second phase installation    
    iIscMainRcvBuffer->DoCreate();
    
    // Create queue for sending frames
    iSend = new TUint32*[configData.channelSendQueueSize];
    ASSERT_RESET_ALWAYS( iSend, "IscDriver",EIscMemoryAllocationFailure );
    
    iSendFrameParameters = new TIscSendFrameInfo*[configData.channelSendQueueSize];
    for ( i = 0; i < configData.channelSendQueueSize; i++ )
        {
        iSendFrameParameters[i] = new TIscSendFrameInfo;
        }
    ASSERT_RESET_ALWAYS( iSendFrameParameters, "IscDriver",EIscMemoryAllocationFailure );

    iSendQueue = new DIscSendQueue( iSend, iSendFrameParameters, configData.channelSendQueueSize );
    ASSERT_RESET_ALWAYS( iSendQueue, "IscDriver",EIscMemoryAllocationFailure );


    // create temporary queue
    iTempSend = new TUint32*[configData.channelSendQueueSize];
    ASSERT_RESET_ALWAYS( iTempSend, "IscDriver",EIscMemoryAllocationFailure );

    iTempFrameParameters = new TIscSendFrameInfo*[configData.channelSendQueueSize];
    for ( i =0; i < configData.channelSendQueueSize; i++ )
        {
        iTempFrameParameters[i] = new TIscSendFrameInfo;
        }
    ASSERT_RESET_ALWAYS( iTempFrameParameters, "IscDriver",EIscMemoryAllocationFailure );

    iTempQueue = new DIscSendQueue( iTempSend, iTempFrameParameters, configData.channelSendQueueSize );
    ASSERT_RESET_ALWAYS( iTempQueue, "IscDriver",EIscMemoryAllocationFailure );


    // Create send queue for control channel
    iControlSend = new TUint32*[configData.channelSendQueueSize];
    ASSERT_RESET_ALWAYS( iControlSend, "IscDriver",EIscMemoryAllocationFailure );

    iControlFrameParameters = new TIscSendFrameInfo*[configData.channelSendQueueSize];
    for ( i = 0; i < configData.channelSendQueueSize; i++ )
        {
        iControlFrameParameters[i] = new TIscSendFrameInfo;
        }
    ASSERT_RESET_ALWAYS( iControlFrameParameters, "IscDriver",EIscMemoryAllocationFailure );

    iControlSendQueue = new DIscSendQueue( iControlSend, iControlFrameParameters, configData.channelSendQueueSize );
    ASSERT_RESET_ALWAYS( iControlSendQueue, "IscDriver",EIscMemoryAllocationFailure );
    
    iIscDataTransmissionInterface->AllocBuffers( configData.bufferConfig );
    
    iConnectionStatus = iIscDataTransmissionInterface->ConnectionStatus();

    iIscMultiplexerInterface->NotifyConnectionStatus( iConnectionStatus );
    C_TRACE( ( _T( "DIscDevice::Initialize - return void" ) ) );
    }
// -----------------------------------------------------------------------------
// DIscDevice::GetCaps
// 
// ( other items were commented in a header ).
// -----------------------------------------------------------------------------
//
EXPORT_C void DIscDevice::GetCaps( 
    TDes8& /*aDes*/ ) const
    {
    // GetCaps implemented to keep compiler happy
    }

// -----------------------------------------------------------------------------
// DEcsDevice::Create
// From DLogicalDevice
// ( other items were commented in a header ).
// -----------------------------------------------------------------------------
//
TInt DIscDevice::Create( 
    DLogicalChannelBase*& aChannel )
    {
    aChannel=new DIscChannel( this );
    return aChannel?KErrNone:KErrNoMemory;
    }

// -----------------------------------------------------------------------------
// DIscDevice::Receive
// Frames coming from Domestic OS
// ( other items were commented in a header ).
// -----------------------------------------------------------------------------
//
EXPORT_C void DIscDevice::Receive( 
    TDesC8* aData ) const
    {
    DIscMainRcvBuffer::MsgReceive( aData );
    }


// -----------------------------------------------------------------------------
// DIscDevice::ReserveMemoryBlock
// Get message block from buffers allocated in IscDataTransmissionBase.dll
// ( other items were commented in a header ).
// -----------------------------------------------------------------------------
//
EXPORT_C void DIscDevice::ReserveMemoryBlock( TDes8*& aPtr, TUint16 aSize )
    {
    iIscDataTransmissionInterface->ReserveMemoryBlock( aPtr, aSize );
    }

// -----------------------------------------------------------------------------
// DIscDevice::ReleaseMemoryBlock
// Release memory block allocated with ReserveMemoryBlock
// ( other items were commented in a header ).
// -----------------------------------------------------------------------------
//
EXPORT_C void DIscDevice::ReleaseMemoryBlock( 
    TDes8* aPtr )
    {
    C_TRACE( ( _T( "DIscDevice::ReleaseMemoryBlock(0x%x)" ), aPtr ) );

    if ( iIscDataTransmissionInterface )
        {
        iIscDataTransmissionInterface->ReleaseMemoryBlock( aPtr );
        }
    }

// -----------------------------------------------------------------------------
// DIscDevice::NotifyConnectionStatus
// Connection status change function
// ( other items were commented in a header ).
// -----------------------------------------------------------------------------
//
EXPORT_C void DIscDevice::NotifyConnectionStatus( const TInt aStatus )
    {
    C_TRACE( ( _T( "DIscDevice::NotifyConnectionStatus(0x%x)" ), aStatus ) );
    if ( iConnectionStatus != aStatus )
        {
        iConnectionStatus = aStatus;
		if ( NKern::CurrentContext() == NKern::EInterrupt )
			{
			iNotifyDfc->Add();
			}
		else
			{
		    iNotifyDfc->Enque();
		    }
        }
        
    C_TRACE( ( _T( "DIscDevice::NotifyConnectionStatus() return" ) ) );    
    }

// -----------------------------------------------------------------------------
// DIscDevice::NotifyConnection
// Connection status change DFC function.
// ( other items were commented in a header ).
// -----------------------------------------------------------------------------
//
void DIscDevice::NotifyConnection( TAny* )
    {
    C_TRACE( ( _T( "DIscDevice::NotifyConnection(0x%x)" ), iConnectionStatus ) );
    
    iIscMultiplexerInterface->NotifyConnectionStatus( iConnectionStatus );
    DIscChannel* tempPtr = NULL;
    for ( TUint16 i = KIscFirstChannel; i < KIscNumberOfUnits; i++ )
        {
        for ( TUint16 ii( 0 ); ii < KIscMaxNumberOfChannelSharers; ii++ )
            {
            tempPtr = IscChannelContainer::Channel( i, ii );
            if ( tempPtr )
                { 
                tempPtr->NotifyConnectionStatus( iConnectionStatus );
                tempPtr = NULL;
                }
            }
        }
    C_TRACE( ( _T( "DIscDevice::NotifyConnection() return" ) ) );

    }

// -----------------------------------------------------------------------------
// DIscDevice::ULFlowControl
// Function to notify client about uplink flow control status
// ( other items were commented in a header ).
// -----------------------------------------------------------------------------
//
EXPORT_C void DIscDevice::ULFlowControl( 
    const TInt aULFlowStatus,
    const TUint16 aChannelId,
    const TAny* aChannelPtr )
    {
    C_TRACE( ( _T( "DIscDevice::ULFlowControl(0x%x, 0x%x, 0x%x)" ), aULFlowStatus, aChannelId, aChannelPtr ) );

    DIscChannel* tempPtr = NULL;
    TBool channelFound(EFalse);

    if ( !aChannelPtr )
        {
        // All channels.
        for ( TUint16 i(0); i < KIscMaxNumberOfChannelSharers; i++ )
            {
            tempPtr = IscChannelContainer::Channel( aChannelId, i );
            if ( tempPtr )
                {
                tempPtr->NotifyFlowControl( aULFlowStatus );
                tempPtr = NULL;
                channelFound = ETrue;
                }
            else
            	{
            	//Do nothing	
            	}
            }
        }
    else
        {
        // Single channel.
        for ( TUint16 i(0); i < KIscMaxNumberOfChannelSharers; i++ )
            {
            tempPtr = IscChannelContainer::Channel( aChannelId, i );
            if ( tempPtr == ( DIscChannel* )aChannelPtr )
                {
                tempPtr->NotifyFlowControl( aULFlowStatus );
                tempPtr = NULL;
                channelFound = ETrue;
                break;
                }
            else
            	{
            	//Do nothing	
            	}                
            }            
        }

    if ( channelFound == EFalse )
        TRACE_ASSERT_ALWAYS;
    
    }

// -----------------------------------------------------------------------------
// DIscDevice::IsPending
// Function to check if asycnhronous request is active
// ( other items were commented in a header ).
// -----------------------------------------------------------------------------
//
EXPORT_C TInt DIscDevice::IsPending( 
    const TUint16 aReqNumber, 
    const TAny* aChannelPtr )
    {
    C_TRACE( ( _T( "DIscDevice::IsPending(0x%x, 0x%x)" ), aReqNumber, aChannelPtr ) );

    DIscChannel* tempPtr = ( DIscChannel* )aChannelPtr;
    TInt error = IscChannelContainer::ValidateChannel( tempPtr );
    if( error == KErrNone )
    	{
    	error = tempPtr->IsPending( aReqNumber );
    	}
    C_TRACE( ( _T( "DIscDevice::IsPending - return %d" ), error ) );	
   	return error;

    }

// -----------------------------------------------------------------------------
// DIscDevice::DLFlowControl
// Notify multiplexer about down link flow control
// ( other items were commented in a header ).
// -----------------------------------------------------------------------------
//
void DIscDevice::DLFlowControlNotify( 
    const TInt aDLFlowStatus,
    const TUint16 aChannel,
    const TAny* aChannelPtr )
    {
    C_TRACE( ( _T( "DIscDevice::DLFlowControlNotify(0x%x, 0x%x)" ), aDLFlowStatus, aChannel ) );
    if ( aChannel >= KIscFirstChannel 
        && aChannel < KIscNumberOfUnits )
        {        
        if ( aDLFlowStatus == EIscFlowControlOn )
            {
            iIscMultiplexerInterface->DLFlowControl( EIscFlowControlOn, aChannel, aChannelPtr );
            }        
        else
            {
            iIscMultiplexerInterface->DLFlowControl( EIscFlowControlOff, aChannel, aChannelPtr );            
            }
        }
    else
        {
        
        if ( aChannel == 0x00 )
            {
            // control channel, no flow control used
            }
        else
            {
            // should never came here
            TRACE_ASSERT_ALWAYS;
            }
        }
    }

// -----------------------------------------------------------------------------
// DIscDevice::InitializeLdd2LddInterface
// Function to connect to DataTransmission and Multiplexer ldds
// ( other items were commented in a header ).
// -----------------------------------------------------------------------------
//
TInt DIscDevice::InitializeLdd2LddInterface()
    {
    C_TRACE( ( _T( "DIscDevice::InitializeLdd2LddInterface()" ) ) );
    
    // Find pointer to second level LDD.
    DObjectCon* lDevices = Kern::Containers()[ ELogicalDevice ];
    TKName driverName;
    ASSERT_RESET_ALWAYS( lDevices, "IscDriver", EIscLogicalDevicesNotFound );

    TInt err( KErrNone );
    //TInt driverHandle( KErrNone ); // API change in SOS9.2 WK08
	TFindHandle driverHandle;
    // Find pointer to ISC Multiplexer.
    err = lDevices->FindByName( driverHandle, KIscMultiplexerName, driverName );
    if( KErrNone != err )
        {
        C_TRACE( ( _T( "DIscDevice::InitializeLdd2LddInterface() ISC Multiplexer Not Found!" ) ) );
        ASSERT_RESET_ALWAYS( 0, "IscDriver" ,EIscMultiplexerNotFound );
        }
	
    iIscMultiplexerInterface = static_cast<DIscMultiplexerBase*>( lDevices->At( driverHandle ) );
    ASSERT_RESET_ALWAYS( iIscMultiplexerInterface, "IscDriver", EIscMultiplexerNotFound );

    //TInt secondDriverHandle( KErrNone );  // API change in SOS9.2 WK08
	TFindHandle secondDriverHandle;
    // Find pointer to Data Transmission Plugin.
    err = lDevices->FindByName( secondDriverHandle, KIscDataTransmissionDriverName, driverName );
    if( KErrNone != err )
        {
        C_TRACE( ( _T( "DIscDevice::InitializeLdd2LddInterface() Data Transmission Plug-In Not Found!" ) ) );
        ASSERT_RESET_ALWAYS( 0, "IscDriver", EIscDataTransmissionDriverNotFound );
        }

    iIscDataTransmissionInterface = static_cast<DIscDataTransmissionBase*>( lDevices->At( secondDriverHandle ) );
    ASSERT_RESET_ALWAYS( iIscDataTransmissionInterface, "IscDriver", EIscDataTransmissionDriverNotFound );
    
    iIscDataTransmissionInterface->Connect( this );
    iIscMultiplexerInterface->Connect( this );

    C_TRACE( ( _T( "DIscDevice::InitializeLdd2LddInterface - return 0x%x" ), err ) );
    return err;
    
    }

// -----------------------------------------------------------------------------
// DIscDevice::QueueFrame
// Queue frames that will be sent to Domestic OS
// ( other items were commented in a header ).
// -----------------------------------------------------------------------------
//
EXPORT_C TInt DIscDevice::QueueFrame( 
    const TUint16 aChannelId,
    const TDesC8* aFrame,
    const TAny* aChannelPtr,
    TAny* aFrameInfo )
    {
    C_TRACE( ( _T( "DIscDevice::QueueFrame(0x%x, 0x%x, 0x%x, 0x%x)" ), aChannelId, aFrame, aChannelPtr, aFrameInfo ) );
    
    TInt error = KErrNone;
    
    // control channel frame ( highest priority )
    if ( aChannelId == KIscControlChannel )
        {
        C_TRACE( ( _T( "DIscDevice::QueueFrame control frame queue" ) ) );
        //add to control frame queue
        error = iControlSendQueue->Add( ( TDes8* )aFrame, aChannelId, ( DIscChannel* )aChannelPtr, aFrameInfo );
        }
    else
        {        
        C_TRACE( ( _T( "DIscDevice::QueueFrame send queue" ) ) );
        // add to send queue
        error = iSendQueue->Add( ( TDes8* )aFrame, aChannelId, ( DIscChannel* )aChannelPtr, aFrameInfo );
        }
    
    C_TRACE( ( _T( "DIscDevice::QueueFrame - return 0x%x" ), error ) );
    return error;
    }


// -----------------------------------------------------------------------------
// DIscDevice::CancelSending
// Cancels sending of frames to Domestic OS
// ( other items were commented in a header ).
// -----------------------------------------------------------------------------
//
EXPORT_C TInt DIscDevice::CancelSending( const TUint16 aChannelId, const TAny* aChannelPtr )
    {
    C_TRACE( ( _T( "DIscDevice::CancelSending - Caller is channel: %d (0x%x)" ), aChannelId, aChannelPtr ) );
    
    TInt error( KErrNotFound );
    TInt irqLevel( 0 );

    TInt counterA( 0 );
    TInt counterB( 0 );

    TIscSendFrameInfo* temp = NULL;
    TDes8* frame = NULL;

    irqLevel = DisableIrqs();

    if ( KIscControlChannel == aChannelId )
        {
        // empty control send queue
        while ( !iControlSendQueue->Empty() )
            {
            temp = iControlSendQueue->GetFirstFrameInfo();
            frame = ( TDes8* )iControlSendQueue->RemoveFirst();
            if ( temp && frame )
                {
                if ( temp->iChannelId == aChannelId && 
                     temp->iChannelPtr == ( DIscChannel* )aChannelPtr )
                    {
                    // sender found, no need to store the frame
                    counterB++;
                    }
                else
                    {
                    iTempQueue->Add( frame, temp->iChannelId, temp->iChannelPtr, temp->iFrameInfo );
                    }
                }
            else
                {
                // should never came here
                TRACE_ASSERT_ALWAYS;
                }
            counterA++;
            temp = NULL;
            frame = NULL;
            }  
        
        while ( !iTempQueue->Empty() )
            {
            temp = iTempQueue->GetFirstFrameInfo();
            frame = ( TDes8* )iTempQueue->RemoveFirst();
            if ( temp && frame )
                {
                iControlSendQueue->Add( frame, temp->iChannelId, temp->iChannelPtr, temp->iFrameInfo );
                }
            else
                {
                // should never came here
                TRACE_ASSERT_ALWAYS;
                }
            temp = NULL;
            frame = NULL;
            }
        }
    else
        {
        // empty normal send queue
        while ( !iSendQueue->Empty() )
            {
            temp = iSendQueue->GetFirstFrameInfo();
            frame = ( TDes8* )iSendQueue->RemoveFirst();
            if ( temp && frame )
                {
                if ( temp->iChannelId == aChannelId  && 
                     temp->iChannelPtr == ( DIscChannel* )aChannelPtr )            
                    {
                    // sender found, no need to store frame
                    counterB++;                
                    }
                else
                    {
                    iTempQueue->Add( frame, temp->iChannelId, temp->iChannelPtr, temp->iFrameInfo );
                    }
                }
            else
                {
                // should never came here
                TRACE_ASSERT_ALWAYS;
                }
            counterA++;
            temp = NULL;
            frame = NULL;
            }  

        while ( !iTempQueue->Empty() )
            {
            temp = iTempQueue->GetFirstFrameInfo();
            frame = ( TDes8* )iTempQueue->RemoveFirst();
            if ( temp && frame )
                {
                iSendQueue->Add( frame, temp->iChannelId, temp->iChannelPtr, temp->iFrameInfo );
                }
            else
                {
                // should never came here
                TRACE_ASSERT_ALWAYS;
                }

            temp = NULL;
            frame = NULL;
            }
        }
        
    RestoreIrqs( irqLevel );

    C_TRACE( ( _T( "DIscDevice::CancelSending() - Frames in queue: Before: %d, After: %d" ), counterA, ( counterA-counterB ) ) );
    C_TRACE( ( _T( "DIscDevice::CancelSending() - So channel 0x%x 0x%x had %d pending messages!" ), aChannelId, aChannelPtr, counterB ) );

    // if there weren't any frames that were cancelled return KErrNotFound, otherwise return KErrNone
    if ( counterB > 0 )
        {        
        error = KErrNone;
        }
    
    return error;

    }
 
// -----------------------------------------------------------------------------
// DIscDevice::FlushQueues
// Adds Dfc to empty queues
// ( other items were commented in a header ).
// -----------------------------------------------------------------------------
//
EXPORT_C void DIscDevice::FlushQueues()
    {
    C_TRACE( ( _T( "DIscDevice::FlushQueues()" ) ) );
 
    if ( NKern::CurrentContext() == NKern::EInterrupt )
		{
		iSendDfc->Add();
		}
	else
		{
	    iSendDfc->Enque();
	    }

    }

// -----------------------------------------------------------------------------
// DIscDevice::CompleteRequest
// Function to complete user side asynchronous request
// ( other items were commented in a header ).
// -----------------------------------------------------------------------------
//
// This method has been modified to allow channel sharing between application.
// The completion routine uses directly a pointer on a DLogicalChannel instead of a channel index
//
EXPORT_C void DIscDevice::CompleteRequest( 
    TUint16 aOperation, 
    TInt aCompleteStatus,
    const TAny* aChannelPtr )
    {
    C_TRACE( ( _T( "DIscDevice::CompleteRequest(0x%x, 0x%x, 0x%x)" ), aOperation, aCompleteStatus, aChannelPtr ) ); 

    DIscChannel* tempPtr = ( DIscChannel* )aChannelPtr;
    TInt error = IscChannelContainer::ValidateChannel( tempPtr );
    if( error == KErrNone )
    	{
    	tempPtr->CompleteRequest( aOperation, aCompleteStatus );
    	}	

    C_TRACE( ( _T( "DIscDevice::CompleteRequest - return void" ) ) );
    }

// -----------------------------------------------------------------------------
// DIscDevice::CopyFromUserBuffer
// 
// ( other items were commented in a header ).
// -----------------------------------------------------------------------------
//
EXPORT_C TInt DIscDevice::CopyFromUserBuffer( 
    const TDesC8& aUserBuffer, 
    TDes8& aKernelBuffer, 
    const TAny* aChannelPtr,
    const TInt aOffset )
    {
    C_TRACE( ( _T( "DIscDevice::CopyFromUserBuffer(0x%x, 0x%x, 0x%x, 0x%x)" ), &aUserBuffer, &aKernelBuffer, aChannelPtr, aOffset ) );

    // Check if channel pointer is valid.
    DIscChannel* tempPtr = ( DIscChannel* )aChannelPtr;
    TInt error = IscChannelContainer::ValidateChannel( tempPtr );
    if( error == KErrNone )
    	{
    	error = tempPtr->CopyFromUserBuffer( aUserBuffer, aKernelBuffer, aOffset );	
    	}
    C_TRACE( ( _T( "DIscDevice::CopyFromUserBuffer - return %d" ), error ) );	
   	return error;
    
    }

// -----------------------------------------------------------------------------
// DIscDevice::CopyToUserBuffer
// 
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
EXPORT_C TInt DIscDevice::CopyToUserBuffer( 
    TAny* aUserBuffer, 
    const TDesC8& aKernelBuffer, 
    const TAny* aChannelPtr,
    const TInt aOffset )
    {
    C_TRACE( ( _T( "DIscDevice::CopyToUserBuffer(0x%x, 0x%x, 0x%x)" ), aUserBuffer, &aKernelBuffer, aChannelPtr ) );
    
    DIscChannel* tempPtr = ( DIscChannel* )aChannelPtr;
    TInt error = IscChannelContainer::ValidateChannel( tempPtr );
    if( KErrNone == error )
    	{
    	error = tempPtr->ThreadWrite( aUserBuffer, &aKernelBuffer, aOffset );
    	}
    C_TRACE( ( _T( "DIscDevice::CopyToUserBuffer - return %d" ), error ) );	
   	return error;

    }

// -----------------------------------------------------------------------------
// DIscMultiplexerBase::GetThreadPtr
// Returns user side thread. Ownership is not given.
// ( other items were commented in a header ).
// -----------------------------------------------------------------------------
//
EXPORT_C DThread* DIscDevice::GetThreadPtr( const TAny* aChannelPtr )
	{
	C_TRACE( ( _T( "DIscMultiplexerBase::GetThreadPtr(0x%x)" ), aChannelPtr ) );
    DIscChannel* tempPtr = ( DIscChannel* )aChannelPtr;
    TInt error = IscChannelContainer::ValidateChannel( tempPtr );
	DThread* tmp = NULL;
	if( KErrNone == error )
		{
		tmp = tempPtr->GetDThread();	
		}
	else
		{
		C_TRACE( ( _T( "DIscMultiplexerBase::GetThreadPtr failed return NULL" ) ) );	    				
		}
	C_TRACE( ( _T( "DIscMultiplexerBase::GetThreadPtr return 0x%x" ), tmp ) );	    	
   	return tmp;
   		
	}
    
// -----------------------------------------------------------------------------
// DIscDevice::Flush
// Dfc to empty control channel and other send queues
// ( other items were commented in a header ).
// -----------------------------------------------------------------------------
//
void DIscDevice::Flush( TAny* aPtr )
    {
    C_TRACE( ( _T( "DIscDevice::Flush(0x%x)" ), aPtr ) );
    DIscDevice* device = ( DIscDevice* )aPtr;

    TDes8* frame = NULL;
    TIscSendFrameInfo* temp = NULL;

    TInt irqLevel(0);

    // If transmission is asynchronous and there can't be
    // several requests at the same time
    if ( !iIscDataTransmissionInterface->IsWritePending() )
        {
        irqLevel = DisableIrqs();
        if ( !iControlSendQueue->Empty() )
            {
            temp = iControlSendQueue->GetFirstFrameInfo();
            frame = ( TDes8* )iControlSendQueue->RemoveFirst();
            }
        else
            {
            temp = iSendQueue->GetFirstFrameInfo();
            frame = ( TDes8* )iSendQueue->RemoveFirst();
            }
        RestoreIrqs( irqLevel );
        C_TRACE( ( _T( "DIscDevice::Flush after RESTOREIRQS" ) ) );    
        if ( frame )    
            iIscDataTransmissionInterface->SendFrame( *frame, device->iSendDfc, temp->iFrameInfo );
        }
    C_TRACE( ( _T( "DIscDevice::Flush - return 0x0" ) ) );

    }


// -----------------------------------------------------------------------------
// DIscDevice::ConnectionStatus
// Function to tell current status of connection to Domestic OS
// ( other items were commented in a header ).
// -----------------------------------------------------------------------------
//
TInt DIscDevice::ConnectionStatus()
    {
    return iConnectionStatus;
    }

// -----------------------------------------------------------------------------
// DIscDevice::DisableIrqs
// Function to disable interrupts
// ( other items were commented in a header ).
// -----------------------------------------------------------------------------
//
TInt DIscDevice::DisableIrqs()
    {
#ifndef __WINS__
    return NKern::DisableInterrupts( KIscInterruptLevelTwo );
#else //__WINS__
    EnterCriticalSection( &g_IscDTBCriticalSection );
    return KErrNone;
#endif//__WINS__
    }

// -----------------------------------------------------------------------------
// DIscDevice::RestoreIrqs
// Function to restore interrupts
// ( other items were commented in a header ).
// -----------------------------------------------------------------------------
//
#ifndef __WINS__
void DIscDevice::RestoreIrqs( 
    TInt aLevel )
    {
    NKern::RestoreInterrupts( aLevel );
    
#else //__WINS__
void DIscDevice::RestoreIrqs( 
    TInt )
	{
    LeaveCriticalSection( &g_IscDTBCriticalSection );
#endif//__WINS__
    }


// ========================== OTHER EXPORTED FUNCTIONS =========================

// -----------------------------------------------------------------------------
// E32Dll
// Epoc Kernel Architecture 2 style entry point
// ( other items were commented in a header ).
// -----------------------------------------------------------------------------
//
DECLARE_STANDARD_LDD()
    {
    DLogicalDevice* device = new DIscDevice;
    if ( !device )
        {
        ASSERT_RESET_ALWAYS( 0,"IscDriver",EIscPanicCreateLogicalDevice );
        }
    return device;
    }

//  End of File