/*****************************************************************************
 * Copyright (C) Gemalto M2M GmbH
 *****************************************************************************
 * Project: IMC-RIL-Driver
 *****************************************************************************
 * Author : Wireless Modules RD SW A2
 *****************************************************************************
 * $Workfile: Y:/z_ms-d/src/working/Quinn/RilDrv/rilhand.cpp $
 * $Revision: /main/ms-d/234 $
 *     $Date: 2014-06-19 16:51:06 $
 *   $Author: pmackent $
 *****************************************************************************
 * Target:
 *  Microsoft Windows Mobile 5.0
 *****************************************************************************
 * Description:
 *  Gemalto IMC RIL
 *****************************************************************************
 *
 * $Log: Y:/z_ms-d/src/working/Quinn/RilDrv/rilhand.cpp$ 
 * 
 * /main/ms-d/234   2014-06-19 16:51:06   pmackent 
 * Fix exception in RIL_GetCurrentSystemType() (IPIS100097887)
 *
 * /main/ms-d/233   2014-05-26 16:30:11   pmackent
 * Correction for incorrectly reported system type while module is in CDMA mode and in no-coverage area (IPIS100097887)
 *
 * /main/ms-d/232   2014-02-13 09:18:46   pmackent
 * Check for initial "SIM full" status
 *
 * /main/ms-d/231   2014-01-22 14:03:42   pmackent
 * Remove Prefast warning
 *
 * /main/ms-d/230   2014-01-22 13:52:22   pmackent
 * Introduce COPS before PIN for AHS3
 *
 * /main/ms-d/229   2013-12-02 14:25:53   pmackent
 * Set signal strength thersholds via registry
 *
 * /main/ms-d/228   2013-11-29 12:43:31   pmackent
 * Prepare for DTMF detection (possible new PHS8 feature)
 *
 * /main/ms-d/227   2013-10-24 13:41:30   pmackent
 * Preparation to support Windows Embedded Compact 2013
 *
 * /main/ms-d/226   2013-10-01 14:15:16   pmackent
 * Handle case of failing AT^SMONI on EHS5
 *
 * /main/ms-d/225   2013-09-25 15:21:45   pmackent
 * New methods for signal strength display in 3G networks (IPIS100091577)
 *
 * /main/ms-d/224   2013-09-13 09:27:21   pmackent
 * Cell Broadcast for CDMA (IPIS100091379)
 *
 * /main/ms-d/223   2013-08-21 13:17:57   pmackent
 * Sprint: warning for roaming costs (IPIS100090678)
 *
 * /main/ms-d/222   2013-06-27 16:00:19   pmackent
 * Adaptions for EHS5 Rel1->Rel2 update
 *
 * /main/ms-d/221   2013-06-17 08:59:18   pmackent
 * Prevent deadlock situation cause by AT+CCLK (IPIS1000881019)
 *
 * /main/ms-d/220   2013-06-10 14:36:21   pmackent
 * CDMA: Show 1xRTT icon in case suspen/resume happens during voice activity (IPIS100087532)
 *
 * /main/ms-d/219   2013-05-24 13:57:56   pmackent
 * Module changes to multimode after AT+COPS=1
 *
 * /main/ms-d/218   2013-05-17 14:59:08   pmackent
 * Make technology switch thread-safe
 *
 * /main/ms-d/217   2013-05-14 14:35:06   pmackent
 * Option to activate OMALOG in Sprint (IPIS100087489)
 *
 * /main/ms-d/216   2013-05-13 15:23:56   pmackent
 * Store NITZ DST settings (IPIS100087449)
 *
 * /main/ms-d/215   2013-05-13 14:12:26   pmackent
 * Optional alternative handling of AT+CDV response (IPIS100087446)
 *
 * /main/ms-d/214   2013-05-10 15:35:23   pmackent
 * No time synchorization in CDMA mode
 *
 * /main/ms-d/213   2013-04-26 16:15:10   pmackent
 * Missing ^SCKS URC in PXS8
 *
 * /main/ms-d/212   2013-04-24 11:44:46   pmackent
 * New CDMA/CNMI setting and CDMA/CLCC workaround
 *
 * /main/ms-d/211   2013-04-22 16:12:07   pmackent
 * Work on workarounds for AT+COPS/<AcT> and AT^SJDL/ATE
 *
 * /main/ms-d/210   2013-04-19 09:11:38   pmackent
 * Allow keyword "all" for "ForceHsdpaIndication" key
 *
 * /main/ms-d/209   2013-04-18 13:24:07   pmackent
 * Registry key to force HSDPA indication
 *
 * /main/ms-d/208   2013-04-12 09:21:57   pmackent
 * Adaptions for PXS8 2.910
 *
 * /main/ms-d/207   2013-04-05 09:53:45   pmackent
 * Finish EHS5 Java midlet update
 * Add RHA-API for bootloader pin on EHS5
 *
 * /main/ms-d/206   2013-03-25 14:43:11   pmackent
 * Small adaptions for PXS8 multimode
 *
 * /main/ms-d/205   2013-03-21 14:40:53   pmackent
 * Don't store T/P dial modifiers
 *
 * /main/ms-d/204   2013-03-13 15:04:17   pmackent
 * Additional debug traces for signal critical error.
 *
 * /main/ms-d/203   2013-03-05 11:33:46   pmackent
 * Handle ^SYSSTART URC for EHS5 Rel2
 *
 * /main/ms-d/202   2013-03-04 13:19:53   pmackent
 * Adaptions for EHS5 1.300
 *
 * /main/ms-d/201   2013-02-26 15:07:52   pmackent
 * Adaptions for EHS5 1.290
 *
 * /main/ms-d/200   2013-01-07 11:27:08   pmackent
 * Added missing initialization of a variable
 *
 * /main/ms-d/199   2013-01-07 10:14:45   pmackent
 * Workaround for exit in AT+CPMS in EHS5
 *
 * /main/ms-d/198   2012-12-13 10:09:49   pmackent
 * Removed constant from if-clause
 *
 * /main/ms-d/197   2012-12-13 09:26:04   pmackent
 * Handling of Sprint variant of AT+CSQ
 *
 * /main/ms-d/196   2012-12-12 15:24:23   pmackent
 * Workarounds for bugs in PXS8 2.821
 *
 * /main/ms-d/195   2012-11-23 16:54:40   pmackent
 * Additional adaptions for EHS5
 *
 * /main/ms-d/194   2012-11-22 10:34:39   pmackent
 * Workaround: no AT+GMM in EHS5, no AT+CGMM in PXS8 (CDMA)
 *
 * /main/ms-d/193   2012-11-21 13:29:58   pmackent
 * Basic support of EHS5 Rel2
 *
 * /main/ms-d/192   2012-11-19 15:29:06   pmackent
 * No AT+CSQ in D3 is now optional
 *
 * /main/ms-d/191   2012-11-15 11:46:47   pmackent
 * Avoid sending AT+CSQ in D3 power state (IPIS100083487)
 *
 * /main/ms-d/190   2012-11-13 13:53:02   pmackent
 * New option: reser of acquisition database (IPIS100083325)
 *
 * /main/ms-d/189   2012-11-01 15:54:38   pmackent
 * Workaround for AT+CSQ problems with PXS8
 *
 * /main/ms-d/188   2012-10-31 12:09:39   pmackent
 * Moce initialization of temperture warning to early RIL initialization
 *
 * /main/ms-d/187   2012-10-22 11:21:14   pmackent
 * Workaround for from NITZ indication in CDMA
 *
 * /main/ms-d/186   2012-10-17 15:22:59   pmackent
 * Fix for missing NITZ/CCLK in CDMA mode (IPIS100082923)
 *
 * /main/ms-d/185   2012-09-25 10:26:29   pmackent
 * Workaround for double CDMA activation URC
 *
 * /main/ms-d/184   2012-09-14 16:32:17   pmackent
 * Workaround for missing +CIEV: simstatus,5 URC (IPIS100082280)
 *
 * /main/ms-d/183   2012-08-29 14:35:48   pmackent
 * Workaround for COPS changes SCFG bug
 *
 * /main/ms-d/182   2012-08-13 11:03:53   pmackent
 * Comply to CE6 code analyzer requirements
 *
 * /main/ms-d/181   2012-07-02 11:34:56   pmackent
 * Stop filtering GPRS registration notifications
 *
 * /main/ms-d/180   2012-06-07 13:58:59   pmackent
 * Adaptions for multimode
 * Workaround for CREG=0 bug in PXS8
 *
 * /main/ms-d/179   2012-06-05 11:29:39   pmackent
 * Avoid some SIM initializations while registered to CDMA
 *
 * /main/ms-d/178   2012-04-19 08:13:14   ctna0256
 * Don't use AT+CMUT? outside active voice call (IPIS100078740)
 *
 * /main/ms-d/177   2012-04-18 13:46:24   ctna0256
 * Introducing PVS8
 * Implementing CDMA-SMS
 * Various CDMA enhancements
 *
 * /main/ms-d/176   2012-02-22 13:27:09   ctna0256
 * Encapsulate use of Intel AT command set
 *
 * /main/ms-d/175   2012-02-10 12:59:30   ctna0256
 * Store Idle Mode Status in registry (IPIS100077395)
 *
 * /main/ms-d/174   2012-02-09 16:44:09   ctna0256
 * Check for missed SMS with AT+CRSM on EHS5, small bug fixes
 *
 * /main/ms-d/173   2012-02-03 15:07:30   ctna0256
 * Move URC parsing functions in separate file
 *
 * /main/ms-d/172   2012-02-02 17:03:54   ctna0256
 * FD phonebook workaround and NITZ URCs for Intel platform
 *
 * /main/ms-d/171   2012-01-31 16:38:53   ctna0256
 * Added support for EHS5
 *
 * /main/ms-d/170   2012-01-24 10:26:16   ctna0256
 * Small adaptions for CDMA
 *
 * /main/ms-d/169   2012-01-20 13:20:38   ctna0256
 * Better handling of SAT Idle Mode Text in case of booting the device (IPIS100077101)
 *
 * /main/ms-d/168   2012-01-17 10:22:29   ctna0256
 * Workaround for wrong indication of "+CIEV: psinfo,6" (IPIS100076880)
 *
 * /main/ms-d/167   2012-01-12 15:22:48   ctna0256
 * Some basic CDMA adaptions
 *
 * /main/ms-d/166   2012-01-05 14:56:39   ctna0256
 * New RHA-API for CDMA/UMTS technology switch
 *
 * /main/ms-d/165   2012-01-05 10:26:49   ctna0256
 * Save PIN2 because of problem with AT+CLCK="FD" in PH8 Rel2 (IPIS100076746)
 *
 * /main/ms-d/164   2012-01-04 15:37:00   ctna0256
 * Outsource XML configuration to external application.
 * Improve CDMA configuration mode.
 *
 * /main/ms-d/163   2012-01-03 15:46:47   ctna0256
 * Introduce PXS8
 *
 * /main/ms-d/162   2011-10-17 11:34:37   ctna0256
 * Workaround for restart on exit and AT+CPIN? timing issues of PH8 Rel2
 *
 * /main/ms-d/161   2011-09-26 13:35:03   ctna0256
 * Comply with CE6 warning level 4
 *
 * /main/ms-d/160   2011-07-22 11:28:59   ctna0256
 * Filter out "searching" extended notification (IPIS100073242)
 *
 * /main/ms-d/159   2011-07-20 13:01:46   ctna0256
 * Introduce RIL_NOTIFY_DEVSPECIFIC_NETWORK_REJECT_CAUSE and prevent multiple notifications (IPIS100073123)
 *
 * /main/ms-d/158   2011-07-19 11:37:46   ctna0256
 * Change default for DST for PTCRB approval (IPIS100073836)
 *
 * /main/ms-d/157   2011-07-07 13:14:23   ctna0256
 * Add polling mechanism for advanced reg status (IPIS100073242)
 *
 * /main/ms-d/156   2011-06-17 10:41:09   ctna0256
 * New API for extended registration status (IPIS100073242)
 *
 * /main/ms-d/155   2011-06-06 13:54:41   ctna0256
 * New registry key for URC indication methods (IPIS100073124)
 *
 * /main/ms-d/154   2011-05-30 10:11:46   ctna0256
 * Avoid SLCC on PH8 Rel1
 *
 * /main/ms-d/153   2011-05-30 09:36:14   ctna0256
 * Ignore wrong CREG:0 after CREG:3 (IPIS100073002)
 *
 * /main/ms-d/152   2011-03-21 09:43:46   ctna0256
 * Use UTC for time synchronization
 *
 * /main/ms-d/151   2011-03-17 10:07:46   ctna0256
 * Abort dial attempt for emergency calls after timeout (IPIS100070746)
 *
 * /main/ms-d/150   2011-03-09 14:24:50   ctna0256
 * Run code analysis on Windows CE7
 *
 * /main/ms-d/149   2011-02-28 09:19:26   ctna0256
 * Reset SAT Idle Mode Text on start (IPIS100070301)
 *
 * /main/ms-d/148   2011-02-15 15:17:15   ctna0256
 * Merge SCKS-WA registry key from Psion
 *
 * /main/ms-d/147   2011-02-02 10:58:25   ctna0256
 * Earlier CSQ notifications
 *
 * /main/ms-d/146   2010-12-22 14:31:24   ctna0256
 * No auto-reboot after emergency shutdown
 *
 * /main/ms-d/145   2010-12-15 10:44:05   ctna0256
 * Performed lint check
 *
 * /main/ms-d/144   2010-11-18 13:32:10   ctna0256
 * Use registry key for simstatus timeout
 *
 * /main/ms-d/143   2010-11-05 10:50:10   ctna0256
 * Better handling of "radio off" in SIM commands.
 *
 * /main/ms-d/142   2010-10-26 11:01:11   ctna0256
 * Introducing new notification for SIM initialization (IPIS100068246)
 *
 * /main/ms-d/141   2010-10-11 16:30:40   ctna0256
 * Add setting of PDU mode
 *
 * /main/ms-d/140   2010-09-21 13:12:48   ctna0256
 * No phonebook access after enabling PIN on PH8 customer sample
 *
 * /main/ms-d/139   2010-09-03 10:59:36   ctna0256
 * Increase checkpoit init
 *
 * /main/ms-d/138   2010-08-18 10:23:16   ctna0450
 * Added Telstra Home-Net workaround
 *
 * /main/ms-d/137   2010-07-22 14:44:54   ctna0256
 * Allow setting of default behaviour for incoming text messages
 *
 * /main/ms-d/136   2010-07-21 09:14:53   ctna0256
 * No audio for CSD dialing option
 *
 * /main/ms-d/135   2010-07-14 10:40:48   ctna0256
 * Preparation: CCUG and ACM may not be supported in PH8
 *
 * /main/ms-d/134   2010-07-06 10:00:34   ctna0256
 * Handle case of data only SIM
 *
 * /main/ms-d/133   2010-07-02 15:58:40   ctna0256
 * Introduce SAIC-settings and modified SNFO for PH8
 *
 * /main/ms-d/132   2010-04-30 15:29:11   ctna0256
 * Automatically switch to 2G for CSD connections (IPIS100064182)
 *
 * /main/ms-d/131   2010-03-05 12:54:53   ctna0256
 * Set correct last COPS mode for automatic network reistration during initialization.
 *
 * /main/ms-d/130   2010-02-17 14:26:55   ctna0256
 * GetRegistrySZ() might return TRUE, even on error (IPIS100062294)
 *
 * /main/ms-d/129   2010-02-03 10:51:15   ctna0256
 * Introduction of WinCE6 support
 *
 * /main/ms-d/128   2010-01-20 12:03:34   ctna0256
 * Send double audio mode change after every use of SNFI outside of voice calls (IPIS100061295)
 *
 * /main/ms-d/127   2010-01-06 14:16:53   ctna0256
 * Additional audio mode changes during initialisation (IPIS100061295)
 *
 * /main/ms-d/126   2009-11-19 08:20:45   ctna0256
 * Alternative COPS1 workaround (IPIS100059385)
 *
 * /main/ms-d/125   2009-10-07 09:22:20   ctna0256
 * Introduce no-operation command queue
 * Support 2nd alpha identifier in SAT setup call (IPIS100055375)
 *
 * /main/ms-d/124   2009-09-28 12:11:46   ctna0256
 * Use no-roaming settings during early registration phase (IPIS100058508)
 *
 * /main/ms-d/123   2009-09-04 11:14:41   ctna0256
 * Unregister from network before registering manually (IPIS100057521)
 *
 * /main/ms-d/122   2009-07-28 10:40:49   ctna0256
 * Better handling of the case "suspend during initialization" (IPIS100056850)
 *
 * /main/ms-d/121   2009-07-06 09:56:25   ctna0256
 * Workaround for wrong busy tone (IPIS100056689)
 *
 * /main/ms-d/120   2009-06-18 16:17:26   ctna0256
 * Alllow paket data even while initialization
 *
 * /main/ms-d/119   2009-05-28 11:36:48   ctna0256
 * Remove "Siemens" from RIL
 *
 * /main/ms-d/118   2009-05-27 10:04:55   ctna0256
 * Deregister module in PUK blocked state caused by wrong PIN change
 *
 * /main/ms-d/117   2009-05-18 13:27:39   ctna0256
 * remove unused notification
 *
 * /main/ms-d/116   2009-04-08 11:37:32   ctna0256
 * Fast registration
 *
 * /main/ms-d/115   2009-04-06 13:44:57   ctna0256
 * Initialize NITZ structure
 *
 * /main/ms-d/114   2009-03-10 11:23:31   ctna0256
 * New registry key for video call rejection
 *
 * /main/ms-d/113   2009-02-23 13:16:14   ctna0256
 * Avoid unwanted E_FAIL error codes
 *
 * /main/ms-d/112   2009-01-20 12:50:27   ctna0450
 * Fixed problem with new ppp data in response buffer avoidance
 *
 * /main/ms-d/111   2009-01-16 12:44:36   ctna0450
 * New mechanism to prevent PPP data from slip into the AT response buffer
 *
 * /main/ms-d/110   2009-01-15 09:18:47   ctna0256
 * Free event registration to prevent a resource leak
 *
 * /main/ms-d/109   2008-12-15 10:16:18   ctna0256
 * New default value for CMMS
 *
 * /main/ms-d/108   2008-12-01 12:02:30   ctna0256
 * Reject incoming video calls automatically
 *
 * /main/ms-d/107   2008-12-01 11:29:23   ctna0450
 * Fixed problem with mux frame size bigger than read buffer size
 *
 * /main/ms-d/106   2008-11-12 13:29:50   ctna0256
 * Execute parsing function before unlock state check
 * (needed, if unlock result in PH-NET PUK state)
 *
 * /main/ms-d/105   2008-10-23 11:32:29   ctna0256
 * New trace option (RIL proxy)
 *
 * /main/ms-d/104   2008-10-21 15:05:15   ctna0256
 * Registry key to force use of AT+CSQ
 *
 * /main/ms-d/103   2008-10-06 16:04:15   ctna0256
 * New options: Disable SMS completely; Use SMS reply address
 *
 * /main/ms-d/102   2008-10-06 09:25:06   ctna0256
 * Remove support of extended phonebook
 *
 * /main/ms-d/101   2008-09-29 08:43:53   ctna0256
 * Extended phonebook not available in official HC28R2
 *
 * /main/ms-d/100   2008-09-24 08:46:00   ctna0256
 * Removed unnecessary debug prints
 *
 * /main/ms-d/99   2008-09-23 16:14:59   ctna0256
 * Mute during VTS (optional)
 *
 * /main/ms-d/98   2008-09-19 16:39:55   ctna0256
 * New registry key "SupportPBEx"
 *
 * /main/ms-d/97   2008-08-26 14:26:49   ctna0256
 * Merged RIL_RADIO_RESILIENCE option from Classic-RIL
 *
 * /main/ms-d/96   2008-08-22 10:27:15   ctna0256
 * Set Cinterion copyright text
 *
 * /main/ms-d/95   2008-08-21 09:35:16   ctna0256
 * Prepared for new disclaimer handling
 *
 * /main/ms-d/94   2008-07-22 15:53:04   mp49210
 * Complience to WM7, Lint and PreFast requirements
 *
 * /main/ms-d/93   2008-07-22 10:45:07   mp49210
 * Changed handling of emergency calls for Korea
 *
 * /main/ms-d/92   2008-06-20 11:05:56   mp49210
 * Remove unused SIEMENS_MAGNETO define
 *
 * /main/ms-d/91   2008-06-12 15:00:28   mp49210
 * Block writing to phonebook during calls, if there had been an incoming call without number
 *
 * /main/ms-d/90   2008-06-12 11:38:27   mp49210
 * Workaround for wrong characters in EONS name
 *
 * /main/ms-d/89   2008-06-06 15:31:11   mp49210
 * Handling of additional CPOL parameters
 *
 * /main/ms-d/88   2008-05-26 09:00:12   mp49210
 * Synchronize module time with system time
 *
 * /main/ms-d/87   2008-05-15 15:00:52   mp49210
 * Additional debug output for RHA function calls
 *
 * /main/ms-d/86   2008-05-06 08:21:54   mp49210
 * No inline for RHA_IsRadioPwrOn()
 *
 * /main/ms-d/85   2008-05-05 10:28:07   mp49210
 * Handling of SIM not inserted after SMS retries (Workaround for CCIN pin for SIM card detection)
 *
 * /main/ms-d/84   2008-04-29 13:38:05   mp49210
 * Workaround for missing simstatus URC.
 * New handling of SIM reset.
 *
 * /main/ms-d/83   2008-04-21 08:16:48   mp49210
 * Handling of AT&Ts network selection menue change
 *
 * /main/ms-d/82   2008-04-16 16:24:21   mp49210
 * Debug zones for RHA traces
 *
 * /main/ms-d/81   2008-04-03 16:13:11   mp49210
 * Don't repeat AT+CRSM=192 if SIM is not inserted
 *
 * /main/ms-d/80   2008-04-03 14:41:52   mp49210
 * Introduction of new debug zones
 *
 * /main/ms-d/79   2008-04-03 14:03:16   kr36712
 * specific comment for read error on downstream port added
 *
 * /main/ms-d/78   2008-02-29 16:25:50   mp49210
 * Remove potential use of NULL pointer
 *
 * /main/ms-d/77   2008-02-26 09:22:22   mp49210
 * No use of Radio/Band configuration for HC25 2.010
 *
 * /main/ms-d/76   2008-02-19 11:33:15   mp49210
 * Handle COPS/AcT parameter sent by the MMI during startup of the RIL
 *
 * /main/ms-d/75   2008-02-04 14:56:15   mp49210
 * Send SMS workaround also for command retries
 *
 * /main/ms-d/74   2008-01-29 11:44:39   mp49210
 * Wrong indentation
 *
 * /main/ms-d/73   2008-01-17 15:26:01   mp49210
 * Fix for slow UICC SIMs (wrong SIM not inserted error)
 *
 * /main/ms-d/72   2007-12-20 14:02:12   mp49210
 * Introduction regsitry keys for CGSMS and PostSIMInitString
 *
 * /main/ms-d/71   2007-12-11 11:01:58   kr36712
 * GPS Powermanagement
 *
 * /main/ms-d/70   2007-12-05 13:54:21   mp49210
 * Introduction of SMS persist link
 *
 * /main/ms-d/69   2007-11-26 17:05:52   kr36712
 * integration of GPS support
 * use of the mux protocol
 *
 * /main/ms-d/68   2007-11-23 15:27:48   mp49210
 * Compatibility SAT Play Tone to Classic RIL
 *
 * /main/ms-d/67   2007-11-10 13:49:00   mp49210
 * Disable supplementary service notifications per registry
 *
 * /main/ms-d/66   2007-11-02 15:17:00   mp49210
 * Check SIM/USIM after successful At+CPIN? command only
 *
 * /main/ms-d/65   2007-10-12 09:52:30   mp49210
 * Optional registry key to send NITZ time, even if outdated.
 *
 * /main/ms-d/64   2007-10-11 16:23:17   mp49210
 * Introduction of AT^SLCC
 *
 * /main/ms-d/63   2007-09-21 10:29:47   mp49210
 * Introduction WM6 specific AcT selection (optional)
 *
 * /main/ms-d/62   2007-09-20 12:10:37   mp49210
 * No useful SIM phonebooks on HC25/HC28 customer samples
 *
 * /main/ms-d/61   2007-09-12 13:34:19   mp49210
 * Configure SIM initialization timeout with registry key
 *
 * /main/ms-d/60   2007-09-07 11:47:37   mp49210
 * Early CNMI initialization to catch VMWI indications, sent very fast from the network.
 *
 * /main/ms-d/59   2007-08-10 16:56:07   mp49210
 * IPIS100040302: send AT+CSIM after AT+CPIN?
 *
 * /main/ms-d/58   2007-08-09 09:56:36   mp49210
 * Check ME storage for accidently wrong routed SMS
 *
 * /main/ms-d/57   2007-08-08 11:16:48   mp49210
 * Introduction of audio profile download
 *
 * /main/ms-d/56   2007-07-10 09:29:01   mp49210
 * Introduction of new Radio/Band/Group parameter
 *
 * /main/ms-d/55   2007-07-04 08:57:19   mp49210
 * Introduction of maximum trace file length
 *
 * /main/ms-d/54   2007-07-04 07:32:16   mp49210
 * Introduction of radio band group search
 *
 * /main/ms-d/53   2007-06-28 09:58:54   mp49210
 * Close handle to threads to prevent handle leaks in memory
 *
 * /main/ms-d/52   2007-06-20 13:50:24   mp49210
 * Select FD phonebook as default in case fixed dialing is active
 *
 * /main/ms-d/51   2007-06-11 11:41:07   mp49210
 * Correct use of AT^SNWS/+COPS workarounds
 *
 * /main/ms-d/50   2007-06-01 15:21:28   mp49210
 * IPIS100037366: continue with initialization, even when setting SM phonebook fails.
 *
 * /main/ms-d/49   2007-05-29 09:37:05   mp49210
 * Workaoround for wrong error code to AT+CPIN?
 *
 * /main/ms-d/48   2007-05-23 08:37:40   mp49210
 * Introduction of AT^SNWS command (optional)
 *
 * /main/ms-d/47   2007-05-04 13:37:51   mp49210
 * Workaround for Exit when setting UCS2 during SIM initialization
 *
 * /main/ms-d/46   2007-05-02 10:26:17   mp49210
 * New registry key "NoRoaming Indicator"
 *
 * /main/ms-d/45   2007-04-27 08:33:58   mp49210
 * Removed Lint warnings
 *
 * /main/ms-d/44   2007-04-24 15:58:20   mp49210
 * IPIS100035501: introduction of list of networks (registry), where the RIL should not send the roaming status
 *
 * /main/ms-d/43   2007-04-05 09:00:45   mp49210
 * Send CLIR earlier
 *
 * /main/ms-d/42   2007-04-03 14:38:37   mp49210
 * Added missing UCS2 configuration for NITZ URC
 *
 * /main/ms-d/41   2007-03-28 13:30:08   mp49210
 * Move initialization of NITZ URC
 *
 * /main/ms-d/40   2007-03-28 11:31:42   mp49210
 * Workaround for missing '0' in AT+CLCC
 *
 * /main/ms-d/39   2007-03-28 10:42:04   mp49210
 * Store CLIR value persistent
 *
 * /main/ms-d/38   2007-03-27 11:35:56   mp49210
 * SAT in HC25 is now active before been activated.
 *
 * /main/ms-d/37   2007-03-26 14:57:17   mp49210
 * Minimum difference between +CLIP and AT+CLCC
 *
 * /main/ms-d/36   2007-02-26 16:15:34   mp49210
 * New behaviour of CBS, SIM storage and SMS SR
 *
 * /main/ms-d/35   2007-02-23 10:34:21   mp49210
 * Workaround for AT+CSCA is not needed any more
 *
 * /main/ms-d/34   2007-02-22 16:44:36   mp49210
 * Workaround for unusable AT+CRSM=242 on USIMs
 *
 * /main/ms-d/33   2007-02-09 16:02:35   mp49210
 * PreFast compatibility
 *
 * /main/ms-d/32   2007-02-09 15:15:21   mp49210
 * Lint compatibility
 *
 * /main/ms-d/31   2007-01-31 17:00:11   mp49210
 * Changed handling of cell broadcast messages to pass Crossbow radiometrics.exe
 *
 * /main/ms-d/30   2007-01-22 16:18:27   wm36264
 * Removed workaround for failing 1st at command after data mode
 *
 * /main/ms-d/29   2007-01-09 14:36:13   mp49210
 * Change NITZ-URC to UCS2
 *
 * /main/ms-d/28   2007-01-03 17:04:27   mp49210
 * Replace +CIEV: sounder with +CIEV: audio
 *
 * /main/ms-d/27   2007-01-02 15:03:37   mp49210
 * Remove some features not supported by Quinn
 *
 * /main/ms-d/26   2006-12-21 17:21:50   mp49210
 * Use new GPRS Auto Attach method
 *
 * /main/ms-d/25   2006-12-20 17:01:05   mp49210
 * Changes for AT+CNMI, AT+CAOC.
 * Modified URC configuration commands.
 *
 * /main/ms-d/24   2006-12-20 11:32:55   mp49210
 * Report system capabilities for voice+data according AT^SIND=psinfo
 *
 * /main/ms-d/23   2006-12-19 18:13:18   mp49210
 * Some changes for commands used during initialization
 *
 * /main/ms-d/22   2006-12-19 11:34:57   mp49210
 * Addotions for AT^SIND=psinfo
 *
 * /main/ms-d/21   2006-12-18 17:46:10   mp49210
 * Introduction of AT^SIND=psinfo
 *
 * /main/ms-d/20   2006-12-18 11:58:59   mp49210
 * Workaround for bug in AT+COPS?
 *
 * /main/ms-d/19   2006-12-15 16:40:12   mp49210
 * Workaorund for volatile CSCA setting
 *
 * /main/ms-d/18   2006-12-13 16:02:55   mp49210
 * Simplify 2G/3G-Selection in preparation for AT^SIND=psinfo
 *
 * /main/ms-d/17   2006-12-06 10:12:38   mp49210
 * Workaround for AT+CNMI problem in HC25 008
 *
 * /main/ms-d/16   2006-12-04 15:35:21   mp49210
 * Improvement in AT^SIND, SMS Phase 2+ in Quinn 006
 *
 * /main/ms-d/15   2006-11-22 15:43:12   wm36264
 * Avoid obsolete new/delete cycles
 *
 * /main/ms-d/14   2006-11-22 15:17:43   mp49210
 * Configure name of RHA with registry key
 *
 * /main/ms-d/13   2006-11-21 09:02:20   mp49210
 * New GPRS auto attach mechanism
 *
 * /main/ms-d/12   2006-11-14 16:59:59   wm36264
 * Tidy up more unused stuff
 *
 * /main/ms-d/11   2006-11-14 14:40:05   wm36264
 * Disposed unused CRilEventLog
 *
 * /main/ms-d/10   2006-11-14 12:49:19   wm36264
 * Updated trace stuff due to global trace handling
 *
 * /main/ms-d/9   2006-11-13 11:54:00   wm36264
 * Added workaround for failing 1st cmd after data mode
 *
 * /main/ms-d/8   2006-11-13 10:05:17   mp49210
 * New PIN2 handling in Quinn
 *
 * /main/ms-d/7   2006-11-10 12:49:59   wm36264
 * Simplyfied "Wait for Response" mechanism
 *
 * /main/ms-d/6   2006-11-09 14:24:35   mp49210
 * Quinn specific feature: selction of 2G / 3G network
 *
 * /main/ms-d/5   2006-11-07 10:18:49   mp49210
 * Substitute AT^SPLR and AT^SPLW
 *
 * /main/ms-d/4   2006-11-02 09:38:57   mp49210
 * Some adjustments for post-PIN-init sequence
 *
 * /main/ms-d/3   2006-10-30 12:30:12   wm36264
 * Fixed problem with new number of threads
 *
 * /main/ms-d/2   2006-10-30 10:26:33   wm36264
 * Removed unused stuff
 *
 * /main/ms-d/1   2006-10-25 16:51:44   wm36264
 * First transformation from classic RIL
 *
*/

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

/*++
THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
PARTICULAR PURPOSE.
Copyright (c) 1995-1999  Microsoft Corporation
--*/

#include "precomp.h"
#include "simmgr.h"
#include <notify.h>

