/*****************************************************************************
 * Copyright (C) Cinterion Wireless Modules GmbH
 *****************************************************************************
 * Project: CE-MUX-Driver
 *****************************************************************************
 * Author : Siemens AG Berlin COM WM RD SW1
 *****************************************************************************
 * $Workfile: Y:/z_ms-d/src/working/Classic/MuxDrv/DrvEntryMux.cpp $
 * $Revision: /main/ms-d/15 $
 * $Date: 2009-02-18 11:58:05 $
 * $Author: ctna0256 $
 *****************************************************************************
 * Target:
 *  Microsoft Windows CE 4.2 or 5.0
 *****************************************************************************
 * Description:
 *  Cinterion Multiplex Driver MUX driver object entry points
 *****************************************************************************
 *
 * $Log: Y:/z_ms-d/src/working/Classic/MuxDrv/DrvEntryMux.cpp$ 
 * 
 * /main/ms-d/15   2009-02-18 11:58:05   ctna0256 
 * Set copyright text 
 * 
 * /main/ms-d/14   2008-11-20 15:11:46   ctna0450 
 * Added new debug zones for detailed hdlc tracing
 *
 * /main/ms-d/13   2008-10-17 12:03:57   ctna0450
 * Added debug zone for IOCTLs
 *
 * /main/ms-d/12   2008-08-20 11:38:22   ctna0450
 * Prepared for new disclaimer handling
 *
 * /main/ms-d/11   2007-05-08 16:47:10   kr36712
 * IPIS100034485
 * reopen implemented for suspend/resume over usb-driver
 *
 * /main/ms-d/10   2006-05-18 13:32:58   wm36264
 * Fixed all useful lint warnings
 *
 * /main/ms-d/9   2006-05-15 14:22:25   wm36264
 * Avoid strange exception
 *
 * /main/ms-d/8   2006-05-09 16:09:19   wm36264
 * Added missing debug settings
 *
 * /main/ms-d/7   2006-05-02 14:31:03   KR36712
 * debug feature implemented (port, file)
 *
 * /main/ms-d/6   2005-12-16 14:02:02   wm36264
 * Avoid linker warning
 *
 * /main/ms-d/5   2005-11-28 15:01:17   wm36264
 * Improved module power off detection
 *
 * /main/ms-d/4   2005-11-09 10:59:27   wm36264
 * Switched to new instancable mux interface
 *
 * /main/ms-d/3   2005-10-24 14:20:44   WM36264
 * Added file descriptions
 *
 * /main/ms-d/2   2005-10-20 13:11:08   WM36264
 * Added proper copyright header
 *
 * /main/ms-d/1   2005-10-07 16:29:46   wm36264
 * First version of Windows CE Muxer
 *
*/

//////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2008 Cinterion Wireless Modules GmbH
// Copyright (C) 2005-2008 Siemens AG
//
// Version: 1.0
// Date:    dummy
//
//////////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////////
//
// DrvEntryMux.cpp
//
// This file contains the Windows CE device driver interface for the "MPX"
// device context as well as the driver dll's main entry function
// "MuxDllMain()".
//
//////////////////////////////////////////////////////////////////////////////

#include "precomp.h"

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

extern "C" void __cdecl _cinit(void);
extern "C" void __cdecl _cexit(void);

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

#ifdef DEBUG
DBGPARAM dpCurSettings = {
  TEXT("MuxDrv"), {
    TEXT("General"),         TEXT("Module Exit"),       TEXT("AT-Cmd"),
    TEXT("Frame-Error"),     TEXT("Mux-Protocol 1"),    TEXT("Mux-Protocol 2"),
    TEXT("Mux-Hdlc"),        TEXT("Raw-data"),          TEXT("Mux Exit"),
    TEXT("Ioctl"),           TEXT("Mux-Hdlc-Framing"),  TEXT("Mux-Hdlc-Error")
  },
  0xFFFF
};
#endif

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

