xref: /onnv-gate/usr/src/cmd/hal/utils/acpi.c (revision 6573)
1*6573Sphitran /***************************************************************************
2*6573Sphitran  *
3*6573Sphitran  * acpi.c : Main routines for setting battery, AC adapter, and lid properties
4*6573Sphitran  *
5*6573Sphitran  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
6*6573Sphitran  * Use is subject to license terms.
7*6573Sphitran  *
8*6573Sphitran  * Licensed under the Academic Free License version 2.1
9*6573Sphitran  *
10*6573Sphitran  **************************************************************************/
11*6573Sphitran 
12*6573Sphitran #pragma ident	"%Z%%M%	%I%	%E% SMI"
13*6573Sphitran 
14*6573Sphitran #ifdef HAVE_CONFIG_H
15*6573Sphitran #include <config.h>
16*6573Sphitran #endif
17*6573Sphitran 
18*6573Sphitran #include <unistd.h>
19*6573Sphitran #include <strings.h>
20*6573Sphitran #include <string.h>
21*6573Sphitran #include <kstat.h>
22*6573Sphitran #include <fcntl.h>
23*6573Sphitran #include <errno.h>
24*6573Sphitran #include <sys/acpi_drv.h>
25*6573Sphitran 
26*6573Sphitran #include <libhal.h>
27*6573Sphitran #include "../hald/device_info.h"
28*6573Sphitran #include "../hald/hald_dbus.h"
29*6573Sphitran #include "../hald/logger.h"
30*6573Sphitran #include "../hald/util_pm.h"
31*6573Sphitran #include "acpi.h"
32*6573Sphitran 
33*6573Sphitran 
34*6573Sphitran static void
35*6573Sphitran my_dbus_error_free(DBusError *error)
36*6573Sphitran {
37*6573Sphitran 	if (dbus_error_is_set(error)) {
38*6573Sphitran 		dbus_error_free(error);
39*6573Sphitran 	}
40*6573Sphitran }
41*6573Sphitran 
42*6573Sphitran gboolean
43*6573Sphitran laptop_panel_update(LibHalContext *ctx, const char *udi, int fd)
44*6573Sphitran {
45*6573Sphitran 	LibHalChangeSet *cs;
46*6573Sphitran 	DBusError error;
47*6573Sphitran 	struct acpi_drv_output_info inf;
48*6573Sphitran 
49*6573Sphitran 	HAL_DEBUG(("laptop_panel_update() enter"));
50*6573Sphitran 
51*6573Sphitran 	dbus_error_init(&error);
52*6573Sphitran 	if (!libhal_device_query_capability(ctx, udi, "laptop_panel", &error)) {
53*6573Sphitran 		bzero(&inf, sizeof (inf));
54*6573Sphitran 		if ((ioctl(fd, ACPI_DRV_IOC_INFO, &inf) < 0) ||
55*6573Sphitran 		    (inf.nlev == 0)) {
56*6573Sphitran 			return (FALSE);
57*6573Sphitran 		}
58*6573Sphitran 
59*6573Sphitran 		my_dbus_error_free(&error);
60*6573Sphitran 		libhal_device_add_capability(ctx, udi, "laptop_panel", &error);
61*6573Sphitran 		if ((cs = libhal_device_new_changeset(udi)) == NULL) {
62*6573Sphitran 			my_dbus_error_free(&error);
63*6573Sphitran 			return (FALSE);
64*6573Sphitran 		}
65*6573Sphitran 		libhal_changeset_set_property_string(cs, "info.product",
66*6573Sphitran 		    "Generic Backlight Device");
67*6573Sphitran 		libhal_changeset_set_property_string(cs, "info.category",
68*6573Sphitran 		    "laptop_panel");
69*6573Sphitran 		libhal_changeset_set_property_int(cs, "laptop_panel.num_levels",
70*6573Sphitran 		    inf.nlev);
71*6573Sphitran 		my_dbus_error_free(&error);
72*6573Sphitran 		libhal_device_commit_changeset(ctx, cs, &error);
73*6573Sphitran 		libhal_device_free_changeset(cs);
74*6573Sphitran 	}
75*6573Sphitran 	my_dbus_error_free(&error);
76*6573Sphitran 	HAL_DEBUG(("ac_adapter_present() exit"));
77*6573Sphitran 	return (TRUE);
78*6573Sphitran }
79*6573Sphitran 
80*6573Sphitran gboolean
81*6573Sphitran lid_update(LibHalContext *ctx, const char *udi, int fd)
82*6573Sphitran {
83*6573Sphitran 	LibHalChangeSet *cs;
84*6573Sphitran 	DBusError error;
85*6573Sphitran 
86*6573Sphitran 	HAL_DEBUG(("lid_update() enter"));
87*6573Sphitran 
88*6573Sphitran 	dbus_error_init(&error);
89*6573Sphitran 	if (!libhal_device_query_capability(ctx, udi, "button", &error)) {
90*6573Sphitran 		my_dbus_error_free(&error);
91*6573Sphitran 		libhal_device_add_capability(ctx, udi, "button", &error);
92*6573Sphitran 		if ((cs = libhal_device_new_changeset(udi)) == NULL) {
93*6573Sphitran 			my_dbus_error_free(&error);
94*6573Sphitran 			return (FALSE);
95*6573Sphitran 		}
96*6573Sphitran 		libhal_changeset_set_property_bool(cs, "button.has_state",
97*6573Sphitran 		    TRUE);
98*6573Sphitran 		libhal_changeset_set_property_bool(cs, "button.state.value",
99*6573Sphitran 		    FALSE);
100*6573Sphitran 		libhal_changeset_set_property_string(cs, "button.type",
101*6573Sphitran 		    "lid");
102*6573Sphitran 		libhal_changeset_set_property_string(cs, "info.product",
103*6573Sphitran 		    "Lid Switch");
104*6573Sphitran 		libhal_changeset_set_property_string(cs, "info.category",
105*6573Sphitran 		    "button");
106*6573Sphitran 		my_dbus_error_free(&error);
107*6573Sphitran 		libhal_device_commit_changeset(ctx, cs, &error);
108*6573Sphitran 		libhal_device_free_changeset(cs);
109*6573Sphitran 	}
110*6573Sphitran 	my_dbus_error_free(&error);
111*6573Sphitran 	HAL_DEBUG(("update_lid() exit"));
112*6573Sphitran 	return (TRUE);
113*6573Sphitran }
114*6573Sphitran 
115*6573Sphitran static void
116*6573Sphitran ac_adapter_present(LibHalContext *ctx, const char *udi, int fd)
117*6573Sphitran {
118*6573Sphitran 	int pow;
119*6573Sphitran 	LibHalChangeSet *cs;
120*6573Sphitran 	DBusError error;
121*6573Sphitran 
122*6573Sphitran 	HAL_DEBUG(("ac_adapter_present() enter"));
123*6573Sphitran 	if (ioctl(fd, ACPI_DRV_IOC_POWER_STATUS, &pow) < 0) {
124*6573Sphitran 		return;
125*6573Sphitran 	}
126*6573Sphitran 	if ((cs = libhal_device_new_changeset(udi)) == NULL) {
127*6573Sphitran 		return;
128*6573Sphitran 	}
129*6573Sphitran 	if (pow > 0) {
130*6573Sphitran 		libhal_changeset_set_property_bool(cs, "ac_adapter.present",
131*6573Sphitran 		    TRUE);
132*6573Sphitran 	} else {
133*6573Sphitran 		libhal_changeset_set_property_bool(cs, "ac_adapter.present",
134*6573Sphitran 		    FALSE);
135*6573Sphitran 	}
136*6573Sphitran 
137*6573Sphitran 	dbus_error_init(&error);
138*6573Sphitran 	libhal_device_commit_changeset(ctx, cs, &error);
139*6573Sphitran 	libhal_device_free_changeset(cs);
140*6573Sphitran 	my_dbus_error_free(&error);
141*6573Sphitran 	HAL_DEBUG(("ac_adapter_present() exit"));
142*6573Sphitran }
143*6573Sphitran 
144*6573Sphitran static void
145*6573Sphitran battery_remove(LibHalContext *ctx, const char *udi)
146*6573Sphitran {
147*6573Sphitran 	DBusError error;
148*6573Sphitran 
149*6573Sphitran 	HAL_DEBUG(("battery_remove() enter"));
150*6573Sphitran 	dbus_error_init(&error);
151*6573Sphitran 	libhal_device_remove_property(ctx, udi, "battery.remaining_time",
152*6573Sphitran 	    &error);
153*6573Sphitran 	my_dbus_error_free(&error);
154*6573Sphitran 	libhal_device_remove_property(ctx, udi,
155*6573Sphitran 	    "battery.charge_level.percentage", &error);
156*6573Sphitran 	my_dbus_error_free(&error);
157*6573Sphitran 	libhal_device_remove_property(ctx, udi, "battery.charge_level.rate",
158*6573Sphitran 	    &error);
159*6573Sphitran 	my_dbus_error_free(&error);
160*6573Sphitran 	libhal_device_remove_property(ctx, udi,
161*6573Sphitran 	    "battery.charge_level.last_full", &error);
162*6573Sphitran 	my_dbus_error_free(&error);
163*6573Sphitran 	libhal_device_remove_property(ctx, udi,
164*6573Sphitran 	    "battery.charge_level.current", &error);
165*6573Sphitran 	my_dbus_error_free(&error);
166*6573Sphitran 	libhal_device_remove_property(ctx, udi, "battery.voltage.present",
167*6573Sphitran 	    &error);
168*6573Sphitran 	my_dbus_error_free(&error);
169*6573Sphitran 	libhal_device_remove_property(ctx, udi, "battery.reporting.rate",
170*6573Sphitran 	    &error);
171*6573Sphitran 	my_dbus_error_free(&error);
172*6573Sphitran 	libhal_device_remove_property(ctx, udi, "battery.reporting.current",
173*6573Sphitran 	    &error);
174*6573Sphitran 	my_dbus_error_free(&error);
175*6573Sphitran 	libhal_device_remove_property(ctx, udi,
176*6573Sphitran 	    "battery.rechargeable.is_discharging", &error);
177*6573Sphitran 	my_dbus_error_free(&error);
178*6573Sphitran 	libhal_device_remove_property(ctx, udi,
179*6573Sphitran 	    "battery.rechargeable.is_charging", &error);
180*6573Sphitran 	my_dbus_error_free(&error);
181*6573Sphitran 	libhal_device_remove_property(ctx, udi, "battery.is_rechargeable",
182*6573Sphitran 	    &error);
183*6573Sphitran 	my_dbus_error_free(&error);
184*6573Sphitran 	libhal_device_remove_property(ctx, udi, "battery.charge_level.unit",
185*6573Sphitran 	    &error);
186*6573Sphitran 	my_dbus_error_free(&error);
187*6573Sphitran 	libhal_device_remove_property(ctx, udi,
188*6573Sphitran 	    "battery.charge_level.granularity_2", &error);
189*6573Sphitran 	my_dbus_error_free(&error);
190*6573Sphitran 	libhal_device_remove_property(ctx, udi,
191*6573Sphitran 	    "battery.charge_level.granularity_1", &error);
192*6573Sphitran 	my_dbus_error_free(&error);
193*6573Sphitran 	libhal_device_remove_property(ctx, udi, "battery.charge_level.low",
194*6573Sphitran 	    &error);
195*6573Sphitran 	my_dbus_error_free(&error);
196*6573Sphitran 	libhal_device_remove_property(ctx, udi, "battery.charge_level.warning",
197*6573Sphitran 	    &error);
198*6573Sphitran 	my_dbus_error_free(&error);
199*6573Sphitran 	libhal_device_remove_property(ctx, udi, "battery.charge_level.design",
200*6573Sphitran 	    &error);
201*6573Sphitran 	my_dbus_error_free(&error);
202*6573Sphitran 	libhal_device_remove_property(ctx, udi, "battery.voltage.design",
203*6573Sphitran 	    &error);
204*6573Sphitran 	my_dbus_error_free(&error);
205*6573Sphitran 	libhal_device_remove_property(ctx, udi,
206*6573Sphitran 	    "battery.reporting.granularity_2", &error);
207*6573Sphitran 	my_dbus_error_free(&error);
208*6573Sphitran 	libhal_device_remove_property(ctx, udi,
209*6573Sphitran 	    "battery.reporting.granularity_1", &error);
210*6573Sphitran 	my_dbus_error_free(&error);
211*6573Sphitran 	libhal_device_remove_property(ctx, udi, "battery.reporting.low",
212*6573Sphitran 	    &error);
213*6573Sphitran 	my_dbus_error_free(&error);
214*6573Sphitran 	libhal_device_remove_property(ctx, udi, "battery.reporting.warning",
215*6573Sphitran 	    &error);
216*6573Sphitran 	my_dbus_error_free(&error);
217*6573Sphitran 	libhal_device_remove_property(ctx, udi, "battery.reporting.design",
218*6573Sphitran 	    &error);
219*6573Sphitran 	my_dbus_error_free(&error);
220*6573Sphitran 	libhal_device_remove_property(ctx, udi, "battery.reporting.last_full",
221*6573Sphitran 	    &error);
222*6573Sphitran 	my_dbus_error_free(&error);
223*6573Sphitran 	libhal_device_remove_property(ctx, udi, "battery.reporting.unit",
224*6573Sphitran 	    &error);
225*6573Sphitran 	my_dbus_error_free(&error);
226*6573Sphitran 	libhal_device_remove_property(ctx, udi, "battery.technology", &error);
227*6573Sphitran 	my_dbus_error_free(&error);
228*6573Sphitran 	libhal_device_remove_property(ctx, udi, "battery.reporting.technology",
229*6573Sphitran 	    &error);
230*6573Sphitran 	my_dbus_error_free(&error);
231*6573Sphitran 	libhal_device_remove_property(ctx, udi, "battery.serial", &error);
232*6573Sphitran 	my_dbus_error_free(&error);
233*6573Sphitran 	libhal_device_remove_property(ctx, udi, "battery.model", &error);
234*6573Sphitran 	my_dbus_error_free(&error);
235*6573Sphitran 	libhal_device_remove_property(ctx, udi, "battery.vendor", &error);
236*6573Sphitran 	my_dbus_error_free(&error);
237*6573Sphitran 	HAL_DEBUG(("battery_remove() exit"));
238*6573Sphitran }
239*6573Sphitran 
240*6573Sphitran static void
241*6573Sphitran battery_last_full(LibHalChangeSet *cs, int fd)
242*6573Sphitran {
243*6573Sphitran 	acpi_bif_t bif;
244*6573Sphitran 
245*6573Sphitran 	bzero(&bif, sizeof (bif));
246*6573Sphitran 	if (ioctl(fd, ACPI_DRV_IOC_INFO, &bif) < 0) {
247*6573Sphitran 		return;
248*6573Sphitran 	}
249*6573Sphitran 	libhal_changeset_set_property_int(cs, "battery.reporting_last_full",
250*6573Sphitran 	    bif.bif_last_cap);
251*6573Sphitran }
252*6573Sphitran 
253*6573Sphitran static void
254*6573Sphitran battery_dynamic_update(LibHalContext *ctx, const char *udi, int fd)
255*6573Sphitran {
256*6573Sphitran 	int reporting_rate;
257*6573Sphitran 	int reporting_current;
258*6573Sphitran 	int reporting_lastfull;
259*6573Sphitran 	int design_voltage;
260*6573Sphitran 	int present_voltage;
261*6573Sphitran 	char *reporting_unit;
262*6573Sphitran 	int remaining_time;
263*6573Sphitran 	int remaining_percentage;
264*6573Sphitran 	gboolean charging;
265*6573Sphitran 	gboolean discharging;
266*6573Sphitran 	acpi_bst_t bst;
267*6573Sphitran 	LibHalChangeSet *cs;
268*6573Sphitran 	DBusError error;
269*6573Sphitran 	static int counter = 0;
270*6573Sphitran 
271*6573Sphitran 	HAL_DEBUG(("battery_dynamic_update() enter"));
272*6573Sphitran 	bzero(&bst, sizeof (bst));
273*6573Sphitran 	if (ioctl(fd, ACPI_DRV_IOC_STATUS, &bst) < 0) {
274*6573Sphitran 		return;
275*6573Sphitran 	}
276*6573Sphitran 
277*6573Sphitran 	charging = bst.bst_state & ACPI_DRV_BST_CHARGING ? TRUE : FALSE;
278*6573Sphitran 	discharging = bst.bst_state & ACPI_DRV_BST_DISCHARGING ? TRUE : FALSE;
279*6573Sphitran 	/* No need to continue if battery is essentially idle. */
280*6573Sphitran 	if (counter && !charging && !discharging) {
281*6573Sphitran 		return;
282*6573Sphitran 	}
283*6573Sphitran 	dbus_error_init(&error);
284*6573Sphitran 	libhal_device_set_property_bool(ctx, udi, "battery.is_rechargeable",
285*6573Sphitran 	    TRUE, &error);
286*6573Sphitran 	my_dbus_error_free(&error);
287*6573Sphitran 	if (libhal_device_property_exists(ctx, udi,
288*6573Sphitran 	    "battery.charge_level.percentage", &error)) {
289*6573Sphitran 		remaining_percentage = libhal_device_get_property_int(ctx, udi,
290*6573Sphitran 		    "battery.charge_level.percentage", &error);
291*6573Sphitran 		if ((remaining_percentage == 100) && charging) {
292*6573Sphitran 			charging = FALSE;
293*6573Sphitran 		}
294*6573Sphitran 	}
295*6573Sphitran 	libhal_device_set_property_bool(ctx, udi,
296*6573Sphitran 	    "battery.rechargeable.is_charging", charging, &error);
297*6573Sphitran 	my_dbus_error_free(&error);
298*6573Sphitran 	libhal_device_set_property_bool(ctx, udi,
299*6573Sphitran 	    "battery.rechargeable.is_discharging", discharging, &error);
300*6573Sphitran 	my_dbus_error_free(&error);
301*6573Sphitran 	reporting_current = bst.bst_rem_cap;
302*6573Sphitran 	libhal_device_set_property_int(ctx, udi, "battery.reporting.current",
303*6573Sphitran 	    bst.bst_rem_cap, &error);
304*6573Sphitran 	my_dbus_error_free(&error);
305*6573Sphitran 	reporting_rate = bst.bst_rate;
306*6573Sphitran 	libhal_device_set_property_int(ctx, udi, "battery.reporting.rate",
307*6573Sphitran 	    bst.bst_rate, &error);
308*6573Sphitran 	my_dbus_error_free(&error);
309*6573Sphitran 	present_voltage = bst.bst_voltage;
310*6573Sphitran 	libhal_device_set_property_int(ctx, udi, "battery.voltage.present",
311*6573Sphitran 	    bst.bst_voltage, &error);
312*6573Sphitran 	/* get all the data we know */
313*6573Sphitran 	my_dbus_error_free(&error);
314*6573Sphitran 	reporting_unit = libhal_device_get_property_string(ctx, udi,
315*6573Sphitran 	    "battery.reporting.unit", &error);
316*6573Sphitran 	my_dbus_error_free(&error);
317*6573Sphitran 	reporting_lastfull = libhal_device_get_property_int(ctx, udi,
318*6573Sphitran 	    "battery.reporting.last_full", &error);
319*6573Sphitran 
320*6573Sphitran 	/*
321*6573Sphitran 	 * Convert mAh to mWh since util_compute_time_remaining() works
322*6573Sphitran 	 * for mWh.
323*6573Sphitran 	 */
324*6573Sphitran 	if (reporting_unit && strcmp(reporting_unit, "mAh") == 0) {
325*6573Sphitran 		my_dbus_error_free(&error);
326*6573Sphitran 		design_voltage = libhal_device_get_property_int(ctx, udi,
327*6573Sphitran 		    "battery.voltage.design", &error);
328*6573Sphitran 		/*
329*6573Sphitran 		 * If the present_voltage is inaccurate, set it to the
330*6573Sphitran 		 * design_voltage.
331*6573Sphitran 		 */
332*6573Sphitran 		if (((present_voltage * 10) < design_voltage) ||
333*6573Sphitran 		    (present_voltage <= 0) ||
334*6573Sphitran 		    (present_voltage > design_voltage)) {
335*6573Sphitran 			present_voltage = design_voltage;
336*6573Sphitran 		}
337*6573Sphitran 		reporting_rate = (reporting_rate * present_voltage) / 1000;
338*6573Sphitran 		reporting_lastfull = (reporting_lastfull * present_voltage) /
339*6573Sphitran 		    1000;
340*6573Sphitran 		reporting_current = (reporting_current * present_voltage) /
341*6573Sphitran 		    1000;
342*6573Sphitran 	}
343*6573Sphitran 
344*6573Sphitran 	/* Make sure the current charge does not exceed the full charge */
345*6573Sphitran 	if (reporting_current > reporting_lastfull) {
346*6573Sphitran 		reporting_current = reporting_lastfull;
347*6573Sphitran 	}
348*6573Sphitran 	if (!charging && !discharging) {
349*6573Sphitran 		counter++;
350*6573Sphitran 		reporting_rate = 0;
351*6573Sphitran 	}
352*6573Sphitran 
353*6573Sphitran 	if ((cs = libhal_device_new_changeset(udi)) == NULL) {
354*6573Sphitran 		HAL_DEBUG(("Cannot allocate changeset"));
355*6573Sphitran 		libhal_free_string(reporting_unit);
356*6573Sphitran 		my_dbus_error_free(&error);
357*6573Sphitran 		return;
358*6573Sphitran 	}
359*6573Sphitran 
360*6573Sphitran 	libhal_changeset_set_property_int(cs, "battery.charge_level.rate",
361*6573Sphitran 	    reporting_rate);
362*6573Sphitran 	libhal_changeset_set_property_int(cs,
363*6573Sphitran 	    "battery.charge_level.last_full", reporting_lastfull);
364*6573Sphitran 	libhal_changeset_set_property_int(cs,
365*6573Sphitran 	    "battery.charge_level.current", reporting_current);
366*6573Sphitran 
367*6573Sphitran 	remaining_percentage = util_compute_percentage_charge(udi,
368*6573Sphitran 	    reporting_current, reporting_lastfull);
369*6573Sphitran 	remaining_time = util_compute_time_remaining(udi, reporting_rate,
370*6573Sphitran 	    reporting_current, reporting_lastfull, discharging, charging, 0);
371*6573Sphitran 	/*
372*6573Sphitran 	 * Some batteries give bad remaining_time estimates relative to
373*6573Sphitran 	 * the charge level.
374*6573Sphitran 	 */
375*6573Sphitran 	if (charging && ((remaining_time < 30) || ((remaining_time < 300) &&
376*6573Sphitran 	    (remaining_percentage < 95)) || (remaining_percentage > 97))) {
377*6573Sphitran 		remaining_time = util_compute_time_remaining(udi,
378*6573Sphitran 		    reporting_rate, reporting_current, reporting_lastfull,
379*6573Sphitran 		    discharging, charging, 1);
380*6573Sphitran 	}
381*6573Sphitran 
382*6573Sphitran 	if (remaining_percentage > 0) {
383*6573Sphitran 		libhal_changeset_set_property_int(cs,
384*6573Sphitran 		    "battery.charge_level.percentage", remaining_percentage);
385*6573Sphitran 	} else {
386*6573Sphitran 		my_dbus_error_free(&error);
387*6573Sphitran 		libhal_device_remove_property(ctx, udi,
388*6573Sphitran 		    "battery.charge_level.percentage", &error);
389*6573Sphitran 	}
390*6573Sphitran 	if ((remaining_percentage == 100) && charging) {
391*6573Sphitran 		battery_last_full(cs, fd);
392*6573Sphitran 	}
393*6573Sphitran 	/*
394*6573Sphitran 	 * remaining_percentage is more accurate so we handle cases
395*6573Sphitran 	 * where the remaining_time cannot be correct.
396*6573Sphitran 	 */
397*6573Sphitran 	if ((!charging && !discharging) || ((remaining_percentage == 100) &&
398*6573Sphitran 	    !discharging)) {
399*6573Sphitran 		remaining_time = 0;
400*6573Sphitran 	}
401*6573Sphitran 	if (remaining_time < 0) {
402*6573Sphitran 		my_dbus_error_free(&error);
403*6573Sphitran 		libhal_device_remove_property(ctx, udi,
404*6573Sphitran 		    "battery.remaining_time", &error);
405*6573Sphitran 	} else if (remaining_time >= 0) {
406*6573Sphitran 		libhal_changeset_set_property_int(cs,
407*6573Sphitran 		    "battery.remaining_time", remaining_time);
408*6573Sphitran 	}
409*6573Sphitran 
410*6573Sphitran 	my_dbus_error_free(&error);
411*6573Sphitran 	libhal_device_commit_changeset(ctx, cs, &error);
412*6573Sphitran 	libhal_device_free_changeset(cs);
413*6573Sphitran 	libhal_free_string(reporting_unit);
414*6573Sphitran 	my_dbus_error_free(&error);
415*6573Sphitran 	HAL_DEBUG(("battery_dynamic_update() exit"));
416*6573Sphitran }
417*6573Sphitran 
418*6573Sphitran static gboolean
419*6573Sphitran battery_static_update(LibHalContext *ctx, const char *udi, int fd)
420*6573Sphitran {
421*6573Sphitran 	const char *technology;
422*6573Sphitran 	int reporting_design;
423*6573Sphitran 	int reporting_warning;
424*6573Sphitran 	int reporting_low;
425*6573Sphitran 	int reporting_gran1;
426*6573Sphitran 	int reporting_gran2;
427*6573Sphitran 	int voltage_design;
428*6573Sphitran 	char reporting_unit[10];
429*6573Sphitran 	acpi_bif_t bif;
430*6573Sphitran 	LibHalChangeSet *cs;
431*6573Sphitran 	DBusError error;
432*6573Sphitran 
433*6573Sphitran 	HAL_DEBUG(("battery_static_update() enter"));
434*6573Sphitran 	bzero(&bif, sizeof (bif));
435*6573Sphitran 	if (ioctl(fd, ACPI_DRV_IOC_INFO, &bif) < 0) {
436*6573Sphitran 		return (FALSE);
437*6573Sphitran 	}
438*6573Sphitran 	if ((cs = libhal_device_new_changeset(udi)) == NULL) {
439*6573Sphitran 		HAL_DEBUG(("Cannot allocate changeset"));
440*6573Sphitran 		return (FALSE);
441*6573Sphitran 	}
442*6573Sphitran 
443*6573Sphitran 	libhal_changeset_set_property_string(cs, "battery.vendor",
444*6573Sphitran 	    bif.bif_oem_info);
445*6573Sphitran 	technology = bif.bif_type;
446*6573Sphitran 	if (technology != NULL) {
447*6573Sphitran 		libhal_changeset_set_property_string(cs,
448*6573Sphitran 		    "battery.reporting.technology", technology);
449*6573Sphitran 		libhal_changeset_set_property_string(cs, "battery.technology",
450*6573Sphitran 		    util_get_battery_technology(technology));
451*6573Sphitran 	}
452*6573Sphitran 	libhal_changeset_set_property_string(cs, "battery.serial",
453*6573Sphitran 	    bif.bif_serial);
454*6573Sphitran 	libhal_changeset_set_property_string(cs, "battery.model",
455*6573Sphitran 	    bif.bif_model);
456*6573Sphitran 
457*6573Sphitran 	if (bif.bif_unit) {
458*6573Sphitran 		libhal_changeset_set_property_string(cs,
459*6573Sphitran 		    "battery.reporting.unit", "mAh");
460*6573Sphitran 		strlcpy(reporting_unit, "mAh", sizeof (reporting_unit));
461*6573Sphitran 	} else {
462*6573Sphitran 		libhal_changeset_set_property_string(cs,
463*6573Sphitran 		    "battery.reporting.unit", "mWh");
464*6573Sphitran 		strlcpy(reporting_unit, "mWh", sizeof (reporting_unit));
465*6573Sphitran 	}
466*6573Sphitran 	libhal_changeset_set_property_int(cs, "battery.reporting.last_full",
467*6573Sphitran 	    bif.bif_last_cap);
468*6573Sphitran 	libhal_changeset_set_property_int(cs, "battery.reporting.design",
469*6573Sphitran 	    bif.bif_design_cap);
470*6573Sphitran 	reporting_design = bif.bif_design_cap;
471*6573Sphitran 	libhal_changeset_set_property_int(cs, "battery.reporting.warning",
472*6573Sphitran 	    bif.bif_warn_cap);
473*6573Sphitran 	reporting_warning = bif.bif_warn_cap;
474*6573Sphitran 	libhal_changeset_set_property_int(cs, "battery.reporting.low",
475*6573Sphitran 	    bif.bif_low_cap);
476*6573Sphitran 	reporting_low = bif.bif_low_cap;
477*6573Sphitran 	libhal_changeset_set_property_int(cs,
478*6573Sphitran 	    "battery.reporting.granularity_1", bif.bif_gran1_cap);
479*6573Sphitran 	reporting_gran1 = bif.bif_gran1_cap;
480*6573Sphitran 	libhal_changeset_set_property_int(cs,
481*6573Sphitran 	    "battery.reporting.granularity_2", bif.bif_gran2_cap);
482*6573Sphitran 	reporting_gran2 = bif.bif_gran2_cap;
483*6573Sphitran 	libhal_changeset_set_property_int(cs, "battery.voltage.design",
484*6573Sphitran 	    bif.bif_voltage);
485*6573Sphitran 	voltage_design = bif.bif_voltage;
486*6573Sphitran 
487*6573Sphitran 	if (reporting_unit && strcmp(reporting_unit, "mAh") == 0) {
488*6573Sphitran 		/* convert to mWh */
489*6573Sphitran 		libhal_changeset_set_property_string(cs,
490*6573Sphitran 		    "battery.charge_level.unit", "mWh");
491*6573Sphitran 		libhal_changeset_set_property_int(cs,
492*6573Sphitran 		    "battery.charge_level.design",
493*6573Sphitran 		    (reporting_design * voltage_design) / 1000);
494*6573Sphitran 		libhal_changeset_set_property_int(cs,
495*6573Sphitran 		    "battery.charge_level.warning",
496*6573Sphitran 		    (reporting_warning * voltage_design) / 1000);
497*6573Sphitran 		libhal_changeset_set_property_int(cs,
498*6573Sphitran 		    "battery.charge_level.low",
499*6573Sphitran 		    (reporting_low * voltage_design) / 1000);
500*6573Sphitran 		libhal_changeset_set_property_int(cs,
501*6573Sphitran 		    "battery.charge_level.granularity_1",
502*6573Sphitran 		    (reporting_gran1 * voltage_design) / 1000);
503*6573Sphitran 		libhal_changeset_set_property_int(cs,
504*6573Sphitran 		    "battery.charge_level.granularity_2",
505*6573Sphitran 		    (reporting_gran2 * voltage_design) / 1000);
506*6573Sphitran 	} else {
507*6573Sphitran 		if (reporting_unit && strcmp(reporting_unit, "mWh") == 0) {
508*6573Sphitran 			libhal_changeset_set_property_string(cs,
509*6573Sphitran 			    "battery.charge_level.unit", "mWh");
510*6573Sphitran 		}
511*6573Sphitran 		libhal_changeset_set_property_int(cs,
512*6573Sphitran 		    "battery.charge_level.design", reporting_design);
513*6573Sphitran 		libhal_changeset_set_property_int(cs,
514*6573Sphitran 		    "battery.charge_level.warning", reporting_warning);
515*6573Sphitran 		libhal_changeset_set_property_int(cs,
516*6573Sphitran 		    "battery.charge_level.low", reporting_low);
517*6573Sphitran 		libhal_changeset_set_property_int(cs,
518*6573Sphitran 		    "battery.charge_level.granularity_1", reporting_gran1);
519*6573Sphitran 		libhal_changeset_set_property_int(cs,
520*6573Sphitran 		    "battery.charge_level.granularity_2", reporting_gran2);
521*6573Sphitran 	}
522*6573Sphitran 
523*6573Sphitran 
524*6573Sphitran 	dbus_error_init(&error);
525*6573Sphitran 	libhal_device_commit_changeset(ctx, cs, &error);
526*6573Sphitran 	libhal_device_free_changeset(cs);
527*6573Sphitran 	my_dbus_error_free(&error);
528*6573Sphitran 	HAL_DEBUG(("battery_static_update() exit"));
529*6573Sphitran 	return (TRUE);
530*6573Sphitran }
531*6573Sphitran 
532*6573Sphitran gboolean
533*6573Sphitran battery_update(LibHalContext *ctx, const char *udi, int fd)
534*6573Sphitran {
535*6573Sphitran 	acpi_bst_t bst;
536*6573Sphitran 	DBusError error;
537*6573Sphitran 
538*6573Sphitran 	HAL_DEBUG(("battery_update() enter"));
539*6573Sphitran 	dbus_error_init(&error);
540*6573Sphitran 	libhal_device_set_property_string(ctx, udi, "info.product",
541*6573Sphitran 	    "Battery Bay", &error);
542*6573Sphitran 	my_dbus_error_free(&error);
543*6573Sphitran 	libhal_device_set_property_string(ctx, udi, "info.category", "battery",
544*6573Sphitran 	    &error);
545*6573Sphitran 
546*6573Sphitran 	bzero(&bst, sizeof (bst));
547*6573Sphitran 	if (ioctl(fd, ACPI_DRV_IOC_STATUS, &bst) < 0) {
548*6573Sphitran 		if (errno == ENXIO) {
549*6573Sphitran 			my_dbus_error_free(&error);
550*6573Sphitran 			libhal_device_set_property_bool(ctx, udi,
551*6573Sphitran 			    "battery.present", FALSE, &error);
552*6573Sphitran 		} else {
553*6573Sphitran 			my_dbus_error_free(&error);
554*6573Sphitran 			return (FALSE);
555*6573Sphitran 		}
556*6573Sphitran 	} else {
557*6573Sphitran 		my_dbus_error_free(&error);
558*6573Sphitran 		libhal_device_set_property_bool(ctx, udi, "battery.present",
559*6573Sphitran 		    TRUE, &error);
560*6573Sphitran 	}
561*6573Sphitran 
562*6573Sphitran 	my_dbus_error_free(&error);
563*6573Sphitran 	if (!libhal_device_get_property_bool(ctx, udi, "battery.present",
564*6573Sphitran 	    &error)) {
565*6573Sphitran 		HAL_DEBUG(("battery_update(): battery is NOT present"));
566*6573Sphitran 		battery_remove(ctx, udi);
567*6573Sphitran 	} else {
568*6573Sphitran 		HAL_DEBUG(("battery_update(): battery is present"));
569*6573Sphitran 		my_dbus_error_free(&error);
570*6573Sphitran 		libhal_device_set_property_string(ctx, udi, "battery.type",
571*6573Sphitran 		    "primary", &error);
572*6573Sphitran 		my_dbus_error_free(&error);
573*6573Sphitran 		libhal_device_add_capability(ctx, udi, "battery", &error);
574*6573Sphitran 		my_dbus_error_free(&error);
575*6573Sphitran 		if (libhal_device_get_property_type(ctx, udi, "battery.vendor",
576*6573Sphitran 		    &error) == LIBHAL_PROPERTY_TYPE_INVALID) {
577*6573Sphitran 			battery_static_update(ctx, udi, fd);
578*6573Sphitran 		}
579*6573Sphitran 		battery_dynamic_update(ctx, udi, fd);
580*6573Sphitran 	}
581*6573Sphitran 	my_dbus_error_free(&error);
582*6573Sphitran 	HAL_DEBUG(("battery_update() exit"));
583*6573Sphitran 	return (TRUE);
584*6573Sphitran }
585*6573Sphitran 
586*6573Sphitran static gboolean
587*6573Sphitran battery_update_all(LibHalContext *ctx)
588*6573Sphitran {
589*6573Sphitran 	int i;
590*6573Sphitran 	int num_devices;
591*6573Sphitran 	char **battery_devices;
592*6573Sphitran 	int fd;
593*6573Sphitran 	DBusError error;
594*6573Sphitran 
595*6573Sphitran 	HAL_DEBUG(("battery_update_all() enter"));
596*6573Sphitran 
597*6573Sphitran 	dbus_error_init(&error);
598*6573Sphitran 	if ((battery_devices = libhal_manager_find_device_string_match
599*6573Sphitran 	    (ctx, "info.category", "battery", &num_devices, &error)) !=
600*6573Sphitran 	    NULL) {
601*6573Sphitran 		for (i = 0; i < num_devices; i++) {
602*6573Sphitran 			my_dbus_error_free(&error);
603*6573Sphitran 			if (libhal_device_get_property_bool(ctx,
604*6573Sphitran 			    battery_devices[i], "battery.present", &error)) {
605*6573Sphitran 				if ((fd = open_device(ctx,
606*6573Sphitran 				    battery_devices[i])) == -1) {
607*6573Sphitran 					continue;
608*6573Sphitran 				}
609*6573Sphitran 				battery_dynamic_update(ctx, battery_devices[i],
610*6573Sphitran 				    fd);
611*6573Sphitran 				close(fd);
612*6573Sphitran 			}
613*6573Sphitran 		}
614*6573Sphitran 		libhal_free_string_array(battery_devices);
615*6573Sphitran 	}
616*6573Sphitran 	my_dbus_error_free(&error);
617*6573Sphitran 	HAL_DEBUG(("battery_update_all() exit"));
618*6573Sphitran 	return (TRUE);
619*6573Sphitran }
620*6573Sphitran 
621*6573Sphitran gboolean
622*6573Sphitran ac_adapter_update(LibHalContext *ctx, const char *udi, int fd)
623*6573Sphitran {
624*6573Sphitran 	LibHalChangeSet *cs;
625*6573Sphitran 	DBusError error;
626*6573Sphitran 
627*6573Sphitran 	HAL_DEBUG(("ac_adapter_update() enter"));
628*6573Sphitran 	dbus_error_init(&error);
629*6573Sphitran 	if (!libhal_device_query_capability(ctx, udi, "ac_adapter", &error)) {
630*6573Sphitran 		my_dbus_error_free(&error);
631*6573Sphitran 		libhal_device_add_capability(ctx, udi, "ac_adapter", &error);
632*6573Sphitran 		if ((cs = libhal_device_new_changeset(udi)) == NULL) {
633*6573Sphitran 			my_dbus_error_free(&error);
634*6573Sphitran 			return (FALSE);
635*6573Sphitran 		}
636*6573Sphitran 		libhal_changeset_set_property_string(cs, "info.product",
637*6573Sphitran 		    "AC Adapter");
638*6573Sphitran 		libhal_changeset_set_property_string(cs, "info.category",
639*6573Sphitran 		    "ac_adapter");
640*6573Sphitran 		my_dbus_error_free(&error);
641*6573Sphitran 		libhal_device_commit_changeset(ctx, cs, &error);
642*6573Sphitran 		libhal_device_free_changeset(cs);
643*6573Sphitran 	}
644*6573Sphitran 	ac_adapter_present(ctx, udi, fd);
645*6573Sphitran 	battery_update_all(ctx);
646*6573Sphitran 
647*6573Sphitran 	my_dbus_error_free(&error);
648*6573Sphitran 	HAL_DEBUG(("ac_adapter_update() exit"));
649*6573Sphitran 	return (TRUE);
650*6573Sphitran }
651*6573Sphitran 
652*6573Sphitran static gboolean
653*6573Sphitran ac_adapter_update_all(LibHalContext *ctx)
654*6573Sphitran {
655*6573Sphitran 	int i;
656*6573Sphitran 	int num_devices;
657*6573Sphitran 	char **ac_adapter_devices;
658*6573Sphitran 	int fd;
659*6573Sphitran 	DBusError error;
660*6573Sphitran 
661*6573Sphitran 	HAL_DEBUG(("ac_adapter_update_all() enter"));
662*6573Sphitran 	dbus_error_init(&error);
663*6573Sphitran 	if ((ac_adapter_devices = libhal_manager_find_device_string_match(
664*6573Sphitran 	    ctx, "info.category", "ac_adapter", &num_devices, &error)) !=
665*6573Sphitran 	    NULL) {
666*6573Sphitran 		for (i = 0; i < num_devices; i++) {
667*6573Sphitran 			if ((fd = open_device(ctx, ac_adapter_devices[i]))
668*6573Sphitran 			    == -1) {
669*6573Sphitran 				continue;
670*6573Sphitran 			}
671*6573Sphitran 			ac_adapter_present(ctx, ac_adapter_devices[i], fd);
672*6573Sphitran 			close(fd);
673*6573Sphitran 		}
674*6573Sphitran 		libhal_free_string_array(ac_adapter_devices);
675*6573Sphitran 	}
676*6573Sphitran 	my_dbus_error_free(&error);
677*6573Sphitran 	HAL_DEBUG(("ac_adapter_update_all() exit"));
678*6573Sphitran 	return (TRUE);
679*6573Sphitran }
680*6573Sphitran 
681*6573Sphitran gboolean
682*6573Sphitran update_devices(gpointer data)
683*6573Sphitran {
684*6573Sphitran 	LibHalContext *ctx = (LibHalContext *)data;
685*6573Sphitran 
686*6573Sphitran 	HAL_DEBUG(("update_devices() enter"));
687*6573Sphitran 	ac_adapter_update_all(ctx);
688*6573Sphitran 	battery_update_all(ctx);
689*6573Sphitran 	HAL_DEBUG(("update_devices() exit"));
690*6573Sphitran 	return (TRUE);
691*6573Sphitran }
692*6573Sphitran 
693*6573Sphitran int
694*6573Sphitran open_device(LibHalContext *ctx, char *udi)
695*6573Sphitran {
696*6573Sphitran 	char path[HAL_PATH_MAX] = "/devices";
697*6573Sphitran 	char *devfs_path;
698*6573Sphitran 	DBusError error;
699*6573Sphitran 
700*6573Sphitran 	dbus_error_init(&error);
701*6573Sphitran 	devfs_path = libhal_device_get_property_string(ctx, udi,
702*6573Sphitran 	    "solaris.devfs_path", &error);
703*6573Sphitran 	my_dbus_error_free(&error);
704*6573Sphitran 	if (devfs_path == NULL) {
705*6573Sphitran 		return (-1);
706*6573Sphitran 	}
707*6573Sphitran 	strlcat(path, devfs_path, HAL_PATH_MAX);
708*6573Sphitran 	libhal_free_string(devfs_path);
709*6573Sphitran 	return (open(path, O_RDONLY | O_NONBLOCK));
710*6573Sphitran }
711