static HANDLE g_hSIMUnlockThread, g_hSIMUnlockEvent;
HANDLE g_hAckSMSEvent = NULL;
HANDLE g_hTimeChangeEvent = NULL;
DWORD g_dwSendNITZTime = 0;
BOOL g_fReportLocationUpdateAsRegistrationState = FALSE;
MODEMTYPE g_dwModemType = MODEMTYPE_UNKNOWN;
DWORD g_dwModemVersion = 0;
DWORD g_dwProductInternalVersion = 0;
DWORD g_dwSIMLockedState = RIL_LOCKEDSTATE_UNKNOWN;
DWORD g_dwReceiveCellBroadCast = 2;
DWORD g_dwUseReplyAddressIncoming = 0;
DWORD g_dwDisableSMS = 0;
BOOL  g_fUseGSM0707Cmds = FALSE;
#ifdef CSCB_IN_MC75_STYLE
DWORD g_dwReceiveCellBroadCastAccept = 0;
#endif
char g_szReceiveCellBroadCastChannels[MAX_CBM_STRING];
char g_szReceiveCellBroadCastDCS[MAX_CBM_STRING];
BOOL g_fDisableCOLPInformation = FALSE;
UINT g_nCOLPStatus = 0;
BOOL g_fNoCSQinSuspend = FALSE;
DWORD g_dwSignalStrenth3G = SS_3G_RSSI;
DWORD g_dwSignalStrenth4G = SS_LTE_RSSI;
extern DWORD g_dwLastSMSCmd;
#ifdef RIL_WM6_ACT_SELECTION
extern UINT g_iSetCOPSinInitParams;
#endif
extern char g_szLastKnownEONSNameLong[MAXLENGTH_OPERATOR_LONG+1];
extern char g_szLastKnownEONSNameShort[MAXLENGTH_OPERATOR_LONG+1];
extern DWORD g_dwCallerIdStatus;
static BOOL g_fExtRegStatusPollingActive = FALSE;

/*extern "C" {
void fnRHACallback(DWORD dwEventMask);
}*/

static DWORD WINAPI SIMUnlockThreadProc(LPVOID lpParameter);
static DWORD WINAPI AckSMSThreadProc(LPVOID lpParameter);
LPCTSTR g_tszRegKeyIntrinsycRIL = TEXT("Software\\RIL");

// RIL registry key
const LPCTSTR g_tszRegKeyRIL = TEXT("Software\\Microsoft\\RIL");

// RIL API info registry key
static const LPCTSTR g_tszRegKeyAPIInfo = TEXT("Software\\Microsoft\\RIL\\APIInfo\\");

// RIL opertor names registry key
const LPCTSTR g_tszRegKeyOperNames = TEXT("Software\\Microsoft\\RIL\\OperatorNames");

// Named event to be triggered on system time change
const LPCTSTR g_wszTimeChangeEvent = L"RILTimeChange";

#ifdef RILDRV_CE6
// Visual Studio wants to see S_FALSE here instead of 1, but
// 1 is the correct value here and even when S_FALSE is used,
// the warning still shows up.
#pragma warning (push)
#pragma warning ( disable : 6225 )
#endif
const HRESULT INITIAL_COMMAND_ID = 1;
#ifdef RILDRV_CE6
#pragma warning (pop)
#endif

// Two needed DLLs:
const WCHAR wszRHADLLDefault[] = L"RHA.DLL";
const WCHAR wszSIMSECDLL[] = L"simsec.dll";

DWORD g_TimeoutCmdInit;
DWORD g_TimeoutAPIDefault;

DWORD g_iCurrentSIMStatus = 0;

// It's safe to put these params in globals since the SIM PW prompt thread is only launched from the command thread,
// and no more than one SIM PW prompt thread at a time is launched.
static BOOL g_PromptingForSim=FALSE;
static DWORD g_dwLockFacility;
static CQueue<CCommand, 10>* g_pSimLockedQueue;

// Setting for CDMA Cell Broadcast (see AT$QCSCP)
DWORD g_dwCdmaCBSetting = 0;

// Interface to RHA.DLL
RHA_FUNCTION_LIST RHAFunctionList;
static HINSTANCE g_hRHAInst = NULL;

#ifdef RIL_RADIO_RESILIENCE
BOOL g_fAllowReboot = FALSE;
DWORD g_dwLastAutoReboot = 0;
DWORD g_dwRebootEmergencyStatus = EMERG_SHUTDOWN_NONE;
#endif

// Delay for AT+CNMA SMS acknowledgement in ms
#define CNMA_DELAY   200

// Structure needed for RIL_NOTIFY_DEVSPECIFIC_REGSTATUS_EX
struct CHECKEXTREG_THREAD_DATA {
    CRilHandle* pHandle;
    DWORD dwRegStatus;
};

#ifdef RIL_ENABLE_SYNC_TIME
//
// TimeEventThreadProc registers itself to the GWES to be notified about changes
// in the system time. If such event occurs, it changes the time in the radio
// acordingly.
//
static DWORD WINAPI TimeEventThreadProc(LPVOID lpParameter)
{
    CRilHandle* pRilDevice = (CRilHandle*)lpParameter;
    DWORD dwEvent;
    DWORD dwError;
    WCHAR wszEventName[MAX_PATH];

    (void)_snwprintfz(wszEventName, MAX_PATH, L"\\\\.\\Notifications\\NamedEvents\\%s", g_wszTimeChangeEvent);
    if (!SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL))
    {
        return 0;
    }

    // The RIL has to register to the GWES to be notified about changes in the
    // system time.
    // As a system driver, the RIL loaded earlier than the GWES, so the RIL has
    // to wait for the GWES to be ready to accept the registration.
    while (!pRilDevice->FCancelSet())
    {
        // First deregister old event to avoid a resource leak, since events
        // keep getting stored even through a warm boot.
        if(CeRunAppAtEvent(wszEventName, NOTIFICATION_EVENT_NONE))
        {
            if(CeRunAppAtEvent(wszEventName, NOTIFICATION_EVENT_TIME_CHANGE))
                break;
        }
        dwError = GetLastError();
        if (dwError != ERROR_SERVICE_NOT_ACTIVE)
        {
            RILRetailTraceZone(ZONE_INFO, (TEXT("RilDrv: TimeEventThreadProc:  CeRunAppAtEvent() failed with code %d\r\n"), dwError));
            return 0;
        }
        Sleep(10000);       // Try again in 10 seconds.
    }

    // Wait for time change event
    while (!pRilDevice->FCancelSet())
    {
        dwEvent = WaitForSingleObject(g_hTimeChangeEvent, INFINITE);
        // See if the thread needs to terminate
        if (pRilDevice->FCancelSet())
        {
            break;
        }
        if(dwEvent == WAIT_OBJECT_0)
        {
            if (!g_PowerManager.IsRadioOff())   // If the radio is currently off, it makes no sense to set the time.
                (void)pRilDevice->SetTimeInModule();
        }
    }
    return 0;
}
#endif

//
// RIL handle ctor
//
CRilHandle::CRilHandle()
: m_hInitEvent(NULL),
m_hCancelEvent(NULL),
m_hSimReadyEvent(NULL),
m_hAbortInternalSimReadyEvent(NULL),
m_hInternalSimReadyEvent(NULL),
m_hAudioModeEvent(NULL),
m_hCallStateChangeEvent(NULL),
m_hCmdThread(NULL),
m_hNoopCmdThread(NULL),
m_hNoMuteThread(NULL),
m_fQuitReadyStateThread(FALSE),
m_fIgnoreNextNOCARRIER(FALSE),
m_fVoiceCallDialing(FALSE),
m_fSMSURCInitPhase(FALSE),
m_fCIEVaudioActive(FALSE),
m_fSLCCaudioActive(FALSE),
m_fCIEVaudioUsed(FALSE),
m_fNoAudioForCSD(FALSE),
m_fNITZactivated(FALSE),
m_pMonitor(NULL),
m_pInstances(NULL),
m_hrNextCmdID(INITIAL_COMMAND_ID),
m_fInited(FALSE),
m_fFailedInit(FALSE),
m_fWaitingForRsp(FALSE),
m_fEmergencyMode(FALSE),
m_fSimReady(FALSE),
m_pCurrCommand(NULL),
m_fUSSDAnswerMode(FALSE),
m_nSIMType(SIMTYPE_UNKNOWN),
m_dwAudioTxDevice(RIL_AUDIO_HANDSET),
m_dwAudioRxDevice(RIL_AUDIO_HANDSET),
m_dwLastSATPlayToneCmd(0),
m_dwDisableSyncTime(0),
m_dwForce2GforCSD(0),
m_fBlockRegistrationURCs(FALSE),
m_dwTempMuteRunning(0),
m_dwTempMuteEnd(0),
m_dwTempMuteDelay(0),
m_hBlockCmdsEvent(NULL),
m_hBlockRspsEvent(NULL),
m_pSimToolkitHandling(NULL),
m_pEonsHandling(NULL),
m_dwNumNoRomingNetworks(0),
m_fNoRomingIndicator(FALSE),
m_fNeedBandGroupSearchActivation(FALSE),
m_fNextSIMStatusIsWorng(FALSE),
m_fNoNeedForSCKSWorkaround(FALSE),
m_fReceivedPhoneCallWONumber(FALSE),
m_fIPUKrequieredAfterPINchange(FALSE),
m_fBlockPhonebook(FALSE),
m_fExtendedRegStatusNotification(FALSE),
m_fNetworkRejectionDetected(FALSE),
m_dwIgnoreNextCIEVAudioTimer(0),
m_dwIgnoreSCKSsupport(0),
m_dwLastCallURC(0),
m_dwConfigureExtRegStatus(2),
m_nCurrentENSSetting(ENS_UNKNOWN),
m_nMultiModeSetting(MULTIMODE_CONFIG_MULTIMODE),
m_nCurrentTechnology(TEC_MODE_UNKNOWN),
m_fGsmUrcsActivated(FALSE),
m_fCdmaUrcsActivated(FALSE),
m_fGotCdmaActivationURC(FALSE),
m_dwHSDPAdetected(0),
m_fNoCheckForACQDBneeded(FALSE),
m_fUseGMMCommand(FALSE),
m_fSysStartDected(FALSE),
m_nStoredDST(MAXDWORD)
{
    WCHAR wszRHADLL[MAX_PATH];

    // Intialize critical sections
    InitializeCriticalSection(&m_cs);
    InitializeCriticalSection(&m_csCmdID);
    InitializeCriticalSection(&m_csEmergency);
    InitializeCriticalSection(&m_csTechnologySwitch);
    InitializeCriticalSection(&m_csATTimeouts);
    InitializeCriticalSection(&m_csBlockCmds);

    memset(m_rgpAPIInfo, 0x00, APIID_TOTAL * sizeof(APIINFO*));
    memset(m_pComDevice, 0x00, sizeof(m_pComDevice));
    memset(m_pReadBytes, 0x00, sizeof(m_pReadBytes));
    memset(m_fLastCommandTimedOut, 0x00, sizeof(m_fLastCommandTimedOut));
    memset((void*)m_hReadThread, 0x00, sizeof(m_hReadThread));
    memset((void*)m_dwPendingPortCalls, 0x00, sizeof(m_dwPendingPortCalls));
    memset(m_szCdmaProvider, 0, MAX_CDMA_PROVIDER_NAME_LEN);
    memset(m_szLastDialedNumber, 0, MAX_ATCMD_LEN);

    m_pEonsHandling = new CEonsHandling();
    m_pSimToolkitHandling = new CSimToolkitHandling(this);
    m_pForceHomeNet = new CForceHomeNet();

    g_fReportLocationUpdateAsRegistrationState = FALSE;
    g_bCINDIsActive = FALSE;
    g_iLastRSSI = 99;
    g_iLastSignal = 99;
    g_dwLastSMSCmd = 0;
#ifdef RIL_RADIO_RESILIENCE
    ClearPINSecure();
#endif
    ClearPIN2Secure();

    wcscpy(wszRHADLL, wszRHADLLDefault);
    (void)GetRegistrySZ(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, TEXT("RHAFileName"), wszRHADLL, MAX_PATH);

    RHAFunctionList.pfnRHA_Init = NULL;
    RHAFunctionList.pfnRHA_DeInit = NULL;
    RHAFunctionList.pfnRHA_RadioPwrOn = NULL;
    RHAFunctionList.pfnRHA_RadioPwrOff = NULL;
    RHAFunctionList.pfnRHA_IsRadioPwrOn = NULL;
    RHAFunctionList.pfnRHA_ActivateVoicePath = NULL;
    RHAFunctionList.pfnRHA_DeactivateVoicePath = NULL;
    RHAFunctionList.pfnRHA_AdjustTxVolume = NULL;
    RHAFunctionList.pfnRHA_AdjustRxVolume = NULL;
    RHAFunctionList.pfnRHA_GetRHAVersion = NULL;
    RHAFunctionList.pfnRHA_ConfirmAudioMode = NULL;
    RHAFunctionList.pfnRHA_SystemPowerChange = NULL;
    RHAFunctionList.pfnRHA_GpsAntennaPowerSupplyOn = NULL;
    RHAFunctionList.pfnRHA_GpsAntennaPowerSupplyOff = NULL;
    RHAFunctionList.pfnRHA_SetRadioIgnition  = NULL;
    RHAFunctionList.pfnRHA_SwitchToCDMA = NULL;
    RHAFunctionList.pfnRHA_SwitchToUMTS = NULL;
    RHAFunctionList.pfnRHA_SetBootloaderPin = NULL;

    g_hRHAInst = LoadLibrary(wszRHADLL);
    if(g_hRHAInst == NULL)
    {
        RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: Cannot load %s\r\n"), wszRHADLL));
    }
    else
    {
        RHAFunctionList.pfnRHA_Init = (PFNRHA_INIT_DEINIT)GetProcAddress(g_hRHAInst, RHA_INIT);
        RHAFunctionList.pfnRHA_DeInit = (PFNRHA_INIT_DEINIT)GetProcAddress(g_hRHAInst, RHA_DEINIT);
        RHAFunctionList.pfnRHA_RadioPwrOn = (PFNRHA_RADIO_POWER_ON)GetProcAddress(g_hRHAInst, RHA_RADIO_POWER_ON);
        RHAFunctionList.pfnRHA_RadioPwrOff = (PFNRHA_RADIO_POWER_OFF)GetProcAddress(g_hRHAInst, RHA_RADIO_POWER_OFF);
        RHAFunctionList.pfnRHA_IsRadioPwrOn = (PFNRHA_IS_RADIO_POWER_ON)GetProcAddress(g_hRHAInst, RHA_IS_RADIO_POWER_ON);
        RHAFunctionList.pfnRHA_ActivateVoicePath = (PFNRHA_ACTIVATE_VOICE_PATH)GetProcAddress(g_hRHAInst, RHA_ACTIVATE_VOICE_PATH);
        RHAFunctionList.pfnRHA_DeactivateVoicePath = (PFNRHA_DEACTIVATE_VOICE_PATH)GetProcAddress(g_hRHAInst, RHA_DEACTIVATE_VOICE_PATH);
        RHAFunctionList.pfnRHA_AdjustTxVolume = (PFNRHA_ADJUST_TX_VOLUME)GetProcAddress(g_hRHAInst, RHA_ADJUST_TX_VOLUME);
        RHAFunctionList.pfnRHA_AdjustRxVolume = (PFNRHA_ADJUST_RX_VOLUME)GetProcAddress(g_hRHAInst, RHA_ADJUST_RX_VOLUME);
        RHAFunctionList.pfnRHA_GetRHAVersion = (PFNRHA_GET_RHA_VERSION)GetProcAddress(g_hRHAInst, RHA_GET_RHA_VERSION);
        RHAFunctionList.pfnRHA_ConfirmAudioMode = (PFNRHA_CONFIRM_AUDIO_MODE)GetProcAddress(g_hRHAInst, RHA_CONFIRM_AUDIO_MODE);
        RHAFunctionList.pfnRHA_SystemPowerChange = (PFNRHA_SYSTEM_POWER_CHANGE)GetProcAddress(g_hRHAInst, RHA_SYSTEM_POWER_CHANGE);
        RHAFunctionList.pfnRHA_GpsAntennaPowerSupplyOn = (PFNRHA_GPS_ANTENNA_POWER_SUPPLY_ON)GetProcAddress(g_hRHAInst, RHA_GPS_ANTENNA_POWER_SUPPLY_ON);
        RHAFunctionList.pfnRHA_GpsAntennaPowerSupplyOff = (PFNRHA_GPS_ANTENNA_POWER_SUPPLY_OFF)GetProcAddress(g_hRHAInst, RHA_GPS_ANTENNA_POWER_SUPPLY_OFF);
        RHAFunctionList.pfnRHA_SetRadioIgnition = (PFNRHA_SET_RADIO_IGNITION)GetProcAddress(g_hRHAInst, RHA_SET_RADIO_IGNITION);
        RHAFunctionList.pfnRHA_SwitchToCDMA = (PFNRHA_SWITCH_TO_CDMA)GetProcAddress(g_hRHAInst, RHA_SWITCH_TO_CDMA);
        RHAFunctionList.pfnRHA_SwitchToUMTS = (PFNRHA_SWITCH_TO_UMTS)GetProcAddress(g_hRHAInst, RHA_SWITCH_TO_UMTS);
        RHAFunctionList.pfnRHA_SetBootloaderPin = (PFNRHA_SET_BOOTLOADER_PIN)GetProcAddress(g_hRHAInst, RHA_SET_BOOTLOADER_PIN);
#ifdef RIL_RADIO_RESILIENCE
        if (RHAFunctionList.pfnRHA_SetRadioIgnition == NULL)
            RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: WARNING - Cannot find function 'RHA_SetRadioIgnition()' in RHA.")));
#endif
    }
    RHA_Init();
}


//
// Function passed to CDlbList::Enum() below
//
static BOOL DeleteInstanceHandle(void* pItem, DWORD /*dwData*/)
{
    CRilInstanceHandle* pHandle = (CRilInstanceHandle*)pItem;
    delete pHandle;

    // Continue enumeration
    return FALSE;
}

//
// RIL handle dtor
//
CRilHandle::~CRilHandle()
{
    UINT i;

    {
        SYNCBLOCK(m_cs);

        // Stop the SIM-Toolkit handling
        (void)m_pSimToolkitHandling->Deinit();
        delete m_pSimToolkitHandling;

        // Stop the EONS handling
        (void)m_pEonsHandling->Deinit();
        delete m_pEonsHandling;
        delete m_pForceHomeNet;

        // Signal the cancel event to kill the thread
        if (m_hCancelEvent)
        {
            (void)SetEvent(m_hCancelEvent);
        }

        StopReadyStateQuery();

        // Wait for auxiliary threads to terminate
        (void)WaitForSingleObject(m_hCmdThread, 10000);
        for (i = 0; i < NUMBER_OF_PORTS; i++) {
          (void)WaitForSingleObject(m_hReadThread[i], 10000);
        }
        (void)WaitForSingleObject(m_hNoopCmdThread, 10000);

        // Get rid of the threads
        if (m_hCmdThread)
        {
          (void)CloseHandle(m_hCmdThread);
          m_hCmdThread = NULL;
        }
        for (i = 0; i < NUMBER_OF_PORTS; i++) {
          if (m_hReadThread[i])
          {
            (void)CloseHandle(m_hReadThread[i]);
            m_hReadThread[i] = NULL;
          }
        }
        if (m_hNoopCmdThread)
        {
          (void)CloseHandle(m_hNoopCmdThread);
          m_hNoopCmdThread = NULL;
        }

        if (g_hTimeChangeEvent)
        {
            (void)SetEvent(g_hTimeChangeEvent);    // Kill the time change thread
            Sleep(10);
            (void)CloseHandle(g_hTimeChangeEvent);
            g_hTimeChangeEvent = NULL;
        }
        if (g_hAckSMSEvent)
        {
            (void)SetEvent(g_hAckSMSEvent);    // Kill the SMS acknowledgement thread
            Sleep(10);
            (void)CloseHandle(g_hAckSMSEvent);
            g_hAckSMSEvent = NULL;
        }
        if (g_hSIMUnlockEvent)
        {
            (void)SetEvent(g_hSIMUnlockEvent);    // Kill the unlock thread
            Sleep(10);
            (void)CloseHandle(g_hSIMUnlockEvent);
            g_hSIMUnlockEvent = NULL;
        }
        if (g_hSIMUnlockThread)
        {
            (void)CloseHandle(g_hSIMUnlockThread);
            g_hSIMUnlockThread = NULL;
        }

        // Get rid of the event
        if (m_hCancelEvent)
        {
            (void)CloseHandle(m_hCancelEvent);
            m_hCancelEvent = NULL;
        }

        // Get rid of the monitor
        delete m_pMonitor;
        m_pMonitor = NULL;

        delete g_pSimLockedQueue;
        g_pSimLockedQueue = NULL;

        // Close the serial ports
        for (i = 0; i < NUMBER_OF_PORTS; i++) {
          if (m_pComDevice[i])
          {
            m_pComDevice[i]->SetExternalCancelEvent(NULL);
            (void)g_ComManager.DestroyPortDevice((COM_PORT_TYPE)i);
            m_pComDevice[i] = NULL;
          }
        }

        if (m_pInstances != NULL) {
            // All of the instance handles should be closed
            // before the driver handle is destroyed.
            m_pInstances->Enum(DeleteInstanceHandle, 0);

            // Delete the instance handle list
            delete m_pInstances;
            m_pInstances = NULL;
        }

        // Delete the Read Bytes buffers
        for (i = 0; i < NUMBER_OF_PORTS; i++) {
          if (m_pReadBytes[i]) {
            delete m_pReadBytes[i];
            m_pReadBytes[i] = NULL;
           }
        }

        // Get rid of remaining events
        if (m_hInitEvent) {
            (void)CloseHandle(m_hInitEvent);
            m_hInitEvent = NULL;
        }
        if (m_hBlockCmdsEvent) {
            (void)CloseHandle(m_hBlockCmdsEvent);
            m_hBlockCmdsEvent = NULL;
        }
        if (m_hBlockRspsEvent) {
            (void)CloseHandle(m_hBlockRspsEvent);
            m_hBlockRspsEvent = NULL;
        }
        if (m_hAudioModeEvent) {
            (void)CloseHandle(m_hAudioModeEvent);
            m_hAudioModeEvent = NULL;
        }
        if (m_hCallStateChangeEvent) {
            (void)CloseHandle(m_hCallStateChangeEvent);
            m_hCallStateChangeEvent = NULL;
        }
        for (i = 0; i < APIID_TOTAL; i++)
        {
            delete m_rgpAPIInfo[i];
            m_rgpAPIInfo[i] = NULL;
        }

        if(g_hRHAInst != NULL) {
            RHA_DeInit();
            (void)FreeLibrary(g_hRHAInst);
            g_hRHAInst = NULL;
        }

        DeleteCriticalSection(&m_csBlockCmds);
        DeleteCriticalSection(&m_csATTimeouts);
        DeleteCriticalSection(&m_csCmdID);
        DeleteCriticalSection(&m_csEmergency);
        DeleteCriticalSection(&m_csTechnologySwitch);

        m_fInited = FALSE;
        m_fFailedInit=FALSE;
    }

    DeleteCriticalSection(&m_cs);
}

//
// Broadcasts a change in the radio ready state
//
void CRilHandle::SendReadyStateNotification(DWORD dwReadyState, BOOL fBroadcast)
{
    RILEQUIPMENTSTATE res;
    CNotificationData *pnd = NULL;

    // Set this in our global
    if (dwReadyState)
    {
        g_dwReadyState |= dwReadyState;
    }
    else
    {
        g_dwReadyState = 0;
    }

    if (fBroadcast)
    {
        // Broadcast the notification
        memset(&res, 0x00, sizeof(RILEQUIPMENTSTATE));
        res.cbSize = sizeof(RILEQUIPMENTSTATE);
        res.dwParams = RIL_PARAM_EQUIPMENTSTATE_READYSTATE;
        res.dwReadyState = g_dwReadyState;
        pnd = new CNotificationData;
        if (pnd && pnd->InitFromRealBlob(RIL_NOTIFY_RADIOEQUIPMENTSTATECHANGED, (void *) &res, res.cbSize))
        {
            // Note that BroadcastNotification frees pnd
            BroadcastNotification(pnd);
            pnd = NULL;
        }

        delete pnd;
    }

    // Now, update StatStor
    UpdateStatStore();
}

//
// This thread checks if we are registered to the correct network.
//
DWORD WINAPI Check2G3GRegistration(LPVOID pVoid)
{
    BOOL fRet;
    DWORD n2G3GSelectionOld;
    DWORD n2G3GSelectionTmp;
    CRilHandle* pHandle = (CRilHandle *)pVoid;
    const char *szNetCmd = "AT+WS46?\r";
    PFN_CMD_PARSE fnParsing = ParseGet2G3GSelection;

    if (INTEL_STYLE_NET_CMDS) {
        szNetCmd = "AT^SXRAT?\r";
        fnParsing = ParseGet2G3GSelectionIntel;
    }
#ifdef SUPPORTS_EHSX_R1
    if (INTEL_AT_CMDS) {
        szNetCmd = "AT+XRAT?\r";
        fnParsing = ParseGet2G3GSelectionXRAT;
    }
#endif
    if (AVOID_COPS_ACT) {
        szNetCmd = "AT^SCFG=Radio/Band\r";
        fnParsing = ParseGet2G3GSelectionSCFG;
    }

    n2G3GSelectionTmp = g_n2G3GSelection;

    fRet = QueueInternalCmdBlocking(HCCMD_STANDARD, pHandle, szNetCmd, CMDOPT_NONE, APIID_DEVSPECIFIC, 0, 0, 0, fnParsing);
    if (fRet)
    {
        BOOL fCOPSused = FALSE;
        BOOL fCOPS1used = FALSE;
        UINT nSetRadioBand = 0;
		
		char szCmd[MAX_ATCMD_LEN];

        n2G3GSelectionOld = g_n2G3GSelection;
        g_n2G3GSelection = n2G3GSelectionTmp;
        if (n2G3GSelectionOld != g_n2G3GSelection && g_n2G3GSelection != SELECTION2G3G_AUTOMATIC && !AVOID_COPS_ACT)
        {
            

            // We are using the wrong technology and need to correct it.
            if (g_iLastCOPS == 0)
            {
                (void)_snprintfz(szCmd, MAX_ATCMD_LEN, "AT+COPS=0,2,,%d\r", g_n2G3GSelection == SELECTION2G3G_GSM_ONLY?0:(g_n2G3GSelection == SELECTION2G3G_UMTS_ONLY?2:7));
                //(void)QueueInternalCmdBlocking(HCCMD_STANDARD, pHandle, szCmd, CMDOPT_NONE, APIID_REGISTERONNETWORK, 0, 0, 0, NULL);
			   (void)QueueInternalCmd(HCCMD_STANDARD, pHandle, szCmd, CMDOPT_NONE, APIID_REGISTERONNETWORK, 0, 0, 0);

                fCOPSused = TRUE;
            }
            else if (g_iLastCOPS == 1 && g_iLastCOPSOpr > 0)
            {
                (void)_snprintfz(szCmd, MAX_ATCMD_LEN, "AT+COPS=1,2,%d,%d\r", g_iLastCOPSOpr, g_n2G3GSelection == SELECTION2G3G_GSM_ONLY?0:(g_n2G3GSelection == SELECTION2G3G_UMTS_ONLY?2:7));
                (void)QueueInternalCmdBlocking(HCCMD_STANDARD, pHandle, szCmd, CMDOPT_NONE, APIID_REGISTERONNETWORK, 0, 0, 0, NULL);
                fCOPSused = TRUE;
                fCOPS1used = TRUE;
            }
			
        }
        else if (n2G3GSelectionOld != g_n2G3GSelection && (g_n2G3GSelection == SELECTION2G3G_AUTOMATIC || AVOID_COPS_ACT))
        {
            //char szCmd[MAX_ATCMD_LEN];

            // We are using the wrong technology and need to correct it.
            if (g_iLastCOPS == 0)
            {
                (void)_snprintfz(szCmd, MAX_ATCMD_LEN, "AT+COPS=0\r");
                (void)QueueInternalCmdBlocking(HCCMD_STANDARD, pHandle, szCmd, CMDOPT_NONE, APIID_REGISTERONNETWORK, 0, 0, 0, NULL);
                fCOPSused = TRUE;
            }
            else if (g_iLastCOPS == 1 && g_iLastCOPSOpr > 0)
            {
                (void)_snprintfz(szCmd, MAX_ATCMD_LEN, "AT+COPS=1,2,%d\r", g_iLastCOPSOpr);
                (void)QueueInternalCmdBlocking(HCCMD_STANDARD, pHandle, szCmd, CMDOPT_NONE, APIID_REGISTERONNETWORK, 0, 0, 0, NULL);
                fCOPSused = TRUE;
                fCOPS1used = TRUE;
            }
        }
		
		if(SUPPORTS_ALL_NETWORK)
		{
			if(g_n2G3GSelection == SELECTION2G3G_GSM_ONLY)
			{
				(void)_snprintfz(szCmd, MAX_ATCMD_LEN, "AT^SXRAT=0\r");
			} 
			else if(g_n2G3GSelection == SELECTION2G3G_UMTS_ONLY)
			{
				(void)_snprintfz(szCmd, MAX_ATCMD_LEN, "AT^SXRAT=2\r");
			} 
			else if(g_n2G3GSelection == SELECTION2G3G_LTE_ONLY)
			{
				(void)_snprintfz(szCmd, MAX_ATCMD_LEN, "AT^SXRAT=3\r");
			}
			else if(g_n2G3GSelection == SELECTION2G3G_AUTOMATIC)
			{
			    if(g_dwModemType == MODEMTYPE_ELS81_E)
				{
				    (void)_snprintfz(szCmd, MAX_ATCMD_LEN, "AT^SXRAT=6,3,2\r");
				}
				else
				{
				    (void)_snprintfz(szCmd, MAX_ATCMD_LEN, "AT^SXRAT=6,2,3\r");
				}
			}
			QueueInternalCmdBlocking(HCCMD_STANDARD, pHandle, szCmd, CMDOPT_NONE, APIID_NONE, 0, 0, 0);
		}
		
		if(SUPPORTS_ONLY_GPRS_LTE)
		{
			if(g_n2G3GSelection == SELECTION2G3G_GSM_ONLY)
			{
				(void)_snprintfz(szCmd, MAX_ATCMD_LEN, "AT^SXRAT=0\r");
			} 
			else if(g_n2G3GSelection == SELECTION2G3G_LTE_ONLY)
			{
				(void)_snprintfz(szCmd, MAX_ATCMD_LEN, "AT^SXRAT=3\r");
			}
			else if(g_n2G3GSelection == SELECTION2G3G_AUTOMATIC)
			{
				(void)_snprintfz(szCmd, MAX_ATCMD_LEN, "AT^SXRAT=5,3\r");
			}
			QueueInternalCmdBlocking(HCCMD_STANDARD, pHandle, szCmd, CMDOPT_NONE, APIID_NONE, 0, 0, 0);
		}
		
		if(SUPPORTS_ONLY_UMTS_LTE)
		{
			if(g_n2G3GSelection == SELECTION2G3G_UMTS_ONLY)
			{
				(void)_snprintfz(szCmd, MAX_ATCMD_LEN, "AT^SXRAT=2\r");
			} 
			else if(g_n2G3GSelection == SELECTION2G3G_LTE_ONLY)
			{
				(void)_snprintfz(szCmd, MAX_ATCMD_LEN, "AT^SXRAT=3\r");
			}
			else if(g_n2G3GSelection == SELECTION2G3G_AUTOMATIC)
			{
				(void)_snprintfz(szCmd, MAX_ATCMD_LEN, "AT^SXRAT=4,3\r");
			}
			QueueInternalCmdBlocking(HCCMD_STANDARD, pHandle, szCmd, CMDOPT_NONE, APIID_NONE, 0, 0, 0);
		}
		
		if(SUPPORTS_ONLY_GPRS_UMTS)
		{
		    if(g_n2G3GSelection == SELECTION2G3G_UMTS_ONLY)
			{
				(void)_snprintfz(szCmd, MAX_ATCMD_LEN, "AT^SXRAT=2\r");
			} 
			else if(g_n2G3GSelection == SELECTION2G3G_GSM_ONLY)
			{
				(void)_snprintfz(szCmd, MAX_ATCMD_LEN, "AT^SXRAT=0\r");
			}
			else if(g_n2G3GSelection == SELECTION2G3G_AUTOMATIC)
			{
				(void)_snprintfz(szCmd, MAX_ATCMD_LEN, "AT^SXRAT=1,2\r");
			}
			QueueInternalCmdBlocking(HCCMD_STANDARD, pHandle, szCmd, CMDOPT_NONE, APIID_NONE, 0, 0, 0);
		}
		
        if (AVOID_COPS_ACT) {
            // AT+COPS/<AcT> bug (PXS8): When using the <AcT> parameter of AT+COPS
            // the module might freeze. As a workaround, the RIL reconfigures the
            // AT^SCFG=Radio/Band setting to force the module into the correct
            // access technology.
            nSetRadioBand = 7679;    // All GSM/UMTS + CDMA bands.
            if (g_n2G3GSelection == SELECTION2G3G_GSM_ONLY)
                nSetRadioBand = 7183;    // CDMA + GSM
            else if (g_n2G3GSelection == SELECTION2G3G_UMTS_ONLY)
                nSetRadioBand = 7664;    // CDMA + UMTS
        }

        if (nSetRadioBand > 0) {
            char szSCFGCmd[MAX_ATCMD_LEN];
            DWORD dwRegRadioBand;

            if (!GetRegistryDWORD(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, TEXT("UseCopsActWorkaround"), &dwRegRadioBand))
                dwRegRadioBand = 1;
            // Set Radio/Band. Needed for AT+COPS/<AcT> workaround.
            (void)_snprintfz(szSCFGCmd, MAX_ATCMD_LEN, "AT^SCFG=\"Radio/Band\",\"%d\",\"1\"\r", nSetRadioBand);
            if (dwRegRadioBand == 1)
                (void)QueueInternalCmd(HCCMD_STANDARD, pHandle, szSCFGCmd, CMDOPT_NONE, APIID_SCFGRADIOBAND, 0, 0, 0);
        }

        if ((COPS_CHANGES_SCFG && fCOPSused) || (COPS1_CHANGES_SCFG && fCOPS1used)) {
            // Bug in PXS8: the use of AT+COPS changes the module from GSM-only to
            // multimode. If necessary, the RIL must change the setting back.
            if (pHandle->GetMultiModeSetting() == MULTIMODE_CONFIG_LTE)
                (void)QueueInternalCmd(HCCMD_STANDARD, pHandle, "AT^SCFG=MEopMode/AccT,\"GSM/UMTS\"\r", CMDOPT_NONE, APIID_SCFGRADIOBAND, 0, 0, 0);
        }
    }

    return 0;
}

