//
// 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:  

Abstract:

Platform dependent PCMCIA initialization functions

Notes: 
--*/
#ifndef __PCCARD_H_
#define __PCCARD_H_
#include <CRefCon.h>
#include <PCTuple.h>
#include <pm.h>
#include <devload.h>
//----------------------------------------Socket Function-------------------------------------------
class CAttachedSocket : public CRefObject
{
public:
    CAttachedSocket( const SS_SOCKET_SERVICE* pSocketService,
                     LPCTSTR lpcHardwareName )
    {
        m_pSocketService = NULL;
        if( pSocketService )
        {
            m_pSocketService = new SS_SOCKET_SERVICE;
            if( m_pSocketService )
                *m_pSocketService = *pSocketService;
        }
        m_lpSocketNaume = NULL;
        if( lpcHardwareName )
        {
            DWORD   dwLength = _tcslen( lpcHardwareName );
            m_lpSocketNaume = new TCHAR[dwLength + 1];
            if( m_lpSocketNaume )
                _tcscpy( m_lpSocketNaume, lpcHardwareName );
        }
    }
    ~CAttachedSocket()
    {
        if( m_lpSocketNaume != NULL )
        {
            delete m_lpSocketNaume;
        }
        if( m_pSocketService )
        {
            delete m_pSocketService;
        }
    }
    SS_SOCKET_SERVICE* GetSocketService()
    {
        return m_pSocketService;
    };
    LPCTSTR GetSocketName()
    {
        return m_lpSocketNaume;
    };
private:
    LPTSTR              m_lpSocketNaume;
    SS_SOCKET_SERVICE*  m_pSocketService;
};


#define NUM_SOCKETS 0x20
class CSocketInfoContainer : public CStaticContainer <CAttachedSocket, NUM_SOCKETS>
{
public:
    static CSocketInfoContainer*    g_pSocketContainer;
    STATUS AddSocket( PDWORD pReturnIndex,
                      const SS_SOCKET_SERVICE* pSocketService,
                      LPCTSTR lpcHardwareName )
    {
        STATUS              status = CERR_GENERAL_FAILURE;
        CAttachedSocket*    pSocket = NULL;
        if( ( pSocket = new CAttachedSocket( pSocketService, lpcHardwareName ) ) !=
            NULL )
        {
            if( pReturnIndex )
                *pReturnIndex = 0;
            if( pSocket->GetSocketService() !=
                NULL &&
                InsertObjectAtEmpty( pReturnIndex,
                                     pSocket ) !=
                NULL )
            {
                status = CERR_SUCCESS;
            }
            else
                delete pSocket;
        }
        return status;
    }
    STATUS DeleteSocket( DWORD dwIndex )
    {
        STATUS  status = CERR_GENERAL_FAILURE;
        if( RemoveObjectBy( dwIndex ) != NULL )
        {
            status = CERR_SUCCESS;
        }
        return status;
    }
} ;

//------------------------------------------Card Function ---------------------------------------
#define MAX_FUNCTION_CARD 0x10
#define DEVICE_BUSNAME_PREFIX TEXT("PCCARD")    

class CPCCard : public CRefObject, public CLockObject
{
    // Basic Class for both CardBus and PCMCIA.
private:
    SS_SOCKET_SERVICE       m_SocketService;
    HANDLE                  m_hSocket;
    UINT16                  m_uSocket;
    UINT                    m_uFunction;
    CARD_SOCKET_HANDLE      m_hCardHandle;
    CARD_CLIENT_HANDLE      m_hClient;
    HANDLE                  m_hBusDriver;
    CPCCard * const         m_pPFunction;
    TCHAR                   m_lpDeviceBusName[sizeof( DEVICE_BUSNAME_PREFIX ) / sizeof( TCHAR ) + 13 * 3 + 2 + 1];
    static DWORD            g_dwCardRef;
    DWORD                   m_dwCardRef;
    DWORD                   m_dwCardLockCount;
    // m_cardPowerState is Paranet class used only, It use to track function power state.
    CEDEVICE_POWER_STATE    m_cardPowerState[MAX_FUNCTION_CARD];
    BYTE                    m_bCardFlag[MAX_FUNCTION_CARD];
#define PCCARD_RESET_FLAG   0x1
#define PCCARD_DISABLE_FLAG 0x2
protected:
    PSS_POWER_ENTRY         m_pssPowerEntry;
    SS_SOCKET_INFO          m_SocketInfo;
    CEDEVICE_POWER_STATE    m_cePowerState;
    SS_SOCKET_STATE         m_BackupState;
public:
    // Intialization
                            CPCCard( PSS_SOCKET_SERVICE pSocketService,
                                     PSS_SOCKET_STATE pSocketState,
                                     HANDLE hSocket,
                                     UINT16 uSocket,
                                     HANDLE hBusHandle,
                                     CPCCard* pPFunction,
                                     UINT uFuntion ) ;
    virtual                 ~CPCCard() ;
    virtual BOOL            Init( BOOL bScanBus = FALSE ) ;
    LPCTSTR GetDeviceBusName()
    {
        return m_lpDeviceBusName;
    };
    HANDLE GetDeviceHandle()
    {
        return m_hBusDriver;
    };
    virtual CPCTuple*   GetTupleObject() = 0;
    // Handle and Reference.
    // Socket Infomation.
    PSS_SOCKET_SERVICE GetSocketService()
    {
        return &m_SocketService;
    };
    HANDLE GetSocketHandle()
    {
        return m_hSocket;
    };
    UINT16 GetSocketIndex()
    {
        return m_uSocket;
    };
    INTERFACE_TYPE GetInterfaceType()
    {
        return ( INTERFACE_TYPE ) m_SocketInfo.dwBusType ;
    };
    // Card Infomation.
    UINT GetCardFunctionNumber()
    {
        return m_uFunction;
    };
    CARD_SOCKET_HANDLE GetCardHandle()
    {
        return m_hCardHandle;
    };

