xref: /onnv-gate/usr/src/cmd/hal/utils/acpi.c (revision 7651:0cebc536e909)
16573Sphitran /***************************************************************************
26573Sphitran  *
36573Sphitran  * acpi.c : Main routines for setting battery, AC adapter, and lid properties
46573Sphitran  *
56573Sphitran  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
66573Sphitran  * Use is subject to license terms.
76573Sphitran  *
86573Sphitran  * Licensed under the Academic Free License version 2.1
96573Sphitran  *
106573Sphitran  **************************************************************************/
116573Sphitran 
126573Sphitran #ifdef HAVE_CONFIG_H
136573Sphitran #include <config.h>
146573Sphitran #endif
156573Sphitran 
166573Sphitran #include <unistd.h>
176573Sphitran #include <strings.h>
186573Sphitran #include <string.h>
196573Sphitran #include <kstat.h>
206573Sphitran #include <fcntl.h>
216573Sphitran #include <errno.h>
226573Sphitran #include <sys/acpi_drv.h>
236573Sphitran 
246573Sphitran #include <libhal.h>
256573Sphitran #include "../hald/device_info.h"
266573Sphitran #include "../hald/hald_dbus.h"
276573Sphitran #include "../hald/logger.h"
286573Sphitran #include "../hald/util_pm.h"
296573Sphitran #include "acpi.h"
306573Sphitran 
316573Sphitran 
326573Sphitran static void
my_dbus_error_free(DBusError * error)336573Sphitran my_dbus_error_free(DBusError *error)
346573Sphitran {
356573Sphitran 	if (dbus_error_is_set(error)) {
366573Sphitran 		dbus_error_free(error);
376573Sphitran 	}
386573Sphitran }
396573Sphitran 
406573Sphitran gboolean
laptop_panel_update(LibHalContext * ctx,const char * udi,int fd)416573Sphitran laptop_panel_update(LibHalContext *ctx, const char *udi, int fd)
426573Sphitran {
436573Sphitran 	LibHalChangeSet *cs;
446573Sphitran 	DBusError error;
456573Sphitran 	struct acpi_drv_output_info inf;
466573Sphitran 
476573Sphitran 	HAL_DEBUG(("laptop_panel_update() enter"));
486573Sphitran 
496573Sphitran 	dbus_error_init(&error);
506573Sphitran 	if (!libhal_device_query_capability(ctx, udi, "laptop_panel", &error)) {
516573Sphitran 		bzero(&inf, sizeof (inf));
526573Sphitran 		if ((ioctl(fd, ACPI_DRV_IOC_INFO, &inf) < 0) ||
536573Sphitran 		    (inf.nlev == 0)) {
546573Sphitran 			return (FALSE);
556573Sphitran 		}
566573Sphitran 
576573Sphitran 		my_dbus_error_free(&error);
586573Sphitran 		libhal_device_add_capability(ctx, udi, "laptop_panel", &error);
596573Sphitran 		if ((cs = libhal_device_new_changeset(udi)) == NULL) {
606573Sphitran 			my_dbus_error_free(&error);
616573Sphitran 			return (FALSE);
626573Sphitran 		}
636573Sphitran 		libhal_changeset_set_property_string(cs, "info.product",
646573Sphitran 		    "Generic Backlight Device");
656573Sphitran 		libhal_changeset_set_property_string(cs, "info.category",
666573Sphitran 		    "laptop_panel");
676573Sphitran 		libhal_changeset_set_property_int(cs, "laptop_panel.num_levels",
686573Sphitran 		    inf.nlev);
696573Sphitran 		my_dbus_error_free(&error);
706573Sphitran 		libhal_device_commit_changeset(ctx, cs, &error);
716573Sphitran 		libhal_device_free_changeset(cs);
726573Sphitran 	}
736573Sphitran 	my_dbus_error_free(&error);
746573Sphitran 	HAL_DEBUG(("ac_adapter_present() exit"));
756573Sphitran 	return (TRUE);
766573Sphitran }
776573Sphitran 
786573Sphitran gboolean
lid_update(LibHalContext * ctx,const char * udi,int fd)796573Sphitran lid_update(LibHalContext *ctx, const char *udi, int fd)
806573Sphitran {
816573Sphitran 	LibHalChangeSet *cs;
826573Sphitran 	DBusError error;
83*7651SPhi.Tran@Sun.COM 	int lid_state;
846573Sphitran 
856573Sphitran 	HAL_DEBUG(("lid_update() enter"));
866573Sphitran 
87*7651SPhi.Tran@Sun.COM 	if ((cs = libhal_device_new_changeset(udi)) == NULL) {
88*7651SPhi.Tran@Sun.COM 		return (FALSE);
89*7651SPhi.Tran@Sun.COM 	}
906573Sphitran 	dbus_error_init(&error);
916573Sphitran 	if (!libhal_device_query_capability(ctx, udi, "button", &error)) {
926573Sphitran 		my_dbus_error_free(&error);
936573Sphitran 		libhal_device_add_capability(ctx, udi, "button", &error);
94*7651SPhi.Tran@Sun.COM 		my_dbus_error_free(&error);
95*7651SPhi.Tran@Sun.COM 		libhal_changeset_set_property_bool(cs, "button.has_state",
96*7651SPhi.Tran@Sun.COM 		    TRUE);
97*7651SPhi.Tran@Sun.COM 
98*7651SPhi.Tran@Sun.COM 		if (ioctl(fd, ACPI_DRV_IOC_LID_STATUS, &lid_state) < 0) {
996573Sphitran 			return (FALSE);
1006573Sphitran 		}
101*7651SPhi.Tran@Sun.COM 		if (lid_state != 0) {
102*7651SPhi.Tran@Sun.COM 			/* lid open */
103*7651SPhi.Tran@Sun.COM 			libhal_changeset_set_property_bool(cs,
104*7651SPhi.Tran@Sun.COM 			    "button.state.value", FALSE);
105*7651SPhi.Tran@Sun.COM 		} else {
106*7651SPhi.Tran@Sun.COM 			/* lid closed */
107*7651SPhi.Tran@Sun.COM 			libhal_changeset_set_property_bool(cs,
108*7651SPhi.Tran@Sun.COM 			    "button.state.value", TRUE);
109*7651SPhi.Tran@Sun.COM 		}
110*7651SPhi.Tran@Sun.COM 		libhal_changeset_set_property_bool(cs, "button.workaround",
1116573Sphitran 		    TRUE);
1126573Sphitran 		libhal_changeset_set_property_string(cs, "button.type",
1136573Sphitran 		    "lid");
1146573Sphitran 		libhal_changeset_set_property_string(cs, "info.product",
1156573Sphitran 		    "Lid Switch");
1166573Sphitran 		libhal_changeset_set_property_string(cs, "info.category",
1176573Sphitran 		    "button");
118*7651SPhi.Tran@Sun.COM 	} else {
1196573Sphitran 		my_dbus_error_free(&error);
120*7651SPhi.Tran@Sun.COM 		if (ioctl(fd, ACPI_DRV_IOC_LID_UPDATE, &lid_state) < 0) {
121*7651SPhi.Tran@Sun.COM 			return (FALSE);
122*7651SPhi.Tran@Sun.COM 		}
123*7651SPhi.Tran@Sun.COM 		if (lid_state != 0) {
124*7651SPhi.Tran@Sun.COM 			/* lid open */
125*7651SPhi.Tran@Sun.COM 			libhal_changeset_set_property_bool(cs,
126*7651SPhi.Tran@Sun.COM 			    "button.state.value", FALSE);
127*7651SPhi.Tran@Sun.COM 		} else {
128*7651SPhi.Tran@Sun.COM 			/* lid closed */
129*7651SPhi.Tran@Sun.COM 			libhal_changeset_set_property_bool(cs,
130*7651SPhi.Tran@Sun.COM 			    "button.state.value", TRUE);
131*7651SPhi.Tran@Sun.COM 		}
1326573Sphitran 	}
133*7651SPhi.Tran@Sun.COM 
134*7651SPhi.Tran@Sun.COM 	libhal_device_commit_changeset(ctx, cs, &error);
135*7651SPhi.Tran@Sun.COM 	libhal_device_free_changeset(cs);
1366573Sphitran 	my_dbus_error_free(&error);
1376573Sphitran 	HAL_DEBUG(("update_lid() exit"));
1386573Sphitran 	return (TRUE);
1396573Sphitran }
1406573Sphitran 
1416573Sphitran static void
ac_adapter_present(LibHalContext * ctx,const char * udi,int fd)1426573Sphitran ac_adapter_present(LibHalContext *ctx, const char *udi, int fd)
1436573Sphitran {
1446573Sphitran 	int pow;
1456573Sphitran 	LibHalChangeSet *cs;
1466573Sphitran 	DBusError error;
1476573Sphitran 
1486573Sphitran 	HAL_DEBUG(("ac_adapter_present() enter"));
1496573Sphitran 	if (ioctl(fd, ACPI_DRV_IOC_POWER_STATUS, &pow) < 0) {
1506573Sphitran 		return;
1516573Sphitran 	}
1526573Sphitran 	if ((cs = libhal_device_new_changeset(udi)) == NULL) {
1536573Sphitran 		return;
1546573Sphitran 	}
1556573Sphitran 	if (pow > 0) {
1566573Sphitran 		libhal_changeset_set_property_bool(cs, "ac_adapter.present",
1576573Sphitran 		    TRUE);
1586573Sphitran 	} else {
1596573Sphitran 		libhal_changeset_set_property_bool(cs, "ac_adapter.present",
1606573Sphitran 		    FALSE);
1616573Sphitran 	}
1626573Sphitran 
1636573Sphitran 	dbus_error_init(&error);
1646573Sphitran 	libhal_device_commit_changeset(ctx, cs, &error);
1656573Sphitran 	libhal_device_free_changeset(cs);
1666573Sphitran 	my_dbus_error_free(&error);
1676573Sphitran 	HAL_DEBUG(("ac_adapter_present() exit"));
1686573Sphitran }
1696573Sphitran 
1706573Sphitran static void
battery_remove(LibHalContext * ctx,const char * udi)1716573Sphitran battery_remove(LibHalContext *ctx, const char *udi)
1726573Sphitran {
1736573Sphitran 	DBusError error;
1746573Sphitran 
1756573Sphitran 	HAL_DEBUG(("battery_remove() enter"));
1766573Sphitran 	dbus_error_init(&error);
1776573Sphitran 	libhal_device_remove_property(ctx, udi, "battery.remaining_time",
1786573Sphitran 	    &error);
1796573Sphitran 	my_dbus_error_free(&error);
1806573Sphitran 	libhal_device_remove_property(ctx, udi,
1816573Sphitran 	    "battery.charge_level.percentage", &error);
1826573Sphitran 	my_dbus_error_free(&error);
1836573Sphitran 	libhal_device_remove_property(ctx, udi, "battery.charge_level.rate",
1846573Sphitran 	    &error);
1856573Sphitran 	my_dbus_error_free(&error);
1866573Sphitran 	libhal_device_remove_property(ctx, udi,
1876573Sphitran 	    "battery.charge_level.last_full", &error);
1886573Sphitran 	my_dbus_error_free(&error);
1896573Sphitran 	libhal_device_remove_property(ctx, udi,
1906573Sphitran 	    "battery.charge_level.current", &error);
1916573Sphitran 	my_dbus_error_free(&error);
1926573Sphitran 	libhal_device_remove_property(ctx, udi, "battery.voltage.present",
1936573Sphitran 	    &error);
1946573Sphitran 	my_dbus_error_free(&error);
1956573Sphitran 	libhal_device_remove_property(ctx, udi, "battery.reporting.rate",
1966573Sphitran 	    &error);
1976573Sphitran 	my_dbus_error_free(&error);
1986573Sphitran 	libhal_device_remove_property(ctx, udi, "battery.reporting.current",
1996573Sphitran 	    &error);
2006573Sphitran 	my_dbus_error_free(&error);
2016573Sphitran 	libhal_device_remove_property(ctx, udi,
2026573Sphitran 	    "battery.rechargeable.is_discharging", &error);
2036573Sphitran 	my_dbus_error_free(&error);
2046573Sphitran 	libhal_device_remove_property(ctx, udi,
2056573Sphitran 	    "battery.rechargeable.is_charging", &error);
2066573Sphitran 	my_dbus_error_free(&error);
2076573Sphitran 	libhal_device_remove_property(ctx, udi, "battery.is_rechargeable",
2086573Sphitran 	    &error);
2096573Sphitran 	my_dbus_error_free(&error);
2106573Sphitran 	libhal_device_remove_property(ctx, udi, "battery.charge_level.unit",
2116573Sphitran 	    &error);
2126573Sphitran 	my_dbus_error_free(&error);
2136573Sphitran 	libhal_device_remove_property(ctx, udi,
2146573Sphitran 	    "battery.charge_level.granularity_2", &error);
2156573Sphitran 	my_dbus_error_free(&error);
2166573Sphitran 	libhal_device_remove_property(ctx, udi,
2176573Sphitran 	    "battery.charge_level.granularity_1", &error);
2186573Sphitran 	my_dbus_error_free(&error);
2196573Sphitran 	libhal_device_remove_property(ctx, udi, "battery.charge_level.low",
2206573Sphitran 	    &error);
2216573Sphitran 	my_dbus_error_free(&error);
2226573Sphitran 	libhal_device_remove_property(ctx, udi, "battery.charge_level.warning",
2236573Sphitran 	    &error);
2246573Sphitran 	my_dbus_error_free(&error);
2256573Sphitran 	libhal_device_remove_property(ctx, udi, "battery.charge_level.design",
2266573Sphitran 	    &error);
2276573Sphitran 	my_dbus_error_free(&error);
2286573Sphitran 	libhal_device_remove_property(ctx, udi, "battery.voltage.design",
2296573Sphitran 	    &error);
2306573Sphitran 	my_dbus_error_free(&error);
2316573Sphitran 	libhal_device_remove_property(ctx, udi,
2326573Sphitran 	    "battery.reporting.granularity_2", &error);
2336573Sphitran 	my_dbus_error_free(&error);
2346573Sphitran 	libhal_device_remove_property(ctx, udi,
2356573Sphitran 	    "battery.reporting.granularity_1", &error);
2366573Sphitran 	my_dbus_error_free(&error);
2376573Sphitran 	libhal_device_remove_property(ctx, udi, "battery.reporting.low",
2386573Sphitran 	    &error);
2396573Sphitran 	my_dbus_error_free(&error);
2406573Sphitran 	libhal_device_remove_property(ctx, udi, "battery.reporting.warning",
2416573Sphitran 	    &error);
2426573Sphitran 	my_dbus_error_free(&error);
2436573Sphitran 	libhal_device_remove_property(ctx, udi, "battery.reporting.design",
2446573Sphitran 	    &error);
2456573Sphitran 	my_dbus_error_free(&error);
2466573Sphitran 	libhal_device_remove_property(ctx, udi, "battery.reporting.last_full",
2476573Sphitran 	    &error);
2486573Sphitran 	my_dbus_error_free(&error);
2496573Sphitran 	libhal_device_remove_property(ctx, udi, "battery.reporting.unit",
2506573Sphitran 	    &error);
2516573Sphitran 	my_dbus_error_free(&error);
2526573Sphitran 	libhal_device_remove_property(ctx, udi, "battery.technology", &error);
2536573Sphitran 	my_dbus_error_free(&error);
2546573Sphitran 	libhal_device_remove_property(ctx, udi, "battery.reporting.technology",
2556573Sphitran 	    &error);
2566573Sphitran 	my_dbus_error_free(&error);
2576573Sphitran 	libhal_device_remove_property(ctx, udi, "battery.serial", &error);
2586573Sphitran 	my_dbus_error_free(&error);
2596573Sphitran 	libhal_device_remove_property(ctx, udi, "battery.model", &error);
2606573Sphitran 	my_dbus_error_free(&error);
2616573Sphitran 	libhal_device_remove_property(ctx, udi, "battery.vendor", &error);
2626573Sphitran 	my_dbus_error_free(&error);
2636573Sphitran 	HAL_DEBUG(("battery_remove() exit"));
2646573Sphitran }
2656573Sphitran 
2666573Sphitran static void
battery_last_full(LibHalChangeSet * cs,int fd)2676573Sphitran battery_last_full(LibHalChangeSet *cs, int fd)
2686573Sphitran {
2696573Sphitran 	acpi_bif_t bif;
2706573Sphitran 
2716573Sphitran 	bzero(&bif, sizeof (bif));
2726573Sphitran 	if (ioctl(fd, ACPI_DRV_IOC_INFO, &bif) < 0) {
2736573Sphitran 		return;
2746573Sphitran 	}
2756573Sphitran 	libhal_changeset_set_property_int(cs, "battery.reporting_last_full",
2766573Sphitran 	    bif.bif_last_cap);
2776573Sphitran }
2786573Sphitran 
2796573Sphitran static void
battery_dynamic_update(LibHalContext * ctx,const char * udi,int fd)2806573Sphitran battery_dynamic_update(LibHalContext *ctx, const char *udi, int fd)
2816573Sphitran {
2826573Sphitran 	int reporting_rate;
2836573Sphitran 	int reporting_current;
2846573Sphitran 	int reporting_lastfull;
2856573Sphitran 	int design_voltage;
2866573Sphitran 	int present_voltage;
2876573Sphitran 	char *reporting_unit;
2886573Sphitran 	int remaining_time;
2896573Sphitran 	int remaining_percentage;
2906573Sphitran 	gboolean charging;
2916573Sphitran 	gboolean discharging;
2926573Sphitran 	acpi_bst_t bst;
2936573Sphitran 	LibHalChangeSet *cs;
2946573Sphitran 	DBusError error;
2956573Sphitran 	static int counter = 0;
2966573Sphitran 
2976573Sphitran 	HAL_DEBUG(("battery_dynamic_update() enter"));
2986573Sphitran 	bzero(&bst, sizeof (bst));
2996573Sphitran 	if (ioctl(fd, ACPI_DRV_IOC_STATUS, &bst) < 0) {
3006573Sphitran 		return;
3016573Sphitran 	}
3026573Sphitran 
3036573Sphitran 	charging = bst.bst_state & ACPI_DRV_BST_CHARGING ? TRUE : FALSE;
3046573Sphitran 	discharging = bst.bst_state & ACPI_DRV_BST_DISCHARGING ? TRUE : FALSE;
3056573Sphitran 	/* No need to continue if battery is essentially idle. */
3066573Sphitran 	if (counter && !charging && !discharging) {
3076573Sphitran 		return;
3086573Sphitran 	}
3096573Sphitran 	dbus_error_init(&error);
3106573Sphitran 	libhal_device_set_property_bool(ctx, udi, "battery.is_rechargeable",
3116573Sphitran 	    TRUE, &error);
3126573Sphitran 	my_dbus_error_free(&error);
3136573Sphitran 	if (libhal_device_property_exists(ctx, udi,
3146573Sphitran 	    "battery.charge_level.percentage", &error)) {
3156573Sphitran 		remaining_percentage = libhal_device_get_property_int(ctx, udi,
3166573Sphitran 		    "battery.charge_level.percentage", &error);
3176573Sphitran 		if ((remaining_percentage == 100) && charging) {
3186573Sphitran 			charging = FALSE;
3196573Sphitran 		}
3206573Sphitran 	}
3216573Sphitran 	libhal_device_set_property_bool(ctx, udi,
3226573Sphitran 	    "battery.rechargeable.is_charging", charging, &error);
3236573Sphitran 	my_dbus_error_free(&error);
3246573Sphitran 	libhal_device_set_property_bool(ctx, udi,
3256573Sphitran 	    "battery.rechargeable.is_discharging", discharging, &error);
3266573Sphitran 	my_dbus_error_free(&error);
3276573Sphitran 	reporting_current = bst.bst_rem_cap;
3286573Sphitran 	libhal_device_set_property_int(ctx, udi, "battery.reporting.current",
3296573Sphitran 	    bst.bst_rem_cap, &error);
3306573Sphitran 	my_dbus_error_free(&error);
3316573Sphitran 	reporting_rate = bst.bst_rate;
3326573Sphitran 	libhal_device_set_property_int(ctx, udi, "battery.reporting.rate",
3336573Sphitran 	    bst.bst_rate, &error);
3346573Sphitran 	my_dbus_error_free(&error);
3356573Sphitran 	present_voltage = bst.bst_voltage;
3366573Sphitran 	libhal_device_set_property_int(ctx, udi, "battery.voltage.present",
3376573Sphitran 	    bst.bst_voltage, &error);
3386573Sphitran 	/* get all the data we know */
3396573Sphitran 	my_dbus_error_free(&error);
3406573Sphitran 	reporting_unit = libhal_device_get_property_string(ctx, udi,
3416573Sphitran 	    "battery.reporting.unit", &error);
3426573Sphitran 	my_dbus_error_free(&error);
3436573Sphitran 	reporting_lastfull = libhal_device_get_property_int(ctx, udi,
3446573Sphitran 	    "battery.reporting.last_full", &error);
3456573Sphitran 
3466573Sphitran 	/*
3476573Sphitran 	 * Convert mAh to mWh since util_compute_time_remaining() works
3486573Sphitran 	 * for mWh.
3496573Sphitran 	 */
3506573Sphitran 	if (reporting_unit && strcmp(reporting_unit, "mAh") == 0) {
3516573Sphitran 		my_dbus_error_free(&error);
3526573Sphitran 		design_voltage = libhal_device_get_property_int(ctx, udi,
3536573Sphitran 		    "battery.voltage.design", &error);
3546573Sphitran 		/*
3556573Sphitran 		 * If the present_voltage is inaccurate, set it to the
3566573Sphitran 		 * design_voltage.
3576573Sphitran 		 */
3586573Sphitran 		if (((present_voltage * 10) < design_voltage) ||
3596573Sphitran 		    (present_voltage <= 0) ||
3606573Sphitran 		    (present_voltage > design_voltage)) {
3616573Sphitran 			present_voltage = design_voltage;
3626573Sphitran 		}
3636573Sphitran 		reporting_rate = (reporting_rate * present_voltage) / 1000;
3646573Sphitran 		reporting_lastfull = (reporting_lastfull * present_voltage) /
3656573Sphitran 		    1000;
3666573Sphitran 		reporting_current = (reporting_current * present_voltage) /
3676573Sphitran 		    1000;
3686573Sphitran 	}
3696573Sphitran 
3706573Sphitran 	/* Make sure the current charge does not exceed the full charge */
3716573Sphitran 	if (reporting_current > reporting_lastfull) {
3726573Sphitran 		reporting_current = reporting_lastfull;
3736573Sphitran 	}
3746573Sphitran 	if (!charging && !discharging) {
3756573Sphitran 		counter++;
3766573Sphitran 		reporting_rate = 0;
3776573Sphitran 	}
3786573Sphitran 
3796573Sphitran 	if ((cs = libhal_device_new_changeset(udi)) == NULL) {
3806573Sphitran 		HAL_DEBUG(("Cannot allocate changeset"));
3816573Sphitran 		libhal_free_string(reporting_unit);
3826573Sphitran 		my_dbus_error_free(&error);
3836573Sphitran 		return;
3846573Sphitran 	}
3856573Sphitran 
3866573Sphitran 	libhal_changeset_set_property_int(cs, "battery.charge_level.rate",
3876573Sphitran 	    reporting_rate);
3886573Sphitran 	libhal_changeset_set_property_int(cs,
3896573Sphitran 	    "battery.charge_level.last_full", reporting_lastfull);
3906573Sphitran 	libhal_changeset_set_property_int(cs,
3916573Sphitran 	    "battery.charge_level.current", reporting_current);
3926573Sphitran 
3936573Sphitran 	remaining_percentage = util_compute_percentage_charge(udi,
3946573Sphitran 	    reporting_current, reporting_lastfull);
3956573Sphitran 	remaining_time = util_compute_time_remaining(udi, reporting_rate,
3966573Sphitran 	    reporting_current, reporting_lastfull, discharging, charging, 0);
3976573Sphitran 	/*
3986573Sphitran 	 * Some batteries give bad remaining_time estimates relative to
3996573Sphitran 	 * the charge level.
4006573Sphitran 	 */
4016573Sphitran 	if (charging && ((remaining_time < 30) || ((remaining_time < 300) &&
4026573Sphitran 	    (remaining_percentage < 95)) || (remaining_percentage > 97))) {
4036573Sphitran 		remaining_time = util_compute_time_remaining(udi,
4046573Sphitran 		    reporting_rate, reporting_current, reporting_lastfull,
4056573Sphitran 		    discharging, charging, 1);
4066573Sphitran 	}
4076573Sphitran 
4086573Sphitran 	if (remaining_percentage > 0) {
4096573Sphitran 		libhal_changeset_set_property_int(cs,
4106573Sphitran 		    "battery.charge_level.percentage", remaining_percentage);
4116573Sphitran 	} else {
4126573Sphitran 		my_dbus_error_free(&error);
4136573Sphitran 		libhal_device_remove_property(ctx, udi,
4146573Sphitran 		    "battery.charge_level.percentage", &error);
4156573Sphitran 	}
4166573Sphitran 	if ((remaining_percentage == 100) && charging) {
4176573Sphitran 		battery_last_full(cs, fd);
4186573Sphitran 	}
4196573Sphitran 	/*
4206573Sphitran 	 * remaining_percentage is more accurate so we handle cases
4216573Sphitran 	 * where the remaining_time cannot be correct.
4226573Sphitran 	 */
4236573Sphitran 	if ((!charging && !discharging) || ((remaining_percentage == 100) &&
4246573Sphitran 	    !discharging)) {
4256573Sphitran 		remaining_time = 0;
4266573Sphitran 	}
4276573Sphitran 	if (remaining_time < 0) {
4286573Sphitran 		my_dbus_error_free(&error);
4296573Sphitran 		libhal_device_remove_property(ctx, udi,
4306573Sphitran 		    "battery.remaining_time", &error);
4316573Sphitran 	} else if (remaining_time >= 0) {
4326573Sphitran 		libhal_changeset_set_property_int(cs,
4336573Sphitran 		    "battery.remaining_time", remaining_time);
4346573Sphitran 	}
4356573Sphitran 
4366573Sphitran 	my_dbus_error_free(&error);
4376573Sphitran 	libhal_device_commit_changeset(ctx, cs, &error);
4386573Sphitran 	libhal_device_free_changeset(cs);
4396573Sphitran 	libhal_free_string(reporting_unit);
4406573Sphitran 	my_dbus_error_free(&error);
4416573Sphitran 	HAL_DEBUG(("battery_dynamic_update() exit"));
4426573Sphitran }
4436573Sphitran 
4446573Sphitran static gboolean
battery_static_update(LibHalContext * ctx,const char * udi,int fd)4456573Sphitran battery_static_update(LibHalContext *ctx, const char *udi, int fd)
4466573Sphitran {
4476573Sphitran 	const char *technology;
4486573Sphitran 	int reporting_design;
4496573Sphitran 	int reporting_warning;
4506573Sphitran 	int reporting_low;
4516573Sphitran 	int reporting_gran1;
4526573Sphitran 	int reporting_gran2;
4536573Sphitran 	int voltage_design;
4546573Sphitran 	char reporting_unit[10];
4556573Sphitran 	acpi_bif_t bif;
4566573Sphitran 	LibHalChangeSet *cs;
4576573Sphitran 	DBusError error;
4586573Sphitran 
4596573Sphitran 	HAL_DEBUG(("battery_static_update() enter"));
4606573Sphitran 	bzero(&bif, sizeof (bif));
4616573Sphitran 	if (ioctl(fd, ACPI_DRV_IOC_INFO, &bif) < 0) {
4626573Sphitran 		return (FALSE);
4636573Sphitran 	}
4646573Sphitran 	if ((cs = libhal_device_new_changeset(udi)) == NULL) {
4656573Sphitran 		HAL_DEBUG(("Cannot allocate changeset"));
4666573Sphitran 		return (FALSE);
4676573Sphitran 	}
4686573Sphitran 
4696573Sphitran 	libhal_changeset_set_property_string(cs, "battery.vendor",
4706573Sphitran 	    bif.bif_oem_info);
4716573Sphitran 	technology = bif.bif_type;
4726573Sphitran 	if (technology != NULL) {
4736573Sphitran 		libhal_changeset_set_property_string(cs,
4746573Sphitran 		    "battery.reporting.technology", technology);
4756573Sphitran 		libhal_changeset_set_property_string(cs, "battery.technology",
4766573Sphitran 		    util_get_battery_technology(technology));
4776573Sphitran 	}
4786573Sphitran 	libhal_changeset_set_property_string(cs, "battery.serial",
4796573Sphitran 	    bif.bif_serial);
4806573Sphitran 	libhal_changeset_set_property_string(cs, "battery.model",
4816573Sphitran 	    bif.bif_model);
4826573Sphitran 
4836573Sphitran 	if (bif.bif_unit) {
4846573Sphitran 		libhal_changeset_set_property_string(cs,
4856573Sphitran 		    "battery.reporting.unit", "mAh");
4866573Sphitran 		strlcpy(reporting_unit, "mAh", sizeof (reporting_unit));
4876573Sphitran 	} else {
4886573Sphitran 		libhal_changeset_set_property_string(cs,
4896573Sphitran 		    "battery.reporting.unit", "mWh");
4906573Sphitran 		strlcpy(reporting_unit, "mWh", sizeof (reporting_unit));
4916573Sphitran 	}
4926573Sphitran 	libhal_changeset_set_property_int(cs, "battery.reporting.last_full",
4936573Sphitran 	    bif.bif_last_cap);
4946573Sphitran 	libhal_changeset_set_property_int(cs, "battery.reporting.design",
4956573Sphitran 	    bif.bif_design_cap);
4966573Sphitran 	reporting_design = bif.bif_design_cap;
4976573Sphitran 	libhal_changeset_set_property_int(cs, "battery.reporting.warning",
4986573Sphitran 	    bif.bif_warn_cap);
4996573Sphitran 	reporting_warning = bif.bif_warn_cap;
5006573Sphitran 	libhal_changeset_set_property_int(cs, "battery.reporting.low",
5016573Sphitran 	    bif.bif_low_cap);
5026573Sphitran 	reporting_low = bif.bif_low_cap;
5036573Sphitran 	libhal_changeset_set_property_int(cs,
5046573Sphitran 	    "battery.reporting.granularity_1", bif.bif_gran1_cap);
5056573Sphitran 	reporting_gran1 = bif.bif_gran1_cap;
5066573Sphitran 	libhal_changeset_set_property_int(cs,
5076573Sphitran 	    "battery.reporting.granularity_2", bif.bif_gran2_cap);
5086573Sphitran 	reporting_gran2 = bif.bif_gran2_cap;
5096573Sphitran 	libhal_changeset_set_property_int(cs, "battery.voltage.design",
5106573Sphitran 	    bif.bif_voltage);
5116573Sphitran 	voltage_design = bif.bif_voltage;
5126573Sphitran 
5136573Sphitran 	if (reporting_unit && strcmp(reporting_unit, "mAh") == 0) {
5146573Sphitran 		/* convert to mWh */
5156573Sphitran 		libhal_changeset_set_property_string(cs,
5166573Sphitran 		    "battery.charge_level.unit", "mWh");
5176573Sphitran 		libhal_changeset_set_property_int(cs,
5186573Sphitran 		    "battery.charge_level.design",
5196573Sphitran 		    (reporting_design * voltage_design) / 1000);
5206573Sphitran 		libhal_changeset_set_property_int(cs,
5216573Sphitran 		    "battery.charge_level.warning",
5226573Sphitran 		    (reporting_warning * voltage_design) / 1000);
5236573Sphitran 		libhal_changeset_set_property_int(cs,
5246573Sphitran 		    "battery.charge_level.low",
5256573Sphitran 		    (reporting_low * voltage_design) / 1000);
5266573Sphitran 		libhal_changeset_set_property_int(cs,
5276573Sphitran 		    "battery.charge_level.granularity_1",
5286573Sphitran 		    (reporting_gran1 * voltage_design) / 1000);
5296573Sphitran 		libhal_changeset_set_property_int(cs,
5306573Sphitran 		    "battery.charge_level.granularity_2",
5316573Sphitran 		    (reporting_gran2 * voltage_design) / 1000);
5326573Sphitran 	} else {
5336573Sphitran 		if (reporting_unit && strcmp(reporting_unit, "mWh") == 0) {
5346573Sphitran 			libhal_changeset_set_property_string(cs,
5356573Sphitran 			    "battery.charge_level.unit", "mWh");
5366573Sphitran 		}
5376573Sphitran 		libhal_changeset_set_property_int(cs,
5386573Sphitran 		    "battery.charge_level.design", reporting_design);
5396573Sphitran 		libhal_changeset_set_property_int(cs,
5406573Sphitran 		    "battery.charge_level.warning", reporting_warning);
5416573Sphitran 		libhal_changeset_set_property_int(cs,
5426573Sphitran 		    "battery.charge_level.low", reporting_low);
5436573Sphitran 		libhal_changeset_set_property_int(cs,
5446573Sphitran 		    "battery.charge_level.granularity_1", reporting_gran1);
5456573Sphitran 		libhal_changeset_set_property_int(cs,
5466573Sphitran 		    "battery.charge_level.granularity_2", reporting_gran2);
5476573Sphitran 	}
5486573Sphitran 
5496573Sphitran 
5506573Sphitran 	dbus_error_init(&error);
5516573Sphitran 	libhal_device_commit_changeset(ctx, cs, &error);
5526573Sphitran 	libhal_device_free_changeset(cs);
5536573Sphitran 	my_dbus_error_free(&error);
5546573Sphitran 	HAL_DEBUG(("battery_static_update() exit"));
5556573Sphitran 	return (TRUE);
5566573Sphitran }
5576573Sphitran 
5586573Sphitran gboolean
battery_update(LibHalContext * ctx,const char * udi,int fd)5596573Sphitran battery_update(LibHalContext *ctx, const char *udi, int fd)
5606573Sphitran {
5616573Sphitran 	acpi_bst_t bst;
5626573Sphitran 	DBusError error;
5636573Sphitran 
5646573Sphitran 	HAL_DEBUG(("battery_update() enter"));
5656573Sphitran 	dbus_error_init(&error);
5666573Sphitran 	libhal_device_set_property_string(ctx, udi, "info.product",
5676573Sphitran 	    "Battery Bay", &error);
5686573Sphitran 	my_dbus_error_free(&error);
5696573Sphitran 	libhal_device_set_property_string(ctx, udi, "info.category", "battery",
5706573Sphitran 	    &error);
5716573Sphitran 
5726573Sphitran 	bzero(&bst, sizeof (bst));
5736573Sphitran 	if (ioctl(fd, ACPI_DRV_IOC_STATUS, &bst) < 0) {
5746573Sphitran 		if (errno == ENXIO) {
5756573Sphitran 			my_dbus_error_free(&error);
5766573Sphitran 			libhal_device_set_property_bool(ctx, udi,
5776573Sphitran 			    "battery.present", FALSE, &error);
5786573Sphitran 		} else {
5796573Sphitran 			my_dbus_error_free(&error);
5806573Sphitran 			return (FALSE);
5816573Sphitran 		}
5826573Sphitran 	} else {
5836573Sphitran 		my_dbus_error_free(&error);
5846573Sphitran 		libhal_device_set_property_bool(ctx, udi, "battery.present",
5856573Sphitran 		    TRUE, &error);
5866573Sphitran 	}
5876573Sphitran 
5886573Sphitran 	my_dbus_error_free(&error);
5896573Sphitran 	if (!libhal_device_get_property_bool(ctx, udi, "battery.present",
5906573Sphitran 	    &error)) {
5916573Sphitran 		HAL_DEBUG(("battery_update(): battery is NOT present"));
5926573Sphitran 		battery_remove(ctx, udi);
5936573Sphitran 	} else {
5946573Sphitran 		HAL_DEBUG(("battery_update(): battery is present"));
5956573Sphitran 		my_dbus_error_free(&error);
5966573Sphitran 		libhal_device_set_property_string(ctx, udi, "battery.type",
5976573Sphitran 		    "primary", &error);
5986573Sphitran 		my_dbus_error_free(&error);
5996573Sphitran 		libhal_device_add_capability(ctx, udi, "battery", &error);
6006573Sphitran 		my_dbus_error_free(&error);
6016573Sphitran 		if (libhal_device_get_property_type(ctx, udi, "battery.vendor",
6026573Sphitran 		    &error) == LIBHAL_PROPERTY_TYPE_INVALID) {
6036573Sphitran 			battery_static_update(ctx, udi, fd);
6046573Sphitran 		}
6056573Sphitran 		battery_dynamic_update(ctx, udi, fd);
6066573Sphitran 	}
6076573Sphitran 	my_dbus_error_free(&error);
6086573Sphitran 	HAL_DEBUG(("battery_update() exit"));
6096573Sphitran 	return (TRUE);
6106573Sphitran }
6116573Sphitran 
6126573Sphitran static gboolean
battery_update_all(LibHalContext * ctx)6136573Sphitran battery_update_all(LibHalContext *ctx)
6146573Sphitran {
6156573Sphitran 	int i;
6166573Sphitran 	int num_devices;
6176573Sphitran 	char **battery_devices;
6186573Sphitran 	int fd;
6196573Sphitran 	DBusError error;
6206573Sphitran 
6216573Sphitran 	HAL_DEBUG(("battery_update_all() enter"));
6226573Sphitran 
6236573Sphitran 	dbus_error_init(&error);
6246573Sphitran 	if ((battery_devices = libhal_manager_find_device_string_match
6256573Sphitran 	    (ctx, "info.category", "battery", &num_devices, &error)) !=
6266573Sphitran 	    NULL) {
6276573Sphitran 		for (i = 0; i < num_devices; i++) {
6286573Sphitran 			my_dbus_error_free(&error);
6296573Sphitran 			if (libhal_device_get_property_bool(ctx,
6306573Sphitran 			    battery_devices[i], "battery.present", &error)) {
6316573Sphitran 				if ((fd = open_device(ctx,
6326573Sphitran 				    battery_devices[i])) == -1) {
6336573Sphitran 					continue;
6346573Sphitran 				}
6356573Sphitran 				battery_dynamic_update(ctx, battery_devices[i],
6366573Sphitran 				    fd);
6376573Sphitran 				close(fd);
6386573Sphitran 			}
6396573Sphitran 		}
6406573Sphitran 		libhal_free_string_array(battery_devices);
6416573Sphitran 	}
6426573Sphitran 	my_dbus_error_free(&error);
6436573Sphitran 	HAL_DEBUG(("battery_update_all() exit"));
6446573Sphitran 	return (TRUE);
6456573Sphitran }
6466573Sphitran 
6476573Sphitran gboolean
ac_adapter_update(LibHalContext * ctx,const char * udi,int fd)6486573Sphitran ac_adapter_update(LibHalContext *ctx, const char *udi, int fd)
6496573Sphitran {
6506573Sphitran 	LibHalChangeSet *cs;
6516573Sphitran 	DBusError error;
6526573Sphitran 
6536573Sphitran 	HAL_DEBUG(("ac_adapter_update() enter"));
6546573Sphitran 	dbus_error_init(&error);
6556573Sphitran 	if (!libhal_device_query_capability(ctx, udi, "ac_adapter", &error)) {
6566573Sphitran 		my_dbus_error_free(&error);
6576573Sphitran 		libhal_device_add_capability(ctx, udi, "ac_adapter", &error);
6586573Sphitran 		if ((cs = libhal_device_new_changeset(udi)) == NULL) {
6596573Sphitran 			my_dbus_error_free(&error);
6606573Sphitran 			return (FALSE);
6616573Sphitran 		}
6626573Sphitran 		libhal_changeset_set_property_string(cs, "info.product",
6636573Sphitran 		    "AC Adapter");
6646573Sphitran 		libhal_changeset_set_property_string(cs, "info.category",
6656573Sphitran 		    "ac_adapter");
6666573Sphitran 		my_dbus_error_free(&error);
6676573Sphitran 		libhal_device_commit_changeset(ctx, cs, &error);
6686573Sphitran 		libhal_device_free_changeset(cs);
6696573Sphitran 	}
6706573Sphitran 	ac_adapter_present(ctx, udi, fd);
6716573Sphitran 	battery_update_all(ctx);
6726573Sphitran 
6736573Sphitran 	my_dbus_error_free(&error);
6746573Sphitran 	HAL_DEBUG(("ac_adapter_update() exit"));
6756573Sphitran 	return (TRUE);
6766573Sphitran }
6776573Sphitran 
6786573Sphitran static gboolean
ac_adapter_update_all(LibHalContext * ctx)6796573Sphitran ac_adapter_update_all(LibHalContext *ctx)
6806573Sphitran {
6816573Sphitran 	int i;
6826573Sphitran 	int num_devices;
6836573Sphitran 	char **ac_adapter_devices;
6846573Sphitran 	int fd;
6856573Sphitran 	DBusError error;
6866573Sphitran 
6876573Sphitran 	HAL_DEBUG(("ac_adapter_update_all() enter"));
6886573Sphitran 	dbus_error_init(&error);
6896573Sphitran 	if ((ac_adapter_devices = libhal_manager_find_device_string_match(
6906573Sphitran 	    ctx, "info.category", "ac_adapter", &num_devices, &error)) !=
6916573Sphitran 	    NULL) {
6926573Sphitran 		for (i = 0; i < num_devices; i++) {
6936573Sphitran 			if ((fd = open_device(ctx, ac_adapter_devices[i]))
6946573Sphitran 			    == -1) {
6956573Sphitran 				continue;
6966573Sphitran 			}
6976573Sphitran 			ac_adapter_present(ctx, ac_adapter_devices[i], fd);
6986573Sphitran 			close(fd);
6996573Sphitran 		}
7006573Sphitran 		libhal_free_string_array(ac_adapter_devices);
7016573Sphitran 	}
7026573Sphitran 	my_dbus_error_free(&error);
7036573Sphitran 	HAL_DEBUG(("ac_adapter_update_all() exit"));
7046573Sphitran 	return (TRUE);
7056573Sphitran }
7066573Sphitran 
7076573Sphitran gboolean
update_devices(gpointer data)7086573Sphitran update_devices(gpointer data)
7096573Sphitran {
7106573Sphitran 	LibHalContext *ctx = (LibHalContext *)data;
7116573Sphitran 
7126573Sphitran 	HAL_DEBUG(("update_devices() enter"));
7136573Sphitran 	ac_adapter_update_all(ctx);
7146573Sphitran 	battery_update_all(ctx);
7156573Sphitran 	HAL_DEBUG(("update_devices() exit"));
7166573Sphitran 	return (TRUE);
7176573Sphitran }
7186573Sphitran 
7196573Sphitran int
open_device(LibHalContext * ctx,char * udi)7206573Sphitran open_device(LibHalContext *ctx, char *udi)
7216573Sphitran {
7226573Sphitran 	char path[HAL_PATH_MAX] = "/devices";
7236573Sphitran 	char *devfs_path;
7246573Sphitran 	DBusError error;
7256573Sphitran 
7266573Sphitran 	dbus_error_init(&error);
7276573Sphitran 	devfs_path = libhal_device_get_property_string(ctx, udi,
7286573Sphitran 	    "solaris.devfs_path", &error);
7296573Sphitran 	my_dbus_error_free(&error);
7306573Sphitran 	if (devfs_path == NULL) {
7316573Sphitran 		return (-1);
7326573Sphitran 	}
7336573Sphitran 	strlcat(path, devfs_path, HAL_PATH_MAX);
7346573Sphitran 	libhal_free_string(devfs_path);
7356573Sphitran 	return (open(path, O_RDONLY | O_NONBLOCK));
7366573Sphitran }
737