//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// Use of this sample source code is subject to the terms of the Microsoft
// license agreement under which you licensed this sample source code. If
// you did not accept the terms of the license agreement, you are not
// authorized to use this sample source code. For the terms of the license,
// please see the license agreement between you and Microsoft or, if applicable,
// see the LICENSE.RTF on your install media or the root of your tools installation.
// THE SAMPLE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES.
//
/*++
THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
PARTICULAR PURPOSE.

Module Name:

pccard.cpp

Abstract:

This file implements the PCMCIA model device driver initialization functions
This is provided as a sample to platform writers and is
expected to be able to be used without modification on most (if not
all) hardware platforms.

Functions:


Notes:


--*/
#include <windows.h>
#include <types.h>
#include "cardsv2.h"
#include "socksv2.h"
#include <ceddk.h>
#include <debug.h>
#include "PCCard.h"
#include "PCclient.h"
#include <CeBus.h>
#include <defbus.h>

CPCCardContainer* CPCCardContainer::g_pCardContainer = NULL;

DWORD CPCCard::g_dwCardRef = 0;
CPCCard::CPCCard( PSS_SOCKET_SERVICE pSocketService,
                  PSS_SOCKET_STATE pSocketState,
                  HANDLE hSocket,
                  UINT16 uSocket,
                  HANDLE hBusHandle,
                  CPCCard* pPFunction,
                  UINT uFunction ) : m_pPFunction( pPFunction ),
                                     m_hBusDriver( hBusHandle )
{
    if( pSocketService )
    {
        m_SocketService = *pSocketService;
    }
    else
    {
        DEBUGCHK( FALSE );
        memset( &m_SocketService, 0, sizeof( SS_SOCKET_SERVICE ) );
    }
    m_hCardHandle.uSocket = 0 ;
    if( m_pPFunction != NULL )
    {
        m_pPFunction->AddRef();
        m_hCardHandle = pPFunction->GetCardHandle();
        m_hCardHandle.uFunction = ( UINT8 ) uFunction;
        DEBUGCHK( uFunction != 0 );
    }
    else
    {
        m_hCardHandle.uFunction = 0;
        while( m_hCardHandle.uSocket == 0 )
        {
            // We do not allow zero reference so do it again.
            m_dwCardRef = ( DWORD )
                          InterlockedIncrement( ( LONG * ) &g_dwCardRef );
            m_hCardHandle.uSocket = ( UINT8 ) m_dwCardRef;
            // Make sure there is no one use this index.
            CPCCard* pCard = CPCCardContainer::g_pCardContainer->FoundObjectBy( NULL,
                                                                                m_hCardHandle );
            if( pCard )
            {
                // Found it, We can not use this one.
                m_hCardHandle.uSocket = 0;
                pCard->DeRef();
            }
        }
    }
    m_hClient = NULL;
    // Create Bus Name
    _stprintf( m_lpDeviceBusName,
               TEXT( "%s_%d_%d_%d" ),
               DEVICE_BUSNAME_PREFIX,
               0,
               uSocket,
               uFunction );
    m_lpDeviceBusName[sizeof( m_lpDeviceBusName ) / sizeof( TCHAR ) - 1] = 0;

    m_uFunction = m_hCardHandle.uFunction;
    m_hSocket = hSocket;
    m_uSocket = uSocket;
    m_cePowerState = D0;
    STATUS status = PDCardInquireSocket( &m_SocketInfo );
    DEBUGCHK( status == CERR_SUCCESS );
    status = PDCardGetSocket( &m_BackupState );
    DEBUGCHK( status == CERR_SUCCESS );
    m_pssPowerEntry = NULL;
    if( status == CERR_SUCCESS )
    {
        m_pssPowerEntry = new SS_POWER_ENTRY[m_SocketInfo.dwNumOfPowerEntry];
        if( m_pssPowerEntry != NULL )
        {
            DWORD dwNumOfEntry = m_SocketInfo.dwNumOfPowerEntry; 
            if( PDCardGetPowerEntry( &dwNumOfEntry, m_pssPowerEntry ) ==
                CERR_SUCCESS )
            {
                m_SocketInfo.dwNumOfPowerEntry = dwNumOfEntry;
            }
            else
            {
                delete m_pssPowerEntry;
                m_pssPowerEntry = NULL;
                DEBUGCHK( FALSE );
            }
        }
    }
    for( UINT uFuncIndex = 0; uFuncIndex < MAX_FUNCTION_CARD; uFuncIndex++ )
    {
        m_cardPowerState[uFuncIndex] = D4;
        m_bCardFlag[uFuncIndex] = 0xff;
    }
    // Set this card Function to D0.
    if( m_pPFunction != NULL )
    {
        m_pPFunction->SetPowerStateGlobal( D0, m_uFunction );
        m_pPFunction->SetPCCardFlag( 0, TRUE, m_uFunction );
    }
    else
    {
        m_cardPowerState[0] = D0;
        m_bCardFlag[0] = 0;
    }
}
BOOL CPCCard::Init( BOOL /*bScanBus*/ )
{
    EventNotification( CE_CARD_BUS_INFO,
                       ( UINT32 ) m_hBusDriver,
                       ( UINT32 ) m_lpDeviceBusName );
    return TRUE;
}

CPCCard::~CPCCard()
{
    // Delete all the other function card here.
    EventNotification( CE_CARD_REMOVAL );
    Lock();
    if( m_uFunction == 0 )
    {
        // This is Root Card to this socket. Power Off the socket.
        SS_SOCKET_STATE m_SocketState;
        STATUS status = PDCardGetSocket( &m_SocketState );
        if( status == CERR_SUCCESS )
        {
            m_SocketState.fVcc = m_SocketState.uVpp1 = m_SocketState.uVpp2 = 0; // Set to  0 Volt.
            status = PDCardSetSocket( &m_SocketState );
            DEBUGCHK( status == CERR_SUCCESS );
        }
    }
    if( m_pssPowerEntry != NULL )
    {
        delete m_pssPowerEntry;
        m_pssPowerEntry = NULL;
    }
    if( m_pPFunction )
    {
        m_pPFunction->DeRef();
    }
    Unlock();
};

BYTE CPCCard::SetPCCardFlag( BYTE bFlag, BOOL bAnd, UINT uFunctionIndex )
{
    if( m_pPFunction == NULL && uFunctionIndex < MAX_FUNCTION_CARD )
    {
        Lock();
        if( bAnd )
            m_bCardFlag[uFunctionIndex] &= bFlag;
        else
            m_bCardFlag[uFunctionIndex] |= bFlag;  
        BYTE bReturnGlobalFlag = 0xff;
        for( UINT uIndex = 0; uIndex < MAX_FUNCTION_CARD; uIndex++ )
            bReturnGlobalFlag &= m_bCardFlag[uIndex];
        Unlock();
        return bReturnGlobalFlag;
    }
    else
    {
        DEBUGCHK( FALSE );
        return 0;
    }
}

