/** * Init state handler * * - check ac, charger, battery and temperature * - initialize charger * - new states: DISCHARGE, IDLE */ static enum charge_state state_init(struct charge_state_context *ctx) { /* Stop charger, unconditionally */ charge_request(0, 0); /* if battery was not detected initially, get battery info again */ if (ctx->battery == NULL) ctx->battery = battery_get_info(); /* Update static battery info */ update_battery_info(); /* Clear shutdown timer */ ctx->shutdown_warning_time.val = 0; /* If AC is not present, switch to discharging state */ if (!ctx->curr.ac) return PWR_STATE_DISCHARGE; /* Check general error conditions */ if (ctx->curr.error) return PWR_STATE_ERROR; /* Send battery event to host */ host_set_single_event(EC_HOST_EVENT_BATTERY); return PWR_STATE_IDLE0; }
//Updates status and info of all batteries locally and in the xenstore. void update_batteries(void) { struct battery_status *old_status = NULL; struct battery_info *old_info = NULL; char path[256]; unsigned int old_num_batteries = 0; unsigned int num_batteries = 0; unsigned int i, new_array_size, old_array_size, num_batteries_to_update; bool present_batteries_changed = false; if ( pm_specs & PM_SPEC_NO_BATTERIES ) return; //Keep a copy of what the battery status/info used to be. old_status = (struct battery_status *)malloc(num_battery_structs_allocd * sizeof(struct battery_status)); old_info = (struct battery_info *)malloc(num_battery_structs_allocd * sizeof(struct battery_info)); if (last_status != NULL) memcpy(old_status, last_status, num_battery_structs_allocd * sizeof(struct battery_status)); else memset(old_status, 0, num_battery_structs_allocd * sizeof(struct battery_status)); if (last_info != NULL) memcpy(old_info, last_info, num_battery_structs_allocd * sizeof(struct battery_info)); else memset(old_info, 0, num_battery_structs_allocd * sizeof(struct battery_info)); old_array_size = num_battery_structs_allocd; //Resize the arrays if necessary. new_array_size = (unsigned int)(get_max_battery_index() + 1); if (new_array_size != old_array_size) { if (new_array_size == 0) { xcpmd_log(LOG_INFO, "All batteries removed.\n"); free(last_info); free(last_status); } else { last_info = (struct battery_info *)realloc(last_info, new_array_size * sizeof(struct battery_info)); last_status = (struct battery_status *)realloc(last_status, new_array_size * sizeof(struct battery_status)); memset(last_info, 0, new_array_size * sizeof(struct battery_info)); memset(last_status, 0, new_array_size * sizeof(struct battery_status)); } num_battery_structs_allocd = new_array_size; } num_batteries_to_update = (new_array_size > old_array_size) ? new_array_size : old_array_size; //Updating all status/info before writing to the xenstore prevents bad //calculations of aggregate data (e.g., warning level). for (i=0; i < num_batteries_to_update; ++i) { update_battery_status(i); update_battery_info(i); } //Write back to the xenstore and only send notifications if things have changed. for (i=0; i < num_batteries_to_update; ++i) { //No need to update status/info in Xenstore if there was no battery to begin with. // On some latops, batteries index are not contiguous. It is not a big // deal to have one or two empty array slot, but it should not be // reported as a removed battery (OXT-614). if (last_status[i].present || old_status[i].present) { write_battery_status_to_xenstore(i); write_battery_info_to_xenstore(i); } if (i < old_array_size && i < new_array_size) { if (memcmp(&old_info[i], &last_info[i], sizeof(struct battery_info))) { snprintf(path, 255, "%s%i/%s", XS_BATTERY_EVENT_PATH, i, XS_BATTERY_INFO_EVENT_LEAF); xenstore_write("1", path); } if (memcmp(&old_status[i], &last_status[i], sizeof(struct battery_status))) { snprintf(path, 255, "%s%i/%s", XS_BATTERY_EVENT_PATH, i, XS_BATTERY_STATUS_EVENT_LEAF); xenstore_write("1", path); } if (old_status[i].present == YES) ++old_num_batteries; if (last_status[i].present == YES) ++num_batteries; if (old_status[i].present != last_status[i].present) present_batteries_changed = true; } else if (new_array_size > old_array_size) { //a battery has been added snprintf(path, 255, "%s%i/%s", XS_BATTERY_EVENT_PATH, i, XS_BATTERY_INFO_EVENT_LEAF); xenstore_write("1", path); snprintf(path, 255, "%s%i/%s", XS_BATTERY_EVENT_PATH, i, XS_BATTERY_STATUS_EVENT_LEAF); xenstore_write("1", path); if (last_status[i].present == YES) ++num_batteries; if (i < old_array_size) { if (old_status[i].present != last_status[i].present) present_batteries_changed = true; } else { if (last_status[i].present == YES) present_batteries_changed = true; } } else if (new_array_size < old_array_size) { //a battery has been removed snprintf(path, 255, "%s%i/%s", XS_BATTERY_EVENT_PATH, i, XS_BATTERY_INFO_EVENT_LEAF); xenstore_write("1", path); snprintf(path, 255, "%s%i/%s", XS_BATTERY_EVENT_PATH, i, XS_BATTERY_STATUS_EVENT_LEAF); xenstore_write("1", path); if (old_status[i].present == YES) ++old_num_batteries; if (i < new_array_size) { if (old_status[i].present != last_status[i].present) present_batteries_changed = true; } else { if (old_status[i].present == YES) present_batteries_changed = true; } } } if ((old_array_size != new_array_size) || (memcmp(old_info, last_info, new_array_size * sizeof(struct battery_info)))) { notify_com_citrix_xenclient_xcpmd_battery_info_changed(xcdbus_conn, XCPMD_SERVICE, XCPMD_PATH); } if ((old_array_size != new_array_size) || (memcmp(old_status, last_status, new_array_size * sizeof(struct battery_status)))) { //Here for compatibility--should eventually be removed xenstore_write("1", XS_BATTERY_STATUS_CHANGE_EVENT_PATH); notify_com_citrix_xenclient_xcpmd_battery_status_changed(xcdbus_conn, XCPMD_SERVICE, XCPMD_PATH); } if (present_batteries_changed) { notify_com_citrix_xenclient_xcpmd_num_batteries_changed(xcdbus_conn, XCPMD_SERVICE, XCPMD_PATH); } free(old_info); free(old_status); }