//
// Thread responsible for sending commands from the Command Queue to COM port
//
static DWORD WINAPI SimReadyThreadProc(LPVOID lpParameter)
{
    CRilHandle* pRilDevice = (CRilHandle*)lpParameter;

    if (!SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL))
    {
        return 0;
    }

    const DWORD dwReturn = pRilDevice->SimReadyThread();
    return dwReturn;
}

static HRESULT ParseVeryEarlyRegistrationStatus(LPCSTR szRsp, void*& pBlob, UINT& cbBlob, LPVOID pParam)
{
    CRilHandle *pDevice;
    HRESULT hr = S_OK;
    UINT nMode = 0;
    UINT nStatus = 0;
    BOOL fHandleSREG = FALSE;

    pDevice = (CRilHandle *)pParam;

    pBlob = NULL;
    cbBlob = 0;

    // Parse "<prefix>+CREG: <mode>,<status>,[,<LAC>,<CID>]" (or for CDMA: ^SREG: <mode>,<status>)
    if (!ParseRspPrefix(szRsp, szRsp)                  ||
        !MatchAltStringBeginning(szRsp, "+CREG:", "^SREG:", szRsp, &fHandleSREG) ||
        !ParseUInt(szRsp, TRUE, nMode, szRsp) ||
        !MatchStringBeginning(szRsp, ",", szRsp) ||
        !ParseUInt(szRsp, TRUE, nStatus, szRsp)) {
        hr = E_FAIL;
        goto Error;
    }
    if (NEW_SREG_PARAM && fHandleSREG) {
        UINT nValueEVDO;

        // New ^SREG parameter <statusEVDO>
        if (!MatchStringBeginning(szRsp, ",", szRsp)       ||
            !ParseUInt(szRsp, TRUE, nValueEVDO, szRsp))         {
            hr = E_FAIL;
            goto Error;
        }
        if ((nValueEVDO == 1 || nValueEVDO ==5) && nStatus != 1 && nStatus != 5)
            nStatus = nValueEVDO;
    }

    // Skip rest
    if (!FindRspPostfix(szRsp, szRsp)) {
        hr = E_FAIL;
        goto Error;
    }

    if (NUM_REGSTATS > nStatus && pParam != NULL) {
        DWORD *pdwReg = (DWORD *)pParam;

        *pdwReg= g_rgdwRegStats[nStatus];
    }

Error:
    return hr;
}

//
// Read registry keys needed after the 1st initialization phase. Called when
// RIL checks for PIN status (GSM mode) or when enabling CDMA settings (CDMA
// mode).
//
void CRilHandle::ReadPostInitRegKeys(void)
{
    DWORD dwTemp = 0;

    ReadMiscRegKeys();

    if (!GetRegistryDWORD(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, TEXT("NoCSQinLimitedUrcMode"), &dwTemp))
        dwTemp = 0;
    g_fNoCSQinSuspend = (dwTemp == 1 ? TRUE : FALSE);
    dwTemp = 0;
    if (!GetRegistryDWORD(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, TEXT("SignalStrength3G"), &g_dwSignalStrenth3G))
        g_dwSignalStrenth3G = SS_3G_RSSI;

    if (!GetRegistryDWORD(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, TEXT("UseSMSReplyAddressIncoming"), &g_dwUseReplyAddressIncoming)) {
        g_dwUseReplyAddressIncoming = 0;
    }

    if (!GetRegistryDWORD(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, TEXT("DisableAllSMS"), &g_dwDisableSMS)) {
        g_dwDisableSMS = 0;
    }

    if (!GetRegistryDWORD(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, TEXT("MuteOnVTSDelay"), &m_dwTempMuteDelay)) {
        m_dwTempMuteDelay = 0;
    }

    if (!GetRegistryDWORD(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, TEXT("DisableSyncTime"), &m_dwDisableSyncTime)) {
        m_dwDisableSyncTime = 0;
    }

    if (!GetRegistryDWORD(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, TEXT("Force2GforCSD"), &m_dwForce2GforCSD)) {
        m_dwForce2GforCSD = 0;
    }
    m_fNoAudioForCSD = FALSE;
    if (GetRegistryDWORD(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, TEXT("NoAudioForCSD"), &dwTemp)) {
        m_fNoAudioForCSD = (dwTemp == 1 ? TRUE : FALSE);
    }
}

//
// Activate OMA log
// This is an option only availbale for CDMA provider Sprint
//
void CRilHandle::ActivateOMALOG(void)
{
    DWORD dwReg = 0;
    DWORD dwRetries;
    DWORD dwInterval = 3000;
    DWORD dwPeriodSec = 60; // Default: try for 60 seconds

    // Check im OMA log option is enabled
    (void)GetRegistryDWORD(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, TEXT("ActivateOmaLogSprint"), &dwReg);
    if (dwReg != 1) return;
    // Requires module with multiple CDMA carrier support
    if (!MULTIPLE_CDMA_PRL_LIST) return;
    // Only available on Sprint
    if (_stricmp(m_szCdmaProvider, "Sprint") != 0) return;

    // Calculate timing and retries. Default: try AT command every 3 seconds
    // for up to 60 seconds until command succeeds.
    (void)GetRegistryDWORD(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, TEXT("ActivateOmaLogSprintInterval"), &dwInterval);
    if (dwInterval == 0) dwInterval = 3000;  // Default: try every 3 seconds
    (void)GetRegistryDWORD(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, TEXT("ActivateOmaLogSprintSec"), &dwPeriodSec);
    if (dwPeriodSec == 0) dwPeriodSec = 60;  // Default: try for 60 seconds
    dwRetries = (dwPeriodSec * 1000) / dwInterval;
    // Try to activate OMA log.
    (void)QueueInternalCmd(HCCMD_STANDARD, this, "AT+OMALOG=1\r", CMDOPT_NONE, APIID_NONE, 3000, dwRetries, dwInterval);
    return;
}

//
// Loop until RIL is ready to process SIM commands
//
DWORD CRilHandle::SimReadyThread(void)
{
    APIINFO apiiInfo;
    const APIID apiid = APIID_UNLOCKPHONE;
    DWORD dwSimReadyRetry = 0;
    DWORD dwRegStatus = RIL_REGSTAT_UNKNOWN;
    DWORD dwMaxSimReadyRetries = MAX_SIM_READY_TRIES_DEFAULT;
    DWORD dwDelayCPINcommand = 0;
    char szCmd[MAX_ATCMD_LEN];

    // Create an event
    m_fSimReady = FALSE;
    m_hSimReadyEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
    if (!m_hSimReadyEvent)
    {
        goto Error;
    }

    // Read settings from registry
    ReadPostInitRegKeys();

    if (!GetRegistryDWORD(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, TEXT("DelayFirstCPIN"), &dwDelayCPINcommand)) {
        dwDelayCPINcommand = (DELAY_FOR_FIRST_CPIN ? 8500 : 0);
    }

    if (Force2GforCSD())
        (void)QueueInternalCmd(HCCMD_STANDARD, this, "AT^SCFG=Radio/Band,\"127\",\"1\"\r", CMDOPT_NONE, APIID_SCFGRADIOBAND, 0, 0, 0);

    if (!GetRegistryDWORD(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, TEXT("InitSIMReadyRetries"), &dwMaxSimReadyRetries))
        dwMaxSimReadyRetries = MAX_SIM_READY_TRIES_DEFAULT;

    if (!POSSIBLE_WRONG_SIMNOTINSTERTED_ERROR)
        (void)GetRegistryDWORD(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, TEXT("IgnoreSCKSsupport"), &m_dwIgnoreSCKSsupport);

    (void)GetRegistryDWORD(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, TEXT("ConfigureExtRegStatus"), &m_dwConfigureExtRegStatus);

    (void)GetRegistryDWORD(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, TEXT("ActivateCdmaCellBroadCast"), &g_dwCdmaCBSetting);

    m_fNoNeedForSCKSWorkaround = FALSE;
    m_fReceivedPhoneCallWONumber = FALSE;
    m_fIPUKrequieredAfterPINchange = FALSE;
    m_fGsmUrcsActivated = FALSE;
    m_fCdmaUrcsActivated = FALSE;
    SetIgnoreNextCIEVAudioSounderTimer(0);
	if(UNSUPPORTS_PHONEBOOK){
    	SetPhonebookBlock(TRUE);
	}else{
		SetPhonebookBlock(FALSE);
	}

    // Get the info about this API
    memset(&apiiInfo,0,sizeof(apiiInfo));
    GetAPIInfo(apiid, apiiInfo);

	// From now on emergency calls are possible.
    SetEmergencyReadyState(TRUE, TRUE);

    if (AVOID_SIND_NITZ) {
        // Intel AT command set: NITZ notifiacations must be turned on now.
        DWORD fNitz;
        if (GetRegistryDWORD(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, TEXT("NitzEnable"), &fNitz) && fNitz==1) {
            (void)QueueInternalCmd(HCCMD_STANDARD, this, "AT+CTZR=1\r", CMDOPT_NONE, APIID_UNLOCKPHONE, 0, 0, 0, NULL);
        }
    }

    // Skip this step, if the module supports only CDMA.
    if (!CDMA_ONLY_RADIO) {
        // Check the initialal registration state. This command may fail if the module
        // is currently registered to CDMA.
        if (QueueInternalCmdBlocking(HCCMD_STANDARD, this, "AT+CREG?\r", CMDOPT_NONE, APIID_GETREGISTRATIONSTATUS, 0, 0, 0, ParseVeryEarlyRegistrationStatus, NULL, (LPVOID)&dwRegStatus)) {
            if (dwRegStatus != RIL_REGSTAT_UNKNOWN) {
                g_dwRegStatus = dwRegStatus;
                GenerateRegStatusNotification(dwRegStatus, TRUE);
            }
        }
    }
    // If the module is capable of CDMA, check the CDMA state as well.
    if (GLOBAL_MODE_RADIO || CDMA_ONLY_RADIO) {
        ActivateOMALOG();
        (void)QueueInternalCmdBlocking(HCCMD_STANDARD, this, "AT^SREG=1\r", CMDOPT_NONE, APIID_GETREGISTRATIONSTATUS, 0, 0, 0);

        ConfigureCdmaCellBroadcast(this);

        // If the module not already registered to GSM, check if it is registered to CDMA.
        if (CDMA_ONLY_RADIO || (g_dwRegStatus != RIL_REGSTAT_HOME && g_dwRegStatus != RIL_REGSTAT_ROAMING)) {
            if (QueueInternalCmdBlocking(HCCMD_STANDARD, this, "AT^SREG?\r", CMDOPT_NONE, APIID_GETREGISTRATIONSTATUS, 0, 0, 0, ParseVeryEarlyRegistrationStatus, NULL, (LPVOID)&dwRegStatus)) {
                if (dwRegStatus != RIL_REGSTAT_UNKNOWN) {
                    g_dwRegStatus = dwRegStatus;
                    GenerateRegStatusNotification(dwRegStatus, TRUE);
                    if (g_dwRegStatus == RIL_REGSTAT_HOME || g_dwRegStatus == RIL_REGSTAT_ROAMING)
                        NotifyNewTechnologyMode(TEC_MODE_CDMA);
                }
            }
        }
    }

    // If the module is mconfigured into the CDMA-only mode, there is no PIN, so
    // the following PIN detection phase can be skipped.
    if (GetMultiModeSetting() != MULTIMODE_CONFIG_CDMA) {
        // PXS8: the ^SCKS URC is not activated automatically. This must be done now.
        if (GLOBAL_MODE_RADIO)
            (void)QueueInternalCmd(HCCMD_URCPORT_ONLY, this, "AT^SCKS=1\r", CMDOPT_NONE, APIID_ENABLEDISABLEURCS, 0, 0, 0);

        if (dwDelayCPINcommand > 0) {
            DWORD dwTime;

            dwTime = GetTickCount() - g_PowerManager.GetLastModuleStart();
            if (dwTime < dwDelayCPINcommand) {
                RILRetailTraceZone(ZONE_INFO, (TEXT("RilDrv: Delay AT+CPIN?/^SCKS? by %d ms.\r\n"), dwDelayCPINcommand - dwTime));
                Sleep(dwDelayCPINcommand - dwTime);
            }
        }

        // Some modules allow to set AT+COPS even at this early state.
        if (ALLOW_PRE_PIN_COPS && g_iSetCOPSinInit != NO_INIT_COPS_SETTING) {
            INT iAcT = -1;
            DWORD dwCOPS1InitTimeout = 0;       // Per default: use standard timeout
            UINT nSetRadioBand = 0;
            BOOL bMustResetBand = FALSE;

            RILRetailTraceZone(ZONE_INFO, (TEXT("RilDrv: Perform Pre-PIN AT+COPS setting.\r\n")));

            // If the manual network selection is not allowed, switch to automatic selection.
            if (GetCurrentENSSetting() == ENS_MENU_DISABLED)
                g_iSetCOPSinInit = 0;

            switch (g_n2G3GSelection)
            {
                case SELECTION2G3G_GSM_ONLY:
                    iAcT = 0;
                    break;
                case SELECTION2G3G_UMTS_ONLY:
                    iAcT = 2;
                    break;
                default:
                    iAcT = -1;
            }
#ifdef RIL_WM6_ACT_SELECTION
            // If the WM6 style 2G/3G selection is in use, lpOperatorNames->dwParams may contain the
            // selection of 2G or 3G network type. This setting will overwrite the settings from RIL_DevSpecific
            // option RIL_DEVSPECIFIC_SET2G3GSELECTION.
            if (g_iSetCOPSinInitParams & RIL_PARAM_ON_GSM_ACT) {
                iAcT = 0;
                g_n2G3GSelection = SELECTION2G3G_GSM_ONLY;
            }
            if (g_iSetCOPSinInitParams & RIL_PARAM_ON_UMTS_ACT) {
                iAcT = 2;
                g_n2G3GSelection = SELECTION2G3G_UMTS_ONLY;
            }
#endif
            if (g_iSetCOPSinInit == 0 || g_iSetCOPSinInit == 2) {
                if (iAcT == -1 || g_iSetCOPSinInit == 2 || AVOID_COPS_ACT) {
                    (void)_snprintfz(szCmd, MAX_ATCMD_LEN, "AT+COPS=%u\r", g_iSetCOPSinInit);
                    if (AVOID_COPS_ACT && g_iSetCOPSinInit != 2) {
                        // AT+COPS/<AcT> bug (PXS8): When using the <AcT> parameter of AT+COPS
                        // the module might freeze. As a workaround, the RIL reconfigures the
                        // AT^SCFG=Radio/Band setting to force the module into the correct
                        // access technology.
                        nSetRadioBand = 7679;    // All GSM/UMTS + CDMA bands.
                        if (iAcT == 0)
                            nSetRadioBand = 7183;    // CDMA + GSM
                        else if (iAcT == 2)
                            nSetRadioBand = 7664;    // CDMA + UMTS
                    }
                }
                else {
                    (void)_snprintfz(szCmd, MAX_ATCMD_LEN, "AT+COPS=%u,2,,%d\r", g_iSetCOPSinInit, iAcT);
                }
            }
            else {
                if (g_bNeedAllBandNetworkSelection && g_iSetCOPSinInit == 1)
                {
                    if (NEED_RESET_BAND_SETTINGS_AFTER_SNWS && g_dwAutomaticGroupSearchTimeout == 0)
                        bMustResetBand = TRUE;      // Reset of the radio band settings is necessary.

                    // Please note, that due to a bug in the HC25 we first must set AT+COPS=0
                    // before we can use th AT^SNWS command.
                    if (iAcT == -1)
                        (void)_snprintfz(szCmd, MAX_ATCMD_LEN, "AT%s^SNWS=%u,2,%s\r", (NEED_COPS0_BEFORE_SNWS ? "+COPS=0;" : ""), g_iSetCOPSinInit, g_szSetCOPSinInitOperator);
                    else
                        (void)_snprintfz(szCmd, MAX_ATCMD_LEN, "AT%s^SNWS=%u,2,%s,%d\r", (NEED_COPS0_BEFORE_SNWS ? "+COPS=0;" : ""), g_iSetCOPSinInit, g_szSetCOPSinInitOperator, iAcT);
                    SetNeedBandGroupSearchActivation(TRUE);
                }
                else {
                    if (iAcT == -1 || AVOID_COPS_ACT) {
                        (void)_snprintfz(szCmd, MAX_ATCMD_LEN, "AT+COPS=%u,2,%s\r", g_iSetCOPSinInit, g_szSetCOPSinInitOperator);
                        // AT+COPS/<AcT> bug (PXS8): When using the <AcT> parameter of AT+COPS
                        // the module might freeze. As a workaround, the RIL reconfigures the
                        // AT^SCFG=Radio/Band setting to force the module into the correct
                        // access technology.
                        nSetRadioBand = 7679;    // All GSM/UMTS + CDMA bands.
                        if (iAcT == 0)
                            nSetRadioBand = 7183;    // CDMA + GSM
                        else if (iAcT == 2)
                            nSetRadioBand = 7664;    // CDMA + UMTS
                    }
                    else {
                        (void)_snprintfz(szCmd, MAX_ATCMD_LEN, "AT+COPS=%u,2,%s,%d\r", g_iSetCOPSinInit, g_szSetCOPSinInitOperator, iAcT);
                    }
                }
            }

            g_dwLastKnowBandSelection = 127;
            if (bMustResetBand)
                (void)QueueInternalCmdBlocking(HCCMD_STANDARD, this, "AT^SCFG=\"Radio/Band\"\r", CMDOPT_NONE, APIID_SCFGRADIOBAND, 0, 0, 0, ParseGetCurrentRadioBand);

            if (nSetRadioBand > 0) {
                char szSCFGCmd[MAX_ATCMD_LEN];
                DWORD dwRegRadioBand;

                if (!GetRegistryDWORD(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, TEXT("UseCopsActWorkaround"), &dwRegRadioBand))
                    dwRegRadioBand = 1;
                // Set Radio/Band. Needed for AT+COPS/<AcT> workaround.
                (void)_snprintfz(szSCFGCmd, MAX_ATCMD_LEN, "AT^SCFG=\"Radio/Band\",\"%d\",\"1\"\r", nSetRadioBand);
                if (dwRegRadioBand == 1)
                    (void)QueueInternalCmd(HCCMD_STANDARD, this, szSCFGCmd, CMDOPT_NONE, APIID_SCFGRADIOBAND, 0, 0, 0);
            }

            if (g_iSetCOPSinInit == 1)
            {
                // Potentional problem: if already registered to the network it may be necessary
                // unregister first (NEED_COPS2_BEFORE_COPS1 workaround).
                //
                // Alternative: if the "COPS1InitTimeout" registry key is set, the AT+COPS=1 command
                // will be send with the given (reduced) timeout (recommendation: 3-4 seconds). Since
                // the command won't return, the RIL make a user break and sends the command again.
                //
                if (g_dwRegStatus == RIL_REGSTAT_HOME || g_dwRegStatus == RIL_REGSTAT_ROAMING) {
                    if (NEED_COPS2_BEFORE_COPS1) {
                        GetRegistryDWORD(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, TEXT("COPS1InitTimeout"), &dwCOPS1InitTimeout);
                        // If registry key "COPS1InitTimeout" is not set, unregister from network first.
                        if (dwCOPS1InitTimeout == 0)
                            (void)QueueInternalCmd(HCCMD_STANDARD, this, "AT+COPS=2\r", CMDOPT_NONE, APIID_UNREGISTERFROMNETWORK, 0, 0, 0);
                    }
                }
            }

            (void)QueueInternalCmd(HCCMD_STANDARD, this, szCmd, CMDOPT_NONE, APIID_REGISTERONNETWORK, dwCOPS1InitTimeout, 1, 1000);

            if (bMustResetBand)
            {
                (void)_snprintfz(szCmd, MAX_ATCMD_LEN, "AT^SCFG=\"Radio/Band\",\"%d\"\r", g_dwLastKnowBandSelection);

                (void)QueueInternalCmd(HCCMD_STANDARD, this, szCmd, CMDOPT_NONE, APIID_SCFGRADIOBAND, 0, 0, 0);
            }
            if (COPS_CHANGES_SCFG || (COPS1_CHANGES_SCFG && g_iSetCOPSinInit == 1)) {
                // Bug in PXS8: the use of AT+COPS changes the module from GSM-only to
                // multimode. If necessary, the RIL must change the setting back.
                if (GetMultiModeSetting() == MULTIMODE_CONFIG_LTE)
                    (void)QueueInternalCmd(HCCMD_STANDARD, this, "AT^SCFG=MEopMode/AccT,\"GSM/UMTS\"\r", CMDOPT_NONE, APIID_SCFGRADIOBAND, 0, 0, 0);
            }
        }
        // Query for the PIN until we don't get back 515 as an error
        do
        {
            BOOL bSIMinserted = FALSE;

            if (POSSIBLE_WRONG_SIMNOTINSTERTED_ERROR) {
                if(dwSimReadyRetry < dwMaxSimReadyRetries)
                    (void)QueueInternalCmdBlocking(HCCMD_STANDARD, this, "AT^SCKS?\r", CMDOPT_NONE, APIID_GETPHONELOCKEDSTATE, 0, 0, 0, ParseSCKSResponse, NULL, (LPVOID)&bSIMinserted);
                else
                    m_fNoNeedForSCKSWorkaround = TRUE;
            }

            // Set up a CPIN command to be sent
            // Note that we don't care what the return value is, so long as it's not that the radio isn't ready.
            if (!QueueInternalCmd(HCCMD_STANDARD, this, "AT+CPIN?\r", CMDOPT_SIMQUERY, apiid, 0, 0, 0, ParseGetPhoneLockedState, NULL, (LPVOID)this, NULL, (bSIMinserted || IgnoreSCKSsupport()) ? g_CMET_CPINWithSIM : g_CMET_CPINNoSIM))
            {
                goto Error;
            }

            // Now, block until we get a response back
            (void)WaitForSingleObject(m_hSimReadyEvent, apiiInfo.dwTimeout);

            // Sleep a bit before the next try
            if (!m_fSimReady && !m_fQuitReadyStateThread)
            {
                Sleep(SIM_READY_RETRY_INTERVAL);
                if(dwSimReadyRetry++ > dwMaxSimReadyRetries) break;
            }
        }
        while (!m_fSimReady && !m_fQuitReadyStateThread);

        m_fNoNeedForSCKSWorkaround = TRUE;
        CloseHandle(CreateThread(NULL, 0, ReadECCFilesThread, (LPVOID)this, 0, 0));
    }
    else {
        WCHAR wszCmd[MAX_ATCMD_LEN];

        // CDMA only: set SIM states to "SIM not inserted".
        g_PowerManager.SetPreliminaryURCInitState(TRUE);   // Preliminary URC phase has ended now.
        m_fNoNeedForSCKSWorkaround = TRUE;
        m_nSIMType = SIMTYPE_NOT_INSERTED;
        g_dwSIMLockedState = RIL_LOCKEDSTATE_UNKNOWN;
        NotifyNewTechnologyMode(TEC_MODE_CDMA);
        (void)QueueInternalCmd(HCCMD_URCPORT_ONLY, this, "AT^SLCC=1\r", CMDOPT_NONE, APIID_UNLOCKPHONE, 0, 0, 0);
        (void)QueueInternalCmd(HCCMD_STANDARD, this, "AT+CMGF=0\r", CMDOPT_NONE, APIID_UNLOCKPHONE, 0, 0, 0, NULL);
        (void)QueueInternalCmd(HCCMD_URCPORT_ONLY, this, GetCdmaCnmiSetting(), CMDOPT_NONE, APIID_UNLOCKPHONE, 0, 0, 0);

        (void)g_ComManager.SendUnlockedInitCmds();

        GenerateRegStatusNotification(dwRegStatus, FALSE);
        SendReadyStateNotification(RIL_READYSTATE_SMS|RIL_READYSTATE_UNLOCKED, TRUE);
        UpdateSIMState(RIL_LOCKEDSTATE_READY);

        (void)g_PowerManager.EnterUrcState(NULL, MODEMSTATE_POWERON, TRUE);
        g_PowerManager.SetPreliminaryURCInitState(FALSE);   // Preliminary URC phase has ended now.

        // The RIL just sent the last RIL_READYSTATE_INITIALIZED notification.
        (void)BroadcastDWORDBlobNotification(RIL_NOTIFY_DEVSPECIFIC_LAST_READYSTATE_MSG, LAST_READYSTATE_MSG_FINAL);

        // Optional customer defined AT command
        memset(wszCmd, 0, sizeof(wszCmd));
        if (GetRegistrySZ(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, TEXT("PostSIMInitCommand"), wszCmd, MAX_ATCMD_LEN)) {
            if (wcslen(wszCmd) > 0) {
                _snprintfz(szCmd, MAX_ATCMD_LEN, "%S\r", wszCmd);
                (void)QueueInternalCmd(HCCMD_STANDARD, this, szCmd, CMDOPT_NONE, APIID_DEVSPECIFIC, g_TimeoutCmdInit, 0, 0);
            }
        }
        memset(wszCmd, 0, sizeof(wszCmd));
        if (GetRegistrySZ(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, TEXT("PostSIMInitCommandURC"), wszCmd, MAX_ATCMD_LEN)) {
            if (wcslen(wszCmd) > 0) {
                _snprintfz(szCmd, MAX_ATCMD_LEN, "%S\r", wszCmd);
                (void)QueueInternalCmd(HCCMD_URCPORT_ONLY, this, szCmd, CMDOPT_NONE, APIID_DEVSPECIFIC, g_TimeoutCmdInit, 0, 0);
            }
        }

        // It may be necessary to do some additional audio mode changes, unless a voice call
        // is already ongoing.
        PerformDoubleAudioCheck(this, RIL_AUDIO_HANDSET);
    }

    // If the SIM is currently in the PIN (or PUK) required state, send the necessary notification.
    if (g_dwSIMLockedState == RIL_LOCKEDSTATE_SIM_PIN || g_dwSIMLockedState == RIL_LOCKEDSTATE_SIM_PUK)
        (void)BroadcastDWORDBlobNotification(RIL_NOTIFY_DEVSPECIFIC_LAST_READYSTATE_MSG, LAST_READYSTATE_MSG_PIN);
    if (g_dwSIMLockedState == RIL_LOCKEDSTATE_UNKNOWN && m_nSIMType == SIMTYPE_NOT_INSERTED)
        (void)BroadcastDWORDBlobNotification(RIL_NOTIFY_DEVSPECIFIC_LAST_READYSTATE_MSG, LAST_READYSTATE_MSG_NO_SIM);

    if (m_fQuitReadyStateThread)
    {
        goto Error;
    }

Error:
    if (m_hSimReadyEvent)
    {
        (void)CloseHandle(m_hSimReadyEvent);
        m_hSimReadyEvent = NULL;
    }

    return 0;
}

//
// Launch a thread to see if the SIM is ready or not
//
void CRilHandle::StartReadyStateQuery(void)
{
    m_fQuitReadyStateThread = FALSE;
    HANDLE hThread = CreateThread(NULL, 0, SimReadyThreadProc, (LPVOID)this, 0, NULL);
    if (NULL != hThread)
        (void)CloseHandle(hThread);   // close handle we don't need
}

void CRilHandle::StopReadyStateQuery(void)
{
    m_fQuitReadyStateThread = TRUE;
    if (m_hSimReadyEvent)
    {
        (void)SetEvent(m_hSimReadyEvent);
    }
}

//
// Start initialization
//
BOOL CRilHandle::StartInit(void)
{
    SYNCBLOCK(m_cs);

    DWORD i;
    DWORD dwTemp;
    BOOL fRet = FALSE;
    DWORD dwRHAVersion;

    ReadDebugOptions();
    if (m_fInited)
    {
        fRet = TRUE;
        goto Error;
    }

    // Read parameters from the registry
    g_TimeoutCmdInit = TIMEOUT_CMD_INIT;
    if (GetRegistryDWORD(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, TEXT("TimeoutCmdInit"), &dwTemp))
    {
        g_TimeoutCmdInit = dwTemp;
    }

    g_TimeoutAPIDefault = TIMEOUT_API_DEFAULT;
    if (GetRegistryDWORD(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, TEXT("TimeoutAPIDefault"), &dwTemp))
    {
        g_TimeoutAPIDefault = dwTemp;
    }

    g_dwReceiveCellBroadCast = 2;
#ifdef CSCB_IN_MC75_STYLE
    g_dwReceiveCellBroadCastAccept = 0;
#endif
    g_szReceiveCellBroadCastChannels[0] = '\0';
    g_szReceiveCellBroadCastDCS[0] = '\0';

    // Create required events
    m_hInitEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
    if (!m_hInitEvent) {
        goto Error;
    }
    m_hBlockCmdsEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
    if (!m_hBlockCmdsEvent) {
        goto Error;
    }
    m_hBlockRspsEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
    if (!m_hBlockRspsEvent) {
        goto Error;
    }
    m_pInstances = new CDblList<CRilInstanceHandle>;
    if (!m_pInstances) {
        goto Error;
    }
    m_hAudioModeEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
    if (!m_hAudioModeEvent) {
        goto Error;
    }
    m_hCallStateChangeEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
    if (!m_hCallStateChangeEvent) {
        goto Error;
    }

    // Create the serial ports
    for (i = 0; i < NUMBER_OF_PORTS; i++) {
      m_pComDevice[i] = g_ComManager.CreatePortDevice((COM_PORT_TYPE)i);
      if (!m_pComDevice[i])
      {
        goto Error;
      }
    }

    // Launch the auxiliary threads
    if (!LaunchThreads())
    {
        goto Error;
    }

	// ELSx does't support Audio.
	if (!UNSUPPORTS_AUDIO) {
	    GetAudioConfig();   // Get the audio config from the registry
	}
	
    // Initialize some global variables
    g_fReportLocationUpdateAsRegistrationState = FALSE;
    g_bCINDIsActive = FALSE;
    g_iLastRSSI = 99;
    g_iLastSignal = 99;
    g_dwLastSMSCmd = 0;
    m_fUSSDAnswerMode = FALSE;

    GeneralInitDone(TRUE);

    // Get the RHA version
    (void)RHA_GetRHAVersion(&dwRHAVersion);
    RILRetailTraceZone(ZONE_INFO, (TEXT("RHA version : %d.%d.%d.%d"), (dwRHAVersion>>24)&0xFF, (dwRHAVersion>>16)&0xFF, (dwRHAVersion>>8)&0xFF, dwRHAVersion&0xFF));

    // Register the callback function
    fRet = TRUE;

    Error:
    if (!fRet) {
      for (i = 0; i < NUMBER_OF_PORTS; i++) {
        if (m_pComDevice[i]) {
          (void)g_ComManager.DestroyPortDevice((COM_PORT_TYPE)i);
          m_pComDevice[i] = NULL;
        }
      }
      if (m_hBlockCmdsEvent) {
        (void)CloseHandle(m_hBlockCmdsEvent);
        m_hBlockCmdsEvent = NULL;
      }
      if (m_hBlockRspsEvent) {
        (void)CloseHandle(m_hBlockRspsEvent);
        m_hBlockRspsEvent = NULL;
      }
      if (m_hInitEvent) {
        (void)CloseHandle(m_hInitEvent);
        m_hInitEvent = NULL;
      }
      if (m_hAudioModeEvent) {
        (void)CloseHandle(m_hAudioModeEvent);
        m_hAudioModeEvent = NULL;
      }
      if (m_hCallStateChangeEvent) {
        (void)CloseHandle(m_hCallStateChangeEvent);
        m_hCallStateChangeEvent = NULL;
      }
    }
    return fRet;
}


