//
// 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:

init.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:

CardSystemInit()
InitAdapterInfo()
InitSocketInfo()
BitNumber()
InitWindowInfo()
DeInitCardSvc()
InitCardSvc()
DllEntry()

Notes:


--*/
#include <windows.h>
#include <types.h>
#include "cardsv2.h"
#include "socksv2.h"
#include <ceddk.h>
#include "PcCard.h"
#include "PcCardEn.h"
#include "Pcclient.h"
#include "debug.h"

#ifdef DEBUG
DBGPARAM dpCurSettings =
{
    TEXT( "PCCARD" ),
    {
    TEXT( "Errors" ),
    TEXT( "Warnings" ),
    TEXT( "Functions" ),
    TEXT( "Callbacks" ),
    TEXT( "STSCHG Int" ),
    TEXT( "IREQ Int" ),
    TEXT( "MDD Init" ),
    TEXT( "Enum" ),
    TEXT( "PDD" ),
    TEXT( "PDD Init" ),
    TEXT( "CIS Tuples" ),
    TEXT( "MDD" ),
    TEXT( "Undefined" ),
    TEXT( "Undefined" ),
    TEXT( "Undefined" ),
    TEXT( "Undefined" ) },
    0x3
};
#endif  // DEBUG
CSocketInfoContainer* CSocketInfoContainer::g_pSocketContainer = NULL;

DWORD g_PcCardIoResourceID = 0xabcd0001;

#define SUPPORTED_SOCKET_VERSION 0
extern "C" STATUS CS_AddSocket( PUINT16 puSocket,
                                DWORD dwSize,
                                const SS_SOCKET_SERVICE* pSocketService,
                                LPCTSTR lpcHardwareName )
{
    STATUS status = CERR_GENERAL_FAILURE;
    if( CSocketInfoContainer::g_pSocketContainer != NULL )
    {
        // Check the socket service is correct or not.
        if( dwSize >= sizeof( SS_SOCKET_SERVICE ) &&
            pSocketService != NULL &&
            pSocketService->dwVersion >= SUPPORTED_SOCKET_VERSION )
        {
            DWORD dwIndex = 0;
            if( CSocketInfoContainer::g_pSocketContainer->AddSocket( &dwIndex,
                                                                     pSocketService,
                                                                     lpcHardwareName ) ==
                CERR_SUCCESS )
            {
                status = CERR_SUCCESS;
                if( puSocket )
                    *puSocket = ( UINT16 ) dwIndex;
            }
        }
    }
    else
    {
        DEBUGCHK( FALSE );
    }
    return status;
}
extern "C" STATUS CS_DeleteSocket( UINT16 uSocket )
{
    STATUS status = CERR_GENERAL_FAILURE;
    if( CSocketInfoContainer::g_pSocketContainer != NULL )
    {
        status = CSocketInfoContainer::g_pSocketContainer->DeleteSocket( uSocket );
    }
    return status;
}
CPCCard* CreateCardObject( PSS_SOCKET_SERVICE pSocketService,
                           PSS_SOCKET_STATE pSocketState,
                           HANDLE hSocket,
                           UINT16 uSocket,
                           HANDLE hDevice )
{
    if( pSocketState != NULL &&
        ( pSocketState->dwEventStatus & SOCK_EVENT_CARDBUS_CARD ) != 0 )
    {
#ifndef NO_32BIT_PCCARD
        return CreateCardBusCard( pSocketService,
                                  pSocketState,
                                  hSocket,
                                  uSocket,
                                  hDevice );
#else
        RETAILMSG( 1,
                   ( TEXT( "pcc_serv.DLL : 32 Bit PCMCIA Card has not been supported!!!\r\n" ) ) );
#endif
    }
    if( pSocketState != NULL &&
        ( pSocketState->dwEventStatus & SOCK_EVENT_CARDBUS_CARD ) == 0 )
    {
#ifndef NO_16BIT_PCARD
        return CreatePCMCIACard( pSocketService,
                                 pSocketState,
                                 hSocket,
                                 uSocket,
                                 hDevice );
#else
        RETAILMSG( 1,
                   ( TEXT( "pcc_serv.DLL : 16 Bit PCMCIA Card has not been supported!!!\r\n" ) ) );
#endif
    };
    return NULL;
}
//--------------------------------------PC Card Driver Entry ----------------------------------------------------------