    //Paranet Function Card
    CPCCard* GetParentFunction()
    {
        return  m_pPFunction;
    };

    //LPTSTR GetSocketName(LPTSTR lpStr, DWORD dwNumOfChar);
    virtual BOOL IsCardBusCard()
    {
        return FALSE;
    };

    // Power Handling
    virtual void PowerUp()
    {
        ;};
    virtual void PowerDown()
    {
        ;};
    virtual BYTE    SetPCCardFlag( BYTE bFlag, BOOL bAnd, UINT uFunctionIndex );
    virtual BOOL    SetPowerState( CEDEVICE_POWER_STATE ceState );
    virtual BOOL    SetPowerStateGlobal( CEDEVICE_POWER_STATE ceState,
                                         UINT uFunctionIndex );
    CEDEVICE_POWER_STATE GetPowerState()
    {
        return m_cePowerState;
    };
    // Attribute or Parameter
    CARD_CLIENT_HANDLE GetClientHandle()
    {
        return m_hClient;
    };
    CARD_CLIENT_HANDLE SetClientHandle( CARD_CLIENT_HANDLE hClient )
    {
        return m_hClient = hClient;
    };
    // Call PDD
    STATUS          PDCardInquireSocket( PSS_SOCKET_INFO pSocketInfo );
    STATUS          PDCardGetPowerEntry( PDWORD pdwNumOfEnery,
                                         PSS_POWER_ENTRY pPowerEntry );
    STATUS          PDCardGetSocket( PSS_SOCKET_STATE pSocketState );
    STATUS          PDCardSetSocket( PSS_SOCKET_STATE pSocketState );
    STATUS          PDCardResetSocket();
    STATUS          PDCardInquireWindow( UINT32 uWindow,
                                         PSS_WINDOW_INFO pWindowInfo );
    STATUS          PDCardGetWindow( UINT32 uWindow,
                                     PSS_WINDOW_STATE pWindowState );
    STATUS          PDCardSetWindow( UINT32 uWindow,
                                     PSS_WINDOW_STATE pWindowState );
    STATUS          PDTranslateBusAddr( INTERFACE_TYPE  InterfaceType,
                                        ULONG BusNumber,
                                        PHYSICAL_ADDRESS BusAddress,
                                        PULONG AddressSpace,
                                        PPHYSICAL_ADDRESS TranslatedAddress );
    STATUS          PDTranslateSystemAddr( INTERFACE_TYPE  InterfaceType,
                                           ULONG BusNumber,
                                           PHYSICAL_ADDRESS SystemAddress,
                                           PPHYSICAL_ADDRESS TranslatedAddress );

    STATUS          EventNotification( UINT32 uEvent,
                                       UINT32 Parm1 = 0,
                                       UINT32 Parm2 = 0 );// Notify Client
    virtual void    EventNotification( PSS_SOCKET_STATE pSocketState ) = 0; // Notification from PDD.

