ia64/xen-unstable

view tools/xenpmd/xenpmd.c @ 19835:edfdeb150f27

Fix buildsystem to detect udev > version 124

udev removed the udevinfo symlink from versions higher than 123 and
xen's build-system could not detect if udev is in place and has the
required version.

Signed-off-by: Marc-A. Dahlhaus <mad@wol.de>
author Keir Fraser <keir.fraser@citrix.com>
date Thu Jun 25 13:02:37 2009 +0100 (2009-06-25)
parents 045f70d1acdb
children
line source
1 /*
2 * xenpmd.c
3 *
4 * xen power management daemon - Facilitates power management
5 * functionality within xen guests.
6 *
7 * Copyright (c) 2008 Kamala Narasimhan
8 * Copyright (c) 2008 Citrix Systems, Inc.
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 */
25 /* Xen extended power management support provides HVM guest power management
26 * features beyond S3, S4, S5. For example, it helps expose system level
27 * battery status and battery meter information and in future will be extended
28 * to include more power management support. This extended power management
29 * support is enabled by setting xen_extended_power_mgmt to 1 or 2 in the HVM
30 * config file. When set to 2, non-pass through mode is enabled which heavily
31 * relies on this power management daemon to glean battery information from
32 * dom0 and store it xenstore which would then be queries and used by qemu and
33 * passed to the guest when appropriate battery ports are read/written to.
34 */
36 #include <stdio.h>
37 #include <stdarg.h>
38 #include <string.h>
39 #include <stdlib.h>
40 #include <dirent.h>
41 #include <unistd.h>
42 #include <sys/stat.h>
43 #include <xs.h>
45 /* #define RUN_STANDALONE */
46 #define RUN_IN_SIMULATE_MODE
48 enum BATTERY_INFO_TYPE {
49 BIF,
50 BST
51 };
53 enum BATTERY_PRESENT {
54 NO,
55 YES
56 };
58 enum BATTERY_TECHNOLOGY {
59 NON_RECHARGEABLE,
60 RECHARGEABLE
61 };
63 struct battery_info {
64 enum BATTERY_PRESENT present;
65 unsigned long design_capacity;
66 unsigned long last_full_capacity;
67 enum BATTERY_TECHNOLOGY battery_technology;
68 unsigned long design_voltage;
69 unsigned long design_capacity_warning;
70 unsigned long design_capacity_low;
71 unsigned long capacity_granularity_1;
72 unsigned long capacity_granularity_2;
73 char model_number[32];
74 char serial_number[32];
75 char battery_type[32];
76 char oem_info[32];
77 };
79 struct battery_status {
80 enum BATTERY_PRESENT present;
81 unsigned long state;
82 unsigned long present_rate;
83 unsigned long remaining_capacity;
84 unsigned long present_voltage;
85 };
87 static struct xs_handle *xs;
89 #ifdef RUN_IN_SIMULATE_MODE
90 #define BATTERY_DIR_PATH "/tmp/battery"
91 #define BATTERY_INFO_FILE_PATH "/tmp/battery/%s/info"
92 #define BATTERY_STATE_FILE_PATH "/tmp/battery/%s/state"
93 #else
94 #define BATTERY_DIR_PATH "/proc/acpi/battery"
95 #define BATTERY_INFO_FILE_PATH "/proc/acpi/battery/%s/info"
96 #define BATTERY_STATE_FILE_PATH "/proc/acpi/battery/%s/state"
97 #endif
99 FILE *get_next_battery_file(DIR *battery_dir,
100 enum BATTERY_INFO_TYPE battery_info_type)
101 {
102 FILE *file = 0;
103 struct dirent *dir_entries;
104 char file_name[32];
106 do
107 {
108 dir_entries = readdir(battery_dir);
109 if ( !dir_entries )
110 return 0;
111 if ( strlen(dir_entries->d_name) < 4 )
112 continue;
113 if ( battery_info_type == BIF )
114 snprintf(file_name, 32, BATTERY_INFO_FILE_PATH,
115 dir_entries->d_name);
116 else
117 snprintf(file_name, 32, BATTERY_STATE_FILE_PATH,
118 dir_entries->d_name);
119 file = fopen(file_name, "r");
120 } while ( !file );
122 return file;
123 }
125 void set_attribute_battery_info(char *attrib_name,
126 char *attrib_value,
127 struct battery_info *info)
128 {
129 if ( strstr(attrib_name, "present") )
130 {
131 if ( strstr(attrib_value, "yes") )
132 info->present = YES;
133 return;
134 }
136 if ( strstr(attrib_name, "design capacity warning") )
137 {
138 info->design_capacity_warning = strtoull(attrib_value, NULL, 10);
139 return;
140 }
142 if ( strstr(attrib_name, "design capacity low") )
143 {
144 info->design_capacity_low = strtoull(attrib_value, NULL, 10);
145 return;
146 }
148 if ( strstr(attrib_name, "design capacity") )
149 {
150 info->design_capacity = strtoull(attrib_value, NULL, 10);
151 return;
152 }
154 if ( strstr(attrib_name, "last full capacity") )
155 {
156 info->last_full_capacity = strtoull(attrib_value, NULL, 10);
157 return;
158 }
160 if ( strstr(attrib_name, "design voltage") )
161 {
162 info->design_voltage = strtoull(attrib_value, NULL, 10);
163 return;
164 }
166 if ( strstr(attrib_name, "capacity granularity 1") )
167 {
168 info->capacity_granularity_1 = strtoull(attrib_value, NULL, 10);
169 return;
170 }
172 if ( strstr(attrib_name, "capacity granularity 2") )
173 {
174 info->capacity_granularity_2 = strtoull(attrib_value, NULL, 10);
175 return;
176 }
178 if ( strstr(attrib_name, "battery technology") )
179 {
180 if ( strncmp(attrib_value, "rechargeable",
181 strlen("rechargeable")) == 0 )
182 info->battery_technology = RECHARGEABLE;
183 else
184 info->battery_technology = NON_RECHARGEABLE;
185 return;
186 }
188 if ( strstr(attrib_name, "model number") )
189 {
190 strncpy(info->model_number, attrib_value, 32);
191 return;
192 }
194 if ( strstr(attrib_name, "serial number") )
195 {
196 strncpy(info->serial_number, attrib_value, 32);
197 return;
198 }
200 if ( strstr(attrib_name, "battery type") )
201 {
202 strncpy(info->battery_type, attrib_value, 32);
203 return;
204 }
206 if ( strstr(attrib_name, "OEM info") )
207 {
208 strncpy(info->oem_info, attrib_value, 32);
209 return;
210 }
212 return;
213 }
215 void set_attribute_battery_status(char *attrib_name,
216 char *attrib_value,
217 struct battery_status *status)
218 {
219 if ( strstr(attrib_name, "charging state") )
220 {
221 /* Check this, below is half baked */
222 if ( strstr(attrib_value, "charged") )
223 status->state = 0;
224 else
225 status->state = 1;
226 return;
227 }
229 if ( strstr(attrib_name, "present rate") )
230 {
231 status->present_rate = strtoull(attrib_value, NULL, 10);
232 return;
233 }
235 if ( strstr(attrib_name, "remaining capacity") )
236 {
237 status->remaining_capacity = strtoull(attrib_value, NULL, 10);
238 return;
239 }
241 if ( strstr(attrib_name, "present voltage") )
242 {
243 status->present_voltage = strtoull(attrib_value, NULL, 10);
244 return;
245 }
247 if ( strstr(attrib_name, "present") )
248 {
249 if ( strstr(attrib_value, "yes") )
250 status->present = YES;
251 return;
252 }
253 }
255 void parse_battery_info_or_status(char *line_info,
256 enum BATTERY_INFO_TYPE type,
257 void *info_or_status)
258 {
259 char attrib_name[128];
260 char attrib_value[64];
261 char *delimiter;
262 unsigned long length;
264 length = strlen(line_info);
265 delimiter = (char *) strchr( line_info, ':');
266 if ( (!delimiter) || (delimiter == line_info) ||
267 (delimiter == line_info + length) )
268 return;
270 strncpy(attrib_name, line_info, delimiter-line_info);
271 while ( *(delimiter+1) == ' ' )
272 {
273 delimiter++;
274 if ( delimiter+1 == line_info + length)
275 return;
276 }
277 strncpy(attrib_value, delimiter+1,
278 (unsigned long)line_info + length -(unsigned long)delimiter);
280 if ( type == BIF )
281 set_attribute_battery_info(attrib_name, attrib_value,
282 (struct battery_info *)info_or_status);
283 else
284 set_attribute_battery_status(attrib_name, attrib_value,
285 (struct battery_status *)info_or_status);
287 return;
288 }
290 int get_next_battery_info_or_status(DIR *battery_dir,
291 enum BATTERY_INFO_TYPE type,
292 void *info_or_status)
293 {
294 FILE *file;
295 char line_info[256];
297 if ( !info_or_status )
298 return 0;
300 if (type == BIF)
301 memset(info_or_status, 0, sizeof(struct battery_info));
302 else
303 memset(info_or_status, 0, sizeof(struct battery_status));
305 file = get_next_battery_file(battery_dir, type);
306 if ( !file )
307 return 0;
309 while ( fgets(line_info, sizeof(line_info), file) != NULL )
310 parse_battery_info_or_status(line_info, type, info_or_status);
312 fclose(file);
313 return 1;
314 }
316 #ifdef RUN_STANDALONE
317 void print_battery_info(struct battery_info *info)
318 {
319 printf("present: %d\n", info->present);
320 printf("design capacity: %d\n", info->design_capacity);
321 printf("last full capacity: %d\n", info->last_full_capacity);
322 printf("battery technology: %d\n", info->battery_technology);
323 printf("design voltage: %d\n", info->design_voltage);
324 printf("design capacity warning:%d\n", info->design_capacity_warning);
325 printf("design capacity low: %d\n", info->design_capacity_low);
326 printf("capacity granularity 1: %d\n", info->capacity_granularity_1);
327 printf("capacity granularity 2: %d\n", info->capacity_granularity_2);
328 printf("model number: %s\n", info->model_number);
329 printf("serial number: %s\n", info->serial_number);
330 printf("battery type: %s\n", info->battery_type);
331 printf("OEM info: %s\n", info->oem_info);
332 }
333 #endif /*RUN_STANDALONE*/
335 void write_ulong_lsb_first(char *temp_val, unsigned long val)
336 {
337 snprintf(temp_val, 9, "%02x%02x%02x%02x", (unsigned int)val & 0xff,
338 (unsigned int)(val & 0xff00) >> 8, (unsigned int)(val & 0xff0000) >> 16,
339 (unsigned int)(val & 0xff000000) >> 24);
340 }
342 void write_battery_info_to_xenstore(struct battery_info *info)
343 {
344 char val[1024], string_info[256];
346 xs_mkdir(xs, XBT_NULL, "/pm");
348 memset(val, 0, 1024);
349 memset(string_info, 0, 256);
350 /* write 9 dwords (so 9*4) + length of 4 strings + 4 null terminators */
351 snprintf(val, 3, "%02x",
352 (unsigned int)(9*4 +
353 strlen(info->model_number) +
354 strlen(info->serial_number) +
355 strlen(info->battery_type) +
356 strlen(info->oem_info) + 4));
357 write_ulong_lsb_first(val+2, info->present);
358 write_ulong_lsb_first(val+10, info->design_capacity);
359 write_ulong_lsb_first(val+18, info->last_full_capacity);
360 write_ulong_lsb_first(val+26, info->battery_technology);
361 write_ulong_lsb_first(val+34, info->design_voltage);
362 write_ulong_lsb_first(val+42, info->design_capacity_warning);
363 write_ulong_lsb_first(val+50, info->design_capacity_low);
364 write_ulong_lsb_first(val+58, info->capacity_granularity_1);
365 write_ulong_lsb_first(val+66, info->capacity_granularity_2);
367 snprintf(string_info, 256, "%02x%s%02x%s%02x%s%02x%s",
368 (unsigned int)strlen(info->model_number), info->model_number,
369 (unsigned int)strlen(info->serial_number), info->serial_number,
370 (unsigned int)strlen(info->battery_type), info->battery_type,
371 (unsigned int)strlen(info->oem_info), info->oem_info);
372 strncat(val+73, string_info, 1024-73-1);
373 xs_write(xs, XBT_NULL, "/pm/bif",
374 val, 73+8+strlen(info->model_number)+strlen(info->serial_number)+
375 strlen(info->battery_type)+strlen(info->oem_info)+1);
376 }
378 int write_one_time_battery_info(void)
379 {
380 DIR *dir;
381 int ret = 0;
382 struct battery_info info;
384 dir = opendir(BATTERY_DIR_PATH);
385 if ( !dir )
386 return 0;
388 while ( get_next_battery_info_or_status(dir, BIF, (void *)&info) )
389 {
390 #ifdef RUN_STANDALONE
391 print_battery_info(&info);
392 #endif
393 if ( info.present == YES )
394 {
395 write_battery_info_to_xenstore(&info);
396 ret = 1;
397 break; /* rethink this... */
398 }
399 }
401 closedir(dir);
402 return ret;
403 }
405 #ifdef RUN_STANDALONE
406 void print_battery_status(struct battery_status *status)
407 {
408 printf("present: %d\n", status->present);
409 printf("Battery state %d\n", status->state);
410 printf("Battery present rate %d\n", status->present_rate);
411 printf("Battery remining capacity %d\n", status->remaining_capacity);
412 printf("Battery present voltage %d\n", status->present_voltage);
413 }
414 #endif /*RUN_STANDALONE*/
416 void write_battery_status_to_xenstore(struct battery_status *status)
417 {
418 char val[35];
420 xs_mkdir(xs, XBT_NULL, "/pm");
422 memset(val, 0, 35);
423 snprintf(val, 3, "%02x", 16);
424 write_ulong_lsb_first(val+2, status->state);
425 write_ulong_lsb_first(val+10, status->present_rate);
426 write_ulong_lsb_first(val+18, status->remaining_capacity);
427 write_ulong_lsb_first(val+26, status->present_voltage);
429 xs_write(xs, XBT_NULL, "/pm/bst", val, 35);
430 }
432 int wait_for_and_update_battery_status_request(void)
433 {
434 DIR *dir;
435 int ret = 0;
436 unsigned int count;
437 struct battery_status status;
439 while ( true )
440 {
441 /* KN:@TODO - It is rather inefficient to not cache the file handle.
442 * Switch to caching file handle.
443 */
444 dir = opendir(BATTERY_DIR_PATH);
445 if ( !dir )
446 return 0;
448 while ( get_next_battery_info_or_status(dir, BST, (void *)&status) )
449 {
450 #ifdef RUN_STANDALONE
451 print_battery_status(&status);
452 #endif
453 if ( status.present == YES )
454 {
455 write_battery_status_to_xenstore(&status);
456 ret = 1;
457 /* rethink this; though I have never seen, there might be
458 * systems out there with more than one battery device
459 * present
460 */
461 break;
462 }
463 }
464 closedir(dir);
465 xs_watch(xs, "/pm/events", "refreshbatterystatus");
466 xs_read_watch(xs, &count);
467 }
469 return ret;
470 }
472 /* Borrowed daemonize from xenstored - Initially written by Stevens. */
473 static void daemonize(void)
474 {
475 pid_t pid;
477 if ( (pid = fork()) < 0 )
478 exit(1);
480 if ( pid != 0 )
481 exit(0);
483 setsid();
485 if ( (pid = fork()) < 0 )
486 exit(1);
488 if ( pid != 0 )
489 exit(0);
491 if ( chdir("/") == -1 )
492 exit(1);
494 umask(0);
495 }
497 int main(int argc, char *argv[])
498 {
499 #ifndef RUN_STANDALONE
500 daemonize();
501 #endif
502 xs = (struct xs_handle *)xs_daemon_open();
503 if ( xs == NULL )
504 return -1;
506 if ( write_one_time_battery_info() == 0 )
507 {
508 xs_daemon_close(xs);
509 return -1;
510 }
512 wait_for_and_update_battery_status_request();
513 xs_daemon_close(xs);
514 return 0;
515 }