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