void CRilHandle::GeneralInitDone(BOOL bSucceeded)
{
    if (bSucceeded)
    {
        m_fInited = TRUE;
    }
    else
    {
        m_fFailedInit = TRUE;
    }

    (void)SetEvent(m_hInitEvent);

    // Now we need to send a notification that we've intiailized properly
    SendReadyStateNotification(RIL_READYSTATE_INITIALIZED, TRUE);
}

//
// Finish intialization
//
void CRilHandle::FinishInit(const CCommand* pInitCmd, BOOL bSucceeded)
{
    if (pInitCmd->FGeneralInit())
    {
        GeneralInitDone(bSucceeded);
    }

    // Allow the module to be turned off from here on
    (void)g_PowerManager.UnlockPowerState();
}


//
// Function passed to CQueue::Enum() below
//
static BOOL GenerateCancelledRsp(void* pItem, DWORD /*dwData*/)
{
    CCommand* pCmd = (CCommand*)pItem;
    //CRilHandle* pRilDevice = (CRilHandle*)dwData;
    HRESULT dwError = RIL_E_CANCELLED;

    // Send out cancelled response as a notification
    pCmd->SendResponse(RIL_RESULT_ERROR, &dwError, sizeof(HRESULT));

    // Continue enumeration
    return FALSE;
}


//
//
//
void CRilHandle::PrepareForReinit(void)
{
    (void)ResetEvent(m_hInitEvent);
    m_fInited = FALSE;
    m_fFailedInit = FALSE;

    // Reset g_dwReadyState
    SendReadyStateNotification(RIL_READYSTATE_NONE, FALSE);

    // Clear the command queue, sending out "cancelled" responses to response callbacks
    // NOTE: The following line has been commented out to prevent commands
    // from being cancelled on start up when the shell turns the radio on.
    //g_pCmdQ[COMMAND_PORT]->Enum(GenerateCancelledRsp, (DWORD)this, TRUE);
}

DWORD CRilHandle::GetSystemTypeFromPSInfo(DWORD dwPSInfo) const
{
    DWORD dwSysType = RIL_SYSTEMTYPE_NONE;  // Default:no network available.

    // Handle unknown "psinfo" values like "no network available".
    if (dwPSInfo >= NUM_PSPINFOS) goto Error;

    // Default: use system type according to the "AT^SIND=psinfo"-> "RIL_SYSTEMTYPE_xxx"
    // translation table.
    dwSysType = g_rgdwPSInfos[dwPSInfo];
    // Special case "psinfo=0": if this appears while the module is registered to GSM network,
    // this means "GSM only" (RIL_SYSTEMTYPE_GSM). In CDMA here should always be an psinfo
    // value while the module is registered, but if it happens use the 1xRTT as default.
    if (dwSysType == RIL_SYSTEMTYPE_NONE && (g_dwRegStatus == RIL_REGSTAT_HOME || g_dwRegStatus == RIL_REGSTAT_ROAMING)) {
        if (GetCurrentTechnology() == TEC_MODE_CDMA)
            dwSysType = RIL_SYSTEMTYPE_1XRTTPACKET;
        else
            dwSysType = RIL_SYSTEMTYPE_GSM;
    }

Error:
    return dwSysType;
}

//
// Launch auxiliary threads
//
BOOL CRilHandle::LaunchThreads(void)
{
    DWORD              i;
    CCheckPoint        CheckPoint;
    QUEUE_THREAD_DATA  CmdData;
    QUEUE_THREAD_DATA  NoopCmdData;
    QUEUE_THREAD_DATA  ReadData[NUMBER_OF_PORTS];
    BOOL               fRet = FALSE;
    HANDLE hThread;

    // Create a cancel event
    m_hCancelEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
    if (!m_hCancelEvent)
    {
        goto Error;
    }

    // Create a hSIMUnlockEvent event
    g_hSIMUnlockEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
    if (!g_hSIMUnlockEvent)
    {
        goto Error;
    }

    // Create a g_hTimeChangeEvent event as system wide named event
    g_hTimeChangeEvent = CreateEvent(NULL, FALSE, FALSE, g_wszTimeChangeEvent);
    if (!g_hTimeChangeEvent)
    {
        goto Error;
    }

    // Create a g_hAckSMSEvent event
    g_hAckSMSEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
    if (!g_hAckSMSEvent)
    {
        goto Error;
    }
    // Create command and response queues
    for (i = 0; i < NUMBER_OF_PORTS; i++) {
      m_pComDevice[i]->SetExternalCancelEvent(m_hCancelEvent);
    }
    if (!g_CmdQ.Init(m_hCancelEvent) || !g_RspQ.Init(m_hCancelEvent) || !g_NoopCmdQ.Init(m_hCancelEvent)) {
      goto Error;
    }

    g_pSimLockedQueue = new CQueue<CCommand, 10>;
    if (!g_pSimLockedQueue || !g_pSimLockedQueue->Init(m_hCancelEvent))
    {
        goto Error;
    }

    // Init checkpoint for read/write threads
    if (!CheckPoint.Init(NUMBER_OF_PORTS + 2))
    {
        goto Error;
    }

    // Launch read/write threads
    CmdData.pRilDevice = this;
    CmdData.pCheckPoint = &CheckPoint;
    CmdData.PortType = (COM_PORT_TYPE)INVALID_PORT;
    m_hCmdThread = CreateThread(NULL, 0, CmdThreadProc, (LPVOID)(&CmdData), 0, NULL);
    if (!m_hCmdThread) {
      goto Error;
    }
    for (i = 0; i < NUMBER_OF_PORTS; i++) {
      ReadData[i].pRilDevice = this;
      ReadData[i].pCheckPoint = &CheckPoint;
      ReadData[i].PortType = (COM_PORT_TYPE)i;
      m_hReadThread[i] = CreateThread(NULL, 0, ReadThreadProc, (LPVOID)(&(ReadData[i])), 0, NULL);
      if (!m_hReadThread[i]) {
        goto Error;
      }
    }
    NoopCmdData.pRilDevice = this;
    NoopCmdData.pCheckPoint = &CheckPoint;
    NoopCmdData.PortType = (COM_PORT_TYPE)INVALID_PORT;
    m_hNoopCmdThread = CreateThread(NULL, 0, NoopCmdThreadProc, (LPVOID)(&NoopCmdData), 0, NULL);
    if (!m_hNoopCmdThread) {
      goto Error;
    }

    // Launch auxiliary threads
    g_hSIMUnlockThread = CreateThread(NULL, 0, SIMUnlockThreadProc, (LPVOID)this, 0, NULL);
    if (!g_hSIMUnlockThread)
    {
        goto Error;
    }

    hThread = CreateThread(NULL, 0, AckSMSThreadProc, (LPVOID)this, 0, NULL);
    if (!hThread)
    {
        goto Error;
    }
    CloseHandle(hThread);

#ifdef RIL_ENABLE_SYNC_TIME
    hThread = CreateThread(NULL, 0, TimeEventThreadProc, (LPVOID)this, 0, NULL);
    if (!hThread)
    {
        goto Error;
    }
    CloseHandle(hThread);
#endif

    // Wait until read/write threads reached the checkpoint
    if (!CheckPoint.Wait(10000))
    {
        goto Error;
    }

    fRet = TRUE;

    Error:
    if (!fRet)
    {
        if (m_hCmdThread) {
          (void)CloseHandle(m_hCmdThread);
          m_hCmdThread = NULL;
        }
        for (i = 0; i < NUMBER_OF_PORTS; i++) {
          if (m_hReadThread[i]) {
            (void)CloseHandle(m_hReadThread[i]);
            m_hReadThread[i] = NULL;
          }
        }
        if (m_hNoopCmdThread) {
          (void)CloseHandle(m_hNoopCmdThread);
          m_hNoopCmdThread = NULL;
        }

        if (g_hTimeChangeEvent)
        {
            (void)CloseHandle(g_hTimeChangeEvent);
            g_hTimeChangeEvent = NULL;
        }
        if (g_hAckSMSEvent)
        {
            (void)CloseHandle(g_hAckSMSEvent);
            g_hAckSMSEvent = NULL;
        }
        if (g_hSIMUnlockEvent)
        {
            (void)CloseHandle(g_hSIMUnlockEvent);
            g_hSIMUnlockEvent = NULL;
        }
        if (g_hSIMUnlockThread)
        {
            (void)CloseHandle(g_hSIMUnlockThread);
            g_hSIMUnlockThread = NULL;
        }

        delete g_pSimLockedQueue;
        g_pSimLockedQueue = NULL;

        if (m_hCancelEvent)
        {
            (void)CloseHandle(m_hCancelEvent);
            m_hCancelEvent = NULL;
        }
    }
    return fRet;
}

DWORD CRilHandle::GetInitSMSTries(void)
{
    DWORD dwSIMTries = 0;

    (void)GetRegistryDWORD(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, TEXT("InitSIMTries"), &dwSIMTries);
    if (dwSIMTries == 0)
        dwSIMTries = 30;

    return dwSIMTries;
}

HRESULT ParseInitialPSInfoError(LPCSTR szRsp, void*& pBlob, UINT& cbBlob, LPVOID pParam, DWORD& dwCode)
{
    DWORD* pdwSystemType = NULL;
    DWORD dwSystemType = RIL_SYSTEMTYPE_1XEVDOPACKET;
    DWORD dwSystemCaps = RIL_SYSTEMCAPS_VOICEDATA;
    CRilHandle *pDevice;

    pDevice = (CRilHandle *)pParam;

    (void)GetRegistryDWORD(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, TEXT("DefaultCDMATechnology"), &dwSystemType);
    (void)GetRegistryDWORD(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, TEXT("DefaultCDMATechnologyCaps"), &dwSystemCaps);

    if (szRsp != NULL && NO_SIND_PSINFO_IN_CDMA) {
        // Bug in PXS8 2.821: The module doesn't report the current CDMA network
        // technology. If this is the case the RIL must return a reasonable default
        // value instead.
        if (strstr(szRsp, "CME ERROR: 370") != NULL) {
            // Since this isn't an error, we reconfigure this response to be an 'OK' instead.
            if (pBlob != NULL)
                (void)FreeBlob(pBlob);
            pdwSystemType = (DWORD*)AllocBlob(sizeof(DWORD));
            *pdwSystemType = dwSystemType;
            pBlob = (void*)pdwSystemType;
            cbBlob = sizeof(DWORD);
            dwCode = RIL_RESULT_OK;
            if (pDevice != NULL)  {
                (void)pDevice->BroadcastDWORDBlobNotification(RIL_NOTIFY_SYSTEMCHANGED, dwSystemType);
                (void)pDevice->BroadcastDWORDBlobNotification(RIL_NOTIFY_SYSTEMCAPSCHANGED, dwSystemCaps);
            }
        }
    }
    return S_OK;
}

static HRESULT ParseInitialPSInfoInternal(BOOL fReturnValue, LPCSTR szRsp, void*& pBlob, UINT& cbBlob, CRilHandle *pDevice)
{
    DWORD* pdwSystemType = NULL;
    UINT nValue;
    HRESULT hr = S_OK;

    pBlob = NULL;
    cbBlob = 0;

    // Parse "<prefix>^SIND: psinfo,<mode>"
    if (!ParseRspPrefix(szRsp, szRsp)                  ||
        !MatchStringBeginning(szRsp, "^SIND: psinfo,", szRsp) ||
        !ParseUInt(szRsp, TRUE, nValue, szRsp)) {
        hr = E_FAIL;
        goto Error;
    }

    if (!MatchStringBeginning(szRsp, ",", szRsp)) {
        goto Error;
    }

    // Parse "<status>"
    if (!ParseUInt(szRsp, TRUE, nValue, szRsp)) {
        hr = E_FAIL;
        goto Error;
    }

    // Parse "<postfix>"
    if (!ParseRspPostfix(szRsp, szRsp)) {
        hr = E_FAIL;
        goto Error;
    }

    if (!fReturnValue)
        nValue = pDevice->GetCorrectNetworkTechnology(nValue);

    if (nValue < NUM_PSPINFOS)
    {
        // Special case: CDMA icon during active voice call must show 1xRTT even
        // when AT^SIND=psinfo reports EVDO.
        if (MISSING_1XRTT_INDICATION_FOR_CDMA_VC && pDevice->GetCurrentTechnology() == TEC_MODE_CDMA) {
            DWORD dwReg = 1;

            (void)GetRegistryDWORD(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, TEXT("CdmaSwitch1xRTTVoiceCall"), &dwReg);
            if (dwReg == 1) {
                BOOL bCallActive = FALSE;
                INT iCall;

                // Check if there is currently any voice call active.
                EnterCriticalSection(&g_CallInfoSection);
                if (g_iNrCallInfo > 0) {
                    for (iCall=0; iCall < g_iNrCallInfo; iCall++) {
                        if (g_CallInfo[iCall].dwType == RIL_CALLTYPE_VOICE) {
                            bCallActive = TRUE;
                            break;
                        }
                    }
                }
                LeaveCriticalSection(&g_CallInfoSection);
                // If a voice call is active, always report 1xRTT instead of EVDO.
                if (bCallActive)
                    nValue = 11;   // 11 = 1xRTT
            }
        }
        if (!fReturnValue) {
            (void)pDevice->BroadcastDWORDBlobNotification(RIL_NOTIFY_SYSTEMCHANGED, pDevice->GetSystemTypeFromPSInfo(nValue));
            (void)pDevice->BroadcastDWORDBlobNotification(RIL_NOTIFY_SYSTEMCAPSCHANGED, g_rgdwPSCaps[nValue]);
        }
    }

    if (fReturnValue)
    {
        pdwSystemType = (DWORD*)AllocBlob(sizeof(DWORD));
        if (!pdwSystemType)
        {
            hr = E_OUTOFMEMORY;
            goto Error;
        }
        memset(pdwSystemType, 0x00, sizeof(DWORD));

        *pdwSystemType = pDevice->GetSystemTypeFromPSInfo(nValue);

        pBlob = (void*)pdwSystemType;
        cbBlob = sizeof(DWORD);
    }

Error:
    if (FAILED(hr) && pdwSystemType != NULL)
    {
        (void)FreeBlob(pdwSystemType);
    }
    return hr;
}

HRESULT ParseInitialPSInfo(LPCSTR szRsp, void*& pBlob, UINT& cbBlob, LPVOID pParam)
{
    if (pParam == NULL) {
        pBlob = NULL;
        cbBlob = 0;
        return E_FAIL;
    }
    return ParseInitialPSInfoInternal(FALSE, szRsp, pBlob, cbBlob, (CRilHandle *)pParam);
}

HRESULT ParseInitialPSInfoCS(LPCSTR szRsp, void*& pBlob, UINT& cbBlob, LPVOID pParam)
{
    if (pParam == NULL) {
        pBlob = NULL;
        cbBlob = 0;
        return E_FAIL;
    }
    return ParseInitialPSInfoInternal(TRUE, szRsp, pBlob, cbBlob, (CRilHandle *)pParam);
}

#ifdef SUPPORTS_EHSX_R1
HRESULT ParseInitialXREGInfo(LPCSTR szRsp, void*& pBlob, UINT& cbBlob, LPVOID pParam)
{
    DWORD* pdwSystemType = NULL;
    CRilHandle *pDevice;
    char szBand[MAXLENGTH_OPERATOR_LONG];
    UINT nValue, nState;
    HRESULT hr = S_OK;

    pDevice = (CRilHandle *)pParam;
    pBlob = NULL;
    cbBlob = 0;
    memset(szBand, 0, MAXLENGTH_OPERATOR_LONG);

    // Parse "<prefix>+XREG: <mode>"
    if (!ParseRspPrefix(szRsp, szRsp)                  ||
        !MatchStringBeginning(szRsp, "+XREG: ", szRsp) ||
        !ParseUInt(szRsp, TRUE, nValue, szRsp)) {
        hr = E_FAIL;
        goto Error;
    }

    if (!MatchStringBeginning(szRsp, ",", szRsp)) {
        goto Error;
    }

    // Parse "<state>"
    if (!ParseUInt(szRsp, TRUE, nState, szRsp)) {
        hr = E_FAIL;
        goto Error;
    }

    if (!MatchStringBeginning(szRsp, ",", szRsp)) {
        goto Error;
    }

    // Parse "<band>"
    if (!ParseUnquotedString(szRsp, '\r', szBand, MAXLENGTH_OPERATOR_LONG, szRsp)) {
        hr = E_FAIL;
        goto Error;
    }

    // Parse "<postfix>"
    if (!ParseRspPostfix(szRsp, szRsp)) {
        hr = E_FAIL;
        goto Error;
    }

    // Convert the EHS5 <state> values to the PH8 style <value>
    switch (nState) {
        case 1:             // GPRS
            nValue = 2;
            break;
        case 2:             // EDGE
            nValue = 4;
            break;
        case 3:             // UMTS
            nValue = 6;
            break;
        case 4:             // HSDPA
            nValue = 8;
            break;
        case 5:             // HSUPA
        case 6:             // HSPA
            nValue = 10;
            break;
        default:
            nValue = 0;
    }

    if (pDevice != NULL)
        nValue = pDevice->GetCorrectNetworkTechnology(nValue);

    if (nValue < NUM_PSPINFOS && pDevice != NULL)
    {
        (void)pDevice->BroadcastDWORDBlobNotification(RIL_NOTIFY_SYSTEMCHANGED, pDevice->GetSystemTypeFromPSInfo(nValue));
        (void)pDevice->BroadcastDWORDBlobNotification(RIL_NOTIFY_SYSTEMCAPSCHANGED, g_rgdwPSCaps[nValue]);
    }

    if (pDevice == NULL)
    {
        pdwSystemType = (DWORD*)AllocBlob(sizeof(DWORD));
        if (!pdwSystemType)
        {
            hr = E_OUTOFMEMORY;
            goto Error;
        }
        memset(pdwSystemType, 0x00, sizeof(DWORD));

        *pdwSystemType = pDevice->GetSystemTypeFromPSInfo(nValue);

        pBlob = (void*)pdwSystemType;
        cbBlob = sizeof(DWORD);
    }

Error:
    if (FAILED(hr) && pdwSystemType != NULL)
    {
        (void)FreeBlob(pdwSystemType);
    }
    return hr;
}
#endif

#if defined(RIL_NOTIFY_NITZ)
HRESULT ParseInitialNITZState(LPCSTR szRsp, void*& pBlob, UINT& cbBlob, LPVOID pParam)
{
    LPCSTR szDummy;
    CRilHandle *pDevice;
    UINT nValue;
    UINT nTimeZone= 0;
    UINT nDayLightSaving = 0;
    BOOL bIsDLSset = FALSE;
    HRESULT hr = S_OK;
    RILNITZINFO oNITZ;
    WCHAR wszTime[NITZ_TIME_STRING_LEN];
    char szTemp[MAX_ATCMD_LEN];
    BOOL bOK = FALSE;

    pDevice = (CRilHandle *)pParam;

    if (pDevice != NULL)
        pDevice->SetNITZactive(TRUE);

    pBlob = NULL;
    cbBlob = 0;
    memset(wszTime, 0, sizeof(wszTime));
    memset(&oNITZ, 0, sizeof(RILNITZINFO));
    memset(szTemp, 0, sizeof(szTemp));

    // Parse "<prefix>^SIND: nitz,<mode>"
    if (!ParseRspPrefix(szRsp, szRsp)                  ||
        !MatchStringBeginning(szRsp, "^SIND: nitz,", szRsp) ||
        !ParseUInt(szRsp, TRUE, nValue, szRsp)) {
        hr = E_FAIL;
        goto Error;
    }

    // Parse "<time>"
    if (!MatchStringBeginning(szRsp, ",", szRsp) ||
         !ParseString(szRsp, szTemp, MAX_ATCMD_LEN, szDummy)) {
        hr = E_FAIL;
        goto Error;
    }

    if ((strlen(szTemp) % 4) == 0) {    // We got an URC in UCS2 format
        bOK = ParseUCS2String(szRsp, wszTime, NITZ_TIME_STRING_LEN, szRsp);
    }
    else {      // String is in GSM format
        if (strlen(szTemp) <= NITZ_TIME_STRING_LEN) {
            bOK = ParseString(szRsp, szTemp, MAX_ATCMD_LEN, szRsp);
            (void)_snwprintfz(wszTime, NITZ_TIME_STRING_LEN, L"%S", szTemp);
            bOK = TRUE;
        }
    }
    if (!bOK) {
        hr = E_FAIL;
        goto Error;
    }

    // Parse "<timezoneoffset>"
    if (!MatchStringBeginning(szRsp, ",", szRsp) ||
         !ParseIntAsUInt(szRsp, nTimeZone, szRsp, TRUE)) {
        hr = E_FAIL;
        goto Error;
    }

    // Parse "<daylightsavingoffset>"
    if (MatchStringBeginning(szRsp, ",", szRsp))
    {
         bIsDLSset = ParseIntAsUInt(szRsp, nDayLightSaving, szRsp);
         if (bIsDLSset) pDevice->StoreNitzDST(nDayLightSaving);
    }
    if (!bIsDLSset)
        bIsDLSset = pDevice->GetStoredNitzDST(&nDayLightSaving);

    // Parse "<postfix>"
    if (!ParseRspPostfix(szRsp, szRsp)) {
        hr = E_FAIL;
        goto Error;
    }

    if (wcslen(wszTime) > 0 && pDevice != NULL)   // Empty time string means, no NITZ message so far, so we do not need to report any timezone information
    {
        CNotificationData *pnd;

        oNITZ.cbSize = sizeof(RILNITZINFO);
        if (CDMA_NITZ_TZ_IN_60_MINUTES && pDevice->GetCurrentTechnology() == TEC_MODE_CDMA)
            oNITZ.TimeZoneOffsetMinutes = 60 * (int)nTimeZone;
        else
            oNITZ.TimeZoneOffsetMinutes = 15 * (int)nTimeZone;
        oNITZ.DaylightSavingOffsetMinutes = 0;
        oNITZ.dwParams = RIL_PARAM_NITZ_TIMEZONEOFFSET|RIL_PARAM_NITZ_DAYLIGHTSAVINGOFFSET;
        if (bIsDLSset)
        {
            oNITZ.DaylightSavingOffsetMinutes = 60 * (int)nDayLightSaving;
            if (CDMA_NITZ_TZ_IN_60_MINUTES && pDevice->GetCurrentTechnology() == TEC_MODE_CDMA)
                oNITZ.TimeZoneOffsetMinutes = oNITZ.TimeZoneOffsetMinutes - oNITZ.DaylightSavingOffsetMinutes;
        }
        oNITZ.dwNotificationCode = RIL_NOTIFY_NITZ;
        // We will not use the reported time, since we don't know, how old this time info might be, but
        // if it is defined by a registry key, it might be used anyhow.
        if (g_dwSendNITZTime == 1)
        {
            if (ParseSystemTimeNITZ(&oNITZ.SysTime, wszTime))
                oNITZ.dwParams |= RIL_PARAM_NITZ_SYSTEMTIME;
        }
        g_dwSendNITZTime = 0;

        pnd = new CNotificationData;
        if (pnd)
        {
            (void)pnd->InitFromRealBlob(RIL_NOTIFY_NITZ, &oNITZ, oNITZ.cbSize);
            pDevice->BroadcastNotification(pnd);
        }
     }

Error:
    return hr;
}
#endif

HRESULT ParseSIMStatus(LPCSTR szRsp, void*& pBlob, UINT& cbBlob, LPVOID /*pParam*/)
{
    UINT nValue;
    HRESULT hr = S_OK;

    pBlob = NULL;
    cbBlob = 0;

    // Parse "<prefix>^SIND: simstatus,<mode>"
    if (!ParseRspPrefix(szRsp, szRsp)                  ||
        !MatchStringBeginning(szRsp, "^SIND: simstatus,", szRsp) ||
        !ParseUInt(szRsp, TRUE, nValue, szRsp)) {
        hr = E_FAIL;
        goto Error;
    }

    if (!MatchStringBeginning(szRsp, ",", szRsp)) {
        goto Error;
    }

    // Parse "<status>"
    if (!ParseUInt(szRsp, TRUE, nValue, szRsp)) {
        hr = E_FAIL;
        goto Error;
    }

    g_iCurrentSIMStatus = nValue;

    // Parse "<postfix>"
    if (!ParseRspPostfix(szRsp, szRsp)) {
        hr = E_FAIL;
        goto Error;
    }

Error:
    return hr;
}

#ifdef RIL_USE_CSQ_NOTIFICATIONS
//
// Needed for very first signal strength query after PIN entry.
// Parses the AT+CSQ response and generates a notification.
//
static HRESULT ParseEarlySignalStrength(LPCSTR szRsp, void*& pBlob, UINT& cbBlob, LPVOID pParam)
{
    UINT nRSSI, nBER;

    pBlob = NULL;
    cbBlob = 0;

    // Parse "<prefix>+CSQ: <rssi>,<ber><postfix>"
    if (!ParseRspPrefix(szRsp, szRsp)                             ||
      !MatchStringBeginning(szRsp, "+CSQ: ", szRsp)             ||
      !ParseUIntAndVerifyAbove(szRsp, TRUE, 100, nRSSI, szRsp)  ||
      !MatchStringBeginning(szRsp, ",", szRsp)                  ||
      !ParseUInt(szRsp, TRUE, nBER, szRsp)                      ||
      !ParseRspPostfix(szRsp, szRsp)) {
        goto Error;
    }

    // Store the aquired values for later use.
    g_nRSSI = nRSSI;
    g_nBER = nBER;

    if (nRSSI == 99) {
        g_iLastRSSI = nRSSI;
    } else {
        g_iLastRSSI = ((2 * nRSSI) + 7) / 15;
        if (g_iLastRSSI > 5)
            g_iLastRSSI = 5;
    }
    g_iLastSignal = nBER;
    g_bCINDIsActive = TRUE;     // flag for RIL_GetSignalQuality to use stored values now.

    if (!ParseRSSIFromSMONI(szRsp, nRSSI)) {
        goto Error;
    }

    if (pParam != NULL) {
        // Send a notification about the detected signal strength-
        CNotificationData* pnd = NULL;
        RILSIGNALQUALITY rsq;
        CRilHandle* pHandle;

        pHandle = (CRilHandle *)pParam;

        FillRSQStruct(&rsq);
        pnd = new CNotificationData;
        if (pnd)
        {
            if (pnd->InitFromRealBlob(RIL_NOTIFY_SIGNALQUALITY, (void*)&rsq, rsq.cbSize))
                pHandle->BroadcastNotification(pnd);
            else
                delete pnd;
        }
    }
Error:
    return S_OK;
}

static HRESULT ParseEarlySignalStrengthSIND(LPCSTR szRsp, void*& pBlob, UINT& cbBlob, LPVOID pParam)
{
    UINT nRSSI, nBER = 99, nRSSISIND, nDummy;

    pBlob = NULL;
    cbBlob = 0;

    // Parse "<prefix>^SIND: rssi,<n>,<rssi><postfix>"
    if (!ParseRspPrefix(szRsp, szRsp)                             ||
      !MatchStringBeginning(szRsp, "^SIND: rssi,", szRsp)             ||
      !ParseUInt(szRsp, FALSE, nDummy, szRsp) ||
      !MatchStringBeginning(szRsp, ",", szRsp)                 ||
      !ParseUInt(szRsp, TRUE, nRSSISIND, szRsp)                     ||
      !ParseRspPostfix(szRsp, szRsp)) {
        goto Error;
    }
    nRSSI = GetRSSIfromCINDvalue(nRSSISIND);

    if (!ParseRSSIFromSMONI(szRsp, nRSSI)) {
        goto Error;
    }

    // Store the aquired values for later use.
    g_nRSSI = nRSSI;
    g_nBER = nBER;

    if (nRSSI == 99) {
        g_iLastRSSI = nRSSI;
    } else {
        g_iLastRSSI = ((2 * nRSSI) + 7) / 15;
        if (g_iLastRSSI > 5)
            g_iLastRSSI = 5;
    }
    g_iLastSignal = nBER;
    g_bCINDIsActive = TRUE;     // flag for RIL_GetSignalQuality to use stored values now.

    if (pParam != NULL) {
        // Send a notification about the detected signal strength-
        CNotificationData* pnd = NULL;
        RILSIGNALQUALITY rsq;
        CRilHandle* pHandle;

        pHandle = (CRilHandle *)pParam;

        FillRSQStruct(&rsq);
        pnd = new CNotificationData;
        if (pnd)
        {
            if (pnd->InitFromRealBlob(RIL_NOTIFY_SIGNALQUALITY, (void*)&rsq, rsq.cbSize))
                pHandle->BroadcastNotification(pnd);
            else
                delete pnd;
        }
    }
Error:
    return S_OK;
}

static HRESULT ParseEarlySignalStrengthSINDError(LPCSTR szRsp, void*& pBlob, UINT& cbBlob, LPVOID pParam, DWORD& dwCode)
{
    HRESULT hr = E_FAIL;
    void* pBlobTmp = NULL;
    UINT cbBlobTmp = 0;

    // If there is no response string, the radio is currently off.
    if (szRsp == NULL)
        return RIL_E_RADIOOFF;

    hr = ParseEarlySignalStrengthSIND(szRsp, pBlobTmp, cbBlobTmp, pParam);
    if (SUCCEEDED(hr)) {
        if (pBlob != NULL)
            (void)FreeBlob(pBlob);
        pBlob = pBlobTmp;
        cbBlob = cbBlobTmp;
        dwCode = RIL_RESULT_OK;
    }
    return hr;
}
#endif

