//
// 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:

PcmciaC.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 <tuple.h>
#include <ceddk.h>
#include "PCCard.h"
#include "PcmciaC.h"
#include "debug.h"
#include <CeBusCfg.h>

#define MAX_PHYSICAL_MAP_SIZE 0x1000000

CPCPcmciaCard ::CPCPcmciaCard( PSS_SOCKET_SERVICE pSocketService,
                               PSS_SOCKET_STATE pSocketState,
                               HANDLE hSocket,
                               UINT16 uSocket,
                               HANDLE hDevice,
                               CPCPcmciaCard* pPFunction,
                               UINT uFunction ) : CPCCard( pSocketService,
                                                           pSocketState,
                                                           hSocket,
                                                           uSocket,
                                                           hDevice,
                                                           pPFunction,
                                                           uFunction )
{
    if( pSocketState )
    {
        m_SocketState = *pSocketState;
    }
    else
    {
        STATUS status = PDCardGetSocket( &m_SocketState );
        DEBUGCHK( status == CERR_SUCCESS );
    }
    m_pTurple = NULL;
    m_bRoot = FALSE;
    m_bPowered = FALSE;
    m_bSuspend = FALSE;
    m_bSysInterAllocated = FALSE;
    m_pCommonWindow = NULL;
    m_pAttributeWindow = NULL;
    m_ppPcmciaWindows = ( CPcmciaWindows * * )new PVOID[m_SocketInfo.dwNumOfWindows];
    if( m_ppPcmciaWindows )
    {
        for( DWORD dwIndex = 0;
             dwIndex < m_SocketInfo.dwNumOfWindows;
             dwIndex++ )
        {
            *( m_ppPcmciaWindows + dwIndex ) = NULL;
        }
    }
    m_dwCardRegisterBase = 0; // Undefined.
    m_dwFunctionDest = 0;
    // Get Power Entry for Syspend and resume.
    m_dwZeroEntryIndex = 0;
    m_cePowerState = D0;
    m_bPrimaryAttrMemMapped = FALSE;
    m_bPrimaryCommonMemMapped = FALSE;
};

BOOL CPCPcmciaCard::Init( BOOL bRoot )
{
    DEBUGMSG( ZONE_MDD,
              ( TEXT( "CPCPcmciaCard::Init Function=%d bRoot=%d\r\n" ),
                GetCardFunctionNumber(),
                bRoot ) );
    DEBUGCHK( ( m_SocketState.dwInterfaceType & CFG_IFACE_CARDBUS ) == NULL );
    Lock();
    CPCCard::EventNotification( CE_CARD_INSERTION, m_SocketState.dwInterfaceType );
    BOOL bReturn = CPCCard::Init( bRoot );
    // Power On the Card and Get Info.
    STATUS status = CERR_SUCCESS;
    if( bReturn && bRoot && GetParentFunction() == NULL ) {
        m_bRoot = TRUE;
        if( m_ppPcmciaWindows == NULL ) {
            bReturn = FALSE;
        }
        else {
            for( DWORD dwIndex = 0; dwIndex < m_SocketInfo.dwNumOfWindows; dwIndex++ ) {
                if( ( *( m_ppPcmciaWindows + dwIndex ) = new CPcmciaWindows( this,dwIndex ) ) == NULL )
                    bReturn = FALSE;
            }
        }
        PDCardResetSocket();
        PDCardGetSocket( &m_SocketState );
    }
    GetConfigureRegisterBase();

    Unlock();
    return bReturn;
}
void CPCPcmciaCard::PowerUp()
{
    if( m_bSuspend == TRUE )
    {
        DEBUGMSG( ZONE_MDD,
                  ( TEXT( "CPCCardBusCard::PowerUp Function=%d SocketNumber=%d\r\n" ),
                    GetCardFunctionNumber(),
                    GetSocketIndex() ) );
        CardRequestConfiguration( &m_BackupConfig );
        CPCCard::EventNotification( CE_PM_RESUME );
    }
    m_bSuspend = FALSE;
}
void CPCPcmciaCard::PowerDown()
{
    if( m_bSuspend == FALSE )
    {
        //
        // We need back up Configuration Registery.
        CPCCard::EventNotification( CE_PM_SUSPEND );
        DEBUGMSG( ZONE_MDD,
                  ( TEXT( "CPCCardBusCard::PowerDown Function=%d SocketNumber=%d\r\n" ),
                    GetCardFunctionNumber(),
                    GetSocketIndex() ) );
        m_bSuspend = TRUE;
    }
}

