/*****************************************************************************
 * Copyright (C) Gemalto M2M GmbH
 *****************************************************************************
 * Project: IMC-RIL-Driver
 *****************************************************************************
 * Author : Wireless Modules RD SW A2
 *****************************************************************************
 * $Workfile: Y:/z_ms-d/src/working/Quinn/RilDrv/PowerManager.cpp $
 * $Revision: /main/ms-d/197 $
 *     $Date: 2014-03-11 13:16:55 $
 *   $Author: pmackent $
 *****************************************************************************
 * Target:
 *  Microsoft Windows Mobile 5.0
 *****************************************************************************
 * Description:
 *  Gemalto IMC RIL
 *****************************************************************************
 *
 * $Log: Y:/z_ms-d/src/working/Quinn/RilDrv/PowerManager.cpp$ 
 * 
 * /main/ms-d/197   2014-03-11 13:16:55   pmackent 
 * Introduce delay on module start (IPIS100094735)
 *
 * /main/ms-d/196   2013-10-01 14:15:22   pmackent
 * Handle case of failing AT^SMONI on EHS5
 *
 * /main/ms-d/195   2013-09-25 15:21:42   pmackent
 * New methods for signal strength display in 3G networks (IPIS100091577)
 *
 * /main/ms-d/194   2013-06-27 16:00:15   pmackent
 * Adaptions for EHS5 Rel1->Rel2 update
 *
 * /main/ms-d/193   2013-06-11 10:07:13   pmackent
 * Retries for entering PIN in resilience mode
 *
 * /main/ms-d/192   2013-05-07 14:16:59   pmackent
 * New GPIO setting in EHS5
 *
 * /main/ms-d/191   2013-04-29 16:20:18   pmackent
 * Improved deactivation of data connections
 *
 * /main/ms-d/190   2013-04-25 13:07:02   pmackent
 * New CDMA/CNMI setting and CDMA/CLCC workaround
 *
 * /main/ms-d/189   2013-04-12 16:44:28   pmackent
 * Workaround for wrong CGREG status in PXS8 multimode
 *
 * /main/ms-d/188   2013-04-12 09:21:54   pmackent
 * Adaptions for PXS8 2.910
 *
 * /main/ms-d/187   2013-04-11 11:18:10   pmackent
 * Turn off module if already on on module start (IPIS100086657)
 *
 * /main/ms-d/186   2013-04-05 09:53:41   pmackent
 * Finish EHS5 Java midlet update
 * Add RHA-API for bootloader pin on EHS5
 *
 * /main/ms-d/185   2013-04-03 13:42:43   pmackent
 * Added ARRAYSIZE macro for Windows CE 6
 *
 * /main/ms-d/184   2013-03-15 14:09:11   pmackent
 * Start introducing Java update for EHS5
 *
 * /main/ms-d/183   2013-03-05 11:33:41   pmackent
 * Handle ^SYSSTART URC for EHS5 Rel2
 *
 * /main/ms-d/182   2013-03-04 13:19:47   pmackent
 * Adaptions for EHS5 1.300
 *
 * /main/ms-d/181   2013-02-27 15:18:02   pmackent
 * Introduce provider spezific PRL update
 *
 * /main/ms-d/180   2013-02-19 11:21:20   pmackent
 * Fix for problem with URC switching in CDMA mode (IPIS100085249)
 *
 * /main/ms-d/179   2013-02-15 11:33:23   pmackent
 * Allow retries for initial AT
 *
 * /main/ms-d/178   2013-01-30 11:12:21   pmackent
 * Changed handling of SM phonebook while FD lock
 *
 * /main/ms-d/177   2013-01-16 11:28:54   pmackent
 * Introduce update of module file system
 *
 * /main/ms-d/176   2013-01-14 10:33:48   pmackent
 * Allow update of multiple NV items
 *
 * /main/ms-d/175   2013-01-11 14:07:18   pmackent
 * Reset on PRI, PRL and NV update
 *
 * /main/ms-d/174   2012-12-21 13:09:01   pmackent
 * Introduce NV item update
 *
 * /main/ms-d/173   2012-12-13 16:06:30   pmackent
 * Avoid unnecessary check for CDMA registration in GSM-mode.
 *
 * /main/ms-d/172   2012-12-13 09:26:14   pmackent
 * Handling of Sprint variant of AT+CSQ
 *
 * /main/ms-d/171   2012-12-12 15:24:14   pmackent
 * Workarounds for bugs in PXS8 2.821
 *
 * /main/ms-d/170   2012-11-23 16:54:55   pmackent
 * Additional adaptions for EHS5
 *
 * /main/ms-d/169   2012-11-21 13:30:22   pmackent
 * Basic support of EHS5 Rel2
 *
 * /main/ms-d/168   2012-11-19 16:40:07   pmackent
 * Avoid sending power off notification during ACQDB reset (IPIS100083325)
 *
 * /main/ms-d/167   2012-11-15 11:46:25   pmackent
 * Avoid sending AT+CSQ in D3 power state (IPIS100083487)
 *
 * /main/ms-d/166   2012-11-13 13:52:59   pmackent
 * New option: reser of acquisition database (IPIS100083325)
 *
 * /main/ms-d/165   2012-11-05 11:04:59   pmackent
 * Workaround for PIN2-state-query working only once
 *
 * /main/ms-d/164   2012-11-01 15:54:47   pmackent
 * Workaround for AT+CSQ problems with PXS8
 *
 * /main/ms-d/163   2012-09-26 14:08:23   pmackent
 * Perform PRI update before PRL update
 *
 * /main/ms-d/162   2012-09-25 10:26:26   pmackent
 * Workaround for double CDMA activation URC
 *
 * /main/ms-d/161   2012-07-17 14:53:34   pmackent
 * Comply to CE7 warning level 4
 *
 * /main/ms-d/160   2012-07-13 13:04:12   pmackent
 * Changes for compatibility with Windows CE6/6
 *
 * /main/ms-d/159   2012-07-11 15:28:34   pmackent
 * Introduce PRI update
 *
 * /main/ms-d/158   2012-07-10 11:55:51   pmackent
 * Workaround for lost +CMT: URC.
 *
 * /main/ms-d/157   2012-07-05 10:12:13   pmackent
 * Introduce loading of network provider list
 *
 * /main/ms-d/156   2012-06-21 13:16:23   pmackent
 * Introduce CDMA PRL list update
 *
 * /main/ms-d/155   2012-06-19 13:53:58   pmackent
 * Handle case when muted call gets disconnected and next call uses DTMF (IPIS100078740)
 *
 * /main/ms-d/154   2012-06-07 13:58:56   pmackent
 * Adaptions for multimode
 * Workaround for CREG=0 bug in PXS8
 *
 * /main/ms-d/153   2012-04-18 13:47:10   ctna0256
 * Introducing PVS8
 * Implementing CDMA-SMS
 * Various CDMA enhancements
 *
 * /main/ms-d/152   2012-04-11 09:25:40   ctna0256
 * Change re-opening after SDPORT change (IPIS100078714)
 *
 * /main/ms-d/151   2012-04-02 15:52:38   ctna0450
 * Fixed comments for new NDIS-Msg handling
 *
 * /main/ms-d/149   2012-02-29 13:29:04   ctna0256
 * Move inital SIM/USIM to be performed before start of the multiplexer
 *
 * /main/ms-d/148   2012-02-29 10:05:41   ctna0256
 * Proper handling of the CFUN=7 cases
 *
 * /main/ms-d/147   2012-02-22 13:26:59   ctna0256
 * Encapsulate use of Intel AT command set
 *
 * /main/ms-d/146   2012-02-17 11:47:56   ctna0256
 * Define for "no audio" modules
 *
 * /main/ms-d/145   2012-02-17 11:13:05   ctna0256
 * Remove CFUN=7 mode (its not a bug, its a feature)
 *
 * /main/ms-d/144   2012-02-16 13:45:01   ctna0256
 * Comply to CE6 and CE7 compiler warnings
 *
 * /main/ms-d/143   2012-02-14 15:13:07   ctna0256
 * Handle URCs within responses.
 *
 * /main/ms-d/142   2012-02-10 10:00:21   ctna0256
 * Reset module if CFUN7 mode is detected (IPIS100077391)
 *
 * /main/ms-d/141   2012-02-09 16:44:36   ctna0256
 * Check for missed SMS with AT+CRSM on EHS5, small bug fixes
 *
 * /main/ms-d/140   2012-02-08 15:15:42   ctna0256
 * Add Intel-style SAT
 *
 * /main/ms-d/139   2012-02-03 15:07:23   ctna0256
 * Move URC parsing functions in separate file
 *
 * /main/ms-d/138   2012-02-02 17:03:46   ctna0256
 * FD phonebook workaround and NITZ URCs for Intel platform
 *
 * /main/ms-d/137   2012-01-31 16:38:45   ctna0256
 * Added support for EHS5
 *
 * /main/ms-d/136   2012-01-20 13:20:32   ctna0256
 * Better handling of SAT Idle Mode Text in case of booting the device (IPIS100077101)
 *
 * /main/ms-d/135   2012-01-17 10:22:21   ctna0256
 * Workaround for wrong indication of "+CIEV: psinfo,6" (IPIS100076880)
 *
 * /main/ms-d/134   2012-01-13 10:09:56   ctna0256
 * Implement audio workaround with SNFO/SNFI set to 0 (IPIS100076299)
 *
 * /main/ms-d/133   2012-01-12 15:22:45   ctna0256
 * Some basic CDMA adaptions
 *
 * /main/ms-d/132   2012-01-06 14:34:13   ctna0256
 * New workaround for SNFO/SNFI settings (IPIS100076299)
 *
 * /main/ms-d/131   2012-01-05 10:26:46   ctna0256
 * Save PIN2 because of problem with AT+CLCK="FD" in PH8 Rel2 (IPIS100076746)
 *
 * /main/ms-d/130   2012-01-04 15:36:52   ctna0256
 * Outsource XML configuration to external application.
 * Improve CDMA configuration mode.
 *
 * /main/ms-d/129   2011-12-22 10:45:28   ctna0256
 * Optional separation of audio commands (IPIS100076299)
 *
 * /main/ms-d/128   2011-10-17 11:34:32   ctna0256
 * Workaround for restart on exit and AT+CPIN? timing issues of PH8 Rel2
 *
 * /main/ms-d/127   2011-09-26 13:34:51   ctna0256
 * Comply with CE6 warning level 4
 *
 * /main/ms-d/126   2011-08-10 15:12:18   ctna0256
 * Additional CFUN=1 for PH8 246A
 *
 * /main/ms-d/125   2011-07-20 13:01:37   ctna0256
 * Introduce RIL_NOTIFY_DEVSPECIFIC_NETWORK_REJECT_CAUSE and prevent multiple notifications (IPIS100073123)
 *
 * /main/ms-d/124   2011-07-15 10:22:18   ctna0256
 * Added missing deactivation of psinfo in suspend (IPIS100073780)
 *
 * /main/ms-d/123   2011-06-17 10:41:00   ctna0256
 * New API for extended registration status (IPIS100073242)
 *
 * /main/ms-d/122   2011-05-30 09:36:07   ctna0256
 * Ignore wrong CREG:0 after CREG:3 (IPIS100073002)
 *
 * /main/ms-d/121   2011-03-25 09:09:29   ctna0256
 * Prevent unnecessary "radio off" error (IPIS100071415)
 *
 * /main/ms-d/120   2011-03-09 14:24:45   ctna0256
 * Run code analysis on Windows CE7
 *
 * /main/ms-d/119   2011-02-02 10:58:21   ctna0256
 * Earlier CSQ notifications
 *
 * /main/ms-d/118   2011-02-01 14:49:16   ctna0256
 * Allow combination of resilience and CSQ notification mode
 *
 * /main/ms-d/117   2010-12-22 14:31:19   ctna0256
 * No auto-reboot after emergency shutdown
 *
 * /main/ms-d/116   2010-12-15 17:08:23   ctna0256
 * Restart on GPRS-Attach config change
 *
 * /main/ms-d/115   2010-12-15 10:43:59   ctna0256
 * Performed lint check
 *
 * /main/ms-d/114   2010-12-14 10:15:08   ctna0256
 * Fix problem with restart on changed settings and resets on SAD
 *
 * /main/ms-d/113   2010-12-13 16:07:00   ctna0256
 * Allow automatic restart on configuration changes
 *
 * /main/ms-d/112   2010-12-13 10:00:32   ctna0256
 * Allow configuration of SDPORT timeout
 *
 * /main/ms-d/111   2010-11-26 10:26:18   ctna0256
 * Introducing firmware update for PH8
 *
 * /main/ms-d/110   2010-11-18 10:46:11   ctna0256
 * Remove Prefast warnings
 *
 * /main/ms-d/109   2010-11-04 15:47:03   ctna0256
 * New configuration of SDPORT, C-IMEI and SVN
 *
 * /main/ms-d/108   2010-10-26 11:01:06   ctna0256
 * Introducing new notification for SIM initialization (IPIS100068246)
 *
 * /main/ms-d/107   2010-09-08 11:24:30   ctna0256
 * RIL option: automatic GPRS reattach (IPIS100064423)
 *
 * /main/ms-d/106   2010-09-07 10:11:45   ctna0256
 * Workaround for missing ^SSTN: 254 URC (IPIS100067413)
 *
 * /main/ms-d/105   2010-08-20 10:41:33   ctna0256
 * Prevent deadlock between power manager and GPS handling
 *
 * /main/ms-d/104   2010-08-18 10:23:22   ctna0450
 * Added Telstra Home-Net workaround
 *
 * /main/ms-d/103   2010-08-10 09:26:16   ctna0256
 * Default value of key "StoreSMSonSIMasDefault" depending on module type
 *
 * /main/ms-d/102   2010-07-22 14:44:49   ctna0256
 * Allow setting of default behaviour for incoming text messages
 *
 * /main/ms-d/101   2010-07-06 10:00:28   ctna0256
 * Handle case of data only SIM
 *
 * /main/ms-d/100   2010-05-05 11:00:40   ctna0256
 * Option to tread power level D1 differently
 *
 * /main/ms-d/99   2010-04-23 10:20:48   ctna0256
 * Workaround for increasing call IDs after GPRS
 *
 * /main/ms-d/98   2010-02-24 16:04:55   ctna0256
 * Made old smartphone compile flage to RIL_SUSPEND_D2_TO_D3 build option
 *
 * /main/ms-d/97   2010-02-17 14:27:01   ctna0256
 * GetRegistrySZ() might return TRUE, even on error (IPIS100062294)
 *
 * /main/ms-d/96   2010-02-03 10:51:04   ctna0256
 * Introduction of WinCE6 support
 *
 * /main/ms-d/95   2009-09-28 11:54:44   ctna0256
 * Remove Lint warnings
 *
 * /main/ms-d/94   2009-07-28 11:26:05   ctna0256
 * Prevent showing old signal strength when module is off (IPIS100056913)
 *
 * /main/ms-d/93   2009-07-28 10:40:41   ctna0256
 * Better handling of the case "suspend during initialization" (IPIS100056850)
 *
 * /main/ms-d/92   2009-05-28 11:36:43   ctna0256
 * Remove "Siemens" from RIL
 *
 * /main/ms-d/91   2009-05-27 10:05:09   ctna0256
 * Deregister module in PUK blocked state caused by wrong PIN change
 *
 * /main/ms-d/90   2009-05-19 14:54:27   ctna0256
 * Reset exit counter on start instead of shutdown module
 *
 * /main/ms-d/89   2009-05-19 13:17:27   ctna0256
 * New registry keys for restart on exit
 *
 * /main/ms-d/88   2009-05-05 10:21:52   ctna0256
 * Deactivate AT^SNFO and AT^SNFI with registry key.
 *
 * /main/ms-d/87   2009-03-05 10:12:43   ctna0450
 * Added registry key to delay first module start
 *
 * /main/ms-d/86   2009-01-14 11:52:29   ctna0450
 * Consider possible absence of mux driver in driver version check
 *
 * /main/ms-d/85   2009-01-14 10:50:08   ctna0450
 * Removed special handling for consecutive WaitCommEvent() calls because mux ports are properly instancable now
 *
 * /main/ms-d/84   2008-10-06 16:04:12   ctna0256
 * New options: Disable SMS completely; Use SMS reply address
 *
 * /main/ms-d/83   2008-08-26 14:26:41   ctna0256
 * Merged RIL_RADIO_RESILIENCE option from Classic-RIL
 *
 * /main/ms-d/82   2008-08-22 10:25:08   ctna0256
 * Set Cinterion copyright text
 *
 * /main/ms-d/81   2008-08-21 09:35:03   ctna0256
 * Prepared for new disclaimer handling
 *
 * /main/ms-d/80   2008-07-25 13:33:24   wm36264
 * Fixed bug with gps/power off synchronization
 *
 * /main/ms-d/79   2008-07-22 15:52:58   mp49210
 * Complience to WM7, Lint and PreFast requirements
 *
 * /main/ms-d/78   2008-07-14 14:28:59   mp49210
 * Moved initialization of variable
 *
 * /main/ms-d/77   2008-07-10 13:51:47   mp49210
 * Renamed mux IOCTL
 *
 * /main/ms-d/76   2008-07-10 11:49:59   mp49210
 * Renamed define
 *
 * /main/ms-d/75   2008-06-12 15:03:42   mp49210
 * Removed typo in debug prints
 *
 * /main/ms-d/74   2008-06-06 15:31:09   mp49210
 * Handling of additional CPOL parameters
 *
 * /main/ms-d/73   2008-05-15 15:02:09   mp49210
 * Use ECC configuration from radio
 *
 * /main/ms-d/72   2008-04-29 13:40:00   mp49210
 * Removed Lint warning
 *
 * /main/ms-d/71   2008-04-24 14:58:13   kr36712
 * - error: suspend timeout during force power off
 * - error: force power off during airplane mode (GPS active + phone off)
 *
 * /main/ms-d/70   2008-04-16 16:24:16   mp49210
 * Debug zones for RHA traces
 *
 * /main/ms-d/69   2008-04-03 14:41:45   mp49210
 * Introduction of new debug zones
 *
 * /main/ms-d/68   2008-02-29 16:25:46   mp49210
 * Remove potential use of NULL pointer
 *
 * /main/ms-d/67   2008-02-11 09:18:18   mp49210
 * Remove LINT warnings
 *
 * /main/ms-d/66   2008-02-08 13:14:13   mp49210
 * Prevent start of module, if IMEI is missing
 *
 * /main/ms-d/65   2008-01-28 17:44:39   kr36712
 * global suspend timeout
 *
 * /main/ms-d/64   2008-01-24 15:57:41   kr36712
 * integration GPS for MTLR and emergency call
 *
 * /main/ms-d/63   2008-01-15 15:38:16   kr36712
 *
 *
 * /main/ms-d/62   2008-01-15 14:17:18   kr36712
 * GPS Power Management
 *
 * /main/ms-d/61   2007-12-14 11:35:24   kr36712
 * GPS Power Management
 *
 * /main/ms-d/60   2007-12-11 16:22:14   mp49210
 * Read debug options from registry at attach of rilgsm.dll
 *
 * /main/ms-d/59   2007-12-11 14:05:01   kr36712
 * Increase default value for "MaxOpenAttemps"
 *
 * /main/ms-d/58   2007-12-11 11:01:55   kr36712
 * GPS Powermanagement
 *
 * /main/ms-d/57   2007-11-28 13:18:09   kr36712
 * error correction usb shutdown
 *
 * /main/ms-d/56   2007-11-26 17:05:48   kr36712
 * integration of GPS support
 * use of the mux protocol
 *
 * /main/ms-d/55   2007-11-08 09:08:24   mp49210
 * Use own GPRS suspend connection default timeout
 *
 * /main/ms-d/54   2007-11-07 09:20:05   mp49210
 * New GPRS Suspend Delay
 *
 * /main/ms-d/53   2007-11-06 14:56:17   ht37010
 * new retail trace if RHA_SystemPowerChange returns MODEMSTATE_FORCE_POWEROFF
 *
 * /main/ms-d/52   2007-11-02 18:34:45   ht37010
 * fix for EPIC 21310: corrected handling of ForcePowerOff during TurnOnModule
 *
 * /main/ms-d/51   2007-10-17 10:00:43   mp49210
 * Change default value for "StoreIncomingSMSonSIMwhileSending"
 *
 * /main/ms-d/50   2007-09-21 16:08:04   mp49210
 * Optional usage of multiplexer for HC25 Rel2
 *
 * /main/ms-d/49   2007-09-21 10:29:45   mp49210
 * Introduction WM6 specific AcT selection (optional)
 *
 * /main/ms-d/48   2007-08-10 16:56:03   mp49210
 * IPIS100040302: send AT+CSIM after AT+CPIN?
 *
 * /main/ms-d/47   2007-08-08 11:16:46   mp49210
 * Introduction of audio profile download
 *
 * /main/ms-d/46   2007-08-02 11:19:54   mp49210
 * Increase default value for "MaxOpenAttemps"
 *
 * /main/ms-d/45   2007-07-30 15:48:10   mp49210
 * Fix for problems while suspend/resume when SIM was removed
 *
 * /main/ms-d/44   2007-07-12 14:10:21   mp49210
 * Print warning, if radio is on, before it is turned on.
 *
 * /main/ms-d/43   2007-07-11 15:11:30   mp49210
 * Optional additional waiting period before sending AT commands
 *
 * /main/ms-d/42   2007-07-10 09:03:15   mp49210
 * End data mode before sending AT^SMSO
 *
 * /main/ms-d/41   2007-07-04 08:57:17   mp49210
 * Introduction of maximum trace file length
 *
 * /main/ms-d/40   2007-07-04 07:32:14   mp49210
 * Introduction of radio band group search
 *
 * /main/ms-d/39   2007-06-29 14:02:23   kr36712
 * comment correction
 *
 * /main/ms-d/38   2007-06-28 09:58:50   mp49210
 * Close handle to threads to prevent handle leaks in memory
 *
 * /main/ms-d/37   2007-06-11 09:05:09   mp49210
 * Check for radio power down during module shutdown
 *
 * /main/ms-d/36   2007-06-01 16:20:55   mp49210
 * IPIS100036445: workaround for sending and receiving SMS per registry key
 *
 * /main/ms-d/35   2007-05-23 08:37:38   mp49210
 * Introduction of AT^SNWS command (optional)
 *
 * /main/ms-d/34   2007-05-02 10:26:23   mp49210
 * New registry key "NoRoaming Indicator"
 *
 * /main/ms-d/33   2007-04-26 14:24:41   mp49210
 * IPIS100035548: new RIL option: disable audio settings
 *
 * /main/ms-d/32   2007-04-24 15:58:15   mp49210
 * IPIS100035501: introduction of list of networks (registry), where the RIL should not send the roaming status
 *
 * /main/ms-d/31   2007-04-11 15:50:02   ht37010
 * prepare port reopen before suspend as workaround for USB reset problem
 *
 * /main/ms-d/30   2007-04-02 13:54:59   mp49210
 * New URC configuration for disabled USSD.
 *
 * /main/ms-d/29   2007-03-30 10:47:53   mp49210
 * Include USSD settings into URC states
 *
 * /main/ms-d/28   2007-03-29 14:45:09   mp49210
 * Send notification of equipment state change earlier during module startup
 *
 * /main/ms-d/27   2007-02-26 16:15:32   mp49210
 * New behaviour of CBS, SIM storage and SMS SR
 *
 * /main/ms-d/26   2007-02-22 16:44:34   mp49210
 * Workaround for unusable AT+CRSM=242 on USIMs
 *
 * /main/ms-d/25   2007-02-21 13:50:03   mp49210
 * HC25 no longer supports AT^SBC
 *
 * /main/ms-d/24   2007-02-20 18:02:35   wm36264
 * Fixed problem with suspend detection
 *
 * /main/ms-d/23   2007-02-15 12:09:09   wm36264
 * Added port reopen after resume as workaround for USB reset problem
 *
 * /main/ms-d/22   2007-02-09 15:15:17   mp49210
 * Lint compatibility
 *
 * /main/ms-d/21   2007-02-01 09:30:49   mp49210
 * Changed misplaced <tabs> (Lint)
 *
 * /main/ms-d/20   2007-01-31 17:00:09   mp49210
 * Changed handling of cell broadcast messages to pass Crossbow radiometrics.exe
 *
 * /main/ms-d/19   2007-01-19 11:28:00   mp49210
 * New build option RIL_STORE_SMS_ON_SIM_ON_SUSPEND
 *
 * /main/ms-d/18   2007-01-03 17:04:23   mp49210
 * Replace +CIEV: sounder with +CIEV: audio
 *
 * /main/ms-d/17   2007-01-02 15:03:35   mp49210
 * Remove some features not supported by Quinn
 *
 * /main/ms-d/16   2006-12-21 18:26:55   mp49210
 * Changed handling of call states
 *
 * /main/ms-d/15   2006-12-20 17:01:03   mp49210
 * Changes for AT+CNMI, AT+CAOC.
 * Modified URC configuration commands.
 *
 * /main/ms-d/14   2006-12-19 18:13:13   mp49210
 * Some changes for commands used during initialization
 *
 * /main/ms-d/13   2006-12-13 17:02:53   wm36264
 * Removed obsolete WaitForModuleStart()
 *
 * /main/ms-d/12   2006-12-12 11:36:21   mp49210
 * Remove AT+CSCB command from suspend procedure
 *
 * /main/ms-d/11   2006-12-06 13:34:45   mp49210
 * Changed behaviour of AT+CSCB command
 *
 * /main/ms-d/10   2006-11-22 13:01:39   wm36264
 * Removed unused stuff
 *
 * /main/ms-d/9   2006-11-21 09:02:16   mp49210
 * New GPRS auto attach mechanism
 *
 * /main/ms-d/8   2006-11-17 11:19:32   mp49210
 * Introduction of AT^SIND
 *
 * /main/ms-d/7   2006-11-10 12:20:46   wm36264
 * Call init function for opened COM ports
 *
 * /main/ms-d/6   2006-11-02 17:34:34   wm36264
 * Send preinit cmds to data port only, switch airplane mode as soon as possible
 *
 * /main/ms-d/5   2006-11-02 09:33:48   mp49210
 * No AT+CREG=1 for Quinn (yet)
 *
 * /main/ms-d/4   2006-11-01 14:20:05   wm36264
 * Simplyfied handling of new airplane mode
 *
 * /main/ms-d/3   2006-11-01 10:29:34   mp49210
 * New AT+CFUN handling in Quinn
 *
 * /main/ms-d/2   2006-10-31 16:02:33   wm36264
 * Workarounds for missing ^SYSSTART and ^SHUTDOWN urcs
 *
 * /main/ms-d/1   2006-10-25 16:51:18   wm36264
 * First transformation from classic RIL
 *
*/