    // TUPLE
    virtual STATUS CardGetFirstTuple( PCARD_TUPLE_PARMS pGetTupleParms )
    {
        STATUS  status = CERR_BAD_ARGS;
        if( GetTupleObject() != NULL )
        {
            status = GetTupleObject()->CardGetFirstTuple( pGetTupleParms );
        }
        return status;
    };
    virtual STATUS CardGetNextTuple( PCARD_TUPLE_PARMS pGetTupleParms )
    {
        STATUS  status = CERR_BAD_ARGS;
        if( GetTupleObject() != NULL )
        {
            status = GetTupleObject()->CardGetNextTuple( pGetTupleParms );
        }
        return status;
    }
    virtual STATUS CardGetTupleData( PCARD_DATA_PARMS pGetTupleData )
    {
        STATUS  status = CERR_BAD_ARGS;
        if( GetTupleObject() != NULL )
        {
            status = GetTupleObject()->CardGetTupleData( pGetTupleData );
        }
        return status;
    }
    virtual STATUS CardGetParsedTuple( UINT8   DesiredTuple,
                                       PVOID pBuf,
                                       PUINT pnItems )
    {
        STATUS  status = CERR_BAD_ARGS;
        if( GetTupleObject() != NULL )
        {
            status = GetTupleObject()->CardGetParsedTuple( DesiredTuple,
                                                           pBuf,
                                                           pnItems );
        }
        return status;
    }

    // Reuqest and Mapping Windows
    virtual UINT16 CardRequestWindow( PCARD_WINDOW_PARMS pCardWinParms )
    {
        return ( UINT16 ) - 1;
    }
    virtual STATUS CardReleaseWindow( UINT16 uWindowIndex )
    {
        return CERR_BAD_SOCKET;
    }
    virtual STATUS CardModifyWindow( UINT16 uWindowIndex,
                                     UINT16 fAttributes,
                                     UINT8 fAccessSpeed )
    {
        return CERR_BAD_SOCKET;
    }
    virtual PVOID CardMapWindow( UINT16 uWindowIndex,
                                 UINT32 uCardAddress,
                                 UINT32 uSize,
                                 PUINT32 pGranularity )
    {
        return NULL;
    }
    virtual STATUS CardMapWindowPhysical( UINT16 uWindowIndex,
                                          PCARD_WINDOW_ADDRESS pCardWindowAddr )
    {
        return CERR_BAD_SOCKET;
    }

    // IRQ Map
    virtual STATUS CardRequestIRQ( CARD_ISR ISRFunction,
                                   UINT32 uISRContextData )
    {
        return CERR_BAD_SOCKET;
    }
    virtual STATUS CardReleaseIRQ()
    {
        SS_SOCKET_STATE lSocketState;
        STATUS          status;
        if( ( status = PDCardGetSocket( &lSocketState ) ) == CERR_SUCCESS )
        {
            // Enable Socket Interrupt.
            lSocketState.dwInteruptStatus &= ~SOCK_INT_FUNC_IRQ_ROUTING;
            lSocketState.fIREQRouting = -1;
            return PDCardSetSocket( &lSocketState );
        }
        return status;
    }
    virtual STATUS CardRequestIRQLine( UINT16 dwIrqBit,
                                       PDWORD pdwIrqOrSysIntrNumber,
                                       PDWORD pdwIsSysIntr )
    {
        return CERR_BAD_SOCKET;
    }
    // Configuration.
    virtual STATUS CardRequestConfiguration( PCARD_CONFIG_INFO pParms )
    {
        return CERR_BAD_SOCKET;
    }
    virtual STATUS CardReleaseConfiguration()
    {
        return CERR_BAD_SOCKET;
    }
    virtual STATUS CardModifyConfiguration( PUINT16 fAttributes )
    {
        return CERR_BAD_SOCKET;
    }
    virtual STATUS CardRequestConfigRegisterPhAddr( PCARD_WINDOW_ADDRESS pCardWindowAddr,
                                                    PDWORD pOffset )
    {
        return CERR_BAD_SOCKET;
    }

    virtual STATUS CardAccessConfigurationRegister( UINT8 rw_flag,
                                                    UINT8 offset,
                                                    UINT8* pValue )
    {
        return CERR_BAD_SOCKET;
    }
    virtual BOOL AccessConfigurationSpace( DWORD dwSpace,
                                           DWORD dwOffset,
                                           BOOL bRead,
                                           DWORD dwLength,
                                           PVOID pBuffer )
    {
        return FALSE;
    }
    virtual STATUS  CardResetFunction() ;
    virtual STATUS  CardDisableCard() ;
    virtual STATUS  CardGetStatus( PCARD_STATUS pStatus ) = 0;

    BOOL            ValidPowerEntry( UINT fSupply, UINT16 uVoltage ) ;
    BOOL            GetVotageEntry( PDWORD pdwEntry,
                                    UINT16 uValue,
                                    UINT8 fSupply );
};

