src/power/linux/SDL_syspower.c
changeset 3205 f9a4aa1e1b34
parent 3204 f77f50add24f
child 3206 f735edf338d3
equal deleted inserted replaced
3204:f77f50add24f 3205:f9a4aa1e1b34
    32 #include <dirent.h>
    32 #include <dirent.h>
    33 #include <fcntl.h>
    33 #include <fcntl.h>
    34 
    34 
    35 #include "SDL_power.h"
    35 #include "SDL_power.h"
    36 
    36 
    37 static const char *proc_acpi_path = "/proc/acpi/battery";
    37 static const char *proc_acpi_battery_path = "/proc/acpi/battery";
    38 
    38 static const char *proc_acpi_ac_adapter_path = "/proc/acpi/ac_adapter";
    39 static int open_acpi_file(const char *node, const char *key)
    39 
    40 {
    40 static int open_acpi_file(const char *base, const char *node, const char *key)
    41     const size_t pathlen = strlen(proc_acpi_path)+strlen(node)+strlen(key)+3;
    41 {
       
    42     const size_t pathlen = strlen(base) + strlen(node) + strlen(key) + 3;
    42     char *path = (char *) alloca(pathlen);
    43     char *path = (char *) alloca(pathlen);
    43     if (path == NULL) {
    44     if (path == NULL) {
    44         return -1;  /* oh well. */
    45         return -1;  /* oh well. */
    45     }
    46     }
    46 
    47 
    47     snprintf(path, pathlen, "%s/%s/%s", proc_acpi_path, node, key);
    48     snprintf(path, pathlen, "%s/%s/%s", base, node, key);
    48     return open(path, O_RDONLY);
    49     return open(path, O_RDONLY);
    49 }
    50 }
    50 
    51 
    51 
    52 
    52 static SDL_bool
    53 static SDL_bool
    53 load_acpi_file(const char *node, const char *key, char *buf, size_t buflen)
    54 load_acpi_file(const char *base, const char *node, const char *key,
       
    55                char *buf, size_t buflen)
    54 {
    56 {
    55     ssize_t br = 0;
    57     ssize_t br = 0;
    56     const int fd = open_acpi_file(node, key);
    58     const int fd = open_acpi_file(base, node, key);
    57     if (fd == -1) {
    59     if (fd == -1) {
    58         return SDL_FALSE;
    60         return SDL_FALSE;
    59     }
    61     }
    60     br = read(fd, buf, buflen-1);
    62     br = read(fd, buf, buflen-1);
    61     close(fd);
    63     close(fd);
    64     }
    66     }
    65     buf[br] = '\0';             // null-terminate the string.
    67     buf[br] = '\0';             // null-terminate the string.
    66     return SDL_TRUE;
    68     return SDL_TRUE;
    67 }
    69 }
    68 
    70 
       
    71 
    69 static SDL_bool
    72 static SDL_bool
    70 make_acpi_key_val(char **_ptr, char **_key, char **_val)
    73 make_proc_acpi_key_val(char **_ptr, char **_key, char **_val)
    71 {
    74 {
    72     char *ptr = *_ptr;
    75     char *ptr = *_ptr;
    73 
    76 
    74     while (*ptr == ' ') {
    77     while (*ptr == ' ') {
    75         ptr++;  /* skip whitespace. */
    78         ptr++;  /* skip whitespace. */
   112     *_ptr = ptr;  /* store for next time. */
   115     *_ptr = ptr;  /* store for next time. */
   113     return SDL_TRUE;
   116     return SDL_TRUE;
   114 }
   117 }
   115 
   118 
   116 static void
   119 static void
   117 check_acpi(const char * fname, SDL_bool * have_ac, SDL_bool * have_battery,
   120 check_proc_acpi_battery(const char * node, SDL_bool * have_battery,
   118            SDL_bool * charging, int *seconds, int *percent)
   121                         SDL_bool * charging, int *seconds, int *percent)
   119 {
   122 {
   120     int fd = -1;
   123     const char *base = proc_acpi_battery_path;
   121     char info[1024];
   124     char info[1024];
   122     char state[1024];
   125     char state[1024];
   123     ssize_t br = 0;
       
   124     char *ptr = NULL;
   126     char *ptr = NULL;
   125     char *key = NULL;
   127     char *key = NULL;
   126     char *val = NULL;
   128     char *val = NULL;
   127     SDL_bool charge = SDL_FALSE;
   129     SDL_bool charge = SDL_FALSE;
   128     SDL_bool choose = SDL_FALSE;
   130     SDL_bool choose = SDL_FALSE;
   130     int maximum = -1;
   132     int maximum = -1;
   131     int remaining = -1;
   133     int remaining = -1;
   132     int secs = -1;
   134     int secs = -1;
   133     int pct = -1;
   135     int pct = -1;
   134 
   136 
   135     if (!load_acpi_file(fname, "state", state, sizeof (state))) {
   137     if (!load_acpi_file(base, node, "state", state, sizeof (state))) {
   136         return;
   138         return;
   137     } else if (!load_acpi_file(fname, "info", info, sizeof (info))) {
   139     } else if (!load_acpi_file(base, node, "info", info, sizeof (info))) {
   138         return;
   140         return;
   139     }
   141     }
   140 
   142 
   141     ptr = &state[0];
   143     ptr = &state[0];
   142     while (make_acpi_key_val(&ptr, &key, &val)) {
   144     while (make_proc_acpi_key_val(&ptr, &key, &val)) {
   143         if (strcmp(key, "present") == 0) {
   145         if (strcmp(key, "present") == 0) {
   144             if (strcmp(val, "yes") == 0) {
   146             if (strcmp(val, "yes") == 0) {
   145                 *have_battery = SDL_TRUE;
   147                 *have_battery = SDL_TRUE;
   146             }
   148             }
   147         } else if (strcmp(key, "charging state") == 0) {
   149         } else if (strcmp(key, "charging state") == 0) {
   148             /* !!! FIXME: what exactly _does_ charging/discharging mean? */
   150             /* !!! FIXME: what exactly _does_ charging/discharging mean? */
   149             if (strcmp(val, "charging/discharging") == 0) {
   151             if (strcmp(val, "charging/discharging") == 0) {
   150                 *have_ac = is_ac = SDL_TRUE;
       
   151                 charge = SDL_TRUE;
   152                 charge = SDL_TRUE;
   152             } else if (strcmp(val, "charging") == 0) {
   153             } else if (strcmp(val, "charging") == 0) {
   153                 *have_ac = is_ac = SDL_TRUE;
       
   154                 charge = SDL_TRUE;
       
   155             } else if (strcmp(val, "charged") == 0) {
       
   156                 /* !!! FIXME: maybe another battery is discharging,
       
   157                    !!! FIXME:   instead of AC connection. */
       
   158                 *have_ac = is_ac = SDL_TRUE;
       
   159                 charge = SDL_TRUE;
   154                 charge = SDL_TRUE;
   160             }
   155             }
   161         } else if (strcmp(key, "remaining capacity") == 0) {
   156         } else if (strcmp(key, "remaining capacity") == 0) {
   162             char *endptr = NULL;
   157             char *endptr = NULL;
   163             const int cvt = (int) strtol(val, &endptr, 10);
   158             const int cvt = (int) strtol(val, &endptr, 10);
   164             if (*endptr == ' ') {
   159             if (*endptr == ' ') {
   165                 remaining = cvt;
   160                 remaining = cvt;
   166             }
   161             }
   167         }
   162         }
   168     }
   163     }
   169     
   164 
   170     ptr = &info[0];
   165     ptr = &info[0];
   171     while (make_acpi_key_val(&ptr, &key, &val)) {
   166     while (make_proc_acpi_key_val(&ptr, &key, &val)) {
   172         if (strcmp(key, "design capacity") == 0) {
   167         if (strcmp(key, "design capacity") == 0) {
   173             char *endptr = NULL;
   168             char *endptr = NULL;
   174             const int cvt = (int) strtol(val, &endptr, 10);
   169             const int cvt = (int) strtol(val, &endptr, 10);
   175             if (*endptr == ' ') {
   170             if (*endptr == ' ') {
   176                 maximum = cvt;
   171                 maximum = cvt;
   207     if (choose) {
   202     if (choose) {
   208         *seconds = secs;
   203         *seconds = secs;
   209         *percent = pct;
   204         *percent = pct;
   210         *charging = charge;
   205         *charging = charge;
   211     }
   206     }
   212 
   207 }
   213 }
   208 
       
   209 static void
       
   210 check_proc_acpi_ac_adapter(const char * node, SDL_bool * have_ac)
       
   211 {
       
   212     const char *base = proc_acpi_ac_adapter_path;
       
   213     char state[256];
       
   214     char *ptr = NULL;
       
   215     char *key = NULL;
       
   216     char *val = NULL;
       
   217     SDL_bool charge = SDL_FALSE;
       
   218     SDL_bool choose = SDL_FALSE;
       
   219     SDL_bool is_ac = SDL_FALSE;
       
   220     int maximum = -1;
       
   221     int remaining = -1;
       
   222     int secs = -1;
       
   223     int pct = -1;
       
   224 
       
   225     if (!load_acpi_file(base, node, "state", state, sizeof (state))) {
       
   226         return;
       
   227     }
       
   228 
       
   229     ptr = &state[0];
       
   230     while (make_proc_acpi_key_val(&ptr, &key, &val)) {
       
   231         if (strcmp(key, "state") == 0) {
       
   232             if (strcmp(val, "on-line") == 0) {
       
   233                 *have_ac = SDL_TRUE;
       
   234             }
       
   235         }
       
   236     }
       
   237 }
       
   238 
   214 
   239 
   215 SDL_bool
   240 SDL_bool
   216 SDL_GetPowerInfo_Linux_proc_acpi(SDL_PowerState * state,
   241 SDL_GetPowerInfo_Linux_proc_acpi(SDL_PowerState * state,
   217                                  int *seconds, int *percent)
   242                                  int *seconds, int *percent)
   218 {
   243 {
   219     struct dirent *dent = NULL;
   244     struct dirent *dent = NULL;
   220     DIR *dirp = NULL;
   245     DIR *dirp = NULL;
       
   246     SDL_bool have_battery = SDL_FALSE;
   221     SDL_bool have_ac = SDL_FALSE;
   247     SDL_bool have_ac = SDL_FALSE;
   222     SDL_bool have_battery = SDL_FALSE;
       
   223     SDL_bool charging = SDL_FALSE;
   248     SDL_bool charging = SDL_FALSE;
   224 
   249 
   225     *seconds = -1;
   250     *seconds = -1;
   226     *percent = -1;
   251     *percent = -1;
   227     *state = SDL_POWERSTATE_UNKNOWN;
   252     *state = SDL_POWERSTATE_UNKNOWN;
   228 
   253 
   229     dirp = opendir(proc_acpi_path);
   254     dirp = opendir(proc_acpi_battery_path);
   230     if (dirp == NULL) {
   255     if (dirp == NULL) {
   231         return SDL_FALSE;  /* can't use this interface. */
   256         return SDL_FALSE;  /* can't use this interface. */
   232     }
   257     } else {
   233 
   258         while ((dent = readdir(dirp)) != NULL) {
   234     while ((dent = readdir(dirp)) != NULL) {
   259             const char *node = dent->d_name;
   235         const char *name = dent->d_name;
   260             check_proc_acpi_battery(node, &have_battery, &charging,
   236         check_acpi(name, &have_ac, &have_battery, &charging, seconds, percent);
   261                                     seconds, percent);
       
   262         }
       
   263         closedir(dirp);
       
   264     }
       
   265 
       
   266     dirp = opendir(proc_acpi_ac_adapter_path);
       
   267     if (dirp == NULL) {
       
   268         return SDL_FALSE;  /* can't use this interface. */
       
   269     } else {
       
   270         while ((dent = readdir(dirp)) != NULL) {
       
   271             const char *node = dent->d_name;
       
   272             check_proc_acpi_ac_adapter(node, &have_ac);
       
   273         }
       
   274         closedir(dirp);
   237     }
   275     }
   238 
   276 
   239     if (!have_battery) {
   277     if (!have_battery) {
   240         *state = SDL_POWERSTATE_NO_BATTERY;
   278         *state = SDL_POWERSTATE_NO_BATTERY;
   241     } else if (charging) {
   279     } else if (charging) {