[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-changelog] [xen-unstable] Xen power management daemon patch.



# HG changeset patch
# User Keir Fraser <keir.fraser@xxxxxxxxxx>
# Date 1224757045 -3600
# Node ID 635a9691a8a9e9793312dc61184624a6d2e6b285
# Parent  10d338e5f741f813ea5b3335c405e9a57d55f535
Xen power management daemon patch.

Signed-off-by: Kamala Narasimhan <kamala.narasimhan@xxxxxxxxxx>
---
 tools/Makefile        |    1 
 tools/xenpmd/Makefile |   15 +
 tools/xenpmd/xenpmd.c |  520 ++++++++++++++++++++++++++++++++++++++++++++++++++
 xenpmd/xenpmd         |    0 
 4 files changed, 536 insertions(+)

diff -r 10d338e5f741 -r 635a9691a8a9 tools/Makefile
--- a/tools/Makefile    Wed Oct 22 16:47:44 2008 +0100
+++ b/tools/Makefile    Thu Oct 23 11:17:25 2008 +0100
@@ -24,6 +24,7 @@ SUBDIRS-$(LIBXENAPI_BINDINGS) += libxen
 SUBDIRS-$(LIBXENAPI_BINDINGS) += libxen
 SUBDIRS-y += fs-back
 SUBDIRS-$(CONFIG_IOEMU) += ioemu-dir
+SUBDIRS-y += xenpmd
 
 # These don't cross-compile
 ifeq ($(XEN_COMPILE_ARCH),$(XEN_TARGET_ARCH))