STATUS CPCCard::CardDisableCard()
{
    if( GetParentFunction() != NULL )
    {
        if( ( ( GetParentFunction()->SetPCCardFlag( PCCARD_DISABLE_FLAG,
                                                    FALSE,
                                                    m_uFunction ) ) & PCCARD_DISABLE_FLAG ) !=
            0 )
        {
            return ( GetParentFunction()->CardDisableCard() );
        }
    }
    else
    {
        Lock();
        if( ( SetPCCardFlag( PCCARD_DISABLE_FLAG, FALSE, 0 ) & PCCARD_DISABLE_FLAG ) !=
            0 )
        {
            SS_SOCKET_STATE curState;
            DWORD pwrEntry = 0;
            if( ( PDCardGetSocket( &curState ) ) == CERR_SUCCESS )
            {
                if( ValidPowerEntry( PWR_SUPPLY_VCC, 0 ) && // Valid Number;
                   GetVotageEntry( &pwrEntry, 0, PWR_SUPPLY_VCC ) )
                    curState.fVcc = ( BYTE ) pwrEntry;
                if( ValidPowerEntry( PWR_SUPPLY_VPP1, 0 ) &&
                    GetVotageEntry( &pwrEntry,
                                    0,
                                    PWR_SUPPLY_VPP1 ) )
                    curState.uVpp1 = ( BYTE ) pwrEntry;
                if( ValidPowerEntry( PWR_SUPPLY_VPP2, 0 ) &&
                    GetVotageEntry( &pwrEntry,
                                    0,
                                    PWR_SUPPLY_VPP2 ) )
                    curState.uVpp2 = ( BYTE ) pwrEntry;
                PDCardSetSocket( &curState );
            }
        }
        Unlock();
    }
    return CERR_SUCCESS;
}

STATUS CPCCard::CardResetFunction()
{
    STATUS status = CERR_SUCCESS;
    SS_SOCKET_STATE SocketState;
    if( GetParentFunction() != NULL )
    {
        if( ( ( GetParentFunction()->SetPCCardFlag( PCCARD_RESET_FLAG,
                                                    FALSE,
                                                    m_uFunction ) ) & PCCARD_RESET_FLAG ) !=
            0 )
        {
            return ( GetParentFunction()->CardResetFunction() );
        }
    }
    else
    {
        Lock();
        if( ( SetPCCardFlag( PCCARD_RESET_FLAG, FALSE, 0 ) & PCCARD_RESET_FLAG ) !=
            0 )
        {
            if( ( status = PDCardGetSocket( &SocketState ) ) == CERR_SUCCESS )
            {
                SocketState.dwEventStatus |= SOCK_EVENT_EJECT |
                                             SOCK_EVENT_INSERT;
                status = PDCardSetSocket( &SocketState );
            }
        }
        Unlock();
    }
    return status;
}

BOOL CPCCard::SetPowerState( CEDEVICE_POWER_STATE ceState )
{
    if( m_cePowerState != ceState )
    {
        CEDEVICE_POWER_STATE oldState = m_cePowerState;
        Lock();
        switch( ceState )
        {
            // SetupWakeup SOurces.
          case D3:
            {
                SS_SOCKET_STATE lSocketState;
                if( PDCardGetSocket( &lSocketState ) == CERR_SUCCESS )
                {
                    lSocketState.dwEventChanged = 0; // do not reset change bit.
                    lSocketState.dwInteruptStatus |= SOCK_INT_FUNC_IRQ_WAKE |
                                                     SOCK_INT_STATUS_CHG_WAKE;
                    PDCardSetSocket( &lSocketState );
                }
                break;
            }
        }
        if( ceState == D4 )
        {
            // to of D4.
            PowerDown();
        }
        if( m_pPFunction != NULL )
            m_pPFunction->SetPowerStateGlobal( ceState, m_uFunction );
        else
            SetPowerStateGlobal( ceState, 0 );
        if( oldState == D4 )
        {
            // Out of D4
            PowerUp();
        }      
        Unlock();
        return TRUE;
    }
    return FALSE;
}
BOOL CPCCard::SetPowerStateGlobal( CEDEVICE_POWER_STATE ceState,
                                   UINT uFunctionIndex )
{
    if( m_pPFunction == NULL && uFunctionIndex < MAX_FUNCTION_CARD )
    {
        Lock();
        CEDEVICE_POWER_STATE oldState = D4;
        for( DWORD dwIndex = 0; dwIndex < MAX_FUNCTION_CARD ; dwIndex++ )
        {
            if( m_cardPowerState[dwIndex] < oldState )
            {
                oldState = m_cardPowerState[dwIndex];
            }
        }
        m_cardPowerState[uFunctionIndex] = ceState;
        CEDEVICE_POWER_STATE newState = D4;
        for( dwIndex = 0; dwIndex < MAX_FUNCTION_CARD ; dwIndex++ )
        {
            if( m_cardPowerState[dwIndex] < newState )
            {
                newState = m_cardPowerState[dwIndex];
            }
        }
        if( newState != oldState )
        {
            // Global State need to be changed.
            // Here we only can handle To D4 or From D4 So.
            SS_SOCKET_STATE curState;
            DWORD pwrEntry = 0;    
            if( newState == D4 )
            {
                // To D4 , Power Off.
                if( PDCardGetSocket( &curState ) == CERR_SUCCESS )
                {
                    m_BackupState = curState;
                    if( ValidPowerEntry( PWR_SUPPLY_VCC, 0 ) && // Valid Number;
                        GetVotageEntry( &pwrEntry, 0, PWR_SUPPLY_VCC ) )
                        curState.fVcc = ( BYTE ) pwrEntry;
                    if( ValidPowerEntry( PWR_SUPPLY_VPP1, 0 ) &&
                        GetVotageEntry( &pwrEntry,
                                        0,
                                        PWR_SUPPLY_VPP1 ) )
                        curState.uVpp1 = ( BYTE ) pwrEntry;
                    if( ValidPowerEntry( PWR_SUPPLY_VPP2, 0 ) &&
                        GetVotageEntry( &pwrEntry,
                                        0,
                                        PWR_SUPPLY_VPP2 ) )
                        curState.uVpp2 = ( BYTE ) pwrEntry;
                    curState.dwEventChanged = 0; // do not reset change bit.
                    curState.dwInteruptStatus &= ~( SOCK_INT_FUNC_IRQ_WAKE |
                                                    SOCK_INT_STATUS_CHG_WAKE );
                    PDCardSetSocket( &curState );
                }
            }
            else if( oldState == D4 )
            {
                // Out of D4.
                PDCardSetSocket( &m_BackupState );
            }
        }
        Unlock();
        return TRUE;
    }
    else
    {
        DEBUGCHK( FALSE );
        return FALSE;
    };
}

STATUS CPCCard::EventNotification( UINT32 uEvent, UINT32 Parm1, UINT32 Parm2 )
{
    DWORD dwInterfaceType = ( IsCardBusCard() ?
                              CFG_IFACE_CARDBUS :
                              ( CFG_IFACE_MEMORY | CFG_IFACE_MEMORY_IO ) );
    return CClientContainer::EventNotification( dwInterfaceType,
                                                uEvent,
                                                GetCardHandle(),
                                                Parm1,
                                                Parm2 );
}