#define MAX_CARD 0x20
class CPCCardContainer : public CStaticContainer <CPCCard, MAX_CARD>
{
public:
                                CPCCardContainer();
    static CPCCardContainer*    g_pCardContainer;
    BOOL IsSameCardHandle( CARD_SOCKET_HANDLE hCard1,
                           CARD_SOCKET_HANDLE hCard2 ) const
    {
        return ( hCard1.uSocket == hCard2.uSocket &&
                 hCard1.uFunction == hCard2.uFunction );
    }
    // Reference by Socket
    CPCCard* FoundObjectBy( PDWORD pdwIndex, HANDLE hSocket )
    {
        Lock();
        CPCCard*    pReturn = NULL;
        for( DWORD dwIndex = 0; dwIndex < m_dwArraySize; dwIndex++ )
        {
            if( m_rgObjectArray[dwIndex] != NULL )
            {
                if( m_rgObjectArray[dwIndex]->GetSocketHandle() == hSocket )
                {
                    break;
                }
            }
        }
        if( dwIndex < m_dwArraySize )
        {
            pReturn = m_rgObjectArray[dwIndex];
            pReturn->AddRef();
            if( pdwIndex )
                *( pdwIndex ) = dwIndex;
        }
        Unlock();
        return pReturn;
    }
    // Reference By Card Service.
    CPCCard* FoundObjectBy( PDWORD pdwIndex, CARD_SOCKET_HANDLE hCard )
    {
        Lock();
        CPCCard*    pReturn = NULL;
        for( DWORD dwIndex = 0; dwIndex < m_dwArraySize; dwIndex++ )
        {
            if( m_rgObjectArray[dwIndex] != NULL )
            {
                if( IsSameCardHandle( m_rgObjectArray[dwIndex]->GetCardHandle(),
                                      hCard ) )
                {
                    break;
                }
            }
        }
        if( dwIndex < m_dwArraySize )
        {
            pReturn = m_rgObjectArray[dwIndex];
            pReturn->AddRef();
            if( pdwIndex )
                *( pdwIndex ) = dwIndex;
        }
        Unlock();
        return pReturn;
    }
    // Reference By Device Bus Name
    CPCCard* FoundObjectBy( PDWORD pdwIndex, LPCTSTR lpDeviceBusName )
    {
        Lock();
        CPCCard*    pReturn = NULL;
        if( lpDeviceBusName )
        {
            LPCTSTR lpName = ( ( _tcsnicmp( lpDeviceBusName,
                                            TEXT( "$bus\\" ),
                                            5 ) == 0 ) ?
                               ( lpDeviceBusName + 5 ) :
                               lpDeviceBusName );
            for( DWORD dwIndex = 0; dwIndex < m_dwArraySize; dwIndex++ )
                if( m_rgObjectArray[dwIndex] != NULL )
                {
                    if( _tcsicmp( lpName,
                                  m_rgObjectArray[dwIndex]->GetDeviceBusName() ) ==
                        0 )
                        break;
                }
            if( dwIndex < m_dwArraySize )
            {
                pReturn = m_rgObjectArray[dwIndex];
                pReturn->AddRef();
                if( pdwIndex )
                    *( pdwIndex ) = dwIndex;
            }
        }
        Unlock();
        return pReturn;
    }
    void    SocketEvent( HANDLE hSocket,
                         UINT16 uSocket,
                         PSS_SOCKET_STATE pSocketState );
    virtual BOOL Open( DWORD   AccessCode, DWORD   Share )
    {
         return ((AccessCode & DEVACCESS_BUSNAMESPACE)!=0);
    };
    virtual BOOL Close()
    {
        return TRUE;
    };
    virtual BOOL    IOControl( DWORD dwCode,
                               PBYTE pBufIn,
                               DWORD dwLenIn,
                               PBYTE pBufOut,
                               DWORD dwLenOut,
                               PDWORD pdwActualOut );
    HANDLE GetDeviceHandle()
    {
        return m_hDevice;
    };
    HANDLE  SetDeviceHandle( HANDLE hDevice );
private:
    HANDLE  m_hDevice;
};
extern DWORD g_PcCardIoResourceID;
CPCCard* CreateCardObject( PSS_SOCKET_SERVICE pSocketService,
                           PSS_SOCKET_STATE pSocketState,
                           HANDLE hSocket,
                           UINT16 uSocket,
                           HANDLE hDevice );
// For supported Card
CPCCard* CreateCardBusCard( PSS_SOCKET_SERVICE pSocketService,
                            PSS_SOCKET_STATE pSocketState,
                            HANDLE hSocket,
                            UINT16 uSocket,
                            HANDLE hDevice );
CPCCard* CreatePCMCIACard( PSS_SOCKET_SERVICE pSocketService,
                           PSS_SOCKET_STATE pSocketState,
                           HANDLE hSocket,
                           UINT16 uSocket,
                           HANDLE hDevice );

#endif
