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 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 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 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 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 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 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 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 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 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 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 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 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 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 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