STATUS CPCCard::PDCardInquireSocket( PSS_SOCKET_INFO pSocketInfo )
{
    STATUS status = CERR_BAD_HANDLE;
    if( m_SocketService.SS_InquireSocket != NULL )
    {
        __try
        {
            status = m_SocketService.SS_InquireSocket( GetSocketHandle(),
                                                       pSocketInfo );
        } __except( EXCEPTION_EXECUTE_HANDLER )
        {
            status = CERR_BAD_HANDLE;
        }
    }
    return status;
}
STATUS CPCCard::PDCardGetPowerEntry( PDWORD pdwNumOfEnery,
                                     PSS_POWER_ENTRY pPowerEntry )
{
    STATUS status = CERR_BAD_HANDLE;
    if( m_SocketService.SS_InquireSocket != NULL )
    {
        __try
        {
            status = m_SocketService.SS_GetPowerEntry( GetSocketHandle(),
                                                       pdwNumOfEnery,
                                                       pPowerEntry );
        } __except( EXCEPTION_EXECUTE_HANDLER )
        {
            status = CERR_BAD_HANDLE;
        }
    }
    return status;
}

STATUS CPCCard::PDCardGetSocket( PSS_SOCKET_STATE pSocketState )
{
    STATUS status = CERR_BAD_HANDLE;
    if( m_SocketService.SS_GetSocket != NULL )
    {
        __try
        {
            status = m_SocketService.SS_GetSocket( GetSocketHandle(),
                                                   pSocketState );
        } __except( EXCEPTION_EXECUTE_HANDLER )
        {
            status = CERR_BAD_HANDLE;
        }
    }
    return status;
}
STATUS CPCCard::PDCardSetSocket( PSS_SOCKET_STATE pSocketState )
{
    STATUS status = CERR_BAD_HANDLE;
    if( m_SocketService.SS_SetSocket != NULL )
    {
        __try
        {
            status = m_SocketService.SS_SetSocket( GetSocketHandle(),
                                                   pSocketState );
        } __except( EXCEPTION_EXECUTE_HANDLER )
        {
            status = CERR_BAD_HANDLE;
        }
    }
    return status;
}
STATUS CPCCard::PDCardResetSocket()
{
    STATUS status = CERR_BAD_HANDLE;
    if( m_SocketService.SS_ResetSocket != NULL )
    {
        __try
        {
            status = m_SocketService.SS_ResetSocket( GetSocketHandle() );
        } __except( EXCEPTION_EXECUTE_HANDLER )
        {
            status = CERR_BAD_HANDLE;
        }
    }
    return status;
}
STATUS CPCCard::PDCardInquireWindow( UINT32 uWindow,
                                     PSS_WINDOW_INFO pWindowInfo )
{
    STATUS status = CERR_BAD_HANDLE;
    if( m_SocketService.SS_InquireWindow != NULL && pWindowInfo )
    {
        __try
        {
            pWindowInfo->hSocket = GetSocketHandle();// Update to use Index.
            status = m_SocketService.SS_InquireWindow( uWindow, pWindowInfo );
        } __except( EXCEPTION_EXECUTE_HANDLER )
        {
            status = CERR_BAD_HANDLE;
        }
    }
    return status;
}
STATUS CPCCard::PDCardGetWindow( UINT32 uWindow, PSS_WINDOW_STATE pWindowState )
{
    STATUS status = CERR_BAD_HANDLE;
    if( m_SocketService.SS_GetWindow != NULL && pWindowState )
    {
        __try
        {
            pWindowState->hSocket = GetSocketHandle();// Update to use Index.
            status = m_SocketService.SS_GetWindow( uWindow, pWindowState );
        } __except( EXCEPTION_EXECUTE_HANDLER )
        {
            status = CERR_BAD_HANDLE;
        }
    }
    return status;
}
STATUS CPCCard::PDCardSetWindow( UINT32 uWindow, PSS_WINDOW_STATE pWindowState )
{
    STATUS status = CERR_BAD_HANDLE;
    if( m_SocketService.SS_SetWindow != NULL && pWindowState )
    {
        __try
        {
            pWindowState->hSocket = GetSocketHandle();// Update to use Index.
            status = m_SocketService.SS_SetWindow( uWindow, pWindowState );
        } __except( EXCEPTION_EXECUTE_HANDLER )
        {
            status = CERR_BAD_HANDLE;
        }
    }
    return status;
}
STATUS CPCCard::PDTranslateBusAddr( INTERFACE_TYPE  InterfaceType,
                                    ULONG BusNumber,
                                    PHYSICAL_ADDRESS BusAddress,
                                    PULONG AddressSpace,
                                    PPHYSICAL_ADDRESS TranslatedAddress )
{
    STATUS status = CERR_BAD_HANDLE;
    if( m_SocketService.SS_TranslateBusAddr != NULL )
    {
        __try
        {
            status = m_SocketService.SS_TranslateBusAddr( GetSocketHandle(),
                                                          InterfaceType,
                                                          BusNumber,
                                                          BusAddress,
                                                          AddressSpace,
                                                          TranslatedAddress );
        } __except( EXCEPTION_EXECUTE_HANDLER )
        {
            status = CERR_BAD_HANDLE;
        }
    }
    else if( HalTranslateBusAddress( InterfaceType,
                                     BusNumber,
                                     BusAddress,
                                     AddressSpace,
                                     TranslatedAddress ) )
    {
            status = CERR_SUCCESS;
    }
    return status;
}
STATUS CPCCard::PDTranslateSystemAddr( INTERFACE_TYPE  InterfaceType,
                                       ULONG BusNumber,
                                       PHYSICAL_ADDRESS SystemAddress,
                                       PPHYSICAL_ADDRESS TranslatedAddress )
{
    STATUS status = CERR_BAD_HANDLE;
    if( m_SocketService.SS_TranslateSystemAddr != NULL )
    {
        __try
        {
            status = m_SocketService.SS_TranslateSystemAddr( GetSocketHandle(),
                                                             InterfaceType,
                                                             BusNumber,
                                                             SystemAddress,
                                                             TranslatedAddress );
        } __except( EXCEPTION_EXECUTE_HANDLER )
        {
            status = CERR_BAD_HANDLE;
        }
    }
    else if( HalTranslateSystemAddress( InterfaceType,
                                        BusNumber,
                                        SystemAddress,
                                        TranslatedAddress ) )
    {
            status = CERR_SUCCESS;
    }
    return status;
}