static HRESULT ParseEarlyRegistrationStatus(LPCSTR szRsp, void*& pBlob, UINT& cbBlob, LPVOID pParam)
{
    CRilHandle *pDevice;
    HRESULT hr = S_OK;
    UINT nMode = 0;
    UINT nStatus = 0;

    pDevice = (CRilHandle *)pParam;

    pBlob = NULL;
    cbBlob = 0;

    // Parse "<prefix>+CREG: <mode>,<status>,[,<LAC>,<CID>]"
    if (!ParseRspPrefix(szRsp, szRsp)                  ||
        !MatchStringBeginning(szRsp, "+CREG:", szRsp) ||
        !ParseUInt(szRsp, TRUE, nMode, szRsp) ||
        !MatchStringBeginning(szRsp, ",", szRsp) ||
        !ParseUInt(szRsp, TRUE, nStatus, szRsp)) {
        hr = E_FAIL;
        goto Error;
    }

    // Skip rest
    if (!FindRspPostfix(szRsp, szRsp)) {
        hr = E_FAIL;
        goto Error;
    }

    if (NUM_REGSTATS > nStatus) {
        g_dwRegStatus = g_rgdwRegStats[nStatus];

        if(g_bFakeRegStatusDeniedToHome && (g_rgdwRegStats[nStatus] == RIL_REGSTAT_DENIED))
            g_dwGPRSRegStatus = RIL_REGSTAT_HOME;
    }
    else
        g_dwRegStatus = RIL_REGSTAT_UNKNOWN;

    // Special check (needed for +CREG only): any "+CREG: 3" (access denied) is followed by a "+CREG: 0", which is
    // not correct. As a solution the RIL will still report "access denied" until the module has been registered to a
    // network, the SIM is removed or the module has been resetted.
    if (g_dwRegStatus == RIL_REGSTAT_DENIED && CREG0_FOLLOWS_CREG3)
        g_fRegStatus3detected = TRUE;
    if ((g_dwRegStatus == RIL_REGSTAT_UNREGISTERED || g_dwRegStatus == RIL_REGSTAT_ATTEMPTING) && g_fRegStatus3detected)
        g_dwRegStatus = RIL_REGSTAT_DENIED;
    if (g_dwRegStatus == RIL_REGSTAT_HOME || g_dwRegStatus == RIL_REGSTAT_ROAMING)
        g_fRegStatus3detected = FALSE;

    if (g_dwRegStatus == RIL_REGSTAT_ROAMING && pDevice->NeedsCheckForNoRoamingNetwork())
        CloseHandle(CreateThread(NULL, 0, CheckRoamingNetworkThreadProc, (LPVOID)pDevice, 0, 0));
    else
        pDevice->GenerateRegStatusNotification(g_dwRegStatus);

#ifdef RIL_USE_CSQ_NOTIFICATIONS
    if (pDevice != NULL && (g_dwRegStatus == RIL_REGSTAT_HOME || g_dwRegStatus == RIL_REGSTAT_ROAMING)) {
        // Module is already registered, but currently the signal strength URCs are off, so the RIL
        // must query the signal strength using AT+CSQ.
        if (USE_CSQ_READ && !SUBSTITUTE_CSQ_WITH_SIND && pDevice->GetCurrentTechnology() == TEC_MODE_CDMA)
            (void)QueueInternalCmd(HCCMD_STANDARD, pDevice, "AT+CSQ?\r", CMDOPT_NONE, APIID_GETSIGNALQUALITY, 0, 0, 0, ParseEarlySignalStrength, NULL, pParam);
        else if (!SUBSTITUTE_CSQ_WITH_SIND || pDevice->GetMultiModeSetting() != MULTIMODE_CONFIG_CDMA)
            (void)QueueInternalCmd(HCCMD_STANDARD, pDevice, "AT+CSQ\r", CMDOPT_NONE, APIID_GETSIGNALQUALITY, 0, 0, 0, ParseEarlySignalStrength, NULL, pParam);
        else
            (void)QueueInternalCmd(HCCMD_STANDARD, pDevice, "AT^SIND=rssi,2;^SMONI\r", CMDOPT_NONE, APIID_GETSIGNALQUALITY, 0, 0, 0, ParseEarlySignalStrengthSIND, ParseEarlySignalStrengthSINDError, pParam);
    }
#endif

Error:
    return hr;
}

static HRESULT ParseInitialSmsFull(LPCSTR szRsp, void*& pBlob, UINT& cbBlob, LPVOID pParam)
{
    UINT nSMSfull, nDummy;

    pBlob = NULL;
    cbBlob = 0;

    // Parse "<prefix>^SIND: smsfull,<n>,<rssi><postfix>"
    if (!ParseRspPrefix(szRsp, szRsp)                             ||
      !MatchStringBeginning(szRsp, "^SIND: smsfull,", szRsp)             ||
      !ParseUInt(szRsp, FALSE, nDummy, szRsp) ||
      !MatchStringBeginning(szRsp, ",", szRsp)                 ||
      !ParseUInt(szRsp, TRUE, nSMSfull, szRsp)                     ||
      !ParseRspPostfix(szRsp, szRsp)) {
        goto Error;
    }

    if (pParam != NULL && nSMSfull == 1) {
        // Send a notification about the SMS full status.
        CRilHandle* pHandle;

        pHandle = (CRilHandle *)pParam;

        pHandle->BroadcastDWORDBlobNotification(RIL_NOTIFY_SIMSTATUSCHANGED, RIL_SIMSTATUSCHANGED_FULL);
    }
Error:
    return S_OK;
}

static HRESULT ParseCSMSError(LPCSTR szRsp, void*& /*pBlob*/, UINT& /*cbBlob*/, LPVOID pParam, DWORD& /*dwCode*/)
{
    BOOL *pCDMA = (BOOL *)pParam;

    if (szRsp != NULL) {
        // If there is a CME error 370 it means, that the radio is in CDMA mode, but no
        // ^SREG: 1 URC showed up so far.
        if (strstr(szRsp, "+CME ERROR: 370") != NULL) {
            *pCDMA = TRUE;
        }
    }

    return S_OK;
}
//
// This function get the current IMS registry status.
//
static HRESULT ParseGetIMSRegistryInfo(LPCSTR szRsp, void*& pBlob, UINT& cbBlob, LPVOID pParam)
{

    DWORD* pdwIMSState = NULL;
    CRilHandle *pDevice;

    UINT nValue = 0, nState = 0;
    HRESULT hr = S_OK;

    pDevice = (CRilHandle *)pParam;
    pBlob = NULL;
    cbBlob = 0;
 
    // Parse "<prefix>+CIREG: <n>"
    if (!ParseRspPrefix(szRsp, szRsp)                  ||
        !MatchStringBeginning(szRsp, "+CIREG: ", szRsp) ||
        !ParseUInt(szRsp, TRUE, nValue, szRsp)) {
        hr = E_FAIL;
        goto Error;
    }

    if (!MatchStringBeginning(szRsp, ",", szRsp)) {
        goto Error;
    }

    // Parse "<reg_info>"
    if (!ParseUInt(szRsp, TRUE, nState, szRsp)) {
        hr = E_FAIL;
        goto Error;
    }
	
    if (pDevice == NULL)
    {
        pdwIMSState = (DWORD*)AllocBlob(sizeof(DWORD));
        if (!pdwIMSState)
        {
            hr = E_OUTOFMEMORY;
            goto Error;
        }
        memset(pdwIMSState, 0x00, sizeof(DWORD));

        *pdwIMSState = nState;

        pBlob = (void*)pdwIMSState;
        cbBlob = sizeof(DWORD);
    }
	
Error:
    if (FAILED(hr) && pdwIMSState != NULL)
    {
        (void)FreeBlob(pdwIMSState);
    }
    return hr;
}
//
// Init NITZ URCs (if configured). Also checks, if there has been a missed NITZ
// URC. In case of a missed NITZ URC, the RIL will send the notification now.
//
void CRilHandle::InitializeNITZ(void)
{
#ifdef RIL_NOTIFY_NITZ
    // Since the network sends NITZ notifications very early, the NITZ URC is the first to be activated.
    DWORD fNitz;

    // Module with Intel AT commands already have activated their URC by now.
    if (GetRegistryDWORD(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, TEXT("NitzEnable"), &fNitz) && fNitz==1 && !AVOID_SIND_NITZ) {
        g_dwSendNITZTime = 0;
        (void)GetRegistryDWORD(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, TEXT("UseNITZTimeAtStartup"), &g_dwSendNITZTime);
        // Activate NITZ, if supported.
        if (!NO_SIND_NITZ_IN_CDMA || GetCurrentTechnology() != TEC_MODE_CDMA)
          (void)QueueInternalCmd(HCCMD_STANDARD, this, "AT^SIND=nitz,1\r", CMDOPT_NONE, APIID_UNLOCKPHONE, 0, 0, 0, ParseInitialNITZState, NULL, (LPVOID)this);
    }
#endif
    return;
}

//
// Relevant for CDMA networks: the daylight saving time (DST) is only reported
// via 1xRTT, but not via EVDO. To solve this, the RIL will save the 1xRTT DST
// value an uses it, when an EVDO NITZ message appears.
//
void CRilHandle::StoreNitzDST(UINT nDST)
{
    DWORD dwReg = 1;

    (void)GetRegistryDWORD(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, TEXT("CdmaStoreNitzDstValue"), &dwReg);
    if (dwReg == 1 && GetCurrentTechnology() == TEC_MODE_CDMA) {
        // Store current DST to be used if later a Nitz message without DST appears.
        m_nStoredDST = nDST;
    }
    else {
        // Feature turned off, delete current DST value.
        m_nStoredDST = MAXDWORD;
    }
}

//
// Return stored DST value (if available).
//
BOOL CRilHandle::GetStoredNitzDST(UINT *pnDST) const
{
    BOOL fRet = FALSE;

    if (m_nStoredDST != MAXDWORD) {
        fRet = TRUE;
        *pnDST = m_nStoredDST;
    }
    return fRet;
}


void CRilHandle::SignalInternalSIMReady(void)
{
    if (m_hInternalSimReadyEvent != NULL)
        (void)SetEvent(m_hInternalSimReadyEvent);
}

void CRilHandle::SignalAbortInternalSIMReady(void)
{
    if (m_hAbortInternalSimReadyEvent != NULL)
        (void)SetEvent(m_hAbortInternalSimReadyEvent);
}

void CRilHandle::SignalAudioModeEvent(void)
{
    if (m_hAudioModeEvent != NULL)
        (void)SetEvent(m_hAudioModeEvent);
}

void CRilHandle::WaitAudioModeEvent(DWORD dwTimeout)
{
    (void)WaitForSingleObject(m_hAudioModeEvent, dwTimeout);
}

BOOL CRilHandle::WaitForSIMInit(void)
{
    BOOL bOK = FALSE;
    DWORD dwTimeout = 0;

    g_iCurrentSIMStatus = 0;
    m_hInternalSimReadyEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
    if (!m_hInternalSimReadyEvent) {
        goto Error;
    }
    m_hAbortInternalSimReadyEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
    if (!m_hAbortInternalSimReadyEvent) {
        goto Error;
    }
    (void)GetRegistryDWORD(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, TEXT("WaitForSIMInitialization"), &dwTimeout);
    if (dwTimeout == 0)
        dwTimeout = SIMINIT_TIMEOUT;
    if (EXTENDED_SIM_INIT_TIMEOUT && dwTimeout > SIMINIT_TIMEOUT_INTEL)
        dwTimeout = SIMINIT_TIMEOUT_INTEL;

    g_PowerManager.SetPreliminaryURCInitState(TRUE);    // Preliminary URCs (in this case, the simstatus URC) are now on.
    if (!USE_POLLING_FOR_SIM_READY && !USE_PBREADY_URC) {
        if (!QueueInternalCmdBlocking(HCCMD_STANDARD, this, "AT^SIND=simstatus,1\r", CMDOPT_NONE, APIID_UNLOCKPHONE, 0, 0, 0, ParseSIMStatus))
            goto Error;
    }

    if (m_fNextSIMStatusIsWorng || CIEV_SIMSTATUS_UNRELIABLE)
    {
        // The AT^SIND=simstatus has returned a wrong value, so the RIL must use polling instead.
        bOK = TRUE;
        m_fNextSIMStatusIsWorng = FALSE;        // Next time the status report should be OK again.
        (void)QueueInternalCmdBlocking(HCCMD_STANDARD, this, "AT+CPBS=\"SM\"\r", CMDOPT_NONE, APIID_SETPHONEBOOKOPTIONS, 0, dwTimeout/SIM_INIT_POLLING_INTERVAL, SIM_INIT_POLLING_INTERVAL, NULL, NULL, NULL, NULL, g_CMET_CPINWithSIM);
    }
    else if (USE_POLLING_FOR_SIM_READY)
    {
        // EHS5 Rel1: there is no AT^SIND=simstatus, and the URC "+PBREADY", which is equvalent
        // to "+CIEV: simstatus,5", doesn't have a status query, so there is no way to tell, if the RIL
        // might have missed it. For this reason the RIL must use polling here.
        bOK = TRUE;
        m_fNextSIMStatusIsWorng = FALSE;        // Next time the status report should be OK again.
        if (!CANT_USE_CPMS)
            (void)QueueInternalCmdBlocking(HCCMD_STANDARD, this, SMS_INIT_PREFERRED_STORE_UMTS, CMDOPT_NONE, APIID_GETPHONEBOOKOPTIONS, 0, dwTimeout/SIM_INIT_POLLING_INTERVAL, SIM_INIT_POLLING_INTERVAL);
    }
    else
    {
        if (g_iCurrentSIMStatus != 5)
        {
            DWORD dwWait;
            HANDLE rghEvents[] = { m_hInternalSimReadyEvent, m_hAbortInternalSimReadyEvent, m_hCancelEvent };

            dwWait = WaitForMultipleObjects(3, rghEvents, FALSE, dwTimeout);
            if (dwWait != (WAIT_OBJECT_0 + 1) && dwWait != (WAIT_OBJECT_0 + 2))
                bOK = TRUE;
        }
        else
        {
            bOK = TRUE;
        }
    }
Error:

    if (m_hInternalSimReadyEvent != NULL)
    {
        (void)CloseHandle(m_hInternalSimReadyEvent);
        m_hInternalSimReadyEvent = NULL;
    }
    if (m_hAbortInternalSimReadyEvent != NULL)
    {
        (void)CloseHandle(m_hAbortInternalSimReadyEvent);
        m_hAbortInternalSimReadyEvent = NULL;
    }
    return bOK;
}

//
//
//
DWORD CRilHandle::SIMUnlockThread(void)
{
    char szCmd[MAX_ATCMD_LEN];
    DWORD fCSSN, fVCall = 0;
    WCHAR wszCmd[MAX_ATCMD_LEN];
    DWORD fCOLP, fAoC, fCGSMS;
    DWORD dwWaitForCSMS;
    DWORD dwTries, dwDelay;
    DWORD dwSIMTries, dwTmp;
    DWORD dwStatus = 0;
    BOOL bSkipInitialsSMSCheck = FALSE;
    BOOL bEONSInitialized;
    BOOL fCDMAdetected = FALSE;


    for (;;)
    {
        m_fSMSURCInitPhase = FALSE;
        fCDMAdetected = FALSE;

        (void)WaitForSingleObject(g_hSIMUnlockEvent, INFINITE);

        // See if the thread needs to terminate
        if (FCancelSet())
        {
            break;
        }

#ifdef RIL_ENABLE_ALS
        g_dwALSLine = 0;
#endif
        g_dwCallerIdStatus = RIL_SVCPROV_PROVISIONED;
        ClearFDPBCache();
        SetNeedBandGroupSearchActivation(FALSE);
        SetNITZactive(FALSE);
        dwSIMTries = GetInitSMSTries();
        m_szLastDialedNumber[0] = '\0';
        g_dwLastCLIPURC = 0;

        m_fVoiceCallDialing = FALSE;
        bEONSInitialized = FALSE;

        // Early registration state check: the radio might be faster in registering
        // to the network than it is in initializing the SIM. The RIL can inidicate
        // the registration state immediately, but the provider name will not be
        // available that early, so it won't show up until the initialization is
        // finished.
        dwTmp = 1;
        (void)GetRegistryDWORD(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, TEXT("ShowEarlyRegistrationStatus"), &dwTmp);
        if (dwTmp == 1 && GetCurrentTechnology() != TEC_MODE_CDMA) {
            const char *szUrcOnCmd;

            // Problem with multimode: module might already be in CDMA mode, so the
            // AT+CSCS command will return an error. Therefore it cannot be used
            // in a concatenated command.
            if (GetMultiModeSetting() == MULTIMODE_CONFIG_MULTIMODE)
                (void)QueueInternalCmd(HCCMD_URCPORT_ONLY, this, "AT+CSCS=\"UCS2\"\r", CMDOPT_URC, APIID_UNLOCKPHONE, 0, 0, 0);

            // Enable some needed URCs (signal strength, handling of early incoming calls)
			if (SUPPORTS_ONLY_DATAMODE)
				szUrcOnCmd = "AT+CSCS=\"UCS2\";^SIND=rssi,1\r";
			else if (NO_SIND_SIGNAL_AUDIO)
                szUrcOnCmd = "AT+CSCS=\"UCS2\";+CRC=1;+CLIP=1;^SIND=rssi,1\r";
            else if (GetMultiModeSetting() == MULTIMODE_CONFIG_CDMA && NO_SIND_SIGNAL_IN_CDMA)
                szUrcOnCmd = "AT+CRC=1;+CLIP=1;^SIND=rssi,1;^SIND=audio,1\r";
            else if (GetMultiModeSetting() == MULTIMODE_CONFIG_MULTIMODE && NO_SIND_SIGNAL_IN_CDMA)
                szUrcOnCmd = "AT+CRC=1;+CLIP=1;^SIND=rssi,1;^SIND=audio,1\r";
            else if (GetMultiModeSetting() == MULTIMODE_CONFIG_MULTIMODE && !NO_SIND_SIGNAL_IN_CDMA)
                szUrcOnCmd = "AT+CRC=1;+CLIP=1;^SIND=rssi,1;^SIND=signal,1;^SIND=audio,1\r";
            else
                szUrcOnCmd = "AT+CSCS=\"UCS2\";+CRC=1;+CLIP=1;^SIND=rssi,1;^SIND=signal,1;^SIND=audio,1\r";
#ifdef SUPPORTS_EHSX_R1
            if (NO_SIND_INDICATIONS)
                (void)QueueInternalCmd(HCCMD_URCPORT_ONLY, this, "AT+CSCS=\"UCS2\";+CRC=1;+CLIP=1;+XMER=1\r", CMDOPT_URC, APIID_UNLOCKPHONE, 0, 0, 0);
            else
#endif
                (void)QueueInternalCmd(HCCMD_URCPORT_ONLY, this, szUrcOnCmd, CMDOPT_URC, APIID_UNLOCKPHONE, 0, 0, 0);
            // Set preliminary URC state in powermanager to make sure, the URCs are turend off again in case the
            // device is suspended while the early registration phase.
            g_PowerManager.SetPreliminaryURCInitState(TRUE);
            // Start EONS initialization
            bEONSInitialized = m_pEonsHandling->Init(this);
            // Query initial registration state
            (void)QueueInternalCmd(HCCMD_URCPORT_ONLY, this, "AT+CREG=2;+CREG?\r", CMDOPT_NONE, APIID_GETREGISTRATIONSTATUS, 0, 0, 0, ParseEarlyRegistrationStatus, NULL, (LPVOID)this);
        }

		(void)QueueInternalCmd(HCCMD_STANDARD, this, "AT^SIND=psinfo,1\r", CMDOPT_URC, APIID_GETCURRENTSYSTEMTYPE, 0, 0, 0, ParseInitialPSInfo, ParseInitialPSInfoError, (LPVOID)this);

		// Check, if a default APN has been defined.
        CheckDefaultAPN();

        // Reset a possible stored SAT idle mode text.
        GetSimToolkit()->ResetIdleModeText();

        // Initialize NITZ (if configured)
        InitializeNITZ();

#ifdef RILDRV_CE6
        // In Windows CE6 the ^SLCC-URC is mandatory.
        if (SUPPORTS_SLCC && !SUPPORTS_ONLY_DATAMODE)
#else
        if (SUPPORTS_SLCC && !AVOID_SLCC && !SUPPORTS_ONLY_DATAMODE)
#endif
		{
          const char *szURCCmd = "AT^SLCC=1\r";

          if (INTEL_STYLE_NET_CMDS)
            szURCCmd  = "AT^SXCALLSTAT=1\r";
#ifdef SUPPORTS_EHSX_R1
          if (INTEL_AT_CMDS)
            szURCCmd  = "AT+XCALLSTAT=1\r";
#endif
            (void)QueueInternalCmd(HCCMD_URCPORT_ONLY, this, szURCCmd, CMDOPT_NONE, APIID_UNLOCKPHONE, 0, 0, 0);
        }

        // Check if we have to force login into a specific provider home network
        if ((g_n2G3GSelection != SELECTION2G3G_GSM_ONLY) && (g_iSetCOPSinInit != 1) && (g_iSetCOPSinInit != NO_INIT_COPS_SETTING)) {
          if (m_pForceHomeNet->ForceHomeNet(this)) {
            g_iSetCOPSinInit = NO_INIT_COPS_SETTING;
          }
        }

        (void)SetTimeInModule();      // Set time in module to system time of Windows Mobile.

        dwWaitForCSMS = 60000;
        dwTries = dwSIMTries;
        dwDelay = 1000;

        // Make sure, that the module is in PDU mode now before activating CNMI.
        (void)QueueInternalCmd(HCCMD_STANDARD, this, "AT+CMGF=0\r", CMDOPT_NONE, APIID_SETMSGSERVICEOPTIONS, 0, 0, 0);

        // Try to set the preliminary CNMI settings now to catch early VMWI messages. This may fail on
        // some SIMs. In this case the RIL will re-try it later.
        if (GetMultiModeSetting() == MULTIMODE_CONFIG_MULTIMODE) {
            // Multimode: it might not be clear, if the radio is registered to CDMA,
            // so first set CNMI to CDMA settings and then try out the GSM setting.
            // The GSM settings might fail, if module is already in CDMA, so the
            // RIL should not do the retries.
            (void)QueueInternalCmd(HCCMD_URCPORT_ONLY, this, GetCdmaCnmiSetting(), CMDOPT_NONE, APIID_UNLOCKPHONE, 0, dwTries, dwDelay);
            dwTries = 0;
        }
        if (GetCurrentTechnology() == TEC_MODE_CDMA)
            (void)QueueInternalCmd(HCCMD_URCPORT_ONLY, this, GetCdmaCnmiSetting(), CMDOPT_NONE, APIID_UNLOCKPHONE, 0, dwTries, dwDelay);
        else if (USE_STANDARD_CNMI_SETTINGS)
            (void)QueueInternalCmd(HCCMD_URCPORT_ONLY, this, "AT"SMS_CNMI_STORE_ON_SIM_3GPP"\r", CMDOPT_NONE, APIID_UNLOCKPHONE, 0, dwTries, dwDelay);
        else
            (void)QueueInternalCmd(HCCMD_URCPORT_ONLY, this, "AT"SMS_CNMI_STORE_ON_SIM"\r", CMDOPT_NONE, APIID_UNLOCKPHONE, 0, dwTries, dwDelay);

        // If the module supports the audio URC, we use it. If the module doesn't support
        // this URC we use the call states instead, so we can ignore any errors here.
        if (!NO_SIND_AUDIO)
            (void)QueueInternalCmd(HCCMD_STANDARD, this, "AT^SIND=audio,1\r", CMDOPT_NONE, APIID_UNLOCKPHONE, 0, 0, 0);
        // Enable the vcall URC, if needed.
        if (!GetRegistryDWORD(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, TEXT("AutoRejectVCall"), &fVCall))
            fVCall = (AUTOMATIC_VCALL_REJECT ? 1 : 0);
        if (fVCall == 1)
            (void)QueueInternalCmd(HCCMD_STANDARD, this, "AT^SIND=vcall,1\r", CMDOPT_NONE, APIID_UNLOCKPHONE, 0, 0, 0);

        // To catch early incoming SMS, try to re-route them to SMS now. If
        // this is not possible it is necessary to look for them later.
        if (!CANT_USE_CPMS)
            bSkipInitialsSMSCheck = QueueInternalCmdBlocking(HCCMD_URCPORT_ONLY, this, SMS_INIT_PREFERRED_STORE_UMTS, CMDOPT_NONE, APIID_UNLOCKPHONE, 0, 0, 0);

        // Check the status of the enhanced network section.
        CheckENSSetting(TRUE);

        // We now wait for the URC indicating, that the SIM is ready now before we proceed with the next step.
        if (!WaitForSIMInit())
            continue;

        // The SIM is now initialized, notify OS (SMS and phonebook still need initialization).
        SendReadyStateNotification(RIL_READYSTATE_SIM|RIL_READYSTATE_UNLOCKED, TRUE);

        if (!bSkipInitialsSMSCheck && !NO_INCOMING_SMS_ON_ME) {
            // Early SMS might have been been come in unanounced into the ME memory, so now is a
            // good time to look for them.
            if (!CheckForMissedSMS(this, TRUE))
                continue;
        }

        if (GetCurrentTechnology() == TEC_MODE_CDMA) {
            // Save "CDMA detected" state.
            fCDMAdetected = TRUE;

            // Multimode module only: the module is currently in CDMA network,
            // so this setting must be used.
            if (!CANT_USE_CPMS) {
                if (!QueueInternalCmdBlocking(HCCMD_URCPORT_ONLY, this, SMS_INIT_PREFERRED_STORE_CDMA, CMDOPT_NONE, APIID_UNLOCKPHONE, 0, dwSIMTries, 1000))
                    continue;
            }
        }
        else {
            // Place the command into the command queue and wait for response.
            // Multimode only: module might have been registered to CDMA in the mean
            // time, so if this command fails with CME error 370, module is in CDMA
            // already.
            (void)QueueInternalCmdBlocking(HCCMD_STANDARD, this, "AT+CSMS=1\r", CMDOPT_NONE, APIID_UNLOCKPHONE, dwWaitForCSMS, dwTries, dwDelay, NULL, ParseCSMSError, &fCDMAdetected);

            // SMS-URC initilaization phase: in case we go to suspend during this phase we turn on the URC for
            // SMS in order to wake up on incomming SMS, but we don't report the incomming SMS to the OS,
            // yet. Instead we check for SMS on SIM memory at the end of the initialization phase.
            if (!CANT_USE_CPMS && !fCDMAdetected) {
                if (!QueueInternalCmdBlocking(HCCMD_URCPORT_ONLY, this, SMS_INIT_PREFERRED_STORE_UMTS, CMDOPT_NONE, APIID_UNLOCKPHONE, 0, dwSIMTries, 1000))
                    continue;
            }
        }

        m_fSMSURCInitPhase = TRUE;
        g_dwSendNITZTime = 0;

        // Initialize the EONS capability (if not already done)
        if (!bEONSInitialized) {
            if (!m_pEonsHandling->Init(this))
                continue;
        }

        // Send the unlocked init strings
        if (!g_ComManager.SendUnlockedInitCmds())
            continue;
        if (GetCurrentTechnology() == TEC_MODE_CDMA)
            fCDMAdetected = TRUE;
        if (SUPPORTS_ADVICE_OF_CHARGE && GetRegistryDWORD(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, TEXT("EnableAdviceOfCharge"), &fAoC) && (fAoC>=0 && fAoC<=1) && !fCDMAdetected) {
            (void)_snprintfz(szCmd, MAX_ATCMD_LEN, "AT+CAOC=%u\r", fAoC+1);

            if (!QueueInternalCmd(HCCMD_STANDARD, this, szCmd, CMDOPT_NONE, APIID_UNLOCKPHONE, 0, 0, 0))
                continue;
        }
        if (GetRegistryDWORD(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, TEXT("InitialCGSMSSetting"), &fCGSMS) && (fCGSMS>=0 && fCGSMS<=3)) {
            (void)_snprintfz(szCmd, MAX_ATCMD_LEN, "AT+CGSMS=%u\r", fCGSMS);

            if (!QueueInternalCmd(HCCMD_STANDARD, this, szCmd, CMDOPT_NONE, APIID_UNLOCKPHONE, 0, 0, 0))
                continue;
        }
#ifdef RIL_ENABLE_ALS
        (void)_snprintfz(szCmd, MAX_ATCMD_LEN, "AT^SALS=1,1\r");
        // We can ignore errors in AT^SALS: if it fails, it means that the current SIM doesn't support
        // ALS, so we wouldn't receive a ^SALS-URC anyhow.
        (void)QueueInternalCmd(HCCMD_STANDARD, this, szCmd, CMDOPT_NONE, APIID_UNLOCKPHONE, 0, 2, 2000);
#endif
        g_fDisableCOLPInformation = TRUE;
        g_fDisableCOLPInformation = FALSE;
        g_nCOLPStatus = 1;
        if (GetRegistryDWORD(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, TEXT("DisableCOLPInformation"), &fCOLP) && (fCOLP>=0 && fCOLP<=1)) {
            // Disable COLP information is needed, when the radiotest is run on a network, which modifies
            // the format of the dialed number in the COLP notification. The radiometrics.exe will not
            // recognize, that the number dialed and the number shown are identical and sets the test
            // to failed although everything was correct.
            if (fCOLP == 1) {
                g_nCOLPStatus = 0;
                g_fDisableCOLPInformation = TRUE;
                if (!QueueInternalCmdBlocking(HCCMD_STANDARD, this, "AT+COLP=0\r", CMDOPT_NONE, APIID_UNLOCKPHONE, 0, 0, 0))
                    continue;
            }
        }
        fCSSN = 0;
        if (!GetRegistryDWORD(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, TEXT("DisableCSSNInformation"), &fCSSN))
            fCSSN = 0;
        if (GetCurrentTechnology() == TEC_MODE_CDMA)
            fCDMAdetected = TRUE;
        if (fCSSN != 1 && !fCDMAdetected && !SUPPORTS_ONLY_DATAMODE) {
            (void)_snprintfz(szCmd, MAX_ATCMD_LEN, "AT+CSSN=1,1\r");
            if (!QueueInternalCmd(HCCMD_STANDARD, this, szCmd, CMDOPT_NONE, APIID_UNLOCKPHONE, 0, 0, 0))
                continue;
        }

        // Before we update out AT+COPS-State we have to check our current settings.
        (void)GetRegistryDWORD(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, RIL_SELECTION_2G3D, &g_n2G3GSelection);
        if (g_n2G3GSelection < SELECTION2G3G_AUTOMATIC || g_n2G3GSelection > SELECTION2G3G_LTE_ONLY && !fCDMAdetected) {
            const char *szNetCmd = "AT+WS46?\r";
            PFN_CMD_PARSE fnParsing = ParseGet2G3GSelection;

            if (INTEL_STYLE_NET_CMDS) {
                szNetCmd = "AT^SXRAT?\r";
                fnParsing = ParseGet2G3GSelectionIntel;
            }
#ifdef SUPPORTS_EHSX_R1
            if (INTEL_AT_CMDS) {
                szNetCmd = "AT+XRAT?\r";
                fnParsing = ParseGet2G3GSelectionXRAT;
            }
#endif
            if (AVOID_COPS_ACT) {
                szNetCmd = "AT^SCFG=Radio/Band\r";
                fnParsing = ParseGet2G3GSelectionSCFG;
            }
            (void)QueueInternalCmdBlocking(HCCMD_STANDARD, this, szNetCmd, CMDOPT_NONE, APIID_DEVSPECIFIC, 0, 0, 0, fnParsing);
        }
        CloseHandle(CreateThread(NULL, 0, Check2G3GRegistration, (LPVOID)this, 0, 0));

        // AT+COPS setting doesn't apply, if module is already registered to CDMA.
        if (fCDMAdetected)
            g_iSetCOPSinInit = NO_INIT_COPS_SETTING;

        if ((g_iSetCOPSinInit != NO_INIT_COPS_SETTING) || (MUST_SET_COPS_AT_STARTUP && g_iSetCOPSinInit == NO_INIT_COPS_SETTING))
        {
            BOOL bMustResetBand = FALSE;

            // If the manual network selection is not allowed, switch to automatic selection.
            if (GetCurrentENSSetting() == ENS_MENU_DISABLED)
                g_iSetCOPSinInit = 0;

            // Usually the MMI sends its request to set the registration mode when the module hasn't started yet. For
            // this reason the value is stored to be set later during the init sequence (which is here).

            // Query the current +COPS state for further use. The result will be stored in g_iLastCOPS.
            g_szLastKnownEONSNameLong[0] = 0;
            g_szLastKnownEONSNameShort[0] = 0;

            if (WRONG_COPS_VALUE_AT_STARTUP)
                g_iLastCOPS = 2;    // The HC25 Rel1 reports the wrong value on AT+COPS? on startup, so we use <ops>=2 as default value.
            else
                (void)QueueInternalCmdBlocking(HCCMD_STANDARD, this, "AT+COPS?\r", CMDOPT_NONE, APIID_GETCURRENTOPERATOR, 0, 0, 0, ParseGetCurrentOperator);
            if (MUST_SET_COPS_AT_STARTUP && g_iSetCOPSinInit == NO_INIT_COPS_SETTING) g_iSetCOPSinInit = 0;

            if (g_iSetCOPSinInit != g_iLastCOPS || g_iSetCOPSinInit == 2)
            {
                INT iAcT = -1;
                DWORD dwCOPS1InitTimeout = 0;       // Per default: use standard timeout
                UINT nSetRadioBand = 0;

                switch (g_n2G3GSelection)
                {
                    case SELECTION2G3G_GSM_ONLY:
                        iAcT = 0;
                        break;
                    case SELECTION2G3G_UMTS_ONLY:
                        iAcT = 2;
                        break;
                    case SELECTION2G3G_LTE_ONLY:
                        iAcT = 7;
                        break;
                    default:
                        iAcT = -1;
                }
#ifdef RIL_WM6_ACT_SELECTION
                // If the WM6 style 2G/3G selection is in use, lpOperatorNames->dwParams may contain the
                // selection of 2G or 3G network type. This setting will overwrite the settings from RIL_DevSpecific
                // option RIL_DEVSPECIFIC_SET2G3GSELECTION.
                if (g_iSetCOPSinInitParams & RIL_PARAM_ON_GSM_ACT) {
                    iAcT = 0;
                    g_n2G3GSelection = SELECTION2G3G_GSM_ONLY;
                }
                if (g_iSetCOPSinInitParams & RIL_PARAM_ON_UMTS_ACT) {
                    iAcT = 2;
                    g_n2G3GSelection = SELECTION2G3G_UMTS_ONLY;
                }
                if (g_iSetCOPSinInitParams & RIL_PARAM_ON_LTE_ACT) {
                    iAcT = 7;
                    g_n2G3GSelection = SELECTION2G3G_LTE_ONLY;
                }
#endif
                if (g_iSetCOPSinInit == 0 || g_iSetCOPSinInit == 2) {
                    if (iAcT == -1 || g_iSetCOPSinInit == 2 || AVOID_COPS_ACT) {
                        (void)_snprintfz(szCmd, MAX_ATCMD_LEN, "AT+COPS=%u\r", g_iSetCOPSinInit);
                        if (AVOID_COPS_ACT && g_iSetCOPSinInit != 2) {
                            // AT+COPS/<AcT> bug (PXS8): When using the <AcT> parameter of AT+COPS
                            // the module might freeze. As a workaround, the RIL reconfigures the
                            // AT^SCFG=Radio/Band setting to force the module into the correct
                            // access technology.
                            nSetRadioBand = 7679;    // All GSM/UMTS + CDMA bands.
                            if (iAcT == 0)
                                nSetRadioBand = 7183;    // CDMA + GSM
                            else if (iAcT == 2)
                                nSetRadioBand = 7664;    // CDMA + UMTS
                        }
                    }
                    else {
                        (void)_snprintfz(szCmd, MAX_ATCMD_LEN, "AT+COPS=%u,2,,%d\r", g_iSetCOPSinInit, iAcT);
                    }
                    g_iLastCOPS = 0;
                    if (g_iSetCOPSinInit == 0 && g_bNeedAllBandNetworkSelection && g_dwAutomaticGroupSearchTimeout > 0 && NEEDS_RADIOBANDGROUP_WORKAROUND) {
                        CloseHandle(CreateThread(NULL, 0, PerformBandGroupSearchThread, (LPVOID)this, 0, 0));
                    }
                }
                else {
                    g_iLastCOPS = 1;
                    if (g_bNeedAllBandNetworkSelection && g_iSetCOPSinInit == 1)
                    {
                        if (NEED_RESET_BAND_SETTINGS_AFTER_SNWS && g_dwAutomaticGroupSearchTimeout == 0)
                            bMustResetBand = TRUE;      // Reset of the radio band settings is necessary.

                        // Please note, that due to a bug in the HC25 we first must set AT+COPS=0
                        // before we can use th AT^SNWS command.
                        if (iAcT == -1)
                            (void)_snprintfz(szCmd, MAX_ATCMD_LEN, "AT%s^SNWS=%u,2,%s\r", (NEED_COPS0_BEFORE_SNWS ? "+COPS=0;" : ""), g_iSetCOPSinInit, g_szSetCOPSinInitOperator);
                        else
                            (void)_snprintfz(szCmd, MAX_ATCMD_LEN, "AT%s^SNWS=%u,2,%s,%d\r", (NEED_COPS0_BEFORE_SNWS ? "+COPS=0;" : ""), g_iSetCOPSinInit, g_szSetCOPSinInitOperator, iAcT);
                        SetNeedBandGroupSearchActivation(TRUE);
                    }
                    else {
                        if (iAcT == -1 || AVOID_COPS_ACT) {
                            (void)_snprintfz(szCmd, MAX_ATCMD_LEN, "AT+COPS=%u,2,%s\r", g_iSetCOPSinInit, g_szSetCOPSinInitOperator);
                            // AT+COPS/<AcT> bug (PXS8): When using the <AcT> parameter of AT+COPS
                            // the module might freeze. As a workaround, the RIL reconfigures the
                            // AT^SCFG=Radio/Band setting to force the module into the correct
                            // access technology.
                            nSetRadioBand = 7679;    // All GSM/UMTS + CDMA bands.
                            if (iAcT == 0)
                                nSetRadioBand = 7183;    // CDMA + GSM
                            else if (iAcT == 2)
                                nSetRadioBand = 7664;    // CDMA + UMTS
                        }
                        else {
                            (void)_snprintfz(szCmd, MAX_ATCMD_LEN, "AT+COPS=%u,2,%s,%d\r", g_iSetCOPSinInit, g_szSetCOPSinInitOperator, iAcT);
                        }
                    }
                }

                g_dwLastKnowBandSelection = 127;
                if (bMustResetBand)
                    (void)QueueInternalCmdBlocking(HCCMD_STANDARD, this, "AT^SCFG=\"Radio/Band\"\r", CMDOPT_NONE, APIID_SCFGRADIOBAND, 0, 0, 0, ParseGetCurrentRadioBand);

                if (nSetRadioBand > 0) {
                    char szSCFGCmd[MAX_ATCMD_LEN];
                    DWORD dwRegRadioBand;

                    if (!GetRegistryDWORD(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, TEXT("UseCopsActWorkaround"), &dwRegRadioBand))
                        dwRegRadioBand = 1;
                    // Set Radio/Band. Needed for AT+COPS/<AcT> workaround.
                    (void)_snprintfz(szSCFGCmd, MAX_ATCMD_LEN, "AT^SCFG=\"Radio/Band\",\"%d\",\"1\"\r", nSetRadioBand);
                    if (dwRegRadioBand == 1)
                        (void)QueueInternalCmd(HCCMD_STANDARD, this, szSCFGCmd, CMDOPT_NONE, APIID_SCFGRADIOBAND, 0, 0, 0);
                }

                if (g_iSetCOPSinInit == 1)
                {
                    // Potentional problem: if already registered to the network it may be necessary
                    // unregister first (NEED_COPS2_BEFORE_COPS1 workaround).
                    //
                    // Alternative: if the "COPS1InitTimeout" registry key is set, the AT+COPS=1 command
                    // will be send with the given (reduced) timeout (recommendation: 3-4 seconds). Since
                    // the command won't return, the RIL make a user break and sends the command again.
                    //
                    if (g_dwRegStatus == RIL_REGSTAT_HOME || g_dwRegStatus == RIL_REGSTAT_ROAMING) {
                        if (NEED_COPS2_BEFORE_COPS1) {
                            GetRegistryDWORD(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, TEXT("COPS1InitTimeout"), &dwCOPS1InitTimeout);
                            // If registry key "COPS1InitTimeout" is not set, unregister from network first.
                            if (dwCOPS1InitTimeout == 0)
                                (void)QueueInternalCmd(HCCMD_STANDARD, this, "AT+COPS=2\r", CMDOPT_NONE, APIID_UNREGISTERFROMNETWORK, 0, 0, 0);
                        }
                    }
                }

                (void)QueueInternalCmd(HCCMD_STANDARD, this, szCmd, CMDOPT_NONE, APIID_REGISTERONNETWORK, dwCOPS1InitTimeout, 1, 1000);

                if (bMustResetBand)
                {
                    (void)_snprintfz(szCmd, MAX_ATCMD_LEN, "AT^SCFG=\"Radio/Band\",\"%d\"\r", g_dwLastKnowBandSelection);

                    (void)QueueInternalCmd(HCCMD_STANDARD, this, szCmd, CMDOPT_NONE, APIID_SCFGRADIOBAND, 0, 0, 0);
                }
                if (COPS_CHANGES_SCFG || (COPS1_CHANGES_SCFG && g_iSetCOPSinInit == 1)) {
                    // Bug in PXS8: the use of AT+COPS changes the module from GSM-only to
                    // multimode. If necessary, the RIL must change the setting back.
                    if (GetMultiModeSetting() == MULTIMODE_CONFIG_LTE)
                        (void)QueueInternalCmd(HCCMD_STANDARD, this, "AT^SCFG=MEopMode/AccT,\"GSM/UMTS\"\r", CMDOPT_NONE, APIID_SCFGRADIOBAND, 0, 0, 0);
                }
            }
            g_iSetCOPSinInit = NO_INIT_COPS_SETTING;
#ifdef RIL_WM6_ACT_SELECTION
            g_iSetCOPSinInitParams = 0;
#endif
        }
        (void)SetRegistryDWORD(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, RIL_SELECTION_2G3D, g_n2G3GSelection);

        // SMS initialization ended, now the power manager will check if there are missed SMS and turn on the
        // regular SMS notification method.
        m_fSMSURCInitPhase = FALSE;

        if (GetCurrentTechnology() == TEC_MODE_CDMA)
            fCDMAdetected = TRUE;

        // In case we have a stored CLIR value, we restore it now.
        if (GetRegistryDWORD(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, REG_LAST_CLIR, &g_dwHideCallerId)) {
            DWORD i, nValue = 0;

            // Since the HC25 doesn't store the CLIR value, we use this stored value.
            for (i = 0; i < NUM_HIDEIDSTATS; i++) {
                if (g_dwHideCallerId == g_rgdwHideIDStats[i]) {
                    nValue = i;
                    break;
                }
            }
            if (NUM_HIDEIDSTATS != i && !fCDMAdetected) {
                (void)_snprintfz(szCmd, MAX_ATCMD_LEN, "AT+CLIR=%d\r", nValue);
                (void)QueueInternalCmd(HCCMD_STANDARD, this, szCmd, CMDOPT_NONE, APIID_SETHIDEIDSTATUS, 0, 0, 0);
            }
        }
        else {
            g_dwHideCallerId = RIL_SVCPROV_UNKNOWN;
        }

        if (!GetRegistryDWORD(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, TEXT("SMSPersistLinkOption"), &g_dwSMSPersistLink))
            g_dwSMSPersistLink = SMSPERSISTLINK_PERMANENT;
        if (g_dwSMSPersistLink == SMSPERSISTLINK_PERMANENT && !fCDMAdetected)
            (void)QueueInternalCmd(HCCMD_STANDARD, this, "AT+CMMS=2\r", CMDOPT_NONE, APIID_SENDMSGACKNOWLEDGEMENT, 2000, 0, 0);

        // We are not completely ready here, but we can start processing SMS now.
        SendReadyStateNotification(RIL_READYSTATE_SIM|RIL_READYSTATE_UNLOCKED|RIL_READYSTATE_SMS, TRUE);

        if (!g_PowerManager.EnterUrcState(NULL, MODEMSTATE_POWERON, TRUE))
            continue;
        g_PowerManager.SetPreliminaryURCInitState(FALSE);   // Preliminary URC phase has ended now.

        if (GetCurrentTechnology() != TEC_MODE_CDMA) {
            // Check the "SIM SMS full" status (not relevant fo CDMA).
            (void)QueueInternalCmd(HCCMD_STANDARD, this, "AT^SIND=smsfull,2\r", CMDOPT_NONE, APIID_UNLOCKPHONE, 0, 0, 0, ParseInitialSmsFull, NULL, (LPVOID)this);
        }

        // Set Phonebook to SM (SIM phonebook) as default. As a secondary effect
        // this make sure, that the whole SIM is now ready.
        // If the FD lock is active, we use the FD phonebook instead of the SM
        // phonebook.
        // This command might fail on SIMs without phonebook or during GCF
        // approval. For this reason the return value is ignored.
        // PXS8 (multimode) only: if currently in CDMA, skip this check.
        if (!fCDMAdetected && !PhoneBookAccessDisabled() && QueueInternalCmdBlocking(HCCMD_STANDARD, this, "AT+CLCK=\"FD\",2\r", CMDOPT_NONE, APIID_GETLOCKINGSTATUS, 0, 0, 0, ParseGetLockingStatus, NULL, (LPVOID)&dwStatus))
        {
            if (dwStatus == RIL_LOCKINGSTATUS_ENABLED && NO_READ_ON_FD_WO_PIN2)
                g_dwCurrentPhoneBook = RIL_PBLOC_SIMFIXDIALING;
            else if (dwStatus == RIL_LOCKINGSTATUS_ENABLED && !NO_READ_ON_FD_WO_PIN2)
                (void)QueueInternalCmdBlocking(HCCMD_STANDARD, this, "AT+CPBS=\"FD\"\r", CMDOPT_NONE, APIID_SETPHONEBOOKOPTIONS, dwWaitForCSMS, dwTries, dwDelay);
            else if (dwStatus != RIL_LOCKINGSTATUS_ENABLED)
                (void)QueueInternalCmdBlocking(HCCMD_STANDARD, this, "AT+CPBS=\"SM\"\r", CMDOPT_NONE, APIID_SETPHONEBOOKOPTIONS, dwWaitForCSMS, dwTries, dwDelay);
        }

        // Option on some modules: DTMF detection. Must be enabled with a registry
        // key. Generates Microsoft's RIL_NOTIFY_DTMFSIGNAL notification. Check
        // AT Command Set documentation for AT^SIND=dtmf to find out it the
        // module supports this feature. Notice: this feature might require a
        // special audio mode.
        dwTmp = 0;
        (void)GetRegistryDWORD(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, TEXT("EnableDtmfDetection"), &dwTmp);
        if (dwTmp > 0) {
            // Possible values:
            // 1 = network
            // 2 = local + network
            if (dwTmp == 2)
                (void)QueueInternalCmd(HCCMD_STANDARD, this, "AT^SIND=dtmf,1,2\r", CMDOPT_NONE, APIID_ENABLEDISABLEURCS, 0, 0, 0);
            else
                (void)QueueInternalCmd(HCCMD_STANDARD, this, "AT^SIND=dtmf,1,1\r", CMDOPT_NONE, APIID_ENABLEDISABLEURCS, 0, 0, 0);
        }

        // This is the last ready state notification. Although the initialization is still not
        // finished, the full radio functionality is available now.
        SendReadyStateNotification(RIL_READYSTATE_SIM|RIL_READYSTATE_UNLOCKED|RIL_READYSTATE_SMS|RIL_READYSTATE_SIM_PB, TRUE);

        // The RIL just sent the last RIL_READYSTATE_INITIALIZED notification.
        (void)BroadcastDWORDBlobNotification(RIL_NOTIFY_DEVSPECIFIC_LAST_READYSTATE_MSG, LAST_READYSTATE_MSG_FINAL);

        // Workaround for Microsoft MMI bug: the MMI reads the MSISDNs only once and also so early, that not every
        // SIM is ready. As a workaround we send a RIL_SIM_DATACHANGE_MSISDNS notification when the own number
        // phonebook is ready, forcing the OS to read the own number now (expect SAT, but this will be indicated later).
        (void)BroadcastDWORDBlobNotification(RIL_NOTIFY_SIM_DATACHANGE, RIL_SIM_DATACHANGE_MSISDNS);

        // Optional customer defined AT command
        memset(wszCmd, 0, sizeof(wszCmd));
        if (GetRegistrySZ(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, TEXT("PostSIMInitCommand"), wszCmd, MAX_ATCMD_LEN)) {
            if (wcslen(wszCmd) > 0) {
                _snprintfz(szCmd, MAX_ATCMD_LEN, "%S\r", wszCmd);
                (void)QueueInternalCmd(HCCMD_STANDARD, this, szCmd, CMDOPT_NONE, APIID_DEVSPECIFIC, g_TimeoutCmdInit, 0, 0);
            }
        }
        memset(wszCmd, 0, sizeof(wszCmd));
        if (GetRegistrySZ(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, TEXT("PostSIMInitCommandURC"), wszCmd, MAX_ATCMD_LEN)) {
            if (wcslen(wszCmd) > 0) {
                _snprintfz(szCmd, MAX_ATCMD_LEN, "%S\r", wszCmd);
                (void)QueueInternalCmd(HCCMD_URCPORT_ONLY, this, szCmd, CMDOPT_NONE, APIID_DEVSPECIFIC, g_TimeoutCmdInit, 0, 0);
            }
        }

        // It may be necessary to do some additional audio mode changes, unless a voice call
        // is already ongoing.
        if(!UNSUPPORTS_AUDIO){
        	PerformDoubleAudioCheck(this, RIL_AUDIO_HANDSET);
        }
		
		//Support IMS Call(VoLTE) and IMS SMS or not.
		if (SUPPORTS_IMS)
		{
			DWORD dwCurrentStatus = 0xFF;
			DWORD dwMode = 0xFF;

			(void)GetRegistryDWORD(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, TEXT("IMSForCallAndSMS"), &dwMode);
					
			if((dwMode == 0) || (dwMode == 1)){

				(void)QueueInternalCmdBlocking(HCCMD_STANDARD, this, "AT+CIREG?\r", CMDOPT_URC, APIID_GETIMSREGISTRYINFO, 0, 0, 0, ParseGetIMSRegistryInfo, NULL, (LPVOID)&dwCurrentStatus);
				
				if(dwMode != dwCurrentStatus){
				
					QueueInternalCmdBlocking(HCCMD_STANDARD, this, "AT+XICFG=0,1,50,1\r", CMDOPT_NONE, APIID_NONE, 0, 0, 0);
					
					(void)_snprintfz(szCmd, MAX_ATCMD_LEN, "AT+XIREG=%d\r", dwMode);
					QueueInternalCmdBlocking(HCCMD_STANDARD, this, szCmd, CMDOPT_NONE, APIID_NONE, 0, 0, 0);
					
				}
			}
		}

        // Enable the SIM-Toolkit handling if required
        if (!m_pSimToolkitHandling->Init(this))
        {
            continue;
        }
    }

    return 0;
}