CPCTuple* CPCPcmciaCard::GetTupleObject()
{
    return ( m_pTurple !=
             NULL ?
             m_pTurple :
             ( m_pTurple = new CPcmciaTuple( this ) ) );
};
CPcmciaMemWindow* CPCPcmciaCard::GetMemoryWindow( BOOL bAttr )
{
    CPcmciaMemWindow* pReturn = NULL;
    Lock();
    CPCPcmciaCard* pCard = ( CPCPcmciaCard* ) GetParentFunction();
    if( pCard != NULL )
    {
        pReturn = pCard->GetMemoryWindow( bAttr );
    }
    else
    {
        if( bAttr )
        {
            if( m_pAttributeWindow != NULL )
            {
                pReturn = m_pAttributeWindow;
            }
            else
            {
                m_pAttributeWindow = new CPcmciaMemWindow( this, TRUE );
                if( m_pAttributeWindow )
                {
                    if( m_pAttributeWindow->Init() )
                        pReturn = m_pAttributeWindow;
                    else
                    {
                        // Fails
                        delete m_pAttributeWindow;
                        m_pAttributeWindow = NULL;
                    }
                }
            }
        }
        else
        {
            if( m_pCommonWindow != NULL )
            {
                pReturn = m_pCommonWindow;
            }
            else
            {
                m_pCommonWindow = new CPcmciaMemWindow( this, FALSE );
                if( m_pCommonWindow )
                {
                    if( m_pCommonWindow ->Init() )
                        pReturn = m_pCommonWindow ;
                    else
                    {
                        delete m_pCommonWindow ;
                        m_pCommonWindow = NULL;
                    }
                }
            }
        }
    }
    Unlock();
    return pReturn;
}
BYTE CPCPcmciaCard::WriteCardRegister( DWORD dwRegisterOffset, BYTE bValue )
{
    BYTE bReturn = bValue;
    DWORD dwRegisterBit = ( 1 << dwRegisterOffset );
    if( m_dwCardRegisterBase && ( m_dwCardRegisterMask & dwRegisterBit ) != 0 )
    {
        BOOL bAttr = ( ( m_dwCardRegisterBase& TUPLE_COMMON_MEMORY_FLAG ) !=
                       0 ?
                       FALSE :
                       TRUE );
        CPcmciaMemWindow* pConfigWindow = GetMemoryWindow( bAttr );
        DWORD dwOffset = ( m_dwCardRegisterBase& TUPLE_ADDRESS_MASK ) +
                         ( dwRegisterOffset*2 );
        DEBUGMSG( ZONE_MDD,
                  ( TEXT( "CPCPcmciaCard::WriteCardRegister Value  0x%x @ 0x%x \r\n" ),
                    bValue,
                    dwRegisterOffset ) );
        if( pConfigWindow != NULL &&
            pConfigWindow->SetByte( dwOffset, bValue ) )
        {
            DEBUGMSG( ZONE_MDD,
                      ( TEXT( "CPCPcmciaCard::WriteCardRegister Value  0x%x @ 0x%x \r\n" ),
                        bValue,
                        dwRegisterOffset ) );
            if( !pConfigWindow->GetByte( dwOffset, &bReturn ) )
                bReturn = bValue;
        }
    }
    else
    {
        DEBUGMSG( ZONE_ERROR,
                  ( TEXT( "CPCPcmciaCard::WriteCardRegister: FAILS the register(offset=%d) is not supported!!!  \r\n" ),
                    dwRegisterOffset ) );
    }
    return bReturn;
}
BOOL CPCPcmciaCard::AccessConfigurationSpace( DWORD dwSpace,
                                              DWORD dwOffset,
                                              BOOL bRead,
                                              DWORD dwLength,
                                              PVOID pBuffer )
{
    CPCPcmciaCard* pPCard = ( CPCPcmciaCard* ) GetParentFunction();
    if( pPCard != NULL )
    {
        return pPCard->AccessConfigurationSpace( dwSpace,
                                                 dwOffset,
                                                 bRead,
                                                 dwLength,
                                                 pBuffer ) ;
    }

    Lock();
    CPcmciaMemWindow* pCfgWindow = NULL;
    DWORD dwStride = 1;
    switch( dwSpace )
    {
      case PCCARD_ATTRIBUTE_MEMORY:
      case PCCARD_ATTRIBUTE_MEMORY_INDIRECT:
        pCfgWindow = GetMemoryWindow( TRUE ); // ATTRIBUTE Memory
        dwOffset <<=1 ;
        dwStride = 2;
        break;
      case PCCARD_COMMON_MEMORY:
      case PCCARD_COMMON_MEMORY_INDIRECT:
        pCfgWindow = GetMemoryWindow( FALSE ); // ATTRIBUTE Memory
        break;
    }
    BOOL bReturn = FALSE;
    if( pCfgWindow && pBuffer )
    {
        PBYTE pCurPos = ( PBYTE ) pBuffer;
        for( DWORD dwIndex = 0; dwIndex < dwLength; dwIndex++ )
        {
            BOOL bAccessReturn = ( bRead ?
                                   pCfgWindow->GetByte( dwOffset,
                                                                pCurPos ) :
                                   pCfgWindow->SetByte( dwOffset,
                                                        *pCurPos ) );
            if( !bAccessReturn )
                break;
            pCurPos ++;
            dwOffset += dwStride;
        }
        if( dwIndex >= dwLength )
            bReturn = TRUE;
    }        
    Unlock();
    return bReturn;
}
BYTE CPCPcmciaCard::ReadCardRegister( DWORD dwRegisterOffset )
{
    BYTE bReturn = 0xff;
    DWORD dwRegisterBit = ( 1 << dwRegisterOffset );
    if( m_dwCardRegisterBase && ( m_dwCardRegisterMask & dwRegisterBit ) != 0 )
    {
        BOOL bAttr = ( ( m_dwCardRegisterBase& TUPLE_COMMON_MEMORY_FLAG ) !=
                       0 ?
                       FALSE :
                       TRUE );
        DWORD dwOffset = ( m_dwCardRegisterBase& TUPLE_ADDRESS_MASK ) +
                         ( dwRegisterOffset*2 );
        CPcmciaMemWindow* pConfigWindow = GetMemoryWindow( bAttr );
        if( pConfigWindow != NULL )
            pConfigWindow->GetByte( dwOffset, &bReturn );
        DEBUGMSG( ZONE_MDD,
                  ( TEXT( "CPCPcmciaCard::ReadCardRegister Value  0x%x @ 0x%x \r\n" ),
                    bReturn,
                    dwRegisterOffset ) );
    }
    else
    {
        DEBUGMSG( ZONE_ERROR,
                  ( TEXT( "CPCPcmciaCard::WriteCardRegister: FAILS the register(offset=%d) is not supported!!!  \r\n" ),
                    dwRegisterOffset ) );
    }
    return bReturn;
}
BOOL CPCPcmciaCard::GetConfigureRegisterBase()
{
    Lock();
#if 1
   // Paul, Chao @ 2005/8/8 for CF Storage Card identify issue
   Sleep(300);
#endif
    CPCTuple* pTuple = GetTupleObject();
    if( m_dwCardRegisterBase == 0 && pTuple != NULL )
    {
        BYTE bData[sizeof( CARD_TUPLE_PARMS ) + 0x100];
        PCARD_TUPLE_PARMS pTupleParms = ( PCARD_TUPLE_PARMS ) bData;
        memset( pTupleParms, 0, sizeof( CARD_TUPLE_PARMS ) );
        pTupleParms ->uDesiredTuple = CISTPL_CONFIG;
        if( GetTupleObject()->CardGetFirstTuple( pTupleParms ) ==
            CERR_SUCCESS )
        {
            PCARD_DATA_PARMS pGetTupleData = ( PCARD_DATA_PARMS ) bData; // Yes. It overlap with structure CARD_TUPLE_PARMS
            pGetTupleData->uDataLen = 0 ;
            pGetTupleData->uBufLen = sizeof( CARD_TUPLE_PARMS ) +
                                     0x100 -
                                     sizeof( CARD_DATA_PARMS );
            PBYTE pDataPtr = bData + sizeof( CARD_DATA_PARMS );
            if( CardGetTupleData( pGetTupleData ) == CERR_SUCCESS )
            {
                if( pGetTupleData->uDataLen >= 1 )
                {
                    // Get Base Register Address
                    DWORD dwSize = ( ( *pDataPtr ) & 0x3 ) + 1;
                    if( pGetTupleData->uDataLen >= 2 + dwSize )
                    {
                        m_dwCardRegisterBase = 0;
                        DWORD dwShift = 0;
                        for( DWORD dwIndex = 0; dwIndex < dwSize; dwIndex++ )
                        {
                            m_dwCardRegisterBase += ( ( *( pDataPtr +
                                                           2 +
                                                           dwIndex ) ) <<
                                                      dwShift );
                            dwShift += 8;
                        }
                    }
                    // Get Base Register Present Mask.
                    DWORD dwSizeMask = ( ( ( *pDataPtr ) >> 2 ) & 0x3 ) + 1;
                    if( pGetTupleData->uDataLen >= 2 + dwSize + dwSizeMask )
                    {
                        m_dwCardRegisterMask = 0 ;
                        DWORD dwShift = 0;
                        for( DWORD dwIndex = 0;
                             dwIndex < dwSizeMask;
                             dwIndex++ )
                        {
                            m_dwCardRegisterMask += ( ( *( pDataPtr +
                                                           2 +
                                                           dwSize +
                                                           dwIndex ) ) <<
                                                      dwShift );
                            dwShift += 8;
                        }
                    }
                }
            }
        }
    }
    BOOL bReturn = ( m_dwCardRegisterBase != 0 );
    Unlock();
    DEBUGMSG(ZONE_ERROR && !bReturn, ( TEXT("CPCPcmciaCard::GetConfigureRegisterBase: Can't get PCMCIA register address. return FAILS\r\n")));
    return bReturn;
}
void CPCPcmciaCard::EventNotification( PSS_SOCKET_STATE pSocketState )
{
    DEBUGCHK( pSocketState );
    if( pSocketState )
    {
        Lock();
        DWORD dwEvent = ( pSocketState->dwEventMask& pSocketState->dwEventChanged );
        for( DWORD dwEventMask = 0x1; dwEventMask != 0; dwEventMask <<= 1 )
        {
            switch( dwEvent & dwEventMask )
            {
              case SOCK_EVENT_SUSPEND_RESUME:
                if( ( pSocketState->dwEventStatus & SOCK_EVENT_SUSPEND_RESUME ) !=
                    0 )
                    PowerUp();
                else
                    PowerDown();
                break;
              case SOCK_EVENT_PWRCYCLE:
                // Ready to use.
                DEBUGMSG( ZONE_FUNCTION,
                          ( TEXT( "CPCPcmciaCard::EventNotification (CARD_READY) on Function=%d,SocketIndex=%d \r\n" ),
                            GetCardFunctionNumber(),
                            GetSocketIndex() ) );
                if( ( pSocketState->dwEventStatus & SOCK_EVENT_PWRCYCLE ) !=
                    0 )
                {
                    if( m_bPowered == TRUE )
                    {
                        // Recover Configuration Space
                        DEBUGMSG( ZONE_FUNCTION,
                                  ( TEXT( "CPCCardBusCard::EventNotification (CARD_READY) recover\r\n" ) ) );
                    }
                    else
                    {
                        DEBUGMSG( ZONE_FUNCTION,
                                  ( TEXT( "CPCPcmciaCard::EventNotification (CARD_READY) Initilization\r\n" ) ) );
                        if( m_bRoot )
                        {
                            Lock();
                            ScanBus();
                            m_bRoot = FALSE;
                            Unlock();
                        }
                        m_bPowered = TRUE;
                        PCI_SLOT_NUMBER cSlotNumber;
                        cSlotNumber.u.AsULONG = 0;
                        cSlotNumber.u.bits.DeviceNumber = 0;
                        cSlotNumber.u.bits.FunctionNumber = GetCardFunctionNumber();
                        CPCCard::EventNotification( CE_POWER_CYCLE_ON,
                                                    ( m_SocketInfo.dwBusNumber & 0xffff ) +
                                                    ( m_SocketInfo.dwBusType <<
                                                      16 ),
                                                    cSlotNumber.u.AsULONG );
                    }
                }
                break;
              case SOCK_EVENT_WP:
                CPCCard::EventNotification( CE_WRITE_PROTECT );
                break;
              case SOCK_EVENT_LOCKED:
                CPCCard::EventNotification( CE_CARD_LOCK );
                break;
              case SOCK_EVENT_INSERT:
                CPCCard::EventNotification( CE_INSERTION_COMPLETE );
                break;
              case SOCK_EVENT_BVD1:
                CPCCard::EventNotification( CE_BATTERY_DEAD );
                break;
              case SOCK_EVENT_BVD2:
                CPCCard::EventNotification( CE_BATTERY_LOW );
                break;
            }
        };
        if( GetParentFunction() == NULL &&
            ( dwEvent & ~SOCK_EVENT_SUSPEND_RESUME ) != 0 )
        {
            // Do not do set for suspend and resume
            SS_SOCKET_STATE sSocketState;
            PDCardGetSocket( &sSocketState );  // Clean the change bit. 
            sSocketState.dwEventChanged = pSocketState->dwEventChanged;
            PDCardSetSocket( &sSocketState );  // Clean the change bit.                      
        }
        Unlock();
    }
}