#define MAX_ENTRY 0x10
BOOL CPCCard::ValidPowerEntry( UINT fSupply, UINT16 uVoltage )
{
    if( m_pssPowerEntry != NULL )
    {
        for( DWORD dwIndex = 0;
             dwIndex < m_SocketInfo.dwNumOfPowerEntry;
             dwIndex++ )
        {
            if( ( ( ( m_pssPowerEntry + dwIndex )->uPowerLevel * 9 / 10 ) <=
                  uVoltage ) &&
                ( ( m_pssPowerEntry + dwIndex )->uPowerLevel >= uVoltage ) &&
                ( ( m_pssPowerEntry + dwIndex )->fSupply & fSupply ) )
            {
                return TRUE;
            }
        }
    };        
    return FALSE;
}
BOOL CPCCard::GetVotageEntry( PDWORD pdwEntry, UINT16 uValue, UINT8 fSupply )
{
    if( m_pssPowerEntry != NULL )
    {
        DWORD dwRetEntry = ( DWORD ) - 1;
        DWORD dwCurDelt = ( DWORD ) - 1;
        for( DWORD dwIndex = 0;
             dwIndex < m_SocketInfo.dwNumOfPowerEntry;
             dwIndex++ )
        {
            if( uValue <= ( m_pssPowerEntry + dwIndex )->uPowerLevel &&
                ( ( m_pssPowerEntry + dwIndex )->fSupply & fSupply ) != 0 )
            {
                // Potential power entry
                if( ( DWORD )
                    ( ( m_pssPowerEntry + dwIndex )->uPowerLevel - uValue ) <
                    dwCurDelt )
                {
                    // Found Better one.
                    dwRetEntry = dwIndex;
                    dwCurDelt = ( m_pssPowerEntry + dwIndex )->uPowerLevel -
                                uValue;
                }
            };
        }
        if( dwRetEntry != ( DWORD ) - 1 )
        {
            // Found one.
            if( pdwEntry )
            {
                *pdwEntry = dwRetEntry;
            }
            return TRUE;
        };
    }
    return FALSE;
}
//-----------------------------------Container-----------------------------------------------------
extern "C"  void CS_SocketCallback( HANDLE hSocket,
                                    UINT16 uSocket,
                                    PSS_SOCKET_STATE pSocketState )
{
    if( pSocketState &&
        CPCCardContainer::g_pCardContainer &&
        CSocketInfoContainer::g_pSocketContainer )
    {
        CPCCardContainer::g_pCardContainer->SocketEvent( hSocket,
                                                         uSocket,
                                                         pSocketState );
    };
}
void CPCCardContainer::SocketEvent( HANDLE hSocket,
                                    UINT16 uSocket,
                                    PSS_SOCKET_STATE pSocketState )
{
    DEBUGMSG( ZONE_INIT |
              ZONE_MDD,
              ( TEXT( "CardBus.DLL : CallBackFrom Socket with eventchange=0x%x eventstatus=0x%x,dwInterfaceType=0x%x\r\n" ),
                pSocketState->dwEventChanged,
                pSocketState->dwEventStatus,
                pSocketState->dwInterfaceType ) );
    SS_SOCKET_STATE lState = *pSocketState;
    if( ( lState.dwEventStatus & SOCK_EVENT_CD ) != 0 )
    {
        // Card is present.
        BOOL bFoundOneCard = FALSE;
        CPCCard* pCard = NULL;
        for( DWORD dwIndex = 0; dwIndex < m_dwArraySize; dwIndex++ )
        {
            pCard = ObjectIndex( dwIndex );
            if( pCard )
            {
                if( pCard->GetSocketHandle() == hSocket )
                {
                    pCard->EventNotification( pSocketState );
                    bFoundOneCard = TRUE;
                }
                pCard->DeRef();
            }
        }
        if( !bFoundOneCard &&
            CSocketInfoContainer::g_pSocketContainer != NULL )
        {
            CAttachedSocket* pSocket = CSocketInfoContainer::g_pSocketContainer->ObjectIndex( ( DWORD )
                                                                                              uSocket );
            if( pSocket )
            {
                if( ( pCard = CreateCardObject( pSocket->GetSocketService(),
                                                pSocketState,
                                                hSocket,
                                                uSocket,
                                                GetDeviceHandle() ) ) !=
                    NULL )
                {
                    if( InsertObjectAtEmpty( NULL, pCard ) == NULL )
                    {
                        // Card object has been created and Inserted into container
                        DEBUGMSG( ZONE_ERROR,
                                  ( TEXT( "CardBus.DLL : Can not construct new card(%x)!!!\r\n" ),
                                    pCard ) );
                        delete pCard;
                        pCard = NULL;
                    }
                    else if( pCard->Init( TRUE ) == FALSE )
                    {
                        DEBUGMSG( ZONE_ERROR,
                                  ( TEXT( "CardBus.DLL : Can not Initial new card(%x)!!!\r\n" ),
                                    pCard ) );
                        RemoveObjectBy( pCard );
                    }
                    else
                    {
                        DEBUGMSG( ZONE_INIT,
                                  ( TEXT( "pcc_serv.DLL :  new card(%x) created and inserted.!!!\r\n" ),
                                    pCard ) );                        
                        pCard->EventNotification( pSocketState );
                    }
                }
                pSocket->DeRef();
            }
        }
    }
    else
    {
        // Card is not present. delete all the card had this socket handle.
        for( DWORD dwIndex = 0; dwIndex < m_dwArraySize; dwIndex++ )
        {
            CPCCard* pCard = ObjectIndex( dwIndex );
            if( pCard )
            {
                if( pCard->GetSocketHandle() == hSocket )
                {
                    pCard->EventNotification( CE_CARD_REMOVAL );
                    RemoveObjectBy( pCard );
                }
                pCard->DeRef();
            }
        }
    }
}
CPCCardContainer::CPCCardContainer()
{
    m_hDevice = NULL;
}
HANDLE CPCCardContainer::SetDeviceHandle( HANDLE hDevice )
{
    if( m_hDevice == NULL && hDevice != NULL )
    {
        m_hDevice = hDevice;
    }
    return m_hDevice;
}
BOOL CPCCardContainer::IOControl( DWORD dwCode,
                                  PBYTE pBufIn,
                                  DWORD dwLenIn,
                                  PBYTE pBufOut,
                                  DWORD dwLenOut,
                                  PDWORD pdwActualOut )
{
    BOOL RetVal = FALSE;
    switch( dwCode )
    {
      case IOCTL_BUS_TRANSLATE_BUS_ADDRESS:
        if ((!pBufIn || dwLenIn < sizeof(TCHAR)) && (!pBufOut || dwLenOut<sizeof(CEDDK_BUS_TRANSLATE_BUS_ADDR)) ) {
            SetLastError(ERROR_INVALID_PARAMETER);
            RetVal = FALSE;            
        }
        else {
            PCEDDK_BUS_TRANSLATE_BUS_ADDR pceddkBusAddr = (PCEDDK_BUS_TRANSLATE_BUS_ADDR)pBufOut;
            CE_BUS_TRANSLATE_BUS_ADDR CeBusTranslate = {
                (LPTSTR)pBufIn,pceddkBusAddr->InterfaceType,pceddkBusAddr->BusNumber,
                 pceddkBusAddr->BusAddress,&(pceddkBusAddr->AddressSpace),&(pceddkBusAddr->TranslatedAddress) 
            };
            if( CeBusTranslate.lpDeviceBusName  != NULL &&
                CeBusTranslate.AddressSpace != NULL &&
                CeBusTranslate.TranslatedAddress != NULL )
            {
                CPCCard* pCard = FoundObjectBy( NULL,CeBusTranslate.lpDeviceBusName  );
                if( pCard )
                {
                    STATUS status = pCard->PDTranslateBusAddr( CeBusTranslate.InterfaceType,
                                                               CeBusTranslate.BusNumber,
                                                               CeBusTranslate.BusAddress,
                                                               CeBusTranslate.AddressSpace,
                                                               CeBusTranslate.TranslatedAddress );
                    if( status == CERR_SUCCESS )
                    {
                        if( pdwActualOut )
                            *pdwActualOut = sizeof( CEDDK_BUS_TRANSLATE_BUS_ADDR );
                        RetVal = TRUE;
                    }
                    pCard->DeRef();
                }
            }
            if( RetVal == FALSE )
                SetLastError( ERROR_INVALID_PARAMETER );
        }
        break;
      case IOCTL_BUS_TRANSLATE_SYSTEM_ADDRESS:
        if ((!pBufIn || dwLenIn < sizeof(TCHAR)) && (!pBufOut || dwLenOut<sizeof(CEDDK_BUS_TRANSLATE_SYSTEM_ADDR)) ){
            SetLastError(ERROR_INVALID_PARAMETER);
            RetVal = FALSE;            
        }
        else {
            PCEDDK_BUS_TRANSLATE_SYSTEM_ADDR pceddkSystemAddr = (PCEDDK_BUS_TRANSLATE_SYSTEM_ADDR)pBufOut;
            CE_BUS_TRANSLATE_SYSTEM_ADDR CeTranslateSystem = {
                (LPTSTR)pBufIn,pceddkSystemAddr->InterfaceType,pceddkSystemAddr->BusNumber,
                    pceddkSystemAddr->SystemAddress,&(pceddkSystemAddr->TranslatedAddress)
            };
            if( CeTranslateSystem.lpDeviceBusName != NULL && CeTranslateSystem.TranslatedAddress!= NULL )
            {
                CPCCard* pCard = FoundObjectBy( NULL,CeTranslateSystem.lpDeviceBusName );
                if( pCard )
                {
                    STATUS status = pCard->PDTranslateSystemAddr( CeTranslateSystem.InterfaceType,
                                                                  CeTranslateSystem.BusNumber,
                                                                  CeTranslateSystem.SystemAddress,
                                                                  CeTranslateSystem.TranslatedAddress );
                    if( status == CERR_SUCCESS )
                    {
                        if( pdwActualOut )
                            *pdwActualOut = sizeof( CE_BUS_TRANSLATE_SYSTEM_ADDR );
                        RetVal = TRUE;
                    }
                    pCard->DeRef();
                }
            }
            if( RetVal == FALSE )
                SetLastError( ERROR_INVALID_PARAMETER );
        }
        break;
      case IOCTL_BUS_GET_POWER_STATE:
        // Get Power for Child
      case IOCTL_BUS_SET_POWER_STATE:
        if ((!pBufIn || dwLenIn < sizeof(TCHAR)) && (!pBufOut || dwLenOut < sizeof(CEDDK_BUS_POWER_STATE))) {
            SetLastError(ERROR_INVALID_PARAMETER);
            RetVal = FALSE;            
        }
        else {
            PCEDDK_BUS_POWER_STATE pceddkPowerState = (PCEDDK_BUS_POWER_STATE)pBufOut;
            CE_BUS_POWER_STATE CePowerState = {
                (LPTSTR)pBufIn,&(pceddkPowerState->DevicePowerState),pceddkPowerState->lpReserved
            };
            if (CePowerState.lpDeviceBusName && CePowerState.lpceDevicePowerState ) 
            {
                CPCCard* pCard = FoundObjectBy( NULL,
                                                CePowerState.lpDeviceBusName );
                if( pCard )
                {
                    switch( dwCode )
                    {
                      case IOCTL_BUS_GET_POWER_STATE:
                        // Get Power for Child
                        *(CePowerState.lpceDevicePowerState) = pCard->GetPowerState();
                        RetVal = TRUE;
                        break;
                      case IOCTL_BUS_SET_POWER_STATE:
                        RetVal = pCard->SetPowerState( *(CePowerState.lpceDevicePowerState) );
                        break;
                    }
                    if( RetVal && pdwActualOut )
                        *pdwActualOut = sizeof( CE_BUS_POWER_STATE );
                    pCard->DeRef();
                }
            }
            if( !RetVal )
                SetLastError( ERROR_INVALID_PARAMETER );
        }
        break;
      case IOCTL_BUS_GET_CONFIGURE_DATA:
      case IOCTL_BUS_SET_CONFIGURE_DATA:
        if ((!pBufIn || dwLenIn < sizeof(TCHAR)) && (!pBufOut || dwLenOut < sizeof(CEDDK_BUS_DEVICE_CONFIGURATION_DATA))) {
            SetLastError(ERROR_INVALID_PARAMETER);
            RetVal = FALSE;            
        }
        else {
            PCEDDK_BUS_DEVICE_CONFIGURATION_DATA pceddkConfData = (PCEDDK_BUS_DEVICE_CONFIGURATION_DATA)pBufOut;
            CE_BUS_DEVICE_CONFIGURATION_DATA DeviceConfigureData = {
                (LPTSTR)pBufIn,pceddkConfData->dwSpace,pceddkConfData->dwOffset,pceddkConfData->dwLength,pceddkConfData->pBuffer
            };
            if( DeviceConfigureData.lpDeviceBusName &&  DeviceConfigureData.pBuffer )
            {
                CPCCard* pCard = FoundObjectBy( NULL,
                                                DeviceConfigureData.lpDeviceBusName );
                if( pCard )
                {
                    RetVal = pCard->AccessConfigurationSpace( DeviceConfigureData.dwSpace,
                                                              DeviceConfigureData.dwOffset,
                                                              ( dwCode ==
                                                                IOCTL_BUS_GET_CONFIGURE_DATA ?
                                                                TRUE :
                                                                FALSE ),
                                                              DeviceConfigureData.dwLength,
                                                              DeviceConfigureData.pBuffer );
                    pCard->DeRef();
                }
            }
            if( !RetVal )
                SetLastError( ERROR_INVALID_PARAMETER );
        }
        break;
      case IOCTL_BUS_ACTIVATE_CHILD:
      case IOCTL_BUS_DEACTIVATE_CHILD:
        if( !pBufIn ||
            dwLenIn < _tcslen( ( TCHAR * ) pBufIn ) * sizeof( TCHAR ) )
        {
            SetLastError( ERROR_INVALID_PARAMETER );
            RetVal = FALSE;
        }
        else
        {
            CPCCard* pCard = FoundObjectBy( NULL, ( TCHAR* ) pBufIn );
            if( pCard )
            {
                pCard->EventNotification( dwCode ==
                                          IOCTL_BUS_ACTIVATE_CHILD ? CE_CARD_LOAD_DRIVER : CE_CARD_UNLOAD_DRIVER );
                // For testing. They want Card reset by DeactivateChild function.
                if ( dwCode == IOCTL_BUS_DEACTIVATE_CHILD ) {
                    pCard->CardDisableCard();
                    pCard->CardResetFunction();
                }
                pCard->DeRef();
                RetVal = TRUE;
            }
            if( !RetVal )
                SetLastError( ERROR_INVALID_PARAMETER );
        }
        break;
      case IOCTL_BUS_IS_CHILD_REMOVED :
        if( !pBufIn ||
            dwLenIn <
            ( _tcslen( ( TCHAR * ) pBufIn ) + 1 ) * sizeof( TCHAR ) ||
            !pBufOut ||
            dwLenOut <
            sizeof( DWORD ) )
        {
            SetLastError( ERROR_INVALID_PARAMETER );
            RetVal = FALSE;
        }
        else
        {
            CPCCard* pCard = FoundObjectBy( NULL, ( TCHAR* ) pBufIn );
            BOOL bCardRemoved = TRUE;
            if( pCard )
            {
                CARD_STATUS CardStatus;
                if( pCard->CardGetStatus( &CardStatus ) == CERR_SUCCESS &&
                    ( CardStatus.fCardState & EVENT_MASK_CARD_DETECT ) != 0 )
                {
                    // Card is Inserted.
                    bCardRemoved = FALSE;
                }
                pCard->DeRef();
            }
            *( PDWORD ) pBufOut = ( DWORD ) bCardRemoved;
            RetVal = TRUE;
            if( pdwActualOut )
                *pdwActualOut = sizeof( DWORD );
        }
        break;
      case IOCTL_BUS_NAME_PREFIX:
        if( !pBufOut || dwLenOut < sizeof( TCHAR ) )
        {
            SetLastError( ERROR_INVALID_PARAMETER );
            RetVal = FALSE;
        }
        else
        {
            DWORD dwResult = min( sizeof( DEVICE_BUSNAME_PREFIX ), dwLenOut ) /
                             sizeof( TCHAR );
            LPTSTR lpReturnBusName = ( LPTSTR ) pBufOut;
            if( dwResult && lpReturnBusName )
            {
                _tcsncpy( lpReturnBusName, DEVICE_BUSNAME_PREFIX, dwResult );
                lpReturnBusName[dwResult - 1] = 0;
                RetVal = TRUE;                
                if( pdwActualOut )
                    *pdwActualOut = dwResult * sizeof( TCHAR );
            }
            else
            {
                SetLastError( ERROR_INVALID_PARAMETER );
                RetVal = FALSE;
            }
        }
        break;
    };
    return RetVal;
}
extern "C" STATUS CardGetTupleData( PCARD_DATA_PARMS pGetTupleData )
{
    STATUS status = CERR_BAD_ARGS;
    if( pGetTupleData && CPCCardContainer::g_pCardContainer )
    {
        CPCCard* pCard = CPCCardContainer::g_pCardContainer->FoundObjectBy( NULL,
                                                                            pGetTupleData->hSocket );
        if( pCard )
        {
            status = pCard->CardGetTupleData( pGetTupleData );
            pCard->DeRef();
        }
    };
    return status;
}
extern "C" STATUS CardGetNextTuple( PCARD_TUPLE_PARMS pGetTupleParms )
{
    STATUS status = CERR_BAD_ARGS;
    if( pGetTupleParms && CPCCardContainer::g_pCardContainer )
    {
        CPCCard* pCard = CPCCardContainer::g_pCardContainer->FoundObjectBy( NULL,
                                                                            pGetTupleParms->hSocket );
        if( pCard )
        {
            status = pCard->CardGetNextTuple( pGetTupleParms );
            pCard->DeRef();
        }
    };
    return status;
}
extern "C" STATUS CardGetFirstTuple( PCARD_TUPLE_PARMS pGetTupleParms )
{
    STATUS status = CERR_BAD_ARGS;
    if( pGetTupleParms && CPCCardContainer::g_pCardContainer )
    {
        CPCCard* pCard = CPCCardContainer::g_pCardContainer->FoundObjectBy( NULL,
                                                                            pGetTupleParms->hSocket );
        if( pCard )
        {
            status = pCard->CardGetFirstTuple( pGetTupleParms );
            pCard->DeRef();
        }
    };
    return status;
}
extern "C" 
STATUS CardGetParsedTuple( CARD_SOCKET_HANDLE hSocket,
                           UINT8 uDesiredTuple,
                           PVOID pBuf,
                           PUINT32 pnItems )
{
    STATUS status = CERR_BAD_ARGS;
    if( CPCCardContainer::g_pCardContainer && pBuf && pnItems )
    {
        CPCCard* pCard = CPCCardContainer::g_pCardContainer->FoundObjectBy( NULL,
                                                                            hSocket );
        if( pCard )
        {
            status = pCard->CardGetParsedTuple( uDesiredTuple, pBuf, pnItems );
            pCard->DeRef();
        }
    }
    return status;
}

