//
// 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:

cbtuple.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 <tuple.h>
#include "debug.h"
#include "CardBus.h"

CCBTuple::CCBTuple( CPCCardBusCard* pCBCard ) : m_pCBCard( pCBCard )
{
    m_pTupleSpace = NULL;
    PREFAST_DEBUGCHK( m_pCBCard );

    PCI_COMMON_CONFIG pciConfig;
    PCI_SLOT_NUMBER slotNumber;
    slotNumber.u.bits.DeviceNumber = m_pCBCard->m_DeviceNumber;
    slotNumber.u.bits.FunctionNumber = m_pCBCard->m_FunctionNumber;
    pciConfig.VendorID = 0xFFFF;

    int length = HalGetBusData( PCIConfiguration,
                                m_pCBCard->m_dwBusNumber,
                                slotNumber.u.AsULONG,
                                &pciConfig,
                                sizeof( pciConfig ) );

    if( length == 0 || pciConfig.VendorID == 0xFFFF )
    {
        return;
    }
    if( ( pciConfig.HeaderType & ~PCI_MULTIFUNCTION ) != PCI_DEVICE_TYPE )
    {
        return;
    }

    m_uCisOption = ( BYTE ) ( pciConfig.u.type0.CIS & 7 );
    m_dwOffset = pciConfig.u.type0.CIS & 0x0FFFFFF8;
    m_uRomNumber = ( BYTE ) ( ( pciConfig.u.type0.CIS & 0xF0000000 ) >> 28 );
    if( m_uCisOption == 0 )
    {
        // It is in Configuration space.
        m_pTupleSpace = new BYTE[sizeof( pciConfig )];
        if( m_pTupleSpace && m_dwOffset < sizeof( pciConfig ) )
        {
            // Copy it over
            memcpy( m_pTupleSpace, &pciConfig, sizeof( pciConfig ) );
            m_dwTupleMaxSize = sizeof( pciConfig );
        }
        else
        {
            DEBUGMSG( ZONE_ERROR,
                      ( TEXT( "CardBus: Error mapping Turple Space Error Pointer(%x), Offset(%x).\r\n" ),
                        m_pTupleSpace,
                        m_dwOffset ) );
            if( m_pTupleSpace )
            {
                delete m_pTupleSpace;
                m_pTupleSpace = NULL;
            }
        }
    }
    else if( m_uCisOption == 0x7 )
    {
        // ROM . Support it late on
    }
    else
    {
        // One of Bar
        DWORD dwBarNumber = m_uCisOption - 1;
        m_pCBCard->PCIConfig_Write( dwBarNumber * 4 + 0x10, 0xFFFFFFFF );
        DWORD BaseAddress = m_pCBCard->PCIConfig_Read( dwBarNumber*4 + 0x10 );
        DEBUGCHK( ( BaseAddress & PCI_ADDRESS_IO_SPACE ) == 0 ); // It should be alwas as memory.
        DWORD Size = ~( BaseAddress& PCI_ADDRESS_MEMORY_ADDRESS_MASK );
        BOOL SizeFound = ( BaseAddress != 0 ) &&
                         ( BaseAddress != 0xFFFFFFFF ) &&
                         ( ( ( Size + 1 ) & Size ) == 0 );
        if( SizeFound )
        {
            Size += 1;
            m_bIoFlag = FALSE;
            m_dwBarNumber = dwBarNumber;
            CARD_WINDOW_PARMS CardWinParms;
            CardWinParms.hSocket = m_pCBCard->GetCardHandle();
            CardWinParms.fAttributes = 0; // Memory Window
            CardWinParms.fAccessSpeed = 0 ; // This is not used by cardbus.
            CardWinParms.uWindowSize = Size;
            m_uWinIndex = m_pCBCard->CardRequestWindow( &CardWinParms );

            CARD_WINDOW_ADDRESS CardWindowAddr;
            CardWindowAddr.hSocket = m_pCBCard->GetCardHandle();
            CardWindowAddr.uCardAddress = 0;
            CardWindowAddr.uSize = Size;

            if( m_uWinIndex !=
                ( DWORD ) -
                1 &&
                m_pCBCard->CardMapWindowPhysical( m_uWinIndex,
                                                  &CardWindowAddr ) ==
                CERR_SUCCESS )
            {
                // We found index of window that we can use.
                m_pCBCard->PCIConfig_Write( dwBarNumber * 4 + 0x10,
                                            CardWindowAddr.uWindowPhAddr );
                PHYSICAL_ADDRESS ioPhysicalBase;
                ioPhysicalBase.LowPart = CardWindowAddr.uWindowPhAddr;
                ioPhysicalBase.HighPart = 0;
                DWORD inIoSpace = 0;
                SS_SOCKET_INFO lSocketInfo;
                INTERFACE_TYPE bBusType = PCIBus;
                if( m_pCBCard->PDCardInquireSocket( &lSocketInfo ) ==
                    CERR_SUCCESS )
                {
                    bBusType = ( INTERFACE_TYPE ) lSocketInfo.dwBusType;
                }
                if( HalTranslateBusAddress( bBusType,
                                            m_pCBCard->m_dwBusNumber,
                                            ioPhysicalBase,
                                            &inIoSpace,
                                            &ioPhysicalBase ) )
                {
                    if( !inIoSpace )
                    {
                        // Tuple only be support in memory space.
                        if( ( m_pTupleSpace = ( PUCHAR )
                              MmMapIoSpace( ioPhysicalBase,
                                                                       Size,
                                                                       FALSE ) ) ==
                            NULL )
                        {
                            // We may as well not continue
                            DEBUGMSG( ZONE_MDD,
                                      ( TEXT( "CardBus: Error mapping Memory.\r\n" ) ) );
                            DEBUGCHK( FALSE );
                        }
                    }
                    m_bIoFlag = ( inIoSpace != 0 );
                } 
                if( m_pTupleSpace )
                {
                    m_dwTupleMaxSize = Size;
                    DEBUGCHK( m_bIoFlag == FALSE );
                }
                else
                {
                    DEBUGCHK( FALSE );
                    //m_pCBCard->UnMapBar(m_dwBarNumber,m_BridgeWinIndex,m_bIoFlag);
                    m_pCBCard->PCIConfig_Write( dwBarNumber * 4 + 0x10, 0 );
                    m_pCBCard->CardReleaseWindow( m_uWinIndex );
                };
            }
        }
    }
}