BOOL CPCPcmciaCard::DeInit()
{
    Lock();
    if( m_pTurple != NULL )
    {
        delete m_pTurple;
        m_pTurple = NULL;
    }
    if( m_pCommonWindow != NULL )
    {
        delete m_pCommonWindow;
        m_pCommonWindow = NULL;
    }
    if( m_pAttributeWindow != NULL )
    {
        delete m_pAttributeWindow;
        m_pAttributeWindow = NULL;
    }
    if( m_ppPcmciaWindows )
    {
        for( DWORD dwIndex = 0;
             dwIndex < m_SocketInfo.dwNumOfWindows;
             dwIndex++ )
        {
            if( *( m_ppPcmciaWindows + dwIndex ) != NULL )
            {
                delete * ( m_ppPcmciaWindows + dwIndex );
                *( m_ppPcmciaWindows + dwIndex ) = NULL;
            }
        }
        delete m_ppPcmciaWindows;
        m_ppPcmciaWindows = NULL;
    }
    Unlock();
    return TRUE;
};
CPCPcmciaCard::~CPCPcmciaCard()
{
    DeInit();
    CardDisableCard();
}
#define TUPLEBUFFER_SIZE 512
BOOL CPCPcmciaCard::ScanBus()
{
    DWORD dwDeviceIndex = 0;
    CARD_TUPLE_PARMS tupleParms;
    // Get VERS_1 and FUNCID, MANFID, FUNCE for driver location.
    memset( &tupleParms, 0, sizeof( CARD_TUPLE_PARMS ) );
    tupleParms.hSocket = GetCardHandle();
    tupleParms.uDesiredTuple = CISTPL_LONGLINK_MFC;
    if( CardGetFirstTuple( &tupleParms ) == CERR_SUCCESS )
    {
        BYTE dataBuffer[TUPLEBUFFER_SIZE]; // Assume Maximun Turple Length is 512;
        PCARD_DATA_PARMS pTurpleData = ( PCARD_DATA_PARMS ) dataBuffer;
        memcpy( pTurpleData, &tupleParms, sizeof( CARD_TUPLE_PARMS ) );
        PCARD_DATA_PARMS pData = ( PCARD_DATA_PARMS ) pTurpleData;
        WORD wLength = pData->uBufLen = ( UINT16 )
                       ( TUPLEBUFFER_SIZE - sizeof( CARD_DATA_PARMS ) );
        pData->uDataLen = 0;
        if( CardGetTupleData( pData ) == CERR_SUCCESS )
        {
            // We found it . This is multi-function card.
            Lock();
            PBYTE pTupleData = dataBuffer + sizeof( CARD_DATA_PARMS );
            DWORD dwCurPos = 0 ;
            if( dwCurPos < pData->uDataLen )
            {
                BYTE uNumOfFunction = *( pTupleData + dwCurPos );
                dwCurPos ++;
                for( DWORD dwIndex = 0;
                     dwIndex < uNumOfFunction &&
                     dwCurPos + 5 <= pData->uDataLen;
                     dwIndex++ )
                {
                    BOOL bCommonAddr = ( *( pTupleData + dwCurPos ) != 0 );
                    dwCurPos ++;
                    DWORD dwFunctionDest = *( pTupleData + dwCurPos );
                    dwCurPos ++;
                    dwFunctionDest += ( ( *( pTupleData + dwCurPos ) ) << 8 );
                    dwCurPos ++;
                    dwFunctionDest += ( ( *( pTupleData + dwCurPos ) ) << 16 );
                    dwCurPos ++;
                    dwFunctionDest += ( ( *( pTupleData + dwCurPos ) ) << 24 );
                    dwCurPos ++;

                    dwFunctionDest |= ( bCommonAddr ==
                                        1 ?
                                        TUPLE_COMMON_MEMORY_FLAG :
                                        0 );
                    if( dwIndex == 0 )
                    {
                        m_dwFunctionDest = dwFunctionDest;
                        // Pass has changed so redo this.
                        m_dwCardRegisterBase = 0; // Undefined.
                        GetConfigureRegisterBase();
                    }
                    else
                    {
                        if( CPCCardContainer::g_pCardContainer )
                        {
                            CPCPcmciaCard* pNewCard = new CPCPcmciaCard( GetSocketService(),
                                                                         &m_SocketState,
                                                                         GetSocketHandle(),
                                                                         GetSocketIndex(),
                                                                         GetDeviceHandle(),
                                                                         this,
                                                                         dwIndex );
                            if( pNewCard ==
                                NULL ||
                                CPCCardContainer::g_pCardContainer->InsertObjectAtEmpty( NULL,
                                                                                         pNewCard ) ==
                                NULL )
                            {
                                // Success
                                DEBUGMSG( ZONE_ERROR,
                                          ( TEXT( "PCCARD.DLL : Can not construct new card(%x)!!!\r\n" ),
                                            pNewCard ) );
                                if( pNewCard )
                                {
                                    delete pNewCard;
                                    pNewCard = NULL;
                                };
                            }
                            else
                            {
                                pNewCard->m_dwFunctionDest = dwFunctionDest;
                                if( pNewCard->Init( FALSE ) != TRUE )
                                {
                                    // Init with No bus scan 
                                    DEBUGMSG( ZONE_ERROR,
                                              ( TEXT( "PCCARD.DLL : Can not Initial new card(%x)!!!\r\n" ),
                                                pNewCard ) );
                                    DEBUGCHK( FALSE );
                                    CPCCardContainer::g_pCardContainer->RemoveObjectBy( pNewCard );
                                }
                                else
                                {
                                    // Sent Ready to this function card.
                                    SS_SOCKET_STATE lSocketState;
                                    PDCardGetSocket( &lSocketState ); 
                                    lSocketState.dwEventChanged |= SOCK_EVENT_PWRCYCLE;
                                    lSocketState.dwEventStatus |= SOCK_EVENT_PWRCYCLE;
                                    pNewCard->EventNotification( &lSocketState );
                                }
                            };
                        }
                    }
                }
            }
            Unlock();
        }
    }
    return TRUE;
} 