extern "C" CARD_WINDOW_HANDLE CardRequestWindow( CARD_CLIENT_HANDLE hCardClient,
                                                 PCARD_WINDOW_PARMS pCardWinParms )
{
    WINDOW_HANDLE_CONTENT lHandle;
    UINT16 uWindowIndex = ( UINT16 ) - 1;
    if( pCardWinParms && CPCCardContainer::g_pCardContainer )
    {
        CPCCard* pCard = CPCCardContainer::g_pCardContainer->FoundObjectBy( NULL,
                                                                            pCardWinParms ->hSocket );
        if( pCard )
        {
            if( pCard->GetClientHandle() == hCardClient )
                uWindowIndex = pCard->CardRequestWindow( pCardWinParms ) ;
            pCard->DeRef();
        }
    };
    if( uWindowIndex != ( UINT16 ) - 1  && pCardWinParms )
    {
        lHandle.hCardHandle = pCardWinParms->hSocket;
        lHandle.uWindowIndex = uWindowIndex ;
        return ( CARD_WINDOW_HANDLE ) * ( ( CARD_WINDOW_HANDLE * ) &lHandle );
    }
    else
    {
        return NULL;
    }
}
extern "C" STATUS CardReleaseWindow( CARD_WINDOW_HANDLE hCardWin )
{
    STATUS status = CERR_BAD_HANDLE;
    WINDOW_HANDLE_CONTENT lHandle = *( ( WINDOW_HANDLE_CONTENT* ) &hCardWin );
    if( CPCCardContainer::g_pCardContainer )
    {
        CPCCard* pCard = CPCCardContainer::g_pCardContainer->FoundObjectBy( NULL,
                                                                            lHandle.hCardHandle );
        if( pCard )
        {
            status = pCard->CardReleaseWindow( lHandle.uWindowIndex ) ;
            pCard->DeRef();
        }
    };
    return status;
}

