src/power/linux/SDL_syspower.c
author Ryan C. Gordon
Tue, 29 Dec 2015 02:29:56 -0500
changeset 9986 081fbd89a347
parent 9700 d8cc85e50561
child 9998 f67cf37e9cd4
permissions -rw-r--r--
NetBSD: improved joystick support (thanks, Thomas!).

This patch skips non-joystick HID devices and gives joysticks on NetBSD
a human readable name.

Fixes Bugzilla #3178.
icculus@3170
     1
/*
slouken@5535
     2
  Simple DirectMedia Layer
slouken@9619
     3
  Copyright (C) 1997-2015 Sam Lantinga <slouken@libsdl.org>
icculus@3170
     4
slouken@5535
     5
  This software is provided 'as-is', without any express or implied
slouken@5535
     6
  warranty.  In no event will the authors be held liable for any damages
slouken@5535
     7
  arising from the use of this software.
icculus@3170
     8
slouken@5535
     9
  Permission is granted to anyone to use this software for any purpose,
slouken@5535
    10
  including commercial applications, and to alter it and redistribute it
slouken@5535
    11
  freely, subject to the following restrictions:
icculus@3170
    12
slouken@5535
    13
  1. The origin of this software must not be misrepresented; you must not
slouken@5535
    14
     claim that you wrote the original software. If you use this software
slouken@5535
    15
     in a product, an acknowledgment in the product documentation would be
slouken@5535
    16
     appreciated but is not required.
slouken@5535
    17
  2. Altered source versions must be plainly marked as such, and must not be
slouken@5535
    18
     misrepresented as being the original software.
slouken@5535
    19
  3. This notice may not be removed or altered from any source distribution.
icculus@3170
    20
*/
icculus@8093
    21
#include "../../SDL_internal.h"
icculus@3170
    22
icculus@3170
    23
#ifndef SDL_POWER_DISABLED
slouken@6044
    24
#if SDL_POWER_LINUX
icculus@3170
    25
icculus@3170
    26
#include <stdio.h>
icculus@3170
    27
#include <unistd.h>
icculus@3170
    28
bob@3174
    29
#include <sys/types.h>
bob@3174
    30
#include <sys/stat.h>
icculus@3203
    31
#include <dirent.h>
bob@3174
    32
#include <fcntl.h>
bob@3174
    33
icculus@3170
    34
#include "SDL_power.h"
icculus@3170
    35
icculus@3207
    36
static const char *proc_apm_path = "/proc/apm";
icculus@3205
    37
static const char *proc_acpi_battery_path = "/proc/acpi/battery";
icculus@3205
    38
static const char *proc_acpi_ac_adapter_path = "/proc/acpi/ac_adapter";
icculus@9700
    39
static const char *sys_class_power_supply_path = "/sys/class/power_supply";
icculus@3203
    40
icculus@9700
    41
static int
icculus@9700
    42
open_power_file(const char *base, const char *node, const char *key)
icculus@3203
    43
{
icculus@3205
    44
    const size_t pathlen = strlen(base) + strlen(node) + strlen(key) + 3;
icculus@3203
    45
    char *path = (char *) alloca(pathlen);
icculus@3203
    46
    if (path == NULL) {
icculus@3203
    47
        return -1;  /* oh well. */
icculus@3203
    48
    }
icculus@3203
    49
icculus@3205
    50
    snprintf(path, pathlen, "%s/%s/%s", base, node, key);
icculus@3203
    51
    return open(path, O_RDONLY);
icculus@3203
    52
}
icculus@3203
    53
icculus@3203
    54
icculus@3203
    55
static SDL_bool
icculus@9700
    56
read_power_file(const char *base, const char *node, const char *key,
icculus@9700
    57
                char *buf, size_t buflen)
icculus@3203
    58
{
icculus@3203
    59
    ssize_t br = 0;
icculus@9700
    60
    const int fd = open_power_file(base, node, key);
icculus@3170
    61
    if (fd == -1) {
icculus@3203
    62
        return SDL_FALSE;
icculus@3203
    63
    }
icculus@3203
    64
    br = read(fd, buf, buflen-1);
icculus@3203
    65
    close(fd);
icculus@3203
    66
    if (br < 0) {
icculus@3203
    67
        return SDL_FALSE;
icculus@3203
    68
    }
slouken@7191
    69
    buf[br] = '\0';             /* null-terminate the string. */
icculus@3203
    70
    return SDL_TRUE;
icculus@3203
    71
}
icculus@3203
    72