diff -r 10d338e5f741 -r 635a9691a8a9 tools/xenpmd/Makefile
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/xenpmd/Makefile     Thu Oct 23 11:17:25 2008 +0100
@@ -0,0 +1,15 @@
+XEN_ROOT=../..
+include $(XEN_ROOT)/tools/Rules.mk
+
+CFLAGS  += -Werror
+CFLAGS  += $(CFLAGS_libxenstore)
+LDFLAGS += $(LDFLAGS_libxenstore)
+
+BIN      = xenpmd
+
+.PHONY: all
+all: $(BIN)
+
+.PHONY: clean
+clean:
+       $(RM) -f $(BIN)
diff -r 10d338e5f741 -r 635a9691a8a9 tools/xenpmd/xenpmd
Binary file tools/xenpmd/xenpmd has changed
diff -r 10d338e5f741 -r 635a9691a8a9 tools/xenpmd/xenpmd.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/xenpmd/xenpmd.c     Thu Oct 23 11:17:25 2008 +0100
@@ -0,0 +1,520 @@
+/*
+ * xenpmd.c
+ *
+ * xen power management daemon - Facilitates power management 
+ * functionality within xen guests.
+ *
+ * Copyright (c) 2008  Kamala Narasimhan 
+ * Copyright (c) 2008  Citrix Systems, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/* Xen extended power management support provides HVM guest power management
+ * features beyond S3, S4, S5.  For example, it helps expose system level 
+ * battery status and battery meter information and in future will be extended
+ * to include more power management support.  This extended power management 
+ * support is enabled by setting xen_extended_power_mgmt to 1 or 2 in the HVM
+ * config file.  When set to 2, non-pass through mode is enabled which heavily
+ * relies on this power management daemon to glean battery information from 
+ * dom0 and store it xenstore which would then be queries and used by qemu and 
+ * passed to the guest when appropriate battery ports are read/written to.
+ */
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <stdlib.h>
+#include <dirent.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <xs.h>
+
+/* #define RUN_STANDALONE */
+#define RUN_IN_SIMULATE_MODE
+
+enum BATTERY_INFO_TYPE {
+    BIF, 
+    BST 
+};
+
+enum BATTERY_PRESENT {
+    NO, 
+    YES 
+};
+
+enum BATTERY_TECHNOLOGY {
+    NON_RECHARGEABLE, 
+    RECHARGEABLE 
+};
+
+struct battery_info {
+    enum BATTERY_PRESENT    present;
+    unsigned long           design_capacity;
+    unsigned long           last_full_capacity;
+    enum BATTERY_TECHNOLOGY battery_technology;
+    unsigned long           design_voltage;
+    unsigned long           design_capacity_warning;
+    unsigned long           design_capacity_low;
+    unsigned long           capacity_granularity_1;
+    unsigned long           capacity_granularity_2;
+    char                    model_number[32];
+    char                    serial_number[32];
+    char                    battery_type[32];
+    char                    oem_info[32];
+};
+
+struct battery_status {
+    enum BATTERY_PRESENT    present;
+    unsigned long           state;
+    unsigned long           present_rate;
+    unsigned long           remaining_capacity;
+    unsigned long           present_voltage;
+};
+
+static struct xs_handle *xs;
+
+#ifdef RUN_IN_SIMULATE_MODE
+    #define BATTERY_DIR_PATH "/tmp/battery"
+    #define BATTERY_INFO_FILE_PATH "/tmp/battery/%s/info" 
+    #define BATTERY_STATE_FILE_PATH "/tmp/battery/%s/state"
+#else
+    #define BATTERY_DIR_PATH "/proc/acpi/battery"
+    #define BATTERY_INFO_FILE_PATH "/proc/acpi/battery/%s/info"
+    #define BATTERY_STATE_FILE_PATH "/proc/acpi/battery/%s/state"
+#endif
+
+FILE *get_next_battery_file(DIR *battery_dir, 
+                            enum BATTERY_INFO_TYPE battery_info_type)
+{
+    FILE *file = 0;
+    struct dirent *dir_entries;
+    char file_name[32];
+    
+    do 
+    {
+        dir_entries = readdir(battery_dir);
+        if ( !dir_entries ) 
+            return 0;
+        if ( strlen(dir_entries->d_name) < 4 )
+            continue;
+        if ( battery_info_type == BIF ) 
+            snprintf(file_name, 32, BATTERY_INFO_FILE_PATH,
+                     dir_entries->d_name);
+        else 
+            snprintf(file_name, 32, BATTERY_STATE_FILE_PATH,
+                     dir_entries->d_name);
+        file = fopen(file_name, "r");
+    } while ( !file );
+
+    return file;
+}
+
+void set_attribute_battery_info(char *attrib_name,
+                                char *attrib_value,
+                                struct battery_info *info)
+{
+    if ( strstr(attrib_name, "present") ) 
+    {
+        if ( strstr(attrib_value, "yes") ) 
+            info->present = YES;
+        return;
+    }
+
+    if ( strstr(attrib_name, "design capacity warning") ) 
+    {
+        info->design_capacity_warning = strtoull(attrib_value, NULL, 10);
+        return;
+    }
+
+    if ( strstr(attrib_name, "design capacity low") ) 
+    {
+        info->design_capacity_low = strtoull(attrib_value, NULL, 10);
+        return;
+    }
+
+    if ( strstr(attrib_name, "design capacity") ) 
+    { 
+        info->design_capacity = strtoull(attrib_value, NULL, 10);
+        return;
+    }
+
+    if ( strstr(attrib_name, "last full capacity") ) 
+    {
+        info->last_full_capacity = strtoull(attrib_value, NULL, 10);
+        return;
+    }
+
+    if ( strstr(attrib_name, "design voltage") ) 
+    {
+        info->design_voltage = strtoull(attrib_value, NULL, 10);
+        return;
+    }
+
+    if ( strstr(attrib_name, "capacity granularity 1") ) 
+    {
+        info->capacity_granularity_1 = strtoull(attrib_value, NULL, 10);
+        return;
+    }
+
+    if ( strstr(attrib_name, "capacity granularity 2") ) 
+    {
+        info->capacity_granularity_2 = strtoull(attrib_value, NULL, 10);
+        return;
+    }
+
+    if ( strstr(attrib_name, "battery technology") ) 
+    {
+        if ( strncmp(attrib_value, "rechargeable",
+                     strlen("rechargeable")) == 0 ) 
+            info->battery_technology = RECHARGEABLE;
+        else 
+            info->battery_technology = NON_RECHARGEABLE;
+        return;
+    }
+
+    if ( strstr(attrib_name, "model number") ) 
+    {
+        strncpy(info->model_number, attrib_value, 32);
+        return;
+    }
+
+    if ( strstr(attrib_name, "serial number") ) 
+    {
+        strncpy(info->serial_number, attrib_value, 32);
+        return;
+    }
+
+    if ( strstr(attrib_name, "battery type") ) 
+    {
+        strncpy(info->battery_type, attrib_value, 32);
+        return;
+    }
+
+    if ( strstr(attrib_name, "OEM info") ) 
+    {
+        strncpy(info->oem_info, attrib_value, 32);
+        return;
+    }
+
+    return;
+}
+
+void set_attribute_battery_status(char *attrib_name, 
+                                  char *attrib_value,
+                                  struct battery_status *status)
+{
+    if ( strstr(attrib_name, "charging state") ) 
+    {
+        /* Check this, below is half baked */
+        if ( strstr(attrib_value, "charged") ) 
+            status->state = 0;
+        else 
+            status->state = 1;
+        return;
+    }
+
+    if ( strstr(attrib_name, "present rate") ) 
+    {
+        status->present_rate = strtoull(attrib_value, NULL, 10);
+        return;
+    }
+
+    if ( strstr(attrib_name, "remaining capacity") ) 
+    {
+        status->remaining_capacity = strtoull(attrib_value, NULL, 10);
+        return;
+    }
+
+    if ( strstr(attrib_name, "present voltage") ) 
+    {
+        status->present_voltage = strtoull(attrib_value, NULL, 10);
+        return;
+    }
+
+    if ( strstr(attrib_name, "present") ) 
+    {
+        if ( strstr(attrib_value, "yes") ) 
+            status->present = YES;
+        return;
+    }
+}
+
+void parse_battery_info_or_status(char *line_info,
+                                  enum BATTERY_INFO_TYPE type,
+                                  void *info_or_status)
+{
+    char attrib_name[128];
+    char attrib_value[64];
+    char *delimiter;
+    unsigned long length;
+
+    length = strlen(line_info);
+    delimiter = (char *) strchr( line_info, ':');
+    if ( (!delimiter) || (delimiter == line_info) ||
+         (delimiter == line_info + length) ) 
+        return;
+
+    strncpy(attrib_name, line_info, delimiter-line_info);
+    while ( *(delimiter+1) == ' ' ) 
+    {
+        delimiter++;
+        if ( delimiter+1 == line_info + length)
+            return;
+    }
+    strncpy(attrib_value, delimiter+1, 
+            (unsigned long)line_info + length -(unsigned long)delimiter); 
+    
+    if ( type == BIF ) 
+        set_attribute_battery_info(attrib_name, attrib_value,
+                                   (struct battery_info *)info_or_status);
+    else 
+        set_attribute_battery_status(attrib_name, attrib_value,
+                                     (struct battery_status *)info_or_status);
+
+    return;
+}
+
+int get_next_battery_info_or_status(DIR *battery_dir,
+                                    enum BATTERY_INFO_TYPE type,
+                                    void *info_or_status)
+{
+    FILE *file;
+    char line_info[256];
+
+    if  ( !info_or_status )
+        return 0;
+
+    memset(line_info, 0, 256);
+    if (type == BIF) 
+        memset(info_or_status, 0, sizeof(struct battery_info));
+    else 
+        memset(info_or_status, 0, sizeof(struct battery_status));
+
+    file = get_next_battery_file(battery_dir, type);
+    if ( !file )
+        return 0;
+
+    while ( fgets(line_info, 1024, file) != NULL ) 
+    {
+        parse_battery_info_or_status(line_info, type, info_or_status);
+        memset(line_info, 0, 256);
+    }
+
+    fclose(file);
+    return 1;
+}
+
+#ifdef RUN_STANDALONE
+void print_battery_info(struct battery_info *info)
+{
+    printf("present:                %d\n", info->present);
+    printf("design capacity:        %d\n", info->design_capacity);
+    printf("last full capacity:     %d\n", info->last_full_capacity);
+    printf("battery technology:     %d\n", info->battery_technology);
+    printf("design voltage:         %d\n", info->design_voltage);
+    printf("design capacity warning:%d\n", info->design_capacity_warning);
+    printf("design capacity low:    %d\n", info->design_capacity_low);
+    printf("capacity granularity 1: %d\n", info->capacity_granularity_1);
+    printf("capacity granularity 2: %d\n", info->capacity_granularity_2);
+    printf("model number:           %s\n", info->model_number);
+    printf("serial number:          %s\n", info->serial_number);
+    printf("battery type:           %s\n", info->battery_type);
+    printf("OEM info:               %s\n", info->oem_info);
+}
+#endif /*RUN_STANDALONE*/
+
+void write_ulong_lsb_first(char *temp_val, unsigned long val)
+{
+    snprintf(temp_val, 9, "%02x%02x%02x%02x", (unsigned int)val & 0xff, 
+    (unsigned int)(val & 0xff00) >> 8, (unsigned int)(val & 0xff0000) >> 16, 
+    (unsigned int)(val & 0xff000000) >> 24);
+}
+
+void write_battery_info_to_xenstore(struct battery_info *info)
+{
+    char val[1024], string_info[256];
+
+    xs_mkdir(xs, XBT_NULL, "/pm");
+   
+    memset(val, 0, 1024);
+    memset(string_info, 0, 256);
+    /* write 9 dwords (so 9*4) + length of 4 strings + 4 null terminators */
+    snprintf(val, 3, "%02x", 
+             (unsigned int)(9*4 +
+                            strlen(info->model_number) +
+                            strlen(info->serial_number) +
+                            strlen(info->battery_type) +
+                            strlen(info->oem_info) + 4));
+    write_ulong_lsb_first(val+2, info->present);
+    write_ulong_lsb_first(val+10, info->design_capacity);
+    write_ulong_lsb_first(val+18, info->last_full_capacity);
+    write_ulong_lsb_first(val+26, info->battery_technology);
+    write_ulong_lsb_first(val+34, info->design_voltage);
+    write_ulong_lsb_first(val+42, info->design_capacity_warning);
+    write_ulong_lsb_first(val+50, info->design_capacity_low);
+    write_ulong_lsb_first(val+58, info->capacity_granularity_1);
+    write_ulong_lsb_first(val+66, info->capacity_granularity_2);
+
+    snprintf(string_info, 256, "%02x%s%02x%s%02x%s%02x%s", 
+             (unsigned int)strlen(info->model_number), info->model_number,
+             (unsigned int)strlen(info->serial_number), info->serial_number,
+             (unsigned int)strlen(info->battery_type), info->battery_type,
+             (unsigned int)strlen(info->oem_info), info->oem_info);
+    strncat(val+73, string_info, 1024);
+    xs_write(xs, XBT_NULL, "/pm/bif", 
+             val, 73+8+strlen(info->model_number)+strlen(info->serial_number)+
+             strlen(info->battery_type)+strlen(info->oem_info)+1);
+}
+
+int write_one_time_battery_info(void)
+{
+    DIR *dir;
+    int ret = 0;
+    struct battery_info info;
+    
+    dir = opendir(BATTERY_DIR_PATH);
+    if ( !dir )
+        return 0;
+
+    while ( get_next_battery_info_or_status(dir, BIF, (void *)&info) ) 
+    {
+#ifdef RUN_STANDALONE
+        print_battery_info(&info);
+#endif
+        if ( info.present == YES ) 
+        {
+            write_battery_info_to_xenstore(&info);
+            ret = 1;
+            break; /* rethink this... */
+        }
+    }
+
+    closedir(dir);
+    return ret;
+}
+
+#ifdef RUN_STANDALONE
+void print_battery_status(struct battery_status *status)
+{
+    printf("present:                     %d\n", status->present);
+    printf("Battery state                %d\n", status->state);
+    printf("Battery present rate         %d\n", status->present_rate);
+    printf("Battery remining capacity    %d\n", status->remaining_capacity);
+    printf("Battery present voltage      %d\n", status->present_voltage);
+}
+#endif /*RUN_STANDALONE*/
+
+void write_battery_status_to_xenstore(struct battery_status *status)
+{
+    char val[35];
+
+    xs_mkdir(xs, XBT_NULL, "/pm");
+
+    memset(val, 0, 35);
+    snprintf(val, 3, "%02x", 16);
+    write_ulong_lsb_first(val+2, status->state);
+    write_ulong_lsb_first(val+10, status->present_rate);
+    write_ulong_lsb_first(val+18, status->remaining_capacity);
+    write_ulong_lsb_first(val+26, status->present_voltage);
+
+    xs_write(xs, XBT_NULL, "/pm/bst", val, 35);
+}
+
+int wait_for_and_update_battery_status_request(void)
+{
+    DIR *dir;
+    int ret = 0;
+    unsigned int count;
+    struct battery_status status;
+
+    while ( true )
+    {
+        /* KN:@TODO - It is rather inefficient to not cache the file handle.
+         *  Switch to caching file handle. 
+         */
+        dir = opendir(BATTERY_DIR_PATH);
+        if ( !dir )
+            return 0;
+
+        while ( get_next_battery_info_or_status(dir, BST, (void *)&status) ) 
+        {
+#ifdef RUN_STANDALONE
+            print_battery_status(&status);
+#endif
+            if ( status.present == YES ) 
+            {
+                write_battery_status_to_xenstore(&status);
+                ret = 1;
+                /* rethink this; though I have never seen, there might be
+                 * systems out there with more than one battery device 
+                 * present
+                 */
+                break;
+            }
+        }
+        closedir(dir);
+        xs_watch(xs, "/pm/events", "refreshbatterystatus");
+        xs_read_watch(xs, &count); 
+    }
+
+    return ret;
+}
+
+/* Borrowed daemonize from xenstored - Initially written by Stevens. */
+static void daemonize(void)
+{
+    pid_t pid;
+
+    if ( (pid = fork()) < 0 )
+        exit(1);
+
+    if ( pid != 0 )
+        exit(0);
+
+    setsid();
+
+    if ( (pid = fork()) < 0 )
+        exit(1);
+
+    if ( pid != 0 )
+        exit(0);
+
+    if ( chdir("/") == -1 )
+        exit(1);
+
+    umask(0);
+}
+
+int main(int argc, char *argv[])
+{
+#ifndef RUN_STANDALONE
+    daemonize();
+#endif
+    xs = (struct xs_handle *)xs_daemon_open();
+    if ( xs == NULL ) 
+        return -1;
+
+    if ( write_one_time_battery_info() == 0 ) 
+    {
+        xs_daemon_close(xs);
+        return -1;
+    }
+
+    wait_for_and_update_battery_status_request();
+    xs_daemon_close(xs);
+    return 0;
+}
+

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.