ia64/xen-unstable

changeset 18710:635a9691a8a9

Xen power management daemon patch.

Signed-off-by: Kamala Narasimhan <kamala.narasimhan@citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Thu Oct 23 11:17:25 2008 +0100 (2008-10-23)
parents 10d338e5f741
children e5332ba0309f
files tools/Makefile tools/xenpmd/Makefile tools/xenpmd/xenpmd tools/xenpmd/xenpmd.c
line diff
     1.1 --- a/tools/Makefile	Wed Oct 22 16:47:44 2008 +0100
     1.2 +++ b/tools/Makefile	Thu Oct 23 11:17:25 2008 +0100
     1.3 @@ -24,6 +24,7 @@ SUBDIRS-y += libfsimage
     1.4  SUBDIRS-$(LIBXENAPI_BINDINGS) += libxen
     1.5  SUBDIRS-y += fs-back
     1.6  SUBDIRS-$(CONFIG_IOEMU) += ioemu-dir
     1.7 +SUBDIRS-y += xenpmd
     1.8  
     1.9  # These don't cross-compile
    1.10  ifeq ($(XEN_COMPILE_ARCH),$(XEN_TARGET_ARCH))
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/tools/xenpmd/Makefile	Thu Oct 23 11:17:25 2008 +0100
     2.3 @@ -0,0 +1,15 @@
     2.4 +XEN_ROOT=../..
     2.5 +include $(XEN_ROOT)/tools/Rules.mk
     2.6 +
     2.7 +CFLAGS  += -Werror
     2.8 +CFLAGS  += $(CFLAGS_libxenstore)
     2.9 +LDFLAGS += $(LDFLAGS_libxenstore)
    2.10 +
    2.11 +BIN      = xenpmd
    2.12 +
    2.13 +.PHONY: all
    2.14 +all: $(BIN)
    2.15 +
    2.16 +.PHONY: clean
    2.17 +clean:
    2.18 +	$(RM) -f $(BIN)
     3.1 Binary file tools/xenpmd/xenpmd has changed
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/tools/xenpmd/xenpmd.c	Thu Oct 23 11:17:25 2008 +0100
     4.3 @@ -0,0 +1,520 @@
     4.4 +/*
     4.5 + * xenpmd.c
     4.6 + *
     4.7 + * xen power management daemon - Facilitates power management 
     4.8 + * functionality within xen guests.
     4.9 + *
    4.10 + * Copyright (c) 2008  Kamala Narasimhan 
    4.11 + * Copyright (c) 2008  Citrix Systems, Inc.
    4.12 + *
    4.13 + * This program is free software; you can redistribute it and/or modify
    4.14 + * it under the terms of the GNU General Public License as published by
    4.15 + * the Free Software Foundation; either version 2 of the License, or
    4.16 + * (at your option) any later version.
    4.17 + *
    4.18 + * This program is distributed in the hope that it will be useful,
    4.19 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
    4.20 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    4.21 + * GNU General Public License for more details.
    4.22 + *
    4.23 + * You should have received a copy of the GNU General Public License
    4.24 + * along with this program; if not, write to the Free Software
    4.25 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    4.26 + */
    4.27 +
    4.28 +/* Xen extended power management support provides HVM guest power management
    4.29 + * features beyond S3, S4, S5.  For example, it helps expose system level 
    4.30 + * battery status and battery meter information and in future will be extended
    4.31 + * to include more power management support.  This extended power management 
    4.32 + * support is enabled by setting xen_extended_power_mgmt to 1 or 2 in the HVM
    4.33 + * config file.  When set to 2, non-pass through mode is enabled which heavily
    4.34 + * relies on this power management daemon to glean battery information from 
    4.35 + * dom0 and store it xenstore which would then be queries and used by qemu and 
    4.36 + * passed to the guest when appropriate battery ports are read/written to.
    4.37 + */
    4.38 +
    4.39 +#include <stdio.h>
    4.40 +#include <stdarg.h>
    4.41 +#include <string.h>
    4.42 +#include <stdlib.h>
    4.43 +#include <dirent.h>
    4.44 +#include <unistd.h>
    4.45 +#include <sys/stat.h>
    4.46 +#include <xs.h>
    4.47 +
    4.48 +/* #define RUN_STANDALONE */
    4.49 +#define RUN_IN_SIMULATE_MODE
    4.50 +
    4.51 +enum BATTERY_INFO_TYPE {
    4.52 +    BIF, 
    4.53 +    BST 
    4.54 +};
    4.55 +
    4.56 +enum BATTERY_PRESENT {
    4.57 +    NO, 
    4.58 +    YES 
    4.59 +};
    4.60 +
    4.61 +enum BATTERY_TECHNOLOGY {
    4.62 +    NON_RECHARGEABLE, 
    4.63 +    RECHARGEABLE 
    4.64 +};
    4.65 +
    4.66 +struct battery_info {
    4.67 +    enum BATTERY_PRESENT    present;
    4.68 +    unsigned long           design_capacity;
    4.69 +    unsigned long           last_full_capacity;
    4.70 +    enum BATTERY_TECHNOLOGY battery_technology;
    4.71 +    unsigned long           design_voltage;
    4.72 +    unsigned long           design_capacity_warning;
    4.73 +    unsigned long           design_capacity_low;
    4.74 +    unsigned long           capacity_granularity_1;
    4.75 +    unsigned long           capacity_granularity_2;
    4.76 +    char                    model_number[32];
    4.77 +    char                    serial_number[32];
    4.78 +    char                    battery_type[32];
    4.79 +    char                    oem_info[32];
    4.80 +};
    4.81 +
    4.82 +struct battery_status {
    4.83 +    enum BATTERY_PRESENT    present;
    4.84 +    unsigned long           state;
    4.85 +    unsigned long           present_rate;
    4.86 +    unsigned long           remaining_capacity;
    4.87 +    unsigned long           present_voltage;
    4.88 +};
    4.89 +
    4.90 +static struct xs_handle *xs;
    4.91 +
    4.92 +#ifdef RUN_IN_SIMULATE_MODE
    4.93 +    #define BATTERY_DIR_PATH "/tmp/battery"
    4.94 +    #define BATTERY_INFO_FILE_PATH "/tmp/battery/%s/info" 
    4.95 +    #define BATTERY_STATE_FILE_PATH "/tmp/battery/%s/state"
    4.96 +#else
    4.97 +    #define BATTERY_DIR_PATH "/proc/acpi/battery"
    4.98 +    #define BATTERY_INFO_FILE_PATH "/proc/acpi/battery/%s/info"
    4.99 +    #define BATTERY_STATE_FILE_PATH "/proc/acpi/battery/%s/state"
   4.100 +#endif
   4.101 +
   4.102 +FILE *get_next_battery_file(DIR *battery_dir, 
   4.103 +                            enum BATTERY_INFO_TYPE battery_info_type)
   4.104 +{
   4.105 +    FILE *file = 0;
   4.106 +    struct dirent *dir_entries;
   4.107 +    char file_name[32];
   4.108 +    
   4.109 +    do 
   4.110 +    {
   4.111 +        dir_entries = readdir(battery_dir);
   4.112 +        if ( !dir_entries ) 
   4.113 +            return 0;
   4.114 +        if ( strlen(dir_entries->d_name) < 4 )
   4.115 +            continue;
   4.116 +        if ( battery_info_type == BIF ) 
   4.117 +            snprintf(file_name, 32, BATTERY_INFO_FILE_PATH,
   4.118 +                     dir_entries->d_name);
   4.119 +        else 
   4.120 +            snprintf(file_name, 32, BATTERY_STATE_FILE_PATH,
   4.121 +                     dir_entries->d_name);
   4.122 +        file = fopen(file_name, "r");
   4.123 +    } while ( !file );
   4.124 +
   4.125 +    return file;
   4.126 +}
   4.127 +
   4.128 +void set_attribute_battery_info(char *attrib_name,
   4.129 +                                char *attrib_value,
   4.130 +                                struct battery_info *info)
   4.131 +{
   4.132 +    if ( strstr(attrib_name, "present") ) 
   4.133 +    {
   4.134 +        if ( strstr(attrib_value, "yes") ) 
   4.135 +            info->present = YES;
   4.136 +        return;
   4.137 +    }
   4.138 +
   4.139 +    if ( strstr(attrib_name, "design capacity warning") ) 
   4.140 +    {
   4.141 +        info->design_capacity_warning = strtoull(attrib_value, NULL, 10);
   4.142 +        return;
   4.143 +    }
   4.144 +
   4.145 +    if ( strstr(attrib_name, "design capacity low") ) 
   4.146 +    {
   4.147 +        info->design_capacity_low = strtoull(attrib_value, NULL, 10);
   4.148 +        return;
   4.149 +    }
   4.150 +
   4.151 +    if ( strstr(attrib_name, "design capacity") ) 
   4.152 +    { 
   4.153 +        info->design_capacity = strtoull(attrib_value, NULL, 10);
   4.154 +        return;
   4.155 +    }
   4.156 +
   4.157 +    if ( strstr(attrib_name, "last full capacity") ) 
   4.158 +    {
   4.159 +        info->last_full_capacity = strtoull(attrib_value, NULL, 10);
   4.160 +        return;
   4.161 +    }
   4.162 +
   4.163 +    if ( strstr(attrib_name, "design voltage") ) 
   4.164 +    {
   4.165 +        info->design_voltage = strtoull(attrib_value, NULL, 10);
   4.166 +        return;
   4.167 +    }
   4.168 +
   4.169 +    if ( strstr(attrib_name, "capacity granularity 1") ) 
   4.170 +    {
   4.171 +        info->capacity_granularity_1 = strtoull(attrib_value, NULL, 10);
   4.172 +        return;
   4.173 +    }
   4.174 +
   4.175 +    if ( strstr(attrib_name, "capacity granularity 2") ) 
   4.176 +    {
   4.177 +        info->capacity_granularity_2 = strtoull(attrib_value, NULL, 10);
   4.178 +        return;
   4.179 +    }
   4.180 +
   4.181 +    if ( strstr(attrib_name, "battery technology") ) 
   4.182 +    {
   4.183 +        if ( strncmp(attrib_value, "rechargeable",
   4.184 +                     strlen("rechargeable")) == 0 ) 
   4.185 +            info->battery_technology = RECHARGEABLE;
   4.186 +        else 
   4.187 +            info->battery_technology = NON_RECHARGEABLE;
   4.188 +        return;
   4.189 +    }
   4.190 +
   4.191 +    if ( strstr(attrib_name, "model number") ) 
   4.192 +    {
   4.193 +        strncpy(info->model_number, attrib_value, 32);
   4.194 +        return;
   4.195 +    }
   4.196 +
   4.197 +    if ( strstr(attrib_name, "serial number") ) 
   4.198 +    {
   4.199 +        strncpy(info->serial_number, attrib_value, 32);
   4.200 +        return;
   4.201 +    }
   4.202 +
   4.203 +    if ( strstr(attrib_name, "battery type") ) 
   4.204 +    {
   4.205 +        strncpy(info->battery_type, attrib_value, 32);
   4.206 +        return;
   4.207 +    }
   4.208 +
   4.209 +    if ( strstr(attrib_name, "OEM info") ) 
   4.210 +    {
   4.211 +        strncpy(info->oem_info, attrib_value, 32);
   4.212 +        return;
   4.213 +    }
   4.214 +
   4.215 +    return;
   4.216 +}
   4.217 +
   4.218 +void set_attribute_battery_status(char *attrib_name, 
   4.219 +                                  char *attrib_value,
   4.220 +                                  struct battery_status *status)
   4.221 +{
   4.222 +    if ( strstr(attrib_name, "charging state") ) 
   4.223 +    {
   4.224 +        /* Check this, below is half baked */
   4.225 +        if ( strstr(attrib_value, "charged") ) 
   4.226 +            status->state = 0;
   4.227 +        else 
   4.228 +            status->state = 1;
   4.229 +        return;
   4.230 +    }
   4.231 +
   4.232 +    if ( strstr(attrib_name, "present rate") ) 
   4.233 +    {
   4.234 +        status->present_rate = strtoull(attrib_value, NULL, 10);
   4.235 +        return;
   4.236 +    }
   4.237 +
   4.238 +    if ( strstr(attrib_name, "remaining capacity") ) 
   4.239 +    {
   4.240 +        status->remaining_capacity = strtoull(attrib_value, NULL, 10);
   4.241 +        return;
   4.242 +    }
   4.243 +
   4.244 +    if ( strstr(attrib_name, "present voltage") ) 
   4.245 +    {
   4.246 +        status->present_voltage = strtoull(attrib_value, NULL, 10);
   4.247 +        return;
   4.248 +    }
   4.249 +
   4.250 +    if ( strstr(attrib_name, "present") ) 
   4.251 +    {
   4.252 +        if ( strstr(attrib_value, "yes") ) 
   4.253 +            status->present = YES;
   4.254 +        return;
   4.255 +    }
   4.256 +}
   4.257 +
   4.258 +void parse_battery_info_or_status(char *line_info,
   4.259 +                                  enum BATTERY_INFO_TYPE type,
   4.260 +                                  void *info_or_status)
   4.261 +{
   4.262 +    char attrib_name[128];
   4.263 +    char attrib_value[64];
   4.264 +    char *delimiter;
   4.265 +    unsigned long length;
   4.266 +
   4.267 +    length = strlen(line_info);
   4.268 +    delimiter = (char *) strchr( line_info, ':');
   4.269 +    if ( (!delimiter) || (delimiter == line_info) ||
   4.270 +         (delimiter == line_info + length) ) 
   4.271 +        return;
   4.272 +
   4.273 +    strncpy(attrib_name, line_info, delimiter-line_info);
   4.274 +    while ( *(delimiter+1) == ' ' ) 
   4.275 +    {
   4.276 +        delimiter++;
   4.277 +        if ( delimiter+1 == line_info + length)
   4.278 +            return;
   4.279 +    }
   4.280 +    strncpy(attrib_value, delimiter+1, 
   4.281 +            (unsigned long)line_info + length -(unsigned long)delimiter); 
   4.282 +    
   4.283 +    if ( type == BIF ) 
   4.284 +        set_attribute_battery_info(attrib_name, attrib_value,
   4.285 +                                   (struct battery_info *)info_or_status);
   4.286 +    else 
   4.287 +        set_attribute_battery_status(attrib_name, attrib_value,
   4.288 +                                     (struct battery_status *)info_or_status);
   4.289 +
   4.290 +    return;
   4.291 +}
   4.292 +
   4.293 +int get_next_battery_info_or_status(DIR *battery_dir,
   4.294 +                                    enum BATTERY_INFO_TYPE type,
   4.295 +                                    void *info_or_status)
   4.296 +{
   4.297 +    FILE *file;
   4.298 +    char line_info[256];
   4.299 +
   4.300 +    if  ( !info_or_status )
   4.301 +        return 0;
   4.302 +
   4.303 +    memset(line_info, 0, 256);
   4.304 +    if (type == BIF) 
   4.305 +        memset(info_or_status, 0, sizeof(struct battery_info));
   4.306 +    else 
   4.307 +        memset(info_or_status, 0, sizeof(struct battery_status));
   4.308 +
   4.309 +    file = get_next_battery_file(battery_dir, type);
   4.310 +    if ( !file )
   4.311 +        return 0;
   4.312 +
   4.313 +    while ( fgets(line_info, 1024, file) != NULL ) 
   4.314 +    {
   4.315 +        parse_battery_info_or_status(line_info, type, info_or_status);
   4.316 +        memset(line_info, 0, 256);
   4.317 +    }
   4.318 +
   4.319 +    fclose(file);
   4.320 +    return 1;
   4.321 +}
   4.322 +
   4.323 +#ifdef RUN_STANDALONE
   4.324 +void print_battery_info(struct battery_info *info)
   4.325 +{
   4.326 +    printf("present:                %d\n", info->present);
   4.327 +    printf("design capacity:        %d\n", info->design_capacity);
   4.328 +    printf("last full capacity:     %d\n", info->last_full_capacity);
   4.329 +    printf("battery technology:     %d\n", info->battery_technology);
   4.330 +    printf("design voltage:         %d\n", info->design_voltage);
   4.331 +    printf("design capacity warning:%d\n", info->design_capacity_warning);
   4.332 +    printf("design capacity low:    %d\n", info->design_capacity_low);
   4.333 +    printf("capacity granularity 1: %d\n", info->capacity_granularity_1);
   4.334 +    printf("capacity granularity 2: %d\n", info->capacity_granularity_2);
   4.335 +    printf("model number:           %s\n", info->model_number);
   4.336 +    printf("serial number:          %s\n", info->serial_number);
   4.337 +    printf("battery type:           %s\n", info->battery_type);
   4.338 +    printf("OEM info:               %s\n", info->oem_info);
   4.339 +}
   4.340 +#endif /*RUN_STANDALONE*/
   4.341 +
   4.342 +void write_ulong_lsb_first(char *temp_val, unsigned long val)
   4.343 +{
   4.344 +    snprintf(temp_val, 9, "%02x%02x%02x%02x", (unsigned int)val & 0xff, 
   4.345 +    (unsigned int)(val & 0xff00) >> 8, (unsigned int)(val & 0xff0000) >> 16, 
   4.346 +    (unsigned int)(val & 0xff000000) >> 24);
   4.347 +}
   4.348 +
   4.349 +void write_battery_info_to_xenstore(struct battery_info *info)
   4.350 +{
   4.351 +    char val[1024], string_info[256];
   4.352 +
   4.353 +    xs_mkdir(xs, XBT_NULL, "/pm");
   4.354 +   
   4.355 +    memset(val, 0, 1024);
   4.356 +    memset(string_info, 0, 256);
   4.357 +    /* write 9 dwords (so 9*4) + length of 4 strings + 4 null terminators */
   4.358 +    snprintf(val, 3, "%02x", 
   4.359 +             (unsigned int)(9*4 +
   4.360 +                            strlen(info->model_number) +
   4.361 +                            strlen(info->serial_number) +
   4.362 +                            strlen(info->battery_type) +
   4.363 +                            strlen(info->oem_info) + 4));
   4.364 +    write_ulong_lsb_first(val+2, info->present);
   4.365 +    write_ulong_lsb_first(val+10, info->design_capacity);
   4.366 +    write_ulong_lsb_first(val+18, info->last_full_capacity);
   4.367 +    write_ulong_lsb_first(val+26, info->battery_technology);
   4.368 +    write_ulong_lsb_first(val+34, info->design_voltage);
   4.369 +    write_ulong_lsb_first(val+42, info->design_capacity_warning);
   4.370 +    write_ulong_lsb_first(val+50, info->design_capacity_low);
   4.371 +    write_ulong_lsb_first(val+58, info->capacity_granularity_1);
   4.372 +    write_ulong_lsb_first(val+66, info->capacity_granularity_2);
   4.373 +
   4.374 +    snprintf(string_info, 256, "%02x%s%02x%s%02x%s%02x%s", 
   4.375 +             (unsigned int)strlen(info->model_number), info->model_number,
   4.376 +             (unsigned int)strlen(info->serial_number), info->serial_number,
   4.377 +             (unsigned int)strlen(info->battery_type), info->battery_type,
   4.378 +             (unsigned int)strlen(info->oem_info), info->oem_info);
   4.379 +    strncat(val+73, string_info, 1024);
   4.380 +    xs_write(xs, XBT_NULL, "/pm/bif", 
   4.381 +             val, 73+8+strlen(info->model_number)+strlen(info->serial_number)+
   4.382 +             strlen(info->battery_type)+strlen(info->oem_info)+1);
   4.383 +}
   4.384 +
   4.385 +int write_one_time_battery_info(void)
   4.386 +{
   4.387 +    DIR *dir;
   4.388 +    int ret = 0;
   4.389 +    struct battery_info info;
   4.390 +    
   4.391 +    dir = opendir(BATTERY_DIR_PATH);
   4.392 +    if ( !dir )
   4.393 +        return 0;
   4.394 +
   4.395 +    while ( get_next_battery_info_or_status(dir, BIF, (void *)&info) ) 
   4.396 +    {
   4.397 +#ifdef RUN_STANDALONE
   4.398 +        print_battery_info(&info);
   4.399 +#endif
   4.400 +        if ( info.present == YES ) 
   4.401 +        {
   4.402 +            write_battery_info_to_xenstore(&info);
   4.403 +            ret = 1;
   4.404 +            break; /* rethink this... */
   4.405 +        }
   4.406 +    }
   4.407 +
   4.408 +    closedir(dir);
   4.409 +    return ret;
   4.410 +}
   4.411 +
   4.412 +#ifdef RUN_STANDALONE
   4.413 +void print_battery_status(struct battery_status *status)
   4.414 +{
   4.415 +    printf("present:                     %d\n", status->present);
   4.416 +    printf("Battery state                %d\n", status->state);
   4.417 +    printf("Battery present rate         %d\n", status->present_rate);
   4.418 +    printf("Battery remining capacity    %d\n", status->remaining_capacity);
   4.419 +    printf("Battery present voltage      %d\n", status->present_voltage);
   4.420 +}
   4.421 +#endif /*RUN_STANDALONE*/
   4.422 +
   4.423 +void write_battery_status_to_xenstore(struct battery_status *status)
   4.424 +{
   4.425 +    char val[35];
   4.426 +
   4.427 +    xs_mkdir(xs, XBT_NULL, "/pm");
   4.428 +
   4.429 +    memset(val, 0, 35);
   4.430 +    snprintf(val, 3, "%02x", 16);
   4.431 +    write_ulong_lsb_first(val+2, status->state);
   4.432 +    write_ulong_lsb_first(val+10, status->present_rate);
   4.433 +    write_ulong_lsb_first(val+18, status->remaining_capacity);
   4.434 +    write_ulong_lsb_first(val+26, status->present_voltage);
   4.435 +
   4.436 +    xs_write(xs, XBT_NULL, "/pm/bst", val, 35);
   4.437 +}
   4.438 +
   4.439 +int wait_for_and_update_battery_status_request(void)
   4.440 +{
   4.441 +    DIR *dir;
   4.442 +    int ret = 0;
   4.443 +    unsigned int count;
   4.444 +    struct battery_status status;
   4.445 +
   4.446 +    while ( true )
   4.447 +    {
   4.448 +        /* KN:@TODO - It is rather inefficient to not cache the file handle.
   4.449 +         *  Switch to caching file handle. 
   4.450 +         */
   4.451 +        dir = opendir(BATTERY_DIR_PATH);
   4.452 +        if ( !dir )
   4.453 +            return 0;
   4.454 +
   4.455 +        while ( get_next_battery_info_or_status(dir, BST, (void *)&status) ) 
   4.456 +        {
   4.457 +#ifdef RUN_STANDALONE
   4.458 +            print_battery_status(&status);
   4.459 +#endif
   4.460 +            if ( status.present == YES ) 
   4.461 +            {
   4.462 +                write_battery_status_to_xenstore(&status);
   4.463 +                ret = 1;
   4.464 +                /* rethink this; though I have never seen, there might be
   4.465 +                 * systems out there with more than one battery device 
   4.466 +                 * present
   4.467 +                 */
   4.468 +                break;
   4.469 +            }
   4.470 +        }
   4.471 +        closedir(dir);
   4.472 +        xs_watch(xs, "/pm/events", "refreshbatterystatus");
   4.473 +        xs_read_watch(xs, &count); 
   4.474 +    }
   4.475 +
   4.476 +    return ret;
   4.477 +}
   4.478 +
   4.479 +/* Borrowed daemonize from xenstored - Initially written by Stevens. */
   4.480 +static void daemonize(void)
   4.481 +{
   4.482 +    pid_t pid;
   4.483 +
   4.484 +    if ( (pid = fork()) < 0 )
   4.485 +        exit(1);
   4.486 +
   4.487 +    if ( pid != 0 )
   4.488 +        exit(0);
   4.489 +
   4.490 +    setsid();
   4.491 +
   4.492 +    if ( (pid = fork()) < 0 )
   4.493 +        exit(1);
   4.494 +
   4.495 +    if ( pid != 0 )
   4.496 +        exit(0);
   4.497 +
   4.498 +    if ( chdir("/") == -1 )
   4.499 +        exit(1);
   4.500 +
   4.501 +    umask(0);
   4.502 +}
   4.503 +
   4.504 +int main(int argc, char *argv[])
   4.505 +{
   4.506 +#ifndef RUN_STANDALONE
   4.507 +    daemonize();
   4.508 +#endif
   4.509 +    xs = (struct xs_handle *)xs_daemon_open();
   4.510 +    if ( xs == NULL ) 
   4.511 +        return -1;
   4.512 +
   4.513 +    if ( write_one_time_battery_info() == 0 ) 
   4.514 +    {
   4.515 +        xs_daemon_close(xs);
   4.516 +        return -1;
   4.517 +    }
   4.518 +
   4.519 +    wait_for_and_update_battery_status_request();
   4.520 +    xs_daemon_close(xs);
   4.521 +    return 0;
   4.522 +}
   4.523 +