//
// 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:

CardBusC.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 "PCCard.h"
#include "CardBus.h"
#include "debug.h"
#include <CeBusCfg.h>
//
// Displays PCI device configuration space information.
//
VOID DumpPciConfig( PPCI_COMMON_CONFIG pCfg );

#define MAX_ENTRY 0x10

CPCCardBusCard::CPCCardBusCard( PSS_SOCKET_SERVICE pSocketService,
                                PSS_SOCKET_STATE pSocketState,
                                HANDLE hSocket,
                                UINT16 uSocket,
                                HANDLE hDevice,
                                CPCCardBusCard* pPFunction,
                                UINT uFuntion ) : CPCCard( pSocketService,
                                                           pSocketState,
                                                           hSocket,
                                                           uSocket,
                                                           hDevice,
                                                           pPFunction,
                                                           uFuntion )
{
    if( pSocketState )
    {
        m_SocketState = *pSocketState;
    }
    else
    {
        STATUS status = PDCardGetSocket( &m_SocketState );
        DEBUGCHK( status == CERR_SUCCESS );
    }
    m_pTuple = NULL;
    m_dwBusNumber = m_SocketInfo.dwBusNumber;
    m_DeviceNumber = 0;
    m_FunctionNumber = 0;
    m_bRoot = FALSE;
    m_bPowered = FALSE;
    m_bSuspend = FALSE;
    m_ppCBCardWindows = ( CCBCardWindows * * )new PVOID[m_SocketInfo.dwNumOfWindows];
    if( m_ppCBCardWindows != NULL )
    {
        for( DWORD dwIndex = 0;
             dwIndex < m_SocketInfo.dwNumOfWindows;
             dwIndex++ )
        {
            m_ppCBCardWindows[dwIndex] = NULL;
        }
    }
    // Get Power Entry for Syspend and resume.
    m_uiZeroEntryIndex = 0;
    SS_POWER_ENTRY powerEntryArray[MAX_ENTRY];
    DWORD dwMaxEntry = min( MAX_ENTRY, m_SocketInfo.dwNumOfPowerEntry );
    if( PDCardGetPowerEntry( &dwMaxEntry, powerEntryArray ) == CERR_SUCCESS )
    {
        for( DWORD dwEntry = 0; dwEntry < dwMaxEntry; dwEntry++ )
        {
            if( powerEntryArray[dwEntry].uPowerLevel == 0 )
            {
                // Power Voltage Zero Entry found
                m_uiZeroEntryIndex = ( UINT8 ) dwEntry;
                break;
            };
        }
    }
};
BOOL CPCCardBusCard::Init( BOOL bRoot )
{
    DEBUGMSG( ZONE_MDD,
              ( TEXT( "CPCCardBusCard::Init busNumber=%d bRoot=%d\r\n" ),
                m_dwBusNumber,
                bRoot ) );
    DEBUGCHK( ( m_SocketState.dwInterfaceType & CFG_IFACE_CARDBUS ) != 0 );
    Lock();
    CPCCard::EventNotification( CE_CARD_INSERTION, m_SocketState.dwInterfaceType );
    BOOL bReturn = CPCCard::Init( bRoot );
    if(bReturn && bRoot ) {
        // Create the Window Mapping object.
        m_bRoot = TRUE;
        if( m_ppCBCardWindows != NULL ) {
            for( DWORD dwIndex = 0;  dwIndex < m_SocketInfo.dwNumOfWindows; dwIndex++ )
                if( ( m_ppCBCardWindows[dwIndex] = new CCBCardWindows( this, dwIndex ) ) ==  NULL ) {
                    // Fails
                    bReturn = FALSE;
                    break;
                }
        }
        else
            bReturn = FALSE;
        PDCardResetSocket();
        PDCardGetSocket( &m_SocketState );
    }
    PCI_SLOT_NUMBER cSlotNumber;
    cSlotNumber.u.AsULONG = 0;
    cSlotNumber.u.bits.DeviceNumber = m_DeviceNumber;
    cSlotNumber.u.bits.FunctionNumber = m_FunctionNumber;
    Unlock();
    return bReturn;
}
void CPCCardBusCard::PowerUp()
{
    if( m_bSuspend == TRUE )
    {
        DEBUGMSG( ZONE_MDD,
                  ( TEXT( "CPCCardBusCard::PowerUp busNumber=%d SocketNumber=%d\r\n" ),
                    m_dwBusNumber,
                    GetSocketIndex() ) );
        CPCCard::EventNotification( CE_PM_SUSPEND );
    }
    m_bSuspend = FALSE;
}
void CPCCardBusCard::PowerDown()
{
    if( m_bSuspend == FALSE && m_bPowered == TRUE )
    {
        //
        CPCCard::EventNotification( CE_PM_SUSPEND );
        DEBUGMSG( ZONE_MDD,
                  ( TEXT( "CPCCardBusCard::PowerDown busNumber=%d SocketNumber=%d\r\n" ),
                    m_dwBusNumber,
                    GetSocketIndex() ) );
        m_bSuspend = TRUE;
    }
}
BOOL CPCCardBusCard::SetPowerState( CEDEVICE_POWER_STATE ceState )
{
    if( CPCCard::SetPowerState( ceState ) )
    {
        // Setup Power Mgr for thie Function Device.
        return TRUE;
    }
    return FALSE;
}
BOOL CPCCardBusCard::AccessConfigurationSpace( DWORD dwSpace,
                                               DWORD dwOffset,
                                               BOOL bRead,
                                               DWORD dwLength,
                                               PVOID pBuffer )
{
    if( dwSpace == PCCARD_PCI_CONFIGURATION_SPACE )
    {
        PCI_SLOT_NUMBER SlotNumber;
        SlotNumber.u.AsULONG = 0;
        SlotNumber.u.bits.DeviceNumber = m_DeviceNumber;
        SlotNumber.u.bits.FunctionNumber = m_FunctionNumber;
        DWORD dwReturn = 0;
        if( bRead )
            dwReturn = HalGetBusDataByOffset( PCIConfiguration,
                                              m_dwBusNumber,
                                              SlotNumber.u.AsULONG,
                                              pBuffer,
                                              dwOffset,
                                              dwLength );
        else
            dwReturn = HalSetBusDataByOffset( PCIConfiguration,
                                              m_dwBusNumber,
                                              SlotNumber.u.AsULONG,
                                              pBuffer,
                                              dwOffset,
                                              dwLength );
        return ( dwReturn != 0 );
    }
    else
    {
        return FALSE;
    }
}

