224 lines
5.4 KiB
C
224 lines
5.4 KiB
C
|
/* Not particularly good interface to hal, for programs that used to use
|
||
|
* apm.
|
||
|
*/
|
||
|
|
||
|
#include <stdio.h>
|
||
|
#include <stdlib.h>
|
||
|
#include <string.h>
|
||
|
#include <unistd.h>
|
||
|
#include <libhal.h>
|
||
|
#include "apm.h"
|
||
|
|
||
|
static DBusConnection *dbus_ctx = NULL;
|
||
|
static LibHalContext *hal_ctx = NULL;
|
||
|
|
||
|
int num_ac_adapters = 0;
|
||
|
int num_batteries = 0;
|
||
|
char **ac_adapters = NULL;
|
||
|
char **batteries = NULL;
|
||
|
|
||
|
int connect_hal (void) {
|
||
|
DBusError error;
|
||
|
|
||
|
dbus_error_init(&error);
|
||
|
dbus_ctx = dbus_bus_get_private(DBUS_BUS_SYSTEM, &error);
|
||
|
if (dbus_ctx == NULL) {
|
||
|
fprintf(stderr, "error: dbus_bus_get: %s: %s\n",
|
||
|
error.name, error.message);
|
||
|
LIBHAL_FREE_DBUS_ERROR(&error);
|
||
|
return 0;
|
||
|
}
|
||
|
if ((hal_ctx = libhal_ctx_new()) == NULL) {
|
||
|
fprintf(stderr, "error: libhal_ctx_new\n");
|
||
|
LIBHAL_FREE_DBUS_ERROR(&error);
|
||
|
return 0;
|
||
|
}
|
||
|
if (!libhal_ctx_set_dbus_connection(hal_ctx, dbus_ctx)) {
|
||
|
fprintf(stderr, "error: libhal_ctx_set_dbus_connection: %s: %s\n",
|
||
|
error.name, error.message);
|
||
|
LIBHAL_FREE_DBUS_ERROR(&error);
|
||
|
return 0;
|
||
|
}
|
||
|
if (!libhal_ctx_init(hal_ctx, &error)) {
|
||
|
if (dbus_error_is_set(&error)) {
|
||
|
fprintf(stderr, "error: libhal_ctx_init: %s: %s\n", error.name, error.message);
|
||
|
LIBHAL_FREE_DBUS_ERROR(&error);
|
||
|
}
|
||
|
fprintf(stderr, "Could not initialise connection to hald.\n"
|
||
|
"Normally this means the HAL daemon (hald) is not running or not ready.\n");
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
int hal_ready (void) {
|
||
|
if (hal_ctx && dbus_connection_get_is_connected(dbus_ctx)) {
|
||
|
return 1;
|
||
|
}
|
||
|
else {
|
||
|
/* The messy business of reconnecting.
|
||
|
* dbus's design is crap when it comes to reconnecting.
|
||
|
* If dbus is down, can't actually close the connection to hal,
|
||
|
* since libhal wants to use dbus to do it. */
|
||
|
if (dbus_ctx) {
|
||
|
dbus_connection_close(dbus_ctx);
|
||
|
dbus_connection_unref(dbus_ctx);
|
||
|
}
|
||
|
dbus_ctx = NULL;
|
||
|
hal_ctx = NULL;
|
||
|
|
||
|
return connect_hal();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
signed int get_hal_int (const char *udi, const char *key, int optional) {
|
||
|
int ret;
|
||
|
DBusError error;
|
||
|
|
||
|
if (! hal_ready()) {
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
dbus_error_init(&error);
|
||
|
|
||
|
ret = libhal_device_get_property_int (hal_ctx, udi, key, &error);
|
||
|
|
||
|
if (! dbus_error_is_set (&error)) {
|
||
|
return ret;
|
||
|
}
|
||
|
else {
|
||
|
if (! optional) {
|
||
|
fprintf(stderr, "error: libhal_device_get_property_int: %s: %s\n",
|
||
|
error.name, error.message);
|
||
|
}
|
||
|
dbus_error_free (&error);
|
||
|
return -1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
signed int get_hal_bool (const char *udi, const char *key, int optional) {
|
||
|
int ret;
|
||
|
DBusError error;
|
||
|
|
||
|
if (! hal_ready()) {
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
dbus_error_init(&error);
|
||
|
|
||
|
ret = libhal_device_get_property_bool (hal_ctx, udi, key, &error);
|
||
|
|
||
|
if (! dbus_error_is_set (&error)) {
|
||
|
return ret;
|
||
|
}
|
||
|
else {
|
||
|
if (! optional) {
|
||
|
fprintf(stderr, "error: libhal_device_get_property_bool: %s: %s\n",
|
||
|
error.name, error.message);
|
||
|
}
|
||
|
dbus_error_free (&error);
|
||
|
return -1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void find_devices (void) {
|
||
|
DBusError error;
|
||
|
|
||
|
dbus_error_init(&error);
|
||
|
|
||
|
if (ac_adapters)
|
||
|
libhal_free_string_array(ac_adapters);
|
||
|
ac_adapters = libhal_find_device_by_capability(hal_ctx, "ac_adapter",
|
||
|
&num_ac_adapters, &error);
|
||
|
if (dbus_error_is_set (&error)) {
|
||
|
fprintf (stderr, "error: %s: %s\n", error.name, error.message);
|
||
|
LIBHAL_FREE_DBUS_ERROR (&error);
|
||
|
}
|
||
|
|
||
|
if (batteries)
|
||
|
libhal_free_string_array(batteries);
|
||
|
batteries = libhal_find_device_by_capability(hal_ctx, "battery",
|
||
|
&num_batteries, &error);
|
||
|
if (dbus_error_is_set (&error)) {
|
||
|
fprintf (stderr, "error: %s: %s\n", error.name, error.message);
|
||
|
LIBHAL_FREE_DBUS_ERROR (&error);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
int simplehal_supported (void) {
|
||
|
if (! connect_hal()) {
|
||
|
return 0;
|
||
|
}
|
||
|
else {
|
||
|
find_devices();
|
||
|
return 1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* Fill the passed apm_info struct. */
|
||
|
int simplehal_read (int battery, apm_info *info) {
|
||
|
char *device;
|
||
|
int i;
|
||
|
|
||
|
/* Allow a battery that was not present before to appear. */
|
||
|
if (battery > num_batteries) {
|
||
|
find_devices();
|
||
|
}
|
||
|
|
||
|
info->battery_flags = 0;
|
||
|
info->using_minutes = 0;
|
||
|
|
||
|
info->ac_line_status=0;
|
||
|
for (i = 0 ; i < num_ac_adapters && ! info->ac_line_status ; i++) {
|
||
|
info->ac_line_status = (get_hal_bool(ac_adapters[i], "ac_adapter.present", 0) == 1);
|
||
|
}
|
||
|
|
||
|
if (battery > num_batteries) {
|
||
|
info->battery_percentage = 0;
|
||
|
info->battery_time = 0;
|
||
|
info->battery_status = BATTERY_STATUS_ABSENT;
|
||
|
return 0;
|
||
|
}
|
||
|
else {
|
||
|
device=batteries[battery-1];
|
||
|
}
|
||
|
|
||
|
if (get_hal_bool(device, "battery.present", 0) != 1) {
|
||
|
info->battery_percentage = 0;
|
||
|
info->battery_time = 0;
|
||
|
info->battery_status = BATTERY_STATUS_ABSENT;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/* remaining_time and charge_level.percentage are not a mandatory
|
||
|
* keys, so if not present, -1 will be returned */
|
||
|
info->battery_time = get_hal_int(device, "battery.remaining_time", 1);
|
||
|
info->battery_percentage = get_hal_int(device, "battery.charge_level.percentage", 1);
|
||
|
if (get_hal_bool(device, "battery.rechargeable.is_discharging", 0) == 1) {
|
||
|
info->battery_status = BATTERY_STATUS_CHARGING;
|
||
|
/* charge_level.warning and charge_level.low are not
|
||
|
* required to be available; this is good enough */
|
||
|
if (info->battery_percentage < 1) {
|
||
|
info->battery_status = BATTERY_STATUS_CRITICAL;
|
||
|
}
|
||
|
else if (info->battery_percentage < 10) {
|
||
|
info->battery_status = BATTERY_STATUS_LOW;
|
||
|
}
|
||
|
}
|
||
|
else if (info->ac_line_status &&
|
||
|
get_hal_bool(device, "battery.rechargeable.is_charging", 0) == 1) {
|
||
|
info->battery_status = BATTERY_STATUS_CHARGING;
|
||
|
info->battery_flags = info->battery_flags | BATTERY_FLAGS_CHARGING;
|
||
|
}
|
||
|
else if (info->ac_line_status) {
|
||
|
/* Must be fully charged. */
|
||
|
info->battery_status = BATTERY_STATUS_HIGH;
|
||
|
}
|
||
|
else {
|
||
|
fprintf(stderr, "unknown battery state\n");
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|