Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

498 lines
12 KiB

  1. /* Copyright 1999 American Power Conversion, All Rights Reserved
  2. *
  3. * Description:
  4. * Implementation of the super states of the UPS native service:
  5. * Initializing,Waiting_To_Shutdown, Shutting_Down and Stopping
  6. *
  7. * Revision History:
  8. * dsmith 1April1999 Created
  9. *
  10. */
  11. #include <windows.h>
  12. #include "events.h"
  13. #include "driver.h"
  14. #include "eventlog.h"
  15. #include "notifier.h"
  16. #include "shutdown.h"
  17. #include "hibernate.h"
  18. #include "upsmsg.h" // Included since direct access to message #defines is not possible
  19. #include "cmdexe.h"
  20. #include "upsreg.h"
  21. // Internal constants
  22. #define DELAY_UNTIL_SHUTDOWN_C 30000 // 30 seconds
  23. #define DEFAULT_NOTIFICATION_INTERVAL_C 0 // disable periodic notification
  24. #define MILLISECONDS_CONVERSION_C 1000
  25. #define DEFAULT_TURN_OFF_DELAY_C 120 // seconds
  26. /**
  27. * Initializing_Enter
  28. *
  29. * Description:
  30. * Performs the actions necessary when transitioning into the INITIALIZING state.
  31. *
  32. * Parameters:
  33. * anEvent The event that caused the transition into this state.
  34. *
  35. * Returns:
  36. * None
  37. */
  38. void Initializing_Enter(DWORD anEvent){
  39. DWORD first_msg_delay, msg_interval, shutdown_wait;
  40. // Default all registry values and set up any new keys required by the
  41. // service and applet
  42. InitializeRegistry();
  43. // Check the ranges of the Config registry keys
  44. InitUPSConfigBlock();
  45. // Check FirstMessageDelay
  46. if (GetUPSConfigFirstMessageDelay(&first_msg_delay) == ERROR_SUCCESS) {
  47. if (first_msg_delay > WAITSECONDSLASTVAL) {
  48. // Value out of range, set to default
  49. SetUPSConfigFirstMessageDelay(WAITSECONDSDEFAULT);
  50. }
  51. }
  52. // Check MessageInterval
  53. if (GetUPSConfigMessageInterval(&msg_interval) == ERROR_SUCCESS) {
  54. if ((msg_interval < REPEATSECONDSFIRSTVAL) || (msg_interval > REPEATSECONDSLASTVAL)) {
  55. // Value out of range, set to default
  56. SetUPSConfigMessageInterval(REPEATSECONDSDEFAULT);
  57. }
  58. }
  59. // Check Config\ShutdownOnBatteryWait
  60. if (GetUPSConfigShutdownOnBatteryWait(&shutdown_wait) == ERROR_SUCCESS) {
  61. if ((shutdown_wait < SHUTDOWNTIMERMINUTESFIRSTVAL) || (shutdown_wait > SHUTDOWNTIMERMINUTESLASTVAL)) {
  62. // Value out of range, set to default
  63. SetUPSConfigFirstMessageDelay(SHUTDOWNTIMERMINUTESDEFAULT);
  64. }
  65. }
  66. // Write any changes and free the Config block
  67. SaveUPSConfigBlock(FALSE); // Don't force an update of all values
  68. FreeUPSConfigBlock();
  69. }
  70. /**
  71. * Initializing_DoWork
  72. *
  73. * Description:
  74. * Initialize the UPS driver
  75. *
  76. * Parameters:
  77. * None
  78. *
  79. * Returns:
  80. * An error status from the UPS.
  81. */
  82. DWORD Initializing_DoWork(){
  83. DWORD err;
  84. DWORD options = 0;
  85. InitUPSConfigBlock();
  86. // Check the Options reg key to see if the UPS is installed
  87. if ((GetUPSConfigOptions(&options) == ERROR_SUCCESS) &&
  88. (options & UPS_INSTALLED)) {
  89. // UPS is installed, continue initialization
  90. // Create UPS driver
  91. err = UPSInit();
  92. // Convert UPS error to system error
  93. switch(err){
  94. case UPS_INITUNKNOWNERROR:
  95. err = NERR_UPSInvalidConfig;
  96. break;
  97. case UPS_INITOK:
  98. err = NERR_Success;
  99. break;
  100. case UPS_INITNOSUCHDRIVER:
  101. err = NERR_UPSDriverNotStarted;
  102. break;
  103. case UPS_INITBADINTERFACE:
  104. err = NERR_UPSInvalidConfig;
  105. break;
  106. case UPS_INITREGISTRYERROR:
  107. err = NERR_UPSInvalidConfig;
  108. break;
  109. case UPS_INITCOMMOPENERROR:
  110. err = NERR_UPSInvalidCommPort;
  111. break;
  112. case UPS_INITCOMMSETUPERROR:
  113. err = NERR_UPSInvalidCommPort;
  114. break;
  115. default:
  116. err = NERR_UPSInvalidConfig;
  117. }
  118. }
  119. else {
  120. // UPS is not installed, return configuration error
  121. err = NERR_UPSInvalidConfig;
  122. }
  123. FreeUPSConfigBlock();
  124. return err;
  125. }
  126. /**
  127. * Initializing_Exit
  128. *
  129. * Description:
  130. * Performs the actions necessary when transitioning from the INITIALIZING state.
  131. *
  132. * Parameters:
  133. * anEvent The event that caused the transition from the INITIALIZING state.
  134. *
  135. * Returns:
  136. * None
  137. */
  138. void Initializing_Exit(DWORD anEvent){
  139. // No work to perform
  140. }
  141. /**
  142. * WaitingToShutdown_Enter
  143. *
  144. * Description:
  145. * Performs the actions necessary when transitioning into the WAITING_TO_SHUTDOWN state.
  146. *
  147. * Parameters:
  148. * anEvent The event that caused the transition into this state.
  149. *
  150. * Returns:
  151. * None
  152. */
  153. void WaitingToShutdown_Enter(DWORD anEvent){
  154. // Stop periodic notifications
  155. CancelNotification();
  156. }
  157. /**
  158. * WaitingToShutdown_DoWork
  159. *
  160. * Description:
  161. * Perform shutdown actions then transition out of this state.
  162. *
  163. * Parameters:
  164. * None
  165. *
  166. * Returns:
  167. * The event that caused the transition from the WAITING_TO_SHUTDOWN state.
  168. */
  169. DWORD WaitingToShutdown_DoWork(){
  170. LONG err;
  171. DWORD run_command_file;
  172. DWORD notification_interval = 0; // Notify only once
  173. DWORD send_final_notification;
  174. HANDLE sleep_timer;
  175. // Send the shutdown notification. If a configuration error occurs,
  176. // send the final notification by default.
  177. err = GetUPSConfigNotifyEnable(&send_final_notification);
  178. if (err != ERROR_SUCCESS || send_final_notification == TRUE){
  179. SendNotification(APE2_UPS_POWER_SHUTDOWN, notification_interval, 0);
  180. }
  181. // Determine which actions to perform
  182. // If command file action is enabled, execute command file and
  183. // then wait
  184. InitUPSConfigBlock();
  185. err = GetUPSConfigRunTaskEnable(&run_command_file);
  186. if (err != ERROR_SUCCESS){
  187. run_command_file = FALSE;
  188. }
  189. if (run_command_file == TRUE){
  190. // Execute the command file and wait for a while. If the
  191. // command file fails to execute, log an error to the system
  192. // event log.
  193. if (ExecuteShutdownTask() == FALSE){
  194. // Log failed command file event
  195. LogEvent(NELOG_UPS_CmdFileExec, NULL, GetLastError());
  196. }
  197. }
  198. // Always wait here before exiting this state
  199. // Use the WaitForSingleObject since Sleep is not guaranteed to always work
  200. sleep_timer = CreateEvent(NULL, FALSE, FALSE, NULL);
  201. if (sleep_timer){
  202. // Since nothing can signal this event, the following API will wait
  203. // until the time elapses
  204. WaitForSingleObject(sleep_timer, DELAY_UNTIL_SHUTDOWN_C);
  205. CloseHandle(sleep_timer);
  206. }
  207. // If the sleep_timer could not be created, try the sleep call anyway
  208. else {
  209. Sleep(DELAY_UNTIL_SHUTDOWN_C);
  210. }
  211. return SHUTDOWN_ACTIONS_COMPLETED;
  212. }
  213. /**
  214. * WaitingToShutdown_Exit
  215. *
  216. * Description:
  217. * Performs the actions necessary when transitioning from the WAITING_TO_SHUTDOWN state.
  218. *
  219. * Parameters:
  220. * anEvent The event that caused the transition from the WAITING_TO_SHUTDOWN state.
  221. *
  222. * Returns:
  223. * None
  224. */
  225. void WaitingToShutdown_Exit(DWORD anEvent){
  226. // No work to perform
  227. }
  228. /**
  229. * ShuttingDown_Enter
  230. *
  231. * Description:
  232. * Performs the actions necessary when transitioning into the SHUTTING_DOWN state.
  233. *
  234. * Parameters:
  235. * anEvent The event that caused the transition into this state.
  236. *
  237. * Returns:
  238. * None
  239. */
  240. void ShuttingDown_Enter(DWORD anEvent){
  241. // Log the final shut down message
  242. LogEvent(NELOG_UPS_Shutdown, NULL, ERROR_SUCCESS);
  243. }
  244. /**
  245. * ShuttingDown_DoWork
  246. *
  247. * Description:
  248. * Shuts down the OS. This state will waits until the shutdown has completed,
  249. * then exits.
  250. *
  251. * Parameters:
  252. * None
  253. *
  254. * Returns:
  255. * The event that caused the transition from the SHUTTING_DOWN state.
  256. */
  257. DWORD ShuttingDown_DoWork(){
  258. DWORD ups_turn_off_enable;
  259. DWORD ups_turn_off_wait;
  260. // Initialize registry functions
  261. InitUPSConfigBlock();
  262. // Lookup the turn off enable in the registry
  263. if ((GetUPSConfigTurnOffEnable(&ups_turn_off_enable) == ERROR_SUCCESS)
  264. && (ups_turn_off_enable == TRUE)) {
  265. // UPS Turn off enabled, lookup the turn off wait in the registry
  266. if (GetUPSConfigTurnOffWait(&ups_turn_off_wait) != ERROR_SUCCESS) {
  267. // Error obtaining the value, use the default instead
  268. ups_turn_off_wait = DEFAULT_TURN_OFF_DELAY_C;
  269. }
  270. // Tell the UPS driver to turn off the power after the shutdown delay
  271. UPSTurnOff(ups_turn_off_wait);
  272. }
  273. // Tell the OS to Shutdown
  274. ShutdownSystem();
  275. // Free the UPS registry config block
  276. FreeUPSConfigBlock();
  277. return SHUTDOWN_COMPLETE;
  278. }
  279. /**
  280. * ShuttingDown_Exit
  281. *
  282. * Description:
  283. * Performs the actions necessary when transitioning from the SHUTTING_DOWN state.
  284. *
  285. * Parameters:
  286. * anEvent The event that caused the transition from the SHUTTING_DOWN state.
  287. *
  288. * Returns:
  289. * None
  290. */
  291. void ShuttingDown_Exit(DWORD anEvent){
  292. // No work to perform
  293. }
  294. /**
  295. * Hibernate_Enter
  296. *
  297. * Description:
  298. * Performs the actions necessary when transitioning into the HIBERNATE state.
  299. *
  300. * Parameters:
  301. * anEvent The event that caused the transition into this state.
  302. *
  303. * Returns:
  304. * None
  305. */
  306. void Hibernate_Enter(DWORD anEvent){
  307. // Stop periodic notifications
  308. CancelNotification();
  309. }
  310. /**
  311. * Hibernate_DoWork
  312. *
  313. * Description:
  314. * Perform hibernation actions then transition out of this state.
  315. *
  316. * Parameters:
  317. * None
  318. *
  319. * Returns:
  320. * The event that caused the transition from the HIBERNATE state.
  321. */
  322. DWORD Hibernate_DoWork(){
  323. DWORD event = HIBERNATION_ERROR;
  324. LONG err;
  325. DWORD ups_turn_off_enable;
  326. DWORD ups_turn_off_wait;
  327. DWORD notification_interval = 0; // Notify only once
  328. DWORD send_hibernate_notification;
  329. // Initialize registry functions
  330. InitUPSConfigBlock();
  331. // Send the hibernation notification. If a configuration error occurs,
  332. // send the notification by default.
  333. err = GetUPSConfigNotifyEnable(&send_hibernate_notification);
  334. if (err != ERROR_SUCCESS || send_hibernate_notification == TRUE){
  335. // TODO: Send Hibernation nofication
  336. //SendNotification(HIBERNATE, notification_interval);
  337. }
  338. // Lookup the turn off enable in the registry
  339. if ((GetUPSConfigTurnOffEnable(&ups_turn_off_enable) == ERROR_SUCCESS)
  340. && (ups_turn_off_enable == TRUE)) {
  341. // UPS Turn off enabled, lookup the turn off wait in the registry
  342. if (GetUPSConfigTurnOffWait(&ups_turn_off_wait) != ERROR_SUCCESS) {
  343. // Error obtaining the value, use the default instead
  344. ups_turn_off_wait = DEFAULT_TURN_OFF_DELAY_C;
  345. }
  346. // Tell the UPS driver to turn off the power after the shutdown delay
  347. UPSTurnOff(ups_turn_off_wait);
  348. }
  349. // Stop the UPS driver. This needs to be done to ensure that we can start
  350. // correctly when we return from hibernation.
  351. UPSStop();
  352. // Now Hibernate
  353. if (HibernateSystem() == TRUE) {
  354. // The system was hibernated and subsequently restored
  355. event = RETURN_FROM_HIBERNATION;
  356. }
  357. else {
  358. // There was an error attempting to hibernate the system
  359. event = HIBERNATION_ERROR;
  360. }
  361. // Free the UPS registry config block
  362. FreeUPSConfigBlock();
  363. return event;
  364. }
  365. /**
  366. * Hibernate_Exit
  367. *
  368. * Description:
  369. * Performs the actions necessary when transitioning from the HIBERNATE state.
  370. *
  371. * Parameters:
  372. * anEvent The event that caused the transition from the HIBERNATE state.
  373. *
  374. * Returns:
  375. * None
  376. */
  377. void Hibernate_Exit(DWORD anEvent){
  378. // No work to perform
  379. }
  380. /**
  381. * Stopping_Enter
  382. *
  383. * Description:
  384. * Performs the actions necessary when transitioning into the STOPPING state.
  385. *
  386. * Parameters:
  387. * anEvent The event that caused the transition into this state.
  388. *
  389. * Returns:
  390. * None
  391. */
  392. void Stopping_Enter(DWORD anEvent){
  393. // No work to perform
  394. }
  395. /**
  396. * ShuttingDown_DoWork
  397. *
  398. * Description:
  399. * Perform any final cleanup activities.
  400. *
  401. * Parameters:
  402. * None
  403. *
  404. * Returns:
  405. * The event that caused the transition from the STOPPING state.
  406. */
  407. DWORD Stopping_DoWork(){
  408. // Orderly stop the UPS driver (if there is time)
  409. UPSStop();
  410. // Cleanup
  411. FreeUPSConfigBlock();
  412. FreeUPSStatusBlock();
  413. return STOPPED;
  414. }
  415. /**
  416. * Stopping_Exit
  417. *
  418. * Description:
  419. * Performs the actions necessary when transitioning from the STOPPING state.
  420. *
  421. * Parameters:
  422. * anEvent The event that caused the transition from the STOPPING state.
  423. *
  424. * Returns:
  425. * None
  426. */
  427. void Stopping_Exit(DWORD anEvent){
  428. // No work to perform
  429. }