xref: /illumos-gate/usr/src/cmd/hal/utils/acpi.c (revision 076d97ab)
17b840e52Sphitran /***************************************************************************
27b840e52Sphitran  *
3d2ec54f7Sphitran  * acpi.c : Main routines for setting battery, AC adapter, and lid properties
47b840e52Sphitran  *
5d2ec54f7Sphitran  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
67b840e52Sphitran  * Use is subject to license terms.
77b840e52Sphitran  *
87b840e52Sphitran  * Licensed under the Academic Free License version 2.1
97b840e52Sphitran  *
107b840e52Sphitran  **************************************************************************/
117b840e52Sphitran 
127b840e52Sphitran #ifdef HAVE_CONFIG_H
137b840e52Sphitran #include <config.h>
147b840e52Sphitran #endif
157b840e52Sphitran 
167b840e52Sphitran #include <unistd.h>
177b840e52Sphitran #include <strings.h>
187b840e52Sphitran #include <string.h>
197b840e52Sphitran #include <kstat.h>
207b840e52Sphitran #include <fcntl.h>
217b840e52Sphitran #include <errno.h>
22d2ec54f7Sphitran #include <sys/acpi_drv.h>
237b840e52Sphitran 
247b840e52Sphitran #include <libhal.h>
257b840e52Sphitran #include "../hald/device_info.h"
267b840e52Sphitran #include "../hald/hald_dbus.h"
277b840e52Sphitran #include "../hald/logger.h"
287b840e52Sphitran #include "../hald/util_pm.h"
29d2ec54f7Sphitran #include "acpi.h"
307b840e52Sphitran 
317b840e52Sphitran 
327b840e52Sphitran static void
my_dbus_error_free(DBusError * error)337b840e52Sphitran my_dbus_error_free(DBusError *error)
347b840e52Sphitran {
357b840e52Sphitran 	if (dbus_error_is_set(error)) {
367b840e52Sphitran 		dbus_error_free(error);
377b840e52Sphitran 	}
387b840e52Sphitran }
397b840e52Sphitran 
40d2ec54f7Sphitran gboolean
laptop_panel_update(LibHalContext * ctx,const char * udi,int fd)41d2ec54f7Sphitran laptop_panel_update(LibHalContext *ctx, const char *udi, int fd)
42d2ec54f7Sphitran {
43d2ec54f7Sphitran 	LibHalChangeSet *cs;
44d2ec54f7Sphitran 	DBusError error;
45d2ec54f7Sphitran 	struct acpi_drv_output_info inf;
46d2ec54f7Sphitran 
47d2ec54f7Sphitran 	HAL_DEBUG(("laptop_panel_update() enter"));
48d2ec54f7Sphitran 
49d2ec54f7Sphitran 	dbus_error_init(&error);
50d2ec54f7Sphitran 	if (!libhal_device_query_capability(ctx, udi, "laptop_panel", &error)) {
51d2ec54f7Sphitran 		bzero(&inf, sizeof (inf));
52d2ec54f7Sphitran 		if ((ioctl(fd, ACPI_DRV_IOC_INFO, &inf) < 0) ||
53d2ec54f7Sphitran 		    (inf.nlev == 0)) {
54d2ec54f7Sphitran 			return (FALSE);
55d2ec54f7Sphitran 		}
56d2ec54f7Sphitran 
57d2ec54f7Sphitran 		my_dbus_error_free(&error);
58d2ec54f7Sphitran 		libhal_device_add_capability(ctx, udi, "laptop_panel", &error);
59d2ec54f7Sphitran 		if ((cs = libhal_device_new_changeset(udi)) == NULL) {
60d2ec54f7Sphitran 			my_dbus_error_free(&error);
61d2ec54f7Sphitran 			return (FALSE);
62d2ec54f7Sphitran 		}
63d2ec54f7Sphitran 		libhal_changeset_set_property_string(cs, "info.product",
64d2ec54f7Sphitran 		    "Generic Backlight Device");
65d2ec54f7Sphitran 		libhal_changeset_set_property_string(cs, "info.category",
66d2ec54f7Sphitran 		    "laptop_panel");
67d2ec54f7Sphitran 		libhal_changeset_set_property_int(cs, "laptop_panel.num_levels",
68d2ec54f7Sphitran 		    inf.nlev);
69d2ec54f7Sphitran 		my_dbus_error_free(&error);
70d2ec54f7Sphitran 		libhal_device_commit_changeset(ctx, cs, &error);
71d2ec54f7Sphitran 		libhal_device_free_changeset(cs);
72d2ec54f7Sphitran 	}
73d2ec54f7Sphitran 	my_dbus_error_free(&error);
74d2ec54f7Sphitran 	HAL_DEBUG(("ac_adapter_present() exit"));
75d2ec54f7Sphitran 	return (TRUE);
76d2ec54f7Sphitran }
77d2ec54f7Sphitran 
78d2ec54f7Sphitran gboolean
lid_update(LibHalContext * ctx,const char * udi,int fd)79d2ec54f7Sphitran lid_update(LibHalContext *ctx, const char *udi, int fd)
80d2ec54f7Sphitran {
81d2ec54f7Sphitran 	LibHalChangeSet *cs;
82d2ec54f7Sphitran 	DBusError error;
83*076d97abSPhi Tran 	int lid_state;
84d2ec54f7Sphitran 
85d2ec54f7Sphitran 	HAL_DEBUG(("lid_update() enter"));
86d2ec54f7Sphitran 
87*076d97abSPhi Tran 	if ((cs = libhal_device_new_changeset(udi)) == NULL) {
88*076d97abSPhi Tran 		return (FALSE);
89*076d97abSPhi Tran 	}
90d2ec54f7Sphitran 	dbus_error_init(&error);
91d2ec54f7Sphitran 	if (!libhal_device_query_capability(ctx, udi, "button", &error)) {
92d2ec54f7Sphitran 		my_dbus_error_free(&error);
93d2ec54f7Sphitran 		libhal_device_add_capability(ctx, udi, "button", &error);
94*076d97abSPhi Tran 		my_dbus_error_free(&error);
95*076d97abSPhi Tran 		libhal_changeset_set_property_bool(cs, "button.has_state",
96*076d97abSPhi Tran 		    TRUE);
97*076d97abSPhi Tran 
98*076d97abSPhi Tran 		if (ioctl(fd, ACPI_DRV_IOC_LID_STATUS, &lid_state) < 0) {
99d2ec54f7Sphitran 			return (FALSE);
100d2ec54f7Sphitran 		}
101*076d97abSPhi Tran 		if (lid_state != 0) {
102*076d97abSPhi Tran 			/* lid open */
103*076d97abSPhi Tran 			libhal_changeset_set_property_bool(cs,
104*076d97abSPhi Tran 			    "button.state.value", FALSE);
105*076d97abSPhi Tran 		} else {
106*076d97abSPhi Tran 			/* lid closed */
107*076d97abSPhi Tran 			libhal_changeset_set_property_bool(cs,
108*076d97abSPhi Tran 			    "button.state.value", TRUE);
109*076d97abSPhi Tran 		}
110*076d97abSPhi Tran 		libhal_changeset_set_property_bool(cs, "button.workaround",
111d2ec54f7Sphitran 		    TRUE);
112d2ec54f7Sphitran 		libhal_changeset_set_property_string(cs, "button.type",
113d2ec54f7Sphitran 		    "lid");
114d2ec54f7Sphitran 		libhal_changeset_set_property_string(cs, "info.product",
115d2ec54f7Sphitran 		    "Lid Switch");
116d2ec54f7Sphitran 		libhal_changeset_set_property_string(cs, "info.category",
117d2ec54f7Sphitran 		    "button");
118*076d97abSPhi Tran 	} else {
119d2ec54f7Sphitran 		my_dbus_error_free(&error);
120*076d97abSPhi Tran 		if (ioctl(fd, ACPI_DRV_IOC_LID_UPDATE, &lid_state) < 0) {
121*076d97abSPhi Tran 			return (FALSE);
122*076d97abSPhi Tran 		}
123*076d97abSPhi Tran 		if (lid_state != 0) {
124*076d97abSPhi Tran 			/* lid open */
125*076d97abSPhi Tran 			libhal_changeset_set_property_bool(cs,
126*076d97abSPhi Tran 			    "button.state.value", FALSE);
127*076d97abSPhi Tran 		} else {
128*076d97abSPhi Tran 			/* lid closed */
129*076d97abSPhi Tran 			libhal_changeset_set_property_bool(cs,
130*076d97abSPhi Tran 			    "button.state.value", TRUE);
131*076d97abSPhi Tran 		}
132d2ec54f7Sphitran 	}
133*076d97abSPhi Tran 
134*076d97abSPhi Tran 	libhal_device_commit_changeset(ctx, cs, &error);
135*076d97abSPhi Tran 	libhal_device_free_changeset(cs);
136d2ec54f7Sphitran 	my_dbus_error_free(&error);
137d2ec54f7Sphitran 	HAL_DEBUG(("update_lid() exit"));
138d2ec54f7Sphitran 	return (TRUE);
139d2ec54f7Sphitran }
140d2ec54f7Sphitran 
1417b840e52Sphitran static void
ac_adapter_present(LibHalContext * ctx,const char * udi,int fd)1427b840e52Sphitran ac_adapter_present(LibHalContext *ctx, const char *udi, int fd)
1437b840e52Sphitran {
1447b840e52Sphitran 	int pow;
1457b840e52Sphitran 	LibHalChangeSet *cs;
1467b840e52Sphitran 	DBusError error;
1477b840e52Sphitran 
1487b840e52Sphitran 	HAL_DEBUG(("ac_adapter_present() enter"));
149d2ec54f7Sphitran 	if (ioctl(fd, ACPI_DRV_IOC_POWER_STATUS, &pow) < 0) {
1507b840e52Sphitran 		return;
1517b840e52Sphitran 	}
1527b840e52Sphitran 	if ((cs = libhal_device_new_changeset(udi)) == NULL) {
1537b840e52Sphitran 		return;
1547b840e52Sphitran 	}
1557b840e52Sphitran 	if (pow > 0) {
1567b840e52Sphitran 		libhal_changeset_set_property_bool(cs, "ac_adapter.present",
1577b840e52Sphitran 		    TRUE);
1587b840e52Sphitran 	} else {
1597b840e52Sphitran 		libhal_changeset_set_property_bool(cs, "ac_adapter.present",
1607b840e52Sphitran 		    FALSE);
1617b840e52Sphitran 	}
1627b840e52Sphitran 
1637b840e52Sphitran 	dbus_error_init(&error);
1647b840e52Sphitran 	libhal_device_commit_changeset(ctx, cs, &error);
1657b840e52Sphitran 	libhal_device_free_changeset(cs);
1667b840e52Sphitran 	my_dbus_error_free(&error);
1677b840e52Sphitran 	HAL_DEBUG(("ac_adapter_present() exit"));
1687b840e52Sphitran }
1697b840e52Sphitran 
1707b840e52Sphitran static void
battery_remove(LibHalContext * ctx,const char * udi)1717b840e52Sphitran battery_remove(LibHalContext *ctx, const char *udi)
1727b840e52Sphitran {
1737b840e52Sphitran 	DBusError error;
1747b840e52Sphitran 
1757b840e52Sphitran 	HAL_DEBUG(("battery_remove() enter"));
1767b840e52Sphitran 	dbus_error_init(&error);
1777b840e52Sphitran 	libhal_device_remove_property(ctx, udi, "battery.remaining_time",
1787b840e52Sphitran 	    &error);
1797b840e52Sphitran 	my_dbus_error_free(&error);
1807b840e52Sphitran 	libhal_device_remove_property(ctx, udi,
1817b840e52Sphitran 	    "battery.charge_level.percentage", &error);
1827b840e52Sphitran 	my_dbus_error_free(&error);
1837b840e52Sphitran 	libhal_device_remove_property(ctx, udi, "battery.charge_level.rate",
1847b840e52Sphitran 	    &error);
1857b840e52Sphitran 	my_dbus_error_free(&error);
1867b840e52Sphitran 	libhal_device_remove_property(ctx, udi,
1877b840e52Sphitran 	    "battery.charge_level.last_full", &error);
1887b840e52Sphitran 	my_dbus_error_free(&error);
1897b840e52Sphitran 	libhal_device_remove_property(ctx, udi,
1907b840e52Sphitran 	    "battery.charge_level.current", &error);
1917b840e52Sphitran 	my_dbus_error_free(&error);
1927b840e52Sphitran 	libhal_device_remove_property(ctx, udi, "battery.voltage.present",
1937b840e52Sphitran 	    &error);
1947b840e52Sphitran 	my_dbus_error_free(&error);
1957b840e52Sphitran 	libhal_device_remove_property(ctx, udi, "battery.reporting.rate",
1967b840e52Sphitran 	    &error);
1977b840e52Sphitran 	my_dbus_error_free(&error);
1987b840e52Sphitran 	libhal_device_remove_property(ctx, udi, "battery.reporting.current",
1997b840e52Sphitran 	    &error);
2007b840e52Sphitran 	my_dbus_error_free(&error);
2017b840e52Sphitran 	libhal_device_remove_property(ctx, udi,
2027b840e52Sphitran 	    "battery.rechargeable.is_discharging", &error);
2037b840e52Sphitran 	my_dbus_error_free(&error);
2047b840e52Sphitran 	libhal_device_remove_property(ctx, udi,
2057b840e52Sphitran 	    "battery.rechargeable.is_charging", &error);
2067b840e52Sphitran 	my_dbus_error_free(&error);
2077b840e52Sphitran 	libhal_device_remove_property(ctx, udi, "battery.is_rechargeable",
2087b840e52Sphitran 	    &error);
2097b840e52Sphitran 	my_dbus_error_free(&error);
2107b840e52Sphitran 	libhal_device_remove_property(ctx, udi, "battery.charge_level.unit",
2117b840e52Sphitran 	    &error);
2127b840e52Sphitran 	my_dbus_error_free(&error);
2137b840e52Sphitran 	libhal_device_remove_property(ctx, udi,
2147b840e52Sphitran 	    "battery.charge_level.granularity_2", &error);
2157b840e52Sphitran 	my_dbus_error_free(&error);
2167b840e52Sphitran 	libhal_device_remove_property(ctx, udi,
2177b840e52Sphitran 	    "battery.charge_level.granularity_1", &error);
2187b840e52Sphitran 	my_dbus_error_free(&error);
2197b840e52Sphitran 	libhal_device_remove_property(ctx, udi, "battery.charge_level.low",
2207b840e52Sphitran 	    &error);
2217b840e52Sphitran 	my_dbus_error_free(&error);
2227b840e52Sphitran 	libhal_device_remove_property(ctx, udi, "battery.charge_level.warning",
2237b840e52Sphitran 	    &error);
2247b840e52Sphitran 	my_dbus_error_free(&error);
2257b840e52Sphitran 	libhal_device_remove_property(ctx, udi, "battery.charge_level.design",
2267b840e52Sphitran 	    &error);
2277b840e52Sphitran 	my_dbus_error_free(&error);
2287b840e52Sphitran 	libhal_device_remove_property(ctx, udi, "battery.voltage.design",
2297b840e52Sphitran 	    &error);
2307b840e52Sphitran 	my_dbus_error_free(&error);
2317b840e52Sphitran 	libhal_device_remove_property(ctx, udi,
2327b840e52Sphitran 	    "battery.reporting.granularity_2", &error);
2337b840e52Sphitran 	my_dbus_error_free(&error);
2347b840e52Sphitran 	libhal_device_remove_property(ctx, udi,
2357b840e52Sphitran 	    "battery.reporting.granularity_1", &error);
2367b840e52Sphitran 	my_dbus_error_free(&error);
2377b840e52Sphitran 	libhal_device_remove_property(ctx, udi, "battery.reporting.low",
2387b840e52Sphitran 	    &error);
2397b840e52Sphitran 	my_dbus_error_free(&error);
2407b840e52Sphitran 	libhal_device_remove_property(ctx, udi, "battery.reporting.warning",
2417b840e52Sphitran 	    &error);
2427b840e52Sphitran 	my_dbus_error_free(&error);
2437b840e52Sphitran 	libhal_device_remove_property(ctx, udi, "battery.reporting.design",
2447b840e52Sphitran 	    &error);
2457b840e52Sphitran 	my_dbus_error_free(&error);
2467b840e52Sphitran 	libhal_device_remove_property(ctx, udi, "battery.reporting.last_full",
2477b840e52Sphitran 	    &error);
2487b840e52Sphitran 	my_dbus_error_free(&error);
2497b840e52Sphitran 	libhal_device_remove_property(ctx, udi, "battery.reporting.unit",
2507b840e52Sphitran 	    &error);
2517b840e52Sphitran 	my_dbus_error_free(&error);
2527b840e52Sphitran 	libhal_device_remove_property(ctx, udi, "battery.technology", &error);
2537b840e52Sphitran 	my_dbus_error_free(&error);
2547b840e52Sphitran 	libhal_device_remove_property(ctx, udi, "battery.reporting.technology",
2557b840e52Sphitran 	    &error);
2567b840e52Sphitran 	my_dbus_error_free(&error);
2577b840e52Sphitran 	libhal_device_remove_property(ctx, udi, "battery.serial", &error);
2587b840e52Sphitran 	my_dbus_error_free(&error);
2597b840e52Sphitran 	libhal_device_remove_property(ctx, udi, "battery.model", &error);
2607b840e52Sphitran 	my_dbus_error_free(&error);
2617b840e52Sphitran 	libhal_device_remove_property(ctx, udi, "battery.vendor", &error);
2627b840e52Sphitran 	my_dbus_error_free(&error);
2637b840e52Sphitran 	HAL_DEBUG(("battery_remove() exit"));
2647b840e52Sphitran }
2657b840e52Sphitran 
2667b840e52Sphitran static void
battery_last_full(LibHalChangeSet * cs,int fd)2677b840e52Sphitran battery_last_full(LibHalChangeSet *cs, int fd)
2687b840e52Sphitran {
2697b840e52Sphitran 	acpi_bif_t bif;
2707b840e52Sphitran 
2717b840e52Sphitran 	bzero(&bif, sizeof (bif));
272d2ec54f7Sphitran 	if (ioctl(fd, ACPI_DRV_IOC_INFO, &bif) < 0) {
2737b840e52Sphitran 		return;
2747b840e52Sphitran 	}
2757b840e52Sphitran 	libhal_changeset_set_property_int(cs, "battery.reporting_last_full",
2767b840e52Sphitran 	    bif.bif_last_cap);
2777b840e52Sphitran }
2787b840e52Sphitran 
2797b840e52Sphitran static void
battery_dynamic_update(LibHalContext * ctx,const char * udi,int fd)2807b840e52Sphitran battery_dynamic_update(LibHalContext *ctx, const char *udi, int fd)
2817b840e52Sphitran {
2827b840e52Sphitran 	int reporting_rate;
2837b840e52Sphitran 	int reporting_current;
2847b840e52Sphitran 	int reporting_lastfull;
2857b840e52Sphitran 	int design_voltage;
2867b840e52Sphitran 	int present_voltage;
2877b840e52Sphitran 	char *reporting_unit;
2887b840e52Sphitran 	int remaining_time;
2897b840e52Sphitran 	int remaining_percentage;
2907b840e52Sphitran 	gboolean charging;
2917b840e52Sphitran 	gboolean discharging;
2927b840e52Sphitran 	acpi_bst_t bst;
2937b840e52Sphitran 	LibHalChangeSet *cs;
2947b840e52Sphitran 	DBusError error;
2957b840e52Sphitran 	static int counter = 0;
2967b840e52Sphitran 
2977b840e52Sphitran 	HAL_DEBUG(("battery_dynamic_update() enter"));
2987b840e52Sphitran 	bzero(&bst, sizeof (bst));
299d2ec54f7Sphitran 	if (ioctl(fd, ACPI_DRV_IOC_STATUS, &bst) < 0) {
3007b840e52Sphitran 		return;
3017b840e52Sphitran 	}
3027b840e52Sphitran 
303d2ec54f7Sphitran 	charging = bst.bst_state & ACPI_DRV_BST_CHARGING ? TRUE : FALSE;
304d2ec54f7Sphitran 	discharging = bst.bst_state & ACPI_DRV_BST_DISCHARGING ? TRUE : FALSE;
3057b840e52Sphitran 	/* No need to continue if battery is essentially idle. */
3067b840e52Sphitran 	if (counter && !charging && !discharging) {
3077b840e52Sphitran 		return;
3087b840e52Sphitran 	}
3097b840e52Sphitran 	dbus_error_init(&error);
3107b840e52Sphitran 	libhal_device_set_property_bool(ctx, udi, "battery.is_rechargeable",
3117b840e52Sphitran 	    TRUE, &error);
3127b840e52Sphitran 	my_dbus_error_free(&error);
3137b840e52Sphitran 	if (libhal_device_property_exists(ctx, udi,
3147b840e52Sphitran 	    "battery.charge_level.percentage", &error)) {
3157b840e52Sphitran 		remaining_percentage = libhal_device_get_property_int(ctx, udi,
3167b840e52Sphitran 		    "battery.charge_level.percentage", &error);
3177b840e52Sphitran 		if ((remaining_percentage == 100) && charging) {
3187b840e52Sphitran 			charging = FALSE;
3197b840e52Sphitran 		}
3207b840e52Sphitran 	}
3217b840e52Sphitran 	libhal_device_set_property_bool(ctx, udi,
3227b840e52Sphitran 	    "battery.rechargeable.is_charging", charging, &error);
3237b840e52Sphitran 	my_dbus_error_free(&error);
3247b840e52Sphitran 	libhal_device_set_property_bool(ctx, udi,
3257b840e52Sphitran 	    "battery.rechargeable.is_discharging", discharging, &error);
3267b840e52Sphitran 	my_dbus_error_free(&error);
3277b840e52Sphitran 	reporting_current = bst.bst_rem_cap;
3287b840e52Sphitran 	libhal_device_set_property_int(ctx, udi, "battery.reporting.current",
3297b840e52Sphitran 	    bst.bst_rem_cap, &error);
3307b840e52Sphitran 	my_dbus_error_free(&error);
3317b840e52Sphitran 	reporting_rate = bst.bst_rate;
3327b840e52Sphitran 	libhal_device_set_property_int(ctx, udi, "battery.reporting.rate",
3337b840e52Sphitran 	    bst.bst_rate, &error);
3347b840e52Sphitran 	my_dbus_error_free(&error);
3357b840e52Sphitran 	present_voltage = bst.bst_voltage;
3367b840e52Sphitran 	libhal_device_set_property_int(ctx, udi, "battery.voltage.present",
3377b840e52Sphitran 	    bst.bst_voltage, &error);
3387b840e52Sphitran 	/* get all the data we know */
3397b840e52Sphitran 	my_dbus_error_free(&error);
3407b840e52Sphitran 	reporting_unit = libhal_device_get_property_string(ctx, udi,
3417b840e52Sphitran 	    "battery.reporting.unit", &error);
3427b840e52Sphitran 	my_dbus_error_free(&error);
3437b840e52Sphitran 	reporting_lastfull = libhal_device_get_property_int(ctx, udi,
3447b840e52Sphitran 	    "battery.reporting.last_full", &error);
3457b840e52Sphitran 
3467b840e52Sphitran 	/*
3477b840e52Sphitran 	 * Convert mAh to mWh since util_compute_time_remaining() works
3487b840e52Sphitran 	 * for mWh.
3497b840e52Sphitran 	 */
3507b840e52Sphitran 	if (reporting_unit && strcmp(reporting_unit, "mAh") == 0) {
3517b840e52Sphitran 		my_dbus_error_free(&error);
3527b840e52Sphitran 		design_voltage = libhal_device_get_property_int(ctx, udi,
3537b840e52Sphitran 		    "battery.voltage.design", &error);
3547b840e52Sphitran 		/*
3557b840e52Sphitran 		 * If the present_voltage is inaccurate, set it to the
3567b840e52Sphitran 		 * design_voltage.
3577b840e52Sphitran 		 */
3587b840e52Sphitran 		if (((present_voltage * 10) < design_voltage) ||
3597b840e52Sphitran 		    (present_voltage <= 0) ||
3607b840e52Sphitran 		    (present_voltage > design_voltage)) {
3617b840e52Sphitran 			present_voltage = design_voltage;
3627b840e52Sphitran 		}
3637b840e52Sphitran 		reporting_rate = (reporting_rate * present_voltage) / 1000;
3647b840e52Sphitran 		reporting_lastfull = (reporting_lastfull * present_voltage) /
3657b840e52Sphitran 		    1000;
3667b840e52Sphitran 		reporting_current = (reporting_current * present_voltage) /
3677b840e52Sphitran 		    1000;
3687b840e52Sphitran 	}
3697b840e52Sphitran 
3707b840e52Sphitran 	/* Make sure the current charge does not exceed the full charge */
3717b840e52Sphitran 	if (reporting_current > reporting_lastfull) {
3727b840e52Sphitran 		reporting_current = reporting_lastfull;
3737b840e52Sphitran 	}
3747b840e52Sphitran 	if (!charging && !discharging) {
3757b840e52Sphitran 		counter++;
3767b840e52Sphitran 		reporting_rate = 0;
3777b840e52Sphitran 	}
3787b840e52Sphitran 
3797b840e52Sphitran 	if ((cs = libhal_device_new_changeset(udi)) == NULL) {
3807b840e52Sphitran 		HAL_DEBUG(("Cannot allocate changeset"));
3817b840e52Sphitran 		libhal_free_string(reporting_unit);
3827b840e52Sphitran 		my_dbus_error_free(&error);
3837b840e52Sphitran 		return;
3847b840e52Sphitran 	}
3857b840e52Sphitran 
3867b840e52Sphitran 	libhal_changeset_set_property_int(cs, "battery.charge_level.rate",
3877b840e52Sphitran 	    reporting_rate);
3887b840e52Sphitran 	libhal_changeset_set_property_int(cs,
3897b840e52Sphitran 	    "battery.charge_level.last_full", reporting_lastfull);
3907b840e52Sphitran 	libhal_changeset_set_property_int(cs,
3917b840e52Sphitran 	    "battery.charge_level.current", reporting_current);
3927b840e52Sphitran 
3937b840e52Sphitran 	remaining_percentage = util_compute_percentage_charge(udi,
3947b840e52Sphitran 	    reporting_current, reporting_lastfull);
3957b840e52Sphitran 	remaining_time = util_compute_time_remaining(udi, reporting_rate,
3967b840e52Sphitran 	    reporting_current, reporting_lastfull, discharging, charging, 0);
3977b840e52Sphitran 	/*
3987b840e52Sphitran 	 * Some batteries give bad remaining_time estimates relative to
3997b840e52Sphitran 	 * the charge level.
4007b840e52Sphitran 	 */
4017b840e52Sphitran 	if (charging && ((remaining_time < 30) || ((remaining_time < 300) &&
4027b840e52Sphitran 	    (remaining_percentage < 95)) || (remaining_percentage > 97))) {
4037b840e52Sphitran 		remaining_time = util_compute_time_remaining(udi,
4047b840e52Sphitran 		    reporting_rate, reporting_current, reporting_lastfull,
4057b840e52Sphitran 		    discharging, charging, 1);
4067b840e52Sphitran 	}
4077b840e52Sphitran 
4087b840e52Sphitran 	if (remaining_percentage > 0) {
4097b840e52Sphitran 		libhal_changeset_set_property_int(cs,
4107b840e52Sphitran 		    "battery.charge_level.percentage", remaining_percentage);
4117b840e52Sphitran 	} else {
4127b840e52Sphitran 		my_dbus_error_free(&error);
4137b840e52Sphitran 		libhal_device_remove_property(ctx, udi,
4147b840e52Sphitran 		    "battery.charge_level.percentage", &error);
4157b840e52Sphitran 	}
4167b840e52Sphitran 	if ((remaining_percentage == 100) && charging) {
4177b840e52Sphitran 		battery_last_full(cs, fd);
4187b840e52Sphitran 	}
4197b840e52Sphitran 	/*
4207b840e52Sphitran 	 * remaining_percentage is more accurate so we handle cases
4217b840e52Sphitran 	 * where the remaining_time cannot be correct.
4227b840e52Sphitran 	 */
4237b840e52Sphitran 	if ((!charging && !discharging) || ((remaining_percentage == 100) &&
4247b840e52Sphitran 	    !discharging)) {
4257b840e52Sphitran 		remaining_time = 0;
4267b840e52Sphitran 	}
4277b840e52Sphitran 	if (remaining_time < 0) {
4287b840e52Sphitran 		my_dbus_error_free(&error);
4297b840e52Sphitran 		libhal_device_remove_property(ctx, udi,
4307b840e52Sphitran 		    "battery.remaining_time", &error);
4317b840e52Sphitran 	} else if (remaining_time >= 0) {
4327b840e52Sphitran 		libhal_changeset_set_property_int(cs,
4337b840e52Sphitran 		    "battery.remaining_time", remaining_time);
4347b840e52Sphitran 	}
4357b840e52Sphitran 
4367b840e52Sphitran 	my_dbus_error_free(&error);
4377b840e52Sphitran 	libhal_device_commit_changeset(ctx, cs, &error);
4387b840e52Sphitran 	libhal_device_free_changeset(cs);
4397b840e52Sphitran 	libhal_free_string(reporting_unit);
4407b840e52Sphitran 	my_dbus_error_free(&error);
4417b840e52Sphitran 	HAL_DEBUG(("battery_dynamic_update() exit"));
4427b840e52Sphitran }
4437b840e52Sphitran 
4447b840e52Sphitran static gboolean
battery_static_update(LibHalContext * ctx,const char * udi,int fd)4457b840e52Sphitran battery_static_update(LibHalContext *ctx, const char *udi, int fd)
4467b840e52Sphitran {
4477b840e52Sphitran 	const char *technology;
4487b840e52Sphitran 	int reporting_design;
4497b840e52Sphitran 	int reporting_warning;
4507b840e52Sphitran 	int reporting_low;
4517b840e52Sphitran 	int reporting_gran1;
4527b840e52Sphitran 	int reporting_gran2;
4537b840e52Sphitran 	int voltage_design;
4547b840e52Sphitran 	char reporting_unit[10];
4557b840e52Sphitran 	acpi_bif_t bif;
4567b840e52Sphitran 	LibHalChangeSet *cs;
4577b840e52Sphitran 	DBusError error;
4587b840e52Sphitran 
4597b840e52Sphitran 	HAL_DEBUG(("battery_static_update() enter"));
4607b840e52Sphitran 	bzero(&bif, sizeof (bif));
461d2ec54f7Sphitran 	if (ioctl(fd, ACPI_DRV_IOC_INFO, &bif) < 0) {
4627b840e52Sphitran 		return (FALSE);
4637b840e52Sphitran 	}
4647b840e52Sphitran 	if ((cs = libhal_device_new_changeset(udi)) == NULL) {
4657b840e52Sphitran 		HAL_DEBUG(("Cannot allocate changeset"));
4667b840e52Sphitran 		return (FALSE);
4677b840e52Sphitran 	}
4687b840e52Sphitran 
4697b840e52Sphitran 	libhal_changeset_set_property_string(cs, "battery.vendor",
4707b840e52Sphitran 	    bif.bif_oem_info);
4717b840e52Sphitran 	technology = bif.bif_type;
4727b840e52Sphitran 	if (technology != NULL) {
4737b840e52Sphitran 		libhal_changeset_set_property_string(cs,
4747b840e52Sphitran 		    "battery.reporting.technology", technology);
4757b840e52Sphitran 		libhal_changeset_set_property_string(cs, "battery.technology",
4767b840e52Sphitran 		    util_get_battery_technology(technology));
4777b840e52Sphitran 	}
4787b840e52Sphitran 	libhal_changeset_set_property_string(cs, "battery.serial",
4797b840e52Sphitran 	    bif.bif_serial);
4807b840e52Sphitran 	libhal_changeset_set_property_string(cs, "battery.model",
4817b840e52Sphitran 	    bif.bif_model);
4827b840e52Sphitran 
4837b840e52Sphitran 	if (bif.bif_unit) {
4847b840e52Sphitran 		libhal_changeset_set_property_string(cs,
4857b840e52Sphitran 		    "battery.reporting.unit", "mAh");
4867b840e52Sphitran 		strlcpy(reporting_unit, "mAh", sizeof (reporting_unit));
4877b840e52Sphitran 	} else {
4887b840e52Sphitran 		libhal_changeset_set_property_string(cs,
4897b840e52Sphitran 		    "battery.reporting.unit", "mWh");
4907b840e52Sphitran 		strlcpy(reporting_unit, "mWh", sizeof (reporting_unit));
4917b840e52Sphitran 	}
4927b840e52Sphitran 	libhal_changeset_set_property_int(cs, "battery.reporting.last_full",
4937b840e52Sphitran 	    bif.bif_last_cap);
4947b840e52Sphitran 	libhal_changeset_set_property_int(cs, "battery.reporting.design",
4957b840e52Sphitran 	    bif.bif_design_cap);
4967b840e52Sphitran 	reporting_design = bif.bif_design_cap;
4977b840e52Sphitran 	libhal_changeset_set_property_int(cs, "battery.reporting.warning",
4987b840e52Sphitran 	    bif.bif_warn_cap);
4997b840e52Sphitran 	reporting_warning = bif.bif_warn_cap;
5007b840e52Sphitran 	libhal_changeset_set_property_int(cs, "battery.reporting.low",
5017b840e52Sphitran 	    bif.bif_low_cap);
5027b840e52Sphitran 	reporting_low = bif.bif_low_cap;
5037b840e52Sphitran 	libhal_changeset_set_property_int(cs,
5047b840e52Sphitran 	    "battery.reporting.granularity_1", bif.bif_gran1_cap);
5057b840e52Sphitran 	reporting_gran1 = bif.bif_gran1_cap;
5067b840e52Sphitran 	libhal_changeset_set_property_int(cs,
5077b840e52Sphitran 	    "battery.reporting.granularity_2", bif.bif_gran2_cap);
5087b840e52Sphitran 	reporting_gran2 = bif.bif_gran2_cap;
5097b840e52Sphitran 	libhal_changeset_set_property_int(cs, "battery.voltage.design",
5107b840e52Sphitran 	    bif.bif_voltage);
5117b840e52Sphitran 	voltage_design = bif.bif_voltage;
5127b840e52Sphitran 
5137b840e52Sphitran 	if (reporting_unit && strcmp(reporting_unit, "mAh") == 0) {
5147b840e52Sphitran 		/* convert to mWh */
5157b840e52Sphitran 		libhal_changeset_set_property_string(cs,
5167b840e52Sphitran 		    "battery.charge_level.unit", "mWh");
5177b840e52Sphitran 		libhal_changeset_set_property_int(cs,
5187b840e52Sphitran 		    "battery.charge_level.design",
5197b840e52Sphitran 		    (reporting_design * voltage_design) / 1000);
5207b840e52Sphitran 		libhal_changeset_set_property_int(cs,
5217b840e52Sphitran 		    "battery.charge_level.warning",
5227b840e52Sphitran 		    (reporting_warning * voltage_design) / 1000);
5237b840e52Sphitran 		libhal_changeset_set_property_int(cs,
5247b840e52Sphitran 		    "battery.charge_level.low",
5257b840e52Sphitran 		    (reporting_low * voltage_design) / 1000);
5267b840e52Sphitran 		libhal_changeset_set_property_int(cs,
5277b840e52Sphitran 		    "battery.charge_level.granularity_1",
5287b840e52Sphitran 		    (reporting_gran1 * voltage_design) / 1000);
5297b840e52Sphitran 		libhal_changeset_set_property_int(cs,
5307b840e52Sphitran 		    "battery.charge_level.granularity_2",
5317b840e52Sphitran 		    (reporting_gran2 * voltage_design) / 1000);
5327b840e52Sphitran 	} else {
5337b840e52Sphitran 		if (reporting_unit && strcmp(reporting_unit, "mWh") == 0) {
5347b840e52Sphitran 			libhal_changeset_set_property_string(cs,
5357b840e52Sphitran 			    "battery.charge_level.unit", "mWh");
5367b840e52Sphitran 		}
5377b840e52Sphitran 		libhal_changeset_set_property_int(cs,
538d2ec54f7Sphitran 		    "battery.charge_level.design", reporting_design);
539d2ec54f7Sphitran 		libhal_changeset_set_property_int(cs,
540d2ec54f7Sphitran 		    "battery.charge_level.warning", reporting_warning);
541d2ec54f7Sphitran 		libhal_changeset_set_property_int(cs,
542d2ec54f7Sphitran 		    "battery.charge_level.low", reporting_low);
543d2ec54f7Sphitran 		libhal_changeset_set_property_int(cs,
544d2ec54f7Sphitran 		    "battery.charge_level.granularity_1", reporting_gran1);
545d2ec54f7Sphitran 		libhal_changeset_set_property_int(cs,
546d2ec54f7Sphitran 		    "battery.charge_level.granularity_2", reporting_gran2);
5477b840e52Sphitran 	}
548d2ec54f7Sphitran 
5497b840e52Sphitran 
5507b840e52Sphitran 	dbus_error_init(&error);
5517b840e52Sphitran 	libhal_device_commit_changeset(ctx, cs, &error);
5527b840e52Sphitran 	libhal_device_free_changeset(cs);
5537b840e52Sphitran 	my_dbus_error_free(&error);
5547b840e52Sphitran 	HAL_DEBUG(("battery_static_update() exit"));
5557b840e52Sphitran 	return (TRUE);
5567b840e52Sphitran }
5577b840e52Sphitran 
5587b840e52Sphitran gboolean
battery_update(LibHalContext * ctx,const char * udi,int fd)5597b840e52Sphitran battery_update(LibHalContext *ctx, const char *udi, int fd)
5607b840e52Sphitran {
5617b840e52Sphitran 	acpi_bst_t bst;
5627b840e52Sphitran 	DBusError error;
5637b840e52Sphitran 
5647b840e52Sphitran 	HAL_DEBUG(("battery_update() enter"));
5657b840e52Sphitran 	dbus_error_init(&error);
5667b840e52Sphitran 	libhal_device_set_property_string(ctx, udi, "info.product",
5677b840e52Sphitran 	    "Battery Bay", &error);
5687b840e52Sphitran 	my_dbus_error_free(&error);
5697b840e52Sphitran 	libhal_device_set_property_string(ctx, udi, "info.category", "battery",
5707b840e52Sphitran 	    &error);
5717b840e52Sphitran 
5727b840e52Sphitran 	bzero(&bst, sizeof (bst));
573d2ec54f7Sphitran 	if (ioctl(fd, ACPI_DRV_IOC_STATUS, &bst) < 0) {
5747b840e52Sphitran 		if (errno == ENXIO) {
5757b840e52Sphitran 			my_dbus_error_free(&error);
5767b840e52Sphitran 			libhal_device_set_property_bool(ctx, udi,
5777b840e52Sphitran 			    "battery.present", FALSE, &error);
5787b840e52Sphitran 		} else {
5797b840e52Sphitran 			my_dbus_error_free(&error);
5807b840e52Sphitran 			return (FALSE);
5817b840e52Sphitran 		}
5827b840e52Sphitran 	} else {
5837b840e52Sphitran 		my_dbus_error_free(&error);
5847b840e52Sphitran 		libhal_device_set_property_bool(ctx, udi, "battery.present",
5857b840e52Sphitran 		    TRUE, &error);
5867b840e52Sphitran 	}
5877b840e52Sphitran 
5887b840e52Sphitran 	my_dbus_error_free(&error);
5897b840e52Sphitran 	if (!libhal_device_get_property_bool(ctx, udi, "battery.present",
5907b840e52Sphitran 	    &error)) {
5917b840e52Sphitran 		HAL_DEBUG(("battery_update(): battery is NOT present"));
5927b840e52Sphitran 		battery_remove(ctx, udi);
5937b840e52Sphitran 	} else {
5947b840e52Sphitran 		HAL_DEBUG(("battery_update(): battery is present"));
5957b840e52Sphitran 		my_dbus_error_free(&error);
5967b840e52Sphitran 		libhal_device_set_property_string(ctx, udi, "battery.type",
5977b840e52Sphitran 		    "primary", &error);
5987b840e52Sphitran 		my_dbus_error_free(&error);
5997b840e52Sphitran 		libhal_device_add_capability(ctx, udi, "battery", &error);
6007b840e52Sphitran 		my_dbus_error_free(&error);
6017b840e52Sphitran 		if (libhal_device_get_property_type(ctx, udi, "battery.vendor",
6027b840e52Sphitran 		    &error) == LIBHAL_PROPERTY_TYPE_INVALID) {
6037b840e52Sphitran 			battery_static_update(ctx, udi, fd);
6047b840e52Sphitran 		}
6057b840e52Sphitran 		battery_dynamic_update(ctx, udi, fd);
6067b840e52Sphitran 	}
6077b840e52Sphitran 	my_dbus_error_free(&error);
6087b840e52Sphitran 	HAL_DEBUG(("battery_update() exit"));
6097b840e52Sphitran 	return (TRUE);
6107b840e52Sphitran }
6117b840e52Sphitran 
6127b840e52Sphitran static gboolean
battery_update_all(LibHalContext * ctx)6137b840e52Sphitran battery_update_all(LibHalContext *ctx)
6147b840e52Sphitran {
6157b840e52Sphitran 	int i;
6167b840e52Sphitran 	int num_devices;
6177b840e52Sphitran 	char **battery_devices;
6187b840e52Sphitran 	int fd;
6197b840e52Sphitran 	DBusError error;
6207b840e52Sphitran 
6217b840e52Sphitran 	HAL_DEBUG(("battery_update_all() enter"));
6227b840e52Sphitran 
6237b840e52Sphitran 	dbus_error_init(&error);
6247b840e52Sphitran 	if ((battery_devices = libhal_manager_find_device_string_match
6257b840e52Sphitran 	    (ctx, "info.category", "battery", &num_devices, &error)) !=
6267b840e52Sphitran 	    NULL) {
6277b840e52Sphitran 		for (i = 0; i < num_devices; i++) {
6287b840e52Sphitran 			my_dbus_error_free(&error);
6297b840e52Sphitran 			if (libhal_device_get_property_bool(ctx,
6307b840e52Sphitran 			    battery_devices[i], "battery.present", &error)) {
6317b840e52Sphitran 				if ((fd = open_device(ctx,
6327b840e52Sphitran 				    battery_devices[i])) == -1) {
6337b840e52Sphitran 					continue;
6347b840e52Sphitran 				}
6357b840e52Sphitran 				battery_dynamic_update(ctx, battery_devices[i],
6367b840e52Sphitran 				    fd);
6377b840e52Sphitran 				close(fd);
6387b840e52Sphitran 			}
6397b840e52Sphitran 		}
6407b840e52Sphitran 		libhal_free_string_array(battery_devices);
6417b840e52Sphitran 	}
6427b840e52Sphitran 	my_dbus_error_free(&error);
6437b840e52Sphitran 	HAL_DEBUG(("battery_update_all() exit"));
6447b840e52Sphitran 	return (TRUE);
6457b840e52Sphitran }
6467b840e52Sphitran 
6477b840e52Sphitran gboolean
ac_adapter_update(LibHalContext * ctx,const char * udi,int fd)6487b840e52Sphitran ac_adapter_update(LibHalContext *ctx, const char *udi, int fd)
6497b840e52Sphitran {
6507b840e52Sphitran 	LibHalChangeSet *cs;
6517b840e52Sphitran 	DBusError error;
6527b840e52Sphitran 
6537b840e52Sphitran 	HAL_DEBUG(("ac_adapter_update() enter"));
6547b840e52Sphitran 	dbus_error_init(&error);
6557b840e52Sphitran 	if (!libhal_device_query_capability(ctx, udi, "ac_adapter", &error)) {
6567b840e52Sphitran 		my_dbus_error_free(&error);
6577b840e52Sphitran 		libhal_device_add_capability(ctx, udi, "ac_adapter", &error);
6587b840e52Sphitran 		if ((cs = libhal_device_new_changeset(udi)) == NULL) {
6597b840e52Sphitran 			my_dbus_error_free(&error);
6607b840e52Sphitran 			return (FALSE);
6617b840e52Sphitran 		}
6627b840e52Sphitran 		libhal_changeset_set_property_string(cs, "info.product",
6637b840e52Sphitran 		    "AC Adapter");
6647b840e52Sphitran 		libhal_changeset_set_property_string(cs, "info.category",
6657b840e52Sphitran 		    "ac_adapter");
6667b840e52Sphitran 		my_dbus_error_free(&error);
6677b840e52Sphitran 		libhal_device_commit_changeset(ctx, cs, &error);
6687b840e52Sphitran 		libhal_device_free_changeset(cs);
6697b840e52Sphitran 	}
6707b840e52Sphitran 	ac_adapter_present(ctx, udi, fd);
6717b840e52Sphitran 	battery_update_all(ctx);
6727b840e52Sphitran 
6737b840e52Sphitran 	my_dbus_error_free(&error);
6747b840e52Sphitran 	HAL_DEBUG(("ac_adapter_update() exit"));
6757b840e52Sphitran 	return (TRUE);
6767b840e52Sphitran }
6777b840e52Sphitran 
6787b840e52Sphitran static gboolean
ac_adapter_update_all(LibHalContext * ctx)6797b840e52Sphitran ac_adapter_update_all(LibHalContext *ctx)
6807b840e52Sphitran {
6817b840e52Sphitran 	int i;
6827b840e52Sphitran 	int num_devices;
6837b840e52Sphitran 	char **ac_adapter_devices;
6847b840e52Sphitran 	int fd;
6857b840e52Sphitran 	DBusError error;
6867b840e52Sphitran 
6877b840e52Sphitran 	HAL_DEBUG(("ac_adapter_update_all() enter"));
6887b840e52Sphitran 	dbus_error_init(&error);
6897b840e52Sphitran 	if ((ac_adapter_devices = libhal_manager_find_device_string_match(
6907b840e52Sphitran 	    ctx, "info.category", "ac_adapter", &num_devices, &error)) !=
6917b840e52Sphitran 	    NULL) {
6927b840e52Sphitran 		for (i = 0; i < num_devices; i++) {
6937b840e52Sphitran 			if ((fd = open_device(ctx, ac_adapter_devices[i]))
6947b840e52Sphitran 			    == -1) {
6957b840e52Sphitran 				continue;
6967b840e52Sphitran 			}
6977b840e52Sphitran 			ac_adapter_present(ctx, ac_adapter_devices[i], fd);
6987b840e52Sphitran 			close(fd);
6997b840e52Sphitran 		}
7007b840e52Sphitran 		libhal_free_string_array(ac_adapter_devices);
7017b840e52Sphitran 	}
7027b840e52Sphitran 	my_dbus_error_free(&error);
7037b840e52Sphitran 	HAL_DEBUG(("ac_adapter_update_all() exit"));
7047b840e52Sphitran 	return (TRUE);
7057b840e52Sphitran }
7067b840e52Sphitran 
7077b840e52Sphitran gboolean
update_devices(gpointer data)7087b840e52Sphitran update_devices(gpointer data)
7097b840e52Sphitran {
7107b840e52Sphitran 	LibHalContext *ctx = (LibHalContext *)data;
7117b840e52Sphitran 
7127b840e52Sphitran 	HAL_DEBUG(("update_devices() enter"));
7137b840e52Sphitran 	ac_adapter_update_all(ctx);
7147b840e52Sphitran 	battery_update_all(ctx);
7157b840e52Sphitran 	HAL_DEBUG(("update_devices() exit"));
7167b840e52Sphitran 	return (TRUE);
7177b840e52Sphitran }
7187b840e52Sphitran 
7197b840e52Sphitran int
open_device(LibHalContext * ctx,char * udi)7207b840e52Sphitran open_device(LibHalContext *ctx, char *udi)
7217b840e52Sphitran {
7227b840e52Sphitran 	char path[HAL_PATH_MAX] = "/devices";
7237b840e52Sphitran 	char *devfs_path;
7247b840e52Sphitran 	DBusError error;
7257b840e52Sphitran 
7267b840e52Sphitran 	dbus_error_init(&error);
7277b840e52Sphitran 	devfs_path = libhal_device_get_property_string(ctx, udi,
7287b840e52Sphitran 	    "solaris.devfs_path", &error);
7297b840e52Sphitran 	my_dbus_error_free(&error);
7307b840e52Sphitran 	if (devfs_path == NULL) {
7317b840e52Sphitran 		return (-1);
7327b840e52Sphitran 	}
7337b840e52Sphitran 	strlcat(path, devfs_path, HAL_PATH_MAX);
7347b840e52Sphitran 	libhal_free_string(devfs_path);
7357b840e52Sphitran 	return (open(path, O_RDONLY | O_NONBLOCK));
7367b840e52Sphitran }
737