/*****************************************************************************
 * Copyright (C) Cinterion Wireless Modules GmbH
 *****************************************************************************
 * Project: Quinn-RIL-Driver
 *****************************************************************************
 * Author : Wireless Modules RD SW A2
 *****************************************************************************
 * $Workfile: Y:/z_ms-d/src/working/Quinn/RhaDll/rhadll.c $
 * $Revision: /main/ms-d/12 $
 *     $Date: 2013-10-21 09:51:53 $
 *   $Author: pmackent $
 *****************************************************************************
 * Target:
 *  Microsoft Windows Mobile 5.0
 *****************************************************************************
 * Description:
 *  HC25 Radio Hardware Abstraction Layer
 *****************************************************************************
 *
 * $Log: Y:/z_ms-d/src/working/Quinn/RhaDll/rhadll.c$ 
 * 
 * /main/ms-d/12   2013-10-21 09:51:53   pmackent 
 * Remove unused #include
 *
 * /main/ms-d/11   2012-01-05 14:38:50   ctna0256
 * New API for CDMA/UMTS network technology switch
 *
 * /main/ms-d/10   2010-09-08 09:56:34   ctna0256
 * Unnecessary include of riltrace removed
 *
 * /main/ms-d/9   2010-02-25 14:51:12   ctna0256
 * Iginition for ICOP
 *
 * /main/ms-d/8   2008-08-22 10:22:16   ctna0256
 * Set Cinterion copyright text
 *
 * /main/ms-d/7   2008-08-20 12:11:09   ctna0450
 * Prepared new disclaimer handling
 *
 * /main/ms-d/6   2007-11-26 17:05:38   kr36712
 * integration of GPS support
 * use of the mux protocol
 *
 * /main/ms-d/5   2007-01-19 10:06:46   mp49210
 * New audio configuration registry structure
 *
 * /main/ms-d/4   2006-11-14 12:23:45   wm36264
 * Added missing trace init and deinit
 *
 * /main/ms-d/3   2006-10-31 16:00:11   wm36264
 * Don't return failure when not using DSB power on
 *
 * /main/ms-d/2   2006-10-31 14:14:50   wm36264
 * Removed obsolete switch on ports
 *
 * /main/ms-d/1   2006-10-27 16:50:07   wm36264
 * Copied from classic RIL
 *
*/

//////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2008 Cinterion Wireless Modules GmbH
// Copyright (C) 2006-2008 Siemens AG
// Copyright (C) 2003 Intrinsyc Europe Ltd.
//
// Version: 1.0
// Date:    dummy
//
//////////////////////////////////////////////////////////////////////////////

#include <windows.h>
#include <memory.h>
#include <linklist.h>
#include <windev.h>
#include <pkfuncs.h>
#include <pegdser.h>
#include <devload.h>
#include <dbgapi.h>
#include <ril.h>
#include "..\..\inc\rhaapi.h"
#include "rhadll.h"

//////////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////////

#define RIL_REGISTRY_KEY                  TEXT("Software\\Microsoft\\RIL")
#define DEDICATED_SWITCHON_PORT           TEXT("RhaSwitchOnPort")
#define MIN_DSB_DTR_LOW_TIME              2000
#define IGNITION_PULSE_TIME               500

void __cdecl _cinit(void);
void __cdecl _cexit(void);

#ifdef DEBUG
DBGPARAM dpCurSettings = {
  TEXT("RhaDll"), {
    TEXT("Init"), TEXT("Function") },
  0xFFFF
};
#endif

BOOL    g_fRadioOn = FALSE;
DWORD   g_dwTimeLastOff = 0;

//
// Get the device name of serial port the module is connected to
//
BOOL GetModulePortName(LPTSTR szPortName, DWORD dwNameLen) {
    DWORD   dwValueType;
    DWORD   dwDataSize;
    HKEY    hRegKey;
    BOOL    fRet;

    fRet = FALSE;

    // First try if there is a dedicated switch on port in the registry
    if (!RegOpenKeyEx(HKEY_LOCAL_MACHINE, RIL_REGISTRY_KEY, 0, KEY_READ, &hRegKey))
    {
        dwDataSize = dwNameLen;
        if (!RegQueryValueEx(hRegKey, DEDICATED_SWITCHON_PORT, NULL, &dwValueType, (LPBYTE)szPortName, &dwDataSize))
        {
            fRet = TRUE;
        }
        RegCloseKey(hRegKey);
    }

    return fRet;
}

