/*****************************************************************************
 * Copyright (C) Cinterion Wireless Modules GmbH
 *****************************************************************************
 * Project: Quinn-CE-USB-Driver
 *****************************************************************************
 * Author : Siemens AG Berlin COM WM RD SW
 *****************************************************************************
 * $Workfile: O:/ctna0450_RIL/z_ms-d/src/working/Classic/HcUsbDrv/DrvEntryVCom.cpp $
 * $Revision: /main/ms-d/18 $
 * $Date: 2010-08-04 13:54:50 $
 * $Author: ctna0450 $
 *****************************************************************************
 * Target:
 *  Microsoft Windows CE 5.0
 *****************************************************************************
 * Description:
 *  UMTS-Module USB-Driver: Virtual COM port driver object entry
 *  points
 *****************************************************************************
 *
 * $Log: O:/ctna0450_RIL/z_ms-d/src/working/Classic/HcUsbDrv/DrvEntryVCom.cpp$ 
 * 
 * /main/ms-d/18   2010-08-04 13:54:50   ctna0450 
 * Unified enumeration process
 *
 * /main/ms-d/17   2009-02-18 11:49:04   ctna0256
 * Set copyright text
 *
 * /main/ms-d/16   2009-01-14 10:47:41   ctna0450
 * Make virtual port instancable to properly support handling of consecutive WaitCommEvent() calls
 *
 * /main/ms-d/15   2008-08-20 11:39:30   ctna0450
 * Prepared for new disclaimer handling
 *
 * /main/ms-d/14   2007-12-18 13:34:50   ht37010
 * changed debug zones
 *
 * /main/ms-d/13   2007-12-18 11:44:34   ht37010
 * added debug messages
 *
 * /main/ms-d/12   2007-08-28 12:51:41   ht37010
 * added encapsulation for all-for-one driver
 *
 * /main/ms-d/11   2007-08-14 12:43:48   ht37010
 * added support for all modules
 *
 * /main/ms-d/10   2007-08-01 10:31:50   ht37010
 * improved handling if new device is attached before old device is detached during global resume
 *
 * /main/ms-d/9   2007-05-30 16:36:25   ht37010
 * added global port validation handling
 *
 * /main/ms-d/8   2007-02-22 14:31:38   wm36264
 * Clear buffers before aborting transfers in IOCTL_SERIAL_PURGE
 *
 * /main/ms-d/7   2006-10-09 15:24:14   wm36264
 * Fixed USB detach problems
 *
 * /main/ms-d/6   2006-10-06 18:00:32   wm36264
 * Make virtual ports fully instancable and use different device names for serial, ndis and qmi devices
 *
 * /main/ms-d/5   2006-09-29 15:33:09   wm36264
 * Consider latest findings about QMI and NDIS handling
 *
 * /main/ms-d/4   2006-09-27 17:07:09   wm36264
 * Switched to central version and trace handling
 *
 * /main/ms-d/3   2006-09-22 14:33:24   wm36264
 * Cosmetics mostly
 *
 * /main/ms-d/2   2006-09-21 17:05:40   wm36264
 * Prepared access to QMI interface
 *
 * /main/ms-d/1   2006-09-18 15:31:46   wm36264
 * Initial Quinn Windows CE USB Driver based on UsbSer
 *
*/

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

//////////////////////////////////////////////////////////////////////////////
//
// DrvEntryVCom.cpp
//
// This file contains the Windows CE device driver interface for the "VCU"
// virtual port device contexts.
//
//////////////////////////////////////////////////////////////////////////////

#include "precomp.h"