icculus@3205
    73
icculus@3203
    74
static SDL_bool
icculus@3205
    75
make_proc_acpi_key_val(char **_ptr, char **_key, char **_val)
icculus@3203
    76
{
icculus@3203
    77
    char *ptr = *_ptr;
icculus@3203
    78
icculus@3203
    79
    while (*ptr == ' ') {
icculus@3203
    80
        ptr++;  /* skip whitespace. */
icculus@3203
    81
    }
icculus@3203
    82
icculus@3203
    83
    if (*ptr == '\0') {
icculus@3203
    84
        return SDL_FALSE;  /* EOF. */
icculus@3203
    85
    }
icculus@3203
    86
icculus@3203
    87
    *_key = ptr;
icculus@3203
    88
icculus@3203
    89
    while ((*ptr != ':') && (*ptr != '\0')) {
icculus@3203
    90
        ptr++;
icculus@3203
    91
    }
icculus@3203
    92
icculus@3203
    93
    if (*ptr == '\0') {
icculus@3203
    94
        return SDL_FALSE;  /* (unexpected) EOF. */
icculus@3203
    95
    }
icculus@3203
    96
icculus@3203
    97
    *(ptr++) = '\0';  /* terminate the key. */
icculus@3203
    98
icculus@3203
    99
    while ((*ptr == ' ') && (*ptr != '\0')) {
icculus@3203
   100
        ptr++;  /* skip whitespace. */
icculus@3203
   101
    }
icculus@3203
   102
icculus@3203
   103
    if (*ptr == '\0') {
icculus@3203
   104
        return SDL_FALSE;  /* (unexpected) EOF. */
icculus@3203
   105
    }
icculus@3203
   106
icculus@3203
   107
    *_val = ptr;
icculus@3203
   108
icculus@3203
   109
    while ((*ptr != '\n') && (*ptr != '\0')) {
icculus@3203
   110
        ptr++;
icculus@3203
   111
    }
icculus@3203
   112
icculus@3203
   113
    if (*ptr != '\0') {
icculus@3203
   114
        *(ptr++) = '\0';  /* terminate the value. */
icculus@3170
   115
    }
icculus@3203
   116
icculus@3203
   117
    *_ptr = ptr;  /* store for next time. */
icculus@3170
   118
    return SDL_TRUE;
icculus@3203
   119
}
icculus@3203
   120
icculus@3203
   121
static void
icculus@3205
   122
check_proc_acpi_battery(const char * node, SDL_bool * have_battery,
icculus@3205
   123
                        SDL_bool * charging, int *seconds, int *percent)