//////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2008 Gemalto M2M GmbH
// Copyright (C) 2006-2008 Siemens AG
//
// Version: 1.0
// Date:    dummy
//
//////////////////////////////////////////////////////////////////////////////

#include "precomp.h"
#include <Pmpolicy.h>
#include "..\..\inc\muxapi.h"

#ifndef ARRAYSIZE
#define ARRAYSIZE(a)        (sizeof(a) / sizeof(a[0]))
#endif

//////////////////////////////////////////////////////////////////////////////
// Currently the one and only instance of the CPowerManager
//////////////////////////////////////////////////////////////////////////////

CPowerManager g_PowerManager;

//////////////////////////////////////////////////////////////////////////////
// Externals
//////////////////////////////////////////////////////////////////////////////

extern BOOL   g_fEmergencyCall;
extern DWORD  g_dwSIMLockedState;

static DWORD s_dwPSInfoStatus = 0;

//////////////////////////////////////////////////////////////////////////////
//
// Class CPowerCmd
//
//////////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////////
//
// Constructor
//
//////////////////////////////////////////////////////////////////////////////
#ifdef RIL_RADIO_RESILIENCE
CPowerCmd::CPowerCmd(DWORD dwCmd, CRilInstanceHandle* pHandle, CEDEVICE_POWER_STATE NewPwrState, CEDEVICE_POWER_STATE OldPwrState, BOOL fEquCmd, BOOL fUrcInit, BOOL fDelayCmd) {
#else
CPowerCmd::CPowerCmd(DWORD dwCmd, CRilInstanceHandle* pHandle, CEDEVICE_POWER_STATE NewPwrState, CEDEVICE_POWER_STATE OldPwrState, BOOL fEquCmd, BOOL fUrcInit) {
#endif
  SYNCBLOCK(g_csClosing);
  m_NewPwrState = NewPwrState;
  m_OldPwrState = OldPwrState;
  m_dwCmd = dwCmd;
  m_pHandle = pHandle;
  m_fUrcInit = fUrcInit;
  m_fEquCmd = fEquCmd;
  m_hFinishEvent = NULL;
#ifdef RIL_RADIO_RESILIENCE
  m_fDelay = fDelayCmd;
#endif
  if ((IsPowerCmd() && (NewPwrState >= D3)) || IsGpsCmd()) {
    m_hFinishEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  }
  if (m_pHandle) {
    (void)m_pHandle->GetCmdList()->Add(this);
  }
}

//////////////////////////////////////////////////////////////////////////////
//
// Destructor
//
//////////////////////////////////////////////////////////////////////////////
CPowerCmd::~CPowerCmd() {
  (void)SetEvent(m_hFinishEvent);
  (void)CloseHandle(m_hFinishEvent);
}

//////////////////////////////////////////////////////////////////////////////
//
// Indicating if the command is a power command sending the system to a
// power state suspend.
//
// Return:
//  TRUE if the command is a power command suspending the system,
//  FALSE otherwise.
//
//////////////////////////////////////////////////////////////////////////////
BOOL CPowerCmd::IsSuspendCmd(void) const {
  if (IsPowerCmd()) {
    // Block further command handling on power states D3 and below
#ifdef RIL_SUSPEND_D2_TO_D3
    if ((GetNewPowerState() >= D3) && (GetOldPowerState() <= D2)) {
#else // RIL_SUSPEND_D2_TO_D3
    if ((GetNewPowerState() >= D2) && (GetOldPowerState() <= D1)) {
#endif // RIL_SUSPEND_D2_TO_D3
      return TRUE;
    }
  }
  return FALSE;
}

//////////////////////////////////////////////////////////////////////////////
//
// Indicating if the command is a power command resuming the system from
// power state suspend.
//
// Return:
//  TRUE if the command is a power command resuming the system,
//  FALSE otherwise.
//
//////////////////////////////////////////////////////////////////////////////
BOOL CPowerCmd::IsResumeCmd(void) const {
  if (IsPowerCmd()) {
    // Block further command handling on power states D3 and below
#ifdef RIL_SUSPEND_D2_TO_D3
    if ((GetNewPowerState() <= D2) && (GetOldPowerState() >= D3)) {
#else // RIL_SUSPEND_D2_TO_D3
    if ((GetNewPowerState() <= D1) && (GetOldPowerState() >= D2)) {
#endif // RIL_SUSPEND_D2_TO_D3
      return TRUE;
    }
  }
  return FALSE;
}

//////////////////////////////////////////////////////////////////////////////
//
// Reset and return the internal finish event to assign to other instance.
//
// Return:
//  The internal finish event.
//
//////////////////////////////////////////////////////////////////////////////
HANDLE CPowerCmd::InheritFinishEvent(void) {
  HANDLE hRet = m_hFinishEvent;
  m_hFinishEvent = NULL;
  return hRet;
};

//////////////////////////////////////////////////////////////////////////////
//
// Get the name of the power command for debug trace.
//
// Return:
//  The name of the command we're looking for.
//
//////////////////////////////////////////////////////////////////////////////
const TCHAR* CPowerCmd::GetCmdName(void) const {
  switch(m_dwCmd) {
    case MODEMSTATE_FORCE_POWEROFF            :  return(PWR_STATE_TXT(MODEMSTATE_FORCE_POWEROFF));
    case MODEMSTATE_POWEROFF                  :  return(PWR_STATE_TXT(MODEMSTATE_POWEROFF));
    case MODEMSTATE_AIRPLANE                  :  return(PWR_STATE_TXT(MODEMSTATE_AIRPLANE));
    case MODEMSTATE_POWERON                   :  return(PWR_STATE_TXT(MODEMSTATE_POWERON));
    case MODEMSTATE_URCCONFIG_CALL            :  return(PWR_STATE_TXT(MODEMSTATE_URCCONFIG_CALL));
    case MODEMSTATE_URCCONFIG_CALL_SMS        :  return(PWR_STATE_TXT(MODEMSTATE_URCCONFIG_CALL_SMS));
    case MODEMSTATE_URCCONFIG_CALL_SMS_CGREG  :  return(PWR_STATE_TXT(MODEMSTATE_URCCONFIG_CALL_SMS_CGREG));
    case MODEMSTATE_URCCONFIG_CALL_SMS_REG    :  return(PWR_STATE_TXT(MODEMSTATE_URCCONFIG_CALL_SMS_REG));
    case MODEMSTATE_GPSON                     :  return(PWR_STATE_TXT(MODEMSTATE_GPSON));
    case MODEMSTATE_GPSOFF                    :  return(PWR_STATE_TXT(MODEMSTATE_GPSOFF));
  }
  return TEXT("Unkown Power Command");
}

//////////////////////////////////////////////////////////////////////////////
//
// Get the type of the power command for debug trace.
//
// Return:
//  The type of the command we're looking for.
//
//////////////////////////////////////////////////////////////////////////////
const TCHAR* CPowerCmd::GetCmdType(void) const {
  if (IsPowerCmd())           return TEXT("Power Command");
  if (IsEquipmentStateCmd())  return TEXT("Equipment State Command");
  if (IsGpsCmd())             return TEXT("GPS Command");
  if (IsUrcCmd())             return TEXT("URC Command");
  return TEXT("Unknown Command");
}

//////////////////////////////////////////////////////////////////////////////
//
// Class CPowerManager
//
//////////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////////
//
// Public class implementation
//
//////////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////////
//
// Constructor
//
//////////////////////////////////////////////////////////////////////////////
CPowerManager::CPowerManager() {
  m_pRilHandle = NULL;
  m_hShutdownThread = NULL;
  m_dwModemState = MODEMSTATE_POWEROFF;
  m_dwNewModemState = m_dwModemState;
  m_dwOldModemState = m_dwModemState;
  m_dwInitUrcState = INVALID_MODEM_STATE;
  m_PowerState = D0;
  m_fOngoing = FALSE;
  m_fUrcInitialized = FALSE;
  m_fPreUrcInitialized = FALSE;
  m_fPowerOffForced = FALSE;
  m_fUnattendedMode = FALSE;
  m_fIdleTimerReset = FALSE;
  m_fRadioOn = FALSE;
  m_dwRegStatusCache = 0;
  m_dwGPRSRegStatusCache = 0;
  m_nSMSPhase = 0;
  m_nCNMIMode = 0;
  m_nLAC = 0;
  m_nCI = 0;
  m_hCmdQueueThread = NULL;
#ifdef RIL_USE_CSQ_NOTIFICATIONS
#ifdef RIL_RADIO_RESILIENCE
  m_hResiliencePollingThread = NULL;
#endif
#endif
  m_hATCmdRequeueEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
  m_hRadioOnOffMutex = CreateEvent(NULL, TRUE, TRUE, NULL);
  m_hIdleResetLeaveEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
  m_hCmdQueueExitEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
  (void)m_CmdQueue.Init(m_hCmdQueueExitEvent);
  InitializeCriticalSection(&m_csPowerState);
  InitializeCriticalSection(&m_csForcePower);
  InitializeCriticalSection(&m_csUnattended);
  InitializeCriticalSection(&m_csRadioOn);
#ifdef RIL_RADIO_RESILIENCE
  m_nRestartCount = 0;
#endif
  m_dwLastModuleStart = 0;
}

//////////////////////////////////////////////////////////////////////////////
//
// Destructor
//
//////////////////////////////////////////////////////////////////////////////
CPowerManager::~CPowerManager() {
  Deinit();
  (void)CloseHandle(m_hIdleResetLeaveEvent);
  (void)CloseHandle(m_hRadioOnOffMutex);
  (void)CloseHandle(m_hATCmdRequeueEvent);
  (void)CloseHandle(m_hCmdQueueExitEvent);
  DeleteCriticalSection(&m_csRadioOn);
  DeleteCriticalSection(&m_csUnattended);
  DeleteCriticalSection(&m_csForcePower);
  DeleteCriticalSection(&m_csPowerState);
}

//////////////////////////////////////////////////////////////////////////////
//
// Initialize the class with required information.
//
// Params:
//  pRilHandle: Pointer to the connected CRilHandle instance which is needed
//              internal.
//
//////////////////////////////////////////////////////////////////////////////
void CPowerManager::Init(CRilHandle* pRilHandle) {
  SYNCBLOCK(m_csPowerState);
  m_pRilHandle= pRilHandle;
  m_hCmdQueueThread = CreateThread(NULL, 0, CmdQueueThread, (LPVOID)this, 0, NULL);
#ifdef RIL_USE_CSQ_NOTIFICATIONS
#ifdef RIL_RADIO_RESILIENCE
  m_hResiliencePollingThread = CreateThread(NULL, 0, ResiliencePollingThread, (LPVOID)this, 0, NULL);
#endif
#endif
  SwitchUnattendedMode(TRUE);
}

//////////////////////////////////////////////////////////////////////////////
//
// Tell the class that the information passed to Init() is no longer valid.
//
//////////////////////////////////////////////////////////////////////////////
void CPowerManager::Deinit(void) {
  SYNCBLOCK(m_csPowerState);
  SwitchUnattendedMode(FALSE);
  (void)SetEvent(m_hCmdQueueExitEvent);
  (void)WaitForSingleObject(m_hCmdQueueThread, POWER_LOCK_TIMEOUT);
  (void)CloseHandle(m_hCmdQueueThread);
#ifdef RIL_USE_CSQ_NOTIFICATIONS
#ifdef RIL_RADIO_RESILIENCE
  (void)WaitForSingleObject(m_hResiliencePollingThread, POWER_LOCK_TIMEOUT);
  (void)CloseHandle(m_hResiliencePollingThread);
  m_hResiliencePollingThread = NULL;
#endif
#endif
  EmptyCmdQueue();
  m_hCmdQueueThread = NULL;
  (void)ForcePowerOff();
  m_pRilHandle= NULL;
}

//////////////////////////////////////////////////////////////////////////////
//
// Enter a given power state.
//
// Params:
//  pHandle    : Pointer to CRilInstanceHandle to be used for the operation.
//  NewPwrState: The new power state to switch the module into.
//
// Return:
//  TRUE on successs, FALSE otherwise.
//
//////////////////////////////////////////////////////////////////////////////
BOOL CPowerManager::EnterPowerState(CRilInstanceHandle* pHandle, CEDEVICE_POWER_STATE NewPwrState) {
CPowerCmd*            pCmd;
DWORD                 dwLastEquipmentState = 0;
DWORD                 dwNewModemState = 0;
DWORD                 dwNewModemStateDefault = 0;
CEDEVICE_POWER_STATE  OldPwrState;

  if ((NewPwrState < D0) || (NewPwrState > D4)) {
    RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: Unsupported Power-State D%d\r\n"), NewPwrState));
    SetLastError(ERROR_INVALID_PARAMETER);
    return FALSE;
  }

  EnterCriticalSection(&m_csPowerState);

  OldPwrState = m_PowerState;

  RILRetailTraceZone(ZONE_INFO, (TEXT("RilDrv: EnterPowerState(old: D%d, new: D%d)\r\n"), OldPwrState, NewPwrState));

  // Load the last equipment state from the registry
  if (!GetRegistryDWORD(RIL_LAST_EQUIPMENT_STATE_ROOT, RIL_LAST_EQUIPMENT_STATE_KEY, RIL_LAST_EQUIPMENT_STATE_VALUE, &dwLastEquipmentState)) {
    dwLastEquipmentState = RIL_EQSTATE_FULL;
  } else {
    switch (dwLastEquipmentState) {
      case RIL_EQSTATE_FULL:
      case RIL_EQSTATE_MINIMUM:
      case RIL_EQSTATE_DISABLETXANDRX:
        break;
      default:
        dwLastEquipmentState = RIL_EQSTATE_FULL;
        break;
    }
  }

  // Get the default new module state
  switch (NewPwrState) {
    case D0:
    case D1:
    case D2:
      switch (dwLastEquipmentState) {
        case RIL_EQSTATE_MINIMUM:
          dwNewModemStateDefault = MODEMSTATE_POWEROFF;
          break;
        case RIL_EQSTATE_DISABLETXANDRX:
          dwNewModemStateDefault = MODEMSTATE_AIRPLANE;
          break;
        default: // RIL_EQSTATE_FULL
          dwNewModemStateDefault = MODEMSTATE_POWERON;
          break;
      }
      break;

    case D3:
      switch (dwLastEquipmentState) {
        case RIL_EQSTATE_MINIMUM:
          dwNewModemStateDefault = MODEMSTATE_POWEROFF;
          break;
        case RIL_EQSTATE_DISABLETXANDRX:
           {
             DWORD dwKeepGpsActive = 0;
             GetRegistryDWORD(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, TEXT("KeepGpsActiveOnSuspend"), &dwKeepGpsActive);
             if (dwKeepGpsActive) {
               dwNewModemStateDefault = MODEMSTATE_AIRPLANE;
             } else {
               dwNewModemStateDefault = MODEMSTATE_POWEROFF;
             }
          }
          break;
        default: // RIL_EQSTATE_FULL
          dwNewModemStateDefault = DEFAULT_URCCONFIG;
          break;
      }
      break;

    case D4:
      dwNewModemStateDefault = MODEMSTATE_POWEROFF;
      break;
  }

  // Check if we missed an external power change
  if (!m_fOngoing && (m_dwNewModemState != MODEMSTATE_POWEROFF)) {
    if (!RHA_IsRadioPwrOn()) {
      RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: EnterPowerState() - Module powered off externally!\r\n")));
      // Tidy up internal states
      (void)ForcePowerOff();
      pCmd = new CPowerCmd(MODEMSTATE_FORCE_POWEROFF, pHandle, NewPwrState, OldPwrState, FALSE, FALSE);
      if (pCmd != NULL) {
        if (!m_CmdQueue.Put(pCmd, POWER_LOCK_TIMEOUT)) {
          delete pCmd;;
        }
      }
    }
  }

  // First ask if our default power handling shall be overwritten
  dwNewModemState = RHA_SystemPowerChange(m_PowerState, NewPwrState, m_dwNewModemState, dwNewModemStateDefault, m_fOngoing, FALSE);
  if (dwNewModemState == MODEMSTATE_FORCE_POWEROFF || dwNewModemState == MODEMSTATE_POWEROFF) {
#ifdef RIL_RADIO_RESILIENCE
    g_fAllowReboot = FALSE;
    ClearPINSecure();
#endif
    ClearPIN2Secure();
  }

  if (dwNewModemState == MODEMSTATE_FORCE_POWEROFF) {
      RILRetailTraceZone(ZONE_INFO, (TEXT("RilDrv: new modem state was set to MODEMSTATE_FORCE_POWEROFF by RHA_SystemPowerChange()\r\n")));
  } else {

    // patch error in rha.dll for Airplane Mode
    if ((dwNewModemStateDefault == MODEMSTATE_AIRPLANE) && (dwNewModemState  != MODEMSTATE_AIRPLANE)) {
      RILRetailTraceZone(ZONE_INFO, (TEXT("RilDrv: EnterPowerState() patch MODEMSTATE_AIRPLANE\r\n")));
      dwNewModemState = MODEMSTATE_AIRPLANE;
    }

  }

  if (!IS_VALID_MODEMSTATE(dwNewModemState)) {
    dwNewModemState = dwNewModemStateDefault;
  }

  // Store the new power state
  m_PowerState = NewPwrState;

  // Execute FORCE_POWEROFF immediately ...
  if (dwNewModemState == MODEMSTATE_FORCE_POWEROFF) {
    // ... but we have to wait until pending commands has finished nevertheless ...
    (void)ForcePowerOff();
    // ... so run through the usual command queue including wait also for FORCE_POWEROFF.
    // Otherwise there could be conflicts with aborted commands during next switch on.
  }

  // Now queue the command
  pCmd = new CPowerCmd(dwNewModemState, pHandle, NewPwrState, OldPwrState, FALSE, FALSE);
  LeaveCriticalSection(&m_csPowerState);
  if (pCmd == NULL || !m_CmdQueue.Put(pCmd, POWER_LOCK_TIMEOUT)) {
    if (pCmd != NULL)
      delete pCmd;
    return FALSE;
  }

  // Register unattended mode for power state changes from D3 or below to D2 or above
  if ((OldPwrState >= D3) && (NewPwrState <= D2)) {
    SwitchUnattendedMode(TRUE);
  }

  (void)WaitForSingleObject(pCmd->GetFinishEvent(), POWER_LOCK_TIMEOUT);

  return TRUE;
}

#pragma warning( push )
// Warning disabled to avoid unnecessary complicated ifdef-construction
#pragma warning(disable : 4100)
//////////////////////////////////////////////////////////////////////////////
//
// Enter a given equipment state via the RIL equipment state interface.
//
// Params:
//  pHandle   : Pointer to CRilInstanceHandle to be used for the operation.
//  dwNewState: The new equipment state to switch the module into.
//
// Return:
//  TRUE on successs, FALSE otherwise.
//
//////////////////////////////////////////////////////////////////////////////
BOOL CPowerManager::EnterEquipmentState(CRilInstanceHandle* pHandle, DWORD dwNewState, BOOL fDelay) {
CPowerCmd*  pCmd;
DWORD       dwNewModuleState = 0;

  if ((dwNewState != RIL_EQSTATE_MINIMUM)         &&
      (dwNewState != RIL_EQSTATE_DISABLETXANDRX)  &&
      (dwNewState != RIL_EQSTATE_FULL)) {
    RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: Unsupported Equipment-State %d\r\n"), dwNewState));
    return FALSE;
  }

#ifdef RIL_RADIO_RESILIENCE
  // If there is a module start via RIL API, reset the restart counter.
  if (dwNewState == RIL_EQSTATE_FULL && pHandle != NULL)
    m_nRestartCount = 0;
#endif

  EnterCriticalSection(&m_csPowerState);

  g_fEmergencyCall = FALSE;
  g_GpsHandling.DisableGpsStatePassiveAsync();

  switch (dwNewState) {
    case RIL_EQSTATE_MINIMUM:
      RILRetailTraceZone(ZONE_INFO, (TEXT("RilDrv: EnterEquipmentState(RIL_EQSTATE_MINIMUM)\r\n")));
      g_dwGPRSRegStatus = RIL_REGSTAT_UNKNOWN;
      g_dwRegStatus = RIL_REGSTAT_UNKNOWN;
      g_fRegStatus3detected = FALSE;
      dwNewModuleState = MODEMSTATE_POWEROFF;
      break;

    case RIL_EQSTATE_DISABLETXANDRX:
      RILRetailTraceZone(ZONE_INFO, (TEXT("RilDrv: EnterEquipmentState(RIL_EQSTATE_DISABLETXANDRX)\r\n")));
      g_dwGPRSRegStatus = RIL_REGSTAT_UNKNOWN;
      g_dwRegStatus = RIL_REGSTAT_UNKNOWN;
      g_fRegStatus3detected = FALSE;
      dwNewModuleState = MODEMSTATE_AIRPLANE;
      break;

    case RIL_EQSTATE_FULL:
      RILRetailTraceZone(ZONE_INFO, (TEXT("RilDrv: EnterEquipmentState(RIL_EQSTATE_FULL)\r\n")));
      dwNewModuleState = MODEMSTATE_POWERON;
      break;

  }

  (void)SetRegistryDWORD(RIL_LAST_EQUIPMENT_STATE_ROOT, RIL_LAST_EQUIPMENT_STATE_KEY, RIL_LAST_EQUIPMENT_STATE_VALUE, dwNewState);

#ifdef RIL_RADIO_RESILIENCE
  pCmd = new CPowerCmd(dwNewModuleState, pHandle, PwrDeviceUnspecified, PwrDeviceUnspecified, TRUE, FALSE, fDelay);
#else
  pCmd = new CPowerCmd(dwNewModuleState, pHandle, PwrDeviceUnspecified, PwrDeviceUnspecified, TRUE, FALSE);
#endif

  LeaveCriticalSection(&m_csPowerState);

  if (pCmd == NULL || !m_CmdQueue.Put(pCmd, POWER_LOCK_TIMEOUT)) {
    if (pCmd != NULL)
      delete pCmd;
    return FALSE;
  }

  return TRUE;
}

//////////////////////////////////////////////////////////////////////////////
//
// Enable or disable the URCs.
//
// Params:
//  pHandle    : Pointer to CRilInstanceHandle to be used for the operation.
//  NewUrcState: The new URC state to be entered.
//  fInit      : Indicating that we're called during the module
//               initialization phase and we have to broadcast some
//               information notifications.
//
// Return:
//  TRUE on successs, FALSE otherwise.
//
//////////////////////////////////////////////////////////////////////////////
BOOL CPowerManager::EnterUrcState(CRilInstanceHandle* pHandle, DWORD dwNewUrcState, BOOL fInit) {
  EnterCriticalSection(&m_csPowerState);

  // URC switching is only allowed when power state and module are on
#ifdef RIL_SUSPEND_D2_TO_D3
  if ((m_PowerState > D2) || !IS_URCSTATE(dwNewUrcState) || (GetEquipmentState() != RIL_EQSTATE_FULL) || (!fInit && !m_fUrcInitialized && !m_fPreUrcInitialized)) {
#else // RIL_SUSPEND_D2_TO_D3
  if ((m_PowerState != D0) || !IS_URCSTATE(dwNewUrcState) || (GetEquipmentState() != RIL_EQSTATE_FULL) || (!fInit && !m_fUrcInitialized && !m_fPreUrcInitialized)) {
#endif // RIL_SUSPEND_D2_TO_D3
    RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: Invalid call of EnterUrcState()!\r\n")));
    LeaveCriticalSection(&m_csPowerState);
    return FALSE;
  }

  RILRetailTraceZone(ZONE_INFO, (TEXT("RilDrv: EnterUrcState(%s)\r\n"), fInit ? TEXT("init phase") : TEXT("")));

  CPowerCmd* pCmd = new CPowerCmd(dwNewUrcState, pHandle, PwrDeviceUnspecified, PwrDeviceUnspecified, FALSE, fInit);

  LeaveCriticalSection(&m_csPowerState);

  if (pCmd == NULL || !m_CmdQueue.Put(pCmd, POWER_LOCK_TIMEOUT)) {
    if (pCmd != NULL)
      delete pCmd;
    return FALSE;
  }

  return TRUE;
}

//////////////////////////////////////////////////////////////////////////////
//
// This is function enables or disables the GPS mode inside the module. The
// module will be switched to an appropriate equipment state automatically.
// This function blocks until all necessary operations are finished.
//
// Params:
//  fEnable: Flag indicating if GPS mode shall be switched on (TRUE)
//           or off (FALSE).
//
// Return:
//  TRUE on successs, FALSE otherwise.
//
//////////////////////////////////////////////////////////////////////////////
BOOL CPowerManager::EnterGpsState(BOOL fEnable) {
CPowerCmd*  pCmd;
BOOL bEnabled = FALSE;
	
  if (!SUPPORTS_GPS) return FALSE;

  RILRetailTraceZone(ZONE_INFO, (TEXT("RilDrv: EnterGpsState(%s)\r\n"), fEnable ? TEXT("on") : TEXT("off")));
  // First queue the power command command
  pCmd = new CPowerCmd(fEnable ? MODEMSTATE_GPSON : MODEMSTATE_GPSOFF, NULL, PwrDeviceUnspecified, PwrDeviceUnspecified, FALSE, FALSE);
  if (pCmd == NULL || !m_CmdQueue.Put(pCmd, POWER_LOCK_TIMEOUT)) {
    if (pCmd != NULL)
      delete pCmd;
    return FALSE;
  }

  // Wait until the module is in the appropriate state
  if (WaitForSingleObject(pCmd->GetFinishEvent(), POWER_LOCK_TIMEOUT) == WAIT_TIMEOUT) return FALSE;

  bEnabled = g_GpsHandling.IsGpsActive();
  RILRetailTraceZone(ZONE_INFO, (TEXT("RilDrv: EnterGpsState bEnabled = %d \r\n"), bEnabled));
  
  return (bEnabled == fEnable);
}

//////////////////////////////////////////////////////////////////////////////
//
// This is an emergency function to tidy up internal states of the RIL
// driver. It has to be called if the module has lost or is going to loose
// power without the possibility to properly shut it down.
//
// Return:
//  TRUE on successs, FALSE otherwise.
//
//////////////////////////////////////////////////////////////////////////////
BOOL CPowerManager::ForcePowerOff(BOOL bReboot) {
BOOL fRet = TRUE;
#ifdef RIL_RADIO_RESILIENCE
BOOL bAutoReboot = FALSE;
#endif

  SYNCBLOCK(m_csForcePower);

  if (!m_pRilHandle) {
    return FALSE;
  }

  if (!m_fPowerOffForced) {
    SYNCBLOCK2(m_csPowerState);

    if (m_dwModemState != MODEMSTATE_POWEROFF) {
      // Block any further shutdown attempts
      (void)LockPowerState();

#ifdef RIL_RADIO_RESILIENCE
      RHA_SetRadioIgnition(FALSE);
#endif

      // Turn off module power immediately
      (void)RHA_RadioPwrOff();

      EnterCriticalSection(&m_csRadioOn);
      m_fRadioOn = FALSE;
      LeaveCriticalSection(&m_csRadioOn);

      m_fPowerOffForced = TRUE;

      UNSYNCBLOCK(m_csForcePower);

      RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: Forcing module shutdown%s!\r\n"), (bReboot ? TEXT(" to prepare reboot") : TEXT(""))));
#ifdef RIL_RADIO_RESILIENCE
      if (g_fAllowReboot == TRUE && g_dwRebootEmergencyStatus == EMERG_SHUTDOWN_NONE) {
        DWORD dwRestartTimeOut = 0;

        if(!GetRegistryDWORD(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, TEXT("AutoRestartTimeOut"), &dwRestartTimeOut))
            dwRestartTimeOut = 10000;

        if (GetTickCount() - g_dwLastAutoReboot >= dwRestartTimeOut) {
          DWORD dwMaxCount = 0;
          BOOL fDoRestart = TRUE;

          if(GetRegistryDWORD(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, TEXT("AutoRestartMaxCount"), &dwMaxCount)) {
            if (dwMaxCount <= m_nRestartCount) {
                RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: automatic restart attempt not performed (max: %d)\r\n"), dwMaxCount));
                fDoRestart = FALSE;
            }
          }
          if (fDoRestart) {
            DWORD dwAutoRestartTotal = 0;

            RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: Initiate automatic restart\r\n")));
            bAutoReboot = TRUE;
            m_nRestartCount ++;
            // Store total numbers of performed restarts into the registry
            (void)GetRegistryDWORD(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, TEXT("AutoRestartTotal"), &dwAutoRestartTotal);
            (void)SetRegistryDWORD(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, TEXT("AutoRestartTotal"), dwAutoRestartTotal+1);

          }
        }
        else {
          RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: automatic restart attempt too soon after last restart (timeout = %dms)\r\n"), dwRestartTimeOut));
        }
       }
#endif

      // Unlock the Get() function of the response queue
      (void)g_RspQ.SetReadLock(FALSE);

      // Block further command handling and any power state changes
      (void)m_pRilHandle->BlockCommandHandling();

      (void)SendMuxCmd(IOCTL_MPX_POWER_LOSS);
      (void)SendMuxCmd(IOCTL_MPX_POWER_FAIL);
      // Now tidy up internal states and send appropriate notifications.
      // In case of a planned reboot the notification itself is not sent.
      HandleShutdownError(bReboot == TRUE ? FALSE : TRUE);

      // Tidy up possible audio stuff
      g_iNrCallInfo = 0;
      g_iIdxForFirstCall = -1;

	  if(!SUPPORTS_ONLY_DATAMODE){
      	RHADeactivateVoicePath(NULL, FALSE, FALSE);
	  }

      // Save the new equipment state in the registry
      if (IS_DEVICEON(m_PowerState)) {
        (void)SetRegistryDWORD(RIL_LAST_EQUIPMENT_STATE_ROOT, RIL_LAST_EQUIPMENT_STATE_KEY, RIL_LAST_EQUIPMENT_STATE_VALUE, RIL_EQSTATE_MINIMUM);
      }

      // Finally unblock command handling again
      (void)m_pRilHandle->UnblockCommandHandling();

      // Empty possibly queued power commands
      EmptyCmdQueue();
#ifdef RIL_RADIO_RESILIENCE
      if (bAutoReboot == TRUE || bReboot == TRUE) {
        DWORD dwWaitOnRestart = 100;

        g_dwLastAutoReboot = GetTickCount();
        (void)GetRegistryDWORD(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, TEXT("WaitOnRestart"), &dwWaitOnRestart);
        Sleep(dwWaitOnRestart);
        (void)EnterEquipmentState(NULL, RIL_EQSTATE_FULL, TRUE);
      }
#else
      if (bReboot == TRUE) {
        DWORD dwWaitOnRestart = 100;

        (void)GetRegistryDWORD(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, TEXT("WaitOnRestart"), &dwWaitOnRestart);
        Sleep(dwWaitOnRestart);
        (void)EnterEquipmentState(NULL, RIL_EQSTATE_FULL, TRUE);
      }
#endif
      m_fOngoing = FALSE;
      m_dwNewModemState = m_dwModemState;
      m_dwOldModemState = m_dwModemState;
    }
  }

  return fRet;
}

//////////////////////////////////////////////////////////////////////////////
//
// Function to be called if a shutdown has properly finished to properly
// tidy up states and abort waiting the timeout thread.
//
// Params:
//  pRes: Pointer to a RILEQUIPMENTSTATE structure filled according to the
//        new equipment state.
//
// Return:
//  TRUE on success, FALSE if anything went wrong.
//
//////////////////////////////////////////////////////////////////////////////
BOOL CPowerManager::ShutdownFinished(LPRILEQUIPMENTSTATE pRes) {
BOOL fUnsolicited = FALSE;

  SYNCBLOCK(m_csPowerState);

  g_iPPLMNBufferPos = PPLMN_BUFFER_NOT_FILLED;
  g_dwSIMLockedState = RIL_LOCKEDSTATE_UNKNOWN;
  ClearGPRSParamCache();

  if (m_dwModemState != MODEMSTATE_POWEROFF) {
    EnterCriticalSection(&m_csRadioOn);
    m_fRadioOn = FALSE;
    LeaveCriticalSection(&m_csRadioOn);

    (void)m_pRilHandle->BlockCommandHandling();

    // Store the new equipment state
    m_dwModemState = MODEMSTATE_POWEROFF;
    m_fUrcInitialized = FALSE;
    m_fPreUrcInitialized = FALSE;

    if (m_hShutdownThread) {
      // Close handle of finished timeout thread
      (void)CloseHandle(m_hShutdownThread);
      m_hShutdownThread = NULL;
    } else {
      if (!m_fPowerOffForced) {
        // We have an unsolicited ^SHUTDOWN -> let the mux know that the module is gone
        SYNCBLOCK2(m_csForcePower);
        (void)SendMuxCmd(IOCTL_MPX_POWER_LOSS);
        (void)SendMuxCmd(IOCTL_MPX_POWER_FAIL);
        m_fPowerOffForced = TRUE;
        fUnsolicited = TRUE;
      }
    }

    // We'll be turning the radio off
    m_pRilHandle->SetVoiceCallDialing(FALSE);
    m_pRilHandle->SignalAbortInternalSIMReady();
    m_pRilHandle->SetCurrentSIMType(SIMTYPE_UNKNOWN);
    g_dwGPRSRegStatus = RIL_REGSTAT_UNKNOWN;
    g_dwRegStatus = RIL_REGSTAT_UNKNOWN;
    g_fRegStatus3detected = FALSE;
    g_bCINDIsActive = FALSE;
    if (g_iNrCallInfo > 0) {
      // When a call is ended by a shutdown, sometimes the ^SLCC URC doesn't show up, so we
      // broadcast a call state changed notification to allow the MMI to update the display.
      g_iNrCallInfo = 0;
      g_iIdxForFirstCall = -1;
      (void)m_pRilHandle->BroadcastRealBlobNotification(RIL_NOTIFY_CALLSTATECHANGED, NULL, 0);
    }

    // Check if there is any audio activity (for example the SAT play tone) and finish it.
    m_pRilHandle->SetLastSATPlayToneCmd(0);
    m_pRilHandle->SetSLCCaudioActive(FALSE);
    m_pRilHandle->SetCIEVaudioActive(FALSE);

	if(!SUPPORTS_ONLY_DATAMODE){
    	RHADeactivateVoicePath(m_pRilHandle, FALSE, FALSE);
	}

    // Turn off module power
    if (!m_fPowerOffForced || fUnsolicited) {
#ifdef RIL_RADIO_RESILIENCE
      RHA_SetRadioIgnition(FALSE);
#endif
      (void)RHA_RadioPwrOff();
    }

    // Close all possibly still open port devices
    (void)g_ComManager.CloseAllPortDevices();

    m_dwInitUrcState = INVALID_MODEM_STATE;

    (void)UnlockPowerState();

    // Finally unblock command handling again
    (void)m_pRilHandle->UnblockCommandHandling();
    m_pRilHandle->GetSimToolkit()->SSTN254TimeoutAbort();

    RILRetailTraceZone(ZONE_INFO, (TEXT("RilDrv: Module successfully switched off\r\n")));
  }

  if (pRes) {
    FillEquipmentStateStruct(pRes, RIL_EQSTATE_MINIMUM);
    pRes->dwReadyState = 0;
  }

  return TRUE;
}

//////////////////////////////////////////////////////////////////////////////
//
// Function to be called if a ^SYSSTART urc has been received.
//
// Params:
//  fFlightMode: Flag indicating if the ^SYSSTART urc belongs to flight mode.
//
// Return:
//  TRUE on success, FALSE if anything went wrong.
//
//////////////////////////////////////////////////////////////////////////////
BOOL CPowerManager::SysstartFinished(LPRILEQUIPMENTSTATE pRes, BOOL fFlightMode) {
  DWORD dwLastEquipmentState;

  SYNCBLOCK(m_csPowerState);

  if (!m_pRilHandle) {
    return FALSE;
  }

  // Store the new equipment state
  m_dwModemState = fFlightMode ? MODEMSTATE_AIRPLANE : MODEMSTATE_POWERON;
  m_fUrcInitialized = FALSE;
  m_fPreUrcInitialized = FALSE;

  dwLastEquipmentState = fFlightMode ? RIL_EQSTATE_DISABLETXANDRX : RIL_EQSTATE_FULL;
  (void)SetRegistryDWORD(RIL_LAST_EQUIPMENT_STATE_ROOT, RIL_LAST_EQUIPMENT_STATE_KEY, RIL_LAST_EQUIPMENT_STATE_VALUE, dwLastEquipmentState);

  if (pRes) {
    FillEquipmentStateStruct(pRes, fFlightMode ? RIL_EQSTATE_DISABLETXANDRX : RIL_EQSTATE_FULL);
    pRes->dwReadyState = 0;
  }

  (void)m_pRilHandle->BlockCommandPriority();

  (void)UnlockPowerState();

  return TRUE;
}

//////////////////////////////////////////////////////////////////////////////
//
// Fill the the given structure according to the supported system power
// states to let the system power manager know what this class is capable of.
// Currently the power states D4, D3, D0 are supported.
// Support bitmasks "pPpc->DeviceDx" and "pPpc->WakeFromDx":
//   0-0-0-D4-D3-D2-D1-D0
//
// Params:
//  pPpc: Pointer to a POWER_CAPABILITIES structure filled according to
//        the supported power states.
//
//////////////////////////////////////////////////////////////////////////////
void CPowerManager::FillPowerCapsStruct(PPOWER_CAPABILITIES pPpc) const {
UCHAR  ucPowerMask;
DWORD  dwModemState;
DWORD  dwModemStateD0;

  memset(pPpc, 0, sizeof(POWER_CAPABILITIES));

  dwModemStateD0 = RHA_SystemPowerChange(D4, D0, MODEMSTATE_POWEROFF, MODEMSTATE_POWERON, FALSE, TRUE);

  ucPowerMask = 1 << D4;
  for (int i = (int)D4; i >= (int)D0; i--) {
    switch (i) {
      case D0:
      case D1:
      case D2:
        dwModemState = dwModemStateD0;
        break;
      case D3:
        dwModemState = DEFAULT_URCCONFIG;
        break;
      case D4:
      default:
        dwModemState = MODEMSTATE_POWEROFF;
        break;
    }
    if (i != D0) {
      dwModemState = RHA_SystemPowerChange(D0, (CEDEVICE_POWER_STATE)i, dwModemStateD0, dwModemState, FALSE, TRUE);
    } else {
      dwModemState = dwModemStateD0;
    }
    pPpc->Power[i] = GetMaxPowerConsumption(dwModemState);
    pPpc->Latency[i] = GetMaxLatencyTime(dwModemState, dwModemStateD0);
    pPpc->DeviceDx |= ucPowerMask;
    if ((dwModemState != MODEMSTATE_POWEROFF) && (dwModemState != MODEMSTATE_AIRPLANE)) {
      // We can't wake up on external events in power off or airplane mode
      pPpc->WakeFromDx |= ucPowerMask;
    }
    ucPowerMask = ucPowerMask >> 1;
  }
}

//////////////////////////////////////////////////////////////////////////////
//
// Helper function to fill RILEQUIPMENTSTATE structure and implement
// driver-specific RIL_RADIOSUPPORT_* mapping.
//
// Params:
//  pRes     : Pointer to a RILEQUIPMENTSTATE structure filled according to
//             the new equipment state.
//  dwEqState: The new equipment state used to fill the structure.
//
//////////////////////////////////////////////////////////////////////////////
void CPowerManager::FillEquipmentStateStruct(LPRILEQUIPMENTSTATE pRes, DWORD dwEqState) const {
  memset(pRes, 0x00, sizeof(RILEQUIPMENTSTATE));
  pRes->cbSize = sizeof(RILEQUIPMENTSTATE);
  pRes->dwParams = RIL_PARAM_EQUIPMENTSTATE_ALL;
  pRes->dwEqState = dwEqState;
  pRes->dwReadyState = g_dwReadyState;
  if (RIL_EQSTATE_UNKNOWN == dwEqState) {
    pRes->dwRadioSupport = RIL_RADIOSUPPORT_UNKNOWN;
  } else {
    pRes->dwRadioSupport = (dwEqState == RIL_EQSTATE_FULL) ? RIL_RADIOSUPPORT_ON : RIL_RADIOSUPPORT_OFF;
  }
}

//////////////////////////////////////////////////////////////////////////////
//
// Private class implementation
//
//////////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////////
//
// Send a command (IOCTL) to the mux driver.
//
// Params:
//  dwCmd: The mux command.
//
// Return:
//  We might have a mux driver not knowing all proprietary IOCTLs. So we
//  simply return always TRUE to keep the code working.
//
//////////////////////////////////////////////////////////////////////////////
BOOL CPowerManager::SendMuxCmd(DWORD dwCmd) const {
DWORD  dwLen = MAX_PATH;
DWORD  dwActiveLen = MAX_PATH;
TCHAR  szKey[MAX_PATH];
TCHAR  szDummy[MAX_PATH];

  // Try to shutdown the mux
  HANDLE hMux = CreateFile(TEXT("MPX1:"), 0, 0, NULL, OPEN_EXISTING, 0, NULL);
  if (hMux == INVALID_HANDLE_VALUE) {
    // is mux in use ???
    if (!GetDeviceKeys(TEXT("MPX1:"), szDummy, &dwActiveLen, szKey, &dwLen)) {
      if (dwLen) {
        RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: Error -Unable to open mux driver\r\n")));
      }
    }
  } else {
    DWORD dwBytesRet;
    if (!DeviceIoControl(hMux, dwCmd, NULL, 0, NULL, 0, &dwBytesRet, NULL)) {
      // Nothing
    }
    (void)CloseHandle(hMux);
  }

  return TRUE;
}

//////////////////////////////////////////////////////////////////////////////
//
// Get the maximal possible latency time for a modem state change in
// milliseconds.
//
// Params:
//  StateFrom: The old modem state.
//  StateTo  : The new modem state.
//
// Return:
//  The latency time in milliseconds.
//
//////////////////////////////////////////////////////////////////////////////
DWORD CPowerManager::GetMaxLatencyTime(DWORD dwStateFrom, DWORD dwStateTo) const {
  switch(dwStateFrom) {
    case MODEMSTATE_FORCE_POWEROFF:
    case MODEMSTATE_POWEROFF:
      switch (dwStateTo) {
        case MODEMSTATE_FORCE_POWEROFF:
        case MODEMSTATE_POWEROFF:
          return 0;
        case MODEMSTATE_AIRPLANE:
          return 25000;
        case MODEMSTATE_POWERON:
        default: // MODEMSTATE_URCCONFIGs
          return 25000;
      }
    case MODEMSTATE_AIRPLANE:
      switch (dwStateTo) {
        case MODEMSTATE_FORCE_POWEROFF:
          return 1000;
        case MODEMSTATE_POWEROFF:
          return 5000;
        case MODEMSTATE_AIRPLANE:
          return 0;
        case MODEMSTATE_POWERON:
        default: // MODEMSTATE_URCCONFIGs
          return 5000;
      }
    case MODEMSTATE_POWERON:
      switch (dwStateTo) {
        case MODEMSTATE_FORCE_POWEROFF:
          return 1000;
        case MODEMSTATE_POWEROFF:
          return 10000;
        case MODEMSTATE_AIRPLANE:
          return 5000;
        case MODEMSTATE_POWERON:
          return 0;
        default: // MODEMSTATE_URCCONFIGs
          return 2500;
      }
    default: // MODEMSTATE_URCCONFIGs
      switch (dwStateTo) {
        case MODEMSTATE_FORCE_POWEROFF:
          return 1000;
        case MODEMSTATE_POWEROFF:
          return 10000;
        case MODEMSTATE_AIRPLANE:
          return 5000;
        case MODEMSTATE_POWERON:
          return 2500;
        default: // MODEMSTATE_URCCONFIGs
          return 0;
      }
  }
}

//////////////////////////////////////////////////////////////////////////////
//
// Get the maximal possible power consumption for a modem state in milliwatts.
//
// Params:
//  ModemState: The modem state to be queried.
//
// Return:
//  The power consumption in milliwatts.
//
//////////////////////////////////////////////////////////////////////////////
DWORD CPowerManager::GetMaxPowerConsumption(DWORD dwModemState) const {
  switch (dwModemState) {
    case MODEMSTATE_FORCE_POWEROFF:
    case MODEMSTATE_POWEROFF:
      return 0;
    case MODEMSTATE_AIRPLANE:
      return 20;
    case MODEMSTATE_POWERON:
      return 1100;
    default: // MODEMSTATE_URCCONFIGs
      return 20;
  }
}

//////////////////////////////////////////////////////////////////////////////
//
// Get the equipment state from the given modem state.
//
// Params:
//  dwModemState: The modem state we're looking the equipment state for.
//
// Return:
//  The current equipment state.
//
//////////////////////////////////////////////////////////////////////////////
DWORD CPowerManager::GetEquipmentFromModemState(DWORD dwModemState) const {
  switch (dwModemState) {
    case MODEMSTATE_POWEROFF:
      return RIL_EQSTATE_MINIMUM;
    case MODEMSTATE_AIRPLANE:
      return RIL_EQSTATE_DISABLETXANDRX;
    default:
      if (IS_URCSTATE(dwModemState)) {
        return RIL_EQSTATE_FULL;
      }
      break;
  }
  return RIL_EQSTATE_UNKNOWN;
}

//////////////////////////////////////////////////////////////////////////////
//
// Generate and broadcast an equipment state changed notification.
//
// Params:
//  pCmd            : Pointer to corresponding power command.
//  dwEquipmentState: The new equipment state.
//
// Return:
//  TRUE on successs, FALSE otherwise.
//
//////////////////////////////////////////////////////////////////////////////
BOOL CPowerManager::GenerateEquipmentNotification(const CPowerCmd* pCmd, DWORD dwEquipmentState) {
CNotificationData*  pnd;
RILEQUIPMENTSTATE   res;

  SYNCBLOCK(g_csClosing);

  pnd = new CNotificationData;
  if (!pnd) {
    return FALSE;
  }
  FillEquipmentStateStruct(&res, dwEquipmentState);
  if (dwEquipmentState != RIL_EQSTATE_FULL) {
    res.dwReadyState = 0;
  }
  if (!pnd->InitFromRealBlob(RIL_NOTIFY_RADIOEQUIPMENTSTATECHANGED, (void*)&res, res.cbSize)) {
    delete pnd;
    return FALSE;
  }
  GetRilDevice(pCmd ? pCmd->GetHandle() : NULL)->BroadcastNotification(pnd);

  return TRUE;
}

//////////////////////////////////////////////////////////////////////////////
//
// Wait for a possibly running state change to finish and lock further state
// changes.
//
// Return:
//  TRUE on successs, FALSE otherwise.
//
//////////////////////////////////////////////////////////////////////////////
BOOL CPowerManager::WaitAndLockPowerState(void) {
  if (!WaitPowerState()) {
    return FALSE;
  }
  return LockPowerState();
}

//////////////////////////////////////////////////////////////////////////////
//
// Wait for a possibly running state change to finish.
//
// Params:
//  dwEquipmentState: The new equipment state.
//
// Return:
//  TRUE on successs, FALSE otherwise.
//
//////////////////////////////////////////////////////////////////////////////
BOOL CPowerManager::WaitPowerState(void) {
  if (WaitForSingleObject(m_hRadioOnOffMutex, POWER_LOCK_TIMEOUT) != WAIT_OBJECT_0) {
    // Failing to wait for the power mutex indicates a serious problem
    // -> we better turn off the lights
    RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: Timeout while waiting for power mutex!\r\n")));
    (void)ForcePowerOff();
    return FALSE;
  }

  EnterCriticalSection(&m_csForcePower);
  if (m_fPowerOffForced) {
    LeaveCriticalSection(&m_csForcePower);
    return FALSE;
  }
  LeaveCriticalSection(&m_csForcePower);

  return TRUE;
}

//////////////////////////////////////////////////////////////////////////////
//
// Empty the power command queue.
//
//////////////////////////////////////////////////////////////////////////////
void CPowerManager::EmptyCmdQueue(void) {
CPowerCmd* pCmd;

  while(SUCCEEDED(m_CmdQueue.Get(pCmd, 0))) {
    delete pCmd;
  }
}

//////////////////////////////////////////////////////////////////////////////
//
// Empty the AT command queue.
//
//////////////////////////////////////////////////////////////////////////////
void CPowerManager::EmptyATCmdQueues(void) const {
  while (!g_CmdQ.FEmpty()) {
    Sleep(10);
  }
}

//////////////////////////////////////////////////////////////////////////////
//
// Turn module off completely (D4).
//
// Params:
//  pCmd: Pointer to corresponding power command.
//
// Return:
//  TRUE on successs, FALSE otherwise.
//
//////////////////////////////////////////////////////////////////////////////
BOOL CPowerManager::TurnOffModule(CPowerCmd* /*pCmd*/) {
CRilHandle*  pDevice;
CComHandle*  pDataPort;
DWORD        dwCmdOpt;

  pDevice = GetRilDevice(NULL);
  if (pDevice == NULL) {
    return FALSE;
  }

  // Unblock possibly blocked command handling
  (void)pDevice->UnblockCommandHandling();

  // Switch possibly enabled Gps handling off
  (void)g_GpsHandling.SwitchGpsStatePassive(FALSE);
  if (g_GpsHandling.IsGpsActive() && !g_GpsHandling.IsGpsLocked()) {
    (void)g_GpsHandling.SwitchGpsState(FALSE);
  }

  // Before the RIL sends the AT^SMSO command on the data port, it is
  // necessary to check, if the data mode is active there and end it, if
  // necessary.
  pDataPort = m_pRilHandle->GetComDevice(DATA_PORT);
  if (pDataPort != NULL) (void)pDataPort->SwitchBackToCommandMode();

  dwCmdOpt = CMDOPT_NOOP | CMDOPT_NONE | CMDOPT_IGNORERADIOOFF | CMDOPT_POWER;
  if (!QueueInternalCmdBlocking(HCCMD_STANDARD, pDevice, NULL, dwCmdOpt, APIID_SETEQUIPMENTSTATE, 0, 0, 0)) {
    HandleShutdownError();
    return FALSE;
  }

  // Block the command handling
  (void)pDevice->BlockCommandHandling();

  RILRetailTraceZone(ZONE_INFO, (TEXT("RilDrv: Radio off\r\n")));

  // Close the used COM ports (mux mode is left automatically with the last virtual port)
  if (!g_ComManager.CloseAllPortDevices()) {
    HandleShutdownError();
    return FALSE;
  }

  SYNCBLOCK(m_csPowerState);
  SYNCBLOCK2(m_csForcePower);
  if (m_fPowerOffForced) {
    return FALSE;
  }
  m_hShutdownThread = CreateThread(NULL, 0, ShutdownFinishThread, this, 0, NULL);
  if (!m_hShutdownThread) {
    HandleShutdownError();
    return FALSE;
  }

  return TRUE;
}

//////////////////////////////////////////////////////////////////////////////
//
// Turn module on to full operation (D0) from full off mode mode (D4).
//
// Params:
//  pCmd             : Pointer to corresponding power command.
//  fActiveFlightMode: Flag indicating if we have to start in active flight
//                     mode.
//  fFullReinit      : Flag indicating if we have to restart the full
//                     reinitialization (TRUE) ot only a basic one (FALSE).
//
// Return:
//  TRUE on successs, FALSE otherwise.
//
//////////////////////////////////////////////////////////////////////////////
BOOL CPowerManager::TurnOnModule(const CPowerCmd* pCmd, BOOL fActiveFlightMode, BOOL fFullReinit) {
COM_PORT_TYPE  i;
CRilHandle*    pDevice;
TCHAR          tszTmp[MAX_CBM_STRING];
DWORD          dwMaxOpenAttempts;
DWORD          dwPortDelay;
DWORD          dwTime;
DWORD          j;
DWORD          dwDownloadFail = 0;
BOOL           fMuxBasePort = FALSE;
BOOL           bNeedRestart = FALSE;
BOOL           bNeedRestartSBNW = FALSE;
BOOL           bNeedRestartJava = FALSE;
BOOL           bWaitForSysstart = TRUE;
DWORD          dwNeedJavaUpdate = 0;
#ifdef RIL_RADIO_RESILIENCE
char szPIN[MAXLEN_PIN+1];
#endif

  pDevice = GetRilDevice(NULL);
  if (pDevice == NULL) {
    return FALSE;
  }

  pDevice->ReadNetworkListFilename();
  pDevice->ResetSysStartDection();

  ReadDebugOptions();

  TraceDriverInfo();
  j = GetMuxVersion();
  if (j == (DWORD)-1) {
    // Mux driver not used, check version of USB driver
    if (GetUsbVersion() < MIN_REQUIRED_USB_VERSION) {
      j = MIN_REQUIRED_USB_VERSION;
      RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: Unsupported USB-Driver, min. required USB version is %d.%d.%d.%d\r\n"), (j>>24)&255, (j>>16)&255, (j>>8)&255, j&255));
      return FALSE;
    }
  } else {
    // Check required mux version
    if (j < MIN_REQUIRED_MUX_VERSION) {
      j = MIN_REQUIRED_MUX_VERSION;
      RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: Unsupported Mux-Driver, min. required mux version is %d.%d.%d.%d\r\n"), (j>>24)&255, (j>>16)&255, (j>>8)&255, j&255));
      return FALSE;
    }
  }

  // Delay 1st module start
  if (!GetRegistryDWORD(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, TEXT("MinFirstStartTick"), &dwPortDelay)) {
    dwPortDelay = 0;
  }
  dwTime = GetTickCount();
  m_dwLastModuleStart = dwTime;
  if (dwPortDelay > dwTime) {
    dwTime =  dwPortDelay -dwTime;
    RILRetailTraceZone(ZONE_INFO, (TEXT("RilDrv: Delaying module start for %d ms\r\n"), dwTime));
    Sleep(dwTime);
  }

  // Block the command handling
  (void)pDevice->BlockCommandHandling();

  RILRetailTraceZone(ZONE_INFO, (TEXT("RilDrv: Radio on%s (%ums)\r\n"), fActiveFlightMode ? TEXT(" in airplane mode") : TEXT(""), GetTickCount()));

  // Get information about previously aborted firmware updates.
  (void)GetRegistryDWORD(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, TEXT("LastDownloadFailed"), &dwDownloadFail);
  if (dwDownloadFail > 0) {
    // EHS5: to make sure, that the module is really in bootloader mode now,
    // it is possible to set a signal on a special pin on the module.
    RHA_SetBootloaderPin(TRUE);
  }

  // Switch the module on
  if (!SwitchModuleOn(fActiveFlightMode)) {
    RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: Error - Unable to switch module on\r\n")));
    if (dwDownloadFail > 0)
      RHA_SetBootloaderPin(FALSE);
    ForcePowerOff();
    return FALSE;
  }

  // To get rid of the 'X' in the antenna icon fast, we prematurely send the equipment state notification.
  if (!fActiveFlightMode)
      (void)GenerateEquipmentNotification(NULL, RIL_EQSTATE_FULL);

  if (!GetRegistryDWORD(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, TEXT("WaitBeforeATCommand"), &g_dwWaitBeforeATCommand)) {
    g_dwWaitBeforeATCommand = 10;
  }

  if (GetRegistryDWORD(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, TEXT("DelayModuleInit"), &j)) {
    RILRetailTraceZone(ZONE_INFO, (TEXT("RilDrv: Delay module initialization by %dms\r\n"), j));
    Sleep(j);
  }

  // Open the base port
  pDevice->GetPortOpenTimeouts(&dwMaxOpenAttempts, &dwPortDelay);
  for (j = 0; j < dwMaxOpenAttempts; j++) {
    if ( IsPowerOffForced() == TRUE ) {
      RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: Error - already forced power off\r\n")));
      return FALSE;
    }
    if (g_ComManager.OpenBasePort()) {      // Multiplexer installed (HC25 Rel2)? Open mux base port.
      fMuxBasePort = TRUE;
      break;
    }
    Sleep(dwPortDelay);
  }
  if ( (IsPowerOffForced() == TRUE) || (j >= dwMaxOpenAttempts)) {
    RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: Error - Unable to open first port\r\n")));
    if (dwDownloadFail > 0)
      RHA_SetBootloaderPin(FALSE);
    ForcePowerOff();
    return FALSE;
  }

  // The previous firmware download might be failed. Since the module is now in the boot loader
  // mode, the firmware update must be started immediately.
  if (dwDownloadFail > 0)  {
    //Last download failed, start next download immediately.
    RILRetailTraceZone(ZONE_INFO, (TEXT("RilDrv: Forcing firmware download\r\n")));
    if (!pDevice->TestForValidFirmware(DATA_PORT, TRUE, &bNeedRestart)) {
      RHA_SetBootloaderPin(FALSE);
      ForcePowerOff(bNeedRestart);
      return FALSE;
    }
    RHA_SetBootloaderPin(FALSE);
  }

  // EHS5 only: after a firmware update it is necessary to re-initialize the NV
  // block structure before doing anything else. The ^SYSSTART URC won't show
  // up in this situation.
  if (!pDevice->EnsureBlockIntegrity(DATA_PORT, &bNeedRestart)) {
    DWORD dwStartTime;
    DWORD dwCommMask;

    // The module will now reset after a while.
    dwStartTime = GetTickCount();
    // Check USB driver state
    for (;;) {
      if (!GetCommMask(g_ComManager.GetPortHandle(DATA_PORT), &dwCommMask)) {
        RILRetailTraceZone(ZONE_INFO, (TEXT("RilDrv: Cleanup eset finished\r\n")));
        break;
      }

      // Wait for reset
      Sleep(100);
      if ((GetTickCount() - dwStartTime) >= CLEANUP_TIMEOUT) {
        RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: Timeout while waiting for cleanup reset!\r\n")));
        break;
      }
    }
    ForcePowerOff(bNeedRestart);
    return FALSE;
  }

  // Relevant for EHS5 Rel2 only: it might be a good idea to wait for ^SSYSTART
  // now instead later after the first AT commands have been sent.
  j = 0;
  (void)GetRegistryDWORD(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, TEXT("WaitForSysstartAtOpenPort"), &j);
  if (j == 1) {
    pDevice->WaitForSysstart(DATA_PORT);
    bWaitForSysstart = FALSE;   // Avoid waiting for ^SYSSTART again later.
  }

#ifdef RIL_CATCH_NDIS_START_MSG
  CloseHandle(CreateThread(NULL, 0, CatchNdisMsgThread, NULL, 0, NULL));
#endif

  // Send the pre-init strings
  if (!g_ComManager.SendPreInitCmds(DATA_PORT)) {
    ForcePowerOff();
    return FALSE;
  }

  // Check, if it is necessary to reset the Acquisition database.
  if (!pDevice->ResetAcqDB(DATA_PORT, &bNeedRestart)) {
    ForcePowerOff(bNeedRestart);
    return FALSE;
  }

  if (pDevice->EnsureSDPORTsetting(DATA_PORT)) {
    DWORD dwSDPORTTimeout = WAIT_AFTER_SDPORT_SETTING;

    (void)GetRegistryDWORD(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, TEXT("WaitAfterSDPORTChange"), &dwSDPORTTimeout);
    // SDPORT settings have been changed: close the USB port to
    // allow the USB driver to enumerate in the new setting.
    RILRetailTraceZone(ZONE_INFO, (TEXT("RilDrv: SDPORT settings have been changed\r\n")));
    (void)g_ComManager.CloseBasePort();
    Sleep(dwSDPORTTimeout);
    for (j = 0; j < dwMaxOpenAttempts; j++) {
      if (IsPowerOffForced() == TRUE) {
        RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: Error - already forced power off\r\n")));
        return FALSE;
      }
      if (g_ComManager.OpenBasePort()) {      // Multiplexer installed (HC25 Rel2)? Open mux base port.
        fMuxBasePort = TRUE;
        break;
      }
      Sleep(dwPortDelay);
    }
    if ( (IsPowerOffForced() == TRUE) || (j >= dwMaxOpenAttempts)) {
      RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: Error - Unable to open first port after SDPORT change\r\n")));
      ForcePowerOff();
      return FALSE;
    }
  }

  // Lock the cmd requeue threads to handle the proper delays
  EnableCmdRequeueWait();

  if (!pDevice->CheckModemType(DATA_PORT)) {
    ForcePowerOff();
    return FALSE;
  }

  // Wait for ^SYSSTART on EHS5 Rel2 unless it has already been done.
  if (MUST_WAIT_FOR_SYSSTART && bWaitForSysstart)
    pDevice->WaitForSysstart(DATA_PORT);

  // Ensure that the possibly enabled airplane mode is switched off, also check
  // if the module is in a valid CFUN mode.
  if (!EnsureActiveFlightMode(fActiveFlightMode)) {
    RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: Error - Unable to initialize the airplane mode\r\n")));
    ForcePowerOff();
    return FALSE;
  }

  ResetSecurityStates();
  pDevice->SetLastSATPlayToneCmd(0);
  pDevice->SetCIEVaudioActive(FALSE);
  pDevice->SetSLCCaudioActive(FALSE);
  pDevice->SetCurrentSIMType(SIMTYPE_UNKNOWN);
  pDevice->ResetNetworkTechnologyState();
  pDevice->SetGotCDMAActivationURC(FALSE);
  j = 0;
  if (!GetRegistryDWORD(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, TEXT("ExtendAudioPathActivationPhase"), &j))
    j = 1;
  pDevice->SetCIEVaudioUsed(j == 1 ? TRUE : FALSE);
  // Registry key "UseGSM0707Cmds": if set to 1, the RIL will use AT Commands rather
  // than *#-sequences for supplementary service.
  j = 0;
  if (GetRegistryDWORD(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, TEXT("UseGSM0707Cmds"), &j))
    g_fUseGSM0707Cmds = (j==1 ? TRUE : FALSE);
  else
#ifdef RIL_USE_GSM0707_CMDS
    g_fUseGSM0707Cmds = TRUE;
#else
    g_fUseGSM0707Cmds = (USE_GSM0707_CMDS_FOR_SS ? TRUE : FALSE);
#endif
  // Registry key "NoAudioSettings": if set to 1, the module won't use any audio
  // AT commands.
  if (GetRegistryDWORD(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, TEXT("NoAudioSettings"), &j))
    g_fNoAudioSettings = (j==1 ? TRUE : FALSE);
  else
#ifdef DISABLE_AUDIO_SETTING_PER_DEFAULT
    g_fNoAudioSettings = TRUE;
#else
    g_fNoAudioSettings = FALSE;
#endif
  // Some modules don't support audio commands at all.
  if (MUST_NOT_USE_AUDIO) g_fNoAudioSettings = TRUE;
  // Registry key "UseModuleAudioConfig": if set to 0, the RIL won't use the AT commands
  // AT^SNFI and AT^SNFO. Default: 1.
  g_dwUseSNFOSNFI = 1;
  (void)GetRegistryDWORD(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, TEXT("UseModuleAudioConfig"), &g_dwUseSNFOSNFI);
  // Registry key "SeparateAudioATCmds": if set to 1, the RIL won't send the AT command
  // AT^SNFS on the same line as AT^SNFO or AT^SNFI. Default: 0 (all commands are sent
  // on the same line).
  g_dwSeparateAudioATCmds = 0;
  (void)GetRegistryDWORD(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, TEXT("SeparateAudioATCmds"), &g_dwSeparateAudioATCmds);
  // Registry key "ModifyAudioSettingsFirst": if set to a value greater than 0, the RIL
  // will first apply a different set of values for SNFO and SNFI before setting the
  // actual value. If set to 1, this applies to SNFO:<cdcRxGain> and SNFI <ampMic2>.
  // if set to 2 it additionally applies to SNFI:<ampMic1> as well.
  // On EHS5 this setting applies to <outVolStep> (SNFO) and <inVolSteps> (SNFI).
  g_dwModifyAudioSettingsFirst = 0;
  (void)GetRegistryDWORD(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, TEXT("ModifyAudioSettingsFirst"), &g_dwModifyAudioSettingsFirst);
  // Registry key "AlwaysZeroAudioParameters": if using the analogue interface of he
  // PH8 it is recommended to set the SNFO and SNFI parameters to 0 before changing
  // the audio mode with SNFS. So if the analog audio inter face is used, this registry
  // key should be set to 1, if the digital interface is used the key can be set to 0.
  g_dwAlwaysZeroAudioParameters = 0;
  (void)GetRegistryDWORD(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, TEXT("AlwaysZeroAudioParameters"), &g_dwAlwaysZeroAudioParameters);
  // When started, the module is not muted.
  g_dwLastMuteSetting = 0;

#ifdef RIL_USE_CSQ_NOTIFICATIONS
  if (AVOID_SIND_RSSI_IN_CDMA) {
    RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: this radio requires CSQ polling, activate RIL_USE_CSQPOLLING in 'sources' file\r\n")));
  }
#endif

  //ELS61 variant products doesn't support Audio.
  if(!UNSUPPORTS_AUDIO){
	  // If there is a more recent set of audio profiles, download them to the modem
	  if (!g_fNoAudioSettings) {
	    if (pDevice->CheckAudioProfilesVersion(DATA_PORT)) {
	      if (!pDevice->DownloadAudioProfiles(DATA_PORT)) {
	        (void)ForcePowerOff();
	        return FALSE;
	      }
	    }

	    // Read Audio settings from registry
	    GetAudioConfig();
	  }
  }

  // Radio with CDMA support might need an update of the PRL and PRI configuration.
  if (GLOBAL_MODE_RADIO || CDMA_ONLY_RADIO) {
    WCHAR wszFileName[MAX_PATH];
    WCHAR wszRegKey[MAX_PATH];

    if (pDevice->CheckCdmaPriVersion(DATA_PORT)) {
      if (pDevice->DownloadCdmaPriConfig(DATA_PORT)) {
        bNeedRestartSBNW = TRUE;
      }
    }
    if (pDevice->CheckCdmaPrlVersion(DATA_PORT, wszFileName, wszRegKey)) {
      if (pDevice->DownloadCdmaPrlList(DATA_PORT, wszFileName, wszRegKey)) {
        bNeedRestartSBNW = TRUE;
      }
    }
  }

  // There might be an update of NV items necessary.
  if (!pDevice->DownloadNvItems(DATA_PORT, &bNeedRestartSBNW)) {
    (void)ForcePowerOff();
    return FALSE;
  }

  // There might be an update of the file sytem necessary.
  if (!pDevice->DownloadFsItems(DATA_PORT, &bNeedRestartSBNW)) {
    (void)ForcePowerOff();
    return FALSE;
  }

  // Read registry keys for advanced network operator selection.
  g_dwAutomaticGroupSearchTimeout = 0;
  (void)GetRegistryDWORD(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, TEXT("AutomaticGroupSearchTimeout"), &g_dwAutomaticGroupSearchTimeout);
  g_bNeedAllBandNetworkSelection = FALSE;
  j = 0;
  if (GetRegistryDWORD(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, TEXT("AllBandNetworkSelection"), &j))
    g_bNeedAllBandNetworkSelection = (j == 1 ? TRUE : FALSE);
  j = 1;
  (void)GetRegistryDWORD(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, TEXT("ExtendedRegStatusNotification"), &j);
  pDevice->SetExtendedRegStatusNotification(j);
  pDevice->SetNetworkRejectionState(FALSE);

  // Automatic band group serach timeout doesn't apply, when all band network
  // selection is turned off. It is ignored, if the timeout value is less than 10 s.
  if (g_bNeedAllBandNetworkSelection == FALSE || (g_dwAutomaticGroupSearchTimeout > 0 && g_dwAutomaticGroupSearchTimeout < MIN_ABNWSELECTION_TIMEOUT))
    g_dwAutomaticGroupSearchTimeout = MIN_ABNWSELECTION_TIMEOUT;

  g_bChangeCNMIwhileSMSsend = TRUE;
  j = 0;
  if (GetRegistryDWORD(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, TEXT("StoreIncomingSMSonSIMwhileSending"), &j))
    g_bChangeCNMIwhileSMSsend = (j == 1 ? TRUE : FALSE);
  g_bDefaultCNMIstoreOnSIM = (STORE_SMS_ON_SIM_PER_DEFAULT ? TRUE : FALSE);
  j = 0;
  if (GetRegistryDWORD(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, TEXT("StoreSMSonSIMasDefault"), &j))
    g_bDefaultCNMIstoreOnSIM = (j == 1 ? TRUE : FALSE);

  g_dwReceiveCellBroadCast = 2;
  (void)GetRegistryDWORD(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, TEXT("EnableCBM"), &g_dwReceiveCellBroadCast);
#ifdef CSCB_IN_MC75_STYLE
  g_dwReceiveCellBroadCastAccept = 0;
  if (g_dwReceiveCellBroadCast == 1)
    g_dwReceiveCellBroadCastAccept = 1;
#endif
  memset(tszTmp, 0, sizeof(tszTmp));
  (void)GetRegistrySZ(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, TEXT("EnableCBMChannels"), tszTmp, MAX_CBM_STRING);
  (void)_snprintfz(g_szReceiveCellBroadCastChannels, MAX_CBM_STRING, "%S", tszTmp);
  memset(tszTmp, 0, sizeof(tszTmp));
  (void)GetRegistrySZ(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, TEXT("EnableCBMDCS"), tszTmp, MAX_CBM_STRING);
  (void)_snprintfz(g_szReceiveCellBroadCastDCS, MAX_CBM_STRING, "%S", tszTmp);

  j = 0;
  (void)GetRegistryDWORD(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, TEXT("FakeRegStatusDeniedToHome"), &j);
  g_bFakeRegStatusDeniedToHome = (j == 1 ? TRUE : FALSE);

  if (!pDevice->TestForValidIMEI(DATA_PORT, &bNeedRestart)) {
    ForcePowerOff(bNeedRestart);
    return FALSE;
  }
  bNeedRestart = FALSE;
  if (!pDevice->TestForValidFirmware(DATA_PORT, FALSE, &bNeedRestart)) {
    ForcePowerOff(bNeedRestart);
    return FALSE;
  }
  bNeedRestart = bNeedRestartSBNW;
  bNeedRestartJava = FALSE;
  
  
  if (FIRMWARE_UPDATE_WITH_JAVA) {
    (void)GetRegistryDWORD(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, TEXT("FirmwareUpdateWithJava"), &dwNeedJavaUpdate);
	RILRetailTraceZone(ZONE_INFO, (TEXT("RilDrv: FirmwareUpdateWithJava = %d\r\n"), dwNeedJavaUpdate));
	if(1 == dwNeedJavaUpdate){
		RILRetailTraceZone(ZONE_INFO, (TEXT("RilDrv: Begin to update java midlet.\r\n")));
		if (!pDevice->TestForValidJavaMidlet(DATA_PORT, &bNeedRestartJava)) {
		  ForcePowerOff(bNeedRestart);
		  return FALSE;
		}
		(void)SetRegistryDWORD(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, TEXT("FirmwareUpdateWithJava"), 0);

        (void)GetRegistryDWORD(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, TEXT("FirmwareUpdateWithJava"), &dwNeedJavaUpdate);
        RILRetailTraceZone(ZONE_INFO, (TEXT("RilDrv: FirmwareUpdateWithJava is set to %d\r\n"), dwNeedJavaUpdate));
		
		if (bNeedRestartJava)
		  bNeedRestart = TRUE;
		  
		RILRetailTraceZone(ZONE_INFO, (TEXT("RilDrv: Complete updating java midlet.\r\n")));
	}
    else{
	    RILRetailTraceZone(ZONE_INFO, (TEXT("RilDrv: Skip updating java midlet.\r\n")));	
    }
  }
  if (!pDevice->InitGPRSAttachMode(DATA_PORT, &bNeedRestart)) {
    ForcePowerOff();
    return FALSE;
  }
  if (!pDevice->InitConfigurationSettings(DATA_PORT, &bNeedRestart)) {
  	RILRetailTraceZone(ZONE_INFO, (TEXT("RilDrv: Init Configuration failed!!!\r\n")));
    ForcePowerOff();
    return FALSE;
  }
  if (!pDevice->CheckECCSettings(DATA_PORT, &bNeedRestart)) {
    ForcePowerOff();
    return FALSE;
  }
  if (bNeedRestart) {
    // The functions above may have changed settings in the module, which will only
    // become active after the next restart of the module. The RIL can perform a
    // restart now, if configured with registry.
    j = 1;
    (void)GetRegistryDWORD(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, TEXT("RestartOnSettingUpdate"), &j);
    if (j == 1) {
      RILRetailTraceZone(ZONE_INFO, (TEXT("RilDrv: Module configuration changed - initiate restart\r\n")));
      pDevice->ShutdownOnConfigChange(DATA_PORT);
      ForcePowerOff(bNeedRestart);
      return FALSE;
    }
    else {
      RILRetailTraceZone(ZONE_INFO, (TEXT("RilDrv: Module configuration changed - restart disabled\r\n")));
    }
  }

  if (!pDevice->TestUSIMInserted()) {
    ForcePowerOff();
    return FALSE;
  }

#ifdef RIL_RADIO_RESILIENCE
  if (g_fAllowReboot && FetchPINSecure(szPIN, MAXLEN_PIN)) {
    char  szResponse[MAX_ENHANCED_INIT_AT_RESPONSE];
    char  szCmd[MAX_ATCMD_LEN];
    int   iRetries = MAX_SIM_READY_TRIES_DEFAULT;

    // Re-enter PIN.
    (void)_snprintfz(szCmd, MAX_ATCMD_LEN, "AT+CPIN=\"%s\"\r", szPIN);
    // The SIM might not be ready yet to accept the PIN, so the RIL
    // needs to do some retries.
    while (iRetries > 0) {
        Sleep(SIM_READY_RETRY_INTERVAL);
        memset(szResponse, 0, MAX_ENHANCED_INIT_AT_RESPONSE);
        if (!pDevice->ExSendATCmdGetRsp(DATA_PORT, szCmd, szResponse, sizeof(szResponse), 15000, 0)) break;
        // Do retries only on "SIM busy" error.
        if (strstr(szResponse, "+CME ERROR: 14") == NULL) break;
        iRetries++;
    }
  }
  else {
    ClearPINSecure();
  }
  j = 0;
  g_fAllowReboot = FALSE;
  g_dwRebootEmergencyStatus = EMERG_SHUTDOWN_NONE;
  GetRegistryDWORD(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, TEXT("PreventAutoReboot"), &j);
  if (j != 1)
      g_fAllowReboot = TRUE;

  if (g_fAllowReboot) {
    DWORD dwPause = 0;

    if (GetRegistryDWORD(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, TEXT("DelayAutoReboot"), &dwPause))
      Sleep(dwPause);
  }
#endif

  if (fMuxBasePort) {
    // If multiplexer is used: close the mux base port and open the modem port normally.
    (void)g_ComManager.CloseBasePort();

    // Open the modem port
    if (!g_ComManager.OpenPortDevice(DATA_PORT)) {
      RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: Failed to open data port\r\n")));
      ForcePowerOff();
      return FALSE;
    }
  }
  // Open the application port
  if (!g_ComManager.OpenPortDevice(URC_PORT)) {
    RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: Failed to open URC port\r\n")));
    ForcePowerOff();
    return FALSE;
  }

  // Init the ports
  for (i = 0; i < NUMBER_OF_PORTS; i++) {
    if (!pDevice->GetComDevice(i)->InitComPortForRIL(NULL, NULL)) {
      RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: Failed to send initialization commands on port %d\r\n"), i));
      ForcePowerOff();
      return FALSE;
    }
  }

  g_iNrCallInfo = -1;  // From here on, there might come incomming calls, so the buffer of call must be reset.
  g_iIdxForFirstCall = -1;
  pDevice->SetIgnoreNextNOCARRIER(FALSE);
  pDevice->ReadNoRoamingNetworks();

  // Re-Initialize the modem
  if (fFullReinit) {
    if (!StartReinitialization(pCmd)) {
      ForcePowerOff();
      return FALSE;
    }
  } else {
    (void)GetRilDevice(NULL)->UnblockCommandHandling();
    if (!g_ComManager.SendInitCmds(TRUE)) {
      ForcePowerOff();
      return FALSE;
    }
  }

  // With HC25 there won't be any SYSSTART-Urc so we have to generate it on our own
  CResponse*  pRsp;
  char        szSysstart[SYSSTART_MESSAGE_BUFFER];
  LPCSTR      szRemainder;
  UINT        cbRemainder;
  pRsp = new CResponse(DATA_PORT, GetRilDevice(NULL));
  if (!pRsp) {
    ForcePowerOff();
    return FALSE;
  }
  if (fActiveFlightMode) strncpyz(szSysstart, "^SYSSTART AIRPLANE MODE\r\n", SYSSTART_MESSAGE_BUFFER);
  else  strncpyz(szSysstart, "^SYSSTART\r\n", SYSSTART_MESSAGE_BUFFER);
  if (!pRsp->AppendString(szSysstart, strlen(szSysstart), szRemainder, cbRemainder)) {
    delete pRsp;
    ForcePowerOff();
    return FALSE;
  }
  delete pRsp;

  EnterCriticalSection(&m_csRadioOn);
  m_fRadioOn = TRUE;
  LeaveCriticalSection(&m_csRadioOn);

  return TRUE;
}

//////////////////////////////////////////////////////////////////////////////
//
// Start the module initialization sequence.
//
// Params:
//  pCmd: Pointer to corresponding power command.
//
// Return:
//  TRUE on successs, FALSE otherwise.
//
//////////////////////////////////////////////////////////////////////////////
BOOL CPowerManager::StartReinitialization(const CPowerCmd* pCmd) {
DWORD    dwCmdOpt;
DWORD    dwRetries = 1;
DWORD    dwRetryDelay = 1000;
HRESULT  hr = S_OK;

  SYNCBLOCK(g_csClosing);

  if (!RHA_IsRadioPwrOn()) {
    return FALSE;
  }

  // Unblock possibly blocked command handling
  (void)GetRilDevice(NULL)->UnblockCommandHandling();

  dwCmdOpt = CMDOPT_NONE | CMDOPT_SETRADIOON | CMDOPT_IGNORERADIOOFF | CMDOPT_REINIT;

  // Problem with USB on some devices: the first AT command might fail, in
  // this case the RIL can make a retry.
  (void)GetRegistryDWORD(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, TEXT("PostInitATRetries"), &dwRetries);
  (void)GetRegistryDWORD(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, TEXT("PostInitATRetryDelay"), &dwRetryDelay);

  if (pCmd->GetHandle()) {
    if (!QueueCmdWithRetry(HCCMD_STANDARD, pCmd->GetHandle(), "AT\r", dwCmdOpt, APIID_SETEQUIPMENTSTATE, NULL, NULL, hr, dwRetries, dwRetryDelay)) {
      RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: Error - Unable to queue radio on command\r\n")));
      return FALSE;
    }
  } else {
    if (!QueueInternalCmd(HCCMD_STANDARD, GetRilDevice(NULL), "AT\r", dwCmdOpt, APIID_SETEQUIPMENTSTATE, 0, dwRetries, dwRetryDelay)) {
      RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: Error - Unable to queue radio on command\r\n")));
      return FALSE;
    }
  }

  return SUCCEEDED(hr);
}

//////////////////////////////////////////////////////////////////////////////
//
// Ensure that the active flight mode is deactivated during module start.
//
// Params:
//  fEnter : Flag indicating if the special flight mode shall be entered
//           (TRUE) or left (FALSE).
//
// Return:
//  TRUE on success, FALSE otherwise.
//
//////////////////////////////////////////////////////////////////////////////
BOOL CPowerManager::EnsureActiveFlightMode(BOOL fEnter) {
CRilHandle*  pDevice;
char         szResponse[MAX_ENHANCED_INIT_AT_RESPONSE];
DWORD        dwForceCFUN = (FORCE_CFUN1_ON_START ? 1 : 0);
DWORD        dwCFUN = 0;
BOOL         fSendFlightModeCmd = TRUE;

  pDevice = GetRilDevice(NULL);
  if (pDevice == NULL) {
    return FALSE;
  }

  (void)GetRegistryDWORD(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, TEXT("ForceCFUN1"), &dwForceCFUN);
  if (dwForceCFUN != 1 || KEEP_CFUN7_MODE) {
    DWORD dwPos = 0;

    memset(szResponse, 0, sizeof(szResponse));
    if (!pDevice->ExSendATCmdGetRsp(DATA_PORT, "AT+CFUN?\r", szResponse, sizeof(szResponse), FLIGHTMODE_TIMEOUT, 1)) {
      return FALSE;
    }
    // There might be a second parameter in the AT+CFUN? response, but only the
    // first one is relevant.
    if (FindString(0, szResponse, "+CFUN: ", strlen(szResponse), &dwPos))
      dwCFUN = (DWORD)atoi(szResponse + dwPos);
    if (!SPECIAL_FLIGHT_MODE_CMD) {
        // Avoid double sending of AT+CFUN=1
        if (dwCFUN == 1 && !fEnter)
          fSendFlightModeCmd = FALSE;
    }
  }

  // Do not set to CFUN=1, if radio is currently in CFUN=7 mode an needs to
  // keep it.
  if (dwCFUN == 7 && KEEP_CFUN7_MODE) {
    RILRetailTraceZone(ZONE_INFO, (TEXT("RilDrv: Module is in Customer IMEI mode, skip setting CFUN mode\r\n")));
    return TRUE;
  }

  // Set the module to CFUN=1 mode. This depends on some conditions:
  // - Module uses AT^SCFG to enable flight mode.
  // - Module is currently in CFUN=0 mode
  // - This is configured by registry.
  if (SPECIAL_FLIGHT_MODE_CMD || dwCFUN == 0 || dwForceCFUN == 1) {
    // Force module in CFUN=1 mode to make sure, that the module is fully
    // operational and is able to run through the rest of the RIL initialization.
    if (!pDevice->ExSendATCmdGetRsp(DATA_PORT, "AT+CFUN=1\r", szResponse, sizeof(szResponse), FLIGHTMODE_TIMEOUT, 1)) {
      return FALSE;
    }
  }

  // Apply active flight mode (if necessary).
  if (fSendFlightModeCmd) {
    memset(szResponse, 0, sizeof(szResponse));
    if (!pDevice->ExSendATCmdGetRsp(DATA_PORT, FLIGHTMODE_CMD(fEnter), szResponse, sizeof(szResponse), FLIGHTMODE_TIMEOUT, 1)) {
      return FALSE;
    }
    if (!FindString(0, szResponse, "OK\r\n", strlen(szResponse), NULL) && !FindString(0, szResponse, "0\r", strlen(szResponse), NULL)) {
    // Bug in the PH8 Rel2: the module might report to AT+CFUN?, that it is in
    // CFUN=1 mode, but actually it is in CFUN=7. In this case the AT+CFUN=1/4
    // command will fail. The RIL must ignore the error code in this case.
      return KEEP_CFUN7_MODE;
    }
  }

  return TRUE;
}

//////////////////////////////////////////////////////////////////////////////
//
// Switch the active module flight mode on or off if it is supported by the module.
//
// Params:
//  fEnter : Flag indicating if the special flight mode shall be entered
//           (TRUE) or left (FALSE).
//
// Return:
//  TRUE if the module flight mode could be entered, FALSE otherwise.
//
//////////////////////////////////////////////////////////////////////////////
BOOL CPowerManager::SwitchActiveFlightMode(BOOL fEnter) {
CRilHandle* pDevice;

  pDevice = GetRilDevice(NULL);
  if (pDevice == NULL) {
    return FALSE;
  }

  RILRetailTraceZone(ZONE_INFO, (TEXT("RilDrv: %s active flight mode\r\n"), fEnter ? TEXT("Entering") : TEXT("Leaving")));

  // Unblock possibly blocked command handling
  (void)pDevice->UnblockCommandHandling();

  // Block all uncritical commands
  if (!pDevice->BlockCommandPriority(CMDPRI_CRITICAL, fEnter)) {
    RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: Failed to block non critical commands!\r\n")));
    return FALSE;
  }

  // Now switch the flightmode itself
  if (!QueueInternalCmdBlocking(HCCMD_STANDARD, pDevice, FLIGHTMODE_CMD(fEnter), CMDOPT_POWER, APIID_NONE, FLIGHTMODE_TIMEOUT, 0, 0)) {
    RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: Failed to %s active flight mode\r\n"), fEnter ? TEXT("enter") : TEXT("leave")));
    (void)pDevice->BlockCommandPriority();
    return FALSE;
  }

  // With HC25 there won't be any SYSSTART-Urc so we have to generate it on our own
  CResponse*  pRsp;
  char        szSysstart[SYSSTART_MESSAGE_BUFFER];
  LPCSTR      szRemainder;
  UINT        cbRemainder;
  pRsp = new CResponse(DATA_PORT, GetRilDevice(NULL));
  if (!pRsp) {
    ForcePowerOff();
    return FALSE;
  }
  if (fEnter) strncpyz(szSysstart, "^SYSSTART AIRPLANE MODE\r\n", SYSSTART_MESSAGE_BUFFER);
  else  strncpyz(szSysstart, "^SYSSTART\r\n", SYSSTART_MESSAGE_BUFFER);
  if (!pRsp->AppendString(szSysstart, strlen(szSysstart), szRemainder, cbRemainder)) {
    delete pRsp;
    ForcePowerOff();
    return FALSE;
  }
  delete pRsp;

  return TRUE;
}

//////////////////////////////////////////////////////////////////////////////
//
// Switch on module.
//
// Params:
//  fActiveFlightMode: Flag indicating if we have to start in active flight
//                     mode.
//
// Return:
//  TRUE on successs, FALSE otherwise.
//
//////////////////////////////////////////////////////////////////////////////
BOOL CPowerManager::SwitchModuleOn(BOOL fActiveFlightMode) {
  EnterCriticalSection(&m_csPowerState);
  EnterCriticalSection(&m_csForcePower);

  if (RHA_IsRadioPwrOn()) {
    DWORD dwReg = 0;

    // The radio is on, although the RIL hadn't turned it on yet. Most probable cause: the device
    // had been resetted (warm boot), but the radio hasn't been powered down while warm boot.
    // This won't be a problem, if the RHA function RHA_RadioPwrOn() turns the radio power off
    // before restarting the radio as reconmended.
    RILRetailTraceZone(ZONE_INFO, (TEXT("RilDrv: Radio already on!\r\n")));

    // To make sure, that the radio has really been restarted, turn it off now (optional).
    (void)GetRegistryDWORD(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, TEXT("EnsureModuleOffOnSwitchOn"), &dwReg);
    if (dwReg == 1)
        RHA_RadioPwrOff();
  }

  // Call the customer function to switch on the radio
  BOOL fRet = RHA_RadioPwrOn();

  // Signal the radio is now on
  m_dwModemState = fActiveFlightMode ? MODEMSTATE_AIRPLANE : MODEMSTATE_POWERON;

  LeaveCriticalSection(&m_csForcePower);
  LeaveCriticalSection(&m_csPowerState);

  // now wait for the module to start
  return fRet;
}

//////////////////////////////////////////////////////////////////////////////
//
// Increase or decrease the systems unattended mode counter.
//
// Params:
//  fOnOff: Flag indicating if the unattended mode shall be entered (counter
//          increased) or left (counter decreased).
//
//////////////////////////////////////////////////////////////////////////////
void CPowerManager::SwitchIdleTimerReset(BOOL fOnOff) {
#ifdef RIL_ENABLE_UNATTENDED_HANDLING
#ifdef RIL_ENABLE_POWER_HANDLING
  SYNCBLOCK(m_csUnattended);
  if (m_hIdleResetLeaveEvent) {
    if (fOnOff) {
      if (!m_fIdleTimerReset) {
        // Start the thread which resets the system idle timer
        (void)ResetEvent(m_hIdleResetLeaveEvent);
        if (!CloseHandle(CreateThread(NULL, 0, IdleTimerResetThread, this, 0, NULL))) {
          RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: Failed to create idle timer reset thread!\r\n")));
          return;
        }
        m_fIdleTimerReset = TRUE;
        RILRetailTraceZone(ZONE_INFO, (TEXT("RilDrv: Started cyclic system idle timer reset\r\n")));
      }
    } else {
      if (m_fIdleTimerReset) {
        // Stop the thread which resets the system idle timer
        (void)SetEvent(m_hIdleResetLeaveEvent);
        RILRetailTraceZone(ZONE_INFO, (TEXT("RilDrv: Stopped cyclic system idle timer reset\r\n")));
        m_fIdleTimerReset = FALSE;
      }
    }
  }
#endif // RIL_ENABLE_POWER_HANDLING
#endif // RIL_ENABLE_UNATTENDED_HANDLING
}

//////////////////////////////////////////////////////////////////////////////
//
// Thread to reset the system idle timer cyclicly while we requested the
// unattended mode.
//
// Params:
//  lpParameter: "This" pointer to our class instance to get the reference
//               back in this static function.
//
// Return:
//  0 on success.
//
//////////////////////////////////////////////////////////////////////////////
DWORD WINAPI CPowerManager::IdleTimerResetThread(LPVOID lpParameter) {
CPowerManager* pHandle = (CPowerManager*)lpParameter;

  if (pHandle) {
    if (pHandle->m_hIdleResetLeaveEvent) {
      while (WaitForSingleObject(pHandle->m_hIdleResetLeaveEvent, IDLE_TIMER_RESET_CYCLE) == WAIT_TIMEOUT) {
        SystemIdleTimerReset();
      }
    }
  }
  return 0;
}

//////////////////////////////////////////////////////////////////////////////
//
// Increase or decrease the systems unattended mode counter.
//
// Params:
//  fOnOff: Flag indicating if the unattended mode shall be entered (counter
//          increased) or left (counter decreased).
//
//////////////////////////////////////////////////////////////////////////////
void CPowerManager::SwitchUnattendedMode(BOOL fOnOff) {
#ifdef RIL_ENABLE_UNATTENDED_HANDLING
#ifdef RIL_ENABLE_POWER_HANDLING
  SYNCBLOCK(m_csUnattended);
  if (fOnOff) {
    if (!m_fUnattendedMode) {
      if (!PowerPolicyNotify(PPN_UNATTENDEDMODE, TRUE)) {
        RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: Unattended-Mode add-request failed!\r\n")));
        return;
      }
      m_fUnattendedMode = TRUE;
      RILRetailTraceZone(ZONE_INFO, (TEXT("RilDrv: Unattended-Mode request added\r\n")));
    }
  } else {
    if (m_fUnattendedMode) {
      if (!PowerPolicyNotify(PPN_UNATTENDEDMODE, FALSE)) {
        RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: Unattended-Mode remove-request failed!\r\n")));
        return;
      }
      m_fUnattendedMode = FALSE;
      RILRetailTraceZone(ZONE_INFO, (TEXT("RilDrv: Unattended-Mode request removed\r\n")));
    }
  }
#endif // RIL_ENABLE_POWER_HANDLING
#endif // RIL_ENABLE_UNATTENDED_HANDLING
}

//////////////////////////////////////////////////////////////////////////////
//
// Internal parsing callback for SwitchUscState()
//
//////////////////////////////////////////////////////////////////////////////
HRESULT CPowerManager::ParseGetRegStatusAll(LPCSTR szRsp, void*& pBlob, UINT& cbBlob, LPVOID pParam) {
CPowerManager*  pDevice = (CPowerManager*)pParam;
UINT            nValue;
UINT            nRSSI, nBER, nAcT = 0xFF;
HRESULT         hr = S_OK;

  pBlob = NULL;
  cbBlob = 0;

  // Parse "<prefix>+CGREG: <mode>,<status><postfix>"
  if (!ParseRspPrefix(szRsp, szRsp)                    ||
      !MatchStringBeginning(szRsp, "+CGREG: ", szRsp)  ||
      !ParseUInt(szRsp, TRUE, nValue, szRsp)           ||
      !MatchStringBeginning(szRsp, ",", szRsp)         ||
      !ParseUInt(szRsp, TRUE, nValue, szRsp)           ||
      !ParseRspPostfix(szRsp, szRsp)) {
    // The +CGREG: part may be missing. In this case, continue and assume '+CGREG: 0'
    LPCSTR szDummy;

    if (!MatchStringAnywhere(szRsp, "+CREG: ", szDummy)) {
      hr = E_FAIL;
      goto Error;
    }
    nValue = 0;     // assume +CGREG: 0
  }

  if (WRONG_CGREG_IN_MULTIMODE && pDevice->GetRilDevice(NULL)->GetMultiModeSetting() == MULTIMODE_CONFIG_MULTIMODE) {
    // Bug in PXS8 (multimode): the +CGREG status is not correct, try to
    // substitute with the current psinfo setting.
    if (s_dwPSInfoStatus > 0 && s_dwPSInfoStatus < 11)
        nValue = ((s_dwPSInfoStatus & 1) == 0 ? 1 : 0);
  }

  if (NUM_REGSTATS > nValue) {
    g_dwGPRSRegStatus = g_rgdwRegStats[nValue];

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

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

  // There may be additional information, but we ignore them.
  if (MatchStringBeginning(szRsp, ",\"", szRsp))
  {
    (void)ParseHexUInt(szRsp, TRUE, pDevice->m_nLAC, szRsp);
    (void)MatchStringBeginning(szRsp, "\",\"", szRsp);
    (void)ParseHexUInt(szRsp, TRUE, pDevice->m_nCI, szRsp);
    (void)MatchStringBeginning(szRsp, "\"", szRsp);
    // There may be an additional parameter <AcT>
    if (MatchStringBeginning(szRsp, ",", szRsp)) {
      (void)ParseUInt(szRsp, TRUE, nAcT, szRsp);
    }
  }

  if (!ParseRspPostfix(szRsp, szRsp))
  {
      hr = E_FAIL;
      goto Error;
  }

  // Bug in PXS8: AT+CREG? might return "0" while the radio is actually
  // registered. If AT^SIND=psinfo shows GSM/UMTS as technology the RIL
  // assumes the radio is registered.
  if (CREG0_MIGHT_BE_WRONG && nValue == 0) {
    if (s_dwPSInfoStatus > 0 && s_dwPSInfoStatus < 11)
        nValue = 1;
  }

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

    if(g_bFakeRegStatusDeniedToHome && (g_rgdwRegStats[nValue] == 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 (!ParseRspPrefix(szRsp, szRsp)) {
    hr = E_FAIL;
    goto Error;
  }
  if (MatchStringBeginning(szRsp, "+CSQ: ", szRsp)) {
    // Parse "<prefix>+CSQ: <rssi>,<ber><postfix>"
    if (!ParseUIntAndVerifyAbove(szRsp, TRUE, 100, nRSSI, szRsp) ||
        !MatchStringBeginning(szRsp, ",", szRsp)                 ||
        !ParseUInt(szRsp, TRUE, nBER, szRsp)                     ||
        !ParseRspPostfix(szRsp, szRsp)) {
        hr = E_FAIL;
        goto Error;
    }
  }
  else if (MatchStringBeginning(szRsp, "^SIND: rssi,", szRsp)) {
    UINT nDummy;
    UINT nRSSISIND;

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

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

  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.

Error:
  return hr;
}

HRESULT CPowerManager::ParseGetRegStatusAllError(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 = ParseGetRegStatusAll(szRsp, pBlobTmp, cbBlobTmp, pParam);
    if (SUCCEEDED(hr)) {
        if (pBlob != NULL)
            (void)FreeBlob(pBlob);
        pBlob = pBlobTmp;
        cbBlob = cbBlobTmp;
        dwCode = RIL_RESULT_OK;
    }
    return hr;
}

//////////////////////////////////////////////////////////////////////////////
//
// Internal parsing callback for SwitchUscState()
//
//////////////////////////////////////////////////////////////////////////////
HRESULT CPowerManager::ParseGetRegStatusCdma(LPCSTR szRsp, void*& pBlob, UINT& cbBlob, LPVOID /*pParam*/) {
UINT            nValue;
UINT            nRSSI, nBER;
HRESULT         hr = S_OK;

  pBlob = NULL;
  cbBlob = 0;

  // Parse "<prefix>^SREG: <mode>,<status><postfix>"
  if (!ParseRspPrefix(szRsp, szRsp)                    ||
      !MatchStringBeginning(szRsp, "^SREG: ", szRsp)  ||
      !ParseUInt(szRsp, TRUE, nValue, szRsp)           ||
      !MatchStringBeginning(szRsp, ",", szRsp)         ||
      !ParseUInt(szRsp, TRUE, nValue, szRsp)) {
      hr = E_FAIL;
      goto Error;
  }
  if (NEW_SREG_PARAM) {
    UINT nValueEVDO;

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

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

    if(g_bFakeRegStatusDeniedToHome && (g_rgdwRegStats[nValue] == 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 (!ParseRspPrefix(szRsp, szRsp)) {
    hr = E_FAIL;
    goto Error;
  }
  if (MatchStringBeginning(szRsp, "+CSQ: ", szRsp)) {
    // Parse "<prefix>+CSQ: <rssi>,<ber><postfix>"
    if (!ParseUIntAndVerifyAbove(szRsp, TRUE, 100, nRSSI, szRsp) ||
        !MatchStringBeginning(szRsp, ",", szRsp)                 ||
        !ParseUInt(szRsp, TRUE, nBER, szRsp)                     ||
        !ParseRspPostfix(szRsp, szRsp)) {
        hr = E_FAIL;
        goto Error;
    }
  }
  else if (MatchStringBeginning(szRsp, "^SIND: rssi,", szRsp)) {
    UINT nDummy;
    UINT nRSSISIND;

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

  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.

Error:
  return hr;
}

//////////////////////////////////////////////////////////////////////////////
//
// Internal parsing callback for "AT+CSMS?;+CNMI?" request SwitchUscState()
//
//////////////////////////////////////////////////////////////////////////////
HRESULT CPowerManager::ParseGetSMSPhase(LPCSTR szRsp, void*& pBlob, UINT& cbBlob, LPVOID pParam) {
UINT            nValue;
UINT            nPhase = 0;
UINT            nMode = 0;
CPowerManager*  pDevice = (CPowerManager*)pParam;
HRESULT         hr = S_OK;

  pBlob = NULL;
  cbBlob = 0;

  // +CSMS: won't appear in CDMA mode.
  if (strstr(szRsp, "+CSMS:") != NULL) {
    // Parse "<prefix>+CSMS: <phase>,<p1>,<p2>,<p3><postfix>"
    if (!ParseRspPrefix(szRsp, szRsp)                   ||
      !MatchStringBeginning(szRsp, "+CSMS: ", szRsp)  ||
      !ParseUInt(szRsp, TRUE, nPhase, szRsp)          ||
      !MatchStringBeginning(szRsp, ",", szRsp)        ||
      !ParseUInt(szRsp, TRUE, nValue, szRsp)          ||
      !MatchStringBeginning(szRsp, ",", szRsp)        ||
      !ParseUInt(szRsp, TRUE, nValue, szRsp)          ||
      !MatchStringBeginning(szRsp, ",", szRsp)        ||
      !ParseUInt(szRsp, TRUE, nValue, szRsp)          ||
      !ParseRspPostfix(szRsp, szRsp)) {
      hr = E_FAIL;
      goto Error;
    }
  }
  // Parse "<prefix>+CNMI: <mode>,<mt>,<bm>,<ds>,<bfr><postfix>"
  if (!ParseRspPrefix(szRsp, szRsp)                   ||
      !MatchStringBeginning(szRsp, "+CNMI: ", szRsp)  ||
      !ParseUInt(szRsp, TRUE, nMode, szRsp)           ||
      !MatchStringBeginning(szRsp, ",", szRsp)        ||
      !ParseUInt(szRsp, TRUE, nValue, szRsp)          ||
      !MatchStringBeginning(szRsp, ",", szRsp)        ||
      !ParseUInt(szRsp, TRUE, nValue, szRsp)          ||
      !MatchStringBeginning(szRsp, ",", szRsp)        ||
      !ParseUInt(szRsp, TRUE, nValue, szRsp)) {
    hr = E_FAIL;
    goto Error;
  }
  // Bug in PXS8 2.851: even though the last parameter isn't optional, the radio
  // doesn't print it in CDMA mode.
  if (MatchStringBeginning(szRsp, ",", szRsp))
    (void)ParseUInt(szRsp, TRUE, nValue, szRsp);
  if (!ParseRspPostfix(szRsp, szRsp)) {
    hr = E_FAIL;
    goto Error;
  }

  pDevice->m_nSMSPhase = nPhase;
  pDevice->m_nCNMIMode = nMode;

Error:
  return hr;
}

//////////////////////////////////////////////////////////////////////////////
//
// Generates the AT+CNMI command needed for setting the correct SMS notifications
// during suspend.
//
// Params:
//  none
//
// Return:
//  string containig the AT command (without the "AT"), may be empty
//
//////////////////////////////////////////////////////////////////////////////
const char* CPowerManager::GetSMSSettingOnSuspend() const
{
#ifdef RIL_STORE_SMS_ON_SIM_ON_SUSPEND
    BOOL bChangeToStore = FALSE;

    if (!g_bDefaultCNMIstoreOnSIM)
        bChangeToStore = TRUE;

    if (bChangeToStore && m_pRilHandle->GetCurrentTechnology() != TEC_MODE_CDMA) {
        if (USE_STANDARD_CNMI_SETTINGS)
            return SMS_CNMI_STORE_ON_SIM_3GPP";";
        else
            return SMS_CNMI_STORE_ON_SIM";";
    }
    else
        return "";
#else
    return "";
#endif
}

//////////////////////////////////////////////////////////////////////////////
//
// Switch the module to the given URC state.
//
// Params:
//  pCmd: Pointer to corresponding power command.
//
// Return:
//  TRUE on successs, FALSE otherwise.
//
//////////////////////////////////////////////////////////////////////////////
BOOL CPowerManager::SwitchUrcState(const CPowerCmd* pCmd) {
CRilHandle*  pDevice;
DWORD        dwNewUrcState;
char szCmd[MAX_ATCMD_LEN];

  if (!IS_URCSTATE(pCmd->GetCmd())) {
    return FALSE;
  }

  pDevice = GetRilDevice(NULL);
  if (pDevice == NULL) {
    return FALSE;
  }

  // An URC switch before being initialized makes no sense.
  if (!m_fUrcInitialized && !m_fPreUrcInitialized && !pCmd->IsUrcInit()) {
    m_dwInitUrcState = pCmd->GetCmd();
    // Even though there is no need to switch any URCs, send a no-operation
    // command just to make sure, that no commands are currently going on.
    RILRetailTraceZone(ZONE_INFO, (TEXT("RilDrv: No operation on URC state switch\r\n")));
    (void)pDevice->UnblockCommandHandling();
    (void)QueueInternalCmdBlocking(HCCMD_STANDARD, pDevice, NULL, CMDOPT_NOOP|CMDOPT_URC, APIID_DEVSPECIFIC, 0, 0, 0, NULL);
    return FALSE;
  }

  // Check if we have to overwrite the given int URC state from a previous power state call
  dwNewUrcState = pCmd->GetCmd();
  if (pCmd->IsUrcInit() && IS_URCSTATE(m_dwInitUrcState)) {
    dwNewUrcState = m_dwInitUrcState;
    m_dwInitUrcState = INVALID_MODEM_STATE;
    RILRetailTraceZone(ZONE_INFO, (TEXT("RilDrv: Overwritten given init URC state from former power command\r\n")));
  }

  if (m_fUrcInitialized) {
    // We don't support direct URCCONFIG switches!
    if (IS_URCCONFIG(m_dwModemState) && IS_URCCONFIG(dwNewUrcState) && (m_dwModemState != dwNewUrcState)) {
      // So we must enable the URCs before switching to the new URCCONFIG...
      CPowerCmd PwrCmd(MODEMSTATE_POWERON, pCmd->GetHandle(), pCmd->GetNewPowerState(), pCmd->GetOldPowerState(), pCmd->IsEquipmentStateCmd(), pCmd->IsUrcInit());
      if (!SwitchUrcState(&PwrCmd)) {
        return FALSE;
      }
    }
    // Now check if we are already in the requested URC state
    if (m_dwModemState == dwNewUrcState) {
      // Nothing more to do
      return TRUE;
    }
  }

  // Unblock possibly blocked command handling
  (void)pDevice->UnblockCommandHandling();

  // Now switch to the requested URC state
  if (dwNewUrcState == MODEMSTATE_POWERON) {
#ifdef RIL_USE_CSQ_NOTIFICATIONS
    CNotificationData *pnd = NULL;
#endif
    BOOL fCheckMissedSMS = TRUE;
    BOOL bSkipAdditionalInit = FALSE;
    DWORD dwOldGPRSRegState = g_dwGPRSRegStatus;

    RILRetailTraceZone(ZONE_INFO, (TEXT("RilDrv: SwitchUrcState(MODEMSTATE_POWERON)\r\n")));

    // Enable URCs
#ifdef SUPPORTS_EHSX_R1
    if (NO_SIND_INDICATIONS) {
      if (!QueueInternalCmd(HCCMD_STANDARD, pDevice, "AT+CREG=2;+CGREG=1;+CUSD=1;+XMER=1\r", CMDOPT_URC, APIID_ENABLEDISABLEURCS, 0, ENABLEURC_RETRIES, ENABLEURC_RETRIES_DELAY)) {
        return FALSE;
      }
    }
    else {
#endif
      if (m_pRilHandle->GetCurrentTechnology() == TEC_MODE_CDMA) {
        const char *cszCmd;

#ifdef RIL_USE_CSQPOLLING
        cszCmd = "AT+CREG=2;^SREG=1;^SIND=call,1;^SIND=smsfull,1\r";
#else
        if (AVOID_SIND_RSSI_IN_CDMA)
          cszCmd = "AT+CREG=2;^SREG=1;^SIND=call,1;^SIND=smsfull,1\r";
        else if (NO_SIND_SIGNAL_AUDIO && SIND_CALL_MIXES_UP_RESPONSE)
          cszCmd = "AT+CREG=2;^SREG=1;^SIND=rssi,1;^SIND=smsfull,1\r";
        else if (NO_SIND_SIGNAL_AUDIO && !SIND_CALL_MIXES_UP_RESPONSE)
          cszCmd = "AT+CREG=2;^SREG=1;^SIND=call,1;^SIND=smsfull,1;^SIND=rssi,1\r";
        else if (NO_SIND_SIGNAL_IN_CDMA)
          cszCmd = "AT+CREG=2;^SREG=1;^SIND=call,1;^SIND=smsfull,1;^SIND=rssi,1\r";
        else
          cszCmd = "AT+CREG=2;^SREG=1;^SIND=call,1;^SIND=smsfull,1;^SIND=rssi,1;^SIND=signal,1\r";
#endif
        if (!QueueInternalCmd(HCCMD_STANDARD, pDevice, cszCmd, CMDOPT_URC, APIID_ENABLEDISABLEURCS, 0, ENABLEURC_RETRIES, ENABLEURC_RETRIES_DELAY)) {
          return FALSE;
        }
        if (NO_SIND_SIGNAL_AUDIO && SIND_CALL_MIXES_UP_RESPONSE)
          (void)QueueInternalCmd(HCCMD_STANDARD, pDevice, "AT^SIND=call,1\r", CMDOPT_URC, APIID_ENABLEDISABLEURCS, 0, ENABLEURC_RETRIES, ENABLEURC_RETRIES_DELAY);
      }
      else {
        const char *cszCmd;


#ifdef RIL_USE_CSQPOLLING
		if(!SUPPORTS_ONLY_DATAMODE){
        	cszCmd = "AT+CREG=2;+CGREG=1;+CUSD=1;^SIND=call,1;^SIND=smsfull,1\r";
		}else{
			cszCmd = "AT+CREG=2;+CGREG=1;+CUSD=1;^SIND=smsfull,1\r";
		}
#else
        if (NO_SIND_SIGNAL_AUDIO && SIND_CALL_MIXES_UP_RESPONSE)
          cszCmd = "AT+CREG=2;+CGREG=1;+CUSD=1;^SIND=rssi,1;^SIND=smsfull,1\r";
        else if (NO_SIND_SIGNAL_AUDIO && !SIND_CALL_MIXES_UP_RESPONSE){
		  if(!SUPPORTS_ONLY_DATAMODE){
          	cszCmd = "AT+CREG=2;+CGREG=1;+CUSD=1;^SIND=call,1;^SIND=smsfull,1;^SIND=rssi,1\r";
		  }else{
			cszCmd = "AT+CREG=2;+CGREG=1;+CUSD=1;^SIND=smsfull,1;^SIND=rssi,1\r";
		  }
        }
        else
          cszCmd = "AT+CREG=2;+CGREG=1;+CUSD=1;^SIND=call,1;^SIND=smsfull,1;^SIND=rssi,1;^SIND=signal,1\r";
#endif

        if (!QueueInternalCmd(HCCMD_STANDARD, pDevice, cszCmd, CMDOPT_URC, APIID_ENABLEDISABLEURCS, 0, ENABLEURC_RETRIES, ENABLEURC_RETRIES_DELAY)) {
          return FALSE;
        }
        if (NO_SIND_SIGNAL_AUDIO && SIND_CALL_MIXES_UP_RESPONSE && !SUPPORTS_ONLY_DATAMODE)
          (void)QueueInternalCmd(HCCMD_STANDARD, pDevice, "AT^SIND=call,1\r", CMDOPT_URC, APIID_ENABLEDISABLEURCS, 0, ENABLEURC_RETRIES, ENABLEURC_RETRIES_DELAY);
      }
#ifdef SUPPORTS_EHSX_R1
    }
#endif
    // Fetch the registration status (+CREG and +CGREG) and signal strenght (+CSQ)
    m_nLAC = 0;
    m_nCI = 0;
    // Skip this step, if this module supports CDMA only.
    if (!CDMA_ONLY_RADIO) {
        BOOL fCmdSuccess = FALSE;

        s_dwPSInfoStatus = 0;
        // The PXS8 might return a wrong value for AT+CREG?. The RIL will use the
        // information from AT^SIND=psinfo to get the correct value.
        // Other bug in PXS8: the value from AT+CGREG? might be wrong as well.
        // In this case AT^SIND=psinfo helps as well.
        if ((CREG0_MIGHT_BE_WRONG && !NO_SIND_PSINFO_IN_CDMA) || (WRONG_CGREG_IN_MULTIMODE && pDevice->GetMultiModeSetting() == MULTIMODE_CONFIG_MULTIMODE))
          (void)QueueInternalCmdBlocking(HCCMD_STANDARD, pDevice, "AT^SIND=psinfo,2\r", CMDOPT_URC, APIID_GETCURRENTSYSTEMTYPE, 0, 0, 0, ParsePsInfoForCReg, NULL, (LPVOID)&s_dwPSInfoStatus);
        if (USE_CSQ_READ && !SUBSTITUTE_CSQ_WITH_SIND && pDevice->GetCurrentTechnology() == TEC_MODE_CDMA && NO_CGREG_IN_CDMA)
          fCmdSuccess = QueueInternalCmdBlocking(HCCMD_STANDARD, pDevice, "AT+CREG?;+CSQ?\r", CMDOPT_URC, APIID_ENABLEDISABLEURCS, 0, SUBSTITUTE_CSQ_WITH_SIND ? 0 : ENABLEURC_RETRIES, ENABLEURC_RETRIES_DELAY, ParseGetRegStatusAll, NULL, this);
        else if (USE_CSQ_READ && !SUBSTITUTE_CSQ_WITH_SIND && pDevice->GetCurrentTechnology() == TEC_MODE_CDMA)
          fCmdSuccess = QueueInternalCmdBlocking(HCCMD_STANDARD, pDevice, "AT+CGREG?;+CREG?;+CSQ?\r", CMDOPT_URC, APIID_ENABLEDISABLEURCS, 0, SUBSTITUTE_CSQ_WITH_SIND ? 0 : ENABLEURC_RETRIES, ENABLEURC_RETRIES_DELAY, ParseGetRegStatusAll, NULL, this);
        else if (!SUBSTITUTE_CSQ_WITH_SIND || pDevice->GetMultiModeSetting() != MULTIMODE_CONFIG_CDMA)
          fCmdSuccess = QueueInternalCmdBlocking(HCCMD_STANDARD, pDevice, "AT+CGREG?;+CREG?;+CSQ;^SMONI\r", CMDOPT_URC, APIID_ENABLEDISABLEURCS, 0, SUBSTITUTE_CSQ_WITH_SIND ? 0 : ENABLEURC_RETRIES, ENABLEURC_RETRIES_DELAY, ParseGetRegStatusAll, ParseGetRegStatusAllError, this);
        if (!fCmdSuccess)
          fCmdSuccess = QueueInternalCmdBlocking(HCCMD_STANDARD, pDevice, "AT+CGREG?;+CREG?;^SIND=rssi,2;^SMONI\r", CMDOPT_URC, APIID_ENABLEDISABLEURCS, 0, SUBSTITUTE_CSQ_WITH_SIND ? 0 : ENABLEURC_RETRIES, ENABLEURC_RETRIES_DELAY, ParseGetRegStatusAll, ParseGetRegStatusAllError, this);
        if (!fCmdSuccess) {
          // Most probably reason, if this command fails: SIM is not inserted or not ready. In this
          // case the following reduced command will succeed.
          m_dwGPRSRegStatusCache = RIL_REGSTAT_UNREGISTERED;
          // Unless the module is registered to CDMA this means the RIL can skip the additional initialization.
          if (pDevice->GetCurrentTechnology() != TEC_MODE_CDMA)
            bSkipAdditionalInit = TRUE;
          if (SUBSTITUTE_CSQ_WITH_SIND && !fCmdSuccess)
            fCmdSuccess = QueueInternalCmdBlocking(HCCMD_STANDARD, pDevice, "AT+CREG?;^SIND=rssi,2;^SMONI\r", CMDOPT_URC, APIID_ENABLEDISABLEURCS, 0, 0, 0, ParseGetRegStatusAll, ParseGetRegStatusAllError, this);
          if ((!USE_CSQ_READ || pDevice->GetCurrentTechnology() != TEC_MODE_CDMA) && !fCmdSuccess)
            fCmdSuccess = QueueInternalCmdBlocking(HCCMD_STANDARD, pDevice, "AT+CREG?;+CSQ;^SMONI\r", CMDOPT_URC, APIID_ENABLEDISABLEURCS, 0, 0, 0, ParseGetRegStatusAll, ParseGetRegStatusAllError, this);
          if ((!USE_CSQ_READ || pDevice->GetCurrentTechnology() != TEC_MODE_CDMA) && !fCmdSuccess)
            fCmdSuccess = QueueInternalCmdBlocking(HCCMD_STANDARD, pDevice, "AT+CREG?;+CSQ\r", CMDOPT_URC, APIID_ENABLEDISABLEURCS, 0, 0, 0, ParseGetRegStatusAll, ParseGetRegStatusAllError, this);
          if (!fCmdSuccess) {
            // When this command fails as well, there must be another problem than
            // the SIM. In this case the initialitiziation won't succeed.
            return FALSE;
          }
        }
        if (g_dwRegStatus == RIL_REGSTAT_HOME || g_dwRegStatus == RIL_REGSTAT_ROAMING)
            m_pRilHandle->NotifyNewTechnologyMode(TEC_MODE_LTE);
    }

    // If not registered to GSM, but radio has CDMA capabilities, try CDMA (if module is capable of CDMA).
    if (CDMA_ONLY_RADIO || (pDevice->GetMultiModeSetting() != MULTIMODE_CONFIG_LTE && g_dwRegStatus != RIL_REGSTAT_HOME && g_dwRegStatus != RIL_REGSTAT_ROAMING)) {
        BOOL fCmdSuccess = FALSE;

        if (USE_CSQ_READ && !SUBSTITUTE_CSQ_WITH_SIND && pDevice->GetCurrentTechnology() == TEC_MODE_CDMA)
          fCmdSuccess = QueueInternalCmdBlocking(HCCMD_STANDARD, pDevice, "AT^SREG?;+CSQ?\r", CMDOPT_URC, APIID_ENABLEDISABLEURCS, 0, 0, 0, ParseGetRegStatusCdma, NULL, this);
        else if (!SUBSTITUTE_CSQ_WITH_SIND || pDevice->GetMultiModeSetting() != MULTIMODE_CONFIG_CDMA)
          fCmdSuccess = QueueInternalCmdBlocking(HCCMD_STANDARD, pDevice, "AT^SREG?;+CSQ\r", CMDOPT_URC, APIID_ENABLEDISABLEURCS, 0, 0, 0, ParseGetRegStatusCdma, NULL, this);
        if (!fCmdSuccess)
          fCmdSuccess = QueueInternalCmdBlocking(HCCMD_STANDARD, pDevice, "AT^SREG?;^SIND=rssi,2\r", CMDOPT_URC, APIID_ENABLEDISABLEURCS, 0, 0, 0, ParseGetRegStatusCdma, NULL, this);
        if (!fCmdSuccess) {
          // When this command fails as well, there must be some serious issues.
          return FALSE;
        }
        if (g_dwRegStatus == RIL_REGSTAT_HOME || g_dwRegStatus == RIL_REGSTAT_ROAMING)
            m_pRilHandle->NotifyNewTechnologyMode(TEC_MODE_CDMA);
    }

    // Reset radio technologiy cache, if radio lost registration.
    if (g_dwRegStatus != RIL_REGSTAT_HOME && g_dwRegStatus != RIL_REGSTAT_ROAMING)
        m_pRilHandle->ResetNetworkTechnologyState();

    // We generate a RIL_NOTIFY_REGSTATUSCHANGED notification, when the AT+CREG status changed.
    // In case we are roaming, we send this notification in any case, to force the OS to check,
    // if the roaming network changed.
    if ((m_dwRegStatusCache != g_dwRegStatus) || (m_dwRegStatusCache == RIL_REGSTAT_ROAMING) || pCmd->IsUrcInit()) {
      // Notify the OS (check for 'No Roaming' network, if necessary).
      if (g_dwRegStatus == RIL_REGSTAT_ROAMING && pDevice->IsNoRoamingIndicator())
        g_dwRegStatus = RIL_REGSTAT_HOME;
      if (g_dwRegStatus == RIL_REGSTAT_ROAMING && pDevice->NeedsCheckForNoRoamingNetwork() && !pDevice->MustFakeUnregisterdState())
        CloseHandle(CreateThread(NULL, 0, CheckRoamingNetworkThreadProc, (LPVOID)pDevice, 0, 0));
      else {
        DWORD dwRegStatusNotify;

        dwRegStatusNotify = g_dwRegStatus;
        if (pDevice->MustFakeUnregisterdState() && (dwRegStatusNotify == RIL_REGSTAT_ATTEMPTING|| dwRegStatusNotify == RIL_REGSTAT_HOME || dwRegStatusNotify == RIL_REGSTAT_ROAMING))
            dwRegStatusNotify = RIL_REGSTAT_UNREGISTERED;
        pDevice->GenerateRegStatusNotification(dwRegStatusNotify);
      }
    }
    if ((m_dwGPRSRegStatusCache != g_dwGPRSRegStatus) || pCmd->IsUrcInit()) {
#ifdef RILDRV_CE6
      BOOL bAttached = (g_dwGPRSRegStatus == RIL_REGSTAT_HOME || g_dwGPRSRegStatus == RIL_REGSTAT_ROAMING ? TRUE : FALSE);

      (void)pDevice->BroadcastRealBlobNotification(RIL_NOTIFY_GPRSATTACHED, (LPVOID)&bAttached, sizeof(BOOL));
#endif
      (void)pDevice->BroadcastDWORDBlobNotification(RIL_NOTIFY_GPRSREGSTATUSCHANGED, g_dwGPRSRegStatus);
    }
    if (g_dwRegStatus == RIL_REGSTAT_HOME) {
      pDevice->GetForceHomeNet()->NotifyRegistered();
    }
    Sleep(200);

#ifndef RIL_NO_CREG_LOCATION_UPDATES
    if (m_nLAC && m_nCI) {
      CNotificationData *pnd2 = NULL;
      RILLOCATIONINFO sLI;

      sLI.cbSize = sizeof(RILLOCATIONINFO);
      sLI.dwLocationAreaCode = m_nLAC;
      sLI.dwCellID = m_nCI;

      pnd2 = new CNotificationData;
      if (pnd2) {
        if (!pnd2->InitFromRealBlob(RIL_NOTIFY_LOCATIONUPDATE, &sLI, sizeof(RILLOCATIONINFO))) {
          delete pnd2;
          pnd2 = NULL;
        }
      }
      if (pnd2 != NULL)
        pDevice->BroadcastNotification(pnd2);
    }
#endif
    if (m_pRilHandle->GetEons()->GetEONSState() == EONS_ENABLED && !CHECK_EONS_AFTER_CELL_CHANGE)
    {
        (void)QueueInternalCmd(HCCMD_STANDARD, pDevice, "AT^SIND=eons,1\r", CMDOPT_NONE, APIID_UNLOCKPHONE, 0, 0, 0, NULL);
    }
#if defined(RIL_NOTIFY_EONS)
    if ((pDevice->GetEons()->GetEONSState() == EONS_EMULATED || pDevice->GetEons()->GetEONSState() == EONS_ENABLED) &&  (g_dwRegStatus == RIL_REGSTAT_HOME || g_dwRegStatus == RIL_REGSTAT_ROAMING))
    {
        // We might have missed an EONS URC, so we send an EONS notification to
        // force the UI to re-check the provider name.
        (void)pDevice->BroadcastRealBlobNotification(RIL_NOTIFY_EONS, NULL, 0);
    }
#endif
#if defined(RIL_NOTIFY_NITZ)
    if (m_pRilHandle->IsNITZactive())
    {
        // Reactivate NITZ URC and also report the current time zone in case it changed
        // during the time of the suspend.
        if (!NO_SIND_NITZ_IN_CDMA || pDevice->GetCurrentTechnology() != TEC_MODE_CDMA)
          (void)QueueInternalCmd(HCCMD_STANDARD, pDevice, "AT^SIND=nitz,1\r", CMDOPT_NONE, APIID_UNLOCKPHONE, 0, 0, 0, ParseInitialNITZState, NULL, (LPVOID)pDevice);
    }
#endif
#ifdef RIL_USE_CSQ_NOTIFICATIONS
    RILSIGNALQUALITY rsq;
    FillRSQStruct(&rsq);
    pnd = new CNotificationData;
    if (pnd) {
      if (!pnd->InitFromRealBlob(RIL_NOTIFY_SIGNALQUALITY, &rsq, sizeof(RILSIGNALQUALITY))) {
        delete pnd;
        pnd = NULL;
      }
    }
    if (pnd != NULL)
      pDevice->BroadcastNotification(pnd);

    // We already got the +CIEV URC? Resend the information.
    if (g_bCINDIsActive) {
      CloseHandle(CreateThread(NULL, 0, ReSendSignalThreadProc, pDevice, 0, 0));
    }
#endif

    if (m_fPreUrcInitialized && !USE_POLLING_FOR_SIM_READY) {
      // During the preliminary phase, there is the simstatus URC in use, so
      // this one must be restored as well.
      if (QueueInternalCmdBlocking(HCCMD_STANDARD, pDevice, "AT^SIND=simstatus,1\r", CMDOPT_NONE, APIID_UNLOCKPHONE, 0, 0, 0, ParseSIMStatus)) {
        if (g_iCurrentSIMStatus == 5)   // SIM ready? Give signal.
          pDevice->SignalInternalSIMReady();
      }
    }
    if (!bSkipAdditionalInit) {
      if (m_pRilHandle->GetCurrentTechnology() == TEC_MODE_CDMA) {
        // This part of the re-initialization is only relevant, if the SIM is ready.
        m_nSMSPhase = 1;     // Default: SMS Phase 2+
        m_nCNMIMode = 0;    // Default: CNMI not active
        if (!QueueInternalCmdBlocking(HCCMD_STANDARD, pDevice, "AT+CNMI?\r", CMDOPT_URC, APIID_ENABLEDISABLEURCS, 0, ENABLEURC_RETRIES, ENABLEURC_RETRIES_DELAY, ParseGetSMSPhase, NULL, this)) {
          return FALSE;
        }
      }
      else {
        // This part of the re-initialization is only relevant, if the SIM is ready.
        m_nSMSPhase = 1;     // Default: SMS Phase 2+
        m_nCNMIMode = 0;    // Default: CNMI not active
        if (!QueueInternalCmdBlocking(HCCMD_STANDARD, pDevice, "AT+CSMS?;+CNMI?\r", CMDOPT_URC, APIID_ENABLEDISABLEURCS, 0, ENABLEURC_RETRIES, ENABLEURC_RETRIES_DELAY, ParseGetSMSPhase, NULL, this)) {
          return FALSE;
        }
      }

      // If CNMI is already active, we don't need to check for missed SMS, since we have received the URC. Otherwise
      // we might accidently notify the OS twice about the same SMS.
      // Only during the init phase we have to check alway, if there are any missed SMS, which might came in during
      // the initialization of the radio.
      if (!pCmd->IsUrcInit() && m_nCNMIMode > 0) {
        fCheckMissedSMS = FALSE;
      }
      if (m_pRilHandle->GetCurrentTechnology() == TEC_MODE_CDMA) {
        (void)QueueInternalCmd(HCCMD_URCPORT_ONLY, pDevice, GetCdmaCnmiSetting(), CMDOPT_URC, APIID_ENABLEDISABLEURCS, 0, ENABLEURC_RETRIES, ENABLEURC_RETRIES_DELAY);
      }
      else {
        if (m_nSMSPhase == 0 || g_bDefaultCNMIstoreOnSIM) {
          (void)QueueInternalCmd(HCCMD_URCPORT_ONLY, pDevice, USE_STANDARD_CNMI_SETTINGS ? "AT"SMS_CNMI_STORE_ON_SIM_3GPP"\r" : "AT"SMS_CNMI_STORE_ON_SIM"\r", CMDOPT_URC, APIID_ENABLEDISABLEURCS, 0, ENABLEURC_RETRIES, ENABLEURC_RETRIES_DELAY);
        } else {
          (void)QueueInternalCmd(HCCMD_URCPORT_ONLY, pDevice, "AT"SMS_CNMI_MANUAL_ACK"\r", CMDOPT_URC, APIID_ENABLEDISABLEURCS, 0, ENABLEURC_RETRIES, ENABLEURC_RETRIES_DELAY);
        }
      }

#ifdef SUPPORTS_EHSX_R1
      if (NO_SIND_INDICATIONS)
        (void)QueueInternalCmd(HCCMD_STANDARD, pDevice, "AT+XREG=1;+XREG?\r", CMDOPT_URC, APIID_GETCURRENTSYSTEMTYPE, 0, 0, 0, ParseInitialXREGInfo, NULL, (LPVOID)pDevice);
      else
#endif
        (void)QueueInternalCmd(HCCMD_STANDARD, pDevice, "AT^SIND=psinfo,1\r", CMDOPT_URC, APIID_GETCURRENTSYSTEMTYPE, 0, 0, 0, ParseInitialPSInfo, ParseInitialPSInfoError, (LPVOID)pDevice);

      CloseHandle(CreateThread(NULL, 0, ReCheckCBStatusThreadProc, (LPVOID)pDevice, 0, 0));

      if (fCheckMissedSMS) {
        (void)CheckForMissedSMS(pDevice, FALSE);
      }

      CloseHandle(CreateThread(NULL, 0, ReCheckCallStatusThreadProc, (LPVOID)pDevice, 0, 0));

      // If automatich GPRS reattach is configured and GPRS status changed from registerd to unregistered,
      // start thread for perform reattach.
      if (g_dwEnableGPRSReAttach == 1 && g_dwEnableGPRSAttach == 1 && m_pRilHandle->GetCurrentTechnology() != TEC_MODE_CDMA &&
           (g_dwGPRSRegStatus != RIL_REGSTAT_HOME && g_dwGPRSRegStatus != RIL_REGSTAT_ROAMING) && (dwOldGPRSRegState == RIL_REGSTAT_HOME || dwOldGPRSRegState == RIL_REGSTAT_ROAMING)) {
              // Start Thread, which performs a re-attach, if possible.
              CloseHandle(CreateThread(NULL, 0, GPRSReattachThreadProc, (LPVOID)m_pRilHandle, 0, 0));
      }
    }

  } else {
    BOOL fMustHandleNITZorEONS = FALSE;
    BOOL fMustHandleSindSignal = FALSE;
    BOOL fMustHandleSindPsinfo = FALSE;
    BOOL fMustAddSREG = TRUE;

    if (m_fPreUrcInitialized && !m_fUrcInitialized) {
        // Preliminary URC: only a few URCs are currently on.
        if (NO_SIND_SIGNAL_IN_CDMA && pDevice->GetCurrentTechnology() == TEC_MODE_CDMA)
          (void)strncpyz(szCmd, "AT+CREG=0;^SIND=rssi,0^SIND=simstatus,0", MAX_ATCMD_LEN);
       else
          (void)strncpyz(szCmd, "AT+CREG=0;^SIND=rssi,0;^SIND=signal,0;^SIND=simstatus,0", MAX_ATCMD_LEN);
    }
    else {
      switch (dwNewUrcState) {
          case MODEMSTATE_URCCONFIG_CALL_SMS_REG:
            // During suspend mode we have to switch back to SMS phase 2, because not all devices are
            // able to wake up fast enough to acknowledge an incomming SMS in time.
            RILRetailTraceZone(ZONE_INFO, (TEXT("RilDrv: SwitchUrcState(MODEMSTATE_URCCONFIG_CALL_SMS_REG)\r\n")));
            if (g_dwDisableSMS)
                (void)strncpyz(szCmd, "AT+CNMI=0,0,0,0;^SIND=rssi,0", MAX_ATCMD_LEN);
            else
                (void)_snprintfz(szCmd, MAX_ATCMD_LEN, "AT%s^SIND=rssi,0", GetSMSSettingOnSuspend());
            fMustHandleSindSignal = TRUE;
            fMustAddSREG = FALSE;
            break;
          case MODEMSTATE_URCCONFIG_CALL_SMS_NOUSSD:
            // See comment above about SMS.
            RILRetailTraceZone(ZONE_INFO, (TEXT("RilDrv: SwitchUrcState(MODEMSTATE_URCCONFIG_CALL_SMS)\r\n")));
            if (g_dwDisableSMS)
                (void)strncpyz(szCmd, "AT+CREG=0;+CGREG=0;+CUSD=0;+CNMI=0,0,0,0;^SIND=rssi,0", MAX_ATCMD_LEN);
            else
                (void)_snprintfz(szCmd, MAX_ATCMD_LEN, "AT+CREG=0;+CGREG=0;+CUSD=0;%s^SIND=rssi,0", GetSMSSettingOnSuspend());
            fMustHandleSindSignal = TRUE;
            fMustHandleNITZorEONS = TRUE;
            fMustHandleSindPsinfo = TRUE;
            break;
          case MODEMSTATE_URCCONFIG_CALL_SMS:
            // See comment above about SMS.
            RILRetailTraceZone(ZONE_INFO, (TEXT("RilDrv: SwitchUrcState(MODEMSTATE_URCCONFIG_CALL_SMS)\r\n")));
            if (g_dwDisableSMS)
                (void)strncpyz(szCmd, "AT+CREG=0;+CGREG=0;+CNMI=0,0,0,0;^SIND=rssi,0", MAX_ATCMD_LEN);
            else
                (void)_snprintfz(szCmd, MAX_ATCMD_LEN, "AT+CREG=0;+CGREG=0;%s^SIND=rssi,0", GetSMSSettingOnSuspend());
            fMustHandleSindSignal = TRUE;
            fMustHandleNITZorEONS = TRUE;
            fMustHandleSindPsinfo = TRUE;
            break;
          case MODEMSTATE_URCCONFIG_CALL:
            // Although all URCs are disabled, we leave the "SIM full" enabled notification, because
            // outherwise we could lose SMS.
            RILRetailTraceZone(ZONE_INFO, (TEXT("RilDrv: SwitchUrcState(MODEMSTATE_URCCONFIG_CALL)\r\n")));
            if (g_dwDisableSMS)
                (void)strncpyz(szCmd, "AT+CREG=0;+CGREG=0;+CNMI=0,0,0,0;^SIND=rssi,0", MAX_ATCMD_LEN);
            else
                (void)_snprintfz(szCmd, MAX_ATCMD_LEN, "AT+CREG=0;+CGREG=0;%s^SIND=rssi,0", GetSMSSettingOnSuspend());
            fMustHandleSindSignal = TRUE;
            fMustHandleNITZorEONS = TRUE;
            fMustHandleSindPsinfo = TRUE;
            break;
          case MODEMSTATE_URCCONFIG_CALL_SMS_CGREG:
            // Same as MODEMSTATE_URCCONFIG_CALL, but +CGREG (GPRS status) doesn't get
            // disabled.
            RILRetailTraceZone(ZONE_INFO, (TEXT("RilDrv: SwitchUrcState(MODEMSTATE_URCCONFIG_CALL_SMS_CGREG)\r\n")));
            if (g_dwDisableSMS)
                (void)strncpyz(szCmd, "AT+CREG=0;+CNMI=0,0,0,0;^SIND=rssi,0", MAX_ATCMD_LEN);
            else
                (void)_snprintfz(szCmd, MAX_ATCMD_LEN, "AT+CREG=0;%s^SIND=rssi,0", GetSMSSettingOnSuspend());
            fMustHandleSindSignal = TRUE;
            fMustHandleNITZorEONS = TRUE;
            break;
          default:
            return FALSE;
      }
    }

    // Some SIND indications might not work with some module versions.
    if (NO_SIND_SIGNAL_IN_CDMA && pDevice->GetCurrentTechnology() == TEC_MODE_CDMA)
        fMustHandleSindSignal = FALSE;
    if (NO_SIND_PSINFO_IN_CDMA && pDevice->GetCurrentTechnology() == TEC_MODE_CDMA)
        fMustHandleSindPsinfo = FALSE;

    if (fMustHandleNITZorEONS && pDevice->GetEons()->GetEONSState() == EONS_ENABLED)
        (void)strncatz(szCmd, ";^SIND=eons,0", MAX_ATCMD_LEN - strlen(szCmd));
    if (fMustHandleSindPsinfo)
        (void)strncatz(szCmd, ";^SIND=psinfo,0", MAX_ATCMD_LEN - strlen(szCmd));

    if (fMustAddSREG && pDevice->GetCurrentTechnology() != TEC_MODE_LTE && (GLOBAL_MODE_RADIO || CDMA_ONLY_RADIO))
        (void)strncatz(szCmd, ";^SREG=0", MAX_ATCMD_LEN - strlen(szCmd));

    if (NO_SIND_NITZ_IN_CDMA && pDevice->GetCurrentTechnology() == TEC_MODE_CDMA)
        fMustHandleNITZorEONS = FALSE;
    if (fMustHandleNITZorEONS && pDevice->IsNITZactive())
        (void)strncatz(szCmd, ";^SIND=nitz,0", MAX_ATCMD_LEN - strlen(szCmd));

    if (fMustHandleSindSignal && !NO_SIND_SIGNAL_AUDIO)
        (void)strncatz(szCmd, ";^SIND=signal,0", MAX_ATCMD_LEN - strlen(szCmd));

    // Filte "+CGREG=0" in CDMA mode.
    if (NO_CGREG_IN_CDMA && pDevice->GetCurrentTechnology() == TEC_MODE_CDMA) {
      char *szCGREG = strstr(szCmd, ";+CGREG=0");

      if (szCGREG != NULL)
        memmove(szCGREG, szCGREG+9, strlen(szCGREG)-8);
    }

    (void)strncatz(szCmd, "\r", MAX_ATCMD_LEN - strlen(szCmd));

    // Workaround for missing SMS notification bug: the module might already
    // be in the state, where a SMS notification is supposed to be printed out,
    // but isn't. After a timeout this situation could be detected, but this
    // timeout isn't over yet. Solution: reject all pending SMS acknowledgments.
    // If there is such an acknowledgement pending, the network will try again
    // later so nothing is lost. If not, there will be an error message which
    // can safely be ignored.
    if (NEEDS_RECHECK_OF_CNMI_AFTER_CMGS)
        RejectAllPendingSms(m_pRilHandle);

    if (!QueueInternalCmdBlocking(HCCMD_URCPORT_ONLY, pDevice, szCmd, CMDOPT_URC, APIID_NONE, 5000, 2, 1000)) {
        // This command may fail, if the problem is only a not initialized SIM. In this case
        // there are no URCs active anyway, so we can continue. If also a simple AT fails,
        // the problem must lie somewhere else.
        if (!QueueInternalCmdBlocking(HCCMD_URCPORT_ONLY, pDevice, "AT\r", CMDOPT_URC, APIID_NONE, 1000, 0, 0)) {
          return FALSE;
        }
    }

    // Save the last status
    m_dwRegStatusCache = g_dwRegStatus;
    m_dwGPRSRegStatusCache = g_dwGPRSRegStatus;
    // No more CIND indications, we have to use AT+CSQ to get the signal quality.
    g_bCINDIsActive = FALSE;
  }

  m_dwModemState = dwNewUrcState;
  m_fUrcInitialized = TRUE;

  return TRUE;
}

//////////////////////////////////////////////////////////////////////////////
//
// Tidy up internal states after any shutdown error.
//
//////////////////////////////////////////////////////////////////////////////
void CPowerManager::HandleShutdownError(BOOL fSendNotification) {
  RILEQUIPMENTSTATE   res;
  CNotificationData*  pnd = NULL;

  SYNCBLOCK(m_csPowerState);

  RILRetailTraceZone((ZONE_INFO|ZONE_ERROR), (TEXT("RilDrv: Forcing radio off!\r\n")));

  // Ensure that GPS handling is deactivated after power down
  g_GpsHandling.ForceDeactivateAsync();

  // Tidy up internal states
  (void)ShutdownFinished(&res);

  // Signal RIL is no longer ready
  m_pRilHandle->StopReadyStateQuery();
  m_pRilHandle->SendReadyStateNotification(RIL_READYSTATE_NONE, FALSE);

  UpdateSIMState((DWORD)RIL_E_RADIOOFF);

  // Notify the OS of the change in radio power state (default). In case of a
  // planned reboot the notification doesn't need to be sent.
  if (fSendNotification) {
    pnd = new CNotificationData;
    if (pnd && pnd->InitFromRealBlob(RIL_NOTIFY_RADIOEQUIPMENTSTATECHANGED, &res, res.cbSize)) {
      m_pRilHandle->BroadcastNotification(pnd);
      pnd = NULL;
    }
  }
  if (pnd != NULL)
    delete pnd;
}

//////////////////////////////////////////////////////////////////////////////
//
// Finish a shutdown by sending "AT^SMSO" and waiting for "^SHUTDOWN".
//
// Params:
//  lpParameter: "This" pointer to our class instance to get the reference
//               back in this static function.
//
// Return:
//  0 on success.
//
//////////////////////////////////////////////////////////////////////////////
DWORD WINAPI CPowerManager::ShutdownFinishThread(LPVOID lpParameter) {
CPowerManager*  pHandle = (CPowerManager*)lpParameter;
const char *cszCmd = "AT^SMSO\r";
DWORD           dwStartTime;
DWORD           dwCommMask;
char            szResponse[MAX_ENHANCED_INIT_AT_RESPONSE];
BOOL            bUSBShutdown = FALSE;
BOOL            bRHAShutdown = FALSE;
BOOL            bSuccess = TRUE;

  // Check our instance handle
  if (!pHandle) {
    return (DWORD)-1;
  }

  if (!g_ComManager.OpenBasePort()) {
    pHandle->HandleShutdownError();
    return (DWORD)-2;
  }

  // Send the power off command
#ifdef SUPPORTS_EHSX_R1
  if (NO_SUPPORT_SMSO)
    cszCmd = "AT+CPWROFF\r";
#endif
  if (MISSING_OK_ON_SMSO)
    bSuccess = pHandle->m_pRilHandle->ExSendATCommand(DATA_PORT, cszCmd);
  else
    bSuccess = pHandle->m_pRilHandle->ExSendATCmdGetRsp(DATA_PORT, cszCmd, szResponse, sizeof(szResponse), g_TimeoutAPIDefault, 3);
  if (!bSuccess) {
    pHandle->HandleShutdownError();
    return (DWORD)-2;
  }


#ifdef SKIP_RHA_CHECK_DURING_SHUTDOWN
  // When the RHA cannot be used to check the power state of the radio (e.g. on
  // development boards), this check must be skipped.
  bRHAShutdown = TRUE;
#endif

  // With HC25 there won't be any SHUTDOWN-Urc so we have to wait until the USB ports are no.
  // longer accessible.
  // Additionally the RIL uses the RHA to monitor the modules power state. The shutdown is considered
  // to be complete, when the USB driver has been unload and the RHA signals the radio is in power
  // off state.
  dwStartTime = GetTickCount();
  for (;;) {
    // Check USB driver state
    if (!bUSBShutdown)
        bUSBShutdown = !GetCommMask(g_ComManager.GetPortHandle(DATA_PORT), &dwCommMask);
    // Check RHA power state
    if (!bRHAShutdown)
        bRHAShutdown = !RHA_IsRadioPwrOn();

    if (bUSBShutdown && bRHAShutdown) {
      RILRetailTraceZone(ZONE_INFO, (TEXT("RilDrv: Shutdown finished\r\n")));
      (void)pHandle->ShutdownFinished(NULL);
      (void)pHandle->GenerateEquipmentNotification(NULL, pHandle->GetEquipmentState());
      break;
    }

    // Wait for some data
    Sleep(100);
    if ((GetTickCount() - dwStartTime) >= SHUTDOWN_TIMEOUT) {
      RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: Timeout while waiting for shutdown!\r\n")));
      pHandle->HandleShutdownError();
      return (DWORD)-3;
    }

    SYNCBLOCK(pHandle->m_csPowerState);
    SYNCBLOCK2(pHandle->m_csForcePower);
    if (!pHandle->m_hShutdownThread) {
      // We have been closed externally
      return (DWORD)-4;
    }
  }

  return 0;
}

//////////////////////////////////////////////////////////////////////////////
//
// Enable or disable RING on incoming data feature.
//
// Params:
//  pCmd   : Pointer to corresponding power command.
//  fEnable: Flag indicating if RING on incoming data shall be enabled (TRUE)
//           of disabled (FALSE).
//
// Return:
//  None.
//
//////////////////////////////////////////////////////////////////////////////
#ifdef RIL_ENABLE_RING_ON_INCOMMING_DATA
void CPowerManager::SwitchRingOnIncomingData(const CPowerCmd* pCmd, BOOL fEnable) {
  if (pCmd->IsPowerCmd() && IS_URCSTATE(m_dwModemState) && (pCmd->GetNewPowerState() <= D2)) {
    DCB dcb;
    for (COM_PORT_TYPE i = 0; i < NUMBER_OF_PORTS; i++) {
      CComHandle* pComDevice = GetRilDevice(NULL)->GetComDevice(i);
      if (pComDevice) {
        if (pComDevice->VirtGetCommState(&dcb)) {
          if (fEnable) {
            dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;
            (void)pComDevice->VirtSetCommState(&dcb);
          } else {
            dcb.fRtsControl = RTS_CONTROL_DISABLE;
            if (pComDevice->VirtSetCommState(&dcb)) {
              (void)pComDevice->VirtEscapeCommFunction(CLRRTS);
            }
          }
        }
      }
    }
  }
}
#else
void CPowerManager::SwitchRingOnIncomingData(const CPowerCmd* /*pCmd*/, BOOL /*fEnable*/) {
}
#endif

//////////////////////////////////////////////////////////////////////////////
//
// Check if it is allowed to execute the given power command in the current
// power state.
//
// Params:
//  pCmd              : Pointer to corresponding power command.
//  fFlightModeFromGps: Flag indicating if we have been switched to flight
//                      mode with last GPS power command.
//
// Return:
//  TRUE if the power command is valid and can be executed, FALSE otherwise.
//
//////////////////////////////////////////////////////////////////////////////
BOOL CPowerManager::CheckCmdPreCondition(const CPowerCmd* pCmd, BOOL fFlightModeFromGps) {
  SYNCBLOCK(m_csPowerState);

  // GPS commands are only allowed in power state D0
  if (pCmd->IsGpsCmd() && !IS_DEVICEON(m_PowerState)) {
    RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: Removing invalid GPS command from queue\r\n")));
    return FALSE;
  }

  if (!pCmd->IsPowerCmd() && pCmd->IsUrcCmd()) {
    if (!IS_DEVICEON(m_PowerState)) {
      // URC commands are only allowed in power state D0
      RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: Removing invalid URC command from queue\r\n")));
      return FALSE;
    }
    if (!pCmd->IsUrcInit() && !m_fUrcInitialized) {
      // We have an external URC cmd before URCs are initialized
      RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: Removing invalid early urc switch\r\n")));
      return FALSE;
    }
    if (pCmd->IsUrcInit() && (m_dwModemState == MODEMSTATE_POWEROFF)) {
      // We've been switched off during the init phase
      RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: Removing late urc initialization\r\n")));
      return FALSE;
    }
  }

  // Save the new equipment state in the registry
  if (IS_DEVICEON(m_PowerState) && !pCmd->IsGpsCmd()) {
    DWORD  dwLastEquipmentState;
    switch(pCmd->GetCmd()) {
      case MODEMSTATE_POWEROFF:
        dwLastEquipmentState = RIL_EQSTATE_MINIMUM;
        break;
      case MODEMSTATE_AIRPLANE:
        dwLastEquipmentState = RIL_EQSTATE_DISABLETXANDRX;
        break;
      default:
          dwLastEquipmentState = RIL_EQSTATE_FULL;
        break;
    }
    (void)SetRegistryDWORD(RIL_LAST_EQUIPMENT_STATE_ROOT, RIL_LAST_EQUIPMENT_STATE_KEY, RIL_LAST_EQUIPMENT_STATE_VALUE, dwLastEquipmentState);
  }

  // Save the new modem state, filter the GPS commands accordingly
  if (!pCmd->IsGpsCmd()) {
    m_dwNewModemState = pCmd->GetCmd();
  } else {
    if (pCmd->GetCmd() == MODEMSTATE_GPSON) {
      if (m_dwModemState == MODEMSTATE_POWEROFF) {
        m_dwNewModemState = MODEMSTATE_AIRPLANE;
         (void)SetRegistryDWORD(RIL_LAST_EQUIPMENT_STATE_ROOT, RIL_LAST_EQUIPMENT_STATE_KEY, RIL_LAST_EQUIPMENT_STATE_VALUE, RIL_EQSTATE_DISABLETXANDRX);
      } else {
        m_dwNewModemState = m_dwModemState;
      }
    } else {
      if (m_dwModemState == MODEMSTATE_AIRPLANE) {
        if (fFlightModeFromGps) {
          m_dwNewModemState = MODEMSTATE_POWEROFF;
        } else {
          m_dwNewModemState = m_dwModemState;
        }
      } else {
        m_dwNewModemState = m_dwModemState;
      }
    }
  }

  return TRUE;
}

//////////////////////////////////////////////////////////////////////////////
//
// Handler for the power command queue.
//
// Return:
//  0 on success.
//
//////////////////////////////////////////////////////////////////////////////
DWORD CPowerManager::CmdQueueHandler(void) {
CPowerCmd*   pCmd;
DWORD        dwLastEquipmentState;
DWORD        dwKeepGpsActive;
BOOL         fSwitchedOn;
BOOL         fBlock;
BOOL         fUnblock;
BOOL         fEmpty;
BOOL         fWaitDataMode;
BOOL         fEnableGps;
BOOL         fDisableGps;
BOOL         fGpsDisabled = FALSE;
BOOL         fFlightModeFromGps = FALSE;
BOOL         fSuspended = FALSE;
BOOL         fOffToAirplane = FALSE;
BOOL         fSupressEquipmentstateNotification = FALSE;
DWORD        dwCSDSuspendTimeout = DEFAULT_SUSPEND_CSD_TIMEOUT;
DWORD        dwGPRSSuspendTimeout = DEFAULT_SUSPEND_GPRS_TIMEOUT;
DWORD        dwGlobalSuspendTimeout = 0;

  for (;;) {
    if (FAILED(m_CmdQueue.Get(pCmd, INFINITE)) || !pCmd) {
      RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: Leaving power command queue\r\n")));
      break;
    }

    RILRetailTraceZone(ZONE_INFO, (TEXT("RilDrv: Handling %s %s\r\n"), pCmd->GetCmdType(), pCmd->GetCmdName()));

    if (pCmd->GetCmd() == MODEMSTATE_FORCE_POWEROFF) {
      // Empty command queues
      EmptyATCmdQueues();
      // Block further commands on power states D2 and below, unregister unattended mode
      if ((pCmd->GetNewPowerState() >= D2) && (pCmd->GetOldPowerState() <= D1)) {
        (void)GetRilDevice(NULL)->BlockCommandHandling();
        SwitchUnattendedMode(FALSE);
      }
      // Command has been executed before, just delete it
      delete pCmd;
      continue;
    }

    dwKeepGpsActive = 0;
    GetRegistryDWORD(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, TEXT("KeepGpsActiveOnSuspend"), &dwKeepGpsActive);

    EnterCriticalSection(&m_csPowerState);

    // Check if we're allowed to execute the given power command
    if (!CheckCmdPreCondition(pCmd, fFlightModeFromGps)) {
      delete pCmd;
      LeaveCriticalSection(&m_csPowerState);
      continue;
    }

    m_fOngoing = TRUE;
    m_dwOldModemState = m_dwModemState;
    dwLastEquipmentState = GetEquipmentState();
    if (pCmd->GetCmd() != MODEMSTATE_POWEROFF) {
      m_fPowerOffForced = FALSE;
    }

    LeaveCriticalSection(&m_csPowerState);

#ifdef RIL_RADIO_RESILIENCE
    if (pCmd->IsDelayCmd()) {
      DWORD dwPause;

      if (!GetRegistryDWORD(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, TEXT("PowerCmdDelay"), &dwPause))
        dwPause = 2000;

      RILRetailTraceZone(ZONE_INFO, (TEXT("RilDrv: Delay current power/equipment command for %dms\r\n"), dwPause));
      Sleep(dwPause);
     }
#endif

    // Start the system idle timer reset
    SwitchIdleTimerReset(TRUE);

    // Lock the on/off mutex
    (void)WaitAndLockPowerState();

    // Check if we have to wait after resume
    if (fSuspended) {
      DWORD  dwRegistry;
      if (GetRegistryDWORD(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, TEXT("WaitAfterResume"), &dwRegistry)) {
        Sleep(dwRegistry);
      }
      if (GetRegistryDWORD(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, TEXT("ReopenOnResumeTimeout"), &dwRegistry)) {
        g_ComManager.ReopenAllPortDevices(dwRegistry);
      }
      fSuspended = FALSE;
    }

    SwitchRingOnIncomingData(pCmd, TRUE);

#ifdef RIL_RADIO_RESILIENCE
    if (pCmd->IsPowerCmd() && IS_URCSTATE(m_dwModemState) && (pCmd->GetNewPowerState() <= D2)) {
      RHA_SetRadioIgnition(FALSE);
    }
#endif

    // Set the desired new module state
    fSwitchedOn = FALSE;
    /*lint -save -e616 */
    switch (pCmd->GetCmd()) {
      case MODEMSTATE_POWEROFF:
        fFlightModeFromGps = FALSE;
        switch (m_dwModemState) {
          case MODEMSTATE_POWEROFF:
            if (fGpsDisabled && pCmd->IsResumeCmd()) {
              // GPS was active on suspend -> We reactivate it
              // Otherwise we try to start the module directly in airplane mode
              if (!TurnOnModule(pCmd, TRUE, FALSE)) {
                // Failed to enter airplane mode -> switch module off
                if (!TurnOffModule(pCmd)) {
                  (void)UnlockPowerState();
                }
              } else {
                (void)UnlockPowerState();
                fOffToAirplane = TRUE;
                fFlightModeFromGps = TRUE;
              }
            } else {
              // Nothing to do
              (void)UnlockPowerState();
            }
            break;
          case MODEMSTATE_AIRPLANE:
            if (g_GpsHandling.IsGpsActive() && dwKeepGpsActive) {
                (void)g_GpsHandling.LockGpsAccess(TRUE);
                fGpsDisabled = TRUE;
                fFlightModeFromGps = TRUE;
                (void)UnlockPowerState();
            } else {

              if (g_GpsHandling.IsGpsActive()) {
                (void)g_GpsHandling.LockGpsAccess(TRUE);
                fGpsDisabled = TRUE;
              }

              if (!TurnOffModule(pCmd)) {
                (void)UnlockPowerState();
              }
            }
            break;
          case MODEMSTATE_POWERON:
          default: // MODEMSTATE_URCCONFIGs
            if (!g_GpsHandling.IsGpsActive() || (pCmd->IsSuspendCmd() && !dwKeepGpsActive)) {
              if (g_GpsHandling.IsGpsActive()) {
                (void)g_GpsHandling.LockGpsAccess(TRUE);
                fGpsDisabled = TRUE;
              }
              if (!TurnOffModule(pCmd)) {
                (void)UnlockPowerState();
              }
            } else {
              // GPS is still active -> We switch to flight mode
              if (!SwitchActiveFlightMode(TRUE)) {
                // Failed to enter airplane mode -> switch module off
                if (!TurnOffModule(pCmd)) {
                  (void)UnlockPowerState();
                }
              } else {
                fFlightModeFromGps = TRUE;
              }
            }
            break;
        }
        break;

      case MODEMSTATE_AIRPLANE:
        fFlightModeFromGps = FALSE;
        switch (m_dwModemState) {
          case MODEMSTATE_POWEROFF:
            // only if GPS active then start the module directly in airplane mode
            if (g_GpsHandling.IsGpsActive()) {
              if (!TurnOnModule(pCmd, TRUE, FALSE)) {
                // Failed to enter airplane mode -> switch module off
                if (!TurnOffModule(pCmd)) {
                  (void)UnlockPowerState();
                }
              } else {
                (void)g_GpsHandling.SwitchGpsState(TRUE);
                fOffToAirplane = TRUE;
                fFlightModeFromGps = TRUE;
              }
            } else {
              // GPS no active
              (void)UnlockPowerState();
            }
            break;
          case MODEMSTATE_AIRPLANE:
            // Nothing to do
            fFlightModeFromGps = TRUE;
            (void)UnlockPowerState();
            break;
          case MODEMSTATE_POWERON:
          default: // MODEMSTATE_URCCONFIGs
            if (IS_URCCONFIG(m_dwModemState)) {
              // First enable URCs again for later state changes
              CPowerCmd PwrCmd(MODEMSTATE_POWERON, NULL, PwrDeviceUnspecified, PwrDeviceUnspecified, TRUE, FALSE);
              (void)SwitchUrcState(&PwrCmd);
            }
            if (!SwitchActiveFlightMode(TRUE)) {
              // Failed to enter airplane mode -> switch module off
              if (!TurnOffModule(pCmd)) {
                (void)UnlockPowerState();
              }
            }
            break;
        }
        break;

      case MODEMSTATE_POWERON:
        switch (m_dwModemState) {
          case MODEMSTATE_POWEROFF:
            if (!TurnOnModule(pCmd, FALSE, TRUE)) {
              (void)UnlockPowerState();
            }
            fOffToAirplane = FALSE;
            fSwitchedOn = TRUE;
            break;

          case MODEMSTATE_AIRPLANE:
            if (!SwitchActiveFlightMode(FALSE)) {
              (void)UnlockPowerState();
            }
            if (fOffToAirplane || fFlightModeFromGps) {
              // If we had been switched from off to airplane mode we have to repeat the initialization
              (void)WaitAndLockPowerState();
              if (!StartReinitialization(pCmd)) {
                (void)UnlockPowerState();
              }
              fOffToAirplane = FALSE;
              fSwitchedOn = TRUE;
            }
            break;

          case MODEMSTATE_POWERON:
          default: // MODEMSTATE_URCCONFIGs
            (void)SwitchUrcState(pCmd);
            if (pCmd->IsUrcCmd() && pCmd->IsUrcInit())
              fSupressEquipmentstateNotification = TRUE;
            (void)UnlockPowerState();
            break;
        }
        fFlightModeFromGps = FALSE;
        break;

      case MODEMSTATE_GPSON:
        switch (m_dwModemState) {
          case MODEMSTATE_POWEROFF:
            // Otherwise we try to start the module directly in airplane mode
            if (!TurnOnModule(pCmd, TRUE, FALSE)) {
              // Failed to enter airplane mode -> switch module off
              if (!TurnOffModule(pCmd)) {
                (void)UnlockPowerState();
              }
            } else {
              (void)UnlockPowerState();
              fOffToAirplane = TRUE;
              fFlightModeFromGps = TRUE;
              (void)g_GpsHandling.SwitchGpsState(TRUE);
            }
            break;
          case MODEMSTATE_AIRPLANE:
          case MODEMSTATE_POWERON:
          default: // MODEMSTATE_URCCONFIGs
            // Switch gps mode on
            (void)UnlockPowerState();
            (void)g_GpsHandling.SwitchGpsState(TRUE);
            break;
        }
        break;

      case MODEMSTATE_GPSOFF:
        switch (m_dwModemState) {
          case MODEMSTATE_POWEROFF:
            // Nothing to do
            (void)UnlockPowerState();
            break;
          case MODEMSTATE_AIRPLANE:
            if (!fFlightModeFromGps) {
              // We haven't switched on the module just for GPS -> Just disable GPS
              (void)UnlockPowerState();
              (void)g_GpsHandling.SwitchGpsState(FALSE);
            } else {
              // We have switched on the module just for GPS -> Switch module off again
              if (!TurnOffModule(pCmd)) {
                (void)UnlockPowerState();
              }
#ifdef RIL_RADIO_RESILIENCE
              g_fAllowReboot = FALSE;
              ClearPINSecure();
#endif
              ClearPIN2Secure();
            }
            break;
          case MODEMSTATE_POWERON:
          default: // MODEMSTATE_URCCONFIGs
            // Switch GPS mode off
            (void)UnlockPowerState();
            (void)g_GpsHandling.SwitchGpsState(FALSE);
            break;
        }
        fGpsDisabled = FALSE;
        fFlightModeFromGps = FALSE;
        break;

      default: // MODEMSTATE_URCCONFIGs
        fFlightModeFromGps = FALSE;
        switch (m_dwModemState) {
          case MODEMSTATE_POWEROFF:
            if (!TurnOnModule(pCmd, FALSE, TRUE)) {
              (void)UnlockPowerState();
            }
            fOffToAirplane = FALSE;
            fSwitchedOn = TRUE;
            // Store the urc state as new initial urc state
            m_dwInitUrcState = pCmd->GetCmd();
            break;
          case MODEMSTATE_AIRPLANE:
            if (!SwitchActiveFlightMode(FALSE)) {
              (void)UnlockPowerState();
            }
            if (fOffToAirplane) {
              // If we had been switched from off to airplane mode we have to repeat the initialization
              m_dwInitUrcState = pCmd->GetCmd();
              (void)WaitAndLockPowerState();
              if (!StartReinitialization(pCmd)) {
                (void)UnlockPowerState();
              }
              fOffToAirplane = FALSE;
              fSwitchedOn = TRUE;
            } else {
              (void)WaitPowerState();
              (void)SwitchUrcState(pCmd);
              if (pCmd->IsUrcCmd() && pCmd->IsUrcInit())
                fSupressEquipmentstateNotification = TRUE;
            }
            break;
          case MODEMSTATE_POWERON:
          default: // MODEMSTATE_URCCONFIGs
            (void)SwitchUrcState(pCmd);
            if (pCmd->IsUrcCmd() && pCmd->IsUrcInit())
              fSupressEquipmentstateNotification = TRUE;
            (void)UnlockPowerState();
            break;
        }
        break;
    }
    /*lint -restore */

    // If we've been switched on generate the equipment state changed notification
    // before the wait to show the "!" icon immediately
    EnterCriticalSection(&m_csPowerState);
    if (!m_fPowerOffForced && fSwitchedOn && ((dwLastEquipmentState != GetEquipmentFromModemState(m_dwModemState)) || !pCmd->IsPowerCmd())) {
      (void)GenerateEquipmentNotification(pCmd, GetEquipmentFromModemState(m_dwModemState));
    }
    LeaveCriticalSection(&m_csPowerState);

    // Wait for the power operation to finish
    (void)WaitPowerState();

    EnterCriticalSection(&m_csPowerState);

    // Set power state for GetEquipmentState()
    m_dwOldModemState = m_dwModemState;

    // Generate the equipment state changed notification
    if (!m_fPowerOffForced && !fSwitchedOn && ((dwLastEquipmentState != GetEquipmentState()) || !pCmd->IsPowerCmd())) {
      if (!fSupressEquipmentstateNotification)
        (void)GenerateEquipmentNotification(pCmd , GetEquipmentState());
    }

    fBlock = FALSE;
    fUnblock= FALSE;
    fEmpty = FALSE;
    fWaitDataMode= FALSE;
    fEnableGps = FALSE;
    fDisableGps = FALSE;

    if (pCmd->IsSuspendCmd() && !m_fPowerOffForced) {
      // Block further command handling on suspend power states
      if (m_dwModemState == MODEMSTATE_POWEROFF) {
        // If we've been switched off wait until the command queues are empty
        fEmpty = TRUE;
      } else {
        // If we haven't been switched off check if we have to disable GPS
        if (g_GpsHandling.IsGpsActive() && !g_GpsHandling.IsGpsLocked()) {
          fDisableGps = TRUE;
        }
      }
      fBlock = TRUE;
      fWaitDataMode= TRUE;
    }

    if (pCmd->IsResumeCmd() && !m_fPowerOffForced) {
      fUnblock = TRUE;
      if ((m_dwModemState != MODEMSTATE_POWEROFF) && fGpsDisabled) {
        // GPS has been disabled on suspend, we now need to reenable it
        fEnableGps = TRUE;
      }
    }

    if ((pCmd->GetNewPowerState() >= D3) && (m_dwModemState != MODEMSTATE_POWEROFF)) {
      DWORD  dwRegistry;
      fSuspended = TRUE;
      fBlock = TRUE;
      if (GetRegistryDWORD(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, TEXT("ReopenOnResumeTimeout"), &dwRegistry)) {
        g_ComManager.PrepareReopen();
      }
    }

    LeaveCriticalSection(&m_csPowerState);

    // Unblock further command handling if required
    if (fUnblock) {
      (void)GetRilDevice(NULL)->UnblockCommandHandling();
    }

    // Disable GPS is required
    if (fDisableGps) {
      if (g_GpsHandling.LockGpsAccess(TRUE)) {
        fGpsDisabled = TRUE;
      }
    }

    // Enable GPS is required
    if (fEnableGps) {
      if (g_GpsHandling.IsGpsLocked()) {
        (void)g_GpsHandling.LockGpsAccess(FALSE);
        fGpsDisabled = FALSE;
      } else {
        (void)g_GpsHandling.SwitchGpsState(TRUE);
        fGpsDisabled = FALSE;
      }
    }

    if (dwLastEquipmentState == RIL_EQSTATE_FULL) {
      // handle suspend timeout

      // exist global suspend timeout?
      dwGlobalSuspendTimeout = 0;
      (void)GetRegistryDWORD(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, TEXT("SuspendTimeout"), &dwGlobalSuspendTimeout);
      if (fWaitDataMode && dwGlobalSuspendTimeout) {
         // use global suspend timeout
          Sleep(dwGlobalSuspendTimeout);
      }  else {
        // use specific suspend timeout
        // Wait for CSD connection to close
        (void)GetRegistryDWORD(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, TEXT("SuspendCSDTimeout"), &dwCSDSuspendTimeout);
        if (fWaitDataMode && dwCSDSuspendTimeout) {
          if (m_pRilHandle->GetComDevice(DATA_PORT)->FDataCsdMode()) {
            if (m_pRilHandle->GetComDevice(DATA_PORT)->WaitForCommandMode(dwCSDSuspendTimeout)) {
              // Give some additional time if CSD has just been closed
              Sleep(ADDITIONAL_CSD_SUSPEND_PERIOD);
            }
          }
        }
        // Optional GPRS connection delay
        (void)GetRegistryDWORD(HKEY_LOCAL_MACHINE, g_tszRegKeyRIL, TEXT("SuspendGPRSTimeout"), &dwGPRSSuspendTimeout);
        if (fWaitDataMode && dwGPRSSuspendTimeout) {
          if (m_pRilHandle->GetComDevice(DATA_PORT)->FDataMode() && !m_pRilHandle->GetComDevice(DATA_PORT)->FDataCsdMode()) {
            if (m_pRilHandle->GetComDevice(DATA_PORT)->WaitForCommandMode(dwGPRSSuspendTimeout)) {
              // Give some additional time if data connection has just been closed
             Sleep(ADDITIONAL_GPRS_SUSPEND_PERIOD);
            }
          }
        }
      }

    }



    // Empty command queues if required
    if (fEmpty) {
      EmptyATCmdQueues();
    }

    // Block further command handling if required
    if (fBlock) {
      (void)GetRilDevice(NULL)->BlockCommandHandling();
    }

    SwitchRingOnIncomingData(pCmd, FALSE);

#ifdef RIL_RADIO_RESILIENCE
    if (pCmd->IsPowerCmd() && IS_URCSTATE(m_dwModemState) && (pCmd->GetNewPowerState() >= D3)) {
      RHA_SetRadioIgnition(TRUE);
    }
#endif

    // Execute next command if it is a late RIL_EQSTATE_MINIMUM call
    Sleep(0);
    EnterCriticalSection(&m_csPowerState);
    if (pCmd->IsPowerCmd() && pCmd->IsBlocking()) {
      CPowerCmd* pNextCmd;
      if (m_CmdQueue.Peek(pNextCmd)) {
        if (pNextCmd) {
          if (pNextCmd->IsEquipmentStateCmd()) {
            RILRetailTraceZone(ZONE_INFO, (TEXT("RilDrv: Catch up late equipment state call\r\n")));
            pNextCmd->SetFinishEvent(pCmd->InheritFinishEvent());
          }
        }
      }
    }
    m_fOngoing = FALSE;
    LeaveCriticalSection(&m_csPowerState);

    // Stop the system idle timer reset
    SwitchIdleTimerReset(FALSE);

    if ((pCmd->GetNewPowerState() >= D2) && (pCmd->GetOldPowerState() <= D1)) {
      SwitchUnattendedMode(FALSE);
    }

    // Delete the command
    delete pCmd;
  }

  return 0;
}

//////////////////////////////////////////////////////////////////////////////
//
// Thread to handle the power command queue.
//
// Params:
//  lpParameter: "This" pointer to our class instance to get the reference
//               back in this static function.
//
// Return:
//  0 on success.
//
//////////////////////////////////////////////////////////////////////////////
DWORD WINAPI CPowerManager::CmdQueueThread(LPVOID lpParameter) {
CPowerManager* pHandle = (CPowerManager*)lpParameter;

  if (!pHandle) {
    return (DWORD)-2;
  }

  if (!SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL)) {
    return (DWORD)-3;
  }

  return pHandle->CmdQueueHandler();
}

#ifdef RIL_USE_CSQ_NOTIFICATIONS
#ifdef RIL_RADIO_RESILIENCE
//////////////////////////////////////////////////////////////////////////////
//
// Thread to handle the polling thread for the resilience mode.
//
// This is only needed, when the signal strength notifiactions are active. Otherwise the
// OS is polling anyhow, so this polling thread is not needed.
//
// Params:
//  lpParameter: "This" pointer to our class instance to get the reference
//               back in this static function.
//
// Return:
//  0 on success.
//
//////////////////////////////////////////////////////////////////////////////
DWORD WINAPI CPowerManager::ResiliencePollingThread(LPVOID lpParameter) {
CPowerManager* pHandle = (CPowerManager*)lpParameter;

  if (!pHandle) {
    return (DWORD)-2;
  }

  return pHandle->ResiliencePollingHandler();
}

//////////////////////////////////////////////////////////////////////////////
//
// Handler for the polling thread for the resilience mode.
//
// The thread polls every RESILIENCE_POLLING_INTERVAL ms via RHA for an
// unexpected radio power loss. This is only necessary, if the signal strength
// notifications are on. If they are off, the OS will do the polling itself.
//
// Return:
//  0 on success.
//
//////////////////////////////////////////////////////////////////////////////
DWORD CPowerManager::ResiliencePollingHandler(void) {

  for (;;) {
    // The exit signal for the command queue is also the exit signal for this thread.
    if (WaitForSingleObject(m_hCmdQueueExitEvent, RESILIENCE_POLLING_INTERVAL) != WAIT_TIMEOUT) {
      RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: Leaving resilience polling handler\r\n")));
      break;
    }

    // If the power manager still reports the radio is on, but the RHA says it is off,
    // it is necessary to force an emergency radio shutdown now.
    if (!IsRadioOff() &&  !RHA_IsRadioPwrOn() && g_fAllowReboot) {
      RILRetailTraceZone(ZONE_ERROR, (TEXT("RilDrv: RHA reports module shutdown\r\n")));
      ForcePowerOff();
    }
  }
  return 0;
}
#endif
#endif

#ifdef RIL_CATCH_NDIS_START_MSG
//////////////////////////////////////////////////////////////////////////////
//
// This thread handles the NDIS start notification sent by the PH8 if run in
// SDPORT mode 3. This start notification is sent by the module directly after
// system start and repeated in increasing intervals for 2 minutes if it is
// not handled properly. These repetitions may cause unexepected suspend
// resume cycles on the USB bus can can lead to problems on some systems.
// This thread answers the start notification properly and therefore avoids
// the repeated notifications. It should only be activated when an PH8 is
// used in SDPORT mode 3 and if there are actual problems with the USB
// powermangement.
//
//
// Return:
//  Always 0.
//
//////////////////////////////////////////////////////////////////////////////
DWORD CPowerManager::CatchNdisMsgThread(LPVOID lpParameter) {
RILRetailTraceZone(ZONE_INFO, (TEXT("RilDrv: NdisStartMsgThread() start\r\n")));
  BOOL fSucceeded = FALSE;
  HANDLE hPort = CreateFile(TEXT("HCC1:"), GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
  if (hPort != INVALID_HANDLE_VALUE) {
    static const DWORD dwMaxWaitTime = 130000;
    COMMTIMEOUTS CommTimeouts;
    CommTimeouts.WriteTotalTimeoutMultiplier = 0;
    CommTimeouts.WriteTotalTimeoutConstant   = 1000;
    CommTimeouts.ReadIntervalTimeout         = MAXDWORD;
    CommTimeouts.ReadTotalTimeoutMultiplier  = MAXDWORD;
    CommTimeouts.ReadTotalTimeoutConstant    = 1000;
    SetCommTimeouts(hPort, &CommTimeouts);
    DWORD dwStart = GetTickCount();
    while ((GetTickCount() - dwStart) < dwMaxWaitTime) {
      static const BYTE NdisStartInd[] = { 0x01, 0x0B, 0x00, 0x80, 0x00, 0x00, 0x02, 0x00, 0x27, 0x00, 0x00, 0x00 };
      BYTE buf[32];
      DWORD dwCount = 0;
      if (ReadFile(hPort, buf, ARRAYSIZE(buf), &dwCount, NULL)) {
        if ((dwCount == ARRAYSIZE(NdisStartInd)) && !memcmp(buf, NdisStartInd, dwCount)) {
          buf[3] = 0x00;
          buf[6] = 0x00;
          if (WriteFile(hPort, buf, dwCount, &dwCount, NULL)) {
            if (dwCount == ARRAYSIZE(NdisStartInd)) {
              dwCount = 0;
              while (ReadFile(hPort, buf, ARRAYSIZE(buf), &dwCount, NULL) && dwCount);
              fSucceeded = TRUE;
              break;
            }
          }
        }
      } else {
        if (GetLastError() && (ERROR_IO_PENDING != GetLastError())) {
          break;
        }
      }
    }
    CloseHandle(hPort);
  }
  if (fSucceeded) {
    RILRetailTraceZone(ZONE_INFO, (TEXT("RilDrv: Successfully handled NDIS start indication\r\n")));
  } else {
    RILRetailTraceZone(ZONE_INFO, (TEXT("RilDrv: Failed to handle NDIS start indication\r\n")));
  }
  return 0;
}
#endif

//////////////////////////////////////////////////////////////////////////////
//
// Get the internal pointer to CRilHandle or the pointer stored in the
// passed CRilInstanceHandle.
//
// Params:
//  pHandle: Pointer to a CRilInstanceHandle.
//
// Return:
//  The internal stored pointer to CRilHandle if the passed pointer to
//  CRilInstanceHandle is NULL, otherwise the CRilHandle pointer form
//  CRilInstanceHandle.
//
//////////////////////////////////////////////////////////////////////////////
CRilHandle* CPowerManager::GetRilDevice(const CRilInstanceHandle* pHandle) {
  return (pHandle ? pHandle->GetDevice() : m_pRilHandle);
}