//////////////////////////////////////////////////////////////////////////////
//
// Generalized interface functions
//
//////////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////////
//
// 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.
// DevType  : Device type of the corresponding logical device (serial, cmd or
//            ndis). This parameter is proprietary to distinguish the
//            corresponding device types VDU (serial), HCC (cmd) and HCN
//            (ndis).
//
// Return:
// Returns a handle to the device context created, or 0 if unsuccessful.
// This handle is passed to the VCU_Open, VCU_PowerDown, VCU_PowerUp, and
// VCU_Deinit functions.
//
//////////////////////////////////////////////////////////////////////////////
DWORD _Init(DWORD dwContext, HC_DEVICE_TYPE DevType) {
  // Create our virtual port instance
  return (DWORD) new CVirtualPort(GetContextFromReg((LPCTSTR)dwContext), DevType);
}

//////////////////////////////////////////////////////////////////////////////
//
// This function is called by the Device Manager to deinitialize a device.
//
// Parameters:
// hDeviceContext: Handle to the device context. The VCU_Init function
//                 creates and returns this identifier.
//
// Return:
// TRUE indicates success. FALSE indicates failure.
//
//////////////////////////////////////////////////////////////////////////////
BOOL _Deinit(DWORD hDeviceContext) {
  if (!hDeviceContext) {
    DEBUGMSG(ZONE_PORT | ZONE_ERROR, (TEXT("HcUsb:  _Deinit() -> Invalid device context\r\n")));
    return FALSE;
  }

  CVirtualPort::LockSystem();

  // Delete our virtual port instance
  delete (CVirtualPort*)hDeviceContext;

  CVirtualPort::UnlockSystem();

  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 VCU_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 VCU_Read, VCU_Write, VCU_Seek, and VCU_IOControl functions.
// If the device cannot be opened, this function returns NULL.
//
//////////////////////////////////////////////////////////////////////////////
DWORD _Open(DWORD hDeviceContext, DWORD AccessCode, DWORD ShareMode) {
DWORD dwRet = 0;

  if (!hDeviceContext) {
    DEBUGMSG(ZONE_PORT | ZONE_ERROR, (TEXT("HcUsb: _Open() -> Invalid device context\r\n")));
    return 0;
  }

  CVirtualPort::LockSystem();

  if (CVirtualPort::IsVirtualPortValid((CVirtualPort*)hDeviceContext)) {
    // Create our port instance
    CVPortInstance* pInstance = new CVPortInstance((CVirtualPort*)hDeviceContext);
    // try to open the device
    if (pInstance->Open()) {
      dwRet = (DWORD)pInstance;
    } else {
      DEBUGMSG(ZONE_PORT | ZONE_ERROR, (TEXT("HcUsb:  _Open() -> Failed to open virtual port\r\n")));
      delete pInstance;
    }
  } else {
    DEBUGMSG(ZONE_PORT | ZONE_ERROR, (TEXT("HcUsb:  _Open() -> virtual port is invalid\r\n")));
    SetLastError( ERROR_INVALID_ADDRESS );
  }

  CVirtualPort::UnlockSystem();

  return dwRet;
}

//////////////////////////////////////////////////////////////////////////////
//
// This function closes the device context identified by hOpenContext.
//
// Parameters:
// hOpenContext: Handle returned by the VCU_Open function, used to identify
//               the open context of the device.
//
// Return:
// TRUE indicates success. FALSE indicates failure.
//
//////////////////////////////////////////////////////////////////////////////
BOOL _Close(DWORD hOpenContext) {
  DEBUGMSG(ZONE_PORT, (TEXT("HcUsb: +_Close()\r\n")));

  if (!hOpenContext) {
    DEBUGMSG(ZONE_PORT | ZONE_ERROR, (TEXT("HcUsb: -_Close(FALSE) -> Invalid open context\r\n")));
    return FALSE;
  }
  if (!((CVPortInstance*)hOpenContext)->Close()) {
    DEBUGMSG(ZONE_PORT | ZONE_ERROR, (TEXT("HcUsb: -_Close(FALSE) -> Failed to close virtual port\r\n")));
    return FALSE;
  }
  delete (CVPortInstance*)hOpenContext;
  DEBUGMSG(ZONE_PORT, (TEXT("HcUsb: -_Close(TRUE)\r\n")));
  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 VCU_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 _Read(DWORD hOpenContext, LPVOID pBuffer, DWORD Count) {
  if (!hOpenContext) {
    return (DWORD)-1;
  }
  return ((CVPortInstance*)hOpenContext)->ReadData((PBYTE)pBuffer, Count);
}

//////////////////////////////////////////////////////////////////////////////
//
// This function writes data to the device.
//
// Parameters:
// hOpenContext: Handle to the open context of the device. The call to the
//               VCU_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 _Write(DWORD hOpenContext, LPCVOID pBuffer, DWORD Count) {
  if (!hOpenContext) {
    return (DWORD)-1;
  }
  return ((CVPortInstance*)hOpenContext)->WriteData((PBYTE)pBuffer, Count);
}

//////////////////////////////////////////////////////////////////////////////
//
// This function moves the data pointer in the device.
//
// Parameters:
// hOpenContext: Handle to the open context of the device. The VCU_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 _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 VCU_Open
//               function creates and returns this identifier.
//
// Return:
// None.
//
//////////////////////////////////////////////////////////////////////////////
void _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 VCU_Open
//               function creates and returns this identifier.
//
// Return:
// None.
//
//////////////////////////////////////////////////////////////////////////////
void _PowerDown(DWORD hDeviceContext) {
}

//////////////////////////////////////////////////////////////////////////////
//
// This function sends a command to a device.
//
// Parameters:
// hOpenContext: Handle to the open context of the device. The VCU_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 _IOControl(DWORD hOpenContext, DWORD dwCode, PBYTE pBufIn, DWORD dwLenIn, PBYTE pBufOut, DWORD dwLenOut, PDWORD pdwActualOut) {
CVPortInstance*  pInstance = (CVPortInstance*)hOpenContext;
BOOL             fRet = TRUE;

  DEBUGMSG(ZONE_PORT_IOCTL, (TEXT("HcUsb: +_IOControl(port=%p)\r\n"),pInstance));

  if (!pdwActualOut) {
    SetLastError(ERROR_INVALID_PARAMETER);
    DEBUGMSG(ZONE_PORT_IOCTL | ZONE_ERROR, (TEXT("HcUsb: -_IOControl(FALSE) - invalid parameter\r\n")));
    return FALSE;
  }

  *pdwActualOut = 0;

  if (!pInstance) {
      DEBUGMSG(ZONE_PORT_IOCTL | ZONE_ERROR, (TEXT("HcUsb: -_IOControl(FALSE) - no virtual port\r\n")));
      return FALSE;
  }

  switch(dwCode) {
    // Set break state to on
    case IOCTL_SERIAL_SET_BREAK_ON:
      DEBUGMSG(ZONE_PORT_IOCTL, (TEXT("HcUsb:  _IOControl() - IOCTL_SERIAL_SET_BREAK_ON\r\n")));
      fRet = pInstance->SetBreak(TRUE);
      break;

    // Set break state to off
    case IOCTL_SERIAL_SET_BREAK_OFF:
      DEBUGMSG(ZONE_PORT_IOCTL, (TEXT("HcUsb:  _IOControl() - IOCTL_SERIAL_SET_BREAK_OFF\r\n")));
      fRet = pInstance->SetBreak(FALSE);
      break;

    // Set Data Terminal Ready (DTR) signal to high
    case IOCTL_SERIAL_SET_DTR:
      DEBUGMSG(ZONE_PORT_IOCTL, (TEXT("HcUsb:  _IOControl() - IOCTL_SERIAL_SET_DTR\r\n")));
      fRet = pInstance->SetDtr(TRUE);
      break;

    // Set the Data Terminal Ready (DTR) signal to low
    case IOCTL_SERIAL_CLR_DTR:
      DEBUGMSG(ZONE_PORT_IOCTL, (TEXT("HcUsb:  _IOControl() - IOCTL_SERIAL_CLR_DTR\r\n")));
      fRet = pInstance->SetDtr(FALSE);
      break;

    // Set the Ready to Send (RTS) signal to high
    case IOCTL_SERIAL_SET_RTS:
      DEBUGMSG(ZONE_PORT_IOCTL, (TEXT("HcUsb:  _IOControl() - IOCTL_SERIAL_SET_RTS\r\n")));
      fRet = pInstance->SetRts(TRUE);
      break;

    // Set the Request to Send (RTS) signal to low
    case IOCTL_SERIAL_CLR_RTS:
      DEBUGMSG(ZONE_PORT_IOCTL, (TEXT("HcUsb:  _IOControl() - IOCTL_SERIAL_CLR_RTS\r\n")));
      fRet = pInstance->SetRts(FALSE);
      break;

    // Retrieve the value of the wait mask
    case IOCTL_SERIAL_GET_WAIT_MASK:
      DEBUGMSG(ZONE_PORT_IOCTL, (TEXT("HcUsb:  _IOControl() - IOCTL_SERIAL_GET_WAIT_MASK\r\n")));
      if ((dwLenOut >= sizeof(DWORD)) && pBufOut) {
        fRet = pInstance->GetWaitMask((PDWORD)pBufOut);
        *pdwActualOut = sizeof(DWORD);
      } else {
        SetLastError(ERROR_INVALID_PARAMETER);
        fRet = FALSE;
      }
      break;

    // Set the value of the wait mask
    case IOCTL_SERIAL_SET_WAIT_MASK:
      DEBUGMSG(ZONE_PORT_IOCTL, (TEXT("HcUsb:  _IOControl() - IOCTL_SERIAL_SET_WAIT_MASK\r\n")));
      if (pBufIn && (dwLenIn >= sizeof(DWORD))) {
        fRet = pInstance->SetWaitMask(*(PDWORD)pBufIn);
      } else {
        SetLastError(ERROR_INVALID_PARAMETER);
        fRet = FALSE;
      }
      break;

    // Wait for a communications event that matches the event specified in the event mask
    case IOCTL_SERIAL_WAIT_ON_MASK:
      DEBUGMSG(ZONE_PORT_IOCTL, (TEXT("HcUsb:  _IOControl() - IOCTL_SERIAL_WAIT_ON_MASK\r\n")));
      if ((dwLenOut >= sizeof(DWORD)) && pBufOut) {
        fRet = pInstance->WaitOnMask((PDWORD)pBufOut);
      } else {
        SetLastError(ERROR_INVALID_PARAMETER);
        fRet = FALSE;
      }
      break;

    // Clear any pending communications errors and returns the current communication status
    case IOCTL_SERIAL_GET_COMMSTATUS:
      DEBUGMSG(ZONE_PORT_IOCTL, (TEXT("HcUsb:  _IOControl() - IOCTL_SERIAL_GET_COMMSTATUS\r\n")));
      if ((dwLenOut >= sizeof(SERIAL_DEV_STATUS)) && pBufOut) {
        fRet = pInstance->GetComStat(&(((PSERIAL_DEV_STATUS)pBufOut)->ComStat));
        *pdwActualOut = sizeof(SERIAL_DEV_STATUS);
      } else {
        SetLastError(ERROR_INVALID_PARAMETER);
        fRet = FALSE;
      }
      break;

    // Retrieve the current modem control-register values
    case IOCTL_SERIAL_GET_MODEMSTATUS:
      DEBUGMSG(ZONE_PORT_IOCTL, (TEXT("HcUsb:  _IOControl() - IOCTL_SERIAL_GET_MODEMSTATUS\r\n")));
      if ((dwLenOut >= sizeof(DWORD)) && pBufOut) {
        DEBUGMSG(ZONE_PORT, (TEXT("HcUsb: +_IOControl() -> IOCTL_SERIAL_GET_MODEMSTATUS\r\n")));
        fRet = pInstance->GetModemState((PDWORD)pBufOut);
        if ( fRet == FALSE ) {
            DEBUGMSG(ZONE_ERROR, (TEXT("HcUsb:  _IOControl() -> GetModemState() failed: err=%d\r\n"), GetLastError()));
        }
        *pdwActualOut = sizeof(DWORD);
        DEBUGMSG(ZONE_PORT, (TEXT("HcUsb: -_IOControl() -> IOCTL_SERIAL_GET_MODEMSTATUS(%d)\r\n"), fRet));
      } else {
        SetLastError(ERROR_INVALID_PARAMETER);
        fRet = FALSE;
      }
      break;

    // Retrieve information about the communications properties
    case IOCTL_SERIAL_GET_PROPERTIES:
      DEBUGMSG(ZONE_PORT_IOCTL, (TEXT("HcUsb:  _IOControl() - IOCTL_SERIAL_GET_PROPERTIES\r\n")));
      if ((dwLenOut >= sizeof(COMMPROP)) && pBufOut) {
        fRet = pInstance->GetProperties((LPCOMMPROP)pBufOut);
        *pdwActualOut = sizeof(COMMPROP);
      } else {
        SetLastError(ERROR_INVALID_PARAMETER);
        fRet = FALSE;
      }
      break;

    // Set the time-out parameters for all read and write operations
    case IOCTL_SERIAL_SET_TIMEOUTS:
      DEBUGMSG(ZONE_PORT_IOCTL, (TEXT("HcUsb:  _IOControl() - IOCTL_SERIAL_SET_TIMEOUTS\r\n")));
      if (pBufIn && (dwLenIn >= sizeof(COMMTIMEOUTS))) {
        fRet = pInstance->SetTimeouts((COMMTIMEOUTS*)pBufIn);
      } else {
        SetLastError(ERROR_INVALID_PARAMETER);
        fRet = FALSE;
      }
      break;

    // Get the time-out parameters for all read and write operations
    case IOCTL_SERIAL_GET_TIMEOUTS:
      DEBUGMSG(ZONE_PORT_IOCTL, (TEXT("HcUsb:  _IOControl() - IOCTL_SERIAL_GET_TIMEOUTS\r\n")));
      if ((dwLenOut >= sizeof(COMMTIMEOUTS)) && pBufOut) {
        fRet = pInstance->GetTimeouts((COMMTIMEOUTS*)pBufOut);
        *pdwActualOut = sizeof(COMMTIMEOUTS);
      } else {
        SetLastError(ERROR_INVALID_PARAMETER);
        fRet = FALSE;
      }
      break;

    // Discard characters from the output or input buffer, it can also terminate pending read or write operations
    case IOCTL_SERIAL_PURGE:
      DEBUGMSG(ZONE_PORT_IOCTL, (TEXT("HcUsb:  _IOControl() - IOCTL_SERIAL_PURGE\r\n")));
      if (pBufIn && (dwLenIn >= sizeof(DWORD))) {
        DWORD dwFlags = *((PDWORD)pBufIn);
        if (dwFlags & PURGE_RXCLEAR) {
          if (!pInstance->ClearRead()) {
            fRet = FALSE;
          }
        }
        if (dwFlags & PURGE_TXCLEAR) {
          if (!pInstance->ClearWrite()) {
            fRet = FALSE;
          }
        }
        if (dwFlags & PURGE_RXABORT) {
          if (!pInstance->AbortRead()) {
            fRet = FALSE;
          }
        }
        if (dwFlags & PURGE_TXABORT) {
          if (!pInstance->AbortWrite()) {
            fRet = FALSE;
          }
        }
      } else {
        SetLastError(ERROR_INVALID_PARAMETER);
        fRet = FALSE;
      }
      break;

    // Set size of send and receive buffers
    case IOCTL_SERIAL_SET_QUEUE_SIZE:
      DEBUGMSG(ZONE_PORT_IOCTL, (TEXT("HcUsb:  _IOControl() - IOCTL_SERIAL_SET_QUEUE_SIZE\r\n")));
      if ((dwLenIn >= sizeof(SERIAL_QUEUE_SIZES)) && pBufIn) {
        fRet = pInstance->SetQueueSize((SERIAL_QUEUE_SIZES*)pBufIn);
      } else {
        SetLastError(ERROR_INVALID_PARAMETER);
        fRet = FALSE;
      }
      break;

    // Get the device-control block
    case IOCTL_SERIAL_GET_DCB:
      DEBUGMSG(ZONE_PORT_IOCTL, (TEXT("HcUsb:  _IOControl() - IOCTL_SERIAL_GET_DCB\r\n")));
      if ((dwLenOut >= sizeof(DCB)) && pBufOut) {
        fRet = pInstance->GetDcb((DCB*)pBufOut);
        *pdwActualOut = sizeof(DCB);
      } else {
        SetLastError(ERROR_INVALID_PARAMETER);
        fRet = FALSE;
      }
      break;

    // Set the device-control block
    case IOCTL_SERIAL_SET_DCB:
      DEBUGMSG(ZONE_PORT_IOCTL, (TEXT("HcUsb:  _IOControl() - IOCTL_SERIAL_SET_DCB\r\n")));
      if (pBufIn && (dwLenIn >= sizeof(DCB))) {
        fRet = pInstance->SetDcb((DCB*)pBufIn);
      } else {
        SetLastError(ERROR_INVALID_PARAMETER);
        fRet = FALSE;
      }
      break;

    // Unsupported serial interface functions in mux mode
    case IOCTL_SERIAL_SET_XOFF:
    case IOCTL_SERIAL_SET_XON:
    case IOCTL_SERIAL_IMMEDIATE_CHAR:
    case IOCTL_SERIAL_ENABLE_IR:
    case IOCTL_SERIAL_DISABLE_IR:
      DEBUGMSG(ZONE_PORT_IOCTL, (TEXT("HcUsb:  _IOControl() - not supported\r\n")));
      SetLastError(ERROR_NOT_SUPPORTED);
      fRet = FALSE;
      break;

    // Unknown serial interface functions
    default:
      DEBUGMSG(ZONE_PORT_IOCTL, (TEXT("HcUsb:  _IOControl() - unknown\r\n")));
      SetLastError(ERROR_INVALID_PARAMETER);
      fRet = FALSE;
      break;
  }

  DEBUGMSG(ZONE_PORT_IOCTL, (TEXT("HcUsb: -_IOControl(%d)\r\n"), fRet));
  return fRet;
}

