/* Thanks to lmctl code. I'd LOVE, REALLY LOVE to see some docs though... */ static void check_battery (const char *hal_device_udi, PropertyCacheItem *pci) { struct usb_device *curr_device; usb_dev_handle *handle; char buf[80]; DBusError err; unsigned int addr; int is_dual = 0; int percentage = 0; if (pci == NULL) return; HAL_DEBUG (("CSR device: [%s]", hal_device_udi)); is_dual = pci->csr_is_dual; /* Which of subdevices to address */ HAL_DEBUG (("Is dual: %d", is_dual)); addr = is_dual? 1<<8 : 0; curr_device = find_device (pci); if (curr_device == NULL) { HAL_ERROR (("Device %s not found", hal_device_udi)); return; } handle = usb_open (curr_device); if (handle == NULL) { HAL_ERROR (("Could not open usb device")); return; } if (!usb_control_msg (handle, 0xc0, 0x09, 0x03|addr, 0x00|addr, buf, 8, TIMEOUT) != 8) { if ((P0 == 0x3b) && (P4 == 0)) { HAL_DEBUG (("Receiver busy, trying again later")); } else { int current_charge = P5 & 0x07; HAL_DEBUG (("Charge level: %d->%d", pci->current_charge, current_charge)); if (current_charge != pci->current_charge) { pci->current_charge = current_charge; dbus_error_init (&err); libhal_device_set_property_int (halctx, hal_device_udi, "battery.charge_level.current", current_charge, &err); LIBHAL_FREE_DBUS_ERROR (&err); if (current_charge != 0) { percentage = (100.0 / 7.0) * current_charge; libhal_device_set_property_int (halctx, hal_device_udi, "battery.charge_level.percentage", percentage, &err); } else { libhal_device_remove_property(halctx, hal_device_udi, "battery.charge_level.percentage", &err); } LIBHAL_FREE_DBUS_ERROR (&err); } } } else { perror ("Writing to USB device"); } usb_close (handle); }
int main (int argc, char *argv[]) { DBusError err; int retval = 0; hal_set_proc_title_init (argc, argv); setup_logger (); device_udi = getenv ("UDI"); HAL_DEBUG (("device:[%s]", device_udi)); if (device_udi == NULL) { HAL_ERROR (("No device specified")); return -2; } dbus_error_init (&err); if ((halctx = libhal_ctx_init_direct (&err)) == NULL) { HAL_ERROR (("Cannot connect to hald")); retval = -3; goto out; } /* update_properties */ libhal_device_set_property_bool (halctx, device_udi, "battery.present", TRUE, &err); LIBHAL_FREE_DBUS_ERROR (&err); if (!libhal_device_property_exists (halctx, device_udi, "battery.is_rechargeable", &err)) { LIBHAL_FREE_DBUS_ERROR (&err); libhal_device_set_property_bool (halctx, device_udi, "battery.is_rechargeable", FALSE, &err); } LIBHAL_FREE_DBUS_ERROR (&err); libhal_device_set_property_int (halctx, device_udi, "battery.charge_level.design", 7, &err); LIBHAL_FREE_DBUS_ERROR (&err); libhal_device_set_property_int (halctx, device_udi, "battery.charge_level.last_full", 7, &err); LIBHAL_FREE_DBUS_ERROR (&err); libhal_device_set_property_string (halctx, device_udi, "info.category", "battery", &err); LIBHAL_FREE_DBUS_ERROR (&err); libhal_device_set_property_string (halctx, device_udi, "battery.command_interface", "csr", &err); /* monitor change */ libhal_ctx_set_device_property_modified (halctx, property_modified); /* Initial fillup */ dev_props = property_cache_item_get (device_udi); HAL_ERROR (("** Initial fillup done")); /* init usb */ usb_init (); /* do coldplug */ check_all_batteries (NULL); /* only add capability when initial charge_level key has been set */ LIBHAL_FREE_DBUS_ERROR (&err); libhal_device_add_capability (halctx, device_udi, "battery", &err); LIBHAL_FREE_DBUS_ERROR (&err); if (!libhal_device_addon_is_ready (halctx, device_udi, &err)) { retval = -4; goto out; } hal_set_proc_title ("hald-addon-usb-csr: listening on '%s'", libhal_device_get_property_string(halctx, device_udi, "info.product", &err)); main_loop = g_main_loop_new (NULL, FALSE); #ifdef HAVE_GLIB_2_14 g_timeout_add_seconds (TIMEOUT, check_all_batteries, NULL); #else g_timeout_add (1000L * TIMEOUT, check_all_batteries, NULL); #endif g_main_loop_run (main_loop); return 0; out: HAL_DEBUG (("An error occured, exiting cleanly")); LIBHAL_FREE_DBUS_ERROR (&err); if (halctx != NULL) { libhal_ctx_shutdown (halctx, &err); LIBHAL_FREE_DBUS_ERROR (&err); libhal_ctx_free (halctx); } return retval; }
static void battery_remove(LibHalContext *ctx, const char *udi) { DBusError error; HAL_DEBUG(("battery_remove() enter")); dbus_error_init(&error); libhal_device_remove_property(ctx, udi, "battery.remaining_time", &error); my_dbus_error_free(&error); libhal_device_remove_property(ctx, udi, "battery.charge_level.percentage", &error); my_dbus_error_free(&error); libhal_device_remove_property(ctx, udi, "battery.charge_level.rate", &error); my_dbus_error_free(&error); libhal_device_remove_property(ctx, udi, "battery.charge_level.last_full", &error); my_dbus_error_free(&error); libhal_device_remove_property(ctx, udi, "battery.charge_level.current", &error); my_dbus_error_free(&error); libhal_device_remove_property(ctx, udi, "battery.voltage.present", &error); my_dbus_error_free(&error); libhal_device_remove_property(ctx, udi, "battery.reporting.rate", &error); my_dbus_error_free(&error); libhal_device_remove_property(ctx, udi, "battery.reporting.current", &error); my_dbus_error_free(&error); libhal_device_remove_property(ctx, udi, "battery.rechargeable.is_discharging", &error); my_dbus_error_free(&error); libhal_device_remove_property(ctx, udi, "battery.rechargeable.is_charging", &error); my_dbus_error_free(&error); libhal_device_remove_property(ctx, udi, "battery.is_rechargeable", &error); my_dbus_error_free(&error); libhal_device_remove_property(ctx, udi, "battery.charge_level.unit", &error); my_dbus_error_free(&error); libhal_device_remove_property(ctx, udi, "battery.charge_level.granularity_2", &error); my_dbus_error_free(&error); libhal_device_remove_property(ctx, udi, "battery.charge_level.granularity_1", &error); my_dbus_error_free(&error); libhal_device_remove_property(ctx, udi, "battery.charge_level.low", &error); my_dbus_error_free(&error); libhal_device_remove_property(ctx, udi, "battery.charge_level.warning", &error); my_dbus_error_free(&error); libhal_device_remove_property(ctx, udi, "battery.charge_level.design", &error); my_dbus_error_free(&error); libhal_device_remove_property(ctx, udi, "battery.voltage.design", &error); my_dbus_error_free(&error); libhal_device_remove_property(ctx, udi, "battery.reporting.granularity_2", &error); my_dbus_error_free(&error); libhal_device_remove_property(ctx, udi, "battery.reporting.granularity_1", &error); my_dbus_error_free(&error); libhal_device_remove_property(ctx, udi, "battery.reporting.low", &error); my_dbus_error_free(&error); libhal_device_remove_property(ctx, udi, "battery.reporting.warning", &error); my_dbus_error_free(&error); libhal_device_remove_property(ctx, udi, "battery.reporting.design", &error); my_dbus_error_free(&error); libhal_device_remove_property(ctx, udi, "battery.reporting.last_full", &error); my_dbus_error_free(&error); libhal_device_remove_property(ctx, udi, "battery.reporting.unit", &error); my_dbus_error_free(&error); libhal_device_remove_property(ctx, udi, "battery.technology", &error); my_dbus_error_free(&error); libhal_device_remove_property(ctx, udi, "battery.reporting.technology", &error); my_dbus_error_free(&error); libhal_device_remove_property(ctx, udi, "battery.serial", &error); my_dbus_error_free(&error); libhal_device_remove_property(ctx, udi, "battery.model", &error); my_dbus_error_free(&error); libhal_device_remove_property(ctx, udi, "battery.vendor", &error); my_dbus_error_free(&error); HAL_DEBUG(("battery_remove() exit")); }
static gboolean battery_static_update(LibHalContext *ctx, const char *udi, int fd) { const char *technology; int reporting_design; int reporting_warning; int reporting_low; int reporting_gran1; int reporting_gran2; int voltage_design; char reporting_unit[10]; acpi_bif_t bif; LibHalChangeSet *cs; DBusError error; HAL_DEBUG(("battery_static_update() enter")); bzero(&bif, sizeof (bif)); if (ioctl(fd, BATT_IOC_INFO, &bif) < 0) { return (FALSE); } if ((cs = libhal_device_new_changeset(udi)) == NULL) { HAL_DEBUG(("Cannot allocate changeset")); return (FALSE); } libhal_changeset_set_property_string(cs, "battery.vendor", bif.bif_oem_info); technology = bif.bif_type; if (technology != NULL) { libhal_changeset_set_property_string(cs, "battery.reporting.technology", technology); libhal_changeset_set_property_string(cs, "battery.technology", util_get_battery_technology(technology)); } libhal_changeset_set_property_string(cs, "battery.serial", bif.bif_serial); libhal_changeset_set_property_string(cs, "battery.model", bif.bif_model); if (bif.bif_unit) { libhal_changeset_set_property_string(cs, "battery.reporting.unit", "mAh"); strlcpy(reporting_unit, "mAh", sizeof (reporting_unit)); } else { libhal_changeset_set_property_string(cs, "battery.reporting.unit", "mWh"); strlcpy(reporting_unit, "mWh", sizeof (reporting_unit)); } libhal_changeset_set_property_int(cs, "battery.reporting.last_full", bif.bif_last_cap); libhal_changeset_set_property_int(cs, "battery.reporting.design", bif.bif_design_cap); reporting_design = bif.bif_design_cap; libhal_changeset_set_property_int(cs, "battery.reporting.warning", bif.bif_warn_cap); reporting_warning = bif.bif_warn_cap; libhal_changeset_set_property_int(cs, "battery.reporting.low", bif.bif_low_cap); reporting_low = bif.bif_low_cap; libhal_changeset_set_property_int(cs, "battery.reporting.granularity_1", bif.bif_gran1_cap); reporting_gran1 = bif.bif_gran1_cap; libhal_changeset_set_property_int(cs, "battery.reporting.granularity_2", bif.bif_gran2_cap); reporting_gran2 = bif.bif_gran2_cap; libhal_changeset_set_property_int(cs, "battery.voltage.design", bif.bif_voltage); voltage_design = bif.bif_voltage; if (reporting_unit && strcmp(reporting_unit, "mAh") == 0) { /* convert to mWh */ libhal_changeset_set_property_string(cs, "battery.charge_level.unit", "mWh"); libhal_changeset_set_property_int(cs, "battery.charge_level.design", (reporting_design * voltage_design) / 1000); libhal_changeset_set_property_int(cs, "battery.charge_level.warning", (reporting_warning * voltage_design) / 1000); libhal_changeset_set_property_int(cs, "battery.charge_level.low", (reporting_low * voltage_design) / 1000); libhal_changeset_set_property_int(cs, "battery.charge_level.granularity_1", (reporting_gran1 * voltage_design) / 1000); libhal_changeset_set_property_int(cs, "battery.charge_level.granularity_2", (reporting_gran2 * voltage_design) / 1000); } else { if (reporting_unit && strcmp(reporting_unit, "mWh") == 0) { libhal_changeset_set_property_string(cs, "battery.charge_level.unit", "mWh"); } libhal_changeset_set_property_int(cs, "battery.charge_level.design", reporting_design); libhal_changeset_set_property_int(cs, "battery.charge_level.warning", reporting_warning); libhal_changeset_set_property_int(cs, "battery.charge_level.low", reporting_low); libhal_changeset_set_property_int(cs, "battery.charge_level.granularity_1", reporting_gran1); libhal_changeset_set_property_int(cs, "battery.charge_level.granularity_2", reporting_gran2); } dbus_error_init(&error); libhal_device_commit_changeset(ctx, cs, &error); libhal_device_free_changeset(cs); my_dbus_error_free(&error); HAL_DEBUG(("battery_static_update() exit")); return (TRUE); }
static void battery_dynamic_update(LibHalContext *ctx, const char *udi, int fd) { int reporting_rate; int reporting_current; int reporting_lastfull; int design_voltage; int present_voltage; char *reporting_unit; int remaining_time; int remaining_percentage; gboolean charging; gboolean discharging; acpi_bst_t bst; LibHalChangeSet *cs; DBusError error; static int counter = 0; HAL_DEBUG(("battery_dynamic_update() enter")); bzero(&bst, sizeof (bst)); if (ioctl(fd, BATT_IOC_STATUS, &bst) < 0) { return; } charging = bst.bst_state & BATT_BST_CHARGING ? TRUE : FALSE; discharging = bst.bst_state & BATT_BST_DISCHARGING ? TRUE : FALSE; /* No need to continue if battery is essentially idle. */ if (counter && !charging && !discharging) { return; } dbus_error_init(&error); libhal_device_set_property_bool(ctx, udi, "battery.is_rechargeable", TRUE, &error); my_dbus_error_free(&error); if (libhal_device_property_exists(ctx, udi, "battery.charge_level.percentage", &error)) { remaining_percentage = libhal_device_get_property_int(ctx, udi, "battery.charge_level.percentage", &error); if ((remaining_percentage == 100) && charging) { charging = FALSE; } } libhal_device_set_property_bool(ctx, udi, "battery.rechargeable.is_charging", charging, &error); my_dbus_error_free(&error); libhal_device_set_property_bool(ctx, udi, "battery.rechargeable.is_discharging", discharging, &error); my_dbus_error_free(&error); reporting_current = bst.bst_rem_cap; libhal_device_set_property_int(ctx, udi, "battery.reporting.current", bst.bst_rem_cap, &error); my_dbus_error_free(&error); reporting_rate = bst.bst_rate; libhal_device_set_property_int(ctx, udi, "battery.reporting.rate", bst.bst_rate, &error); my_dbus_error_free(&error); present_voltage = bst.bst_voltage; libhal_device_set_property_int(ctx, udi, "battery.voltage.present", bst.bst_voltage, &error); /* get all the data we know */ my_dbus_error_free(&error); reporting_unit = libhal_device_get_property_string(ctx, udi, "battery.reporting.unit", &error); my_dbus_error_free(&error); reporting_lastfull = libhal_device_get_property_int(ctx, udi, "battery.reporting.last_full", &error); /* * Convert mAh to mWh since util_compute_time_remaining() works * for mWh. */ if (reporting_unit && strcmp(reporting_unit, "mAh") == 0) { my_dbus_error_free(&error); design_voltage = libhal_device_get_property_int(ctx, udi, "battery.voltage.design", &error); /* * If the present_voltage is inaccurate, set it to the * design_voltage. */ if (((present_voltage * 10) < design_voltage) || (present_voltage <= 0) || (present_voltage > design_voltage)) { present_voltage = design_voltage; } reporting_rate = (reporting_rate * present_voltage) / 1000; reporting_lastfull = (reporting_lastfull * present_voltage) / 1000; reporting_current = (reporting_current * present_voltage) / 1000; } /* Make sure the current charge does not exceed the full charge */ if (reporting_current > reporting_lastfull) { reporting_current = reporting_lastfull; } if (!charging && !discharging) { counter++; reporting_rate = 0; } if ((cs = libhal_device_new_changeset(udi)) == NULL) { HAL_DEBUG(("Cannot allocate changeset")); libhal_free_string(reporting_unit); my_dbus_error_free(&error); return; } libhal_changeset_set_property_int(cs, "battery.charge_level.rate", reporting_rate); libhal_changeset_set_property_int(cs, "battery.charge_level.last_full", reporting_lastfull); libhal_changeset_set_property_int(cs, "battery.charge_level.current", reporting_current); remaining_percentage = util_compute_percentage_charge(udi, reporting_current, reporting_lastfull); remaining_time = util_compute_time_remaining(udi, reporting_rate, reporting_current, reporting_lastfull, discharging, charging, 0); /* * Some batteries give bad remaining_time estimates relative to * the charge level. */ if (charging && ((remaining_time < 30) || ((remaining_time < 300) && (remaining_percentage < 95)) || (remaining_percentage > 97))) { remaining_time = util_compute_time_remaining(udi, reporting_rate, reporting_current, reporting_lastfull, discharging, charging, 1); } if (remaining_percentage > 0) { libhal_changeset_set_property_int(cs, "battery.charge_level.percentage", remaining_percentage); } else { my_dbus_error_free(&error); libhal_device_remove_property(ctx, udi, "battery.charge_level.percentage", &error); } if ((remaining_percentage == 100) && charging) { battery_last_full(cs, fd); } /* * remaining_percentage is more accurate so we handle cases * where the remaining_time cannot be correct. */ if ((!charging && !discharging) || ((remaining_percentage == 100) && !discharging)) { remaining_time = 0; } if (remaining_time < 0) { my_dbus_error_free(&error); libhal_device_remove_property(ctx, udi, "battery.remaining_time", &error); } else if (remaining_time >= 0) { libhal_changeset_set_property_int(cs, "battery.remaining_time", remaining_time); } my_dbus_error_free(&error); libhal_device_commit_changeset(ctx, cs, &error); libhal_device_free_changeset(cs); libhal_free_string(reporting_unit); my_dbus_error_free(&error); HAL_DEBUG(("battery_dynamic_update() exit")); }
static void add_device (LibHalContext *ctx, const char *udi, const LibHalPropertySet *properties) { DBusError err; DBusConnection *dbus_connection; const char* sysfs_path; const char* function; static gboolean initialized = FALSE; if ((sysfs_path = libhal_ps_get_string (properties, "linux.sysfs_path")) == NULL) { HAL_ERROR(("%s has no property linux.sysfs_path", udi)); return; } if ((function = libhal_ps_get_string (properties, "leds.function")) == NULL) { HAL_ERROR(("%s has no property leds.function", udi)); return; } /* claim the interface */ if ((dbus_connection = libhal_ctx_get_dbus_connection(ctx)) == NULL) { HAL_WARNING (("Cannot get DBus connection")); return; } if (!initialized) { dbus_connection_add_filter (dbus_connection, filter_function, NULL, NULL); initialized = TRUE; } dbus_error_init (&err); if (function != NULL && strcmp(function, "kbd_backlight") == 0) { HAL_DEBUG (("Found a led which is a keyboard backlight.")); if (!libhal_device_claim_interface (ctx, udi, "org.freedesktop.Hal.Device.KeyboardBacklight", " <method name=\"SetBrightness\">\n" " <arg name=\"brightness_value\" direction=\"in\" type=\"i\"/>\n" " <arg name=\"return_code\" direction=\"out\" type=\"i\"/>\n" " </method>\n" " <method name=\"GetBrightness\">\n" " <arg name=\"brightness_value\" direction=\"out\" type=\"i\"/>\n" " </method>\n", &err)) { HAL_ERROR (("Cannot claim interface 'org.freedesktop.Hal.Device.KeyboardBacklight'")); LIBHAL_FREE_DBUS_ERROR (&err); return; } } else if (!libhal_device_claim_interface (ctx, udi, "org.freedesktop.Hal.Device.Leds", " <method name=\"SetBrightness\">\n" " <arg name=\"brightness_value\" direction=\"in\" type=\"i\"/>\n" " <arg name=\"return_code\" direction=\"out\" type=\"i\"/>\n" " </method>\n" " <method name=\"GetBrightness\">\n" " <arg name=\"brightness_value\" direction=\"out\" type=\"i\"/>\n" " </method>\n", &err)) { HAL_ERROR (("Cannot claim interface 'org.freedesktop.Hal.Device.Leds'")); LIBHAL_FREE_DBUS_ERROR (&err); return; } g_hash_table_insert (leds, g_strdup(udi), g_strdup(sysfs_path)); }
/* DBus filter function */ static DBusHandlerResult filter_function (DBusConnection *connection, DBusMessage *message, void *userdata) { DBusError err; DBusMessage *reply; const char *_udi; const char *interface; char *sysfs_path; if ((_udi = dbus_message_get_path (message)) == NULL) { HAL_DEBUG (("Couldn't get the udi for this call, ignore it.")); return DBUS_HANDLER_RESULT_HANDLED; } else { if(!g_hash_table_lookup_extended (leds, _udi, NULL, (gpointer *) &sysfs_path)) { HAL_DEBUG (("This device (%s) isn't yet handled by the addon.", _udi)); return DBUS_HANDLER_RESULT_HANDLED; } } dbus_error_init (&err); interface = dbus_message_get_interface (message); if (interface != NULL && strcmp (interface, "org.freedesktop.Hal.Device.KeyboardBacklight") == 0) { if (!check_priv (ctx, connection, message, dbus_message_get_path (message), "org.freedesktop.hal.power-management.keyboard-backlight")) { HAL_DEBUG(("User don't have the permissions to call the interface")); return DBUS_HANDLER_RESULT_HANDLED; } } else if (!check_priv (ctx, connection, message, dbus_message_get_path (message), "org.freedesktop.hal.leds.brightness")) { HAL_DEBUG(("User don't have the permissions to call the interface")); return DBUS_HANDLER_RESULT_HANDLED; } reply = NULL; if (dbus_message_is_method_call (message, "org.freedesktop.Hal.Device.Leds", "SetBrightness") || dbus_message_is_method_call (message, "org.freedesktop.Hal.Device.KeyboardBacklight", "SetBrightness")) { int brightness; if (dbus_message_get_args (message, &err, DBUS_TYPE_INT32, &brightness, DBUS_TYPE_INVALID)) { int return_code = 0; int set; set = set_leds_brightness (_udi, brightness); reply = dbus_message_new_method_return (message); if (reply == NULL) goto error; if (set == brightness) return_code = 0; else return_code = 1; dbus_message_append_args (reply, DBUS_TYPE_INT32, &return_code, DBUS_TYPE_INVALID); dbus_connection_send (connection, reply, NULL); } } else if (dbus_message_is_method_call (message, "org.freedesktop.Hal.Device.Leds", "GetBrightness") || dbus_message_is_method_call (message, "org.freedesktop.Hal.Device.KeyboardBacklight", "GetBrightness")) { int brightness; if (dbus_message_get_args (message, &err, DBUS_TYPE_INVALID)) { brightness = get_leds_brightness(_udi); reply = dbus_message_new_method_return (message); if (reply == NULL) goto error; dbus_message_append_args (reply, DBUS_TYPE_INT32, &brightness, DBUS_TYPE_INVALID); dbus_connection_send (connection, reply, NULL); } } error: if (reply != NULL) dbus_message_unref (reply); LIBHAL_FREE_DBUS_ERROR (&err); return DBUS_HANDLER_RESULT_HANDLED; }