//
// Open the serial port the module is connected to
//
HANDLE OpenModulePort(void) {
    DWORD   dwMaxOpenAttempts;
    DWORD   dwPortDelay;
    DWORD   dwValueType;
    DWORD   dwDataSize;
    DWORD   j;
    TCHAR   szPortName[MAX_PATH];
    HKEY    hRegKey;
    HANDLE  hRet;

    hRet = INVALID_HANDLE_VALUE;
    if (GetModulePortName(szPortName, MAX_PATH * sizeof(TCHAR)))
    {
        if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, RIL_REGISTRY_KEY, 0, KEY_READ, &hRegKey))
        {
            dwMaxOpenAttempts = 3;
            dwPortDelay = 1000;
        }
        else
        {
            dwDataSize = sizeof(DWORD);
            if (RegQueryValueEx(hRegKey, TEXT("MaxOpenAttempts"), NULL, &dwValueType, (LPBYTE)&dwMaxOpenAttempts, &dwDataSize))
            {
                dwMaxOpenAttempts = 3;
            }
            dwDataSize = sizeof(DWORD);
            if (RegQueryValueEx(hRegKey, TEXT("OpenTimeout"), NULL, &dwValueType, (LPBYTE)&dwMaxOpenAttempts, &dwDataSize))
            {
                dwPortDelay = 1000;
            }
            RegCloseKey(hRegKey);
        }
        for (j = 0; j < dwMaxOpenAttempts; j++)
        {
            hRet = CreateFile(szPortName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
            if (hRet != INVALID_HANDLE_VALUE)
            {
                break;
            }
            Sleep(dwPortDelay);
        }
    }
    return hRet;
}

/*
 @doc INTERNAL
 @func  BOOL | RhaDllEntry | Process attach/detach api.
 *
 @rdesc The return is a BOOL, representing success (TRUE) or failure (FALSE).
 */
BOOL WINAPI RhaDllEntry(HINSTANCE DllInstance, INT Reason, LPVOID Reserved)
{
    switch(Reason) {
        case DLL_PROCESS_ATTACH:
#ifdef DEBUG
#ifndef DEBUG_FILE
            DEBUGREGISTER(DllInstance);
#endif
//          DEBUGMSG(ZONE_INIT, (TEXT("RhaDll: DLL_PROCESS_ATTACH\r\n")));
#endif
            _cinit();
            break;

        case DLL_PROCESS_DETACH:
#ifdef DEBUG
//          DEBUGMSG(ZONE_INIT, (TEXT("RhaDll: DLL_PROCESS_DETACH\r\n")));
#endif
            _cexit();
            break;
    }
    return TRUE;
}

//
// First function called by the RIL after loading of the library
//
void RHA_Init(void)
{
}

//
// Last function called by the RIL before unloading of the library
//
void RHA_DeInit(void)
{
}

//
// Switches on the power to the radio module
// The sample code is designed for a DSB development board where the module
// ignition pin is connected to the serial port DTR signal.
// On a customer hardware the code has to be replaced by the particular
// switch on logic.
//
BOOL RHA_RadioPwrOn(void)
{
    DWORD   dwSleep;
    HANDLE  hPort;

    // Switch on power to the radio
    DEBUGMSG(ZONE_FUNCTION, (TEXT("RhaDll: +RHA_RadioPwrOn()\r\n")));

    // Wait required rercovery time after last switch off
    dwSleep = GetTickCount() - g_dwTimeLastOff;
    if (dwSleep < MIN_DSB_DTR_LOW_TIME)
    {
        Sleep(MIN_DSB_DTR_LOW_TIME - dwSleep);
    }

    // Open the serial port
    hPort = OpenModulePort();
    if (hPort != INVALID_HANDLE_VALUE)
    {
        DEBUGMSG(ZONE_FUNCTION, (TEXT("RhaDll:  Powering module on via serial port\r\n")));
        // On DSB development boards iginition is connected with DTR
        EscapeCommFunction(hPort, SETDTR);

        // We're not sure what happens with DTR after the port is closed again.
        // So we need to wait the required ignition pulse time before closing the port again.
        Sleep(IGNITION_PULSE_TIME);

        // On the ICOP the DTR is on per default, so an addinal pulse is needed
        // to start the module.
        Sleep(IGNITION_PULSE_TIME);
        EscapeCommFunction(hPort, CLRDTR);
        Sleep(IGNITION_PULSE_TIME);
        EscapeCommFunction(hPort, SETDTR);

        CloseHandle(hPort);
    }

    g_fRadioOn = TRUE;

    DEBUGMSG(ZONE_FUNCTION, (TEXT("RhaDll: -RHA_RadioPwrOn()\r\n")));

    return TRUE;
}

