/*****************************************************************************
 * Copyright (C) Cinterion Wireless Modules GmbH
 *****************************************************************************
 * Project: Quinn-CE-USB-Driver
 *****************************************************************************
 * Author : Siemens AG Berlin COM WM RD SW
 *****************************************************************************
 * $Workfile: Y:/z_ms-d/src/working/Quinn/HcUsbDrv/UsbHandling.h $
 * $Revision: /main/ms-d/55 $
 * $Date: 2014-06-13 11:47:40 $
 * $Author: pmackent $
 *****************************************************************************
 * Target:
 *  Microsoft Windows CE 5.0
 *****************************************************************************
 * Description:
 *  Quinn-USB-Driver: Virtual COM port port class CUsbHandling
 *  definition
 *****************************************************************************
 *
 * $Log: Y:/z_ms-d/src/working/Quinn/HcUsbDrv/UsbHandling.h$ 
 * 
 * /main/ms-d/55   2014-06-13 11:47:40   pmackent 
 * Corrected USB interface for PLS8 Rel2 / ALS3
 *
 * /main/ms-d/54   2014-04-03 13:45:53   mwohler
 * Enumerate multiple rmnet interfaces properly.
Added support for PLSx Rel. 2.

 *
 * /main/ms-d/53   2013-11-15 11:43:04   pmackent
 * Added handling of Metropolis
 *
 * /main/ms-d/52   2013-06-19 17:37:29   thinze
 * added device request NTF_NETWORK_CONNECTION
 *
 * /main/ms-d/51   2013-05-21 15:11:54   pmackent
 * Added USB ID for BGS5
 *
 * /main/ms-d/50   2012-11-19 15:23:26   pmackent
 * Introduce EHS5
 *
 * /main/ms-d/49   2012-07-18 15:27:28   thinze
 * added CDC-ECM support
 *
 * /main/ms-d/48   2012-07-16 13:08:07   pmackent
 * Added AH6 product ID
 *
 * /main/ms-d/47   2011-02-14 14:11:27   ctna0152
 * fix for IPIS100069778
 *
 * /main/ms-d/46   2011-02-02 10:27:53   ctna0450
 * Removed unused USB-Reset workaround for Uranus USB problems
 *
 * /main/ms-d/45   2010-12-14 15:15:23   ctna0152
 * added reset handling via registry keys
 *
 * /main/ms-d/44   2010-12-13 14:22:33   ctna0152
 * added USB reset handling
 *
 * /main/ms-d/43   2010-11-15 17:51:14   ctna0152
 * added workaround "PAUSE_ON_RESUME" for IPIS100068602
 *
 * /main/ms-d/42   2010-08-17 14:40:09   ctna0450
 * Use compiler flag for "attach before detach" problem to reenable capability for more than one instance handling
 *
 * /main/ms-d/41   2010-08-10 14:02:57   ctna0152
 * added EU3-E, EU3-P and PH8 (CDC-ACM)
 *
 * /main/ms-d/40   2010-08-09 11:33:14   ctna0450
 * Added manual device index assignment
 *
 * /main/ms-d/39   2010-08-04 13:54:42   ctna0450
 * Unified enumeration process
 *
 * /main/ms-d/38   2009-02-18 11:49:38   ctna0256
 * Set copyright text
 *
 * /main/ms-d/37   2008-08-20 11:39:16   ctna0450
 * Prepared for new disclaimer handling
 *
 * /main/ms-d/36   2008-06-19 14:25:01   ht37010
 * added Cinterion Vendor ID and MC75i Product ID
 *
 * /main/ms-d/35   2008-05-16 14:46:39   ht37010
 * added MC75i product ID
 *
 * /main/ms-d/34   2007-09-12 12:52:17   ht37010
 * added encapsulation for device request handling
 *
 * /main/ms-d/33   2007-09-07 15:08:41   ht37010
 * improved device request handling
 *
 * /main/ms-d/32   2007-08-28 12:52:10   ht37010
 * added encapsulation for one-for-all driver
 *
 * /main/ms-d/31   2007-08-14 12:43:41   ht37010
 * added support for all modules
 *
 * /main/ms-d/30   2007-08-01 13:18:55   ht37010
 * added HC28
 *
 * /main/ms-d/29   2007-08-01 10:31:15   ht37010
 * improved handling if new device is attached before old device is detached during global resume
 *
 * /main/ms-d/28   2007-07-17 10:12:26   ht37010
 * removed syncblock (critical section) in IsUSBAttached() to avoid dead lock if vport->open() is called while usb->detach() is running
 *
 * /main/ms-d/27   2007-06-01 20:39:41   ht37010
 * added synchronization handling of system function calls for USB
 *
 * /main/ms-d/26   2007-02-16 16:37:49   wm36264
 * Adapted selective suspend/resume notification to MS confirmend interface.
 * Untested and still deactivated by default!
 *
 * /main/ms-d/25   2007-02-02 15:20:27   wm36264
 * Block USB attach while detach is in progress
 *
 * /main/ms-d/24   2007-01-29 16:05:14   wm36264
 * Clearyfied names of some USB defines
 *
 * /main/ms-d/23   2006-12-14 12:17:46   wm36264
 * Deactivate selective suspend for now
 *
 * /main/ms-d/22   2006-12-14 12:15:50   wm36264
 * Prepared resume notification
 *
 * /main/ms-d/21   2006-11-15 11:19:47   wm36264
 * Fixed c&p bug with HC25 product id
 *
 * /main/ms-d/20   2006-11-09 12:22:18   wm36264
 * Evaluate connection speed change notification
 *
 * /main/ms-d/19   2006-11-08 18:30:54   wm36264
 * Adjust USB transfer sizes to module requirements (fix strange problems with data connections)
 *
 * /main/ms-d/18   2006-11-03 17:07:15   wm36264
 * Continued to prepare selective suspend handling
 *
 * /main/ms-d/17   2006-11-02 12:08:03   wm36264
 * Support more than one Siemens product id at the same time
 *
 * /main/ms-d/16   2006-10-31 15:52:33   wm36264
 * Added HC25 product id
 *
 * /main/ms-d/15   2006-10-23 10:43:27   wm36264
 * Use global define for transfers on default pipe
 *
 * /main/ms-d/14   2006-10-20 13:38:09   wm36264
 * Addapted to latest USB modifications in module
 *
 * /main/ms-d/13   2006-10-20 12:16:20   wm36264
 * The ndis irq pipe notifies us when there is qmi data available on the default pipe
 *
 * /main/ms-d/12   2006-10-18 16:35:42   wm36264
 * Removed obsolete Qualcom product ids
 *
 * /main/ms-d/11   2006-10-18 12:34:01   wm36264
 * Several modifications regarding default pipe handling for qmi
 *
 * /main/ms-d/10   2006-10-12 16:52:31   wm36264
 * For a possible future selective suspend implementation it is much easier when there is only one pipe class
 *
 * /main/ms-d/9   2006-10-11 11:17:26   wm36264
 * Moved typedef to simplify external include
 *
 * /main/ms-d/8   2006-10-10 15:28:31   wm36264
 * Use correct request types for encapsulated QMI commands
 *
 * /main/ms-d/7   2006-10-10 15:14:28   wm36264
 * Prepared usage of ndis interface number
 *
 * /main/ms-d/6   2006-10-09 15:24:08   wm36264
 * Fixed USB detach problems
 *
 * /main/ms-d/5   2006-10-06 18:00:20   wm36264
 * Make virtual ports fully instancable and use different device names for serial, ndis and qmi devices
 *
 * /main/ms-d/4   2006-09-29 15:33:32   wm36264
 * Consider latest findings about QMI and NDIS handling
 *
 * /main/ms-d/3   2006-09-22 14:33:34   wm36264
 * Cosmetics mostly
 *
 * /main/ms-d/2   2006-09-21 17:05:55   wm36264
 * Prepared access to QMI interface
 *
 * /main/ms-d/1   2006-09-18 15:31:33   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
//
//////////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////////
//
// UsbHandling.h
//
// This file contains the definition of the class "CUsbHandling" which
// implements the access to the USB interface.
//
//////////////////////////////////////////////////////////////////////////////

#pragma once

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

#define INIT_INTERFACE_TIMEOUT              2000

#define DEFAULT_PIPE_TIMEOUT                2000

#define MAX_VIRTUAL_PORTS                   32

#define HCUSBDRV_CLASS_NAME                 TEXT("HCModules")
#define HCUSBDRV_CLIENT_REGKEY              TEXT("Drivers\\USB\\ClientDrivers\\Cinterion\\") HCUSBDRV_CLASS_NAME
#define HCUSBDRV_CLIENT_REGKEY_COMPATIBLITY TEXT("Drivers\\USB\\ClientDrivers\\Siemens\\") HCUSBDRV_CLASS_NAME

#define MAX_SUPPORTED_VENDOR_IDS            2
#define SIEMENS_VENDOR_ID                   0x0681
#define CINTERION_VENDOR_ID                 0x1E2D

#define SIEMENS_HC15_PRODUCT_ID             0x003E
#define SIEMENS_HC25_PRODUCT_ID             0x0040
#define SIEMENS_HC28_PRODUCT_ID             0x004A

#define SIEMENS_MC75_PRODUCT_ID             0x0034
#define CINTERION_MC75i_PRODUCT_ID          0x004F

#define CINTERION_EU3_E_PRODUCT_ID          0x0051
#define CINTERION_EU3_P_PRODUCT_ID          0x0052
#define CINTERION_PH8_PRODUCT_ID            0x0053
#define CINTERION_PH8_CDCACM_PRODUCT_ID     0x0054
#define CINTERION_AH6_PRODUCT_ID            0x0055
#define CINTERION_EHS5_PRODUCT_ID           0x0058 //EHS8 use the same ID
#define CINTERION_BGS5_PRODUCT_ID           0x0059
#define CINTERION_ALS1_PRODUCT_ID           0x0060
#define CINTERION_ALS3_PRODUCT_ID           0x0061
#define CINTERION_PDS5_PRODUCT_ID           0x005A
#define CINTERION_ELS6_PRODUCT_ID           0x005B //PLS62 use the same ID



#define USBSER_DEVICE_SUBCLASS_NONE         0x00  // No device subclass

#define USBSER_DEVICE_PROTOCOL_NONE         0x00  // No device protocol

#define USBSER_INTERFACE_CLASS_COMM_CTRL    0x02  // "Communication Control Interface Class"
#define USBSER_INTERFACE_CLASS_COMM_DATA    0x0A  // "Communication Data Interface Class "

#define USBSER_INTERFACE_SUBCLASS_NONE      0x00  // No interface subclass
#define USBSER_INTERFACE_SUBCLASS_ACM       0x02  // "Abstract Control Model"
#define USBSER_INTERFACE_SUBCLASS_ECM       0x06  // "Ethernet Control Model"

#define USBSER_INTERFACE_PROTOCOL_NONE      0x00  // No interface protocol
#define USBSER_INTERFACE_PROTOCOL_HAYES_AT  0x01  // "Common AT commands (Hayes compatible)"

#define HCUSBDRV_DRIVER_SETTINGS            sizeof(USB_DRIVER_SETTINGS),  \
                                            CINTERION_VENDOR_ID,          \
                                            USB_NO_INFO,                  \
                                            USB_NO_INFO,                  \
                                            USB_NO_INFO,                  \
                                            USB_NO_INFO,                  \
                                            USB_NO_INFO,                  \
                                            USB_NO_INFO,                  \
                                            USB_NO_INFO,                  \
                                            USB_NO_INFO

#define USB_SUSPEND_DELAY_NAME              TEXT("SuspendDelay")
#define USB_PORT_ASSIGNMENT_NAME            TEXT("PortAssignment")
#define USB_PORT_INDEXES_NAME               TEXT("PortIndexes")

#ifdef USE_WA_RETRY_ON_HOSTFN_FAIL
  #define USB_RETRY_DELAY_NAME              TEXT("RetryDelay")
  #define USB_RETRY_COUNT_NAME              TEXT("RetryCount")
#endif

#ifdef USE_WA_PAUSE_ON_RESUME
  #define USB_PAUSE_ON_RESUME_DELAY         TEXT("ResumeDelay")
#endif

#define USB_DEF_SUSPEND_DELAY               INFINITE

#ifdef USE_WA_PAUSE_ON_RESUME
  #define USB_DEF_RESUME_DELAY              100
#endif

#define REQ_SEND_ENCAPSULATED_CMD           0x00
#define REQ_GET_ENCAPSULATED_RSP            0x01
#define REQ_SET_CONTROL_LINE_STATE          0x22
#define REQ_SEND_BREAK                      0x23

#define NTF_NETWORK_CONNECTION              0x00
#define NTF_RESPONSE_AVAILABLE              0x01
#define NTF_SERIAL_STATE                    0x20
#define NTF_CONNECTION_SPEED_CHG            0x2A

#define LINE_STATE_DTR_MASK                 0x01
#define LINE_STATE_RTS_MASK                 0x02
#define LINE_STATE_RING_MASK                0x08
#define LINE_STATE_DSR_MASK                 0x02
#define LINE_STATE_CD_MASK                  0x01

#define CS_INTERFACE                        0x24

#define DESC_SUBTYPE_CALL_MGT               0x01
#define DESC_SUBTYPE_ABSTRACT_CTRL_MGT      0x02
#define DESC_SUBTYPE_UNION                  0x06

#define CAPS_SEND_BREAK                     0x04

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

typedef struct _HC_ENUM_INFO {
  WORD             wProductId;                  // The product id of the module (0 for default)
  WORD             wNumOfPorts;                 // The number of ports to be enumerated
  HC_DEVICE_TYPE   Ports[HC_MAX_USB_IFACES];    // Array containing the existing ports
  BYTE             Indexes[HC_MAX_USB_IFACES];  // Array containing the desired port indexes
} HC_ENUM_INFO, *PHC_ENUM_INFO;

const HC_ENUM_INFO ProductIfaces[] = {
  { 0,                                3,  { HC_SERIAL,    HC_NDIS,  HC_SERIAL                                    },
                                          {         2,          1,          1                                    }},
  { SIEMENS_MC75_PRODUCT_ID,          1,  { HC_SERIAL                                                            },
                                          {         1                                                            }},
  { CINTERION_MC75i_PRODUCT_ID,       1,  { HC_SERIAL                                                            },
                                          {         1                                                            }},
  { CINTERION_EU3_E_PRODUCT_ID,       3,  { HC_SERIAL,  HC_SERIAL,  HC_SERIAL                                    },
                                          {         3,          2,          1                                    }},
  { CINTERION_EU3_P_PRODUCT_ID,       3,  { HC_SERIAL,  HC_SERIAL,  HC_SERIAL                                    },
                                          {         3,          2,          1                                    }},
  { CINTERION_PH8_PRODUCT_ID,         5,  { HC_SERIAL,  HC_SERIAL,  HC_SERIAL,  HC_SERIAL,    HC_NDIS            },
                                          {         4,          3,          2,          1,          1            }},
  { CINTERION_PH8_CDCACM_PRODUCT_ID,  1,  { HC_SERIAL                                                            },
                                          {         1                                                            }},
  { CINTERION_AH6_PRODUCT_ID,         5,  { HC_SERIAL,  HC_SERIAL,  HC_SERIAL,  HC_SERIAL,    HC_NDIS            },
                                          {         2,          3,          4,          1,          1            }},
  { CINTERION_EHS5_PRODUCT_ID,        6,  { HC_SERIAL,  HC_SERIAL,  HC_SERIAL,  HC_SERIAL,  HC_SERIAL,  HC_SERIAL},
                                          {         1,          3,          4,          2,          5,          6}},
  { CINTERION_PDS5_PRODUCT_ID,		  6,  { HC_SERIAL,	HC_SERIAL,	HC_SERIAL,	HC_SERIAL,	HC_SERIAL,	HC_SERIAL},
                                          { 		1,			3,			4,			2,			5,			6}},
  { CINTERION_BGS5_PRODUCT_ID,        5,  { HC_SERIAL,  HC_SERIAL,  HC_SERIAL,  HC_SERIAL,  HC_SERIAL            },
                                          {         1,          3,          4,          2,          5            }},
  { CINTERION_ALS1_PRODUCT_ID,        6,  { HC_SERIAL,  HC_SERIAL,  HC_SERIAL,  HC_SERIAL,    HC_NDIS,    HC_NDIS},
                                          {         4,          2,          1,          3,          1,          2}},
  { CINTERION_ELS6_PRODUCT_ID,		  7,  { HC_SERIAL,	HC_SERIAL,	HC_SERIAL,	HC_SERIAL,	HC_SERIAL,    HC_NDIS,	HC_NDIS  },
     									  { 		1,			2,			3,			4,			5,          1,		  2  }},
  { CINTERION_ALS3_PRODUCT_ID,        7,  { HC_SERIAL,  HC_SERIAL,  HC_SERIAL,  HC_SERIAL,  HC_SERIAL,    HC_NDIS,  HC_NDIS  },
                                          {         1,          2,          3,          4,          5,          1,        2  }}
};

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

class CVirtualPort;

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

class CUsbHandling {
public:
  CUsbHandling();
  ~CUsbHandling();
  BOOL                 USBDeviceAttach(USB_HANDLE Device, LPCUSB_FUNCS Funcs, DWORD dwClientInfo);
  BOOL                 USBDeviceDetach(void);

  BOOL                 IsUSBAttached(void) { return m_fUsbAttached; };
  BOOL                 InitUsbInterface(CVirtualPort* pVirtualPort);
  BOOL                 AddOpenedPort(void);
  BOOL                 RemoveOpenedPort(void);
  BOOL                 DeviceResumed(void) { return m_SelectiveSuspend.DeviceResumed(); };
  BOOL                 DeviceSuspended(void) { return m_SelectiveSuspend.DeviceSuspended(); };

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

  DWORD                DispatchDeviceRequest(PUSB_DEVICE_REQUEST pDevRequest);
  BOOL                 AddVirtualport(CVirtualPort *pVirtualPort);
  BOOL                 RemoveVirtualport(CVirtualPort *pVirtualPort);

private:
  typedef struct _HC_DEVICE_INFO {
    LPCUSB_INTERFACE  pInterface;
    HC_DEVICE_TYPE    DevType;
    BYTE              bDataIndex;
    BYTE              bDeviceIndex;
  } HC_DEVICE_INFO, *PHC_DEVICE_INFO;

  BOOL                 ParseDescriptors(DWORD dwClientInfo);
  BOOL                 ActivateDevices(PHC_DEVICE_INFO pDevInfo, BYTE bDevInfoSize, DWORD dwClientInfo);
  BOOL                 ActivatePortDevice(HC_DEVICE_TYPE DevType, DWORD dwClientInfo, DWORD dwIndex);
  BOOL                 DeactivateDevices(void);
  BOOL                 AddStreamDevice(HANDLE hStreamDevice);
  BOOL                 EnsurePortsClosed(void);
  HC_DEVICE_TYPE       GetDeviceType(WORD wProductId, BYTE bIfaceNum);
  BYTE                 GetPortIndex(WORD wProductId, BYTE bIfaceNum);
  BYTE                 GetInterfaceCaps(LPCUSB_INTERFACE pInterface);
  BYTE                 GetDataInterface(LPCUSB_INTERFACE pInterface);

  CVirtualPort            *m_pVirtualPorts[MAX_VIRTUAL_PORTS];
  CRITICAL_SECTION         m_csDeviceRequestLock;

  static CRITICAL_SECTION  m_csSystemLock;
  CRITICAL_SECTION         m_csLock;
  BOOL                     m_fUsbAttached;
  USB_HANDLE               m_hDevice;
  LPCUSB_FUNCS             m_pFuncs;
  HANDLE                   m_hStreamDevices[MAX_VIRTUAL_PORTS];
  CUsbPipe                 m_DefaultPipe;
  HANDLE                   m_hIfaceReadyEvent;
  HANDLE                   m_hPortsClosedEvent;
  LPCUSB_ENDPOINT          m_pEndointNdisIrqPipe;
  LPCUSB_INTERFACE         m_pCurrUsbIface;
  LPCUSB_INTERFACE         m_pCurrCdcCtrlIface;
  LPCUSB_INTERFACE         m_pCurrCdcDataIface;
  CVirtualPort            *m_pCurrVirtPort;
  BYTE                     m_bCurrInterfaceNum;
  DWORD                    m_dwCurrVirtualPortIndex;
  BYTE                     m_bCurrPortCaps;
  DWORD                    m_dwOpenPorts;
  CSelectiveSuspend        m_SelectiveSuspend;
  HANDLE                   m_hDetachEvent;
};

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

typedef struct _HCUSBDRV_CONTEXT {
  // We use a Signature since we must read our context pointer out of the registry
  ULONG          Sig;
  // The USB handling class instance
  CUsbHandling   UsbHandling;
} HCUSBDRV_CONTEXT, *PHCUSBDRV_CONTEXT;

// Is the pointer a valid HCUSBDRV_CONTEXT
#define IS_VALID_CONTEXT(p)    (p && (HCUSBDRV_SIG == p->Sig))

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