//////////////////////////////////////////////////////////////////////////////
//
// VCU interface (Cdc/Acm or vendor specific serial port)
//
//////////////////////////////////////////////////////////////////////////////

DWORD VCU_Init(DWORD dwContext) {
  DEBUGMSG(ZONE_PORT, (TEXT("HcUsb: +VCU_Init(%s)\r\n"), (LPCTSTR)dwContext));
  DWORD dwRet = _Init(dwContext, HC_SERIAL);
  DEBUGMSG(ZONE_PORT, (TEXT("HcUsb: -VCU_Init() -> %p\r\n"), dwRet));
  return dwRet;
}

BOOL VCU_Deinit(DWORD hDeviceContext) {
  DEBUGMSG(ZONE_PORT, (TEXT("HcUsb: +VCU_Deinit(%p)\r\n"), hDeviceContext));
  BOOL fRet = _Deinit(hDeviceContext);
  DEBUGMSG(ZONE_PORT, (TEXT("HcUsb: -VCU_Deinit() -> %d\r\n"), fRet));
  return fRet;
}

DWORD VCU_Open(DWORD hDeviceContext, DWORD AccessCode, DWORD ShareMode) {
  DEBUGMSG(ZONE_PORT, (TEXT("HcUsb: +VCU_Open(%p, %x, %x)\r\n"), hDeviceContext, AccessCode, ShareMode));
  DWORD dwRet = _Open(hDeviceContext, AccessCode, ShareMode);
  DEBUGMSG(ZONE_PORT, (TEXT("HcUsb: -VCU_Open() -> %p\r\n"), dwRet));
  return dwRet;
}