STATUS CPCPcmciaCard::CardGetStatus( PCARD_STATUS pStatus )
{
    STATUS status = CERR_BAD_ARGS;
    if( pStatus && GetSocketHandle() != 0 )
    {
        SS_SOCKET_STATE SocketState;
        PDCardGetSocket( &SocketState );
        pStatus->fCardState = ( ( SocketState.dwEventStatus & SOCK_EVENT_CD ) !=
                                0 ?
                                EVENT_MASK_CARD_DETECT :
                                0 ) ;// @field current card state
        pStatus->fCardState |= ( ( SocketState.dwEventStatus & SOCK_EVENT_PWRCYCLE ) !=
                                 0 ?
                                 EVENT_MASK_CARD_READY :
                                 0 ) ;// @field current card state
        pStatus->fCardState |= ( ( SocketState.dwEventStatus & SOCK_EVENT_WP ) !=
                                 0 ?
                                 EVENT_MASK_WRITE_PROTECT :
                                 0 ) ;// @field current card state
        pStatus->fCardState |= ( ( SocketState.dwEventStatus & SOCK_EVENT_LOCKED ) !=
                                 0 ?
                                 EVENT_MASK_CARD_LOCK :
                                 0 ) ;// @field current card state
        pStatus->fCardState |= ( ( SocketState.dwEventStatus & SOCK_EVENT_EJECT ) !=
                                 0 ?
                                 EVENT_MASK_EJECT_REQ :
                                 0 ) ;// @field current card state
        pStatus->fCardState |= ( ( SocketState.dwEventStatus & SOCK_EVENT_INSERT ) !=
                                 0 ?
                                 EVENT_MASK_INSERT_REQ :
                                 0 ) ;// @field current card state
        pStatus->fCardState |= ( ( SocketState.dwEventStatus & SOCK_EVENT_BVD1 ) !=
                                 0 ?
                                 EVENT_MASK_BATTERY_DEAD :
                                 0 ) ;// @field current card state
        pStatus->fCardState |= ( ( SocketState.dwEventStatus & SOCK_EVENT_BVD2 ) !=
                                 0 ?
                                 EVENT_MASK_BATTERY_LOW :
                                 0 ) ;// @field current card state
        pStatus->fCardState |= ( ( SocketState.dwEventStatus & SOCK_EVENT_SUSPEND_RESUME ) !=
                                 0 ?
                                 EVENT_MASK_POWER_MGMT :
                                 0 ) ;// @field current card state

        pStatus->fSocketState = pStatus->fCardState;
        status = CERR_SUCCESS;
    }
    return status;
}
STATUS CPCPcmciaCard::CardRequestIRQLine( UINT16 dwIrqBit,
                                          PDWORD pdwIrqOrSysIntrNumber,
                                          PDWORD pdwIsSysIntr )
{
    CPCPcmciaCard* pPCard = ( CPCPcmciaCard* ) GetParentFunction();
    if( pPCard != NULL )
    {
        return pPCard->CardRequestIRQLine( dwIrqBit,
                                           pdwIrqOrSysIntrNumber,
                                           pdwIsSysIntr );
    }

    STATUS status = CERR_BAD_ARGS;
    UINT16 dwBitShift = 1;
    Lock();
    if( ( m_SocketInfo.dwSocketCaps & SOCK_CAP_ONLY_SYSINTR ) != 0 &&
        m_bSysInterAllocated )
    {
        status = CERR_IN_USE;
    }
    else
    {
        for( DWORD dwIndex = 0;
             dwIndex < IRQ_ROUTINGTABLE_SIZE;
             dwIndex++,dwBitShift <<= 1 )
        {
            if( ( dwIrqBit & dwBitShift ) != 0 &&
                m_SocketInfo.bArrayIrqRouting[dwIndex] != ( BYTE ) - 1 )
            {
                // found mapping.
                SS_SOCKET_STATE lSocketState;
                if( ( status = PDCardGetSocket( &lSocketState ) ==
                      CERR_SUCCESS ) )
                {
                    // Enable Socket Interrupt.
                    lSocketState.dwInteruptStatus |= SOCK_INT_FUNC_IRQ_ROUTING;
                    lSocketState.fIREQRouting = m_SocketInfo.bArrayIrqRouting[dwIndex];
                    status = PDCardSetSocket( &lSocketState );
                }
                if( status == CERR_SUCCESS )
                {
                    if( pdwIrqOrSysIntrNumber )
                        *pdwIrqOrSysIntrNumber = m_SocketInfo.bArrayIrqRouting[dwIndex];
                    if( pdwIsSysIntr )
                        *pdwIsSysIntr = ( ( m_SocketInfo.dwSocketCaps & SOCK_CAP_ONLY_SYSINTR ) !=
                                          0 ?
                                          1 :
                                          0 );
                    if( ( m_SocketInfo.dwSocketCaps & SOCK_CAP_ONLY_SYSINTR ) !=
                        0 )
                        m_bSysInterAllocated = TRUE;
                }
                else
                    DEBUGCHK( FALSE );
                break;
            }
        }
    }
    Unlock();
    DEBUGCHK( status == CERR_SUCCESS );
    return status;
}
STATUS CPCPcmciaCard::CardReleaseIRQ()
{
    CPCPcmciaCard* pPCard = ( CPCPcmciaCard* ) GetParentFunction();
    if( pPCard != NULL )
    {
        return pPCard->CardReleaseIRQ();
    }
    Lock();
    m_bSysInterAllocated = FALSE;
    STATUS status = CPCCard::CardReleaseIRQ();
    Unlock();
    return status;
}

#define NUM_REGISTERS 5     // number of function configuration registers
#define NUM_EXT_REGISTERS 4 // number of additional function configuration registers

STATUS CPCPcmciaCard::CardRequestConfiguration( PCARD_CONFIG_INFO pParms )
{
    STATUS status = CERR_SUCCESS;
    SS_SOCKET_STATE curState;
    DWORD pwrEntry = 0;
    Lock();
    if( ( status = PDCardGetSocket( &curState ) ) == CERR_SUCCESS )
    {
        // IRQ Routing Enable when Request IRQ.
        //if (pParms->fAttributes & CFG_ATTR_IRQ_STEERING) {
        //    curState.fIREQRouting=1;
        //}
        curState.dwInterfaceType = pParms->fInterfaceType;
        UINT8 fVcc = curState.fVcc;
        if( pParms->uVcc != -1 &&
                ValidPowerEntry( PWR_SUPPLY_VCC, pParms->uVcc ) && // Valid Number;
                GetVotageEntry( &pwrEntry, pParms->uVcc, PWR_SUPPLY_VCC ) )
            fVcc = ( BYTE ) pwrEntry;

        if( m_dwFunctionDest != 0 )
        {
            // We only can change power for signle function card.
            if( curState.fVcc != fVcc )
            {
                Unlock();
                return CERR_BAD_VCC;
            }
        }
        else
        {
            if( m_pssPowerEntry && fVcc != curState.fVcc && 
                    fVcc < m_SocketInfo.dwNumOfPowerEntry && curState.fVcc < m_SocketInfo.dwNumOfPowerEntry ) {
                if( pParms->uVcc <= ( m_pssPowerEntry + curState.fVcc )->uPowerLevel )
                    curState.fVcc = fVcc;
                else
                    DEBUGMSG( ZONE_WARN,( TEXT( "PcmciaC :Voltage %d Hight than initial value(%d) Ignored !!!\r\n" ),
                                pParms->uVcc, ( m_pssPowerEntry + curState.fVcc )->uPowerLevel ) );
            }
        }

        if( pParms->uVpp1 != -1 &&
            ValidPowerEntry( PWR_SUPPLY_VPP1,
                                                    pParms->uVpp1 ) &&
            GetVotageEntry( &pwrEntry,
                            pParms->uVpp1,
                            PWR_SUPPLY_VPP1 ) )
            curState.uVpp1 = ( BYTE ) pwrEntry;
        if( pParms->uVpp2 != -1 &&
            ValidPowerEntry( PWR_SUPPLY_VPP2,
                                                    pParms->uVpp2 ) &&
            GetVotageEntry( &pwrEntry,
                            pParms->uVpp2,
                            PWR_SUPPLY_VPP2 ) )
            curState.uVpp2 = ( BYTE ) pwrEntry;
        
        if ((pParms->fAttributes & (CFG_ATTR_KEEP_POWERED|CFG_ATTR_IRQ_WAKEUP)) != 0) 
            curState.dwInteruptStatus |= SOCK_INT_FUNC_IRQ_WAKE;
        else {
            curState.dwInteruptStatus &= ~SOCK_INT_FUNC_IRQ_WAKE;
            if ( (pParms->fAttributes & CFG_ATTR_NO_SUSPEND_UNLOAD)== 0  ){
                curState.dwInteruptStatus &= ~SOCK_INT_STATUS_CHG_WAKE;
            }                
        }
        
        PDCardSetSocket( &curState );
    }
    DEBUGMSG( ZONE_MDD,
              ( TEXT( "CPCPcmciaCard::CardRequestConfiguration(RegisterBase=0x%x,RegiserMask = 0x%x\r\n" ),
                m_dwCardRegisterBase,
                m_dwCardRegisterMask ) );
    if( m_pTurple )
    {
        if( pParms->fRegisters & CFG_REGISTER_CONFIG )
            pParms->uConfigReg = WriteCardRegister( 0,
                                                    pParms->uConfigReg |
                                                    FCR_COR_LEVEL_IREQ );
        if( pParms->fRegisters & CFG_REGISTER_STATUS )
            pParms->uStatusReg = WriteCardRegister( 1,
                                                    ( pParms->uStatusReg & ~FCR_FCSR_INTR_ACK ) );
        if( pParms->fRegisters & CFG_REGISTER_PIN )
            pParms->uPinReg = WriteCardRegister( 2, pParms->uPinReg );
        if( pParms->fRegisters & CFG_REGISTER_COPY )
            pParms->uCopyReg = WriteCardRegister( 3, pParms->uCopyReg );
        if( pParms->fRegisters & CFG_REGISTER_EXSTATUS )
        {
            pParms->uExtendedStatus = WriteCardRegister( 4,
                                                         pParms->uExtendedStatus );
        }
        if( pParms->fRegisters & CFG_REGISTER_EXREG )
        {
            WORD wFlag = 0x1;
            for( DWORD dwIndex = 0 ; dwIndex < NUM_EXT_REGISTERS; dwIndex++ )
            {
                if( wFlag & pParms->fExtRegisters )
                {
                    pParms->IOBase[dwIndex] = WriteCardRegister( NUM_REGISTERS +
                                                                 dwIndex,
                                                                 pParms->IOBase[dwIndex] );
                }
                wFlag <<= 1;
            }
            if( pParms->fExtRegisters & CFG_EXREGISTER_IOLIMIT )
            {
                pParms->IOLimit = WriteCardRegister( NUM_REGISTERS +
                                                     NUM_EXT_REGISTERS,
                                                     pParms->IOLimit );
            }
        }
    }
    m_BackupConfig = *pParms;
    Unlock();
    return status;
}