//////////////////////////////////////////////////////////////////////////////
//
// This function is an optional method of entry into a dynamic-link library
// (DLL). If the function is used, it is called by the system when processes
// and threads are initialized and terminated, or upon calls to the
// LoadLibrary and FreeLibrary functions.
//
// Parameters:
// DllInstance: Handle to the DLL. The value is the base address of the DLL.
//              The HINSTANCE of a DLL is the same as the HMODULE of the
//              DLL, so hinstDLL can be used in subsequent calls to the
//              GetModuleFileName function and other functions that require
//              a module handle.
// Reason     : Specifies a flag indicating why the DLL entry-point function
//              is being called (DLL_PROCESS_ATTACH, DLL_THREAD_ATTACH,
//              DLL_THREAD_DETACH, DLL_PROCESS_DETACH).
// Reserved   : Specifies further aspects of DLL initialization and cleanup.
//              If dwReason is DLL_PROCESS_ATTACH, lpvReserved is NULL for
//              dynamic loads and non-NULL for static loads.
//              If dwReason is DLL_PROCESS_DETACH, lpvReserved is NULL if
//              DllMain has been called by using FreeLibrary and non-NULL
//              if DllMain has been called during process termination.
//
// Return:
// When the system calls the DllMain function with the DLL_PROCESS_ATTACH
// value, the function returns TRUE if it succeeds or FALSE if initialization
// fails.
//
//////////////////////////////////////////////////////////////////////////////
BOOL MuxDllMain(HINSTANCE DllInstance, DWORD Reason, LPVOID Reserved) {
  switch(Reason) {
    case DLL_PROCESS_ATTACH:
      _cinit();
      // Init our possibly used serial port trace
      MuxTrace(NULL);
      break;

    case DLL_PROCESS_DETACH:
      _cexit();
      // Deinit our possibly used serial port trace
      MuxTrace(NULL);
      break;
  }
  return TRUE;
}

//////////////////////////////////////////////////////////////////////////////
//
// This function is called by the Device Manager to initialize a device.
//
// Parameters:
// dwContext: Specifies a pointer to a string containing the registry path to
//            the active key for the stream interface driver.
//
// Return:
// Returns a handle to the device context created, or 0 if unsuccessful.
// This handle is passed to the MPX_Open, MPX_PowerDown, MPX_PowerUp, and
// MPX_Deinit functions.
//
//////////////////////////////////////////////////////////////////////////////
DWORD MPX_Init(DWORD dwContext) {
  return (DWORD)(new CBasePort((LPCTSTR)dwContext));
}

//////////////////////////////////////////////////////////////////////////////
//
// This function is called by the Device Manager to deinitialize a device.
//
// Parameters:
// hDeviceContext: Handle to the device context. The MPX_Init function
//                 creates and returns this identifier.
//
// Return:
// TRUE indicates success. FALSE indicates failure.
//
//////////////////////////////////////////////////////////////////////////////
BOOL MPX_Deinit(DWORD hDeviceContext) {
  if (!hDeviceContext) {
    return FALSE;
  }
  delete (CBasePort*)hDeviceContext;
  return TRUE;
}

//////////////////////////////////////////////////////////////////////////////
//
// This function opens a device for reading and/or writing. An application
// indirectly invokes this function when it calls CreateFile to open special
// device file names.
//
// Parameters:
// hDeviceContext: Handle to the device context. The MPX_Init function
//                 creates and returns this handle.
// AccessCode    : Specifies the requested access code of the device. The
//                 access is a combination of read and write.
// ShareMode     : Specifies the requested file share mode of the PC Card
//                 device. The share mode is a combination of file read and
//                 write sharing.
//
// Return:
// This function returns a handle that identifies the open context of the
// device to the calling application. If your device can be opened multiple
// times, use this handle to identify each open context. This identifier is
// passed into the MPX_Read, MPX_Write, MPX_Seek, and MPX_IOControl functions.
// If the device cannot be opened, this function returns NULL.
//
//////////////////////////////////////////////////////////////////////////////
DWORD MPX_Open(DWORD hDeviceContext, DWORD AccessCode, DWORD ShareMode) {
  return hDeviceContext;
}

//////////////////////////////////////////////////////////////////////////////
//
// This function closes the device context identified by hOpenContext.
//
// Parameters:
// hOpenContext: Handle returned by the MPX_Open function, used to identify
//               the open context of the device.
//
// Return:
// TRUE indicates success. FALSE indicates failure.
//
//////////////////////////////////////////////////////////////////////////////
BOOL MPX_Close(DWORD hOpenContext) {
  if (!hOpenContext) {
    return FALSE;
  }
  return TRUE;
}