BOOL VCU_Close(DWORD hOpenContext) {
  DEBUGMSG(ZONE_PORT, (TEXT("HcUsb: +VCU_Close(%p)\r\n"), hOpenContext));
  BOOL fRet = _Close(hOpenContext);
  DEBUGMSG(ZONE_PORT, (TEXT("HcUsb: -VCU_Close()-> %d\r\n"), fRet));
  return fRet;
}

DWORD VCU_Read(DWORD hOpenContext, LPVOID pBuffer, DWORD Count) {
  return _Read(hOpenContext, pBuffer, Count);
}

DWORD VCU_Write(DWORD hOpenContext, LPCVOID pBuffer, DWORD Count) {
  return _Write(hOpenContext, pBuffer, Count);
}

DWORD VCU_Seek(DWORD hOpenContext, long Amount, WORD Type) {
  return _Seek(hOpenContext, Amount, Type);
}

void VCU_PowerUp(DWORD hDeviceContext) {
  _PowerUp(hDeviceContext);
}

void VCU_PowerDown(DWORD hDeviceContext) {
  _PowerDown(hDeviceContext);
}

BOOL VCU_IOControl(DWORD hOpenContext, DWORD dwCode, PBYTE pBufIn, DWORD dwLenIn, PBYTE pBufOut, DWORD dwLenOut, PDWORD pdwActualOut) {
  return _IOControl(hOpenContext, dwCode, pBufIn, dwLenIn, pBufOut, dwLenOut, pdwActualOut);
}