static DWORD WINAPI SIMUnlockThreadProc(LPVOID lpParameter)
{
    CRilHandle* pRilDevice = (CRilHandle*)lpParameter;

    if (!SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL))
    {
        return 0;
    }

    const DWORD dwReturn = pRilDevice->SIMUnlockThread();
    return dwReturn;
}


//
// Test the cancel event
//
BOOL CRilHandle::FCancelSet(void) const
{
    return (WAIT_OBJECT_0 == WaitForSingleObject(m_hCancelEvent, 0));
}


//
//
//
BOOL CRilHandle::WaitForInit(DWORD dwTimeout) const
{
    HANDLE rghEvents[] = { m_hInitEvent, m_hCancelEvent };
    switch (WaitForMultipleObjects(2, rghEvents, FALSE, dwTimeout))
    {
    case WAIT_OBJECT_0:
    case WAIT_OBJECT_0 + 1:
        return TRUE;
    default:
        return FALSE;
    }
}


//
// Simply wait until command handling is unblocked or cancelled.
// Returns false if the command thread should quit.
//
BOOL CRilHandle::WaitForCommandOrCancel()
{
  BOOL    fCmd = FALSE;
  HANDLE  rghEvents[] = { g_CmdQ.GetPutEvent(), m_hCancelEvent };
  HANDLE  rghBlockEvents[] = { m_hBlockCmdsEvent, m_hCancelEvent };

  while (!fCmd) {
    // Wait until command handling is unblocked or we're cancelled
    EnterCriticalSection(&m_csBlockCmds);
    if (WaitForMultipleObjects(2, rghBlockEvents, FALSE, INFINITE) != WAIT_OBJECT_0) {
      LeaveCriticalSection(&m_csBlockCmds);
      return FALSE;
    }

    // Lock the command handling in port objects
    LockRilCmd();
    LeaveCriticalSection(&m_csBlockCmds);

    // Wait until command is availabe or we're cancelled
    if (WaitForMultipleObjects(2, rghEvents, FALSE, INFINITE) != WAIT_OBJECT_0) {
      UnlockRilCmd();
      return FALSE;
    }

    // Check if there is really a command available
    if (!g_CmdQ.FEmpty()) {
      fCmd = TRUE;
    } else {
      // Unlock the command handling in port object again for next wait
      UnlockRilCmd();
    }
  }

  // Set the put event again which has been reset by the last wait
  (void)SetEvent(g_CmdQ.GetPutEvent());

  return TRUE;
}

//
// Simpler version of WaitForCommandOrCancel() for no-operation commands,
// which doesn't need to be blocked during power management etc.
//
BOOL CRilHandle::WaitForNoopCommandOrCancel()
{
  BOOL    fCmd = FALSE;
  HANDLE  rghEvents[] = { g_NoopCmdQ.GetPutEvent(), m_hCancelEvent };

  while (!fCmd) {
    // Wait until command is availabe or we're cancelled
    if (WaitForMultipleObjects(2, rghEvents, FALSE, INFINITE) != WAIT_OBJECT_0) {
      return FALSE;
    }

    // Check if there is really a command available
    if (!g_NoopCmdQ.FEmpty()) {
      fCmd = TRUE;
    }
  }

  // Set the put event again which has been reset by the last wait
  (void)SetEvent(g_NoopCmdQ.GetPutEvent());

  return TRUE;
}


//
// Returns true if there is response data available that can be executed now.
// Returns false if the response thread should quit.
//
BOOL CRilHandle::WaitForResponseOrCancel(COM_PORT_TYPE PortType, PBYTE pBuf, DWORD& dwRead)
{
  DWORD    dwMask;
  DWORD    dwErrors;
  BOOL     fData = FALSE;
  HANDLE   rghBlockEvents[] = { m_hBlockRspsEvent, m_hCancelEvent };
  BOOL     fPortError = TRUE;

  // Wait until we have data or we're cancelled
  while (!fData) {
    fPortError = TRUE;

    // Wait until we have a valid COM port
    if (!m_pComDevice[PortType]->WaitForDownstreamPort()) {
      return FALSE;
    }

    // Wait until command handling is unblocked again or we are cancelled
    if (WaitForMultipleObjects(2, rghBlockEvents, FALSE, INFINITE) != WAIT_OBJECT_0) {
      return FALSE;
    }

    // Now wait until we have data
    m_dwPendingPortCalls[PortType]++;
    if (m_pComDevice[PortType]->VirtSetCommMask(DEFAULT_COM_MASK)) {
      // Check if there isn't still data in the read buffer
      COMSTAT  Stat;
      DWORD    dwErr;
      if (m_pComDevice[PortType]->VirtClearCommError(&dwErr, &Stat, FALSE)) {
        if (!Stat.cbInQue) {
          if (m_pComDevice[PortType]->VirtWaitCommEvent(&dwMask)) {
            if (dwMask & EV_ERR) {
              (void)m_pComDevice[PortType]->VirtClearCommError(&dwErrors, NULL);
            }

            if (dwMask & EV_BREAK) {
              (void)m_pComDevice[PortType]->VirtClearCommBreak();
            }

            if (dwMask & EV_RXCHAR) {
              // Check again if there is really data available
              if (m_pComDevice[PortType]->VirtClearCommError(&dwErr, &Stat, FALSE)) {
                if (Stat.cbInQue) {
                  // If we're waiting for a data connection we're reading only single bytes.
                  // That makes it impossible for ppp data to reach AT response buffer.
                  DWORD dwToRead = m_pComDevice[PortType]->FWaitDataMode() ? 1 : dwRead;
                  if (m_pComDevice[PortType]->VirtRead(pBuf, dwToRead, dwRead)) {
                    fData = TRUE;
                    fPortError = FALSE;
                  }
                } else {
                  fPortError = FALSE;
                }
              }
            } else {
              fPortError = FALSE;
            }
          }
        } else {
          // If we're waiting for a data connection we're reading only single bytes.
          // That makes it impossible for ppp data to reach AT response buffer.
          DWORD dwToRead = m_pComDevice[PortType]->FWaitDataMode() ? 1 : dwRead;
          // There is still data in the read buffer
          if (m_pComDevice[PortType]->VirtRead(pBuf, dwToRead, dwRead)) {
            fData = TRUE;
            fPortError = FALSE;
          }
        }
      }
    }

    m_dwPendingPortCalls[PortType]--;
    if (fPortError) {
      // ReadFile can only fail after USB detach because the module went off
      if (m_pComDevice[PortType]->IsDownstreamPortOpen()) {
        if (RHA_IsRadioPwrOn()) {
          RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: WaitForResponseOrCancel(%s) - Module not responding\r\n"), g_ComManager.GetDebugName(PortType)));
        } else {
          RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: WaitForResponseOrCancel(%s) - Module powered off externally\r\n"), g_ComManager.GetDebugName(PortType)));
        }
        (void)g_PowerManager.ForcePowerOff();
        Sleep(10);
        continue;
      }
    }
  }

  return TRUE;
}


//
//
//
BOOL CRilHandle::BlockCommandPriority(DWORD dwPriority, BOOL fAbort) {
BOOL fRet = TRUE;

  // Abort possibly running commands if required by simply blocking the command handling
  if (fAbort) {
    if (!BlockCommandHandling()) {
      fRet = FALSE;
    }
  }

  // Now block all commands below the given priority
  if (!g_CmdQ.SetPriorityLock(dwPriority)) {
    fRet = FALSE;
  }

  // Now unblock command handling again if it was blocked before
  if (fAbort) {
    if (!UnblockCommandHandling()) {
      fRet = FALSE;
    }
  }

  return fRet;
}


//
//
//
BOOL CRilHandle::BlockCommandHandling(COM_PORT_TYPE PortType) {
  // First check if we're not already blocked
  if ((WaitForSingleObject(m_hBlockCmdsEvent, 0) != WAIT_OBJECT_0) && (WaitForSingleObject(m_hBlockRspsEvent, 0) != WAIT_OBJECT_0)) {
    return FALSE;
  }

  SYNCBLOCK(m_csBlockCmds);

  // Block the command queue
  (void)ResetEvent(m_hBlockCmdsEvent);

  // Now abort possible running commands
  (void)SetEvent(g_CmdQ.GetPutEvent());
  (void)m_pComDevice[PortType]->AbortCommand();

  // And block the response queue
  (void)ResetEvent(m_hBlockRspsEvent);

  // Abort possible WaitCommEvent() in response queue
  if (!m_pComDevice[PortType]->FDataMode()) {
    (void)m_pComDevice[PortType]->VirtSetCommMask(0);
  }

  // Finally wait until all pending COM calls has finished properly
  for (DWORD i = 0; (i < 100) && m_dwPendingPortCalls[PortType]; i++) {
    Sleep(100);
  }
  m_dwPendingPortCalls[PortType] = 0;

  // Wait until possibly running command has finished
  m_pComDevice[PortType]->LockRILCmd();
  m_pComDevice[PortType]->UnlockRILCmd();

  return TRUE;
}


//
//
//
BOOL CRilHandle::BlockCommandHandling(void) {
// DWORD  i;
BOOL   fRet = TRUE;

  if (!BlockCommandHandling(URC_PORT)) {
    fRet = FALSE;
  }

/*
  for (i = 0; i < NUMBER_OF_PORTS; i++) {
    if (!BlockCommandHandling((COM_PORT_TYPE)i)) {
      fRet = FALSE;
    }
  }
*/
  return fRet;
}


//
//
//
BOOL CRilHandle::UnblockCommandHandling(void) const {
  // First check if we're not already unblocked
  if ((WaitForSingleObject(m_hBlockCmdsEvent, 0) == WAIT_OBJECT_0) && (WaitForSingleObject(m_hBlockRspsEvent, 0) == WAIT_OBJECT_0)) {
    return FALSE;
  }

  // Unblock the response queues
  (void)SetEvent(m_hBlockRspsEvent);

  // Unblock the command queues
  (void)SetEvent(m_hBlockCmdsEvent);

  // Restart possibly locked queue handling
  (void)SetEvent(g_CmdQ.GetPutEvent());

  return TRUE;
}


//
//
//
BOOL CRilHandle::AddToList(CRilInstanceHandle* const pInstance)
{
    return m_pInstances->Add(pInstance);
}


//
//
//
BOOL CRilHandle::RemoveFromList(CRilInstanceHandle* const pInstance)
{
    return m_pInstances->Remove(pInstance);
}


//
//
//
HRESULT CRilHandle::GetNextCmdID(void)
{
    SYNCBLOCK(m_csCmdID);

    // Make sure not to wrap into error values
    if (FAILED(m_hrNextCmdID))
    {
        m_hrNextCmdID = INITIAL_COMMAND_ID;
    }

    return m_hrNextCmdID++;
}


//
// Function passed to CDlbList::Enum() below
//
static BOOL NotifyHandle(void* pItem, DWORD dwData)
{
    CRilInstanceHandle* pHandle = (CRilInstanceHandle*)pItem;
    CNotificationData* pnd = (CNotificationData*)dwData;

    if (pHandle->FReadyForNotifications())
    {
        pHandle->Notify(pnd->GetCode(), S_OK, pnd->GetBlob(), pnd->GetSize());
    }

    // Continue enumeration
    return FALSE;
}

//
// Broadcast a notification to all clients
//
void CRilHandle::BroadcastNotification(CNotificationData*& rpnd)
{
    SYNCBLOCK(g_csClosing);

    if (m_fBlockRegistrationURCs && rpnd->GetCode() == RIL_NOTIFY_REGSTATUSCHANGED) {
         RILRetailTraceZone(ZONE_INFO, (TEXT("RilDrv: Registration notification blocked.\r\n")));
    }
    else {
        TraceNotification(rpnd);
        // Notify all RIL proxy instances
        m_pInstances->Enum(NotifyHandle, (DWORD)rpnd);
    }

     // Get rid of the notififcation
    delete rpnd;
    rpnd = NULL;
}


//
//
//
BOOL CRilHandle::BroadcastRealBlobNotification(const DWORD dwNotificationCode, const void* const pBlob,
                                               const UINT cbBlob)
{
    CNotificationData* pnd = NULL;
    BOOL fRet = FALSE;

    pnd = new CNotificationData;
    if (!pnd || !pnd->InitFromRealBlob(dwNotificationCode, pBlob, cbBlob))
    {
        goto Error;
    }

    BroadcastNotification(pnd);
    fRet = TRUE;

    Error:
    if (pnd != NULL)
        delete pnd;
    return fRet;
}


//
//
//
BOOL CRilHandle::BroadcastDWORDBlobNotification(const DWORD dwNotificationCode, const DWORD dwBlob)
{
    CNotificationData* pnd = NULL;
    BOOL fRet = FALSE;

    pnd = new CNotificationData;
    if (!pnd || !pnd->InitFromDWORDBlob(dwNotificationCode, dwBlob))
    {
        goto Error;
    }

    BroadcastNotification(pnd);
    fRet = TRUE;

    Error:
    if (pnd != NULL)
        delete pnd;
    return fRet;
}