extern "C" BOOL WINAPI DllEntry( HINSTANCE DllInstance,
                                 INT Reason,
                                 LPVOID Reserved )
{
    switch( Reason )
    {
      case DLL_PROCESS_ATTACH:
        DEBUGREGISTER( DllInstance );
        DEBUGMSG( ZONE_INIT | ZONE_WARN,
                  ( TEXT( "CardBus.DLL DLL_PROCESS_ATTACH\r\n" ) ) );
        // Delete leftover instance tree.
        ::RegDeleteKey( HKEY_LOCAL_MACHINE, PCMCIA_INSTANCE_PATH );
        ::RegDeleteKey( HKEY_LOCAL_MACHINE, CARDBUS_INSTANCE_PATH );
        CSocketInfoContainer::g_pSocketContainer = new CSocketInfoContainer();
        CClientContainer::g_pClientContainer = new CClientContainer();
        CPCCardContainer::g_pCardContainer = new CPCCardContainer();
        if( !CPCCardContainer::g_pCardContainer ||
            !CClientContainer::g_pClientContainer ||
            !CSocketInfoContainer::g_pSocketContainer )
        {
            if( CSocketInfoContainer::g_pSocketContainer )
            {
                delete CSocketInfoContainer::g_pSocketContainer;
                CSocketInfoContainer::g_pSocketContainer = NULL;
            }
            if( CClientContainer::g_pClientContainer )
            {
                delete CClientContainer::g_pClientContainer;
                CClientContainer::g_pClientContainer = NULL;
            }
            if( CPCCardContainer::g_pCardContainer )
            {
                delete CPCCardContainer::g_pCardContainer;
                CPCCardContainer::g_pCardContainer = NULL;
            }
            return FALSE;
        }
        EnEnableClient() ;
        DisableThreadLibraryCalls( ( HMODULE ) DllInstance );
        break;
      case DLL_PROCESS_DETACH:
        DEBUGMSG( ZONE_INIT | ZONE_WARN,
                  ( TEXT( "CardBus.DLL DLL_PROCESS_DETACH\r\n" ) ) );
        DisEnableClient();
        if( CSocketInfoContainer::g_pSocketContainer )
        {
            delete CSocketInfoContainer::g_pSocketContainer;
            CSocketInfoContainer::g_pSocketContainer = NULL;
        }
        if( CClientContainer::g_pClientContainer )
        {
            delete CClientContainer::g_pClientContainer;
            CClientContainer::g_pClientContainer = NULL;
        }
        if( CPCCardContainer::g_pCardContainer )
        {
            delete CPCCardContainer::g_pCardContainer;
            CPCCardContainer::g_pCardContainer = NULL;
        }
        break;
    };
    return TRUE;
}
LONG ulEntryCount = 0;
#define DEFAULT_PCCARD_BUS_NAME TEXT("PCCARD")
//extern "C" DWORD PDCardInitServices(DWORD dwInfo);
// Init() - called by RegisterDevice when we get loaded
extern "C" DWORD Init( DWORD dwInfo )
{
    HKEY hConfig;
    if( InterlockedIncrement( &ulEntryCount ) > 1 )
    {
        DEBUGMSG( ZONE_INIT |
                  ZONE_ERROR,
                  ( TEXT( "PCCARD.DLL : Cannot load multiple time. Fails!!!\r\n" ) ) );
        InterlockedDecrement( &ulEntryCount );
        return 0;
    }
    DWORD dwReturn = 0;
    if( RegOpenKeyEx( HKEY_LOCAL_MACHINE, ( LPCTSTR ) dwInfo, 0, 0, &hConfig ) ==
        ERROR_SUCCESS )
    {
        HANDLE hDevice = NULL;
        DWORD dwSize = sizeof( HANDLE );
        DWORD dwType;
        if( ( RegQueryValueEx( hConfig,
                               DEVLOAD_HANDLE_VALNAME,
                               0,
                               &dwType,
                               ( PUCHAR ) & hDevice,
                               &dwSize ) ) ==
            ERROR_SUCCESS &&
            dwType ==
            DEVLOAD_HANDLE_VALTYPE )
        {
            if( CPCCardContainer::g_pCardContainer )
            {
                CPCCardContainer::g_pCardContainer->SetDeviceHandle( hDevice );
                dwReturn = 1;
            }
        }
        else
        {
            DEBUGMSG( ZONE_INIT |
                      ZONE_ERROR,
                      ( TEXT( "PCCARD.DLL : Init ResourceCreateList Fails\r\n" ) ) );
        }
        RegCloseKey( hConfig );
    }
    if( !dwReturn )
    {
        return 0;
    }
    if( hConfig = OpenDeviceKey( ( LPCTSTR ) dwInfo ) )
    {
        dwReturn = 0;
        DWORD dwData;
        DWORD dwType;
        DWORD dwSize = sizeof( DWORD );
        if( ( RegQueryValueEx( hConfig,
                               TEXT( "PCCARD_IORESOURCEID" ),
                               0,
                               &dwType,
                               ( PUCHAR ) & dwData,
                               &dwSize ) ) ==
            ERROR_SUCCESS )
        {
            g_PcCardIoResourceID = dwData;
        };
        DEBUGMSG( ZONE_INIT |
                  ZONE_MDD,
                  ( TEXT( "PCCARD.DLL : Init g_PcCardIoResourceID=%x \r\n" ),
                    g_PcCardIoResourceID ) );
        if( ResourceCreateList( g_PcCardIoResourceID, 0, 0xffff ) &&
            ResourceRelease( g_PcCardIoResourceID,
                             0,
                             0xffff ) )
        {
            dwReturn = 1;
        }
        else
        {
            DEBUGMSG( ZONE_INIT |
                      ZONE_ERROR,
                      ( TEXT( "PCCARD.DLL : Init ResourceCreateList Fails\r\n" ) ) );
        }
        RegCloseKey( hConfig );
        return dwReturn;
    }
    return 0;
}
//extern "C" STATUS PDCardDeInitServices(DWORD dwSocketNum);  // This argument is return value from PDCardInitServices.