CPCTuple* CPCCardBusCard::GetTupleObject()
{
    return ( m_pTuple !=
             NULL ?
             m_pTuple :
             ( m_pTuple = new CCBTuple( this ) ) );
};
void CPCCardBusCard::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( "CPCCardBusCard::EventNotification (CARD_READY) on Bus=%d,device=%d function=%d\r\n" ),
                            m_dwBusNumber,
                            m_DeviceNumber,
                            m_FunctionNumber ) );
                if( ( pSocketState->dwEventStatus & SOCK_EVENT_PWRCYCLE ) !=
                    0 )
                {
                    if( m_bPowered == TRUE )
                    {
                        // Reconver Configuration Space
                        DEBUGMSG( ZONE_FUNCTION,
                                  ( TEXT( "CPCCardBusCard::EventNotification (CARD_READY) recover\r\n" ) ) );
                        RestoreConfigSpace();
                        ConfigDump();
                    }
                    else
                    {
                        DEBUGMSG( ZONE_FUNCTION,
                                  ( TEXT( "CPCCardBusCard::EventNotification (CARD_READY) Initilization\r\n" ) ) );
                        if( m_bRoot )
                        {
                            Lock();
                            if( GetCardFunctionNumber() == 0 )
                                ScanBus();
                            else 
                                // Fails: Because the function card as not gerenerated, so it should always fails
                                // if we get here.
                                DEBUGCHK( FALSE );
                            Unlock();
                            DWORD dwCmd = PCIConfig_Read( 4 );
                            PCIConfig_Write( 4, dwCmd | 0x7 );
                            dwCmd = PCIConfig_Read( 4 );
                            ConfigDump();
                            if( ( dwCmd & 0x7 ) != 0x7 )
                            {
                                DEBUGMSG( ZONE_WARN,
                                          ( TEXT( "CPCCardBusCard::Init can not enable this card on bus=%d,statusCmd=%x\r\n" ),
                                            m_dwBusNumber,
                                            dwCmd ) );
                            }
                        }
                        BackupConfigSpace();
                        m_bPowered = TRUE;
                        PCI_SLOT_NUMBER cSlotNumber;
                        cSlotNumber.u.AsULONG = 0;
                        cSlotNumber.u.bits.DeviceNumber = m_DeviceNumber;
                        cSlotNumber.u.bits.FunctionNumber = m_FunctionNumber;
                        CPCCard::EventNotification( CE_POWER_CYCLE_ON,
                                                    ( m_dwBusNumber & 0xffff ) +
                                                    ( GetInterfaceType() <<
                                                      16 ),
                                                    cSlotNumber.u.AsULONG );
                    }
                }
                else
                {
                    DEBUGMSG( ZONE_WARN,
                              ( TEXT( "CPCCardBusCard::Init Power Is Off!!! \r\n" ) ) );
                }
                break;
            }
        };
        if( GetParentFunction() == NULL &&
            ( dwEvent & ~SOCK_EVENT_SUSPEND_RESUME ) != 0 )
        {
            SS_SOCKET_STATE sSocketState;
            PDCardGetSocket( &sSocketState );  // Clean the change bit. 
            sSocketState.dwEventChanged = pSocketState->dwEventChanged;
            PDCardSetSocket( &sSocketState );  // Clean the change bit.                      
        }
        Unlock();
    }
}

