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