//////////////////////////////////////////////////////////////////////////////
//
// This function reads data from the device identified by the open context.
//
// Parameters:
// hOpenContext: Handle to the open context of the device. The MPX_Open
//               function creates and returns this identifier.
// pBuffer     : Pointer to the buffer which stores the data read from the
//               device. This buffer should be at least Count bytes long.
// Count       : Specifies the number of bytes to read from the device into
///              pBuffer.
//
// Return:
// Returns 0 for the end-of-file, –1 for an error, or the number of bytes read
// for success.
//
//////////////////////////////////////////////////////////////////////////////
DWORD MPX_Read(DWORD hOpenContext, LPVOID pBuffer, DWORD Count) {
  return (DWORD)-1;
}

//////////////////////////////////////////////////////////////////////////////
//
// This function writes data to the device.
//
// Parameters:
// hOpenContext: Handle to the open context of the device. The call to the
//               MPX_Open function returns this identifier.
// pBuffer     : Pointer to the buffer that contains the data to write.
// Count       : Specifies the number of bytes to write from the pSourceBytes
//               buffer into the device.
//
// Return:
// The number of bytes written indicates success. A value of –1 indicates
// failure.
//
//////////////////////////////////////////////////////////////////////////////
DWORD MPX_Write(DWORD hOpenContext, LPCVOID pBuffer, DWORD Count) {
  return (DWORD)-1;
}

//////////////////////////////////////////////////////////////////////////////
//
// This function moves the data pointer in the device.
//
// Parameters:
// hOpenContext: Handle to the open context of the device. The MPX_Open
//               function creates and returns this identifier.
// Amount      : Specifies the number of bytes to move the data pointer in the
//               device. A positive value moves the data pointer toward the
//               end of the file, and a negative value moves it toward the
//               beginning.
// Type        : Specifies the starting point for the data pointer
//              (FILE_BEGIN, FILE_CURRENT, FILE_END).
//
// Return:
// The device’s new data pointer indicates success. A value of –1 indicates
// failure.
//
//////////////////////////////////////////////////////////////////////////////
DWORD MPX_Seek(DWORD hOpenContext, long Amount, WORD Type) {
  return (DWORD)-1;
}

//////////////////////////////////////////////////////////////////////////////
//
// This function restores power to a device.
//
// Parameters:
// hOpenContext: Handle to the open context of the device. The MPX_Open
//               function creates and returns this identifier.
//
// Return:
// None.
//
//////////////////////////////////////////////////////////////////////////////
void MPX_PowerUp(DWORD hDeviceContext) {
}

//////////////////////////////////////////////////////////////////////////////
//
// This function suspends power to the device. It is useful only with devices
// that can be shut off under software control. Such devices are typically,
// but not exclusively, PC Card devices.
//
// Parameters:
// hOpenContext: Handle to the open context of the device. The MPX_Open
//               function creates and returns this identifier.
//
// Return:
// None.
//
//////////////////////////////////////////////////////////////////////////////
void MPX_PowerDown(DWORD hDeviceContext) {
}