BOOL CPCCardBusCard::DeInit()
{
    Lock();
    if( m_pTuple != NULL )
    {
        delete m_pTuple;
        m_pTuple = NULL;
    }
    if( m_ppCBCardWindows != NULL )
    {
        for( DWORD dwIndex = 0;
             dwIndex < m_SocketInfo.dwNumOfWindows;
             dwIndex++ )
            if( m_ppCBCardWindows[dwIndex] != NULL )
            {
                delete m_ppCBCardWindows[dwIndex];
                m_ppCBCardWindows[dwIndex] = NULL;
            }
        delete m_ppCBCardWindows;
        m_ppCBCardWindows = NULL;
    }
    Unlock();
    return TRUE;
};
CPCCardBusCard::~CPCCardBusCard()
{
    DeInit();
    CardDisableCard() ;
}
BOOL CPCCardBusCard::ScanBus()
{
    DWORD dwDeviceIndex = 0;
    PCI_COMMON_CONFIG pciConfig;
    int bus, device, function;
    int length;

    PCI_SLOT_NUMBER slotNumber;
    // Scan CardBus
    bus = m_dwBusNumber;
    for( device = 0; device < PCI_MAX_DEVICES; device++ )
    {
        slotNumber.u.bits.DeviceNumber = device;
        for( function = 0; function < PCI_MAX_FUNCTION; function++ )
        {
            slotNumber.u.bits.FunctionNumber = function;
            pciConfig.VendorID = 0xFFFF;
            pciConfig.HeaderType = 0;

            length = HalGetBusData( PCIConfiguration,
                                    bus,
                                    slotNumber.u.AsULONG,
                                    &pciConfig,
                                    sizeof( pciConfig ) -
                                    sizeof( pciConfig.DeviceSpecific ) );

            if( length == 0 || pciConfig.VendorID == 0xFFFF )
            {
                // Device does not exist
                break;
            }
#ifdef DEBUG
            if( ZONE_ENUM )
            {
                RETAILMSG( 1,
                           ( TEXT( "Bus/Device/Function = %d/%d/%d\r\n" ),
                             bus,
                             device,
                             function ) );
                DumpPciConfig( &pciConfig );
            };
#endif
            Lock();
            if( dwDeviceIndex == 0 )
            {
                m_DeviceNumber = device;
                m_FunctionNumber = function;
            }
            else if( CPCCardContainer::g_pCardContainer )
            {
                CPCCardBusCard* pNewCard = new CPCCardBusCard( GetSocketService(),
                                                               &m_SocketState,
                                                               GetSocketHandle(),
                                                               GetSocketIndex(),
                                                               GetDeviceHandle(),
                                                               this,
                                                               dwDeviceIndex );
                if( pNewCard ==
                    NULL ||
                    CPCCardContainer::g_pCardContainer->InsertObjectAtEmpty( NULL,
                                                                             pNewCard ) ==
                    NULL )
                {
                    // Success
                    DEBUGMSG( ZONE_ERROR,
                              ( TEXT( "CardBus.DLL : Can not construct new card(%x)!!!\r\n" ),
                                pNewCard ) );
                    if( pNewCard )
                    {
                        delete pNewCard;
                        pNewCard = NULL;
                    };
                }
                else
                {
                    pNewCard->m_DeviceNumber = device;
                    pNewCard->m_FunctionNumber = function;
                    if( pNewCard->Init( FALSE ) != TRUE )
                    {
                        // Init with No bus scan 
                        DEBUGMSG( ZONE_ERROR,
                                  ( TEXT( "CardBus.DLL : Can not Initial new card(%x)!!!\r\n" ),
                                    pNewCard ) );
                        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 );
                    }
                };
            }
            else
                DEBUGCHK( FALSE );

            dwDeviceIndex++;
            Unlock();

            if( function == 0 &&
                !( pciConfig.HeaderType & PCI_MULTIFUNCTION ) )
            {
                // Not a multi-function device, continue on to next device
                break;
            }
        }

        // Error on HalGetBusData, move on to next bus
        if( length == 0 )
        {
            break;
        }
    }
    return TRUE;
} 
STATUS CPCCardBusCard::CardGetStatus( PCARD_STATUS pStatus )
{
    STATUS status = CERR_BAD_ARGS;
    if( pStatus && GetSocketHandle() != 0 )
    {
        SS_SOCKET_STATE SocketState;
        Lock();
        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 |= EVENT_MASK_CARDBUS_CARD;
        pStatus->fSocketState = pStatus->fCardState;
        Unlock();
        status = CERR_SUCCESS;
    }
    return status;
}
STATUS CPCCardBusCard::CardReleaseIRQ()
{
    Lock();
    DWORD dwReg = PCIConfig_Read( 15 * 4 );
    dwReg = ( dwReg | 0xff );
    PCIConfig_Write( 15 * 4, dwReg );
    BackupConfigSpace();
    ConfigDump();
    STATUS status = CPCCard::CardReleaseIRQ();
    Unlock();
    return status;
}
STATUS CPCCardBusCard::CardRequestIRQLine( UINT16 dwIrqBit,
                                           PDWORD pdwIrqOrSysIntrNumber,
                                           PDWORD pdwIsSysIntr )
{
    if( ( m_SocketInfo.dwSocketCaps & SOCK_CAP_ONLY_SYSINTR ) != 0 )
    {
        DEBUGCHK( FALSE );
        return CERR_UNSUPPORTED_MODE;
    }
    UINT16 dwBitShift = 1;
    for( DWORD dwIndex = 0;
         dwIndex < IRQ_ROUTINGTABLE_SIZE;
         dwIndex++,dwBitShift <<= 1 )
    {
        if( ( dwIrqBit & dwBitShift ) != 0 &&
            m_SocketInfo.bArrayIrqRouting[dwIndex] != ( BYTE ) - 1 )
        {
            // found mapping.
            STATUS status;
            SS_SOCKET_STATE lSocketState;
            Lock();
            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 = 0;
                DWORD dwReg = PCIConfig_Read( 15 * 4 );
                dwReg = ( dwReg & ~0xff ) |
                        m_SocketInfo.bArrayIrqRouting[dwIndex] ;
                PCIConfig_Write( 15 * 4, dwReg );
                BackupConfigSpace();
                ConfigDump();
            }
            else
                DEBUGCHK( FALSE );
            Unlock();
            return status;
        }
    }
    return CERR_BAD_ARGS;
}