//////////////////////////////////////////////////////////////////////////////
//
// HCC interface (command port)
//
//////////////////////////////////////////////////////////////////////////////

DWORD HCC_Init(DWORD dwContext) {
  DEBUGMSG(ZONE_PORT, (TEXT("HcUsb: +HCC_Init(%s)\r\n"), (LPCTSTR)dwContext));
  DWORD dwRet = _Init(dwContext, HC_CMD);
  DEBUGMSG(ZONE_PORT, (TEXT("HcUsb: -HCC_Init() -> %p\r\n"), dwRet));
  return dwRet;
}

BOOL HCC_Deinit(DWORD hDeviceContext) {
  DEBUGMSG(ZONE_PORT, (TEXT("HcUsb: +HCC_Deinit(%p)\r\n"), hDeviceContext));
  BOOL fRet = _Deinit(hDeviceContext);
  DEBUGMSG(ZONE_PORT, (TEXT("HcUsb: -HCC_Deinit() -> %d\r\n"), fRet));
  return fRet;
}

DWORD HCC_Open(DWORD hDeviceContext, DWORD AccessCode, DWORD ShareMode) {
  DEBUGMSG(ZONE_PORT, (TEXT("HcUsb: +HCC_Open(%p, %x, %x)\r\n"), hDeviceContext, AccessCode, ShareMode));
  DWORD dwRet = _Open(hDeviceContext, AccessCode, ShareMode);
  DEBUGMSG(ZONE_PORT, (TEXT("HcUsb: -HCC_Open() -> %p\r\n"), dwRet));
  return dwRet;
}

