//
// 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.
//
/*++

Module Name:

pcmtuple.cpp

Abstract:

This file implements the CPCCard model device driver tuple 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 "PcmciaC.h"

BYTE CPcmciaTuple::GetTupleByte( DWORD dwIndex )
{
    BYTE bReturn = 0xff;
    BOOL bAttr = ( ( dwIndex& TUPLE_COMMON_MEMORY_FLAG ) != 0 ? FALSE : TRUE );
    DWORD dwOffset = ( dwIndex& TUPLE_ADDRESS_MASK );
    CPcmciaMemWindow* pTupleWindow = m_pPcmciaCard->GetMemoryWindow( bAttr );
    if( pTupleWindow != NULL )
    {
        if( bAttr )
            dwOffset <<= 1;
        if( pTupleWindow->GetByte( dwOffset, &bReturn ) != TRUE )
        {
            //The tuple only mapped in Even Byte on 
            DEBUGCHK( FALSE );
            bReturn = 0xff;
        }
    }
    return bReturn;
}

STATUS CPcmciaTuple::GetDesiredTupe( PCARD_TUPLE_PARMS pGetTupleParms )
{
    STATUS status;
    BOOL bCallBaseAgain;
    do
    {
        status = CPCTuple::GetDesiredTupe( pGetTupleParms );
        DWORD dwCurTupleLength = pGetTupleParms->uCISOffset -
                                 pGetTupleParms->uLinkOffset;
        bCallBaseAgain = FALSE;
        if( status == CERR_SUCCESS )
        {
            // We need adjust position if this is long link.
            BOOL bCommon = FALSE;
            switch( pGetTupleParms->uTupleCode )
            {
              case CISTPL_LONGLINK_MFC:
                if( pGetTupleParms->uDesiredTuple != CISTPL_LONGLINK_MFC &&
                    m_pPcmciaCard->GetMFTargetAddr() != 0 )
                {
                    m_fValidLongLink = TRUE;
                    m_dwLongLinkAddr = m_pPcmciaCard->GetMFTargetAddr();
                    bCallBaseAgain = TRUE;
                }
                break;
              case CISTPL_LONGLINK_C:
                // This is link to Common, everything else is same is LONGLINK_A
                bCommon = TRUE;
              case CISTPL_LONGLINK_A:
                {
                    DWORD dwCurData = pGetTupleParms->uLinkOffset;
                    BYTE bLength = 4;//GetTupleByte(dwCurData++);
                    if( bLength <= dwCurTupleLength )
                    {
                        DWORD dwTarget = 0 ;
                        DWORD dwShift = 0;
                        for( BYTE uIndex = 0; uIndex < bLength; uIndex ++ )
                        {
                            dwTarget += ( ( DWORD )
                                          GetTupleByte( dwCurData++ ) <<
                                          dwShift );
                            dwShift += 8;
                        }
                        dwTarget |= ( bCommon ? TUPLE_COMMON_MEMORY_FLAG : 0 );
                        m_fValidLongLink = TRUE;
                        m_dwLongLinkAddr = dwTarget;
                        bCallBaseAgain = TRUE;
                    }
                    else
                        DEBUGCHK( FALSE );
                    break;
                }
              case CISTPL_LINKTARGET:
                {
                    bCallBaseAgain = TRUE; // need to continue search.
                    break;
                }
              case CISTPL_NO_LINK:
                {
                    m_fValidLongLink = FALSE;
                    bCallBaseAgain = TRUE;
                    break;
                }
            }
        }
        if (status != CERR_SUCCESS && (pGetTupleParms->uCISOffset & TUPLE_LONGLINK_FLAG)==0 && m_fValidLongLink ) { 
            // We try check Target Link for long jumper.
            BYTE uLinkTarget[5];
            DWORD dwCurPos = m_dwLongLinkAddr | TUPLE_LONGLINK_FLAG ;
            for( DWORD dwIndex = 0 ; dwIndex < 5 ; dwIndex ++ )
            {
                uLinkTarget[dwIndex] = GetTupleByte( dwCurPos++ );
            }
            const static BYTE uLinkTargetData[5] =
            {
                0x13, 3, 0x43, 0x49, 0x53
            };
            if( memcmp( uLinkTarget, uLinkTargetData, 5 ) == 0 )
            {
                bCallBaseAgain = TRUE; // Let us continue again.
                status = CERR_SUCCESS;
                pGetTupleParms->uCISOffset = (m_dwLongLinkAddr+5) | TUPLE_LONGLINK_FLAG ;
                pGetTupleParms->uLinkOffset = (m_dwLongLinkAddr+2) | TUPLE_LONGLINK_FLAG ;
            }
        }
    }
    while( status == CERR_SUCCESS && bCallBaseAgain );

    return status;
}