void CPCCardBusCard::PCIConfig_Write( DWORD dwOffset, DWORD dwValue )
{
    PCI_SLOT_NUMBER SlotNumber;

    SlotNumber.u.AsULONG = 0;
    SlotNumber.u.bits.DeviceNumber = m_DeviceNumber;
    SlotNumber.u.bits.FunctionNumber = m_FunctionNumber;

    HalSetBusDataByOffset( PCIConfiguration,
                           m_dwBusNumber,
                           SlotNumber.u.AsULONG,
                           &dwValue,
                           dwOffset,
                           sizeof( dwValue ) );
}

DWORD CPCCardBusCard::PCIConfig_Read( DWORD dwOffset )
{
    PCI_SLOT_NUMBER SlotNumber;
    DWORD RetVal = 0;

    SlotNumber.u.AsULONG = 0;
    SlotNumber.u.bits.DeviceNumber = m_DeviceNumber;
    SlotNumber.u.bits.FunctionNumber = m_FunctionNumber;

    HalGetBusDataByOffset( PCIConfiguration,
                           m_dwBusNumber,
                           SlotNumber.u.AsULONG,
                           &RetVal,
                           dwOffset,
                           sizeof( RetVal ) );

    return RetVal;
}
STATUS CPCCardBusCard::CardRequestConfiguration( PCARD_CONFIG_INFO pParms )
{
    STATUS status = CERR_BAD_ARGS;
    if( GetParentFunction() == NULL )
    {
        // It only can be used by first function..
        SS_SOCKET_STATE curState;
        DWORD pwrEntry = 0;
        Lock();
        if( ( status = PDCardGetSocket( &curState ) ) == CERR_SUCCESS )
        {
            if( pParms->uVcc != -1 &&
                ValidPowerEntry( PWR_SUPPLY_VCC,
                                                       pParms->uVcc ) && // Valid Number;
                GetVotageEntry( &pwrEntry, pParms->uVcc, PWR_SUPPLY_VCC ) )
                curState.fVcc = ( BYTE ) pwrEntry;
            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;
            status = PDCardSetSocket( &curState );
        }
        Unlock();
    }
    else
    {
        return CERR_SUCCESS;
    }
    return status;
}

STATUS CPCCardBusCard::CardReleaseConfiguration()
{
    return CERR_SUCCESS;
}

UINT16 CPCCardBusCard::CardRequestWindow( PCARD_WINDOW_PARMS pCardWinParms )
{
    CPCCardBusCard* pPCard = ( CPCCardBusCard* ) GetParentFunction();
    if( pPCard != NULL )
    {
        return pPCard->CardRequestWindow( pCardWinParms );
    }

    UINT16 uReturn = -1;
    if( pCardWinParms != NULL )
    {
        Lock();
        for( UINT16 uIndex = 0;
             uIndex < ( UINT16 ) m_SocketInfo.dwNumOfWindows;
             uIndex++ )
        {
            if( m_ppCBCardWindows[uIndex] != NULL &&
                m_ppCBCardWindows[uIndex]->CardRequestWindow( pCardWinParms ) )
            {
                uReturn = uIndex;
                break;
            }
        }
        Unlock();
    };
    return uReturn;
}
STATUS CPCCardBusCard::CardReleaseWindow( UINT16 uWindowIndex )
{
    STATUS status = CERR_BAD_WINDOW;
    CPCCardBusCard* pPCard = ( CPCCardBusCard* ) GetParentFunction();
    if( pPCard != NULL )
    {
        return pPCard->CardReleaseWindow( uWindowIndex );
    }

    Lock();
    if( uWindowIndex < ( UINT16 ) m_SocketInfo.dwNumOfWindows &&
        m_ppCBCardWindows[uWindowIndex] != NULL &&
        m_ppCBCardWindows[uWindowIndex]->CardReleaseWindow() )
    {
        status = CERR_SUCCESS;
    }
    Unlock();
    return status;
}
STATUS CPCCardBusCard::CardMapWindowPhysical( UINT16 uWindowIndex,
                                              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;
    }

    CPCCardBusCard* pPCard = ( CPCCardBusCard* ) GetParentFunction();
    if( pPCard != NULL )
    {
        return pPCard->CardMapWindowPhysical( uWindowIndex, pCardWindowAddr );
    }
    Lock();
    if( uWindowIndex <
        ( UINT16 )
        m_SocketInfo.dwNumOfWindows &&
        m_ppCBCardWindows[uWindowIndex] !=
        NULL &&
        m_ppCBCardWindows[uWindowIndex]->CardMapWindowPhysical( pCardWindowAddr ) )
    {
        status = CERR_SUCCESS;
    }
    Unlock();
    return status;
}
DWORD CPCCardBusCard::ConfigDump()
{
#ifdef DEBUG
    if( ZONE_ENUM )
    {
        PCI_SLOT_NUMBER slotNumber;
        slotNumber.u.AsULONG = 0;
        slotNumber.u.bits.DeviceNumber = m_DeviceNumber;
        slotNumber.u.bits.FunctionNumber = m_FunctionNumber;
        PCI_COMMON_CONFIG pciConfig;
        HalGetBusData( PCIConfiguration,
                       m_dwBusNumber,
                       slotNumber.u.AsULONG,
                       &pciConfig,
                       sizeof( pciConfig ) -
                       sizeof( pciConfig.DeviceSpecific ) );


        RETAILMSG( 1,
                   ( TEXT( "Bus/Device/Function = %d/%d/%d\r\n" ),
                     m_dwBusNumber,
                     m_DeviceNumber,
                     m_FunctionNumber ) );
        DumpPciConfig( &pciConfig );
    }
#endif
    return 0;
}

