+}
+
diff --git a/tools/xenpmd/xenpmd.c b/tools/xenpmd/xenpmd.c
-index 28de744..b086092 100644
+index 28de744..58abdfa 100644
--- a/tools/xenpmd/xenpmd.c
+++ b/tools/xenpmd/xenpmd.c
-@@ -33,68 +33,10 @@
+@@ -33,68 +33,13 @@
* passed to the guest when appropriate battery ports are read/written to.
*/
+
+struct xs_handle *xs;
+static pthread_t worker_thread;
++static unsigned long battery_warning_capacity = 0;
++static unsigned long battery_low_capacity = 0;
++static enum BATTERY_LEVEL current_battery_level = NORMAL;
FILE *get_next_battery_file(DIR *battery_dir,
enum BATTERY_INFO_TYPE battery_info_type)
-@@ -218,11 +160,19 @@ void set_attribute_battery_status(char *attrib_name,
+@@ -135,13 +80,15 @@ void set_attribute_battery_info(char *attrib_name,
+
+ if ( strstr(attrib_name, "design capacity warning") )
+ {
+- info->design_capacity_warning = strtoull(attrib_value, NULL, 10);
++ battery_warning_capacity = 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);
++ battery_low_capacity = info->design_capacity_low =
++ strtoull(attrib_value, NULL, 10);
+ return;
+ }
+
+@@ -218,11 +165,19 @@ void set_attribute_battery_status(char *attrib_name,
{
if ( strstr(attrib_name, "charging state") )
{
return;
}
-@@ -292,11 +242,12 @@ int get_next_battery_info_or_status(DIR *battery_dir,
+@@ -292,11 +247,12 @@ int get_next_battery_info_or_status(DIR *battery_dir,
void *info_or_status)
{
FILE *file;
if (type == BIF)
memset(info_or_status, 0, sizeof(struct battery_info));
else
-@@ -306,31 +257,34 @@ int get_next_battery_info_or_status(DIR *battery_dir,
+@@ -306,31 +262,34 @@ int get_next_battery_info_or_status(DIR *battery_dir,
if ( !file )
return 0;
void write_ulong_lsb_first(char *temp_val, unsigned long val)
{
-@@ -370,7 +324,7 @@ void write_battery_info_to_xenstore(struct battery_info *info)
+@@ -370,7 +329,7 @@ void write_battery_info_to_xenstore(struct battery_info *info)
(unsigned int)strlen(info->battery_type), info->battery_type,
(unsigned int)strlen(info->oem_info), info->oem_info);
strncat(val+73, string_info, 1024-73-1);
val, 73+8+strlen(info->model_number)+strlen(info->serial_number)+
strlen(info->battery_type)+strlen(info->oem_info)+1);
}
-@@ -383,16 +337,21 @@ int write_one_time_battery_info(void)
+@@ -383,16 +342,21 @@ int write_one_time_battery_info(void)
dir = opendir(BATTERY_DIR_PATH);
if ( !dir )
ret = 1;
break; /* rethink this... */
}
-@@ -402,16 +361,17 @@ int write_one_time_battery_info(void)
+@@ -402,16 +366,35 @@ int write_one_time_battery_info(void)
return ret;
}
+ xenpmd_log(LOG_DEBUG, "Battery remining capacity %d\n",
+ (int) status->remaining_capacity);
+ xenpmd_log(LOG_DEBUG, "Battery present voltage %d\n", (int) status->present_voltage);
++}
++#endif /*XENPMD_DEBUG*/
++
++void adjust_guest_battery_level(struct battery_status *status)
++{
++ current_battery_level = NORMAL;
++ if ( battery_warning_capacity >= status->remaining_capacity - VIRTUAL_BATTERY_THRESHOLD_DELTA )
++ {
++ status->remaining_capacity-= VIRTUAL_BATTERY_THRESHOLD_DELTA;
++ if ( !(status->state & 0x2) ) /* not charging */
++ {
++ if ( status->remaining_capacity <= VIRTUAL_BATTERY_THRESHOLD_DELTA )
++ current_battery_level = CRITICAL;
++ else if ( status->remaining_capacity <= battery_low_capacity )
++ current_battery_level = LOW;
++ else
++ current_battery_level = WARNING;
++ }
++ }
}
-#endif /*RUN_STANDALONE*/
-+#endif /*XENPMD_DEBUG*/
void write_battery_status_to_xenstore(struct battery_status *status)
{
-@@ -426,56 +386,79 @@ void write_battery_status_to_xenstore(struct battery_status *status)
+@@ -426,56 +409,86 @@ void write_battery_status_to_xenstore(struct battery_status *status)
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);
+ xs_write(xs, XBT_NULL, XS_BST, val, 35);
++ if ( current_battery_level != NORMAL )
++ {
++ sprintf(val, "%d", current_battery_level);
++ xs_write(xs, XBT_NULL, XS_BATTERY_LEVEL_NOTIFICATION, val, strlen(val));
++ xenpmd_log(LOG_ALERT, "Battery level below normal - %d!\n", current_battery_level);
++ }
+#ifdef XENPMD_DEBUG
+ xenpmd_log(LOG_DEBUG, "Updated battery information in xenstore\n");
+#endif
- }
+ if ( status.present == YES )
+ {
++ adjust_guest_battery_level(&status);
+ write_battery_status_to_xenstore(&status);
+ /* rethink this; though I have never seen, there might be
+ * systems out there with more than one battery device
if ( pid != 0 )
exit(0);
-@@ -483,34 +466,75 @@ static void daemonize(void)
+@@ -483,34 +496,75 @@ static void daemonize(void)
setsid();
if ( (pid = fork()) < 0 )
+}
diff --git a/tools/xenpmd/xenpmd.h b/tools/xenpmd/xenpmd.h
new file mode 100644
-index 0000000..b3dddac
+index 0000000..3cda66d
--- /dev/null
+++ b/tools/xenpmd/xenpmd.h
-@@ -0,0 +1,130 @@
+@@ -0,0 +1,140 @@
+/*
+ * xenpmd.h
+ *
+ RECHARGEABLE
+};
+
++enum BATTERY_LEVEL {
++ NORMAL,
++ WARNING,
++ LOW,
++ CRITICAL
++};
++
+struct battery_info {
+ enum BATTERY_PRESENT present;
+ unsigned long design_capacity;
+#define XS_AC_ADAPTER_STATE_PATH "/pm/ac_adapter"
+#define XS_LID_STATE_PATH "/pm/lid_state"
+
++#define XS_BATTERY_LEVEL_NOTIFICATION "/pm/events/batterylevelnotification"
+#define XS_AC_ADAPTER_EVENT_PATH "/pm/events/acadapterstatechanged"
+#define XS_LID_EVENT_PATH "/pm/events/lidstatechanged"
+#define XS_PBTN_EVENT_PATH "/pm/events/powerbuttonpressed"
+#define XS_SBTN_EVENT_PATH "/pm/events/sleepbuttonpressed"
+
++#define VIRTUAL_BATTERY_THRESHOLD_DELTA 10
++
+#ifndef RUN_STANDALONE
+ #define xenpmd_log(priority, format, p...) syslog(priority, format, ##p)
+#else