BOOL HCC_Close(DWORD hOpenContext) {
  DEBUGMSG(ZONE_PORT, (TEXT("HcUsb: +HCC_Close(%p)\r\n"), hOpenContext));
  BOOL fRet = _Close(hOpenContext);
  DEBUGMSG(ZONE_PORT, (TEXT("HcUsb: -HCC_Close() -> %d\r\n"), fRet));
  return fRet;
}

DWORD HCC_Read(DWORD hOpenContext, LPVOID pBuffer, DWORD Count) {
  return _Read(hOpenContext, pBuffer, Count);
}

DWORD HCC_Write(DWORD hOpenContext, LPCVOID pBuffer, DWORD Count) {
  return _Write(hOpenContext, pBuffer, Count);
}

DWORD HCC_Seek(DWORD hOpenContext, long Amount, WORD Type) {
  return _Seek(hOpenContext, Amount, Type);
}

void HCC_PowerUp(DWORD hDeviceContext) {
  _PowerUp(hDeviceContext);
}

void HCC_PowerDown(DWORD hDeviceContext) {
  _PowerDown(hDeviceContext);
}

BOOL HCC_IOControl(DWORD hOpenContext, DWORD dwCode, PBYTE pBufIn, DWORD dwLenIn, PBYTE pBufOut, DWORD dwLenOut, PDWORD pdwActualOut) {
  return _IOControl(hOpenContext, dwCode, pBufIn, dwLenIn, pBufOut, dwLenOut, pdwActualOut);
}