CCBCardWindows::CCBCardWindows( CPCCardBusCard* pCBCard, DWORD dwIndex ) : m_pCBCard( pCBCard ),
                                                                           m_dwWinIndex( dwIndex )
{
    PREFAST_DEBUGCHK( m_pCBCard != NULL );
    m_bRequested = FALSE;
    m_pCBCard->PDCardInquireWindow( m_dwWinIndex, &m_WinInfo );
}
CCBCardWindows::~CCBCardWindows()
{
    CardReleaseWindow();
}
BOOL CCBCardWindows::CardRequestWindow( PCARD_WINDOW_PARMS pCardWinParms )
{
    SS_WINDOW_STATE sWindowState;
    if( m_bRequested !=
        TRUE &&
        m_pCBCard->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;
            m_bRequested = TRUE;
            m_CardWinParms = *pCardWinParms;
            return TRUE;
        }
    };
    return FALSE;
}

BOOL CCBCardWindows::CardReleaseWindow()
{
    SS_WINDOW_STATE sWindowState;
    if( m_bRequested ==
        TRUE &&
        m_pCBCard->PDCardGetWindow( m_dwWinIndex,
                                                            &sWindowState ) ==
        CERR_SUCCESS )
    {
        m_bRequested = FALSE;
        if( ( sWindowState.fState & WIN_STATE_ENABLED ) != 0 ||
            sWindowState.uOffset + sWindowState.uSize != 0 )
        {
            sWindowState.fState &= ~WIN_STATE_ENABLED;
            sWindowState.uOffset = sWindowState.uSize = 0;
            if( m_pCBCard->PDCardSetWindow( m_dwWinIndex, &sWindowState ) !=
                CERR_SUCCESS )
                return FALSE;
        }
        return TRUE;
    }
    return FALSE;
}
BOOL CCBCardWindows::CardMapWindowPhysical( PCARD_WINDOW_ADDRESS pCardWindowAddr )
{
    SS_WINDOW_STATE sWindowState;
    if( pCardWindowAddr &&
        m_bRequested ==
        TRUE &&
        m_pCBCard->PDCardGetWindow( m_dwWinIndex,
                                    &sWindowState ) ==
        CERR_SUCCESS )
    {
        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;
        sWindowState.uOffset = pCardWindowAddr-> uCardAddress;
        sWindowState.uSize = pCardWindowAddr-> uSize;
        if( m_pCBCard->PDCardSetWindow( m_dwWinIndex, &sWindowState ) ==
            CERR_SUCCESS )
        {
            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( "CCBCardWindows::CardMapWindowPhysical: return Success with ph=%x,Offset=%x,len=%x!!!" ),
                        pCardWindowAddr->uWindowPhAddr,
                        pCardWindowAddr->uCardAddress,
                        pCardWindowAddr->uSize ) );
            return TRUE;
        }
        else
        {
            DEBUGMSG( ZONE_MDD |
                      ZONE_WARN,
                      ( TEXT( "CCBCardWindows::CardMapWindowPhysical:PDCardSetWindow!!!" ) ) );
        }
    }
    return FALSE;
}

