/*****************************************************************************
 * 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/VirtualPort.h $
 * $Revision: /main/ms-d/27 $
 * $Date: 2011-03-03 09:56:57 $
 * $Author: ctna0450 $
 *****************************************************************************
 * Target:
 *  Microsoft Windows CE 5.0
 *****************************************************************************
 * Description:
 *  Quinn-USB-Driver: Virtual COM port port class CVirtualPort
 *  definition
 *****************************************************************************
 *
 * $Log: O:/ctna0450_RIL/z_ms-d/src/working/Classic/HcUsbDrv/VirtualPort.h$ 
 * 
 * /main/ms-d/27   2011-03-03 09:56:57   ctna0450 
 * Performance improvements
 *
 * /main/ms-d/26   2011-02-14 14:12:52   ctna0152
 * fix for IPIS100069778
 * removed USE_DEVICE_REQUEST_REDIRECT encapsulation
 *
 * /main/ms-d/25   2010-08-17 14:41:52   ctna0450
 * Use dynamic array for port list to be able to handle more than 4 virtual ports
 *
 * /main/ms-d/24   2010-08-04 13:54:48   ctna0450
 * Unified enumeration process
 *
 * /main/ms-d/23   2009-09-07 13:50:11   ctna0450
 * Simplyfied read/write handshaking
 *
 * /main/ms-d/22   2009-02-18 11:50:01   ctna0256
 * Set copyright text
 *
 * /main/ms-d/21   2009-01-14 10:47:50   ctna0450
 * Make virtual port instancable to properly support handling of consecutive WaitCommEvent() calls
 *
 * /main/ms-d/20   2008-10-27 15:42:33   ctna0152
 * bugfix: calling getmodemstate() before line state is sent over USB from module
 *
 * /main/ms-d/19   2008-08-20 11:39:24   ctna0450
 * Prepared for new disclaimer handling
 *
 * /main/ms-d/18   2007-09-12 12:52:18   ht37010
 * added encapsulation for device request handling
 *
 * /main/ms-d/17   2007-09-07 15:08:42   ht37010
 * improved device request handling
 *
 * /main/ms-d/16   2007-08-01 10:31:19   ht37010
 * improved handling if new device is attached before old device is detached during global resume
 *
 * /main/ms-d/15   2007-05-30 16:34:13   ht37010
 * added new static function prototypes for global port validation
 *
 * /main/ms-d/14   2006-12-20 14:41:02   wm36264
 * Access QMI command port directly without read and write threads
 *
 * /main/ms-d/13   2006-12-06 11:08:50   wm36264
 * Make buffer for vendor transfers smaller.
 *
 * /main/ms-d/12   2006-11-10 17:00:05   wm36264
 * Quinn seems to require an USB packet size with 64 byte boundary...
 * Very annoying to have to find that out by try and error!
 *
 * /main/ms-d/11   2006-11-10 12:41:54   wm36264
 * Abort pending calls in case of USB failure
 *
 * /main/ms-d/10   2006-11-08 18:30:55   wm36264
 * Adjust USB transfer sizes to module requirements (fix strange problems with data connections)
 *
 * /main/ms-d/9   2006-10-20 12:16:17   wm36264
 * The ndis irq pipe notifies us when there is qmi data available on the default pipe
 *
 * /main/ms-d/8   2006-10-18 12:33:56   wm36264
 * Several modifications regarding default pipe handling for qmi
 *
 * /main/ms-d/7   2006-10-12 16:52:38   wm36264
 * For a possible future selective suspend implementation it is much easier when there is only one pipe class
 *
 * /main/ms-d/6   2006-10-06 18:00:29   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:05   wm36264
 * Consider latest findings about QMI and NDIS handling
 *
 * /main/ms-d/4   2006-09-22 14:33:20   wm36264
 * Cosmetics mostly
 *
 * /main/ms-d/3   2006-09-21 17:41:47   wm36264
 * No special treatment for NDIS port at this level
 *
 * /main/ms-d/2   2006-09-21 17:05:37   wm36264
 * Prepared access to QMI interface
 *
 * /main/ms-d/1   2006-09-18 15:31:41   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
//
//////////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////////
//
// VirtualPort.h
//
// This file contains the definition of the class "CVirtualPort" which
// provides the functionality of the virtual COM port.
//
//////////////////////////////////////////////////////////////////////////////

#pragma once

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

#define DEFAULT_BUFFER_SIZE             0x2000
#define USB_TRANSFER_SIZE               2048

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

class CVirtualPort {
public:
  CVirtualPort(CUsbHandling* pUsbHandling, HC_DEVICE_TYPE DevType);
  ~CVirtualPort();
  BOOL                 Open(LPVOID pInstance);
  BOOL                 Close(LPVOID pInstance);
  BOOL                 GetDcb(DCB* pDst);
  BOOL                 SetDcb(DCB* pSrc);
  BOOL                 GetTimeouts(COMMTIMEOUTS* pDst);
  BOOL                 SetTimeouts(COMMTIMEOUTS* pSrc);
  BOOL                 GetWaitMask(LPVOID pInstance, PDWORD pdwWaitMask);
  BOOL                 SetWaitMask(LPVOID pInstance, DWORD dwWaitMask);
  BOOL                 WaitOnMask(LPVOID pInstance, PDWORD pdwWaitEvent);
  BOOL                 GetProperties(COMMPROP* pDst);
  BOOL                 SetQueueSize(SERIAL_QUEUE_SIZES* pQueueSize);
  BOOL                 GetComStat(COMSTAT* pDst);
  BOOL                 SetRts(BOOL fState);
  BOOL                 SetDtr(BOOL fState);
  BOOL                 SetBreak(BOOL fState);
  BOOL                 GetModemState(PDWORD pdwState);
  BOOL                 AbortWrite(void);
  BOOL                 AbortRead(void);
  BOOL                 ClearWrite(void);
  BOOL                 ClearRead(void);
  DWORD                ReadData(PBYTE pData, DWORD dwLen);
  DWORD                WriteData(PBYTE pData, DWORD dwLen);
  CUsbPipe*            GetBulkOutPipe(void) { return &m_BulkOutPipe; };
  CUsbPipe*            GetBulkInPipe(void) { return &m_BulkInPipe; };
  CUsbPipe*            GetIrqInPipe(void) { return &m_IrqInPipe; };
  void                 SetVirtualPortIndex(DWORD dwIndex) {m_dwDeviceIndex = dwIndex;};
  void                 SetUsbInterfaceNumber(BYTE bIfaceNum) { m_bUsbIfaceNumber = bIfaceNum; };
  void                 SetUsbPortCaps(BYTE bPortCaps) { m_bUsbPortCaps = bPortCaps; };
  void                 SetDefaultPipe(CUsbPipe* pDefaultPipe) { m_pDefaultPipe = pDefaultPipe; };
  HC_DEVICE_TYPE       GetDeviceType(void) { return m_DevType; };

  CUsbHandling*        GetUsbHandling(void) { return m_pUsbHandling; };
  BYTE                 GetUsbInterfaceNumber( void ) { return m_bUsbIfaceNumber; };

  DWORD                HandleDeviceRequest(PUSB_DEVICE_REQUEST pDevRequest);

  static void          InitSystemLock(void);
  static void          DeinitSystemLock(void);
  static void          LockSystem(void);
  static void          UnlockSystem(void);

  static BOOL          AddVirtualPort(CVirtualPort *virtPort);
  static BOOL          RemoveVirtualPort(CVirtualPort *virtPort);
  static BOOL          IsVirtualPortValid(CVirtualPort *virtPort);

  HANDLE               GetStreamHandle(void);
  void                 SetStreamHandle(HANDLE hStreamHandle);
  BOOL                 SetUsbHandling(CUsbHandling *pUsbHandling);

  BOOL                 EnsurePortClosed(void);

private:
  BOOL                 IsSerial(void) { return (m_DevType == HC_SERIAL); }
  BOOL                 IsPortOpen(void);
  BOOL                 ResetPipes(void);
  BOOL                 AbortPendingCalls();
  static DWORD WINAPI  ThreadReadData(LPVOID lpParameter);
  static DWORD WINAPI  ThreadWriteData(LPVOID lpParameter);
  static DWORD WINAPI  ThreadReadIrqData(LPVOID lpParameter);

  static CRITICAL_SECTION m_csSystemLock;
  static PointerArray  m_PortList;

  CRITICAL_SECTION     m_csLock;
  HC_DEVICE_TYPE       m_DevType;
  DWORD                m_dwDeviceIndex;
  CUsbHandling*        m_pUsbHandling;
  CUsbPipe*            m_pDefaultPipe;
  CUsbPipe             m_BulkOutPipe;
  CUsbPipe             m_BulkInPipe;
  CUsbPipe             m_IrqInPipe;
  BYTE                 m_bUsbIfaceNumber;
  BYTE                 m_bUsbPortCaps;
  BOOL                 m_fUsbOk;
  DWORD                m_dwOpenCount;
  DCB                  m_Dcb;
  COMMTIMEOUTS         m_Timeouts;
  CWaitCommInstance    m_WaitCommEvent;
  HANDLE               m_hThreadReadData;
  HANDLE               m_hThreadWriteData;
  HANDLE               m_hThreadReadIrqData;
  HANDLE               m_hCloseEvent;
  HANDLE               m_hCmdDataAvailableEvent;
  HANDLE               m_hStreamHandle;
  HANDLE               m_hLineStateValidEvent;
  HANDLE               m_hPortClosedEvent;
  CRingBuffer          m_ReadBuffer;
  CRingBuffer          m_WriteBuffer;
  BOOL                 m_fRing;
  BOOL                 m_fCts;
  BOOL                 m_fDsr;
  BOOL                 m_fCd;
  BOOL                 m_fRts;
  BOOL                 m_fDtr;
};

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

class CVPortInstance {
public:
  CVPortInstance(CVirtualPort* pVirtualPort) : m_pVirtualPort(pVirtualPort) {};
  ~CVPortInstance() {};
  BOOL                 Open(void) { return m_pVirtualPort->Open((LPVOID)this); };
  BOOL                 Close(void) { return m_pVirtualPort->Close((LPVOID)this); };
  BOOL                 GetDcb(DCB* pDst) { return m_pVirtualPort->GetDcb(pDst); };
  BOOL                 SetDcb(DCB* pSrc) { return m_pVirtualPort->SetDcb(pSrc); };
  BOOL                 GetTimeouts(COMMTIMEOUTS* pDst) { return m_pVirtualPort->GetTimeouts(pDst); };
  BOOL                 SetTimeouts(COMMTIMEOUTS* pSrc) { return m_pVirtualPort->SetTimeouts(pSrc); };
  BOOL                 GetWaitMask(PDWORD pdwWaitMask) { return m_pVirtualPort->GetWaitMask((LPVOID)this, pdwWaitMask); };
  BOOL                 SetWaitMask(DWORD dwWaitMask) { return m_pVirtualPort->SetWaitMask((LPVOID)this, dwWaitMask); };
  BOOL                 WaitOnMask(PDWORD pdwWaitEvent) { return m_pVirtualPort->WaitOnMask((LPVOID)this, pdwWaitEvent); };
  BOOL                 GetProperties(COMMPROP* pDst) { return m_pVirtualPort->GetProperties(pDst); };
  BOOL                 SetQueueSize(SERIAL_QUEUE_SIZES* pQueueSize) { return m_pVirtualPort->SetQueueSize(pQueueSize); };
  BOOL                 GetComStat(COMSTAT* pDst) { return m_pVirtualPort->GetComStat(pDst); };
  BOOL                 SetRts(BOOL fSate) { return m_pVirtualPort->SetRts(fSate); };
  BOOL                 SetDtr(BOOL fSate) { return m_pVirtualPort->SetDtr(fSate); };
  BOOL                 SetBreak(BOOL fState) { return m_pVirtualPort->SetBreak(fState); };
  BOOL                 GetModemState(PDWORD pdwState) { return m_pVirtualPort->GetModemState(pdwState); };
  BOOL                 AbortWrite(void) { return m_pVirtualPort->AbortWrite(); };
  BOOL                 AbortRead(void) { return m_pVirtualPort->AbortRead(); };
  BOOL                 ClearWrite(void) { return m_pVirtualPort->ClearWrite(); };
  BOOL                 ClearRead(void) { return m_pVirtualPort->ClearRead(); };
  DWORD                ReadData(PBYTE pData, DWORD dwLen) { return m_pVirtualPort->ReadData(pData, dwLen); };
  DWORD                WriteData(PBYTE pData, DWORD dwLen) { return m_pVirtualPort->WriteData(pData, dwLen); };

private:
  CVirtualPort*        m_pVirtualPort;
};