//
//
//
DWORD WINAPI PromptForSimAndRequeueCmdProc(LPVOID /*lpParameter*/)
{
    HINSTANCE hInstSimSec;

    // Load the simsec library
    hInstSimSec = LoadLibrary(wszSIMSECDLL);
    if (!hInstSimSec)
    {
        goto Exit;
    }

    // Get the address of the simsec ui
    typedef HRESULT (*SIMSECURITYUNLOCKPHONE) (HWND hwndMain, DWORD dwStyle);
    SIMSECURITYUNLOCKPHONE pfnSIMSecurityUnlockPhone;
    pfnSIMSecurityUnlockPhone = (SIMSECURITYUNLOCKPHONE)GetProcAddress(hInstSimSec, TEXT("SIMSecurityUnlockPhone"));
    if (pfnSIMSecurityUnlockPhone)
    {
        // Put up the UI
#ifdef TPC
        (void)pfnSIMSecurityUnlockPhone(NULL, SIMSEC_STYLE_CANNOT_CANCEL | SIMSEC_STYLE_EMERGENCY_CALL | SIMSEC_STYLE_BRANDED);
#else
        (void)pfnSIMSecurityUnlockPhone(NULL, SIMSEC_STYLE_EMERGENCY_CALL);
#endif
    }
    else
    {
#ifdef TPC
        goto Exit;
#else
        // backward compatibility for old simsecui, which doesn't have UnlockPhone, and instead uses CheckPin
        typedef HRESULT (*SIMSECURITYCHECKPIN) (HWND hwndMain, SIMPIN_TYPE nPinType, DWORD dwStyle);
        SIMSECURITYCHECKPIN pfnSIMSecurityCheckPin;
        pfnSIMSecurityCheckPin = (SIMSECURITYCHECKPIN)GetProcAddress(hInstSimSec, TEXT("SIMSecurityCheckPin"));
        if (pfnSIMSecurityCheckPin)
        {
            // Put up the UI
            (void)pfnSIMSecurityCheckPin(NULL, (SIM_LOCKFACILITY_SIM == g_dwLockFacility) ? SIMPIN_SIM : SIMPIN_SIM2,
                SIMSEC_STYLE_AUTO_CLOSE | SIMSEC_STYLE_EMERGENCY_CALL);
        }
        else
        {
            goto Exit;
        }
#endif // !TPC
    }


    // Free the library
    (void)FreeLibrary(hInstSimSec);

Exit:
    // Not prompting anymore
    g_PromptingForSim=FALSE;

    // Now safe to requeue the pending commands to try again
    // Requeue any existing commands
    // If the SIM was unlocked, they'll now succeed.
    // Otherwise they'll fail as expected.
    CCommand* pCmd;
    while (g_pSimLockedQueue->Get(pCmd, 0)==S_OK)
    {
        if (!g_CmdQ.Put(pCmd, INFINITE))
        {
            delete pCmd;
        }
    }

    return 0;
}

//
//
//
static BOOL PromptForSimAndRequeueCmd(CCommand* pCmd, DWORD dwLockFacility)
{
    BOOL fRet=FALSE;

    // Queue command up on SIM retry queue
    if(pCmd->FDial())
    {
        // Not re-queuing dial commands
        // Leave fRet FALSE to indicate that the existing response should be used
    }
    else
    {
        pCmd->ClrCmdOpt(CMDOPT_RETRYONSIMLOCKED);
        fRet = g_pSimLockedQueue->Put(pCmd, 0);
        if (!fRet)
        {
            goto Exit;
        }
    }

    // Is another dialog already up?
    // Note: don't need to worry about
    if (!g_PromptingForSim)
    {
        HANDLE hThread;
        // Remember to save nPinType;
        g_dwLockFacility=dwLockFacility;
        hThread = CreateThread(NULL, 0, PromptForSimAndRequeueCmdProc, (LPVOID)NULL, 0, NULL);
        if (!hThread)
        {
            // Eek, we can't create a thread!
            if(pCmd->FDial())
            {
                // Dial commands were not put on the queue, so we don't need to remove them now
            }
            else
            {
                // By definition, our command must be the only one in the queue. Just get it back out.
                // When we return fRet==FALSE, the calling code will fail the response to the app.
                CCommand *pCmdTmp;
                (void)g_pSimLockedQueue->Get(pCmdTmp, 0);
            }
            goto Exit;
        }
        else
        {
            (void)CloseHandle(hThread);   // close handle we don't need
        }
        g_PromptingForSim=TRUE;
    }

    if(!pCmd->FDial())
    {
        // See comment above about leaving fRet FALSE for dial commands
        fRet=TRUE;
    }
Exit:
    return fRet;
}

//
// Handle response to an AT command
//
BOOL CRilHandle::HandleRsp(CCommand*& rpCmd, CResponse*& rpRsp)
{
    void* pBlob = NULL;
    UINT cbBlob = 0;
    HRESULT hrError;
    CNotificationData* pnd = NULL;
    BOOL fRet = FALSE;

    // Handling of the CME-Error translation table.
    if (rpRsp->GetNotifyCode() == RIL_RESULT_ERROR) {
        void* pBlobCMET;
        UINT cbBlobCMET;

        rpRsp->GetBlob(pBlobCMET, cbBlobCMET);

        if (pBlobCMET != NULL && cbBlobCMET >= sizeof(HRESULT))
        {
            HRESULT hr;

            hr = *((HRESULT*)pBlobCMET);

            // If a CME error translation table is available, translate error code.
            hr = rpCmd->TranslateErrorCode(hr);

            // If the error code is E_FAIL, try to generate an appropiate error code.
            if (hr == E_FAIL && rpCmd->CmdOptIsSet(CMDOPT_GENERATE_ERROR_CODE))
            {
                if (g_PowerManager.IsRadioOff())
                    hr = RIL_E_RADIOOFF;
                else if (GetCurrentSIMType() == SIMTYPE_NOT_INSERTED)
                    hr = RIL_E_SIMNOTINSERTED;
                else if (g_dwSIMLockedState == RIL_LOCKEDSTATE_SIM_PIN)
                    hr = RIL_E_SIMPINREQUIRED;
                else if (g_dwSIMLockedState == RIL_LOCKEDSTATE_SIM_PUK)
                    hr = RIL_E_SIMPUKREQUIRED;
                else
                    hr = RIL_E_SIMBUSY;
            }
            memcpy(pBlobCMET, &hr, sizeof(HRESULT));
        }
    }

    if (rpRsp->GetNotifyCode() == RIL_RESULT_ERROR && rpCmd->IsSMSAck()) {
        // Special problem: when a SMS scknowlegment fails, the +CNMI-settings are
        // automaticalli reset to 0,0,0,0 (no inidications of incomming SMS.
        // For this reason we have to reeactivate the CNMI indications.
        CloseHandle(CreateThread(NULL, 0, CNMIReactivationThreadProc, (LPVOID)this, 0, NULL));
    }
    if ((rpRsp->GetNotifyCode() == RIL_RESULT_ERROR) &&
         (rpCmd->GetAPIID() == APIID_CHANGELOCKINGPASSWORD || rpCmd->GetAPIID() == APIID_SETLOCKINGSTATUS)) {
        void* pBlobError;
        UINT cbBlobError;

        rpRsp->GetBlob(pBlobError, cbBlobError);

        if (pBlobError != NULL && cbBlobError >= sizeof(HRESULT))
        {
            HRESULT hr;

            hr = *((HRESULT*)pBlobError);
            if (hr == RIL_E_SIMPUKREQUIRED) {
                PUKStateReached(TRUE);
            }
        }
    }

    // Is this the last modem init command? If so, and if it succeeded, then we're done with initialization
    if (rpCmd->FFinalInit())
    {
        FinishInit(rpCmd,(RIL_RESULT_OK == rpRsp->GetNotifyCode()));
    }

    // If we're not supposed to ignore the response and the command succeeded,
    //  then we should parse the response data now (so that it can be used by the notification
    //  code below).
    if (!rpCmd->FIgnoreRsp())
    {
        (void)rpRsp->ParseOKOrErrorData(rpCmd, (RIL_RESULT_OK == rpRsp->GetNotifyCode()));
    }

    if ((rpCmd->CmdOptIsSet(CMDOPT_UNLOCKING)) && (RIL_RESULT_OK == rpRsp->GetNotifyCode()))
    {
        // Well, looks like we successfully unlocked the phone
        SendReadyStateNotification(RIL_READYSTATE_UNLOCKED, TRUE);
        Sleep(100);
        (void)SetEvent(g_hSIMUnlockEvent);
        PUKStateReached(FALSE);
    }

    if ((rpCmd->CmdOptIsSet(CMDOPT_RETRYONSIMLOCKED)) && (rpRsp->GetNotifyCode()==RIL_RESULT_ERROR))
    {
        BOOL bPrompt=FALSE;
        void* pBlobSim = NULL;
        UINT cbBlobSim = 0;
        rpRsp->GetBlob(pBlobSim, cbBlobSim);
        ASSERT(cbBlobSim==sizeof(DWORD));
        DWORD dwLockFacility = 0;
        switch(*(DWORD*)pBlobSim)
        {
        case RIL_E_PHSIMPINREQUIRED:
        case RIL_E_PHFSIMPINREQUIRED:
        case RIL_E_PHFSIMPUKREQUIRED:
        case RIL_E_SIMPINREQUIRED:
        case RIL_E_SIMPUKREQUIRED:
        case RIL_E_SIMNOTINSERTED:
        case RIL_E_SIMFAILURE:
            dwLockFacility=SIM_LOCKFACILITY_SIM;
            bPrompt=TRUE;
            break;
        case RIL_E_SIMPIN2REQUIRED:
        case RIL_E_SIMPUK2REQUIRED:
            dwLockFacility=SIM_LOCKFACILITY_SIM_PIN2;
            bPrompt=TRUE;
            break;
        default:
            // Other states do not need action
            bPrompt = FALSE;
        }

        if (bPrompt)
        {
            if (PromptForSimAndRequeueCmd(rpCmd, dwLockFacility))
            {
                delete pnd;
                delete rpRsp;
                rpCmd = NULL;
                rpRsp = NULL;
                return TRUE;
            }
        }
    }

    // If we need to re-init the modem after this command and the command was sucessful, do it
    if (rpCmd->FReinit() && (RIL_RESULT_OK == rpRsp->GetNotifyCode())) {
      PrepareForReinit();
      g_dwSIMLockedState = RIL_LOCKEDSTATE_UNKNOWN;
      if (!g_ComManager.SendInitCmds(FALSE)) {
        // We failed sending the init strings -- RIL is not initialized
        goto Error;
      }
    }

    if (rpCmd->FHangup())
    {
        // If this is a hangup command and we got a NO CARRIER response, turn it into OK
        if (RIL_RESULT_NOCARRIER == rpRsp->GetNotifyCode())
        {
            rpRsp->NoCarrierToOK();
        }
    }

    if (rpCmd->CmdOptIsSet(CMDOPT_SIMQUERY))
    {
        // We were just checking to see if the SIM is ready or not.  We only care about if the return
        // value is NOT READY or not in this case
        hrError = rpRsp->GetError();

        m_fSimReady = (hrError != RIL_E_NOTREADY);
        // If the SIM is not inserted, we can abort the polling for the SIM to be ready
        if (hrError == RIL_E_SIMNOTINSERTED)
        {
            m_fQuitReadyStateThread = TRUE;
            (void)BroadcastRealBlobNotification(RIL_NOTIFY_SIMNOTACCESSIBLE, NULL, 0);
            UpdateSIMState((DWORD)RIL_E_SIMNOTINSERTED);
        }

        if(RIL_RESULT_ERROR == rpRsp->GetNotifyCode())m_fSimReady = FALSE;
        if (m_fSimReady)
        {
            // Hey, as long as we got the PIN state, let's see if it's
            // locked or not.  Why not?
            //DWORD dwReadyState = RIL_READYSTATE_SIM;
            void *pBlobSim = NULL;
            UINT cbBlobSim = 0;

            if (RIL_RESULT_OK == rpRsp->GetNotifyCode())
            {
                rpRsp->GetBlob(pBlobSim, cbBlobSim);

                if ((*(DWORD *) pBlobSim) == RIL_LOCKEDSTATE_READY)
                {
                    //dwReadyState |= RIL_READYSTATE_UNLOCKED;
                    // Wake up the SIM unlocked thread
                    (void)SetEvent(g_hSIMUnlockEvent);
                }
                else if((*(DWORD *) pBlobSim) != RIL_LOCKEDSTATE_UNKNOWN)SendReadyStateNotification(RIL_READYSTATE_SIM, TRUE);
            }

        }

        // Wake up the waiting thread
        (void)SetEvent(m_hSimReadyEvent);
        fRet = TRUE;
        goto Error;
    }

    // If we got a CONNECT response, it must be a response to successful ATD or ATA -- change it to OK
    if (RIL_NOTIFY_CONNECT == rpRsp->GetNotifyCode())
    {
        rpRsp->ConnectToOK();

        // Some networks seem to require a brief delay after a data connection is made
        // before data can be sent via the connection. We pause here before sending the
        // connect response to the client. The delay is configured using a registry value.
        // If the value is not present, then there is no delay.
        DWORD dwTemp = 0;
        if (rpCmd->CmdOptIsSet(CMDOPT_DELAYCONNECTRSP) &&
            GetRegistryDWORD(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, TEXT("ConnectResponseDelay"), &dwTemp))
        {
            Sleep(dwTemp);
        }
    }
    else
    {
        // For non-CONNECT responses, if we have a notification to send upon success, do it now
        pnd = rpCmd->GiveUpNotificationData();
        if (pnd)
        {
            if (RIL_RESULT_OK == rpRsp->GetNotifyCode() &&
                (!pnd->FDelayedInitFromRsp() || pnd->FinishInitFromRspBlob(*rpRsp)))
            {
                BroadcastNotification(pnd);
                pnd = NULL;
            }
            else
            {
                delete pnd;
                pnd = NULL;
            }
        }
    }

    // If we got an RIL_E_SIMNOTINSERTED or RIL_E_SIMFAILURE error, send out a "SIM isn't accessible" notification
    hrError = rpRsp->GetError();
    if (RIL_E_SIMNOTINSERTED == hrError || RIL_E_SIMFAILURE == hrError)
    {
        // Should never be used, since, this notification is also send above, when the PIN state check
        // returns SIM not inserted.
        if (g_PowerManager.IsRadioOff())
        {
            UpdateSIMState((DWORD)RIL_E_RADIOOFF);
        }
        else
        {
            (void)BroadcastRealBlobNotification(RIL_NOTIFY_SIMNOTACCESSIBLE, NULL, 0);
            UpdateSIMState((DWORD)RIL_E_SIMNOTINSERTED);
        }
    }
    if (RILERRORCLASS(hrError) == RIL_ERRORCLASS_SIM)
    {
        UpdateSIMState((DWORD)hrError);
    }

    // Forward the response we got to the handle that sent the command
    rpRsp->GetBlob(pBlob, cbBlob);

    rpCmd->SendResponse(rpRsp->GetNotifyCode(), pBlob, cbBlob);
    rpRsp->DeleteBlob();
    pBlob = NULL;
    cbBlob = 0;
    fRet = TRUE;

    Error:
    delete pnd;
    delete rpCmd;
    delete rpRsp;
    rpCmd = NULL;
    rpRsp = NULL;
    return fRet;
}


//
//
//
BOOL CRilHandle::AppendReadBytes(COM_PORT_TYPE PortType, LPCSTR szBytes, UINT cbBytes)
{
    BOOL fRet = FALSE;

    if (!m_pReadBytes[PortType]) {
      m_pReadBytes[PortType] = new CBuffer;
    }

    if (m_pReadBytes[PortType])
    {
        fRet = m_pReadBytes[PortType]->Append(szBytes, cbBytes);
    }

    if (!fRet)
    {
        // Critically low on memory
        RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: No memory for new bytes to append!")));
        SignalCriticalError();
    }
    return fRet;
}


//
//
//
BOOL CRilHandle::InheritReadBytes(COM_PORT_TYPE PortType, CResponse* const pRsp)
{
    BOOL fRet = FALSE;

    if (!m_pReadBytes[PortType]) {
      m_pReadBytes[PortType] = new CBuffer;
    }

    if (m_pReadBytes[PortType])
    {
        m_pReadBytes[PortType]->InheritData(pRsp);
        fRet = TRUE;
    }

    return fRet;
}


//
//
//
BOOL CRilHandle::GiveUpReadBytes(COM_PORT_TYPE PortType, LPSTR& rszBytes, UINT& rcbBytes)
{
    BOOL fRet = FALSE;

    if (!m_pReadBytes[PortType]) {
      m_pReadBytes[PortType] = new CBuffer;
    }

    if (m_pReadBytes[PortType])
    {
        rcbBytes = m_pReadBytes[PortType]->GetLength();
        rszBytes = m_pReadBytes[PortType]->GiveUpData();
        fRet = TRUE;
    }

    return fRet;
}


//
//
//
BOOL CRilHandle::SetEmergencyMode(const BOOL fMode)
{
    SYNCBLOCK(m_csEmergency);

    DWORD dwNotificationCode;
    BOOL fRet = FALSE;

    if (m_fEmergencyMode && fMode)
    {
        // If we're trying to enter the emergency mode while already in emergency mode, fail
        goto Error;
    }

    // Set the new mode
    m_fEmergencyMode = fMode;

    if (m_fEmergencyMode)
    {
        // We just entered emergency mode
        // Clear the command queue, sending out "cancelled" responses to response callbacks
        g_CmdQ.Enum(GenerateCancelledRsp, (DWORD)this, TRUE);
        dwNotificationCode = RIL_NOTIFY_EMERGENCYMODEENTERED;
    }
    else
    {
        // We just exited emergency mode
        dwNotificationCode = RIL_NOTIFY_EMERGENCYMODEEXITED;
    }

    // Send out an appropriate notification
    (void)BroadcastRealBlobNotification(dwNotificationCode, NULL, 0);
    fRet = TRUE;

    Error:
    return fRet;
}


//
//
//
BOOL CRilHandle::RegisterWithCPM(void)
{
    BOOL fRet = FALSE;

    m_pMonitor = new CMonitor;
    if (!m_pMonitor || !m_pMonitor->Init(m_hCancelEvent))
    {
        goto Error;
    }
    fRet = TRUE;

    Error:
    if (!fRet)
    {
        delete m_pMonitor;
        m_pMonitor = NULL;
    }
    return fRet;
}


//
//
//
void CRilHandle::GetAPIInfo(APIID apiid, APIINFO& rapii)
{
    TCHAR tszRegKey[MAX_PATH];
    char szID[40];
    APIINFO* pNewAPIInfo = NULL;
    DWORD dwDummy;

    // Intialize the output struct with defaults
    rapii.dwTimeout  = g_TimeoutAPIDefault;

    // Check index for cache array
    if ((apiid < 0) || (apiid >= APIID_TOTAL)) {
      goto Error;
    }

    // See if already loaded info for this API
    if (!m_rgpAPIInfo[apiid])
    {
        // Allocate new API info
        pNewAPIInfo = new APIINFO;
        if (!pNewAPIInfo)
        {
            goto Error;
        }

        // Compose the registry key
        (void)_itoa((int)apiid, szID, 10);
        (void)_tcsncpyz(tszRegKey, g_tszRegKeyAPIInfo, MAX_PATH);
        (void)_tcsncatz(tszRegKey, TString(szID), MAX_PATH);

        // Exception for the default timeouts: the dial commands should be aborted only by the user or the
        // network, not by the RIL. For this reason the registry Override=dword:1 has to be set, when the
        // RIL should also have an timeout value.
        if (apiid == APIID_DIAL && !GetRegistryDWORD(HKEY_LOCAL_MACHINE, tszRegKey, TEXT("Override"), &dwDummy))
        {
            pNewAPIInfo->dwTimeout  = INFINITE;
        }
        else if (!GetRegistryDWORD(HKEY_LOCAL_MACHINE, tszRegKey, TEXT("Timeout"), &pNewAPIInfo->dwTimeout))
        {
            // Just use the default
            pNewAPIInfo->dwTimeout  = g_TimeoutAPIDefault;
        }

        // If the timeout is specified as 0 milliseconds, assume INFINITE timeout
        if (!pNewAPIInfo->dwTimeout)
        {
            pNewAPIInfo->dwTimeout = INFINITE;
        }

        // Cache the data we just read
        m_rgpAPIInfo[apiid] = pNewAPIInfo;
        pNewAPIInfo = NULL;
    }

    rapii = *m_rgpAPIInfo[apiid];

    Error:
    delete pNewAPIInfo;
}


//
// Used for cleaning up notification items
// when the notification queue is destroyed.
//
static void NotificationItemDtor(void *pItem)
{
    LocalFree(pItem);
}

//
// Instance handle ctor
//
CRilInstanceHandle::CRilInstanceHandle()
: CListElem(),
m_pDevice(NULL),
m_pCmdList(NULL),
m_hNotifyCancelEvent(NULL),
m_notificationQ(NotificationItemDtor),
m_fInited(FALSE),
m_fPreferred(FALSE)
{
}


//
// Instance handle dtor
//
CRilInstanceHandle::~CRilInstanceHandle()
{
    if (m_fPreferred)
    {
        // Switch RIL out of emergency mode
        (void)m_pDevice->SetEmergencyMode(FALSE);

        // This handle is not preferred anymore
        m_fPreferred = FALSE;
    }

    CancelNotifications();

    delete m_pCmdList;
    m_pCmdList = NULL;

    if (m_hNotifyCancelEvent)
    {
        (void)CloseHandle(m_hNotifyCancelEvent);
        m_hNotifyCancelEvent = NULL;
    }
    m_fInited = FALSE;
}


//
// Initalization
//
BOOL CRilInstanceHandle::Init(CRilHandle* const pDevice)
{
    BOOL fRet = FALSE;

    if (pDevice->FInEmergencyMode())
    {
        // We can't create any additional RIL instances in emergency mode
        goto Error;
    }

    // Create command list
    m_pCmdList = new CDblList<CCommand>;
    if (!m_pCmdList)
    {
        goto Error;
    }

    m_pDevice = pDevice;
    m_fInited = TRUE;
    fRet = TRUE;

    Error:
    return fRet;
}


//
//
//
void CRilInstanceHandle::Notify(const DWORD dwCode, const HRESULT hrCmdID, const void* const pBlob,
                                const UINT cbBlob)
{
    RILDRVNOTIFICATION* prdn = NULL;
    UINT cbTotal;

    // Alocate a notification data structure
    // NOTE: LocalAlloc() is used to prevent allocated memory from being tracked
    //       (since it may be freed by a thread coming from RIL proxy)
    cbTotal = sizeof(RILDRVNOTIFICATION) + cbBlob;
    prdn = (RILDRVNOTIFICATION*)LocalAlloc(0, cbTotal);
    if (!prdn)
    {
        goto Error;
    }

    // Fill in the structure fields
    prdn->cbSize = cbTotal;
    prdn->cbSizeNeeded = cbTotal;
    prdn->dwCode = dwCode;
    prdn->hrCmdID = hrCmdID;
    if (cbBlob)
    {
        memcpy(prdn->pbData, pBlob, cbBlob);
    }

    // Try to queue the structure into the Notification Queue
    // (NOTE: this will fail if the queue is already full -- this guarantees that this RIL thread can't
    //        be blocked by a hanging RIL client)
    if (!m_notificationQ.Put(prdn))
    {
        goto Error;
    }

    // The queue took ownership of the notification data
    //prdn = NULL;
    return;

    Error:
    // NOTE: Since we allocated this structure using LocalAlloc(), we need to use LocalFree() to delete it
    //       (or else the memory tracker will assert)
    LocalFree(prdn);
}


//
// Function passed to CQueue::ConditionalGet() below
//
static BOOL FEnoughStorage(void* pItem, DWORD dwData)
{
    RILDRVNOTIFICATION* prdnNextNotification = (RILDRVNOTIFICATION*)pItem;
    RILDRVNOTIFICATION* prdnSuppliedStruct   = (RILDRVNOTIFICATION*)dwData;

    prdnSuppliedStruct->cbSizeNeeded = prdnNextNotification->cbSizeNeeded;
    return (prdnSuppliedStruct->cbSize >= prdnSuppliedStruct->cbSizeNeeded);
}


//
//
//
BOOL CRilInstanceHandle::GetNextNotification(RILDRVNOTIFICATION& rrdnSuppliedStruct)
{
    RILDRVNOTIFICATION* prdnNextNotification = NULL;
    UINT cbBlob;
    HRESULT hr;
    BOOL fRet = FALSE;

    // Initialize cbSizeNeeded field
    rrdnSuppliedStruct.cbSizeNeeded = rrdnSuppliedStruct.cbSize;

    // Get the next notification from the queue, if the provided size is sufficient
    hr = m_notificationQ.ConditionalGet(FEnoughStorage, (DWORD)&rrdnSuppliedStruct, &prdnNextNotification);
    if (E_FAIL == hr)
    {
        // The supplied size wasn't enough - return TRUE
        fRet = TRUE;
        goto Error;
    }
    else if (S_FALSE == hr)
    {
        goto Error;
    }

    // We shouldn't have to worry about any error result other than E_FAIL.
    rrdnSuppliedStruct.dwCode = prdnNextNotification->dwCode;
    rrdnSuppliedStruct.hrCmdID = prdnNextNotification->hrCmdID;
    cbBlob = prdnNextNotification->cbSize - sizeof(RILDRVNOTIFICATION);
    if (cbBlob)
    {
        memcpy(rrdnSuppliedStruct.pbData, prdnNextNotification->pbData, cbBlob);
    }
    fRet = TRUE;

    Error:
    (void)LocalFree(prdnNextNotification);
    return fRet;
}


//
//
//
BOOL CRilInstanceHandle::MakePreferred(void)
{
    BOOL fRet = FALSE;

    // Switch RIL into emergency mode
    if (!m_pDevice->SetEmergencyMode(TRUE))
    {
        goto Error;
    }

    // Mark this handle as preferred
    m_fPreferred = TRUE;
    fRet = TRUE;

    Error:
    return fRet;
}


//
//
//
BOOL CRilInstanceHandle::CreateNotificationQueue(LPCTSTR tszCancelEventName,
                                                 PBYTE pBufOut, DWORD dwLenOut, PDWORD pdwActualOut)
{
    BOOL fRet = FALSE;
    DWORD dwOut = 0;

    if (!pBufOut || !dwLenOut || !pdwActualOut)
    {
        goto Error;
    }

    // Initialize Notification Q
    if (!m_notificationQ.Init(5))
    {
        goto Error;
    }

    // Create the cancel event
    m_hNotifyCancelEvent = CreateEvent(NULL, TRUE, FALSE, tszCancelEventName);
    if (!m_hNotifyCancelEvent)
    {
        goto Error;
    }

    dwOut = _tcslen(m_notificationQ.GetItemsEventName()) * sizeof(TCHAR) + sizeof(TCHAR);
    if (dwOut > dwLenOut)
    {
        goto Error;
    }

    (void)_tcsncpyz((TCHAR*)pBufOut, m_notificationQ.GetItemsEventName(), dwLenOut);
    *pdwActualOut = dwOut;


    fRet = TRUE;

    Error:
    return fRet;
}

//
//
//
DWORD CRilHandle::AckSMSThread(void)
{
    DWORD dwEvent;

    for (;;)
    {
        dwEvent = WaitForSingleObject(g_hAckSMSEvent, INFINITE);
        // See if the thread needs to terminate
        if (FCancelSet())
        {
            break;
        }
        if(dwEvent == WAIT_OBJECT_0)
        {
            g_dwLastSMSCmd = GetTickCount();
            Sleep(CNMA_DELAY);

            (void)QueueInternalCmd(HCCMD_URCPORT_ONLY, this, "AT+CNMA=0\r", CMDOPT_NONE|CMDOPT_SMSACK, APIID_SENDMSGACKNOWLEDGEMENT, 2500, 2, CNMA_DELAY);
        }
    }

    return 0;
}

//
//
//
static DWORD WINAPI AckSMSThreadProc(LPVOID lpParameter)
{
    CRilHandle* pRilDevice = (CRilHandle*)lpParameter;

    if (!SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL))
    {
        return 0;
    }

    const DWORD dwReturn = pRilDevice->AckSMSThread();
    return dwReturn;
}

//-----------------------------------------------
// Handling of special CUSD-URC
//-----------------------------------------------

void CRilHandle::EnterUSSDAnswerMode(COM_PORT_TYPE /*PortType*/)
{
    RILRetailTraceZone(ZONE_ATCOMMAND, (TEXT("RilDrv: USSD Answer Mode entered.\r\n")));
    m_fUSSDAnswerMode = TRUE;
}

void CRilHandle::LeaveUSSDAnswerMode(COM_PORT_TYPE PortType, BYTE* pData, DWORD dwSize)
{
    const BYTE bCtrlZ = 26;
    DWORD dwDummy;

    if (m_fUSSDAnswerMode)
    {
        (void)m_pComDevice[PortType]->VirtWrite(pData, dwSize, dwDummy);
        RILRetailTraceZone(ZONE_ATCOMMAND, (TEXT("RilDrv: USSD Answer Mode: sending %a.\r\n"), pData)); // pData is a zero-terminated string.
        (void)m_pComDevice[PortType]->VirtWrite(&bCtrlZ, 1, dwDummy);
        RILRetailTraceZone(ZONE_ATCOMMAND, (TEXT("RilDrv: USSD Answer Mode: sending Ctrl-Z.\r\n")));
    }
    RILRetailTraceZone(ZONE_ATCOMMAND, (TEXT("RilDrv: USSD Answer Mode left.\r\n")));
    m_fUSSDAnswerMode = FALSE;
}

void CRilHandle::CancelUSSDAnswerMode(COM_PORT_TYPE PortType)
{
    const BYTE bESC = 27;
    DWORD dwDummy;

    if (m_fUSSDAnswerMode) {
        (void)m_pComDevice[PortType]->VirtWrite(&bESC, 1, dwDummy);
        RILRetailTraceZone(ZONE_ATCOMMAND, (TEXT("RilDrv: USSD Answer Mode: sending ESC.\r\n")));
    }
    m_fUSSDAnswerMode = FALSE;
    RILRetailTraceZone(ZONE_ATCOMMAND, (TEXT("RilDrv: USSD Answer Mode canceled.\r\n")));
    Sleep(250);
}

INT CRilHandle::GetPortInUSSDAnswerMode(void) const
{
    INT iPort;

    for (iPort = 0; iPort < NUMBER_OF_PORTS; iPort++) {
        if (m_fUSSDAnswerMode)
            break;
    }

    return iPort;
}

void CRilHandle::AbortRunningCommand() const
{
    if (m_pComDevice[DATA_PORT]->FDataMode())
        (void)m_pComDevice[URC_PORT]->AbortCommand();
    else
        (void)m_pComDevice[DATA_PORT]->AbortCommand();
}

//
// Writes current system time to radio.
//
BOOL CRilHandle::SetTimeInModule(void)
{
    char szCmd[MAX_ATCMD_LEN];
    SYSTEMTIME curTime;
    BOOL fRet = TRUE;

    // While in CDMA mode, the module will automatically update the internal clock.
    if (m_dwDisableSyncTime != 1 && GetCurrentTechnology() != TEC_MODE_CDMA)
    {
        DWORD dwSyncUTC = 1;

        // The module's RTC doesn't support time zones, so the RIL decideces with
        // a registry key wether to sync the RTC to the local time or the UTC.
        // UTC is the default value, since the A-GPS feature requires the UTC, but
        // SAT applications may require the local time.
        (void)GetRegistryDWORD(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, TEXT("SyncClockWithUTC"), &dwSyncUTC);
        if (dwSyncUTC == 1)
            GetSystemTime(&curTime);    // Get UTC
        else
            GetLocalTime(&curTime);     // Get local time

        (void)_snprintfz(szCmd, MAX_ATCMD_LEN,"AT+CCLK=\"%02d/%02d/%02d,%02d:%02d%:%02d\"\r\0", curTime.wYear%100, curTime.wMonth, curTime.wDay, curTime.wHour, curTime.wMinute, curTime.wSecond);
        fRet = QueueInternalCmd(HCCMD_STANDARD, this, szCmd, CMDOPT_URC, APIID_SETRADIOCLOCK, 0, 0, 0);
    }
    return fRet;
}

BOOL CRilHandle::IgnoreCIEVAudioSounder(void) const
{
    DWORD dwTimer = GetTickCount();

    if (m_fNoAudioForCSD && SUPPORTS_SLCC && !AVOID_SLCC) {
        BOOL bCSDDialing = FALSE;

        // Find out, if ther is currently a CSD call in dialing state. Since
        // the "NoAudioForCSD" registry key is set, audio must not be
        // set in this case.
        EnterCriticalSection(&g_CallInfoSection);
        // Skip  test, if there is no call at all or voice and CSD calls simultaniously.
        if (g_iNrCallInfo == 1) {
            if (g_CallInfo[0].dwStatus==RIL_CALLSTAT_DIALING && g_CallInfo[0].dwType == RIL_CALLTYPE_DATA)
                bCSDDialing = TRUE;
        }
        LeaveCriticalSection(&g_CallInfoSection);

        if (bCSDDialing)
            return TRUE;
    }
    return (!m_fCIEVaudioUsed && (dwTimer-m_dwLastSATPlayToneCmd>SATPLAYTONEAUDIO_TIMEOUT)) || (dwTimer-m_dwIgnoreNextCIEVAudioTimer<CHLD0BUSYTONE_TIMEOUT);
};