extern "C" STATUS CardModifyWindow( CARD_WINDOW_HANDLE hCardWindow,
                                    UINT16 fAttributes,
                                    UINT8 fAccessSpeed )
{
    STATUS status = CERR_BAD_HANDLE;
    WINDOW_HANDLE_CONTENT lHandle = *( ( WINDOW_HANDLE_CONTENT* ) &hCardWindow );
    if( CPCCardContainer::g_pCardContainer )
    {
        CPCCard* pCard = CPCCardContainer::g_pCardContainer->FoundObjectBy( NULL,
                                                                            lHandle.hCardHandle );
        if( pCard )
        {
            status = pCard->CardModifyWindow( lHandle.uWindowIndex,
                                              fAttributes,
                                              fAccessSpeed ) ;
            pCard->DeRef();
        }
    };
    return status;
}
extern "C" PVOID CardMapWindow( CARD_WINDOW_HANDLE hCardWindow,
                                UINT32 uCardAddress,
                                UINT32 uSize,
                                PUINT32 pGranularity )
{
    PVOID pReturn = NULL;
    WINDOW_HANDLE_CONTENT lHandle = *( ( WINDOW_HANDLE_CONTENT* ) &hCardWindow );
    if( CPCCardContainer::g_pCardContainer )
    {
        CPCCard* pCard = CPCCardContainer::g_pCardContainer->FoundObjectBy( NULL,
                                                                            lHandle.hCardHandle );
        if( pCard )
        {
            pReturn = pCard->CardMapWindow( lHandle.uWindowIndex,
                                            uCardAddress,
                                            uSize,
                                            pGranularity ) ;
            pCard->DeRef();
        }
    };
    return pReturn;
}
extern "C"  STATUS CardMapWindowPhysical( CARD_WINDOW_HANDLE hCardWindow,
                                          PCARD_WINDOW_ADDRESS pCardWindowAddr )
{
    STATUS status = CERR_BAD_HANDLE;
    WINDOW_HANDLE_CONTENT lHandle = *( ( WINDOW_HANDLE_CONTENT* ) &hCardWindow );
    if( CPCCardContainer::g_pCardContainer )
    {
        CPCCard* pCard = CPCCardContainer::g_pCardContainer->FoundObjectBy( NULL,
                                                                            lHandle.hCardHandle );
        if( pCard )
        {
            status = pCard->CardMapWindowPhysical( lHandle.uWindowIndex,
                                                   pCardWindowAddr );
            pCard->DeRef();
        }
    };
    return status;
}

