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