CCBTuple::~CCBTuple()
{
    if( m_pTupleSpace != NULL )
    {
        if( m_uCisOption == 0 )
        {
            // It is in Configuration space.
            delete m_pTupleSpace;
        }
        else if( m_uCisOption == 0x7 )
        {
        }
        else
        {
            DWORD dwBarNumber = m_uCisOption - 1;
            if( !m_bIoFlag )
                MmUnmapIoSpace( ( PVOID ) m_pTupleSpace, 0 );
            m_pCBCard->PCIConfig_Write( dwBarNumber * 4 + 0x10, 0 );
            m_pCBCard->CardReleaseWindow( m_uWinIndex );
        }
    }
}
BYTE CCBTuple::GetTupleByte( DWORD dwIndex )
{
    if( m_pTupleSpace != NULL && dwIndex < m_dwTupleMaxSize )
    {
        return m_pTupleSpace[( dwIndex & TUPLE_ADDRESS_MASK ) + m_dwOffset];
    }
    else
    {
        return 0xff;
    }
}
STATUS CCBTuple::GetDesiredTupe( PCARD_TUPLE_PARMS pGetTupleParms )
{
    STATUS status;
    BOOL bCallBaseAgain;
    do
    {
        status = CPCTuple::GetDesiredTupe( pGetTupleParms );
        DWORD oldCisOffset = pGetTupleParms->uCISOffset;
        DWORD dwCurTupleLength = pGetTupleParms->uCISOffset -
                                 pGetTupleParms->uLinkOffset;
        bCallBaseAgain = FALSE;
        if( status == CERR_SUCCESS )
        {
            // We need adjust position if this is long link.
            switch( pGetTupleParms->uTupleCode )
            {
              case CISTPL_LINKTARGET:
                {
                    bCallBaseAgain = TRUE; // need to continue search.
                    break;
                }
              case CISTPL_NO_LINK:
                DEBUGCHK( FALSE );
                break;
            }
        }
    }
    while( status == CERR_SUCCESS && bCallBaseAgain );

    return status;
}