icculus@3203
   124
{
icculus@3205
   125
    const char *base = proc_acpi_battery_path;
icculus@3203
   126
    char info[1024];
icculus@3203
   127
    char state[1024];
icculus@3203
   128
    char *ptr = NULL;
icculus@3203
   129
    char *key = NULL;
icculus@3203
   130
    char *val = NULL;
icculus@3203
   131
    SDL_bool charge = SDL_FALSE;
icculus@3203
   132
    SDL_bool choose = SDL_FALSE;
icculus@3203
   133
    int maximum = -1;
icculus@3203
   134
    int remaining = -1;
icculus@3203
   135
    int secs = -1;
icculus@3203
   136
    int pct = -1;
icculus@3203
   137
icculus@9700
   138
    if (!read_power_file(base, node, "state", state, sizeof (state))) {
icculus@3203
   139
        return;
icculus@9700
   140
    } else if (!read_power_file(base, node, "info", info, sizeof (info))) {
icculus@3203
   141
        return;
icculus@3203
   142
    }
icculus@3203
   143
icculus@3203
   144
    ptr = &state[0];
icculus@3205
   145
    while (make_proc_acpi_key_val(&ptr, &key, &val)) {
icculus@3203
   146
        if (strcmp(key, "present") == 0) {
icculus@3203
   147
            if (strcmp(val, "yes") == 0) {
icculus@3203
   148
                *have_battery = SDL_TRUE;
icculus@3203
   149
            }
icculus@3203
   150
        } else if (strcmp(key, "charging state") == 0) {
icculus@3203
   151
            /* !!! FIXME: what exactly _does_ charging/discharging mean? */
icculus@3203
   152
            if (strcmp(val, "charging/discharging") == 0) {
icculus@3203
   153
                charge = SDL_TRUE;
icculus@3203
   154
            } else if (strcmp(val, "charging") == 0) {
icculus@3203
   155
                charge = SDL_TRUE;
icculus@3203
   156
            }
icculus@3203
   157
        } else if (strcmp(key, "remaining capacity") == 0) {
icculus@3203
   158
            char *endptr = NULL;
icculus@3203
   159
            const int cvt = (int) strtol(val, &endptr, 10);
icculus@3203
   160
            if (*endptr == ' ') {
icculus@3203
   161
                remaining = cvt;
icculus@3203
   162
            }
icculus@3203
   163
        }
icculus@3203
   164
    }
icculus@3205
   165
icculus@3203
   166
    ptr = &info[0];
icculus@3205
   167
    while (make_proc_acpi_key_val(&ptr, &key, &val)) {
icculus@3203
   168
        if (strcmp(key, "design capacity") == 0) {
icculus@3203
   169
            char *endptr = NULL;
icculus@3203
   170
            const int cvt = (int) strtol(val, &endptr, 10);
icculus@3203
   171
            if (*endptr == ' ') {
icculus@3203
   172
                maximum = cvt;
icculus@3203
   173
            }
icculus@3203
   174
        }
icculus@3203
   175
    }
icculus@3203
   176
icculus@3203
   177
    if ((maximum >= 0) && (remaining >= 0)) {
icculus@3203
   178
        pct = (int) ((((float) remaining) / ((float) maximum)) * 100.0f);
icculus@3203
   179
        if (pct < 0) {
icculus@3203
   180
            pct = 0;
icculus@3203
   181
        } else if (pct > 100) {
icculus@3203
   182
            pct = 100;
icculus@3203
   183
        }
icculus@3203
   184
    }
icculus@3203
   185
icculus@3203
   186
    /* !!! FIXME: calculate (secs). */
icculus@3203
   187
icculus@3203
   188
    /*
icculus@3203
   189
     * We pick the battery that claims to have the most minutes left.
icculus@3203
   190
     *  (failing a report of minutes, we'll take the highest percent.)
icculus@3203
   191
     */
icculus@3203
   192
    if ((secs < 0) && (*seconds < 0)) {
icculus@3203
   193
        if ((pct < 0) && (*percent < 0)) {
icculus@3203
   194
            choose = SDL_TRUE;  /* at least we know there's a battery. */
icculus@3203
   195
        }
icculus@3203
   196
        if (pct > *percent) {
icculus@3203
   197
            choose = SDL_TRUE;
icculus@3203
   198
        }
icculus@3203
   199
    } else if (secs > *seconds) {
icculus@3203
   200
        choose = SDL_TRUE;
icculus@3203
   201
    }
icculus@3203
   202
icculus@3203
   203
    if (choose) {
icculus@3203
   204
        *seconds = secs;
icculus@3203
   205
        *percent = pct;
icculus@3203
   206
        *charging = charge;
icculus@3203
   207
    }
icculus@3205
   208
}
icculus@3203
   209
icculus@3205
   210
static void
icculus@3205
   211
check_proc_acpi_ac_adapter(const char * node, SDL_bool * have_ac)
icculus@3205
   212
{
icculus@3205
   213
    const char *base = proc_acpi_ac_adapter_path;
icculus@3205
   214
    char state[256];
icculus@3205
   215
    char *ptr = NULL;
icculus@3205
   216
    char *key = NULL;
icculus@3205
   217
    char *val = NULL;
icculus@3205
   218
icculus@9700
   219
    if (!read_power_file(base, node, "state", state, sizeof (state))) {
icculus@3205
   220
        return;
icculus@3205
   221
    }
icculus@3205
   222
icculus@3205
   223
    ptr = &state[0];
icculus@3205
   224
    while (make_proc_acpi_key_val(&ptr, &key, &val)) {
icculus@3205
   225
        if (strcmp(key, "state") == 0) {
icculus@3205
   226
            if (strcmp(val, "on-line") == 0) {
icculus@3205
   227
                *have_ac = SDL_TRUE;
icculus@3205
   228
            }
icculus@3205
   229
        }
icculus@3205
   230
    }
icculus@3170
   231
}
icculus@3170
   232
