ia64/linux-2.6.18-xen.hg

annotate drivers/acpi/battery.c @ 897:329ea0ccb344

balloon: try harder to balloon up under memory pressure.

Currently if the balloon driver is unable to increase the guest's
reservation it assumes the failure was due to reaching its full
allocation, gives up on the ballooning operation and records the limit
it reached as the "hard limit". The driver will not try again until
the target is set again (even to the same value).

However it is possible that ballooning has in fact failed due to
memory pressure in the host and therefore it is desirable to keep
attempting to reach the target in case memory becomes available. The
most likely scenario is that some guests are ballooning down while
others are ballooning up and therefore there is temporary memory
pressure while things stabilise. You would not expect a well behaved
toolstack to ask a domain to balloon to more than its allocation nor
would you expect it to deliberately over-commit memory by setting
balloon targets which exceed the total host memory.

This patch drops the concept of a hard limit and causes the balloon
driver to retry increasing the reservation on a timer in the same
manner as when decreasing the reservation.

Also if we partially succeed in increasing the reservation
(i.e. receive less pages than we asked for) then we may as well keep
those pages rather than returning them to Xen.

Signed-off-by: Ian Campbell <ian.campbell@citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Fri Jun 05 14:01:20 2009 +0100 (2009-06-05)
parents 831230e53067
children
rev   line source
ian@0 1 /*
ian@0 2 * acpi_battery.c - ACPI Battery Driver ($Revision: 37 $)
ian@0 3 *
ian@0 4 * Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
ian@0 5 * Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
ian@0 6 *
ian@0 7 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ian@0 8 *
ian@0 9 * This program is free software; you can redistribute it and/or modify
ian@0 10 * it under the terms of the GNU General Public License as published by
ian@0 11 * the Free Software Foundation; either version 2 of the License, or (at
ian@0 12 * your option) any later version.
ian@0 13 *
ian@0 14 * This program is distributed in the hope that it will be useful, but
ian@0 15 * WITHOUT ANY WARRANTY; without even the implied warranty of
ian@0 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
ian@0 17 * General Public License for more details.
ian@0 18 *
ian@0 19 * You should have received a copy of the GNU General Public License along
ian@0 20 * with this program; if not, write to the Free Software Foundation, Inc.,
ian@0 21 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
ian@0 22 *
ian@0 23 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ian@0 24 */
ian@0 25
ian@0 26 #include <linux/kernel.h>
ian@0 27 #include <linux/module.h>
ian@0 28 #include <linux/init.h>
ian@0 29 #include <linux/types.h>
ian@0 30 #include <linux/proc_fs.h>
ian@0 31 #include <linux/seq_file.h>
ian@0 32 #include <asm/uaccess.h>
ian@0 33
ian@0 34 #include <acpi/acpi_bus.h>
ian@0 35 #include <acpi/acpi_drivers.h>
ian@0 36
ian@0 37 #define ACPI_BATTERY_VALUE_UNKNOWN 0xFFFFFFFF
ian@0 38
ian@0 39 #define ACPI_BATTERY_FORMAT_BIF "NNNNNNNNNSSSS"
ian@0 40 #define ACPI_BATTERY_FORMAT_BST "NNNN"
ian@0 41
ian@0 42 #define ACPI_BATTERY_COMPONENT 0x00040000
ian@0 43 #define ACPI_BATTERY_CLASS "battery"
ian@0 44 #define ACPI_BATTERY_HID "PNP0C0A"
ian@0 45 #define ACPI_BATTERY_DRIVER_NAME "ACPI Battery Driver"
ian@0 46 #define ACPI_BATTERY_DEVICE_NAME "Battery"
ian@0 47 #define ACPI_BATTERY_FILE_INFO "info"
ian@0 48 #define ACPI_BATTERY_FILE_STATUS "state"
ian@0 49 #define ACPI_BATTERY_FILE_ALARM "alarm"
ian@0 50 #define ACPI_BATTERY_NOTIFY_STATUS 0x80
ian@0 51 #define ACPI_BATTERY_NOTIFY_INFO 0x81
ian@0 52 #define ACPI_BATTERY_UNITS_WATTS "mW"
ian@0 53 #define ACPI_BATTERY_UNITS_AMPS "mA"
ian@0 54
ian@0 55 #define _COMPONENT ACPI_BATTERY_COMPONENT
ian@0 56 ACPI_MODULE_NAME("acpi_battery")
ian@0 57
ian@0 58 MODULE_AUTHOR("Paul Diefenbaugh");
ian@0 59 MODULE_DESCRIPTION(ACPI_BATTERY_DRIVER_NAME);
ian@0 60 MODULE_LICENSE("GPL");
ian@0 61
ian@0 62 extern struct proc_dir_entry *acpi_lock_battery_dir(void);
ian@0 63 extern void *acpi_unlock_battery_dir(struct proc_dir_entry *acpi_battery_dir);
ian@0 64
ian@0 65 static int acpi_battery_add(struct acpi_device *device);
ian@0 66 static int acpi_battery_remove(struct acpi_device *device, int type);
ian@0 67
ian@0 68 static struct acpi_driver acpi_battery_driver = {
ian@0 69 .name = ACPI_BATTERY_DRIVER_NAME,
ian@0 70 .class = ACPI_BATTERY_CLASS,
ian@0 71 .ids = ACPI_BATTERY_HID,
ian@0 72 .ops = {
ian@0 73 .add = acpi_battery_add,
ian@0 74 .remove = acpi_battery_remove,
ian@0 75 },
ian@0 76 };
ian@0 77
ian@0 78 struct acpi_battery_status {
ian@0 79 acpi_integer state;
ian@0 80 acpi_integer present_rate;
ian@0 81 acpi_integer remaining_capacity;
ian@0 82 acpi_integer present_voltage;
ian@0 83 };
ian@0 84
ian@0 85 struct acpi_battery_info {
ian@0 86 acpi_integer power_unit;
ian@0 87 acpi_integer design_capacity;
ian@0 88 acpi_integer last_full_capacity;
ian@0 89 acpi_integer battery_technology;
ian@0 90 acpi_integer design_voltage;
ian@0 91 acpi_integer design_capacity_warning;
ian@0 92 acpi_integer design_capacity_low;
ian@0 93 acpi_integer battery_capacity_granularity_1;
ian@0 94 acpi_integer battery_capacity_granularity_2;
ian@0 95 acpi_string model_number;
ian@0 96 acpi_string serial_number;
ian@0 97 acpi_string battery_type;
ian@0 98 acpi_string oem_info;
ian@0 99 };
ian@0 100
ian@0 101 struct acpi_battery_flags {
ian@0 102 u8 present:1; /* Bay occupied? */
ian@0 103 u8 power_unit:1; /* 0=watts, 1=apms */
ian@0 104 u8 alarm:1; /* _BTP present? */
ian@0 105 u8 reserved:5;
ian@0 106 };
ian@0 107
ian@0 108 struct acpi_battery_trips {
ian@0 109 unsigned long warning;
ian@0 110 unsigned long low;
ian@0 111 };
ian@0 112
ian@0 113 struct acpi_battery {
ian@0 114 struct acpi_device * device;
ian@0 115 struct acpi_battery_flags flags;
ian@0 116 struct acpi_battery_trips trips;
ian@0 117 unsigned long alarm;
ian@0 118 struct acpi_battery_info *info;
ian@0 119 };
ian@0 120
ian@0 121 /* --------------------------------------------------------------------------
ian@0 122 Battery Management
ian@0 123 -------------------------------------------------------------------------- */
ian@0 124
ian@0 125 static int
ian@0 126 acpi_battery_get_info(struct acpi_battery *battery,
ian@0 127 struct acpi_battery_info **bif)
ian@0 128 {
ian@0 129 int result = 0;
ian@0 130 acpi_status status = 0;
ian@0 131 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
ian@0 132 struct acpi_buffer format = { sizeof(ACPI_BATTERY_FORMAT_BIF),
ian@0 133 ACPI_BATTERY_FORMAT_BIF
ian@0 134 };
ian@0 135 struct acpi_buffer data = { 0, NULL };
ian@0 136 union acpi_object *package = NULL;
ian@0 137
ian@0 138
ian@0 139 if (!battery || !bif)
ian@0 140 return -EINVAL;
ian@0 141
ian@0 142 /* Evalute _BIF */
ian@0 143
ian@0 144 status = acpi_evaluate_object(battery->device->handle, "_BIF", NULL, &buffer);
ian@0 145 if (ACPI_FAILURE(status)) {
ian@0 146 ACPI_EXCEPTION((AE_INFO, status, "Evaluating _BIF"));
ian@0 147 return -ENODEV;
ian@0 148 }
ian@0 149
ian@0 150 package = (union acpi_object *)buffer.pointer;
ian@0 151
ian@0 152 /* Extract Package Data */
ian@0 153
ian@0 154 status = acpi_extract_package(package, &format, &data);
ian@0 155 if (status != AE_BUFFER_OVERFLOW) {
ian@0 156 ACPI_EXCEPTION((AE_INFO, status, "Extracting _BIF"));
ian@0 157 result = -ENODEV;
ian@0 158 goto end;
ian@0 159 }
ian@0 160
ian@0 161 data.pointer = kmalloc(data.length, GFP_KERNEL);
ian@0 162 if (!data.pointer) {
ian@0 163 result = -ENOMEM;
ian@0 164 goto end;
ian@0 165 }
ian@0 166 memset(data.pointer, 0, data.length);
ian@0 167
ian@0 168 status = acpi_extract_package(package, &format, &data);
ian@0 169 if (ACPI_FAILURE(status)) {
ian@0 170 ACPI_EXCEPTION((AE_INFO, status, "Extracting _BIF"));
ian@0 171 kfree(data.pointer);
ian@0 172 result = -ENODEV;
ian@0 173 goto end;
ian@0 174 }
ian@0 175
ian@0 176 end:
ian@0 177 kfree(buffer.pointer);
ian@0 178
ian@0 179 if (!result)
ian@0 180 (*bif) = (struct acpi_battery_info *)data.pointer;
ian@0 181
ian@0 182 return result;
ian@0 183 }
ian@0 184
ian@0 185 static int
ian@0 186 acpi_battery_get_status(struct acpi_battery *battery,
ian@0 187 struct acpi_battery_status **bst)
ian@0 188 {
ian@0 189 int result = 0;
ian@0 190 acpi_status status = 0;
ian@0 191 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
ian@0 192 struct acpi_buffer format = { sizeof(ACPI_BATTERY_FORMAT_BST),
ian@0 193 ACPI_BATTERY_FORMAT_BST
ian@0 194 };
ian@0 195 struct acpi_buffer data = { 0, NULL };
ian@0 196 union acpi_object *package = NULL;
ian@0 197
ian@0 198
ian@0 199 if (!battery || !bst)
ian@0 200 return -EINVAL;
ian@0 201
ian@0 202 /* Evalute _BST */
ian@0 203
ian@0 204 status = acpi_evaluate_object(battery->device->handle, "_BST", NULL, &buffer);
ian@0 205 if (ACPI_FAILURE(status)) {
ian@0 206 ACPI_EXCEPTION((AE_INFO, status, "Evaluating _BST"));
ian@0 207 return -ENODEV;
ian@0 208 }
ian@0 209
ian@0 210 package = (union acpi_object *)buffer.pointer;
ian@0 211
ian@0 212 /* Extract Package Data */
ian@0 213
ian@0 214 status = acpi_extract_package(package, &format, &data);
ian@0 215 if (status != AE_BUFFER_OVERFLOW) {
ian@0 216 ACPI_EXCEPTION((AE_INFO, status, "Extracting _BST"));
ian@0 217 result = -ENODEV;
ian@0 218 goto end;
ian@0 219 }
ian@0 220
ian@0 221 data.pointer = kmalloc(data.length, GFP_KERNEL);
ian@0 222 if (!data.pointer) {
ian@0 223 result = -ENOMEM;
ian@0 224 goto end;
ian@0 225 }
ian@0 226 memset(data.pointer, 0, data.length);
ian@0 227
ian@0 228 status = acpi_extract_package(package, &format, &data);
ian@0 229 if (ACPI_FAILURE(status)) {
ian@0 230 ACPI_EXCEPTION((AE_INFO, status, "Extracting _BST"));
ian@0 231 kfree(data.pointer);
ian@0 232 result = -ENODEV;
ian@0 233 goto end;
ian@0 234 }
ian@0 235
ian@0 236 end:
ian@0 237 kfree(buffer.pointer);
ian@0 238
ian@0 239 if (!result)
ian@0 240 (*bst) = (struct acpi_battery_status *)data.pointer;
ian@0 241
ian@0 242 return result;
ian@0 243 }
ian@0 244
ian@0 245 static int
ian@0 246 acpi_battery_set_alarm(struct acpi_battery *battery, unsigned long alarm)
ian@0 247 {
ian@0 248 acpi_status status = 0;
ian@0 249 union acpi_object arg0 = { ACPI_TYPE_INTEGER };
ian@0 250 struct acpi_object_list arg_list = { 1, &arg0 };
ian@0 251
ian@0 252
ian@0 253 if (!battery)
ian@0 254 return -EINVAL;
ian@0 255
ian@0 256 if (!battery->flags.alarm)
ian@0 257 return -ENODEV;
ian@0 258
ian@0 259 arg0.integer.value = alarm;
ian@0 260
ian@0 261 status = acpi_evaluate_object(battery->device->handle, "_BTP", &arg_list, NULL);
ian@0 262 if (ACPI_FAILURE(status))
ian@0 263 return -ENODEV;
ian@0 264
ian@0 265 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Alarm set to %d\n", (u32) alarm));
ian@0 266
ian@0 267 battery->alarm = alarm;
ian@0 268
ian@0 269 return 0;
ian@0 270 }
ian@0 271
ian@0 272 static int acpi_battery_check(struct acpi_battery *battery)
ian@0 273 {
ian@0 274 int result = 0;
ian@0 275 acpi_status status = AE_OK;
ian@0 276 acpi_handle handle = NULL;
ian@0 277 struct acpi_device *device = NULL;
ian@0 278 struct acpi_battery_info *bif = NULL;
ian@0 279
ian@0 280
ian@0 281 if (!battery)
ian@0 282 return -EINVAL;
ian@0 283
ian@0 284 device = battery->device;
ian@0 285
ian@0 286 result = acpi_bus_get_status(device);
ian@0 287 if (result)
ian@0 288 return result;
ian@0 289
ian@0 290 /* Insertion? */
ian@0 291
ian@0 292 if (!battery->flags.present && device->status.battery_present) {
ian@0 293
ian@0 294 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Battery inserted\n"));
ian@0 295
ian@0 296 /* Evalute _BIF to get certain static information */
ian@0 297
ian@0 298 result = acpi_battery_get_info(battery, &bif);
ian@0 299 if (result)
ian@0 300 return result;
ian@0 301
ian@0 302 battery->flags.power_unit = bif->power_unit;
ian@0 303 battery->trips.warning = bif->design_capacity_warning;
ian@0 304 battery->trips.low = bif->design_capacity_low;
ian@0 305 kfree(bif);
ian@0 306
ian@0 307 /* See if alarms are supported, and if so, set default */
ian@0 308
ian@0 309 status = acpi_get_handle(battery->device->handle, "_BTP", &handle);
ian@0 310 if (ACPI_SUCCESS(status)) {
ian@0 311 battery->flags.alarm = 1;
ian@0 312 acpi_battery_set_alarm(battery, battery->trips.warning);
ian@0 313 }
ian@0 314 }
ian@0 315
ian@0 316 /* Removal? */
ian@0 317
ian@0 318 else if (battery->flags.present && !device->status.battery_present) {
ian@0 319 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Battery removed\n"));
ian@0 320 }
ian@0 321
ian@0 322 battery->flags.present = device->status.battery_present;
ian@0 323
ian@0 324 return result;
ian@0 325 }
ian@0 326
ian@0 327 /* --------------------------------------------------------------------------
ian@0 328 FS Interface (/proc)
ian@0 329 -------------------------------------------------------------------------- */
ian@0 330
ian@0 331 static struct proc_dir_entry *acpi_battery_dir;
ian@0 332 static int acpi_battery_read_info(struct seq_file *seq, void *offset)
ian@0 333 {
ian@0 334 int result = 0;
ian@0 335 struct acpi_battery *battery = (struct acpi_battery *)seq->private;
ian@0 336 struct acpi_battery_info *bif = NULL;
ian@0 337 char *units = "?";
ian@0 338
ian@0 339
ian@0 340 if (!battery)
ian@0 341 goto end;
ian@0 342
ian@0 343 if (battery->flags.present)
ian@0 344 seq_printf(seq, "present: yes\n");
ian@0 345 else {
ian@0 346 seq_printf(seq, "present: no\n");
ian@0 347 goto end;
ian@0 348 }
ian@0 349
ian@0 350 /* Battery Info (_BIF) */
ian@0 351
ian@0 352 result = acpi_battery_get_info(battery, &bif);
ian@0 353 if (result || !bif) {
ian@0 354 seq_printf(seq, "ERROR: Unable to read battery information\n");
ian@0 355 goto end;
ian@0 356 }
ian@0 357
ian@0 358 units =
ian@0 359 bif->
ian@0 360 power_unit ? ACPI_BATTERY_UNITS_AMPS : ACPI_BATTERY_UNITS_WATTS;
ian@0 361
ian@0 362 if (bif->design_capacity == ACPI_BATTERY_VALUE_UNKNOWN)
ian@0 363 seq_printf(seq, "design capacity: unknown\n");
ian@0 364 else
ian@0 365 seq_printf(seq, "design capacity: %d %sh\n",
ian@0 366 (u32) bif->design_capacity, units);
ian@0 367
ian@0 368 if (bif->last_full_capacity == ACPI_BATTERY_VALUE_UNKNOWN)
ian@0 369 seq_printf(seq, "last full capacity: unknown\n");
ian@0 370 else
ian@0 371 seq_printf(seq, "last full capacity: %d %sh\n",
ian@0 372 (u32) bif->last_full_capacity, units);
ian@0 373
ian@0 374 switch ((u32) bif->battery_technology) {
ian@0 375 case 0:
ian@0 376 seq_printf(seq, "battery technology: non-rechargeable\n");
ian@0 377 break;
ian@0 378 case 1:
ian@0 379 seq_printf(seq, "battery technology: rechargeable\n");
ian@0 380 break;
ian@0 381 default:
ian@0 382 seq_printf(seq, "battery technology: unknown\n");
ian@0 383 break;
ian@0 384 }
ian@0 385
ian@0 386 if (bif->design_voltage == ACPI_BATTERY_VALUE_UNKNOWN)
ian@0 387 seq_printf(seq, "design voltage: unknown\n");
ian@0 388 else
ian@0 389 seq_printf(seq, "design voltage: %d mV\n",
ian@0 390 (u32) bif->design_voltage);
ian@0 391
ian@0 392 seq_printf(seq, "design capacity warning: %d %sh\n",
ian@0 393 (u32) bif->design_capacity_warning, units);
ian@0 394 seq_printf(seq, "design capacity low: %d %sh\n",
ian@0 395 (u32) bif->design_capacity_low, units);
ian@0 396 seq_printf(seq, "capacity granularity 1: %d %sh\n",
ian@0 397 (u32) bif->battery_capacity_granularity_1, units);
ian@0 398 seq_printf(seq, "capacity granularity 2: %d %sh\n",
ian@0 399 (u32) bif->battery_capacity_granularity_2, units);
ian@0 400 seq_printf(seq, "model number: %s\n", bif->model_number);
ian@0 401 seq_printf(seq, "serial number: %s\n", bif->serial_number);
ian@0 402 seq_printf(seq, "battery type: %s\n", bif->battery_type);
ian@0 403 seq_printf(seq, "OEM info: %s\n", bif->oem_info);
ian@0 404
ian@0 405 end:
ian@0 406 kfree(bif);
ian@0 407
ian@0 408 return 0;
ian@0 409 }
ian@0 410
ian@0 411 static int acpi_battery_info_open_fs(struct inode *inode, struct file *file)
ian@0 412 {
ian@0 413 return single_open(file, acpi_battery_read_info, PDE(inode)->data);
ian@0 414 }
ian@0 415
ian@0 416 static int acpi_battery_read_state(struct seq_file *seq, void *offset)
ian@0 417 {
ian@0 418 int result = 0;
ian@0 419 struct acpi_battery *battery = (struct acpi_battery *)seq->private;
ian@0 420 struct acpi_battery_status *bst = NULL;
ian@0 421 char *units = "?";
ian@0 422
ian@0 423
ian@0 424 if (!battery)
ian@0 425 goto end;
ian@0 426
ian@0 427 if (battery->flags.present)
ian@0 428 seq_printf(seq, "present: yes\n");
ian@0 429 else {
ian@0 430 seq_printf(seq, "present: no\n");
ian@0 431 goto end;
ian@0 432 }
ian@0 433
ian@0 434 /* Battery Units */
ian@0 435
ian@0 436 units =
ian@0 437 battery->flags.
ian@0 438 power_unit ? ACPI_BATTERY_UNITS_AMPS : ACPI_BATTERY_UNITS_WATTS;
ian@0 439
ian@0 440 /* Battery Status (_BST) */
ian@0 441
ian@0 442 result = acpi_battery_get_status(battery, &bst);
ian@0 443 if (result || !bst) {
ian@0 444 seq_printf(seq, "ERROR: Unable to read battery status\n");
ian@0 445 goto end;
ian@0 446 }
ian@0 447
ian@0 448 if (!(bst->state & 0x04))
ian@0 449 seq_printf(seq, "capacity state: ok\n");
ian@0 450 else
ian@0 451 seq_printf(seq, "capacity state: critical\n");
ian@0 452
ian@0 453 if ((bst->state & 0x01) && (bst->state & 0x02)) {
ian@0 454 seq_printf(seq,
ian@0 455 "charging state: charging/discharging\n");
ian@0 456 } else if (bst->state & 0x01)
ian@0 457 seq_printf(seq, "charging state: discharging\n");
ian@0 458 else if (bst->state & 0x02)
ian@0 459 seq_printf(seq, "charging state: charging\n");
ian@0 460 else {
ian@0 461 seq_printf(seq, "charging state: charged\n");
ian@0 462 }
ian@0 463
ian@0 464 if (bst->present_rate == ACPI_BATTERY_VALUE_UNKNOWN)
ian@0 465 seq_printf(seq, "present rate: unknown\n");
ian@0 466 else
ian@0 467 seq_printf(seq, "present rate: %d %s\n",
ian@0 468 (u32) bst->present_rate, units);
ian@0 469
ian@0 470 if (bst->remaining_capacity == ACPI_BATTERY_VALUE_UNKNOWN)
ian@0 471 seq_printf(seq, "remaining capacity: unknown\n");
ian@0 472 else
ian@0 473 seq_printf(seq, "remaining capacity: %d %sh\n",
ian@0 474 (u32) bst->remaining_capacity, units);
ian@0 475
ian@0 476 if (bst->present_voltage == ACPI_BATTERY_VALUE_UNKNOWN)
ian@0 477 seq_printf(seq, "present voltage: unknown\n");
ian@0 478 else
ian@0 479 seq_printf(seq, "present voltage: %d mV\n",
ian@0 480 (u32) bst->present_voltage);
ian@0 481
ian@0 482 end:
ian@0 483 kfree(bst);
ian@0 484
ian@0 485 return 0;
ian@0 486 }
ian@0 487
ian@0 488 static int acpi_battery_state_open_fs(struct inode *inode, struct file *file)
ian@0 489 {
ian@0 490 return single_open(file, acpi_battery_read_state, PDE(inode)->data);
ian@0 491 }
ian@0 492
ian@0 493 static int acpi_battery_read_alarm(struct seq_file *seq, void *offset)
ian@0 494 {
ian@0 495 struct acpi_battery *battery = (struct acpi_battery *)seq->private;
ian@0 496 char *units = "?";
ian@0 497
ian@0 498
ian@0 499 if (!battery)
ian@0 500 goto end;
ian@0 501
ian@0 502 if (!battery->flags.present) {
ian@0 503 seq_printf(seq, "present: no\n");
ian@0 504 goto end;
ian@0 505 }
ian@0 506
ian@0 507 /* Battery Units */
ian@0 508
ian@0 509 units =
ian@0 510 battery->flags.
ian@0 511 power_unit ? ACPI_BATTERY_UNITS_AMPS : ACPI_BATTERY_UNITS_WATTS;
ian@0 512
ian@0 513 /* Battery Alarm */
ian@0 514
ian@0 515 seq_printf(seq, "alarm: ");
ian@0 516 if (!battery->alarm)
ian@0 517 seq_printf(seq, "unsupported\n");
ian@0 518 else
ian@0 519 seq_printf(seq, "%d %sh\n", (u32) battery->alarm, units);
ian@0 520
ian@0 521 end:
ian@0 522 return 0;
ian@0 523 }
ian@0 524
ian@0 525 static ssize_t
ian@0 526 acpi_battery_write_alarm(struct file *file,
ian@0 527 const char __user * buffer,
ian@0 528 size_t count, loff_t * ppos)
ian@0 529 {
ian@0 530 int result = 0;
ian@0 531 char alarm_string[12] = { '\0' };
ian@0 532 struct seq_file *m = (struct seq_file *)file->private_data;
ian@0 533 struct acpi_battery *battery = (struct acpi_battery *)m->private;
ian@0 534
ian@0 535
ian@0 536 if (!battery || (count > sizeof(alarm_string) - 1))
ian@0 537 return -EINVAL;
ian@0 538
ian@0 539 if (!battery->flags.present)
ian@0 540 return -ENODEV;
ian@0 541
ian@0 542 if (copy_from_user(alarm_string, buffer, count))
ian@0 543 return -EFAULT;
ian@0 544
ian@0 545 alarm_string[count] = '\0';
ian@0 546
ian@0 547 result = acpi_battery_set_alarm(battery,
ian@0 548 simple_strtoul(alarm_string, NULL, 0));
ian@0 549 if (result)
ian@0 550 return result;
ian@0 551
ian@0 552 return count;
ian@0 553 }
ian@0 554
ian@0 555 static int acpi_battery_alarm_open_fs(struct inode *inode, struct file *file)
ian@0 556 {
ian@0 557 return single_open(file, acpi_battery_read_alarm, PDE(inode)->data);
ian@0 558 }
ian@0 559
ian@0 560 static const struct file_operations acpi_battery_info_ops = {
ian@0 561 .open = acpi_battery_info_open_fs,
ian@0 562 .read = seq_read,
ian@0 563 .llseek = seq_lseek,
ian@0 564 .release = single_release,
ian@0 565 .owner = THIS_MODULE,
ian@0 566 };
ian@0 567
ian@0 568 static const struct file_operations acpi_battery_state_ops = {
ian@0 569 .open = acpi_battery_state_open_fs,
ian@0 570 .read = seq_read,
ian@0 571 .llseek = seq_lseek,
ian@0 572 .release = single_release,
ian@0 573 .owner = THIS_MODULE,
ian@0 574 };
ian@0 575
ian@0 576 static const struct file_operations acpi_battery_alarm_ops = {
ian@0 577 .open = acpi_battery_alarm_open_fs,
ian@0 578 .read = seq_read,
ian@0 579 .write = acpi_battery_write_alarm,
ian@0 580 .llseek = seq_lseek,
ian@0 581 .release = single_release,
ian@0 582 .owner = THIS_MODULE,
ian@0 583 };
ian@0 584
ian@0 585 static int acpi_battery_add_fs(struct acpi_device *device)
ian@0 586 {
ian@0 587 struct proc_dir_entry *entry = NULL;
ian@0 588
ian@0 589
ian@0 590 if (!acpi_device_dir(device)) {
ian@0 591 acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device),
ian@0 592 acpi_battery_dir);
ian@0 593 if (!acpi_device_dir(device))
ian@0 594 return -ENODEV;
ian@0 595 acpi_device_dir(device)->owner = THIS_MODULE;
ian@0 596 }
ian@0 597
ian@0 598 /* 'info' [R] */
ian@0 599 entry = create_proc_entry(ACPI_BATTERY_FILE_INFO,
ian@0 600 S_IRUGO, acpi_device_dir(device));
ian@0 601 if (!entry)
ian@0 602 return -ENODEV;
ian@0 603 else {
ian@0 604 entry->proc_fops = &acpi_battery_info_ops;
ian@0 605 entry->data = acpi_driver_data(device);
ian@0 606 entry->owner = THIS_MODULE;
ian@0 607 }
ian@0 608
ian@0 609 /* 'status' [R] */
ian@0 610 entry = create_proc_entry(ACPI_BATTERY_FILE_STATUS,
ian@0 611 S_IRUGO, acpi_device_dir(device));
ian@0 612 if (!entry)
ian@0 613 return -ENODEV;
ian@0 614 else {
ian@0 615 entry->proc_fops = &acpi_battery_state_ops;
ian@0 616 entry->data = acpi_driver_data(device);
ian@0 617 entry->owner = THIS_MODULE;
ian@0 618 }
ian@0 619
ian@0 620 /* 'alarm' [R/W] */
ian@0 621 entry = create_proc_entry(ACPI_BATTERY_FILE_ALARM,
ian@0 622 S_IFREG | S_IRUGO | S_IWUSR,
ian@0 623 acpi_device_dir(device));
ian@0 624 if (!entry)
ian@0 625 return -ENODEV;
ian@0 626 else {
ian@0 627 entry->proc_fops = &acpi_battery_alarm_ops;
ian@0 628 entry->data = acpi_driver_data(device);
ian@0 629 entry->owner = THIS_MODULE;
ian@0 630 }
ian@0 631
ian@0 632 return 0;
ian@0 633 }
ian@0 634
ian@0 635 static int acpi_battery_remove_fs(struct acpi_device *device)
ian@0 636 {
ian@0 637
ian@0 638 if (acpi_device_dir(device)) {
ian@0 639 remove_proc_entry(ACPI_BATTERY_FILE_ALARM,
ian@0 640 acpi_device_dir(device));
ian@0 641 remove_proc_entry(ACPI_BATTERY_FILE_STATUS,
ian@0 642 acpi_device_dir(device));
ian@0 643 remove_proc_entry(ACPI_BATTERY_FILE_INFO,
ian@0 644 acpi_device_dir(device));
ian@0 645
ian@0 646 remove_proc_entry(acpi_device_bid(device), acpi_battery_dir);
ian@0 647 acpi_device_dir(device) = NULL;
ian@0 648 }
ian@0 649
ian@0 650 return 0;
ian@0 651 }
ian@0 652
ian@0 653 /* --------------------------------------------------------------------------
ian@0 654 Driver Interface
ian@0 655 -------------------------------------------------------------------------- */
ian@0 656
ian@0 657 static void acpi_battery_notify(acpi_handle handle, u32 event, void *data)
ian@0 658 {
ian@0 659 struct acpi_battery *battery = (struct acpi_battery *)data;
ian@0 660 struct acpi_device *device = NULL;
ian@0 661
ian@0 662
ian@0 663 if (!battery)
ian@0 664 return;
ian@0 665
ian@0 666 device = battery->device;
ian@0 667
ian@0 668 switch (event) {
ian@0 669 case ACPI_BATTERY_NOTIFY_STATUS:
ian@0 670 case ACPI_BATTERY_NOTIFY_INFO:
ian@0 671 case ACPI_NOTIFY_BUS_CHECK:
ian@0 672 case ACPI_NOTIFY_DEVICE_CHECK:
ian@0 673 acpi_battery_check(battery);
ian@0 674 acpi_bus_generate_event(device, event, battery->flags.present);
ian@0 675 break;
ian@0 676 default:
ian@0 677 ACPI_DEBUG_PRINT((ACPI_DB_INFO,
ian@0 678 "Unsupported event [0x%x]\n", event));
ian@0 679 break;
ian@0 680 }
ian@0 681
ian@0 682 return;
ian@0 683 }
ian@0 684
ian@0 685 static int acpi_battery_add(struct acpi_device *device)
ian@0 686 {
ian@0 687 int result = 0;
ian@0 688 acpi_status status = 0;
ian@0 689 struct acpi_battery *battery = NULL;
ian@0 690
ian@0 691
ian@0 692 if (!device)
ian@0 693 return -EINVAL;
ian@0 694
ian@0 695 battery = kmalloc(sizeof(struct acpi_battery), GFP_KERNEL);
ian@0 696 if (!battery)
ian@0 697 return -ENOMEM;
ian@0 698 memset(battery, 0, sizeof(struct acpi_battery));
ian@0 699
ian@0 700 battery->device = device;
ian@0 701 strcpy(acpi_device_name(device), ACPI_BATTERY_DEVICE_NAME);
ian@0 702 strcpy(acpi_device_class(device), ACPI_BATTERY_CLASS);
ian@0 703 acpi_driver_data(device) = battery;
ian@0 704
ian@0 705 result = acpi_battery_check(battery);
ian@0 706 if (result)
ian@0 707 goto end;
ian@0 708
ian@0 709 result = acpi_battery_add_fs(device);
ian@0 710 if (result)
ian@0 711 goto end;
ian@0 712
ian@0 713 status = acpi_install_notify_handler(device->handle,
ian@0 714 ACPI_ALL_NOTIFY,
ian@0 715 acpi_battery_notify, battery);
ian@0 716 if (ACPI_FAILURE(status)) {
ian@0 717 result = -ENODEV;
ian@0 718 goto end;
ian@0 719 }
ian@0 720
ian@0 721 printk(KERN_INFO PREFIX "%s Slot [%s] (battery %s)\n",
ian@0 722 ACPI_BATTERY_DEVICE_NAME, acpi_device_bid(device),
ian@0 723 device->status.battery_present ? "present" : "absent");
ian@0 724
ian@0 725 end:
ian@0 726 if (result) {
ian@0 727 acpi_battery_remove_fs(device);
ian@0 728 kfree(battery);
ian@0 729 }
ian@0 730
ian@0 731 return result;
ian@0 732 }
ian@0 733
ian@0 734 static int acpi_battery_remove(struct acpi_device *device, int type)
ian@0 735 {
ian@0 736 acpi_status status = 0;
ian@0 737 struct acpi_battery *battery = NULL;
ian@0 738
ian@0 739
ian@0 740 if (!device || !acpi_driver_data(device))
ian@0 741 return -EINVAL;
ian@0 742
ian@0 743 battery = (struct acpi_battery *)acpi_driver_data(device);
ian@0 744
ian@0 745 status = acpi_remove_notify_handler(device->handle,
ian@0 746 ACPI_ALL_NOTIFY,
ian@0 747 acpi_battery_notify);
ian@0 748
ian@0 749 acpi_battery_remove_fs(device);
ian@0 750
ian@0 751 kfree(battery);
ian@0 752
ian@0 753 return 0;
ian@0 754 }
ian@0 755
ian@0 756 static int __init acpi_battery_init(void)
ian@0 757 {
ian@0 758 int result;
ian@0 759
ian@0 760 if (acpi_disabled)
ian@0 761 return -ENODEV;
ian@0 762
ian@0 763 acpi_battery_dir = acpi_lock_battery_dir();
ian@0 764 if (!acpi_battery_dir)
ian@0 765 return -ENODEV;
ian@0 766
ian@0 767 result = acpi_bus_register_driver(&acpi_battery_driver);
ian@0 768 if (result < 0) {
ian@0 769 acpi_unlock_battery_dir(acpi_battery_dir);
ian@0 770 return -ENODEV;
ian@0 771 }
ian@0 772
ian@0 773 return 0;
ian@0 774 }
ian@0 775
ian@0 776 static void __exit acpi_battery_exit(void)
ian@0 777 {
ian@0 778
ian@0 779 acpi_bus_unregister_driver(&acpi_battery_driver);
ian@0 780
ian@0 781 acpi_unlock_battery_dir(acpi_battery_dir);
ian@0 782
ian@0 783 return;
ian@0 784 }
ian@0 785
ian@0 786 module_init(acpi_battery_init);
ian@0 787 module_exit(acpi_battery_exit);