//////////////////////////////////////////////////////////////////////////////
//
// HCN interface (ndis port)
//
//////////////////////////////////////////////////////////////////////////////

DWORD HCN_Init(DWORD dwContext) {
  DEBUGMSG(ZONE_PORT, (TEXT("HcUsb: +HCN_Init(%s)\r\n"), (LPCTSTR)dwContext));
  DWORD dwRet = _Init(dwContext, HC_NDIS);
  DEBUGMSG(ZONE_PORT, (TEXT("HcUsb: -HCN_Init() -> %p\r\n"), dwRet));
  return dwRet;
}

BOOL HCN_Deinit(DWORD hDeviceContext) {
  DEBUGMSG(ZONE_PORT, (TEXT("HcUsb: +HCN_Deinit(%p)\r\n"), hDeviceContext));
  BOOL fRet = _Deinit(hDeviceContext);
  DEBUGMSG(ZONE_PORT, (TEXT("HcUsb: -HCN_Deinit() -> %d\r\n"), fRet));
  return fRet;
}

DWORD HCN_Open(DWORD hDeviceContext, DWORD AccessCode, DWORD ShareMode) {
  DEBUGMSG(ZONE_PORT, (TEXT("HcUsb: +HCN_Open(%p, %x, %x)\r\n"), hDeviceContext, AccessCode, ShareMode));
  DWORD dwRet = _Open(hDeviceContext, AccessCode, ShareMode);
  DEBUGMSG(ZONE_PORT, (TEXT("HcUsb: -HCN_Open() -> %p\r\n"), dwRet));
  return dwRet;
}