icculus@3205
   233
icculus@3170
   234
SDL_bool
slouken@3186
   235
SDL_GetPowerInfo_Linux_proc_acpi(SDL_PowerState * state,
slouken@3186
   236
                                 int *seconds, int *percent)
icculus@3170
   237
{
icculus@3203
   238
    struct dirent *dent = NULL;
icculus@3203
   239
    DIR *dirp = NULL;
icculus@3205
   240
    SDL_bool have_battery = SDL_FALSE;
icculus@3203
   241
    SDL_bool have_ac = SDL_FALSE;
icculus@3203
   242
    SDL_bool charging = SDL_FALSE;
icculus@3203
   243
icculus@3203
   244
    *seconds = -1;
icculus@3203
   245
    *percent = -1;
icculus@3203
   246
    *state = SDL_POWERSTATE_UNKNOWN;
icculus@3203
   247
icculus@3205
   248
    dirp = opendir(proc_acpi_battery_path);
icculus@3203
   249
    if (dirp == NULL) {
icculus@3203
   250
        return SDL_FALSE;  /* can't use this interface. */
icculus@3205
   251
    } else {
icculus@3205
   252
        while ((dent = readdir(dirp)) != NULL) {
icculus@3205
   253
            const char *node = dent->d_name;
icculus@3205
   254
            check_proc_acpi_battery(node, &have_battery, &charging,
icculus@3205
   255
                                    seconds, percent);
icculus@3205
   256
        }
icculus@3205
   257
        closedir(dirp);
icculus@3170
   258
    }
icculus@3203
   259
icculus@3205
   260
    dirp = opendir(proc_acpi_ac_adapter_path);
icculus@3205
   261
    if (dirp == NULL) {
icculus@3205
   262
        return SDL_FALSE;  /* can't use this interface. */
icculus@3205
   263
    } else {
icculus@3205
   264
        while ((dent = readdir(dirp)) != NULL) {
icculus@3205
   265
            const char *node = dent->d_name;
icculus@3205
   266
            check_proc_acpi_ac_adapter(node, &have_ac);
icculus@3205
   267
        }
icculus@3205
   268
        closedir(dirp);
icculus@3203
   269
    }
icculus@3203
   270
icculus@3203
   271
    if (!have_battery) {
icculus@3203
   272
        *state = SDL_POWERSTATE_NO_BATTERY;
icculus@3203
   273
    } else if (charging) {
icculus@3203
   274
        *state = SDL_POWERSTATE_CHARGING;
icculus@3203
   275
    } else if (have_ac) {
icculus@3203
   276
        *state = SDL_POWERSTATE_CHARGED;
icculus@3203
   277
    } else {
icculus@3203
   278
        *state = SDL_POWERSTATE_ON_BATTERY;
icculus@3203
   279
    }
icculus@3203
   280
icculus@3203
   281
    return SDL_TRUE;   /* definitive answer. */
icculus@3170
   282
}
icculus@3170
   283
icculus@3203
   284
icculus@3170
   285
static SDL_bool
icculus@3170
   286
next_string(char **_ptr, char **_str)
icculus@3170
   287
{
icculus@3170
   288
    char *ptr = *_ptr;
icculus@3170
   289
    char *str = *_str;
icculus@3170
   290
slouken@3186
   291
    while (*ptr == ' ') {       /* skip any spaces... */
icculus@3170
   292
        ptr++;
icculus@3170
   293
    }
icculus@3170
   294
icculus@3170
   295
    if (*ptr == '\0') {
icculus@3170
   296
        return SDL_FALSE;
icculus@3170
   297
    }
icculus@3170
   298
icculus@3170
   299
    str = ptr;
icculus@3203
   300
    while ((*ptr != ' ') && (*ptr != '\n') && (*ptr != '\0'))
icculus@3170
   301
        ptr++;
icculus@3170
   302
icculus@3170
   303
    if (*ptr != '\0')
icculus@3170
   304
        *(ptr++) = '\0';
icculus@3170
   305
icculus@3170
   306
    *_str = str;
icculus@3170
   307
    *_ptr = ptr;
icculus@3170
   308
    return SDL_TRUE;
icculus@3170
   309
}
icculus@3170
   310