STATUS CPCPcmciaCard::CardReleaseConfiguration()
{
    STATUS status = CERR_SUCCESS;
    return status;
}
STATUS CPCPcmciaCard::CardModifyConfiguration( PUINT16 pfAttributes )
{
    STATUS status = CERR_SUCCESS;
    Lock();
    if( GetParentFunction() == NULL )
    {
        // It only can be used by first function..
        SS_SOCKET_STATE curState;
        if( pfAttributes &&
            ( status = PDCardGetSocket( &curState ) ) == CERR_SUCCESS )
        {
            if (*pfAttributes & (CFG_ATTR_KEEP_POWERED|CFG_ATTR_IRQ_WAKEUP)) 
                curState.dwInteruptStatus |=  SOCK_INT_FUNC_IRQ_WAKE;
            else {
                curState.dwInteruptStatus &= ~SOCK_INT_FUNC_IRQ_WAKE;
                if ( (*pfAttributes & CFG_ATTR_NO_SUSPEND_UNLOAD)== 0  ){
                    curState.dwInteruptStatus &= ~SOCK_INT_STATUS_CHG_WAKE;
                }                
            }
            
            status = PDCardSetSocket( &curState );
        }
    }
    Unlock();
    return status;
}
STATUS CPCPcmciaCard::CardAccessConfigurationRegister( UINT8 rw_flag,
                                                       UINT8 offset,
                                                       UINT8* pValue )
{
    DWORD dwRegisterBit = ( 1 << offset );
    if( m_dwCardRegisterBase != 0 &&
        ( m_dwCardRegisterMask & dwRegisterBit ) != 0 &&
        pValue )
    {
        Lock();
        if( rw_flag == CARD_FCR_READ )
        {
            *pValue = ReadCardRegister( offset );
        }
        else
        {
            WriteCardRegister( offset, *pValue );
        }
        Unlock();
        return CERR_SUCCESS;
    }
    else
    {
        return CERR_BAD_ARGS;
    }
}
STATUS CPCPcmciaCard::CardRequestConfigRegisterPhAddr( PCARD_WINDOW_ADDRESS pCardWindowAddr,
                                                       PDWORD pOffset )
{
    STATUS status = CERR_BAD_ARGS;
    if( m_dwCardRegisterBase != 0 )
    {
        Lock();
        BOOL bAttr = ( ( m_dwCardRegisterBase& TUPLE_COMMON_MEMORY_FLAG ) !=
                       0 ?
                       FALSE :
                       TRUE );
        CPcmciaMemWindow* pConfigWindow = GetMemoryWindow( bAttr );
        if( pConfigWindow->IsFixedWindow() && pCardWindowAddr && pOffset )
        {
            *pCardWindowAddr = pConfigWindow->GetWindowPhAddr();
            DEBUGCHK( pCardWindowAddr->uCardAddress == 0 );
            *pOffset = ( m_dwCardRegisterBase & TUPLE_ADDRESS_MASK );
            status = CERR_SUCCESS;
        }
        Unlock();
    }
    DEBUGCHK( status == CERR_SUCCESS );
    return status;
}
UINT16 CPCPcmciaCard::CardRequestWindowNoSpecial( PCARD_WINDOW_PARMS pCardWinParms )
{
    CPCPcmciaCard* pPCard = ( CPCPcmciaCard* ) GetParentFunction();
    if( pPCard != NULL )
    {
        return pPCard->CardRequestWindow( pCardWinParms );
    }

    UINT16 uReturn = ( UINT16 ) - 1;
    if( pCardWinParms != NULL )
    {
        Lock();
        for( UINT16 uIndex = 0;
             uIndex < ( UINT16 ) m_SocketInfo.dwNumOfWindows;
             uIndex++ )
        {
            if( *( m_ppPcmciaWindows + uIndex ) !=
                NULL &&
                ( *( m_ppPcmciaWindows + uIndex ) )->CardRequestWindow( pCardWinParms ) )
            {
                uReturn = uIndex;
                break;
            }
        }
        Unlock();
    };
    return uReturn;
}

#define PCMCIA_COMMON_MEMORY_HANDLE (WORD)(-2)
#define PCMCIA_ATTRIBUTE_MEMORY_HANDLE (WORD)(-3)
UINT16 CPCPcmciaCard::CardRequestWindow( PCARD_WINDOW_PARMS pCardWinParms )
{
    CPCPcmciaCard* pPCard = ( CPCPcmciaCard* ) GetParentFunction();
    if( pPCard != NULL )
    {
        return pPCard->CardRequestWindow( pCardWinParms );
    }

    UINT16 uReturn = ( UINT16 ) - 1;
    if( pCardWinParms != NULL )
    {
        Lock();
        // Memory Window Handles, It needed for Fixed Windows implementation.
        if( ( pCardWinParms-> fAttributes & WIN_ATTR_IO_SPACE ) == 0 )
        {
            if( ( pCardWinParms-> fAttributes & WIN_ATTR_ATTRIBUTE ) )
            {
                // Attribute Memory
                if( !m_bPrimaryAttrMemMapped )
                {
                    if( m_pAttributeWindow &&
                        !m_pAttributeWindow->IsFixedWindow() )
                    {
                        // We can not remap fixed window
                        delete m_pAttributeWindow;
                        m_pAttributeWindow = NULL;
                    }
                    if( m_pAttributeWindow == NULL )
                    {
                        m_pAttributeWindow = new CPcmciaMemWindow( this,
                                                                   TRUE,
                                                                   pCardWinParms->uWindowSize );
                        if( m_pAttributeWindow && m_pAttributeWindow->Init() )
                        {
                            m_bPrimaryAttrMemMapped = TRUE;
                            uReturn = PCMCIA_ATTRIBUTE_MEMORY_HANDLE;
                        }
                        else if( m_pAttributeWindow )
                        {
                            delete m_pAttributeWindow;  
                            m_pAttributeWindow = NULL;
                        }
                    }
                    else
                    {
                        m_bPrimaryAttrMemMapped = TRUE;
                        uReturn = PCMCIA_ATTRIBUTE_MEMORY_HANDLE;
                    }
                }
            }
            else
            {
                // Common Memory.
                if( !m_bPrimaryCommonMemMapped )
                {
                    if( m_pCommonWindow && !m_pCommonWindow->IsFixedWindow() )
                    {
                        delete m_pCommonWindow;
                        m_pCommonWindow = NULL;
                    }
                    if( m_pCommonWindow == NULL )
                    {
                        m_pCommonWindow = new CPcmciaMemWindow( this,
                                                                FALSE,
                                                                pCardWinParms->uWindowSize );
                        if( m_pCommonWindow && m_pCommonWindow->Init() )
                        {
                            m_bPrimaryCommonMemMapped = TRUE;
                            uReturn = PCMCIA_COMMON_MEMORY_HANDLE;
                        }
                        else if( m_pCommonWindow )
                        {
                            delete m_pCommonWindow;
                            m_pCommonWindow = NULL;
                        }
                    }
                    else
                    {
                        m_bPrimaryCommonMemMapped = TRUE;
                        uReturn = PCMCIA_COMMON_MEMORY_HANDLE;
                    }
                }
            }
        }
        if( uReturn == ( UINT16 ) - 1 )
        {
            // If it is not resolved do Nomal Napping.
            uReturn = CardRequestWindowNoSpecial( pCardWinParms );
        }
        Unlock();
    };
    return uReturn;
}
STATUS CPCPcmciaCard::CardReleaseWindow( UINT16 uWinIndex )
{
    STATUS status = CERR_BAD_WINDOW;
    CPCPcmciaCard* pPCard = ( CPCPcmciaCard* ) GetParentFunction();
    if( pPCard != NULL )
    {
        return pPCard->CardReleaseWindow( uWinIndex );
    }

    Lock();
    if( uWinIndex == PCMCIA_ATTRIBUTE_MEMORY_HANDLE )
    {
        m_bPrimaryAttrMemMapped = FALSE;
        if( m_pAttributeWindow && !m_pAttributeWindow->IsFixedWindow() )
        {
            // We can not remap fixed window
            delete m_pAttributeWindow;
            m_pAttributeWindow = NULL;
        }
        status = CERR_SUCCESS;
    }
    else if( uWinIndex == PCMCIA_COMMON_MEMORY_HANDLE )
    {
        m_bPrimaryCommonMemMapped = FALSE;
        if( m_pCommonWindow && !m_pCommonWindow->IsFixedWindow() )
        {
            delete m_pCommonWindow;
            m_pCommonWindow = NULL;
        }
        status = CERR_SUCCESS;
    }
    else if( uWinIndex < ( UINT16 ) m_SocketInfo.dwNumOfWindows &&
             *( m_ppPcmciaWindows + uWinIndex ) != NULL )
    {
             ( *( m_ppPcmciaWindows + uWinIndex ) )->CardReleaseWindow();
             status = CERR_SUCCESS;
    }
    Unlock();
    return status;
}

