Implementation of GetSystemPowerStatus using ACPI (real submission)

David Lee Lambert lamber45 at cse.msu.edu
Tue May 17 23:21:49 CDT 2005


On Tue, May 17, 2005 at 11:56:22PM -0400, David Lee Lambert wrote:
> WinSCP2 calls this function,  but I don't know why.  I also wrote a 
> command-line Win32 app to make this call.
> 
> Perhaps someone with an APM kernel can backport this...
> 
> I know it looks like it's doing a lot,  but on a system without these two 
> ACPI devices (ac_adapter and battery) it will make two unsuccessful 
> opendir() calls and return a default value.

The previous patch had a debugging-statement left in by mistake.  Sorry.
 
Changelog:
   implemented GetSystemPowerStatus


-- 
David Lee Lambert (also as4109 at wayne.edu)    cell ph# 586-873-8813
PGP key at http://www.cse.msu.edu/~lamber45/newmail.htm#GPGKey
resume at  http://www.cse.msu.edu/~lamber45/resume.htm
-------------- next part --------------
--- dlls/kernel/powermgnt.c.v1_3	Tue May 17 13:26:38 2005
+++ dlls/kernel/powermgnt.c	Wed May 18 00:16:31 2005
@@ -17,7 +17,12 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
+#include <dirent.h>
+#include <math.h>
+#include <stdio.h>
 #include <stdarg.h>
+#include <string.h>
+#include <sys/types.h>
 
 #include "windef.h"
 #include "winbase.h"
@@ -39,8 +44,131 @@
  */
 BOOL WINAPI GetSystemPowerStatus(LPSYSTEM_POWER_STATUS sps_ptr)
 {
-    FIXME("(): stub, harmless.\n");
-    return FALSE;   /* no power management support */
+   const char * ac = "/proc/acpi/ac_adapter/";
+   const char *batt= "/proc/acpi/battery/";
+   DIR * batt_dir,*ac_dir;
+   struct dirent * ent;
+   char fnbuf[40]; /* longer than len(ac)+len(HEXDIGIT*4)+len({state|info}) */
+   FILE * file;
+   char line[80],key[40],arg[40];
+   const char * pattern = " %39[^:]: %39[ -~]"; /* for sscanf */
+
+   /* set defaults */
+   sps_ptr->ACLineStatus = 255;
+   sps_ptr->BatteryFlag  = 255;
+   sps_ptr->BatteryLifePercent = 255;
+   sps_ptr->Reserved1    = 0;
+   sps_ptr->BatteryLifeTime = 0xFFFFFFFF;
+   sps_ptr->BatteryFullLifeTime = 0xFFFFFFFF;
+
+   /* check ac adapter */
+   ac_dir = opendir(ac);
+   if (ac_dir) {
+      while ((ent=readdir(ac_dir))) {
+	 if (ent->d_name[0]=='.') continue;
+	 snprintf(fnbuf,40,"%s%s/state",ac,ent->d_name);
+	 file = fopen(fnbuf,"r");
+	 if (file) {
+	    while (fgets(line,80,file) &&
+		   2==sscanf(line,pattern,key,arg)) {
+	       if (strcmp(key,"state")==0) {
+		  if (strcmp(arg,"on-line")==0) {
+		     sps_ptr->ACLineStatus = 1;
+		  }
+		  if (strcmp(arg,"off-line")==0) {
+		     sps_ptr->ACLineStatus = 0;
+		  }}}
+	    fclose(file);
+	 }}
+      closedir(ac_dir);
+   }
+
+   /* check batteries */
+   batt_dir = opendir(batt);
+   if (batt_dir) {
+      float x,design_capacity=0.0,
+	 design_capacity_warning=0.0,design_capacity_low=0.0,
+	 remaining_capacity=0.0,present_rate=0.0;
+      BOOL any_charging=FALSE;
+      while ((ent=readdir(batt_dir))) {
+	 if (ent->d_name[0]=='.') continue;
+	 snprintf(fnbuf,40,"%s%s/info",batt,ent->d_name);
+	 file = fopen(fnbuf,"r");
+	 if (file) {
+	    while (fgets(line,80,file) &&
+		   2==sscanf(line,pattern,key,arg)) {
+	       if (strcmp(key,"design capacity")==0 &&
+		   sscanf(arg,"%g",&x)==1) {
+		  design_capacity += x;
+	       }
+	       if (strcmp(key,"design capacity warning")==0 &&
+		   sscanf(arg,"%g",&x)==1) {
+		  design_capacity_warning += x;
+	       }
+	       if (strcmp(key,"design capacity low")==0 &&
+		   sscanf(arg,"%g",&x)==1) {
+		  design_capacity_low += x;
+	       }
+	    }
+	    fclose(file);
+	 }
+	 snprintf(fnbuf,40,"%s%s/state",batt,ent->d_name);
+	 file = fopen(fnbuf,"r");
+	 if (file) {
+	    int charging = 0;
+	    while (fgets(line,80,file) &&
+		   2==sscanf(line,pattern,key,arg)) {
+	       if (strcmp(key,"charging state")==0) {
+		  if (strcmp(arg,"charged")==0) {
+		  } else if (strcmp(arg,"discharging")==0) {
+		     charging = -1;
+		  } else if (strcmp(arg,"charging")==0) {
+		     charging = 1;
+		     any_charging = TRUE;
+		  } else {
+		     WARN("Unknown line in %s, '%s: %s'\n",fnbuf,key,arg);
+		  }
+	       } else if (strcmp(key,"present rate")==0
+			  && sscanf(arg,"%g",&x)==1) {
+		  present_rate += charging*x;
+	       } else if (strcmp(key,"remaining capacity")==0
+			  && sscanf(arg,"%g:",&x)==1) {
+		  remaining_capacity += x;
+	       }
+	    }
+	    fclose(file);
+	 }}
+      if (design_capacity > 0.0) {
+	 if (remaining_capacity > design_capacity_warning) {
+	    sps_ptr->BatteryFlag = 1;
+	 } else if (remaining_capacity > design_capacity_low) {
+	    sps_ptr->BatteryFlag = 2;
+	 } else {
+	    sps_ptr->BatteryFlag = 4;
+	 }
+	 if (any_charging) {
+	    sps_ptr->BatteryFlag |= 8;
+	 }
+	 sps_ptr->BatteryLifePercent = floorf(( remaining_capacity/design_capacity*100.0) + 0.499 );
+	 if (present_rate < 0.0) {
+	    /* Linux specifies rates in mWh or mAh */
+	    sps_ptr->BatteryLifeTime =
+	       floorf( remaining_capacity/(-present_rate)
+		       * 3600.0 );
+	    sps_ptr->BatteryFullLifeTime =
+	       floorf( design_capacity/(-present_rate)
+		       * 3600.0 );
+	 }
+      }
+      closedir(batt_dir);
+   }
+
+   /* if we have ACPI but no battery... */
+   if (sps_ptr->ACLineStatus != 255 && sps_ptr->BatteryFlag == 255) {
+      sps_ptr->BatteryFlag = 128;
+   }
+
+   return TRUE;
 }
 
 /***********************************************************************


More information about the wine-patches mailing list