static HRESULT ParseLimitedServiceState(LPCSTR szRsp, void*& pBlob, UINT& cbBlob, LPVOID pParam)
{
    DWORD *pdwState = (DWORD *)pParam;

    pBlob = NULL;
    cbBlob = 0;

    // Parse "<prefix>^SMONI: "
    if (!ParseRspPrefix(szRsp, szRsp) ||
        !MatchStringBeginning(szRsp, "^SMONI: ", szRsp)) {
        goto Error;
    }

    if (MatchStringAnywhere(szRsp, "SEARCH", szRsp))
        *pdwState = SMONI_STATE_SEARCHING  ;
    else if (MatchStringAnywhere(szRsp, "LIMSRV", szRsp))
        *pdwState = SMONI_STATE_LIMITED_SERVICE;

Error:
    return S_OK;
}

DWORD GetExtRegistrationState(DWORD dwRegStateNormal, DWORD dwMoniState, SIMTYPE iSIMType)
{
    DWORD dwReg = dwRegStateNormal;

    // Use "unregistered" as default value.
    if (dwReg == RIL_REGSTAT_UNKNOWN)
        dwReg = RIL_REGSTAT_UNREGISTERED;

    if (dwMoniState == SMONI_STATE_LIMITED_SERVICE)
        dwReg |= RIL_EXT_REGSTAT_LIMITED_SERVICE;
    else if (dwMoniState == SMONI_STATE_SEARCHING)
        dwReg |= RIL_EXT_REGSTAT_NO_COVERAGE;

    // The SMONI command might ommit the "limited service" notification.
    if (MISSING_LIMSERV_ON_SMONI && (dwReg == RIL_REGSTAT_DENIED || dwReg == RIL_REGSTAT_UNREGISTERED)) {
        // In case the SIM is missing or the PIN is not entered, it is save to asume,
        // that the module is now in the limited service.
        if (iSIMType == SIMTYPE_NOT_INSERTED || (g_dwSIMLockedState != RIL_LOCKEDSTATE_READY && g_dwSIMLockedState != RIL_LOCKEDSTATE_UNKNOWN))
            dwReg |= RIL_EXT_REGSTAT_LIMITED_SERVICE;
    }
    return dwReg;
}

static DWORD WINAPI CheckExRegistration(LPVOID pVoid)
{
    CHECKEXTREG_THREAD_DATA *pData = (CHECKEXTREG_THREAD_DATA *)pVoid;
    CRilHandle* pHandle;
    DWORD dwMoniState = SMONI_STATE_UNKNOWN;
    DWORD dwReg;
    DWORD dwLastRegStatus;
    DWORD dwPollingInterval = 0;

    pHandle = pData->pHandle;
    dwReg = pData->dwRegStatus;
    delete pData;

    // Ignore possible error code: if command fails, dwMoniState still got its default value.
    if (!SMONI_UNAVAILABLE)
        (void)QueueInternalCmdBlocking(HCCMD_STANDARD, pHandle, "AT^SMONI\r", CMDOPT_NONE, APIID_GETCELLTOWERINFO, 0, 0, 0, ParseLimitedServiceState, NULL, &dwMoniState);

    dwReg = GetExtRegistrationState(dwReg, dwMoniState, pHandle->GetCurrentSIMType());

    pHandle->SendExtRegStatusNotification(dwReg);
    dwLastRegStatus = dwReg;

    // Configuration via registry: is the polling mode is enabled, the RIL periodically checks, if
    // the status has been changed. The polling is necessary, because the radio doesn't have
    // any kind of URC which indicates a change between RIL_EXT_REGSTAT_LIMITED_SERVICE
    // and RIL_EXT_REGSTAT_NO_COVERAGE.
    (void)GetRegistryDWORD(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, TEXT("ExtendedRegStatusNotificationPolling"), &dwPollingInterval);

    if (dwPollingInterval > 0 && !g_fExtRegStatusPollingActive) {
        // Set g_fExtRegStatusPollingActive to prevent the polling to start a 2nd time per accident. An advanced
        // locking mechanism isn't necessary here, because the events triggering a polling come always with a
        // sufficient time difference.
        g_fExtRegStatusPollingActive = TRUE;
        while(g_dwRegStatus != RIL_REGSTAT_HOME && g_dwRegStatus != RIL_REGSTAT_ROAMING && !g_PowerManager.IsRadioOff()) {
            dwReg = g_dwRegStatus;
            dwMoniState = SMONI_STATE_UNKNOWN;

            // Ignore possible error code: if command fails, dwMoniState still got its default value.
            if (!SMONI_UNAVAILABLE)
                (void)QueueInternalCmdBlocking(HCCMD_STANDARD, pHandle, "AT^SMONI\r", CMDOPT_NONE, APIID_GETCELLTOWERINFO, 0, 0, 0, ParseLimitedServiceState, NULL, (LPVOID)&dwMoniState);

            dwReg = GetExtRegistrationState(dwReg, dwMoniState, pHandle->GetCurrentSIMType());

            // Send new notification only, if status has changed.
            if (dwLastRegStatus != dwReg)
                pHandle->SendExtRegStatusNotification(dwReg);
            dwLastRegStatus = dwReg;

            Sleep(dwPollingInterval);
        }
        g_fExtRegStatusPollingActive = FALSE;
    }
    return 0;
}

//
// Sends RIL_NOTIFY_REGSTATUSCHANGED notification and, if configured,
// also the RIL_NOTIFY_DEVSPECIFIC_REGSTATUS_EX
//
void CRilHandle::GenerateRegStatusNotification(DWORD dwRegStatus, BOOL bSupressOrgNotification)
{
    // Always send normal notification (if not explicitly suppressed).
    if (!bSupressOrgNotification)
        (void)BroadcastDWORDBlobNotification(RIL_NOTIFY_REGSTATUSCHANGED, dwRegStatus);

    // If configured, also send extended notification.
    if (m_fExtendedRegStatusNotification) {
        // Unless the module is already registered, try to find out, if there is at least some
        // network with limited service visible.
        if (dwRegStatus != RIL_REGSTAT_HOME && dwRegStatus != RIL_REGSTAT_ROAMING) {
            CHECKEXTREG_THREAD_DATA *pData;

            pData = new CHECKEXTREG_THREAD_DATA;
            if (pData != NULL) {
                pData->pHandle = this;
                pData->dwRegStatus = dwRegStatus;

                CloseHandle(CreateThread(NULL, 0, CheckExRegistration, (LPVOID)pData, 0, 0));
            }
            else
                SendExtRegStatusNotification(dwRegStatus);
        }
        else
            SendExtRegStatusNotification(dwRegStatus);
    }
};

// Sends the RIL_NOTIFY_DEVSPECIFIC_REGSTATUS_EX according to active
// filter rules.
void CRilHandle::SendExtRegStatusNotification(DWORD dwRegStatus)
{
    BOOL fSend = FALSE;

    switch (m_dwConfigureExtRegStatus) {
        case 0:         // 0: Send always notifications
            fSend = TRUE;
            break;
        case 1:         // 1: Send notification only for Unregistered/Denied
            if ((dwRegStatus & 0xFF) == RIL_REGSTAT_UNREGISTERED || (dwRegStatus & 0xFF) == RIL_REGSTAT_DENIED)
                fSend = TRUE;
            break;
        case 2:         // 2: Send notification for everything expect "searching"
            if ((dwRegStatus & 0xFF) != RIL_REGSTAT_ATTEMPTING)
                fSend = TRUE;
            break;
        default:      // Other values: suppress notification
            fSend = FALSE;
    }

    if (fSend)
        (void)BroadcastDWORDBlobNotification(RIL_NOTIFY_DEVSPECIFIC_REGSTATUS_EX, dwRegStatus);
}

MULTIMODE_CONFIG CRilHandle::GetMultiModeSetting(void) const
{
    if (GLOBAL_MODE_RADIO)
        return m_nMultiModeSetting;
    if (CDMA_ONLY_RADIO)
        return MULTIMODE_CONFIG_CDMA;
    return MULTIMODE_CONFIG_LTE;
};


//-----------------------------------------------
// Handling of mute during VTS
//-----------------------------------------------

DWORD WINAPI CRilHandle::TempMuteThread(LPVOID lpParam) {
    CRilHandle*  pHandle = (CRilHandle*)lpParam;

    return pHandle->TempMuteThreadProc();
}

DWORD CRilHandle::TempMuteThreadProc() {

    while (!g_PowerManager.IsRadioOff() || g_iNrCallInfo != 0) {
        if (m_dwTempMuteRunning == 0 && GetTickCount() >= m_dwTempMuteEnd+m_dwTempMuteDelay)
            break;
        Sleep(100);
    }

    if (g_dwLastMuteSetting != 1)
        (void)QueueInternalCmd(HCCMD_STANDARD, this, "AT+CMUT=0\r", CMDOPT_NONE, APIID_SETAUDIOMUTING, 0, 0, 0);
    m_dwTempMuteRunning = 0;
    m_hNoMuteThread = NULL;
    return 0;
}

void CRilHandle::StartTemporaryMuting()
{
    m_dwTempMuteEnd = 0;
    m_dwTempMuteRunning ++;
    if (m_hNoMuteThread == NULL && m_dwTempMuteDelay > 0 && IsVoiceCallActive(this))
    {
        m_dwTempMuteRunning = 1;
        (void)QueueInternalCmd(HCCMD_STANDARD, this, "AT+CMUT=1\r", CMDOPT_NONE, APIID_SETAUDIOMUTING, 0, 0, 0);
        m_hNoMuteThread = CreateThread(0, 0, TempMuteThread, this, 0, 0);
        CloseHandle(m_hNoMuteThread);
    }
}

void CRilHandle::StopTemporaryMuting()
{
    if (m_dwTempMuteRunning > 0)
        m_dwTempMuteRunning --;
    m_dwTempMuteEnd = GetTickCount();
}

void CRilHandle::PUKStateReached(BOOL fPINstate)
{
    if (!m_fIPUKrequieredAfterPINchange && fPINstate && NO_UNREGISTER_IN_PUK_STATE)
    {
#ifdef RILDRV_CE6
        BOOL bAttached = FALSE;
#endif

        // The radio doesn't de-register as required for IOTAS conformace. Solution: the
        // RIL temporarily powers down HF, therby forcing the module to de-register.
        (void)QueueInternalCmd(HCCMD_STANDARD, this, "AT+CFUN=4;+CFUN=1\r", CMDOPT_NONE, APIID_SETEQUIPMENTSTATE, 0, 0, 0, NULL);

        // Send notifications to inform MMI about the new status of the SIM
        GenerateRegStatusNotification(RIL_REGSTAT_UNREGISTERED);
        (void)BroadcastDWORDBlobNotification(RIL_NOTIFY_GPRSREGSTATUSCHANGED, RIL_REGSTAT_UNREGISTERED);
        SendReadyStateNotification(RIL_READYSTATE_NONE, FALSE);
        UpdateSIMState(RIL_LOCKEDSTATE_SIM_PUK);
#ifdef RILDRV_CE6
        (void)BroadcastRealBlobNotification(RIL_NOTIFY_GPRSATTACHED, (LPVOID)&bAttached, sizeof(BOOL));
#endif
    }
    if (m_fIPUKrequieredAfterPINchange && !fPINstate && NO_UNREGISTER_IN_PUK_STATE)
    {
        // If necessary, force net network registration.
        if (NO_REGISTER_AFTER_CFUN_IN_PUK_STATE) {
            char szCmd[MAX_ATCMD_LEN];

            // Unfortunately the modules doesn't register automatically to the network after
            // using the AT+CFUN command during PUK state, so the RIL has to force the
            // re-registration to the network.
            if (g_iLastCOPS == 1 && g_iLastCOPSOpr > 0) {
                if (g_n2G3GSelection == SELECTION2G3G_GSM_ONLY)
                    (void)_snprintfz(szCmd, MAX_ATCMD_LEN, "AT+COPS=2;+COPS=1,2,%u,0\r", g_iLastCOPSOpr);
                else if (g_n2G3GSelection == SELECTION2G3G_UMTS_ONLY)
                    (void)_snprintfz(szCmd, MAX_ATCMD_LEN, "AT+COPS=2;+COPS=1,2,%u,2\r", g_iLastCOPSOpr);
                else
                    (void)_snprintfz(szCmd, MAX_ATCMD_LEN, "AT+COPS=2;+COPS=1,2,%u\r", g_iLastCOPSOpr);
            }
            else {
                if (g_n2G3GSelection == SELECTION2G3G_GSM_ONLY)
                    (void)_snprintfz(szCmd, MAX_ATCMD_LEN, "AT+COPS=2;+COPS=0,,,0\r");
                else if (g_n2G3GSelection == SELECTION2G3G_UMTS_ONLY)
                    (void)_snprintfz(szCmd, MAX_ATCMD_LEN, "AT+COPS=2;+COPS=0,,,2\r");
                else
                    (void)_snprintfz(szCmd, MAX_ATCMD_LEN, "AT+COPS=2;+COPS=0\r");
            }

            (void)QueueInternalCmd(HCCMD_STANDARD, this, szCmd, CMDOPT_NONE, APIID_REGISTERONNETWORK, 0, 0, 0, NULL);

            if (COPS_CHANGES_SCFG || (COPS1_CHANGES_SCFG && g_iLastCOPS == 1 && g_iLastCOPSOpr > 0)) {
                // Bug in PXS8: the use of AT+COPS changes the module from GSM-only to
                // multimode. If necessary, the RIL must change the setting back.
                if (GetMultiModeSetting() == MULTIMODE_CONFIG_LTE)
                    (void)QueueInternalCmd(HCCMD_STANDARD, this, "AT^SCFG=MEopMode/AccT,\"GSM/UMTS\"\r", CMDOPT_NONE, APIID_SCFGRADIOBAND, 0, 0, 0);
            }
        }

        // Send notifications to inform MMI about the new start of the SIM
        SendReadyStateNotification(RIL_READYSTATE_INITIALIZED, TRUE);
        GenerateRegStatusNotification(RIL_REGSTAT_ATTEMPTING);
    }
    m_fIPUKrequieredAfterPINchange = fPINstate;
    return;
}

// When connected to HSDPA the module might intermittend show UMTS as
// used network technology, even though the module is still connected
// to UMTS. This function will return HSDPA in this situation.
DWORD CRilHandle::GetCorrectNetworkTechnology(DWORD dwOriginalState)
{
    WCHAR wszNoHSDPA[MAX_ATCMD_LEN];
    DWORD dwNewState = dwOriginalState;

    if (dwOriginalState < 5) {
        // 2G detected, reset HSDPA detection.
        m_dwHSDPAdetected = 0;
    }
    else if (dwOriginalState < 7) {
        // UMTS indicated, but HSDPA already detected?
        if (m_dwHSDPAdetected > 0)
            dwNewState = m_dwHSDPAdetected;    // Return HSDPA
    }
    else if (dwOriginalState < 11) {
        DWORD dwReg;

        // HSDPA detected. Store this fact (if configured).
        if (!GetRegistryDWORD(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, TEXT("KeepHsdpaStatusIcon"), &dwReg))
            dwReg = 0;
        if (dwReg != 0)
            m_dwHSDPAdetected = dwOriginalState;
    }
    else {
        // CDMA detected, reset HSDPA detection.
        m_dwHSDPAdetected = 0;
    }

    // Additional possibility: for some networks the module will never report "HSDPA".
    // If configured via registry key for some network the RIL will always report
    // "HSDPA" when the module indicates "UMTS".
    memset(wszNoHSDPA, 0, sizeof(wszNoHSDPA));
    if (dwNewState >= 5 && dwNewState <= 6 && g_iLastCOPSOpr > 0 && GetRegistrySZ(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, TEXT("ForceHsdpaIndication"), wszNoHSDPA, MAX_ATCMD_LEN))
    {
        char szOperator[MAX_ATCMD_LEN];

        (void)_snprintfz(szOperator, MAX_ATCMD_LEN, "%d", g_iLastCOPSOpr);
        if (wcscmp(wszNoHSDPA, L"all") == 0 || IsInList(wszNoHSDPA, szOperator, L",")) {
            // For this network the RIL should report "HSDPA" instead of "UMTS".
            dwNewState += 2;
        }
    }


    return dwNewState;
}

void CRilHandle::SetLastDialedNumber(const char *szLastDialedNumber)
{
    INT iRead = 0;
    INT iWrite = 0;
    INT iLen = strlen(szLastDialedNumber);

    memset(m_szLastDialedNumber, 0, MAX_ATCMD_LEN);
    while (iRead < iLen && iWrite < MAX_ATCMD_LEN) {
        // Don't include the call modifiers "T" and "P".
        if (szLastDialedNumber[iRead] != 'T' && szLastDialedNumber[iRead] != 'P') {
            m_szLastDialedNumber[iWrite] = szLastDialedNumber[iRead];
            iWrite++;
        }
        iRead++;
    }
    return;
};

void CRilHandle::SetEmergencyReadyState(BOOL fEmergencyFlag, BOOL fBroadcast)
{
#if defined (RIL_READYSTATE_EMERGENCY)
    DWORD dwReadyState = g_dwReadyState;

    // Emergency flag can only be set, if the module has been initialized.
    if ((dwReadyState&RIL_READYSTATE_INITIALIZED) == 0) return;

    // Set/reset emergency flag
    if (fEmergencyFlag) dwReadyState |= RIL_READYSTATE_EMERGENCY;
    else dwReadyState &= ~RIL_READYSTATE_EMERGENCY;

    if (dwReadyState != g_dwReadyState) {
        // Apply new state
        g_dwReadyState = dwReadyState;
        // Send notification (if required)
        SendReadyStateNotification(dwReadyState, fBroadcast);
    }
#endif
}

static HRESULT ParseGetCurrentRoaming(LPCSTR szRsp, void*& pBlob, UINT& cbBlob, LPVOID pParam)
{
    HRESULT hr = S_OK;
    UINT uiRoaming;
    UINT *puiRoaming = (UINT *)pParam;

    pBlob = NULL;
    cbBlob = 0;

    // Parse "<prefix>$ERI: <RoamMode>"
    if (!ParseRspPrefix(szRsp, szRsp)                  ||
        !MatchStringBeginning(szRsp, "$ERI:", szRsp) ||
        !ParseUInt(szRsp, TRUE, uiRoaming, szRsp)) {
        hr = E_FAIL;
        goto Error;
    }

    // Parse "<postfix>"
    if (!ParseRspPostfix(szRsp, szRsp)) {
        hr = E_FAIL;
        goto Error;
    }

    if (puiRoaming != NULL) {
        *puiRoaming = uiRoaming;
    }

Error:
    return hr;
}

//
// Relevant for Sprint approval: if a voice call is initiated while the device
// is roaming, there should be a warning.
//
void CRilHandle::SprintVoiceCallRoamingWarning(void)
{
    DWORD dwReg = 1;
    UINT  uiRoamMode = 1;
    UINT  uiText = 0;

    // Only on CDMA.
    if (GetCurrentTechnology() != TEC_MODE_CDMA) return;
    // Check if warning option is enabled.
    (void)GetRegistryDWORD(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, TEXT("ActivateSprintRoamingWarning"), &dwReg);
    if (dwReg != 1) return;
    // Applies only on Sprint network.
    if (_stricmp(m_szCdmaProvider, "Sprint") != 0) return;

    // Check current roaming status.
    if (QueueInternalCmdBlocking(HCCMD_STANDARD, this, "AT$ERI?\r", CMDOPT_NONE, APIID_GETROAMINGMODE, 0, 0, 0, ParseGetCurrentRoaming, NULL, (LPVOID)&uiRoamMode)) {
        // Possible roaming modes:
        // 160: domestic roaming
        // 228: international roaming
        // 1: home (no warning)
        if (uiRoamMode == 160)
            uiText = IDS_SPRINT_WARN_ROAM_DOMESTIC;
        else if (uiRoamMode == 228)
            uiText = IDS_SPRINT_WARN_ROAM_INTERNATIONAL;
    }

    // If there is a warning message, show it via USSD notification.
    if (uiText != 0)
    {
        CNotificationData* pnd = NULL;
        RILSUPSERVICEDATA *prssd;
        UINT cbStruct;
        WCHAR wszText[MAX_RESOURCE_STRING_LEN];

        if (LoadString((HINSTANCE)hInstance, uiText, wszText, MAX_RESOURCE_STRING_LEN) > 0)
        {
            cbStruct = sizeof(RILSUPSERVICEDATA) + (wcslen(wszText) * sizeof(WCHAR)) + sizeof(WCHAR);
            prssd = (RILSUPSERVICEDATA*)AllocBlob(cbStruct);
            if (prssd != NULL)
            {
                memcpy(prssd->pbData, (BYTE *)wszText, (wcslen(wszText) * sizeof(WCHAR)) + sizeof(WCHAR));
                prssd->dwParams = RIL_PARAM_SSDI_DATA;
                prssd->dwStatus = RIL_SUPSVCDATASTATUS_UNSUPPORTED;
                prssd->dwParams |= RIL_PARAM_SSDI_STATUS;
                prssd->cbSize = cbStruct;
                pnd = new CNotificationData;
                if (pnd)
                {
                    if (pnd->InitFromRealBlob(RIL_NOTIFY_SUPSERVICEDATA, (void*)prssd, prssd->cbSize))
                        BroadcastNotification(pnd);
                    else
                        delete pnd;
                }
                FreeBlob(prssd);
            }
        }
    }
    return;
}

//-----------------------------------------------
// Wrapper for all RHA functions
//-----------------------------------------------

void RHA_Init()
{
    RILRetailTraceZone(ZONE_RHA, (TEXT("RilDrv: call RHA_Init()\r\n")));
    if (RHAFunctionList.pfnRHA_Init != NULL)
        RHAFunctionList.pfnRHA_Init();
    return;
}

void RHA_DeInit()
{
    RILRetailTraceZone(ZONE_RHA, (TEXT("RilDrv: call RHA_DeInit()\r\n")));
    if (RHAFunctionList.pfnRHA_DeInit != NULL)
        RHAFunctionList.pfnRHA_DeInit();
    return;
}

BOOL RHA_RadioPwrOn()
{
    BOOL fRet;

    RILRetailTraceZone(ZONE_RHA, (TEXT("RilDrv: call RHA_RadioPwrOn()\r\n")));
    fRet = RHAFunctionList.pfnRHA_RadioPwrOn();
    RILRetailTraceZone(ZONE_RHA, (TEXT("RilDrv: call RHA_RadioPwrOn() returned %d\r\n"), fRet));
    return fRet;
}

BOOL RHA_RadioPwrOff()
{
    BOOL fRet;

    RILRetailTraceZone(ZONE_RHA, (TEXT("RilDrv: call RHA_RadioPwrOff()\r\n")));
    fRet = RHAFunctionList.pfnRHA_RadioPwrOff();
    RILRetailTraceZone(ZONE_RHA, (TEXT("RilDrv: call RHA_RadioPwrOff() returned %d\r\n"), fRet));
    return fRet;
}

BOOL RHA_IsRadioPwrOn()
{
    BOOL fRet;

    RILRetailTraceZone(ZONE_RHA_POWER, (TEXT("RilDrv: call RHA_IsRadioPwrOn()\r\n")));
    fRet = RHAFunctionList.pfnRHA_IsRadioPwrOn();
    RILRetailTraceZone(ZONE_RHA_POWER, (TEXT("RilDrv: call RHA_IsRadioPwrOn() returned %d\r\n"), fRet));
    return fRet;
}

BOOL RHA_ActivateVoicePath(DWORD dwTxAudioMode, DWORD dwRxAudioMode)
{
    BOOL fRet;

    RILRetailTraceZone(ZONE_RHA, (TEXT("RilDrv: call RHA_ActivateVoicePath(%d,%d)\r\n"), dwTxAudioMode, dwRxAudioMode));
    fRet = RHAFunctionList.pfnRHA_ActivateVoicePath(dwTxAudioMode, dwRxAudioMode);
    RILRetailTraceZone(ZONE_RHA, (TEXT("RilDrv: call RHA_ActivateVoicePath returned %d\r\n"), fRet));
    return fRet;
}

BOOL RHA_DeactivateVoicePath()
{
    BOOL fRet;

    RILRetailTraceZone(ZONE_RHA, (TEXT("RilDrv: call RHA_DeactivateVoicePath()\r\n")));
    fRet = RHAFunctionList.pfnRHA_DeactivateVoicePath();
    RILRetailTraceZone(ZONE_RHA, (TEXT("RilDrv: call RHA_DeactivateVoicePath returned %d\r\n"), fRet));
    return fRet;
}

BOOL RHA_AdjustTxVolume(DWORD dwAudioMode, DWORD dwExtMicAudioCodecVol)
{
    BOOL fRet;

    RILRetailTraceZone(ZONE_RHA, (TEXT("RilDrv: call RHA_AdjustTxVolume(%d, %d)\r\n"), dwAudioMode, dwExtMicAudioCodecVol));
    fRet = RHAFunctionList.pfnRHA_AdjustTxVolume(dwAudioMode, dwExtMicAudioCodecVol);
    RILRetailTraceZone(ZONE_RHA, (TEXT("RilDrv: call RHA_AdjustTxVolume returned %d\r\n"), fRet));
    return fRet;
}

BOOL RHA_AdjustRxVolume(DWORD dwAudioMode, DWORD dwExtMicAudioCodecVol)
{
    BOOL fRet;

    RILRetailTraceZone(ZONE_RHA, (TEXT("RilDrv: call RHA_AdjustRxVolume(%d, %d)\r\n"), dwAudioMode, dwExtMicAudioCodecVol));
    fRet = RHAFunctionList.pfnRHA_AdjustRxVolume(dwAudioMode, dwExtMicAudioCodecVol);
    RILRetailTraceZone(ZONE_RHA, (TEXT("RilDrv: call RHA_AdjustRxVolume returned %d\r\n"), fRet));
    return fRet;
}

BOOL RHA_GetRHAVersion(DWORD *pRHAVersion)
{
    RILRetailTraceZone(ZONE_RHA, (TEXT("RilDrv: call RHA_GetRHAVersion()\r\n")));
    return RHAFunctionList.pfnRHA_GetRHAVersion(pRHAVersion);
}

BOOL RHA_ConfirmAudioMode(DWORD *dwTxAudioMode, DWORD *dwRxAudioMode)
{
    BOOL fRet;

    if (dwTxAudioMode != NULL && dwRxAudioMode != NULL) {
        RILRetailTraceZone(ZONE_RHA, (TEXT("RilDrv: call RHA_ConfirmAudioMode(%d,%d)\r\n"), *dwTxAudioMode, *dwRxAudioMode));
    }
    fRet = RHAFunctionList.pfnRHA_ConfirmAudioMode(dwTxAudioMode, dwRxAudioMode);
    if (dwTxAudioMode != NULL && dwRxAudioMode != NULL) {
        RILRetailTraceZone(ZONE_RHA, (TEXT("RilDrv: call RHA_ConfirmAudioMode() returned %d (%d,%d)\r\n"), fRet, *dwTxAudioMode, *dwRxAudioMode));
    }
    return fRet;
}

DWORD RHA_SystemPowerChange(CEDEVICE_POWER_STATE CurrPwrState, CEDEVICE_POWER_STATE NewPwrState, DWORD dwCurrModuleState, DWORD dwNewDefaultModuleState, BOOL fOngoing, BOOL fQuery)
{
    DWORD dwRet;

    RILRetailTraceZone(ZONE_RHA, (TEXT("RilDrv: call RHA_SystemPowerChange(%d,%d,%d,%d,%d,%d)\r\n"), CurrPwrState, NewPwrState, dwCurrModuleState, dwNewDefaultModuleState, fOngoing, fQuery));
    dwRet = RHAFunctionList.pfnRHA_SystemPowerChange(CurrPwrState, NewPwrState, dwCurrModuleState, dwNewDefaultModuleState, fOngoing, fQuery);
    RILRetailTraceZone(ZONE_RHA, (TEXT("RilDrv: call RHA_SystemPowerChange() returned %d\r\n"), dwRet));
    return dwRet;
}

BOOL RHA_GpsAntennaPowerSupplyOn()
{
    BOOL fRet = TRUE;

    RILRetailTraceZone(ZONE_RHA, (TEXT("RilDrv: call RHA_GpsAntennaPowerSupplyOn()\r\n")));
    if (RHAFunctionList.pfnRHA_GpsAntennaPowerSupplyOn) {
        fRet = RHAFunctionList.pfnRHA_GpsAntennaPowerSupplyOn();
        RILRetailTraceZone(ZONE_RHA, (TEXT("RilDrv: call RHA_GpsAntennaPowerSupplyOn() returned %d\r\n"), fRet));
    }
    else {
        RILRetailTraceZone(ZONE_RHA, (TEXT("RilDrv: RHA_GpsAntennaPowerSupplyOn() not in RHA\r\n")));
    }
    return fRet;
}

BOOL RHA_GpsAntennaPowerSupplyOff()
{
    BOOL fRet = TRUE;

    RILRetailTraceZone(ZONE_RHA, (TEXT("RilDrv: call RHA_GpsAntennaPowerSupplyOff()\r\n")));
    if (RHAFunctionList.pfnRHA_GpsAntennaPowerSupplyOff) {
        fRet = RHAFunctionList.pfnRHA_GpsAntennaPowerSupplyOff();
        RILRetailTraceZone(ZONE_RHA, (TEXT("RilDrv: call RHA_GpsAntennaPowerSupplyOff() returned %d\r\n"), fRet));
    }
    else {
        RILRetailTraceZone(ZONE_RHA, (TEXT("RilDrv: RHA_GpsAntennaPowerSupplyOff() not in RHA\r\n")));
    }
    return fRet;
}

#ifdef RIL_RADIO_RESILIENCE
void RHA_SetRadioIgnition(BOOL bIgnition)
{
    BOOL fRet;

    RILRetailTraceZone(ZONE_RHA, (TEXT("RilDrv: call RHA_SetRadioIgnition(%d)\r\n"), bIgnition));
    if (RHAFunctionList.pfnRHA_SetRadioIgnition != NULL) {
        fRet = RHAFunctionList.pfnRHA_SetRadioIgnition(bIgnition);
        RILRetailTraceZone(ZONE_RHA, (TEXT("RilDrv: call RHA_SetRadioIgnition() returned %d\r\n"), fRet));
    }
    else {
        RILRetailTraceZone(ZONE_RHA, (TEXT("RilDrv: RHA_SetRadioIgnition() not in RHA\r\n")));
    }
    return;
}
#endif

void RHA_SwitchToCDMA()
{
    RILRetailTraceZone(ZONE_RHA, (TEXT("RilDrv: call RHA_SwitchToCDMA()\r\n")));
    if (RHAFunctionList.pfnRHA_SwitchToCDMA) {
        RHAFunctionList.pfnRHA_SwitchToCDMA();
        RILRetailTraceZone(ZONE_RHA, (TEXT("RilDrv: call RHA_SwitchToCDMA() returned\r\n")));
    }
    else {
        RILRetailTraceZone(ZONE_RHA, (TEXT("RilDrv: RHA_SwitchToCDMA() not in RHA\r\n")));
    }
    return;
}

void RHA_SwitchToUMTS()
{
    RILRetailTraceZone(ZONE_RHA, (TEXT("RilDrv: call RHA_SwitchToUMTS()\r\n")));
    if (RHAFunctionList.pfnRHA_SwitchToUMTS) {
        RHAFunctionList.pfnRHA_SwitchToUMTS();
        RILRetailTraceZone(ZONE_RHA, (TEXT("RilDrv: call RHA_SwitchToUMTS() returned\r\n")));
    }
    else {
        RILRetailTraceZone(ZONE_RHA, (TEXT("RilDrv: RHA_SwitchToUMTS() not in RHA\r\n")));
    }
    return;
}

void RHA_SetBootloaderPin(BOOL bPin)
{
    BOOL fRet;

    RILRetailTraceZone(ZONE_RHA, (TEXT("RilDrv: call RHA_SetBootloaderPin(%d)\r\n"), bPin));
    if (RHAFunctionList.pfnRHA_SetBootloaderPin!= NULL) {
        fRet = RHAFunctionList.pfnRHA_SetBootloaderPin(bPin);
        RILRetailTraceZone(ZONE_RHA, (TEXT("RilDrv: call RHA_SetBootloaderPin() returned %d\r\n"), fRet));
    }
    else {
        RILRetailTraceZone(ZONE_RHA, (TEXT("RilDrv: RHA_SetBootloaderPin() not in RHA\r\n")));
    }
    return;
}