extern "C"  STATUS CardRequestIRQ( CARD_CLIENT_HANDLE hCardClient,
                                   CARD_SOCKET_HANDLE hSocket,
                                   CARD_ISR ISRFunction,
                                   UINT32 uISRContextData )
{
    STATUS status = CERR_BAD_HANDLE;
    if( CPCCardContainer::g_pCardContainer )
    {
        CPCCard* pCard = CPCCardContainer::g_pCardContainer->FoundObjectBy( NULL,
                                                                            hSocket );
        if( pCard )
        {
            if( pCard->GetClientHandle() == hCardClient )
                status = pCard->CardRequestIRQ( ISRFunction, uISRContextData );
            pCard->DeRef();
        }
    }
    return status;
}
extern "C" STATUS CardReleaseIRQ( CARD_CLIENT_HANDLE hCardClient,
                                  CARD_SOCKET_HANDLE hSocket )
{
    STATUS status = CERR_BAD_HANDLE;
    if( CPCCardContainer::g_pCardContainer )
    {
        CPCCard* pCard = CPCCardContainer::g_pCardContainer->FoundObjectBy( NULL,
                                                                            hSocket );
        if( pCard )
        {
            if( pCard->GetClientHandle() == hCardClient )
                status = pCard->CardReleaseIRQ();
            pCard->DeRef();
        }
    }
    return status;
}

extern "C" 
STATUS CardRequestIRQLine( CARD_CLIENT_HANDLE hCardClient,
                           CARD_SOCKET_HANDLE hSocket,
                           UINT16 uSupportedIrqBit,
                           PDWORD pdwIrqNumber,
                           PDWORD pdwIsSysIntr )
{
    STATUS status = CERR_BAD_HANDLE;
    if( CPCCardContainer::g_pCardContainer )
    {
        CPCCard* pCard = CPCCardContainer::g_pCardContainer->FoundObjectBy( NULL,
                                                                            hSocket );
        if( pCard )
        {
            if( pCard->GetClientHandle() == hCardClient )
            {
                status = pCard->CardRequestIRQLine( uSupportedIrqBit,
                                                    pdwIrqNumber,
                                                    pdwIsSysIntr );
            }
            pCard->DeRef();
        }
    }
    return status;
}


extern "C" STATUS CardRequestConfiguration( CARD_CLIENT_HANDLE hCardClient,
                                            PCARD_CONFIG_INFO pParms )
{
    STATUS status = CERR_BAD_HANDLE;
    if( CPCCardContainer::g_pCardContainer && pParms )
    {
        CPCCard* pCard = CPCCardContainer::g_pCardContainer->FoundObjectBy( NULL,
                                                                            pParms->hSocket );
        if( pCard )
        {
            if( pCard->GetClientHandle() == hCardClient )
                status = pCard->CardRequestConfiguration( pParms );
            pCard->DeRef();
        }
    }
    return status;
}
extern "C" 
STATUS CardReleaseConfiguration( CARD_CLIENT_HANDLE hCardClient,
                                 CARD_SOCKET_HANDLE hSocket )
{
    STATUS status = CERR_BAD_HANDLE;
    if( CPCCardContainer::g_pCardContainer )
    {
        CPCCard* pCard = CPCCardContainer::g_pCardContainer->FoundObjectBy( NULL,
                                                                            hSocket );
        if( pCard )
        {
            if( pCard->GetClientHandle() == hCardClient )
                status = pCard->CardReleaseConfiguration();
            pCard->DeRef();
        }
    }
    return status;
}
extern "C"
STATUS CardModifyConfiguration( CARD_CLIENT_HANDLE hCardClient,
                                CARD_SOCKET_HANDLE hSock,
                                PUINT16 fAttributes )
{
    STATUS status = CERR_BAD_HANDLE;
    if( CPCCardContainer::g_pCardContainer )
    {
        CPCCard* pCard = CPCCardContainer::g_pCardContainer->FoundObjectBy( NULL,
                                                                            hSock );
        if( pCard )
        {
            if( pCard->GetClientHandle() == hCardClient )
                status = pCard->CardModifyConfiguration( fAttributes );
            pCard->DeRef();
        }
    }
    return status;
}
extern "C"
STATUS CardRequestConfigRegisterPhAddr( CARD_CLIENT_HANDLE hCardClient,
                                        CARD_SOCKET_HANDLE hSock,
                                        PCARD_WINDOW_ADDRESS pCardWindowAddr,
                                        PDWORD pOffset )
{
    STATUS status = CERR_BAD_HANDLE;
    if( CPCCardContainer::g_pCardContainer )
    {
        CPCCard* pCard = CPCCardContainer::g_pCardContainer->FoundObjectBy( NULL,
                                                                            hSock );
        if( pCard )
        {
            if( pCard->GetClientHandle() == hCardClient )
                status = pCard->CardRequestConfigRegisterPhAddr( pCardWindowAddr,
                                                                 pOffset );
            pCard->DeRef();
        }
    }
    return status;
}
extern "C"
STATUS CardAccessConfigurationRegister( CARD_CLIENT_HANDLE hCardClient,
                                        CARD_SOCKET_HANDLE hSock,
                                        UINT8 rw_flag,
                                        UINT8 offset,
                                        UINT8* pValue )
{
    STATUS status = CERR_BAD_HANDLE;
    if( CPCCardContainer::g_pCardContainer )
    {
        CPCCard* pCard = CPCCardContainer::g_pCardContainer->FoundObjectBy( NULL,
                                                                            hSock );
        if( pCard )
        {
            if( pCard->GetClientHandle() == hCardClient )
                status = pCard->CardAccessConfigurationRegister( rw_flag,
                                                                 offset,
                                                                 pValue );
            pCard->DeRef();
        }
    }
    return status;
}