BOOL HCN_Close(DWORD hOpenContext) {
  DEBUGMSG(ZONE_PORT, (TEXT("HcUsb: +HCN_Close(%p)\r\n"), hOpenContext));
  BOOL fRet = _Close(hOpenContext);
  DEBUGMSG(ZONE_PORT, (TEXT("HcUsb: -HCN_Close() -> %d\r\n"), fRet));
  return fRet;
}

DWORD HCN_Read(DWORD hOpenContext, LPVOID pBuffer, DWORD Count) {
  return _Read(hOpenContext, pBuffer, Count);
}

DWORD HCN_Write(DWORD hOpenContext, LPCVOID pBuffer, DWORD Count) {
  return _Write(hOpenContext, pBuffer, Count);
}

DWORD HCN_Seek(DWORD hOpenContext, long Amount, WORD Type) {
  return _Seek(hOpenContext, Amount, Type);
}

void HCN_PowerUp(DWORD hDeviceContext) {
  _PowerUp(hDeviceContext);
}

void HCN_PowerDown(DWORD hDeviceContext) {
  _PowerDown(hDeviceContext);
}

BOOL HCN_IOControl(DWORD hOpenContext, DWORD dwCode, PBYTE pBufIn, DWORD dwLenIn, PBYTE pBufOut, DWORD dwLenOut, PDWORD pdwActualOut) {
  return _IOControl(hOpenContext, dwCode, pBufIn, dwLenIn, pBufOut, dwLenOut, pdwActualOut);
}