//
// Returns String describing a device based on Class, SubClass and Programming Interface.
//
PWCHAR DeviceType( UCHAR ucBaseClass, UCHAR ucSubClass, UCHAR ucProgIf )
{
    static  struct
    {
        ULONG   ulClass;
        ULONG   ulMask;
        PWCHAR  pszDescription;
    }   ClassNames[] =
    {
        // Class code 0 (pre rev 2.0)
        {
            0x000000, 0xFFFFFF, TEXT( "Pre 2.0 Non VGA device" )
        },
        {
            0x000101, 0xFFFFFF, TEXT( "Pre 2.0 VGA device" )
        },

        // Class code 1: mass storage controllers
        {
            0x010000, 0xFFFFFF, TEXT( "SCSI Controller" )
        },
        {
            0x010100, 0xFFFF00, TEXT( "IDE Controller" )
        },
        {
            0x010180, 0xFFFFFF, TEXT( "Busmaster IDE Controller" )
        },
        {
            0x010200, 0xFFFFFF, TEXT( "Floppy Controller" )
        },
        {
            0x010300, 0xFFFFFF, TEXT( "IPI Controller" )
        },
        {
            0x010400, 0xFFFFFF, TEXT( "RAID Controller" )
        },
        {
            0x018000, 0xFFFFFF, TEXT( "Other Mass Storage Device" )
        },

        // Class code 2: network controllers
        {
            0x020000, 0xFFFFFF, TEXT( "Ethernet Network Controller" )
        },
        {
            0x020100, 0xFFFFFF, TEXT( "Token Ring Network Controller" )
        },
        {
            0x020200, 0xFFFFFF, TEXT( "FDDI Network Controller" )
        },
        {
            0x020300, 0xFFFFFF, TEXT( "ATM Network Controller" )
        },
        {
            0x028000, 0xFFFFFF, TEXT( "Other Network Controller" )
        },

        // Class code 3: display controllers
        {
            0x030000, 0xFFFFFF, TEXT( "VGA Compatible Display Adapter" )
        },
        {
            0x030001, 0xFFFFFF, TEXT( "8514 Compatible Display Adapter" )
        },
        {
            0x030100, 0xFFFFFF, TEXT( "XGA Compatible Display Adapter" )
        },
        {
            0x038000, 0xFFFFFF, TEXT( "Other Display Adapter" )
        },

        // Class code 4: multimedia devices
        {
            0x040000, 0xFFFFFF, TEXT( "Video Multimedia Device" )
        },
        {
            0x040100, 0xFFFFFF, TEXT( "Audio Multimedia Device" )
        },
        {
            0x048000, 0xFFFFFF, TEXT( "Other Multimedia Device" )
        },

        // Class code 5: memory controllers
        {
            0x050000, 0xFFFFFF, TEXT( "RAM Memory Controller" )
        },
        {
            0x050100, 0xFFFFFF, TEXT( "Flash Memory Controller" )
        },
        {
            0x058000, 0xFFFFFF, TEXT( "Other Memory Controller" )
        },

        // Class code 6: bridge devices
        {
            0x060000, 0xFFFFFF, TEXT( "Host / PCI Bridge" )
        },
        {
            0x060100, 0xFFFFFF, TEXT( "PCI / ISA Bridge" )
        },
        {
            0x060200, 0xFFFFFF, TEXT( "PCI / EISA Bridge" )
        },
        {
            0x060300, 0xFFFFFF, TEXT( "PCI / MCA Bridge" )
        },
        {
            0x060400, 0xFFFFFF, TEXT( "PCI / PCI Bridge" )
        },
        {
            0x060500, 0xFFFFFF, TEXT( "PCI / PCMCIA Bridge" )
        },
        {
            0x060600, 0xFFFFFF, TEXT( "PCI / NuBus Bridge" )
        },
        {
            0x060700, 0xFFFFFF, TEXT( "PCI / CardBus Bridge" )
        },
        {
            0x068000, 0xFFFFFF, TEXT( "Other Bridge" )
        },

        // Class code 7: simple communications controllers
        {
            0x070000,
            0xFFFFFF,
            TEXT( "8250 Compatible Communications Device" )
        },
        {
            0x070001,
            0xFFFFFF,
            TEXT( "16450 Compatible Communications Device" )
        },
        {
            0x070002,
            0xFFFFFF,
            TEXT( "16550 Compatible Communications Device" )
        },
        {
            0x070100, 0xFFFFFF, TEXT( "Parallel Port" )
        },
        {
            0x070101, 0xFFFFFF, TEXT( "Bidirectional Parallel Port" )
        },
        {
            0x070102, 0xFFFFFF, TEXT( "ECP 1.X Parallel Port" )
        },
        {
            0x078000, 0xFFFFFF, TEXT( "Other Communications Device" )
        },

        // Class code C: serial bus controllers
        {
            0x0C0000, 0xFFFFFF, TEXT( "Firewire (IEEE 1394) Bus Controller" )
        },
        {
            0x0C0100, 0xFFFFFF, TEXT( "ACCESS.bus Controller" )
        },
        {
            0x0C0200, 0xFFFFFF, TEXT( "SSA Controller" )
        },
        {
            0x0C0300, 0xFFFFFF, TEXT( "UHCI USB Bus Controller" )
        },
        {
            0x0C0310, 0xFFFFFF, TEXT( "OHCI USB Bus Controller" )
        },
        {
            0x0C0400, 0xFFFFFF, TEXT( "Fibre Channel Controller" )
        },
    };

#define NUMBER_CLASS_NAMES  (sizeof(ClassNames) / sizeof(ClassNames[0]))

    ULONG ulClassKey;
    int i;

    ulClassKey = ( ucBaseClass << 16 ) | ( ucSubClass << 8 ) | ucProgIf;

    for( i = 0; i < NUMBER_CLASS_NAMES; i++ )
    {
        if( ( ClassNames[i].ulClass & ClassNames[i].ulMask ) ==
            ( ulClassKey & ClassNames[i].ulMask ) )
        {
            return ClassNames[i].pszDescription;
        }
    }

    return TEXT( "Unknown Device Type" );
}