extern "C" void Deinit( DWORD dwData )
{
    //PDCardDeInitServices(dwData);
    ULONG ulResult = InterlockedDecrement( &ulEntryCount );
    DEBUGCHK( ulResult == 0 );
}
extern "C" BOOL PowerUp( DWORD dwData )
{
    DEBUGMSG( ZONE_INIT | ZONE_MDD,
              ( TEXT( "CardBus.DLL : +PowerUp dwData=%x \r\n" ), dwData ) );
    DEBUGMSG( ZONE_INIT | ZONE_MDD,
              ( TEXT( "CardBus.DLL : -PowerUp dwData=%x \r\n" ) ) );
    return TRUE;
}
extern "C" BOOL PowerDown( DWORD dwData )
{
    DEBUGMSG( ZONE_INIT | ZONE_MDD,
              ( TEXT( "CardBus.DLL : +PowerDown dwData=%x \r\n" ), dwData ) );
    DEBUGMSG( ZONE_INIT | ZONE_MDD,
              ( TEXT( "CardBus.DLL : -PowerDown dwData=%x \r\n" ) ) );
    return TRUE;
}
extern "C" HANDLE Open( HANDLE  pHead, // @parm Handle returned by COM_Init.
     DWORD   AccessCode, // @parm access code.
     DWORD   ShareMode       // @parm share mode - Not used in this driver.
)
{
    if( ulEntryCount !=
        0 &&
        CPCCardContainer::g_pCardContainer &&
        CPCCardContainer::g_pCardContainer->Open( AccessCode,
                                                  ShareMode ) )
    {
        return ( pHead );
    }
    return NULL;
}
extern "C" BOOL Close( HANDLE pOpenHead )
{
    if( CPCCardContainer::g_pCardContainer )
    {
        return CPCCardContainer::g_pCardContainer->Close();
    }
    return FALSE;
}
extern "C" BOOL IOControl( HANDLE pOpenHead,
                           DWORD dwCode,
                           PBYTE pBufIn,
                           DWORD dwLenIn,
                           PBYTE pBufOut,
                           DWORD dwLenOut,
                           PDWORD pdwActualOut )
{
    if( ulEntryCount != NULL && CPCCardContainer::g_pCardContainer )
    {
        return CPCCardContainer::g_pCardContainer->IOControl( dwCode,
                                                              pBufIn,
                                                              dwLenIn,
                                                              pBufOut,
                                                              dwLenOut,
                                                              pdwActualOut );
    }
    return FALSE;
}


#ifdef DEBUG
#define BYTE_PER_LINE 0x40
void DumpHex( DWORD dwLength, PBYTE pBuffer )
{
    RETAILMSG( 1,
               ( TEXT( "DumpHext length=0x%x,bufferaddr=0x%x" ),
                 dwLength,
                 pBuffer ) );
    TCHAR strBuffer[BYTE_PER_LINE*3 + 1];
    while( dwLength != 0 )
    {
        DWORD dwCurPos = 0;
        for( DWORD dwIndex = 0;
             dwIndex < BYTE_PER_LINE && dwLength != 0;
             dwIndex++ )
        {
            TCHAR bHexValue = ( ( ( *pBuffer ) >> 4 ) & 0xf );
            if( bHexValue <= 9 )
                bHexValue += _T( '0' );
            else
                bHexValue += _T( 'A' ) - 10;
            strBuffer[dwCurPos++] = bHexValue;
            bHexValue = ( ( ( *pBuffer ) ) & 0xf ) ;
            if( bHexValue <= 9 )
                bHexValue += _T( '0' );
            else
                bHexValue += _T( 'A' ) - 10;
            strBuffer[dwCurPos++] = bHexValue;
            strBuffer[dwCurPos++] = _T( ' ' );

            dwLength--;
            pBuffer++;
        }
        strBuffer[dwCurPos] = 0; // Terminated.
        RETAILMSG( 1, ( TEXT( "%s" ), strBuffer ) );
    }
}
#endif

