home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / xwplascr.zip / XWPL0208.ZIP / src / startshut / apm.c next >
C/C++ Source or Header  |  2002-02-26  |  12KB  |  333 lines

  1.  
  2. /*
  3.  *@@sourcefile apm.c:
  4.  *      this contains the XFolder APM interface for automatically
  5.  *      turning the computer off after shutdown has completed.
  6.  *      This is mostly used in the context of XShutdown (shutdown.c).
  7.  *
  8.  *      Massive thanks go out to ARAKAWA Atsushi (arakaw@ibm.net)
  9.  *      for filling this in, and to Roman Stangl (rstangl@vnet.ibm.com)
  10.  *      for finding out all the APM stuff in the first place.
  11.  *
  12.  *@@header "startshut\apm.h"
  13.  */
  14.  
  15. /*
  16.  *      Copyright (C) 1998 ARAKAWA Atsushi.
  17.  *      Copyright (C) 1997-2002 Ulrich Möller.
  18.  *      This program is free software; you can redistribute it and/or modify
  19.  *      it under the terms of the GNU General Public License as published by
  20.  *      the Free Software Foundation, in version 2 as it comes in the COPYING
  21.  *      file of the XWorkplace main distribution.
  22.  *      This program is distributed in the hope that it will be useful,
  23.  *      but WITHOUT ANY WARRANTY; without even the implied warranty of
  24.  *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  25.  *      GNU General Public License for more details.
  26.  */
  27.  
  28. #pragma strings(readonly)
  29.  
  30. /*
  31.  *  Suggested #include order:
  32.  *  1)  os2.h
  33.  *  2)  C library headers
  34.  *  3)  setup.h (code generation and debugging options)
  35.  *  4)  headers in helpers\
  36.  *  5)  at least one SOM implementation header (*.ih)
  37.  *  6)  dlgids.h, headers in shared\ (as needed)
  38.  *  7)  headers in implementation dirs (e.g. filesys\, as needed)
  39.  *  8)  #pragma hdrstop and then more SOM headers which crash with precompiled headers
  40.  */
  41.  
  42. #define INCL_DOSPROCESS
  43. #define INCL_DOSERRORS
  44. #define INCL_DOSDEVICES
  45. #define INCL_DOSDEVIOCTL
  46. #include <os2.h>
  47.  
  48. // C library headers
  49. #include <stdio.h>
  50. #include <string.h>
  51.  
  52. // generic headers
  53. #include "setup.h"                      // code generation and debugging options
  54.  
  55. // headers in /helpers
  56. #include "helpers\apmh.h"               // Advanced Power Management helpers
  57.  
  58. // XWorkplace implementation headers
  59. #include "startshut\apm.h"            // APM power-off for XShutdown
  60.  
  61. static HFILE           G_hfAPMSys = NULLHANDLE;
  62. static ULONG           G_ulAPMStat = APM_UNKNOWN;
  63. static USHORT          G_usAPMVersion = 0;
  64. static CHAR            G_szAPMVersion[10];
  65.  
  66. /*
  67.  *@@  apmQueryVersion:
  68.  *      This function returns a PSZ to a static APM
  69.  *      version string, e.g. "1.2".
  70.  *
  71.  *      <B>Usage:</B> any time, esp. on the shutdown
  72.  *      notebook page.
  73.  *
  74.  */
  75.  
  76. PSZ apmQueryVersion(VOID)
  77. {
  78.     if (G_ulAPMStat == APM_UNKNOWN)
  79.         apmPowerOffSupported();
  80.     sprintf(G_szAPMVersion, "%d.%d", G_usAPMVersion>>8, G_usAPMVersion & 0xff);
  81.     return (G_szAPMVersion);
  82. }
  83.  
  84. /*
  85.  *@@  apmPowerOffSupported:
  86.  *      This function returns TRUE if the computer
  87.  *      supports the APM power-off function.
  88.  *
  89.  *      <B>Usage:</B> any time, especially
  90.  *      by the "XDesktop" page in the Desktop's
  91.  *      settings notebook to determine if the "APM power
  92.  *      off" checkbox will be enabled or not (i.e. cannot
  93.  *      be selected).
  94.  *
  95.  *@@changed V0.9.9 (2001-02-28) [umoeller]: now allowing power-off with APM 1.1 also
  96.  */
  97.  
  98. BOOL apmPowerOffSupported(VOID)
  99. {
  100.     USHORT          usBIOSVersion, usDriverVersion;
  101.     APIRET          arc = NO_ERROR;
  102.     ULONG           ulAction = 0;
  103.     GETPOWERINFO    getpowerinfo;
  104.     ULONG           ulAPMRc;
  105.     ULONG           ulPacketSize;
  106.     ULONG           ulDataSize;
  107.  
  108.     if (G_ulAPMStat == APM_UNKNOWN)
  109.     {
  110.         // open APM.SYS
  111.         ulAction = 0;
  112.         arc = DosOpen("\\DEV\\APM$", &G_hfAPMSys, &ulAction, 0, FILE_NORMAL,
  113.                       OPEN_ACTION_OPEN_IF_EXISTS,
  114.                       OPEN_FLAGS_FAIL_ON_ERROR | OPEN_SHARE_DENYNONE | OPEN_ACCESS_READWRITE,
  115.                       NULL);
  116.         if (arc == NO_ERROR)
  117.         {
  118.             // query version of APM-BIOS and APM driver
  119.             memset(&getpowerinfo, 0, sizeof(getpowerinfo));
  120.             getpowerinfo.usParmLength = sizeof(getpowerinfo);
  121.             ulPacketSize = sizeof(getpowerinfo);
  122.             ulAPMRc = 0;
  123.             ulDataSize = sizeof(ulAPMRc);
  124.             arc = DosDevIOCtl(G_hfAPMSys, IOCTL_POWER,
  125.                               POWER_GETPOWERINFO,
  126.                               &getpowerinfo, ulPacketSize, &ulPacketSize,
  127.                               &ulAPMRc, ulDataSize, &ulDataSize);
  128.             if ((arc == NO_ERROR) && (ulAPMRc == NO_ERROR))
  129.             {
  130.                 // swap lower-byte(major vers.) to higher-byte(minor vers.)
  131.                 usBIOSVersion = (getpowerinfo.usBIOSVersion & 0xff) <<8 |
  132.                     (getpowerinfo.usBIOSVersion >>8);
  133.                 usDriverVersion = (getpowerinfo.usDriverVersion & 0xff) <<8 |
  134.                     (getpowerinfo.usDriverVersion >>8);
  135.                 // set general APM version to lower
  136.                 G_usAPMVersion = (usBIOSVersion < usDriverVersion)
  137.                     ? usBIOSVersion : usDriverVersion;
  138.  
  139.                 // check APM version whether power-off is supported
  140.                 // if (G_usAPMVersion >= 0x102)  // version 1.2 or above
  141.                 // changed V0.9.9 (2001-02-28) [umoeller]:
  142.                 if (G_usAPMVersion >= 0x101)  // version 1.1 or above
  143.                     G_ulAPMStat = APM_OK;
  144.                 else
  145.                     G_ulAPMStat = APM_IGNORE;
  146.  
  147.             }
  148.             else
  149.             {
  150.                 // DosDevIOCtl failed
  151.                 G_ulAPMStat = APM_IGNORE;
  152.                 G_usAPMVersion = 0;
  153.             }
  154.             DosClose(G_hfAPMSys);
  155.         }
  156.         else
  157.         {
  158.             // DosOpen failed; APM.SYS is not loaded
  159.             G_ulAPMStat = APM_IGNORE;
  160.             G_usAPMVersion = 0;
  161.         }
  162.     }
  163.     return (G_ulAPMStat == APM_OK);
  164. }
  165.  
  166. /*
  167.  *@@ apmPreparePowerOff:
  168.  *      This function is called _once_ by XShutdown while
  169.  *      the system is being shut down, if apmPowerOffSupported
  170.  *      above returned TRUE. This call happens
  171.  *      after all windows have been closed, but
  172.  *      before DosShutdown is called, so you may
  173.  *      open the APM.SYS device driver here and
  174.  *      do other preparations you might need.
  175.  *
  176.  *      After this, you must return _one_ of the
  177.  *      following flags:
  178.  *      --  APM_OK:  go ahead with XShutdown and call
  179.  *                   apmDoPowerOff later.
  180.  *      --  APM_IGNORE: go ahead with XShutdown and do
  181.  *                   _not_ call apmDoPowerOff later;
  182.  *                   this will lead to the normal
  183.  *                   "Press Ctrl+Alt+Del" window.
  184.  *      --  APM_CANCEL: cancel shutdown and present the
  185.  *                   error message which you must
  186.  *                   then copy to pszError, which
  187.  *                   points to a buffer 500 bytes in
  188.  *                   size.
  189.  *
  190.  *      ORed with _one_ or _none_ of the following:
  191.  *      --  APM_DOSSHUTDOWN_0:
  192.  *                   set this flag if XFolder should
  193.  *                   call DosShutdown(0); this is _not_
  194.  *                   recommended, because this would block
  195.  *                   any subsequent DosDevIOCtl calls.
  196.  *      --  APM_DOSSHUTDOWN_1:
  197.  *                   the same for DosShutdown(1), which is
  198.  *                   recommended.
  199.  *
  200.  *      If you return APM_OK only without either
  201.  *      APM_DOSSHUTDOWN_0 or APM_DOSSHUTDOWN_1,
  202.  *      XFolder will call apmDoPowerOff later,
  203.  *      but without having called DosShutdown.
  204.  *      You MUST do this yourself then.
  205.  *      This will however prevent XFolder from
  206.  *      presenting the proper informational windows
  207.  *      to the user.
  208.  *
  209.  *      The buffer that pszError points to is only
  210.  *      evaluated if you return APM_CANCEL.
  211.  */
  212.  
  213. ULONG apmPreparePowerOff(PSZ pszError)      // in: error message
  214. {
  215.     APIRET          arc = NO_ERROR;
  216.     ULONG           ulAction = 0;
  217.     SENDPOWEREVENT  sendpowerevent;
  218.     ULONG           ulAPMRc;
  219.     ULONG           ulPacketSize;
  220.     ULONG           ulDataSize;
  221.  
  222.     // open APM.SYS
  223.     ulAction = 0;
  224.     arc = DosOpen("\\DEV\\APM$",
  225.                   &G_hfAPMSys,
  226.                   &ulAction,
  227.                   0,
  228.                   FILE_NORMAL,
  229.                   OPEN_ACTION_OPEN_IF_EXISTS,
  230.                   OPEN_FLAGS_FAIL_ON_ERROR | OPEN_SHARE_DENYNONE | OPEN_ACCESS_READWRITE,
  231.                   NULL);
  232.     if (arc != NO_ERROR)
  233.     {
  234.         strcpy(pszError, "Cannot open APM driver.");
  235.         return (APM_CANCEL);
  236.     }
  237.     // enable APM feature
  238.     memset(&sendpowerevent, 0, sizeof(sendpowerevent));
  239.     ulAPMRc = 0;
  240.     sendpowerevent.usSubID = POWER_SUBID_ENABLE_APM;
  241.     ulPacketSize = sizeof(sendpowerevent);
  242.     ulDataSize = sizeof(ulAPMRc);
  243.     arc = DosDevIOCtl(G_hfAPMSys,
  244.                       IOCTL_POWER,
  245.                       POWER_SENDPOWEREVENT,
  246.                       &sendpowerevent, ulPacketSize, &ulPacketSize,
  247.                       &ulAPMRc, ulDataSize, &ulDataSize);
  248.     if (    (arc != NO_ERROR)
  249.          || (ulAPMRc != NO_ERROR)
  250.        )
  251.     {
  252.         strcpy(pszError, "Cannot enable APM.");
  253.         return (APM_CANCEL);
  254.     }
  255.  
  256.     return (APM_OK | APM_DOSSHUTDOWN_1);
  257. }
  258.  
  259. /*
  260.  *@@ apmDoPowerOff:
  261.  *      If apmPreparePowerOff returned with the APM_OK flag set,
  262.  *      XFolder calls this function after it is
  263.  *      done with XShutdown. In this function,
  264.  *      you should call the APM function which
  265.  *      turns off the computer's power. If you
  266.  *      have not specified one of the APM_DOSSHUTDOWN
  267.  *      flags in apmPreparePowerOff, you must call DosShutdown
  268.  *      yourself here.
  269.  *
  270.  *      <P><B>Usage:</B>
  271.  *      only once after XShutdown.
  272.  *      We do not return from this function, but stay in an infinite loop.
  273.  *
  274.  *      <P><B>Parameters:</B>
  275.  *      none.
  276.  *      </LL>
  277.  *
  278.  *@@changed V0.9.2 (2000-03-04) [umoeller]: added "APM delay" support
  279.  */
  280.  
  281. VOID apmDoPowerOff(BOOL fDelay)
  282. {
  283.     APIRET          arc = NO_ERROR;
  284.     SENDPOWEREVENT  sendpowerevent;
  285.     USHORT          usAPMRc;
  286.     ULONG           ulPacketSize;
  287.     ULONG           ulDataSize;
  288.     ULONG           ul;
  289.  
  290.     memset(&sendpowerevent, 0, sizeof(sendpowerevent));
  291.     usAPMRc = 0;
  292.     sendpowerevent.usSubID = POWER_SUBID_SET_POWER_STATE;
  293.     sendpowerevent.usData1 = POWER_DEVID_ALL_DEVICES;
  294.     sendpowerevent.usData2 = POWER_STATE_OFF;
  295.     ulPacketSize = sizeof(sendpowerevent);
  296.     ulDataSize = sizeof(usAPMRc);
  297.  
  298.     if (fDelay)
  299.     {
  300.         // try another pause of 3 seconds; maybe DosShutdown is
  301.         // still running V0.9.2 (2000-02-29) [umoeller]
  302.         for (ul = 0;
  303.              ul < 3;
  304.              ul++)
  305.         {
  306.             DosBeep(4000, 10);
  307.             DosSleep(1000);
  308.         }
  309.         DosBeep(8000, 10);
  310.     }
  311.  
  312.     // this initiates the APM power-off
  313.     arc = DosDevIOCtl(G_hfAPMSys,
  314.                       IOCTL_POWER,
  315.                       POWER_SENDPOWEREVENT,
  316.                       &sendpowerevent, ulPacketSize, &ulPacketSize,
  317.                       &usAPMRc, ulDataSize, &ulDataSize);
  318.     DosClose(G_hfAPMSys);
  319.  
  320.     // OS/2 _does_ return from that function, but in the
  321.     // background APM power-off is now being executed.
  322.     // So we must now loop forever until power-off has
  323.     // completed, when the computer will just stop
  324.     // executing anything.
  325.  
  326.     // We must _not_ return to the XFolder shutdown routines,
  327.     // because XFolder would then enter a critical section,
  328.     // which would keep power-off from working.
  329.     while (TRUE)
  330.         DosSleep(10000);
  331. }
  332.  
  333.