extern "C" 
STATUS CardGetStatus( PCARD_STATUS pStatus )
{
    STATUS status = CERR_BAD_HANDLE;
    if( CPCCardContainer::g_pCardContainer && pStatus )
    {
        CPCCard* pCard = CPCCardContainer::g_pCardContainer->FoundObjectBy( NULL,
                                                                            pStatus->hSocket );
        if( pCard )
        {
            status = pCard->CardGetStatus( pStatus );
            pCard->DeRef();
        }
    }
    return status;
}
extern "C" 
STATUS CardResetFunction( CARD_CLIENT_HANDLE hCardClient,
                          CARD_SOCKET_HANDLE hSock )
{
    STATUS status = CERR_BAD_HANDLE;
    if( CPCCardContainer::g_pCardContainer )
    {
        CPCCard* pCard = CPCCardContainer::g_pCardContainer->FoundObjectBy( NULL,
                                                                            hSock );
        if( pCard )
        {
            if( pCard->GetClientHandle() == hCardClient )
                status = pCard->CardResetFunction();
            pCard->DeRef();
        }
    }
    return status;
}
extern "C" 
STATUS CardRequestExclusive( CARD_CLIENT_HANDLE hCardClient,
                             CARD_SOCKET_HANDLE hSocket )
{
    STATUS status = CERR_BAD_HANDLE;
    if( CPCCardContainer::g_pCardContainer )
    {
        CPCCard* pCard = CPCCardContainer::g_pCardContainer->FoundObjectBy( NULL,
                                                                            hSocket );
        if( pCard )
        {
            if( pCard->GetClientHandle() == NULL )
            {
                pCard->SetClientHandle( hCardClient );
                pCard->EventNotification( CE_EXCLUSIVE_COMPLETE );
                status = CERR_SUCCESS;
            }
            pCard->DeRef();
        }
    }
    return status;
}
extern "C" 
STATUS CardRequestDisable( CARD_CLIENT_HANDLE hCardClient,
                           CARD_SOCKET_HANDLE hSocket )
{
    STATUS status = CERR_BAD_HANDLE;
    if( CPCCardContainer::g_pCardContainer )
    {
        CPCCard* pCard = CPCCardContainer::g_pCardContainer->FoundObjectBy( NULL,
                                                                            hSocket );
        if( pCard )
        {
            if( pCard->GetClientHandle() == hCardClient )
                status = pCard->CardDisableCard();
            pCard->DeRef();
        }
    }
    return status;
}

extern "C" 
STATUS CardReleaseExclusive( CARD_CLIENT_HANDLE hCardClient,
                             CARD_SOCKET_HANDLE hSocket )
{
    STATUS status = CERR_BAD_HANDLE;
    if( CPCCardContainer::g_pCardContainer )
    {
        CPCCard* pCard = CPCCardContainer::g_pCardContainer->FoundObjectBy( NULL,
                                                                            hSocket );
        if( pCard )
        {
            if( pCard->GetClientHandle() == hCardClient )
            {
                pCard->SetClientHandle( NULL );
                status = CERR_SUCCESS;
            }
            pCard->DeRef();
        }
    }
    return status;
}
extern "C" 
STATUS EnumSocket( PDWORD pdwNumOfStructure,
                   PSOCKET_DESCRIPTOR pSocketDescriptorArray,
                   PDWORD pdwNumOfStructureCopied )
{
    STATUS status = CERR_BAD_ARGS;
    if( pdwNumOfStructure && CSocketInfoContainer::g_pSocketContainer )
    {
        DWORD dwNumOfItem = *pdwNumOfStructure;
        if( dwNumOfItem != 0 && pSocketDescriptorArray == NULL )
        {
            // Irrigle.
            return status;
        }
        DWORD dwCurItem = 0;
        for( DWORD dwIndex = 0; dwIndex < NUM_SOCKETS; dwIndex++ )
        {
            CAttachedSocket* pSocket = CSocketInfoContainer::g_pSocketContainer->ObjectIndex( dwIndex );
            if( pSocket )
            {
                if( pSocketDescriptorArray != NULL && dwCurItem < dwNumOfItem )
                {
                    ( pSocketDescriptorArray + dwCurItem )->dwSocketIndex = dwIndex;
                    _tcsncpy( ( pSocketDescriptorArray + dwCurItem )->sSocketName,
                              pSocket->GetSocketName(),
                              MAX_SOCKET_DESCRIPTOR_NAME );
                    ( pSocketDescriptorArray + dwCurItem )->sSocketName[MAX_SOCKET_DESCRIPTOR_NAME - 1] = 0;
                    if( pdwNumOfStructureCopied )
                    {
                        *pdwNumOfStructureCopied = dwCurItem + 1;
                    }
                }
                dwCurItem++;
                pSocket->DeRef();
            }
        }
        *pdwNumOfStructure = dwCurItem;
        status = CERR_SUCCESS;
    }
    return status;
}
extern "C" 
STATUS EnumCard( PDWORD pdwNumOfStructure,
                 PCARD_DESCRIPTOR pCardDescriptorArray,
                 PDWORD pdwNumOfStructureCopied )
{
    STATUS status = CERR_BAD_ARGS;
    if( pdwNumOfStructure && CPCCardContainer::g_pCardContainer )
    {
        DWORD dwNumOfItem = *pdwNumOfStructure;
        if( dwNumOfItem != 0 && pCardDescriptorArray == NULL )
        {
            // Irrigle.
            return status;
        }
        DWORD dwCurItem = 0;
        for( DWORD dwIndex = 0; dwIndex < MAX_CARD; dwIndex++ )
        {
            CPCCard* pCard = CPCCardContainer::g_pCardContainer->ObjectIndex( dwIndex );
            if( pCard )
            {
                if( pCardDescriptorArray != NULL && dwCurItem < dwNumOfItem )
                {
                    ( pCardDescriptorArray + dwCurItem )->hCardHandle = pCard->GetCardHandle();
                    ( pCardDescriptorArray + dwCurItem )->dwSocketIndex = pCard->GetSocketIndex();
                    if( pdwNumOfStructureCopied )
                    {
                        *pdwNumOfStructureCopied = dwCurItem + 1;
                    }
                }
                dwCurItem++;
                pCard->DeRef();
            }
        }
        *pdwNumOfStructure = dwCurItem;
        status = CERR_SUCCESS;
    }
    return status;
}
extern "C" 
STATUS GetSocketStatus( DWORD dwSocketIndex, PDWORD pdwStatus )
{
    if( pdwStatus )
    {
        BOOL bContinue = TRUE;
        DWORD dwStatus = 0;
        for( DWORD dwIndex = 0; dwIndex < MAX_CARD && bContinue ; dwIndex++ )
        {
            CPCCard* pCard = CPCCardContainer::g_pCardContainer->ObjectIndex( dwIndex );
            if( pCard )
            {
                if( pCard->GetSocketIndex() == dwSocketIndex )
                {
                    CARD_STATUS cardStatus;
                    cardStatus.hSocket = pCard->GetCardHandle();
                    CardGetStatus( &cardStatus );
                    bContinue = FALSE;
                    dwStatus = cardStatus.fSocketState;
                }
                pCard->DeRef();
            }
        }
        *pdwStatus = dwStatus;
        return CERR_SUCCESS;
    }
    return CERR_BAD_ARGS;
}
extern "C" 
STATUS GetSocketIndex( CARD_SOCKET_HANDLE hSocket, PDWORD pdwSocketIndex )
{
    STATUS status = CERR_BAD_HANDLE;
    if( CPCCardContainer::g_pCardContainer && pdwSocketIndex )
    {
        CPCCard* pCard = CPCCardContainer::g_pCardContainer->FoundObjectBy( NULL,
                                                                            hSocket );
        if( pCard )
        {
            *pdwSocketIndex = pCard->GetSocketIndex();
            pCard->DeRef();
            status = CERR_SUCCESS;
        }
    }
    return status;
}