icculus@3170
   311
static SDL_bool
icculus@3170
   312
int_string(char *str, int *val)
icculus@3170
   313
{
icculus@3170
   314
    char *endptr = NULL;
icculus@3206
   315
    *val = (int) strtol(str, &endptr, 0);
icculus@3170
   316
    return ((*str != '\0') && (*endptr == '\0'));
icculus@3170
   317
}
icculus@3170
   318
icculus@3170
   319
/* http://lxr.linux.no/linux+v2.6.29/drivers/char/apm-emulation.c */
icculus@3170
   320
SDL_bool
slouken@3186
   321
SDL_GetPowerInfo_Linux_proc_apm(SDL_PowerState * state,
slouken@3186
   322
                                int *seconds, int *percent)
icculus@3170
   323
{
icculus@3170
   324
    SDL_bool need_details = SDL_FALSE;
icculus@3170
   325
    int ac_status = 0;
icculus@3170
   326
    int battery_status = 0;
icculus@3170
   327
    int battery_flag = 0;
icculus@3170
   328
    int battery_percent = 0;
icculus@3170
   329
    int battery_time = 0;
icculus@3207
   330
    const int fd = open(proc_apm_path, O_RDONLY);
icculus@3170
   331
    char buf[128];
icculus@3170
   332
    char *ptr = &buf[0];
icculus@3170
   333
    char *str = NULL;
icculus@3170
   334
    ssize_t br;
icculus@3170
   335
icculus@3170
   336
    if (fd == -1) {
slouken@3186
   337
        return SDL_FALSE;       /* can't use this interface. */
icculus@3170
   338
    }
icculus@3170
   339
icculus@3203
   340
    br = read(fd, buf, sizeof (buf) - 1);
icculus@3170
   341
    close(fd);
icculus@3170
   342
icculus@3170
   343
    if (br < 0) {
icculus@3170
   344
        return SDL_FALSE;
icculus@3170
   345
    }
icculus@3170
   346
slouken@7191
   347
    buf[br] = '\0';             /* null-terminate the string. */
slouken@3186
   348
    if (!next_string(&ptr, &str)) {     /* driver version */
icculus@3170
   349
        return SDL_FALSE;
icculus@3170
   350
    }
slouken@3186
   351
    if (!next_string(&ptr, &str)) {     /* BIOS version */
icculus@3170
   352
        return SDL_FALSE;
icculus@3170
   353
    }
slouken@3186
   354
    if (!next_string(&ptr, &str)) {     /* APM flags */
icculus@3170
   355
        return SDL_FALSE;
icculus@3170
   356
    }
icculus@3170
   357
slouken@3186
   358
    if (!next_string(&ptr, &str)) {     /* AC line status */
icculus@3170
   359
        return SDL_FALSE;
icculus@3170
   360
    } else if (!int_string(str, &ac_status)) {
icculus@3170
   361
        return SDL_FALSE;
icculus@3170
   362
    }
icculus@3170
   363
slouken@3186
   364
    if (!next_string(&ptr, &str)) {     /* battery status */
icculus@3170
   365
        return SDL_FALSE;
icculus@3170
   366
    } else if (!int_string(str, &battery_status)) {
icculus@3170
   367
        return SDL_FALSE;
icculus@3170
   368
    }
slouken@3186
   369
    if (!next_string(&ptr, &str)) {     /* battery flag */
icculus@3170
   370
        return SDL_FALSE;
icculus@3170
   371
    } else if (!int_string(str, &battery_flag)) {
icculus@3170
   372
        return SDL_FALSE;
icculus@3170
   373
    }
slouken@3186
   374
    if (!next_string(&ptr, &str)) {     /* remaining battery life percent */
icculus@3170
   375
        return SDL_FALSE;
icculus@3170
   376
    }
icculus@3170
   377
    if (str[strlen(str) - 1] == '%') {
icculus@3170
   378
        str[strlen(str) - 1] = '\0';
icculus@3170
   379
    }
icculus@3170
   380
    if (!int_string(str, &battery_percent)) {
icculus@3170
   381
        return SDL_FALSE;
icculus@3170
   382
    }
icculus@3170
   383
slouken@3186
   384
    if (!next_string(&ptr, &str)) {     /* remaining battery life time */
icculus@3170
   385
        return SDL_FALSE;
icculus@3170
   386
    } else if (!int_string(str, &battery_time)) {
icculus@3170
   387
        return SDL_FALSE;
icculus@3170
   388
    }
icculus@3170
   389
slouken@3186
   390
    if (!next_string(&ptr, &str)) {     /* remaining battery life time units */
icculus@3170
   391
        return SDL_FALSE;
icculus@3170
   392
    } else if (strcmp(str, "min") == 0) {
icculus@3170
   393
        battery_time *= 60;
icculus@3170
   394
    }
icculus@3170
   395
slouken@3186
   396
    if (battery_flag == 0xFF) { /* unknown state */
icculus@3170
   397
        *state = SDL_POWERSTATE_UNKNOWN;
slouken@3186
   398
    } else if (battery_flag & (1 << 7)) {       /* no battery */
icculus@3170
   399
        *state = SDL_POWERSTATE_NO_BATTERY;
slouken@3186
   400
    } else if (battery_flag & (1 << 3)) {       /* charging */
icculus@3170
   401
        *state = SDL_POWERSTATE_CHARGING;
icculus@3170
   402
        need_details = SDL_TRUE;
icculus@3170
   403
    } else if (ac_status == 1) {
slouken@3186
   404
        *state = SDL_POWERSTATE_CHARGED;        /* on AC, not charging. */
icculus@3170
   405
        need_details = SDL_TRUE;
icculus@3170
   406
    } else {
icculus@3170
   407
        *state = SDL_POWERSTATE_ON_BATTERY;
icculus@3170
   408
        need_details = SDL_TRUE;
icculus@3170
   409
    }
icculus@3170
   410
icculus@3170
   411
    *percent = -1;
icculus@3170
   412
    *seconds = -1;
icculus@3170
   413
    if (need_details) {
icculus@3170
   414
        const int pct = battery_percent;
icculus@3170
   415
        const int secs = battery_time;
icculus@3170
   416
slouken@3186
   417
        if (pct >= 0) {         /* -1 == unknown */
slouken@3186
   418
            *percent = (pct > 100) ? 100 : pct; /* clamp between 0%, 100% */
icculus@3170
   419
        }
slouken@3186
   420
        if (secs >= 0) {        /* -1 == unknown */
icculus@3170
   421
            *seconds = secs;
icculus@3170
   422
        }
icculus@3170
   423
    }
icculus@3170
   424
icculus@3170
   425
    return SDL_TRUE;
icculus@3170
   426
}
icculus@3170
   427