//////////////////////////////////////////////////////////////////////////////
//
// This function sends a command to a device.
// We use it in the mux driver object for power management only.
//
// Parameters:
// hOpenContext: Handle to the open context of the device. The MPX_Open
//               function creates and returns this identifier.
// dwCode      : Specifies a value indicating the I/O control operation to
//               perform. These codes are device-specific and are usually
//               exposed to programmers by means of a header file.
// pBufIn      : Pointer to the buffer containing data to be transferred to
//               the device.
// dwLenIn     : Specifies the number of bytes of data in the buffer specified
//               for pBufIn.
// pBufOut     : Pointer to the buffer used to transfer the output data from
//               the device.
// dwLenOut    : Specifies the maximum number of bytes in the buffer specified
//               by pBufOut.
// pdwActualOut: Pointer to the DWORD buffer that this function uses to return
//               the actual number of bytes received from the device.
//
// Return:
// TRUE indicates success. FALSE indicates failure.
//
//////////////////////////////////////////////////////////////////////////////
BOOL MPX_IOControl(DWORD hOpenContext, DWORD dwCode, PBYTE pBufIn, DWORD dwLenIn, PBYTE pBufOut, DWORD dwLenOut, PDWORD pdwActualOut) {
BOOL fRet = TRUE;

  if (!pdwActualOut) {
    SetLastError(ERROR_INVALID_PARAMETER);
    return FALSE;
  }

  *pdwActualOut = 0;

  if (!hOpenContext) return FALSE;

  MUXDBG(ZONE_IOCTL, (TEXT("MuxDrv: Received IOCTL %08x on MPX instance %p\r\n"), dwCode, hOpenContext));

  switch(dwCode) {
    // Internal mux interface
    case IOCTL_MPX_ADD_VCOM:
      if ((dwLenIn >= sizeof(DWORD)) && pBufIn && (dwLenOut >= sizeof(DWORD)) && pBufOut) {
        *(PDWORD)pBufOut = ((CBasePort*)hOpenContext)->AddVCom(*((PDWORD)pBufIn));
        *pdwActualOut = sizeof(DWORD);
        if (!(*(PDWORD)pBufOut)) {
          fRet = FALSE;
        }
      } else {
        SetLastError(ERROR_INVALID_PARAMETER);
        fRet = FALSE;
      }
      break;

    case IOCTL_MPX_REMOVE_VCOM:
      if (!((CBasePort*)hOpenContext)->RemoveVCom()) {
        fRet = FALSE;
      }
      break;

    case IOCTL_MPX_POWER_FAIL:
      if (!((CBasePort*)hOpenContext)->ShutdownMux()) {
        fRet = FALSE;
      }
      break;

    // Power management
    case IOCTL_POWER_CAPABILITIES :
      if ((dwLenOut >= sizeof(POWER_CAPABILITIES)) && pBufOut) {
        // We support all power modes
        memset(pBufOut, 0, sizeof(POWER_CAPABILITIES));
        ((PPOWER_CAPABILITIES)(pBufOut))->DeviceDx = DX_MASK(D0)|DX_MASK(D1)|DX_MASK(D2)|DX_MASK(D3)|DX_MASK(D4);
        *pdwActualOut = sizeof(POWER_CAPABILITIES);
      } else {
        SetLastError(ERROR_INVALID_PARAMETER);
        fRet = FALSE;
      }
      break;

    case IOCTL_POWER_SET :
      if ((dwLenOut >= sizeof(CEDEVICE_POWER_STATE)) && pBufOut) {
        if (((CBasePort*)hOpenContext)->SetPowerState(*(PCEDEVICE_POWER_STATE)pBufOut)) {
          *(PCEDEVICE_POWER_STATE)pBufOut = ((CBasePort*)hOpenContext)->GetPowerState();
          *pdwActualOut = sizeof(CEDEVICE_POWER_STATE);
        } else {
          fRet = FALSE;
        }
      } else {
        SetLastError(ERROR_INVALID_PARAMETER);
        fRet = FALSE;
      }
      break;

    case IOCTL_POWER_GET :
      if ((dwLenOut >= sizeof(CEDEVICE_POWER_STATE)) && pBufOut) {
        *(PCEDEVICE_POWER_STATE)pBufOut = ((CBasePort*)hOpenContext)->GetPowerState();
        *pdwActualOut = sizeof(CEDEVICE_POWER_STATE);
      } else {
        SetLastError(ERROR_INVALID_PARAMETER);
        fRet = FALSE;
      }
      break;

    case IOCTL_POWER_QUERY :
    case IOCTL_REGISTER_POWER_RELATIONSHIP :
      MUXDBG(ZONE_IOCTL, (TEXT("MuxDrv: Received IOCTL is not supported\r\n")));
      SetLastError(ERROR_NOT_SUPPORTED);
      fRet = FALSE;
      break;

    // Unknown serial interface functions
    default:
      MUXDBG(ZONE_IOCTL, (TEXT("MuxDrv: Received IOCTL is unknown\r\n")));
      SetLastError(ERROR_INVALID_PARAMETER);
      fRet = FALSE;
      break;
  }

  return fRet;
}