STATUS CPCPcmciaCard::CardMapWindowPhysical( UINT16 uWinIndex,
                                             PCARD_WINDOW_ADDRESS pCardWindowAddr )
{
    STATUS status = CERR_BAD_WINDOW;
    if( !pCardWindowAddr ||
        pCardWindowAddr->uCardAddress +
        pCardWindowAddr->uSize <=
        pCardWindowAddr->uCardAddress )
    {
        // NoAddr structure or Overflowed address range.
        return status;
    }
    CPCPcmciaCard* pPCard = ( CPCPcmciaCard* ) GetParentFunction();
    if( pPCard != NULL )
    {
        return pPCard->CardMapWindowPhysical( uWinIndex, pCardWindowAddr );
    }
    Lock();
    if( uWinIndex == PCMCIA_ATTRIBUTE_MEMORY_HANDLE )
    {
        if( m_pAttributeWindow &&
            m_bPrimaryAttrMemMapped &&
            m_pAttributeWindow->MapWindowPhysical( pCardWindowAddr ) )
        {
            status = CERR_SUCCESS;
        }
    }
    else if( uWinIndex == PCMCIA_COMMON_MEMORY_HANDLE )
    {
        if( m_pCommonWindow &&
            m_bPrimaryCommonMemMapped &&
            m_pCommonWindow->MapWindowPhysical( pCardWindowAddr ) )
        {
            status = CERR_SUCCESS;
        }
    }
    else if( uWinIndex <
             m_SocketInfo.dwNumOfWindows &&
             *( m_ppPcmciaWindows + uWinIndex ) &&
             ( *( m_ppPcmciaWindows + uWinIndex ) )->CardMapWindowPhysical( pCardWindowAddr ) )
    {
        status = CERR_SUCCESS;
    }
    Unlock();
    return status;
};

STATUS CPCPcmciaCard::CardGetWindowInfo( UINT16 uWindowIndex,
                                         PSS_WINDOW_INFO pWinInfo )
{
    STATUS status = CERR_BAD_WINDOW;
    CPCPcmciaCard* pPCard = ( CPCPcmciaCard* ) GetParentFunction();
    if( pPCard != NULL )
    {
        return pPCard->CardGetWindowInfo( uWindowIndex, pWinInfo );
    }
    Lock();
    if( uWindowIndex == PCMCIA_ATTRIBUTE_MEMORY_HANDLE )
    {
        if( m_pAttributeWindow &&
            m_pAttributeWindow->GetWindowInfo( pWinInfo ) )
        {
            status = CERR_SUCCESS;
        }
    }
    else if( uWindowIndex == PCMCIA_COMMON_MEMORY_HANDLE )
    {
        if( m_pCommonWindow && m_pCommonWindow->GetWindowInfo( pWinInfo ) )
        {
            status = CERR_SUCCESS;
        }
    }
    else if( uWindowIndex < m_SocketInfo.dwNumOfWindows &&
             *( m_ppPcmciaWindows + uWindowIndex ) &&
             pWinInfo )
    {
        *pWinInfo = ( *( m_ppPcmciaWindows + uWindowIndex ) )->CardGetWindowInfo();
             status = CERR_SUCCESS;
    }
    Unlock();
    return status;
}

CPcmciaWindows::CPcmciaWindows( CPCPcmciaCard* pPcmciaCard, DWORD dwIndex ) : m_pPcmciaCard( pPcmciaCard ),
                                                                              m_dwWinIndex( dwIndex )
{
    PREFAST_DEBUGCHK( m_pPcmciaCard != NULL );
    m_bRequested = FALSE;
    m_pPcmciaCard->PDCardInquireWindow( m_dwWinIndex, &m_WinInfo );
    m_dwIoResourceBase = 0;
    m_dwIoResourceLen = 0;
}

CPcmciaWindows::~CPcmciaWindows()
{
    CardReleaseWindow();
}

BOOL CPcmciaWindows::CardRequestWindow( PCARD_WINDOW_PARMS pCardWinParms )
{
    SS_WINDOW_STATE sWindowState;
    if( m_bRequested !=
        TRUE &&
        m_pPcmciaCard->PDCardGetWindow( m_dwWinIndex,
                                                                &sWindowState ) ==
        CERR_SUCCESS )
    {
        if( sWindowState.uOffset + sWindowState.uSize == 0 )
        {
            BOOL reqiredTypeIO = ( ( ( pCardWinParms-> fAttributes& WIN_ATTR_IO_SPACE ) !=
                                     0 ) ?
                                   TRUE :
                                   FALSE );
            BOOL TypeIO = ( ( ( m_WinInfo.fWindowCaps& WIN_CAP_IO ) != 0 ) ?
                            TRUE :
                            FALSE );
            if( reqiredTypeIO != TypeIO )
                return FALSE;
            UINT16 fAccessCap = ( reqiredTypeIO ?
                                  m_WinInfo.fIOCaps :
                                  m_WinInfo.fMemoryCaps );
            if( ( pCardWinParms->fAttributes & WIN_ATTR_16BIT ) != 0 &&
                ( fAccessCap & MEM_CAP_16BIT ) == 0 )
                return FALSE;
            if( ( pCardWinParms->fAttributes & WIN_ATTR_16BIT ) == 0 &&
                ( fAccessCap & MEM_CAP_8BIT ) == 0 )
                return FALSE;
            m_bRequested = TRUE;
            m_dwIoResourceBase = m_dwIoResourceLen = 0;
            m_CardWinParms = *pCardWinParms;
            return TRUE;
        }
    };
    return FALSE;
}