//
// Switches off the power to the radio module
//
BOOL RHA_RadioPwrOff(void)
{
    // Switch off power to the radio
    DEBUGMSG(ZONE_FUNCTION, (TEXT("RhaDll: +RHA_RadioPwrOff()\r\n")));

    if (g_fRadioOn)
    {
        g_dwTimeLastOff = GetTickCount();
    }
    g_fRadioOn = FALSE;

    DEBUGMSG(ZONE_FUNCTION, (TEXT("RhaDll: -RHA_RadioPwrOff()\r\n")));
    return TRUE;
}

//
// Returns the current state of the radio power
//
BOOL RHA_IsRadioPwrOn(void)
{
    DEBUGMSG(ZONE_FUNCTION, (TEXT("RhaDll: +RHA_IsRadioPwrOn()\r\n")));

    DEBUGMSG(ZONE_FUNCTION, (TEXT("RhaDll: -RHA_IsRadioPwrOn()\r\n")));
    return g_fRadioOn;
}

//
// Performs the actions required to route the voice audio to the user
//
BOOL RHA_ActivateVoicePath(DWORD dwTxAudioMode, DWORD dwRxAudioMode)
{
    HANDLE  hVoxStartEv;

    DEBUGMSG(ZONE_FUNCTION, (TEXT("RhaDll: +RHA_ActivateVoicePath()\r\n")));

    /*** Example code ***/
    // Signal the audio driver that a voice call is starting
    hVoxStartEv = CreateEvent(NULL, FALSE, FALSE, TEXT("RIL_EVT_VOICECALL_START"));
    if(hVoxStartEv)
    {
        SetEvent(hVoxStartEv);
        CloseHandle(hVoxStartEv);
    }

    DEBUGMSG(ZONE_FUNCTION, (TEXT("RhaDll: -RHA_ActivateVoicePath()\r\n")));
    return TRUE;
}

//
// Performs the actions required to route the normal audio to the user
//
BOOL RHA_DeactivateVoicePath(void)
{
    HANDLE  hVoxEndEv;

    DEBUGMSG(ZONE_FUNCTION, (TEXT("RhaDll: +RHA_DeactivateVoicePath()\r\n")));

    /*** Example code ***/
    // Signal the audio driver that a voice call is ending
    hVoxEndEv = CreateEvent(NULL, FALSE, FALSE, TEXT("RIL_EVT_VOICECALL_END"));
    if(hVoxEndEv)
    {
        SetEvent(hVoxEndEv);
        CloseHandle(hVoxEndEv);
    }

    DEBUGMSG(ZONE_FUNCTION, (TEXT("RhaDll: -RHA_DeactivateVoicePath()\r\n")));
    return TRUE;
}

//
//
//
BOOL RHA_AdjustTxVolume(DWORD dwAudioMode, DWORD dwExtMicAudioCodecVol)
{
    DEBUGMSG(ZONE_FUNCTION, (TEXT("RhaDll: +RHA_AdjustTxVolume()\r\n")));

    DEBUGMSG(ZONE_FUNCTION, (TEXT("RhaDll: -RHA_AdjustTxVolume()\r\n")));
    return TRUE;
}

//
//
//
BOOL RHA_AdjustRxVolume(DWORD dwAudioMode, DWORD dwExtAudioCodecVol)
{
    DEBUGMSG(ZONE_FUNCTION, (TEXT("RhaDll: +RHA_AdjustRxVolume()\r\n")));

    DEBUGMSG(ZONE_FUNCTION, (TEXT("RhaDll: -RHA_AdjustRxVolume()\r\n")));
    return TRUE;
}

//
//
//
BOOL RHA_GetRHAVersion(DWORD *pdwVersion)
{
    DWORD   dwHandle, dwSize, i;
    PDWORD  pvsVersionInfo;
    VS_FIXEDFILEINFO    *pvsFixedFileInfo = NULL;
    DWORD   dwMSVer = 0, dwLSVer = 0;

    DEBUGMSG(ZONE_FUNCTION, (TEXT("RhaDll: +RHA_GetRHAVersion()\r\n")));

    // Fetch the size of the version structure
    dwSize = GetFileVersionInfoSize(TEXT("RHA.DLL"), &dwHandle);

    // Allocate some memory for it
    pvsVersionInfo = (PDWORD)LocalAlloc(LPTR, dwSize);

    // Fetch the version structure
    GetFileVersionInfo(TEXT("RHA.DLL"), dwHandle, dwSize, pvsVersionInfo);

    // Search for the signature
    for(i=0;i<dwSize/4;i++)
    {
        if(pvsVersionInfo[i] == VS_FFI_SIGNATURE)
        {
            pvsFixedFileInfo = (VS_FIXEDFILEINFO*)&pvsVersionInfo[i];
        }
    }

    if (pvsFixedFileInfo != NULL)
    {
        DEBUGMSG(ZONE_FUNCTION, (TEXT("RhaDll:  Version LS = 0x%X  MS = 0x%X\r\n"), pvsFixedFileInfo->dwFileVersionLS, pvsFixedFileInfo->dwFileVersionMS));

        // Read the version info
        dwMSVer = pvsFixedFileInfo->dwFileVersionMS;
        dwLSVer = pvsFixedFileInfo->dwFileVersionLS;
    }

    // Construct a 32 bit version number
    *pdwVersion = ((dwMSVer&0x00FF0000)<<8) + ((dwMSVer&0x000000FF)<<16) + ((dwLSVer&0x00FF0000)>>8) + (dwLSVer&0x000000FF);

    // Free the memory
    LocalFree(pvsVersionInfo);

    DEBUGMSG(ZONE_FUNCTION, (TEXT("RhaDll: -RHA_GetRHAVersion()\r\n")));

    return TRUE;
}