icculus@9700
   428
/* !!! FIXME: implement d-bus queries to org.freedesktop.UPower. */
icculus@9700
   429
icculus@9700
   430
SDL_bool
icculus@9700
   431
SDL_GetPowerInfo_Linux_sys_class_power_supply(SDL_PowerState *state, int *seconds, int *percent)
icculus@9700
   432
{
icculus@9700
   433
    const char *base = sys_class_power_supply_path;
icculus@9700
   434
    struct dirent *dent;
icculus@9700
   435
    DIR *dirp;
icculus@9700
   436
icculus@9700
   437
    dirp = opendir(base);
icculus@9700
   438
    if (!dirp) {
icculus@9700
   439
        return SDL_FALSE;
icculus@9700
   440
    }
icculus@9700
   441
icculus@9700
   442
    *state = SDL_POWERSTATE_NO_BATTERY;  /* assume we're just plugged in. */
icculus@9700
   443
    *seconds = -1;
icculus@9700
   444
    *percent = -1;
icculus@9700
   445
icculus@9700
   446
    while ((dent = readdir(dirp)) != NULL) {
icculus@9700
   447
        const char *name = dent->d_name;
icculus@9700
   448
        SDL_bool choose = SDL_FALSE;
icculus@9700
   449
        char str[64];
icculus@9700
   450
        SDL_PowerState st;
icculus@9700
   451
        int secs;
icculus@9700
   452
        int pct;
icculus@9700
   453
icculus@9700
   454
        if ((SDL_strcmp(name, ".") == 0) || (SDL_strcmp(name, "..") == 0)) {
icculus@9700
   455
            continue;  /* skip these, of course. */
icculus@9700
   456
        } else if (!read_power_file(base, name, "type", str, sizeof (str))) {
icculus@9700
   457
            continue;  /* Don't know _what_ we're looking at. Give up on it. */
icculus@9700
   458
        } else if (SDL_strcmp(str, "Battery\n") != 0) {
icculus@9700
   459
            continue;  /* we don't care about UPS and such. */
icculus@9700
   460
        }
icculus@9700
   461
icculus@9700
   462
        /* some drivers don't offer this, so if it's not explicitly reported assume it's present. */
icculus@9700
   463
        if (read_power_file(base, name, "present", str, sizeof (str)) && (SDL_strcmp(str, "0\n") == 0)) {
icculus@9700
   464
            st = SDL_POWERSTATE_NO_BATTERY;
icculus@9700
   465
        } else if (!read_power_file(base, name, "status", str, sizeof (str))) {
icculus@9700
   466
            st = SDL_POWERSTATE_UNKNOWN;  /* uh oh */
icculus@9700
   467
        } else if (SDL_strcmp(str, "Charging\n") == 0) {
icculus@9700
   468
            st = SDL_POWERSTATE_CHARGING;
icculus@9700
   469
        } else if (SDL_strcmp(str, "Discharging\n") == 0) {
icculus@9700
   470
            st = SDL_POWERSTATE_ON_BATTERY;
icculus@9700
   471
        } else if ((SDL_strcmp(str, "Full\n") == 0) || (SDL_strcmp(str, "Not charging\n") == 0)) {
icculus@9700
   472
            st = SDL_POWERSTATE_CHARGED;
icculus@9700
   473
        } else {
icculus@9700
   474
            st = SDL_POWERSTATE_UNKNOWN;  /* uh oh */
icculus@9700
   475
        }
icculus@9700
   476
icculus@9700
   477
        if (!read_power_file(base, name, "capacity", str, sizeof (str))) {
icculus@9700
   478
            pct = -1;
icculus@9700
   479
        } else {
icculus@9700
   480
            pct = SDL_atoi(str);
icculus@9700
   481
            pct = (pct > 100) ? 100 : pct; /* clamp between 0%, 100% */
icculus@9700
   482
        }
icculus@9700
   483
icculus@9700
   484
        if (!read_power_file(base, name, "time_to_empty_now", str, sizeof (str))) {
icculus@9700
   485
            secs = -1;
icculus@9700
   486
        } else {
icculus@9700
   487
            secs = SDL_atoi(str);
icculus@9700
   488
            secs = (secs <= 0) ? -1 : secs;  /* 0 == unknown */
icculus@9700
   489
        }
icculus@9700
   490
icculus@9700
   491
        /*
icculus@9700
   492
         * We pick the battery that claims to have the most minutes left.
icculus@9700
   493
         *  (failing a report of minutes, we'll take the highest percent.)
icculus@9700
   494
         */
icculus@9700
   495
        if ((secs < 0) && (*seconds < 0)) {
icculus@9700
   496
            if ((pct < 0) && (*percent < 0)) {
icculus@9700
   497
                choose = SDL_TRUE;  /* at least we know there's a battery. */
icculus@9700
   498
            } else if (pct > *percent) {
icculus@9700
   499
                choose = SDL_TRUE;
icculus@9700
   500
            }
icculus@9700
   501
        } else if (secs > *seconds) {
icculus@9700
   502
            choose = SDL_TRUE;
icculus@9700
   503
        }
icculus@9700
   504
icculus@9700
   505
        if (choose) {
icculus@9700
   506
            *seconds = secs;
icculus@9700
   507
            *percent = pct;
icculus@9700
   508
            *state = st;
icculus@9700
   509
        }
icculus@9700
   510
    }
icculus@9700
   511
icculus@9700
   512
    closedir(dirp);
icculus@9700
   513
    return SDL_TRUE;  /* don't look any further. */
icculus@9700
   514
}
icculus@9700
   515
icculus@3170
   516
#endif /* SDL_POWER_LINUX */
icculus@3170
   517
#endif /* SDL_POWER_DISABLED */
icculus@3170
   518
icculus@3170
   519
/* vi: set ts=4 sw=4 expandtab: */