BOOL CPcmciaWindows::CardReleaseWindow()
{
    SS_WINDOW_STATE sWindowState;
    if( m_bRequested ==
        TRUE &&
        m_pPcmciaCard->PDCardGetWindow( m_dwWinIndex,
                                                                &sWindowState ) ==
        CERR_SUCCESS )
    {
        m_bRequested = FALSE;
        if( m_dwIoResourceLen )
        {
            ResourceRelease( g_PcCardIoResourceID,
                             m_dwIoResourceBase,
                             m_dwIoResourceLen );
            m_dwIoResourceBase = m_dwIoResourceLen = 0;
        }
        if( ( sWindowState.fState & WIN_STATE_ENABLED ) != 0 ||
            sWindowState.uOffset + sWindowState.uSize != 0 )
        {
            sWindowState.fState &= ~WIN_STATE_ENABLED;
            sWindowState.uOffset = sWindowState.uSize = 0;
            if( m_pPcmciaCard->PDCardSetWindow( m_dwWinIndex, &sWindowState ) !=
                CERR_SUCCESS )
                return FALSE;
        }
        return TRUE;
    }
    return FALSE;
}

BOOL CPcmciaWindows::CardMapWindowPhysical( PCARD_WINDOW_ADDRESS pCardWindowAddr )
{
    SS_WINDOW_STATE sWindowState;
    if( pCardWindowAddr &&
        m_bRequested ==
        TRUE &&
        m_pPcmciaCard->PDCardGetWindow( m_dwWinIndex,
                                        &sWindowState ) ==
        CERR_SUCCESS )
    {
        if( m_dwIoResourceLen )
        {
            ResourceRelease( g_PcCardIoResourceID,
                             m_dwIoResourceBase,
                             m_dwIoResourceLen );
            m_dwIoResourceBase = m_dwIoResourceLen = 0;
        }
        if( ( m_CardWinParms.fAttributes & WIN_ATTR_IO_SPACE ) !=
            0 &&
            !ResourceRequest( g_PcCardIoResourceID,
                              pCardWindowAddr->uCardAddress,
                              pCardWindowAddr->uSize ) )
        {
            DEBUGMSG( ZONE_MDD |
                      ZONE_WARN,
                      ( TEXT( "CPcmciaWindows::CardMapWindowPhysical:RsourceRequest(%x,%x,%x )fail!!!" ),
                        g_PcCardIoResourceID,
                        pCardWindowAddr->uCardAddress,
                        pCardWindowAddr->uSize ) );
            return FALSE;
        }
        sWindowState.fState |= WIN_STATE_ENABLED;
        if( ( m_CardWinParms.fAttributes & WIN_ATTR_IO_SPACE ) != 0 )
            sWindowState.fState |= WIN_STATE_MAPS_IO;
        else
            sWindowState.fState &= ~WIN_STATE_MAPS_IO;

        if( ( m_CardWinParms.fAttributes & WIN_ATTR_ATTRIBUTE ) != 0 )
            sWindowState.fState |= WIN_STATE_ATTRIBUTE;
        else
            sWindowState.fState &= ~WIN_STATE_ATTRIBUTE;
        if( ( m_CardWinParms.fAttributes & WIN_ATTR_16BIT ) != 0 )
            sWindowState.fState |= WIN_STATE_16BIT;
        else
            sWindowState.fState &= ~WIN_STATE_16BIT;
        // Speed is same definition both Card and socket.
        sWindowState.fSpeed = m_CardWinParms.fAccessSpeed;
        sWindowState.uOffset = pCardWindowAddr->uCardAddress;
        sWindowState.uSize = pCardWindowAddr->uSize;
        if( m_pPcmciaCard->PDCardSetWindow( m_dwWinIndex, &sWindowState ) ==
            CERR_SUCCESS )
        {
            if( ( m_CardWinParms.fAttributes & WIN_ATTR_IO_SPACE ) != 0 )
            {
                m_dwIoResourceBase = pCardWindowAddr->uCardAddress;
                m_dwIoResourceLen = pCardWindowAddr->uSize;
            }
            pCardWindowAddr->uCardAddress = sWindowState.uOffset ;
            pCardWindowAddr->uSize = sWindowState.uSize ;
            pCardWindowAddr->uWindowPhAddr = sWindowState.uBase;
            pCardWindowAddr->uGranularity = m_WinInfo.uIOGranularity;
            pCardWindowAddr->fAttributes = ( ( sWindowState.fState & WIN_STATE_ENABLED ) !=
                                             0 ?
                                             WIN_ATTR_ENABLED :
                                             0 );
            pCardWindowAddr->fAttributes |= ( ( sWindowState.fState & WIN_STATE_MAPS_IO ) !=
                                              0 ?
                                              WIN_ATTR_IO_SPACE :
                                              0 );
            pCardWindowAddr->fAttributes |= ( ( sWindowState.fState & WIN_STATE_ATTRIBUTE ) !=
                                              0 ?
                                              WIN_ATTR_16BIT :
                                              0 );
            pCardWindowAddr->fAttributes |= ( ( sWindowState.fState & WIN_STATE_SHARED_IO ) !=
                                              0 ?
                                              WIN_ATTR_SHARED_IO :
                                              0 );
            pCardWindowAddr->fAccessSpeed = sWindowState.fSpeed;
            DEBUGMSG( ZONE_MDD,
                      ( TEXT( "CPcmciaWindows::CardMapWindowPhysical: return Success with ph=%x,Offset=%x,len=%x!!!" ),
                        pCardWindowAddr->uWindowPhAddr,
                        pCardWindowAddr->uCardAddress,
                        pCardWindowAddr->uSize ) );
            return TRUE;
        }
        else
        {
            if( ( m_CardWinParms.fAttributes & WIN_ATTR_IO_SPACE ) != 0 )
                ResourceRelease( g_PcCardIoResourceID,
                                 pCardWindowAddr->uCardAddress,
                                 pCardWindowAddr->uSize );
            DEBUGMSG( ZONE_MDD |
                      ZONE_WARN,
                      ( TEXT( "CPcmciaWindows::CardMapWindowPhysical:PDCardSetWindow!!!" ) ) );
        }
    }
    return FALSE;
}

CPcmciaMemWindow::CPcmciaMemWindow( CPCPcmciaCard* pPcmciaCard,
                                    BOOL bAttr,
                                    DWORD dwSize ) : m_pPcmciaCard( pPcmciaCard ),
                                                     m_bAttrMem( bAttr ),
                                                     m_dwWinSize( dwSize )
{
    PREFAST_DEBUGCHK( pPcmciaCard );
    m_WindowAddr.hSocket = m_WinParms.hSocket = m_pPcmciaCard->GetCardHandle();
    m_WinParms.fAttributes = ( m_bAttrMem ? WIN_ATTR_ATTRIBUTE : 0 );
    m_WinParms.uWindowSize = m_dwWinSize * 2;
    m_WindowAddr.uSize = m_dwWinSize;
    m_WinParms.fAccessSpeed = 0; // for any speed.
    m_uWinIndex = ( UINT16 ) - 1;
    m_WindowAddr.uCardAddress = 0 ;
    m_pVirtualAddr = NULL;
    m_b16bitAccess = FALSE;
#ifndef PCCARD_NO_LEGACY_SUPPORT
    m_bFixedWindow = TRUE;
#else
    m_bFixedWindow = FALSE;
#endif
}
BOOL CPcmciaMemWindow::Init()
{
    m_uWinIndex = m_pPcmciaCard->CardRequestWindowNoSpecial( &m_WinParms );
    if( m_uWinIndex == ( UINT16 ) - 1 )
    {
        // Fails, try 16-bit access.
        m_WinParms.fAttributes |= WIN_ATTR_16BIT;
        m_b16bitAccess = TRUE;
        m_uWinIndex = m_pPcmciaCard->CardRequestWindowNoSpecial( &m_WinParms );
    }
    if( m_uWinIndex != ( UINT16 ) - 1 )
    {
        // sucess
        if( m_bFixedWindow )
        {
            // Change Window Size to Maximun.
            SS_WINDOW_INFO sWinInfo;
            if( m_pPcmciaCard->CardGetWindowInfo( m_uWinIndex, &sWinInfo ) ==
                CERR_SUCCESS )
            {
                m_dwWinSize = min( sWinInfo.uMemMaxSize,
                                   MAX_PHYSICAL_MAP_SIZE );
                m_WinParms.uWindowSize = m_dwWinSize;
                m_WindowAddr.uSize = m_dwWinSize;
                m_WindowAddr.uCardAddress = 0;
            }
        }
        if( m_pPcmciaCard->CardMapWindowPhysical( m_uWinIndex, &m_WindowAddr ) ==
            CERR_SUCCESS )
        {
            PHYSICAL_ADDRESS ioPhysicalBase;
            ioPhysicalBase.LowPart = m_WindowAddr.uWindowPhAddr;
            ioPhysicalBase.HighPart = 0;
            ULONG inIoSpace = 0;
            if( m_WindowAddr.uGranularity <= 1 )
                m_WindowAddr.uGranularity = 1;
            if( HalTranslateBusAddress( ( INTERFACE_TYPE )
                                        ( ( m_pPcmciaCard->GetSocketInfo() ).dwBusType ),
                                        ( m_pPcmciaCard->GetSocketInfo() ).dwBusNumber,
                                        ioPhysicalBase,
                                        &inIoSpace,
                                        &ioPhysicalBase ) )
            {
                if( !inIoSpace )
                {
                    if( ( m_pVirtualAddr = ( PUCHAR )
                          MmMapIoSpace( ioPhysicalBase,
                                        m_WindowAddr.uSize * m_WindowAddr.uGranularity,
                                        FALSE ) ) !=
                        NULL )
                    {
                        return TRUE;
                    }
                    else
                    {
                        // We may as well not continue
                        DEBUGMSG( ZONE_MDD,
                                  ( TEXT( "PCMCIA: Error mapping I/O Ports.\r\n" ) ) );
                        DEBUGCHK( FALSE );
                    }
                }
                else
                {
                    DEBUGMSG( ZONE_MDD,
                              ( TEXT( "PCMCIA: Error: HalTranslateBusAddress mapping ATTR or COMMON to I/O Ports.\r\n" ) ) );
                    DEBUGCHK( FALSE );
                }
            }
        }
    }
    DEBUGCHK( FALSE );
    return FALSE;
}

