summaryrefslogtreecommitdiff
path: root/battstat/battstat-hal.c
diff options
context:
space:
mode:
Diffstat (limited to 'battstat/battstat-hal.c')
-rw-r--r--battstat/battstat-hal.c608
1 files changed, 0 insertions, 608 deletions
diff --git a/battstat/battstat-hal.c b/battstat/battstat-hal.c
deleted file mode 100644
index 28426f33..00000000
--- a/battstat/battstat-hal.c
+++ /dev/null
@@ -1,608 +0,0 @@
-/*
- * Copyright (C) 2005 by Ryan Lortie <[email protected]>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Street #330, Boston, MA 02110-1301, USA.
- *
- * $Id$
- */
-
-#include <config.h>
-
-#ifdef HAVE_HAL
-
-#include <dbus/dbus-glib-lowlevel.h>
-#include <libhal.h>
-#include <string.h>
-#include <math.h>
-
-#include "battstat-hal.h"
-
-static LibHalContext *battstat_hal_ctx;
-static GSList *batteries;
-static GSList *adaptors;
-static void (*status_updated_callback) (void);
-
-struct battery_status
-{
- int present;
- int current_level, design_level, full_level;
- int remaining_time;
- int charging, discharging;
- int rate;
-};
-
-struct battery_info
-{
- char *udi; /* must be first member */
- struct battery_status status;
-};
-
-struct adaptor_info
-{
- char *udi; /* must be first member */
- int present;
-};
-
-static gboolean
-battery_update_property( LibHalContext *ctx, struct battery_info *battery,
- const char *key )
-{
- DBusError error;
- gboolean ret;
-
- ret = TRUE;
- dbus_error_init( &error );
-
- if( !strcmp( key, "battery.present" ) )
- battery->status.present =
- libhal_device_get_property_bool( ctx, battery->udi, key, &error );
-
- if( !strcmp( key, "battery.charge_level.current" ) )
- battery->status.current_level =
- libhal_device_get_property_int( ctx, battery->udi, key, &error );
-
- if( !strcmp( key, "battery.charge_level.rate" ) )
- battery->status.rate =
- libhal_device_get_property_int( ctx, battery->udi, key, &error );
-
- else if( !strcmp( key, "battery.charge_level.design" ) )
- battery->status.design_level =
- libhal_device_get_property_int( ctx, battery->udi, key, &error );
-
- else if( !strcmp( key, "battery.charge_level.last_full" ) )
- battery->status.full_level =
- libhal_device_get_property_int( ctx, battery->udi, key, &error );
-
- else if( !strcmp( key, "battery.remaining_time" ) )
- battery->status.remaining_time =
- libhal_device_get_property_int( ctx, battery->udi, key, &error );
-
- else if( !strcmp( key, "battery.rechargeable.is_charging" ) )
- battery->status.charging =
- libhal_device_get_property_bool( ctx, battery->udi, key, &error );
-
- else if( !strcmp( key, "battery.rechargeable.is_discharging" ) )
- battery->status.discharging =
- libhal_device_get_property_bool( ctx, battery->udi, key, &error );
-
- else
- ret = FALSE;
-
- dbus_error_free( &error );
-
- return ret;
-}
-
-static gboolean
-adaptor_update_property( LibHalContext *ctx, struct adaptor_info *adaptor,
- const char *key )
-{
- DBusError error;
- gboolean ret;
-
- ret = TRUE;
- dbus_error_init( &error );
-
- if( !strcmp( key, "ac_adapter.present" ) )
- adaptor->present =
- libhal_device_get_property_bool( ctx, adaptor->udi, key, &error );
- else
- ret = FALSE;
-
- dbus_error_free( &error );
-
- return ret;
-}
-
-static GSList *
-find_link_by_udi( GSList *list, const char *udi )
-{
- GSList *link;
-
- for( link = list; link; link = g_slist_next( link ) )
- {
- /* this might be an adaptor! this is OK as long as 'udi' is the first
- * member of both structures.
- */
- struct battery_info *battery = link->data;
-
- if( !strcmp( udi, battery->udi ) )
- return link;
- }
-
- return NULL;
-}
-
-static void *
-find_device_by_udi( GSList *list, const char *udi )
-{
- GSList *link;
-
- link = find_link_by_udi( list, udi );
-
- if( link )
- return link->data;
- else
- return NULL;
-}
-
-static gboolean status_update_scheduled;
-
-static gboolean
-update_status_idle (gpointer junk)
-{
- if (status_updated_callback)
- status_updated_callback ();
-
- return status_update_scheduled = FALSE;
-}
-
-static void
-schedule_status_callback (void)
-{
- if (status_update_scheduled)
- return;
-
- status_update_scheduled = TRUE;
- g_idle_add (update_status_idle, NULL);
-}
-
-static void
-property_callback( LibHalContext *ctx, const char *udi, const char *key,
- dbus_bool_t is_removed, dbus_bool_t is_added )
-{
- struct battery_info *battery;
- struct adaptor_info *adaptor;
- gboolean changed;
-
- /* It is safe to do nothing since the device will have been marked as
- * not present and the old information will be ignored.
- */
- if( is_removed )
- return;
-
- changed = FALSE;
-
- if( (battery = find_device_by_udi( batteries, udi )) )
- changed |= battery_update_property( ctx, battery, key );
-
- if( (adaptor = find_device_by_udi( adaptors, udi )) )
- changed |= adaptor_update_property( ctx, adaptor, key );
-
- if (changed && status_updated_callback)
- schedule_status_callback ();
-}
-
-static void
-add_to_list( LibHalContext *ctx, GSList **list, const char *udi, int size )
-{
- struct battery_info *battery = g_malloc0( size );
- LibHalPropertySetIterator iter;
- LibHalPropertySet *properties;
- DBusError error;
-
- /* this might be an adaptor! this is OK as long as 'udi' is the first
- * member of both structures.
- */
- battery->udi = g_strdup( udi );
- *list = g_slist_append( *list, battery );
-
- dbus_error_init( &error );
-
- libhal_device_add_property_watch( ctx, udi, &error );
-
- properties = libhal_device_get_all_properties( ctx, udi, &error );
-
- for( libhal_psi_init( &iter, properties );
- libhal_psi_has_more( &iter );
- libhal_psi_next( &iter ) )
- {
- const char *key = libhal_psi_get_key( &iter );
- property_callback( ctx, udi, key, FALSE, FALSE );
- }
-
- libhal_free_property_set( properties );
- dbus_error_free( &error );
-}
-
-static void
-free_list_data( void *data )
-{
- /* this might be an adaptor! this is OK as long as 'udi' is the first
- * member of both structures.
- */
- struct battery_info *battery = data;
-
- g_free( battery->udi );
- g_free( battery );
-}
-
-static GSList *
-remove_from_list( LibHalContext *ctx, GSList *list, const char *udi )
-{
- GSList *link = find_link_by_udi( list, udi );
-
- if( link )
- {
- DBusError error;
-
- dbus_error_init( &error );
- libhal_device_remove_property_watch( ctx, udi, &error );
- dbus_error_free( &error );
-
- free_list_data( link->data );
- list = g_slist_delete_link( list, link );
- }
-
- return list;
-}
-
-static GSList *
-free_entire_list( GSList *list )
-{
- GSList *item;
-
- for( item = list; item; item = g_slist_next( item ) )
- free_list_data( item->data );
-
- g_slist_free( list );
-
- return NULL;
-}
-
-static void
-device_added_callback( LibHalContext *ctx, const char *udi )
-{
- if( libhal_device_property_exists( ctx, udi, "battery", NULL ) )
- {
- char *type = libhal_device_get_property_string( ctx, udi,
- "battery.type",
- NULL );
-
- if( type )
- {
- /* We only track 'primary' batteries (ie: to avoid monitoring
- * batteries in cordless mice or UPSes etc.)
- */
- if( !strcmp( type, "primary" ) )
- add_to_list( ctx, &batteries, udi, sizeof (struct battery_info) );
-
- libhal_free_string( type );
- }
- }
-
- if( libhal_device_property_exists( ctx, udi, "ac_adapter", NULL ) )
- add_to_list( ctx, &adaptors, udi, sizeof (struct adaptor_info) );
-}
-
-static void
-device_removed_callback( LibHalContext *ctx, const char *udi )
-{
- batteries = remove_from_list( ctx, batteries, udi );
- adaptors = remove_from_list( ctx, adaptors, udi );
-}
-
-/* ---- public functions ---- */
-
-char *
-battstat_hal_initialise (void (*callback) (void))
-{
- DBusConnection *connection;
- LibHalContext *ctx;
- DBusError error;
- char *error_str;
- char **devices;
- int i, num;
-
- status_updated_callback = callback;
-
- if( battstat_hal_ctx != NULL )
- return g_strdup( "Already initialised!" );
-
- dbus_error_init( &error );
-
- if( (connection = dbus_bus_get( DBUS_BUS_SYSTEM, &error )) == NULL )
- goto error_out;
-
- dbus_connection_setup_with_g_main( connection, g_main_context_default() );
-
- if( (ctx = libhal_ctx_new()) == NULL )
- {
- dbus_set_error( &error, _("HAL error"), _("Could not create libhal_ctx") );
- goto error_out;
- }
-
- libhal_ctx_set_device_property_modified( ctx, property_callback );
- libhal_ctx_set_device_added( ctx, device_added_callback );
- libhal_ctx_set_device_removed( ctx, device_removed_callback );
- libhal_ctx_set_dbus_connection( ctx, connection );
-
- if( libhal_ctx_init( ctx, &error ) == 0 )
- goto error_freectx;
-
- devices = libhal_find_device_by_capability( ctx, "battery", &num, &error );
-
- if( devices == NULL )
- goto error_shutdownctx;
-
- /* FIXME: for now, if 0 battery devices are present on first scan, then fail.
- * This allows fallover to the legacy (ACPI, APM, etc) backends if the
- * installed version of HAL doesn't know about batteries. This check should
- * be removed at some point in the future (maybe circa MATE 2.13..).
- */
- if( num == 0 )
- {
- dbus_free_string_array( devices );
- dbus_set_error( &error, _("HAL error"), _("No batteries found") );
- goto error_shutdownctx;
- }
-
- for( i = 0; i < num; i++ )
- {
- char *type = libhal_device_get_property_string( ctx, devices[i],
- "battery.type",
- &error );
-
- if( type )
- {
- /* We only track 'primary' batteries (ie: to avoid monitoring
- * batteries in cordless mice or UPSes etc.)
- */
- if( !strcmp( type, "primary" ) )
- add_to_list( ctx, &batteries, devices[i],
- sizeof (struct battery_info) );
-
- libhal_free_string( type );
- }
- }
- dbus_free_string_array( devices );
-
- devices = libhal_find_device_by_capability( ctx, "ac_adapter", &num, &error );
-
- if( devices == NULL )
- {
- batteries = free_entire_list( batteries );
- goto error_shutdownctx;
- }
-
- for( i = 0; i < num; i++ )
- add_to_list( ctx, &adaptors, devices[i], sizeof (struct adaptor_info) );
- dbus_free_string_array( devices );
-
- dbus_error_free( &error );
-
- battstat_hal_ctx = ctx;
-
- return NULL;
-
-error_shutdownctx:
- libhal_ctx_shutdown( ctx, NULL );
-
-error_freectx:
- libhal_ctx_free( ctx );
-
-error_out:
- error_str = g_strdup_printf( _("Unable to initialise HAL: %s: %s"),
- error.name, error.message );
- dbus_error_free( &error );
- return error_str;
-}
-
-void
-battstat_hal_cleanup( void )
-{
- if( battstat_hal_ctx == NULL )
- return;
-
- libhal_ctx_free( battstat_hal_ctx );
- batteries = free_entire_list( batteries );
- adaptors = free_entire_list( adaptors );
-}
-
-#include "battstat.h"
-
-/* This function currently exists to allow the multiple batteries supported
- * by the HAL backend to appear as a single composite battery device (since
- * at the current time this is all that battstat supports).
- *
- * This entire function is filled with logic to make multiple batteries
- * appear as one "composite" battery. Comments included as appropriate.
- *
- * For more information about some of the assumptions made in the following
- * code please see the following mailing list post and the resulting thread:
- *
- * http://lists.freedesktop.org/archives/hal/2005-July/002841.html
- */
-void
-battstat_hal_get_battery_info( BatteryStatus *status )
-{
- /* The calculation to get overall percentage power remaining is as follows:
- *
- * Sum( Current charges ) / Sum( Full Capacities )
- *
- * We can't just take an average of all of the percentages since this
- * doesn't deal with the case that one battery might have a larger
- * capacity than the other.
- *
- * In order to do this calculation, we need to keep a running total of
- * current charge and full capacities.
- */
- int current_charge_total = 0, full_capacity_total = 0;
-
- /* Record the time remaining as reported by HAL. This is used in the event
- * that the system has exactly one battery (since, then, the HAL is capable
- * of providing an accurate time remaining report and we should trust it.)
- */
- int remaining_time = 0;
-
- /* The total (dis)charge rate of the system is the sum of the rates of
- * the individual batteries.
- */
- int rate_total = 0;
-
- /* We need to know if we should report the composite battery as present
- * at all. The logic is that if at least one actual battery is installed
- * then the composite battery will be reported to exist.
- */
- int present = 0;
-
- /* We need to know if we are on AC power or not. Eventually, we can look
- * at the AC adaptor HAL devices to determine that. For now, we assume that
- * if any battery is discharging then we must not be on AC power. Else, by
- * default, we must be on AC.
- */
- int on_ac_power = 1;
-
- /* Finally, we consider the composite battery to be "charging" if at least
- * one of the actual batteries in the system is charging.
- */
- int charging = 0;
-
- /* A list iterator. */
- GSList *item;
-
- /* For each physical battery bay... */
- for( item = batteries; item; item = item->next )
- {
- struct battery_info *battery = item->data;
-
- /* If no battery is installed here, don't count it toward the totals. */
- if( !battery->status.present )
- continue;
-
- /* This battery is present. */
-
- /* At least one battery present -> composite battery is present. */
- present++;
-
- /* At least one battery charging -> composite battery is charging. */
- if( battery->status.charging )
- charging = 1;
-
- /* At least one battery is discharging -> we're not on AC. */
- if( battery->status.discharging )
- on_ac_power = 0;
-
- /* Sum the totals for current charge, design capacity, (dis)charge rate. */
- current_charge_total += battery->status.current_level;
- full_capacity_total += battery->status.full_level;
- rate_total += battery->status.rate;
-
- /* Record remaining time too, incase this is the only battery. */
- remaining_time = battery->status.remaining_time;
- }
-
- if( !present || full_capacity_total <= 0 || (charging && !on_ac_power) )
- {
- /* Either no battery is present or something has gone horribly wrong.
- * In either case we must return that the composite battery is not
- * present.
- */
- status->present = FALSE;
- status->percent = 0;
- status->minutes = -1;
- status->on_ac_power = TRUE;
- status->charging = FALSE;
-
- return;
- }
-
- /* Else, our composite battery is present. */
- status->present = TRUE;
-
- /* As per above, overall charge is:
- *
- * Sum( Current charges ) / Sum( Full Capacities )
- */
- status->percent = ( ((double) current_charge_total) /
- ((double) full_capacity_total) ) * 100.0 + 0.5;
-
- if( present == 1 )
- {
- /* In the case of exactly one battery, report the time remaining figure
- * from HAL directly since it might have come from an authorative source
- * (ie: the PMU or APM subsystem).
- *
- * HAL gives remaining time in seconds with a 0 to mean that the
- * remaining time is unknown. Battstat uses minutes and -1 for
- * unknown time remaining.
- */
-
- if( remaining_time == 0 )
- status->minutes = -1;
- else
- status->minutes = (remaining_time + 30) / 60;
- }
- /* Rest of cases to deal with multiple battery systems... */
- else if( !on_ac_power && rate_total != 0 )
- {
- /* Then we're discharging. Calculate time remaining until at zero. */
-
- double remaining;
-
- remaining = (double) current_charge_total;
- remaining /= (double) rate_total;
- status->minutes = (int) floor( remaining * 60.0 + 0.5 );
- }
- else if( charging && rate_total != 0 )
- {
- /* Calculate time remaining until charged. For systems with more than
- * one battery, this code is very approximate. The assumption is that if
- * one battery reaches full charge before the other that the other will
- * start charging faster due to the increase in available power (similar
- * to how a laptop will charge faster if you're not using it).
- */
-
- double remaining;
-
- remaining = (double) (full_capacity_total - current_charge_total);
- if( remaining < 0 )
- remaining = 0;
- remaining /= (double) rate_total;
-
- status->minutes = (int) floor( remaining * 60.0 + 0.5 );
- }
- else
- {
- /* On AC power and not charging -or- rate is unknown. */
- status->minutes = -1;
- }
-
- /* These are simple and well-explained above. */
- status->charging = charging;
- status->on_ac_power = on_ac_power;
-}
-
-#endif /* HAVE_HAL */