//
// Displays PCI device configuration space information.
//
VOID DumpPciConfig( PPCI_COMMON_CONFIG pCfg )
{
    RETAILMSG( 1,
               ( TEXT( "---------------------%s-------------------------------------------\r\n" ),
                 DeviceType( pCfg->BaseClass,
                             pCfg->SubClass,
                             pCfg->ProgIf ) ) );

    RETAILMSG( 1,
               ( TEXT( "  VendorID = 0x%4.4X, DeviceID = 0x%4.4X, Command = 0x%4.4X, Status = 0x%4.4X\r\n" ),
                 pCfg->VendorID,
                 pCfg->DeviceID,
                 pCfg->Command,
                 pCfg->Status ) );

    RETAILMSG( 1,
               ( TEXT( "  RevisionID = 0x%2.2X, ProgIf = 0x%2.2X, SubClass = 0x%2.2X, BaseClass = 0x%2.2X\r\n" ),
                 pCfg->RevisionID,
                 pCfg->ProgIf,
                 pCfg->SubClass,
                 pCfg->BaseClass ) );

    RETAILMSG( 1,
               ( TEXT( "  CacheLineSize = 0x%2.2X, LatencyTimer = 0x%2.2X, HeaderType = 0x%2.2X, BIST = 0x%2.2X\r\n" ),
                 pCfg->CacheLineSize,
                 pCfg->LatencyTimer,
                 pCfg->HeaderType,
                 pCfg->BIST ) );


    switch( pCfg->HeaderType & ~PCI_MULTIFUNCTION )
    {
      case PCI_DEVICE_TYPE:
        RETAILMSG( 1, ( TEXT( "  BaseAddresses:\r\n" ) ) );

        RETAILMSG( 1,
                   ( TEXT( "    0x%8.8X  0x%8.8X  0x%8.8X  0x%8.8X  0x%8.8X  0x%8.8X\r\n" ),
                     pCfg->u.type0.BaseAddresses[0],
                     pCfg->u.type0.BaseAddresses[1],
                     pCfg->u.type0.BaseAddresses[2],
                     pCfg->u.type0.BaseAddresses[3],
                     pCfg->u.type0.BaseAddresses[4],
                     pCfg->u.type0.BaseAddresses[5] ) );

        RETAILMSG( 1,
                   ( TEXT( "  CIS = 0x%8.8X, SubVendorID = 0x%4.4X, SubSystemID = 0x%4.4X\r\n" ),
                     pCfg->u.type0.CIS,
                     pCfg->u.type0.SubVendorID,
                     pCfg->u.type0.SubSystemID ) );

        RETAILMSG( 1,
                   ( TEXT( "  ROMBaseAddress = 0x%8.8X\r\n" ),
                     pCfg->u.type0.ROMBaseAddress ) );

        RETAILMSG( 1,
                   ( TEXT( "  InterruptLine = 0x%2.2X, InterruptPin = 0x%2.2X, MinGrant = 0x%2.2X, MaxLatency = 0x%2.2X\r\n" ),
                     pCfg->u.type0.InterruptLine,
                     pCfg->u.type0.InterruptPin,
                     pCfg->u.type0.MinimumGrant,
                     pCfg->u.type0.MaximumLatency ) );
        break;

      case PCI_BRIDGE_TYPE:
        RETAILMSG( 1,
                   ( TEXT( "  BaseAddresses = 0x%8.8X 0x%8.8X\r\n" ),
                     pCfg->u.type1.BaseAddresses[0],
                     pCfg->u.type1.BaseAddresses[1] ) );

        RETAILMSG( 1,
                   ( TEXT( "  PrimaryBusNumber = %d, SecondaryBusNumber = %d\r\n" ),
                     pCfg->u.type1.PrimaryBusNumber,
                     pCfg->u.type1.SecondaryBusNumber ) );

        RETAILMSG( 1,
                   ( TEXT( "  SubordinateBusNumber = %d, SecondaryLatencyTimer = %d\r\n" ),
                     pCfg->u.type1.SubordinateBusNumber,
                     pCfg->u.type1.SecondaryLatencyTimer ) );

        RETAILMSG( 1,
                   ( TEXT( "  IOBase = 0x%2.2X, IOLimit = 0x%2.2X, SecondaryStatus = 0x%4.4X\r\n" ),
                     pCfg->u.type1.IOBase,
                     pCfg->u.type1.IOLimit,
                     pCfg->u.type1.SecondaryStatus ) );

        RETAILMSG( 1,
                   ( TEXT( "  MemoryBase = 0x%4.4X, MemoryLimit = 0x%4.4X\r\n" ),
                     pCfg->u.type1.MemoryBase,
                     pCfg->u.type1.MemoryLimit ) );

        RETAILMSG( 1,
                   ( TEXT( "  PrefetchableMemoryBase = 0x%4.4X, PrefetchableMemoryLimit = 0x%4.4X\r\n" ),
                     pCfg->u.type1.PrefetchableMemoryBase,
                     pCfg->u.type1.PrefetchableMemoryLimit ) );

        RETAILMSG( 1,
                   ( TEXT( "  PrefetchableMemoryBaseUpper32 = 0x%8.8X\r\n" ),
                     pCfg->u.type1.PrefetchableMemoryBaseUpper32 ) );

        RETAILMSG( 1,
                   ( TEXT( "  PrefetchableMemoryLimitUpper32 = 0x%8.8X\r\n" ),
                     pCfg->u.type1.PrefetchableMemoryLimitUpper32 ) );

        RETAILMSG( 1,
                   ( TEXT( "  IOBaseUpper = 0x%4.4X, IOLimitUpper = 0x%4.4X\r\n" ),
                     pCfg->u.type1.IOBaseUpper,
                     pCfg->u.type1.IOLimitUpper ) );

        RETAILMSG( 1,
                   ( TEXT( "  Reserved2 = 0x%8.8X, ExpansionROMBase = 0x%8.8X\r\n" ),
                     pCfg->u.type1.Reserved2,
                     pCfg->u.type1.ExpansionROMBase ) );

        RETAILMSG( 1,
                   ( TEXT( "  InterruptLine = 0x%2.2X, InterruptPin = 0x%2.2X, BridgeControl = 0x%4.4X\r\n" ),
                     pCfg->u.type1.InterruptLine,
                     pCfg->u.type1.InterruptPin,
                     pCfg->u.type1.BridgeControl ) );

        break;

      case PCI_CARDBUS_TYPE:
        RETAILMSG( 1,
                   ( TEXT( "  BaseAddress (CardBus Socket/ExCA Base Address Register) = 0x%8.8X\r\n" ),
                     pCfg->u.type2.BaseAddress ) );

        RETAILMSG( 1,
                   ( TEXT( "  CapabilitiesPtr = 0x%2.2X, Reserved2 = 0x%2.2X, SecondaryStatus = 0x%4.4X\r\n" ),
                     pCfg->u.type2.CapabilitiesPtr,
                     pCfg->u.type2.Reserved2,
                     pCfg->u.type1.SecondaryStatus ) );

        RETAILMSG( 1,
                   ( TEXT( "  PrimaryBusNumber = %d, CardbusBusNumber = %d\r\n" ),
                     pCfg->u.type2.PrimaryBusNumber,
                     pCfg->u.type2.CardbusBusNumber ) );

        RETAILMSG( 1,
                   ( TEXT( "  SubordinateBusNumber = %d, CardbusLatencyTimer = %d\r\n" ),
                     pCfg->u.type2.SubordinateBusNumber,
                     pCfg->u.type2.CardbusLatencyTimer ) );

        RETAILMSG( 1,
                   ( TEXT( "  MemoryBase0 = 0x%8.8X, MemoryLimit0 = 0x%8.8X\r\n" ),
                     pCfg->u.type2.MemoryBase0,
                     pCfg->u.type2.MemoryLimit0 ) );

        RETAILMSG( 1,
                   ( TEXT( "  MemoryBase1 = 0x%8.8X, MemoryLimit1 = 0x%8.8X\r\n" ),
                     pCfg->u.type2.MemoryBase1,
                     pCfg->u.type2.MemoryLimit1 ) );

        RETAILMSG( 1,
                   ( TEXT( "  IOBase0_LO = 0x%4.4X, IOBase0_HI = 0x%4.4X\r\n" ),
                     pCfg->u.type2.IOBase0_LO,
                     pCfg->u.type2.IOBase0_HI ) );

        RETAILMSG( 1,
                   ( TEXT( "  IOLimit0_LO = 0x%4.4X, IOLimit0_HI = 0x%4.4X\r\n" ),
                     pCfg->u.type2.IOLimit0_LO,
                     pCfg->u.type2.IOLimit0_HI ) );

        RETAILMSG( 1,
                   ( TEXT( "  IOBase1_LO = 0x%4.4X, IOBase1_HI = 0x%4.4X\r\n" ),
                     pCfg->u.type2.IOBase1_LO,
                     pCfg->u.type2.IOBase1_HI ) );

        RETAILMSG( 1,
                   ( TEXT( "  IOLimit1_LO = 0x%4.4X, IOLimit1_HI = 0x%4.4X\r\n" ),
                     pCfg->u.type2.IOLimit1_LO,
                     pCfg->u.type2.IOLimit1_HI ) );

        RETAILMSG( 1,
                   ( TEXT( "  InterruptLine = 0x%2.2X, InterruptPin = 0x%2.2X, BridgeControl = 0x%4.4X\r\n" ),
                     pCfg->u.type2.InterruptLine,
                     pCfg->u.type2.InterruptPin,
                     pCfg->u.type2.BridgeControl ) );

        RETAILMSG( 1,
                   ( TEXT( "  SubVendorID = 0x%4.4X, SubSystemID = 0x%4.4X\r\n" ),
                     pCfg->u.type2.SubVendorID,
                     pCfg->u.type2.SubSystemID ) );

        RETAILMSG( 1,
                   ( TEXT( "  LegactyBaseAddress = 0x%8.8X\r\n" ),
                     pCfg->u.type2.LegacyBaseAddress ) );
        RETAILMSG( 1,
                   ( TEXT( "  SystemControl = 0x%8.8X\r\n" ),
                     pCfg->u.type2.SystemControl ) );

        RETAILMSG( 1,
                   ( TEXT( "  DeviceControl = 0x%2.2X\r\n" ),
                     pCfg->u.type2.DeviceControl ) );

        RETAILMSG( 1,
                   ( TEXT( "  Diagnostic = 0x%2.2X\r\n" ),
                     pCfg->u.type2.Diagnostic ) );
        break;

      default:
        RETAILMSG( 1,
                   ( L"ERROR: Unrecognized header type 0x%X\r\n",
                     pCfg->HeaderType & ~PCI_MULTIFUNCTION ) );
    }

    RETAILMSG( 1,
               ( TEXT( "-------------------------------------------------------------------------------\r\n" ) ) );
}

CPCCard* CreateCardBusCard( PSS_SOCKET_SERVICE pSocketService,
                            PSS_SOCKET_STATE pSocketState,
                            HANDLE hSocket,
                            UINT16 uSocket,
                            HANDLE hDevice )
{
    return new  CPCCardBusCard( pSocketService,
                                pSocketState,
                                hSocket,
                                uSocket,
                                hDevice );
}