CPcmciaMemWindow::~CPcmciaMemWindow()
{
    if( m_pVirtualAddr )
    {
        MmUnmapIoSpace( m_pVirtualAddr, 0 );
        m_pVirtualAddr = NULL;
    }
    if( m_uWinIndex != ( DWORD ) - 1 )
    {
        m_pPcmciaCard->CardReleaseWindow( m_uWinIndex );
        m_uWinIndex = ( UINT16 ) - 1;
    }
}

BOOL CPcmciaMemWindow::MapWindowView( DWORD dwAddress )
{
    DWORD dwOldBaseAddr = m_WindowAddr.uWindowPhAddr;
    BOOL bReturn = FALSE;
    if( !m_bFixedWindow &&
        ( dwAddress < m_WindowAddr.uCardAddress ||
          dwAddress >= m_WindowAddr.uCardAddress + m_WindowAddr.uSize ) )
    {
        // Out of Range. Re-map it.
        m_WindowAddr.uCardAddress = dwAddress ;
        m_WindowAddr.uSize = m_dwWinSize;
        if( m_pPcmciaCard->CardMapWindowPhysical( m_uWinIndex, &m_WindowAddr ) ==
            CERR_SUCCESS &&
            ( dwAddress >= m_WindowAddr.uCardAddress &&
              dwAddress < m_WindowAddr.uCardAddress + m_WindowAddr.uSize ) )
        {
            // Success.
            if( dwOldBaseAddr != m_WindowAddr.uWindowPhAddr &&
                m_pVirtualAddr != NULL )
            {
                // Base Address has changed we need remapped 
                MmUnmapIoSpace( m_pVirtualAddr, 0 );
                m_pVirtualAddr = NULL;
            }
            if( m_WindowAddr.uGranularity <= 1 )
                m_WindowAddr.uGranularity = 1;
            if( m_pVirtualAddr == NULL )
            {
                PHYSICAL_ADDRESS ioPhysicalBase;
                ioPhysicalBase.LowPart = m_WindowAddr.uWindowPhAddr;
                ioPhysicalBase.HighPart = 0;
                ULONG inIoSpace = 0;

                if( HalTranslateBusAddress( ( INTERFACE_TYPE )
                                            ( ( m_pPcmciaCard->GetSocketInfo() ).dwBusType ),
                                            ( m_pPcmciaCard->GetSocketInfo() ).dwBusNumber,
                                            ioPhysicalBase,
                                            &inIoSpace,
                                            &ioPhysicalBase ) )
                {
                    if( !inIoSpace )
                    {
                        if( ( m_pVirtualAddr = ( PUCHAR )
                              MmMapIoSpace( ioPhysicalBase,
                                            m_WindowAddr.uSize * m_WindowAddr.uGranularity,
                                            FALSE ) ) ==
                            NULL )
                        {
                            // We may as well not continue
                            DEBUGMSG( ZONE_MDD,
                                      ( TEXT( "PCMCIA: Error mapping I/O Ports.\r\n" ) ) );
                            DEBUGCHK( FALSE );
                        }
                        else
                            bReturn = TRUE;
                    }
                    else
                    {
                        DEBUGMSG( ZONE_MDD,
                                  ( TEXT( "PCMCIA: Error: HalTranslateBusAddress mapping ATTR or COMMON to I/O Ports.\r\n" ) ) );
                        DEBUGCHK( FALSE );
                    }
                }
            }
            else
                bReturn = TRUE;
        }
        else
        {
            DEBUGCHK( FALSE );
            if( m_pVirtualAddr )
            {
                MmUnmapIoSpace( m_pVirtualAddr, 0 );
                m_pVirtualAddr = NULL;
            }
        }
    }
    else if ( dwAddress >= m_WindowAddr.uCardAddress &&
              dwAddress < m_WindowAddr.uCardAddress + m_WindowAddr.uSize ) {
        bReturn = TRUE;
    }
    return bReturn;
}

BOOL CPcmciaMemWindow::AccessByte( DWORD dwAddress, PBYTE pbData, BOOL bRead )
{
    BOOL bReturn = MapWindowView( dwAddress );
    DEBUGCHK( bReturn == TRUE );
    if( m_pVirtualAddr &&
        ( dwAddress >= m_WindowAddr.uCardAddress &&
          dwAddress < m_WindowAddr.uCardAddress + m_WindowAddr.uSize ) )
    {
        // We are in the window of previous mapped window so return the value.
        bReturn = TRUE;
        __try
        {
            if( pbData )
            {
                if( m_b16bitAccess )
                {
                    dwAddress &= ~1;
                    if( bRead )
                        *pbData = ( BYTE ) * ( PWORD )
                                  ( m_pVirtualAddr +
                                    ( dwAddress - m_WindowAddr.uCardAddress ) * m_WindowAddr.uGranularity );
                    else
                        *( PWORD )
                        ( m_pVirtualAddr +
                          ( dwAddress - m_WindowAddr.uCardAddress ) * m_WindowAddr.uGranularity ) = *pbData ;
                }
                else
                {
                    if( bRead )
                        *pbData = *( m_pVirtualAddr +
                                     ( dwAddress - m_WindowAddr.uCardAddress ) * m_WindowAddr.uGranularity );
                    else
                        *( m_pVirtualAddr +
                           ( dwAddress - m_WindowAddr.uCardAddress ) * m_WindowAddr.uGranularity ) = *pbData ;
                }
            }
        } __except( EXCEPTION_EXECUTE_HANDLER )
        {
            bReturn = FALSE;
        }
        return bReturn;
    }
    else
    {
        DEBUGCHK( FALSE );
        return FALSE;
    }
}

BOOL CPcmciaMemWindow::MapWindowPhysical( PCARD_WINDOW_ADDRESS pCardWindowAddr )
{
    BOOL bReturn = MapWindowView( pCardWindowAddr->uCardAddress );
    DEBUGCHK( bReturn == TRUE );
    if( bReturn &&
        m_WindowAddr.uCardAddress <=
        pCardWindowAddr->uCardAddress &&
        ( m_WindowAddr.uCardAddress + m_WindowAddr.uSize ) >=
        ( pCardWindowAddr->uCardAddress + pCardWindowAddr->uSize ) )
    {
        // It is correct map.
        *pCardWindowAddr = m_WindowAddr;
        return TRUE;
    }
    DEBUGCHK( FALSE );
    return FALSE;
}

CPCCard* CreatePCMCIACard( PSS_SOCKET_SERVICE pSocketService,
                           PSS_SOCKET_STATE pSocketState,
                           HANDLE hSocket,
                           UINT16 uSocket,
                           HANDLE hDevice )
{
    return new CPCPcmciaCard( pSocketService,
                              pSocketState,
                              hSocket,
                              uSocket,
                              hDevice );
}