//
//
//
BOOL RHA_ConfirmAudioMode(DWORD *dwTxAudioMode, DWORD *dwRxAudioMode)
{
    DEBUGMSG(ZONE_FUNCTION, (TEXT("RhaDll: +RHA_ConfirmAudioMode()\r\n")));

    // Purpose of this function:
    // The Microsoft TAPI sets the audio device for each voice call to
    // RIL_AUDIO_HANDSET. Since it is not possible to configure the audio
    // device via TAPI, the RIL tests via this RHA-API which audio device
    // is valid. In the following example the RHA tests if the head set is
    // inserted an changes the audio device to RIL_AUDIO_HEADSET.
    // Example:
    //if (*dwTxAudioMode == RIL_AUDIO_HANDSET && RHA_IsHeadSetInserted()) {
    //        *dwTxAudioMode = RIL_AUDIO_HEADSET;
    //        *dwRxAudioMode = RIL_AUDIO_HEADSET;
    //        return FALSE;
    // The function RHA_IsHeadSetInserted() has to be implemented by the customer.
    //}

    // Default: we confirm the given values.

    DEBUGMSG(ZONE_FUNCTION, (TEXT("RhaDll: -RHA_ConfirmAudioMode()\r\n")));
    return TRUE;
}

//
// Function to overwrite the default behaviour of the RIL internal power
// management. See Rgaapi.h for a detailed description of the RIL
// power management. Simply return the value passed in the parameter
// "dwNewDefaultModuleState" for any call to use the default power management.
//
DWORD RHA_SystemPowerChange(CEDEVICE_POWER_STATE CurrPwrState, CEDEVICE_POWER_STATE NewPwrState, DWORD dwCurrModuleState, DWORD dwNewDefaultModuleState, BOOL fOngoing, BOOL fQuery)
{
    DEBUGMSG(ZONE_FUNCTION, (TEXT("RhaDll: +RHA_SystemPowerChange()\r\n")));

    DEBUGMSG(ZONE_FUNCTION, (TEXT("RhaDll: -RHA_SystemPowerChange()\r\n")));
    return dwNewDefaultModuleState;
}

//
//
//
BOOL RHA_GpsAntennaPowerSupplyOn(void)
{
    DEBUGMSG(ZONE_FUNCTION, (TEXT("RhaDll: +RHA_GpsAntennaPowerSupplyOn()\r\n")));

    DEBUGMSG(ZONE_FUNCTION, (TEXT("RhaDll: -RHA_GpsAntennaPowerSupplyOn()\r\n")));
    return TRUE;
}

//
//
//
BOOL RHA_GpsAntennaPowerSupplyOff(void)
{
    DEBUGMSG(ZONE_FUNCTION, (TEXT("RhaDll: +RHA_GpsAntennaPowerSupplyOff()\r\n")));

    DEBUGMSG(ZONE_FUNCTION, (TEXT("RhaDll: -RHA_GpsAntennaPowerSupplyOff()\r\n")));
    return TRUE;
}

//
//
//
void RHA_SwitchToCDMA(void)
{
    DEBUGMSG(ZONE_FUNCTION, (TEXT("RhaDll: +RHA_SwitchToCDMA()\r\n")));

    DEBUGMSG(ZONE_FUNCTION, (TEXT("RhaDll: -RHA_SwitchToCDMA()\r\n")));
    return;
}

//
//
//
void RHA_SwitchToUMTS(void)
{
    DEBUGMSG(ZONE_FUNCTION, (TEXT("RhaDll: +RHA_SwitchToUMTS()\r\n")));

    DEBUGMSG(ZONE_FUNCTION, (TEXT("RhaDll: -RHA_SwitchToUMTS()\r\n")));
    return;
}
