]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blame - drivers/acpi/battery.c
process reading battery status hangs
[mirror_ubuntu-artful-kernel.git] / drivers / acpi / battery.c
CommitLineData
1da177e4
LT
1/*
2 * acpi_battery.c - ACPI Battery Driver ($Revision: 37 $)
3 *
4 * Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
5 * Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
6 *
7 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or (at
12 * your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write to the Free Software Foundation, Inc.,
21 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
22 *
23 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
24 */
25
26#include <linux/kernel.h>
27#include <linux/module.h>
28#include <linux/init.h>
29#include <linux/types.h>
30#include <linux/proc_fs.h>
31#include <linux/seq_file.h>
32#include <asm/uaccess.h>
33
34#include <acpi/acpi_bus.h>
35#include <acpi/acpi_drivers.h>
36
1da177e4
LT
37#define ACPI_BATTERY_VALUE_UNKNOWN 0xFFFFFFFF
38
39#define ACPI_BATTERY_FORMAT_BIF "NNNNNNNNNSSSS"
40#define ACPI_BATTERY_FORMAT_BST "NNNN"
41
42#define ACPI_BATTERY_COMPONENT 0x00040000
43#define ACPI_BATTERY_CLASS "battery"
44#define ACPI_BATTERY_HID "PNP0C0A"
1da177e4
LT
45#define ACPI_BATTERY_DEVICE_NAME "Battery"
46#define ACPI_BATTERY_FILE_INFO "info"
a1f0eff2 47#define ACPI_BATTERY_FILE_STATE "state"
1da177e4
LT
48#define ACPI_BATTERY_FILE_ALARM "alarm"
49#define ACPI_BATTERY_NOTIFY_STATUS 0x80
50#define ACPI_BATTERY_NOTIFY_INFO 0x81
51#define ACPI_BATTERY_UNITS_WATTS "mW"
52#define ACPI_BATTERY_UNITS_AMPS "mA"
53
1da177e4 54#define _COMPONENT ACPI_BATTERY_COMPONENT
b6ce4083
VL
55
56#define ACPI_BATTERY_UPDATE_TIME 0
57
58#define ACPI_BATTERY_NONE_UPDATE 0
59#define ACPI_BATTERY_EASY_UPDATE 1
60#define ACPI_BATTERY_INIT_UPDATE 2
61
f52fd66d 62ACPI_MODULE_NAME("battery");
1da177e4 63
f52fd66d 64MODULE_AUTHOR("Paul Diefenbaugh");
7cda93e0 65MODULE_DESCRIPTION("ACPI Battery Driver");
1da177e4
LT
66MODULE_LICENSE("GPL");
67
b6ce4083
VL
68static unsigned int update_time = ACPI_BATTERY_UPDATE_TIME;
69
70/* 0 - every time, > 0 - by update_time */
71module_param(update_time, uint, 0644);
72
3f86b832
RT
73extern struct proc_dir_entry *acpi_lock_battery_dir(void);
74extern void *acpi_unlock_battery_dir(struct proc_dir_entry *acpi_battery_dir);
75
4be44fcd
LB
76static int acpi_battery_add(struct acpi_device *device);
77static int acpi_battery_remove(struct acpi_device *device, int type);
5d9464a4 78static int acpi_battery_resume(struct acpi_device *device);
1da177e4
LT
79
80static struct acpi_driver acpi_battery_driver = {
c2b6705b 81 .name = "battery",
4be44fcd
LB
82 .class = ACPI_BATTERY_CLASS,
83 .ids = ACPI_BATTERY_HID,
84 .ops = {
85 .add = acpi_battery_add,
34c4415a 86 .resume = acpi_battery_resume,
4be44fcd
LB
87 .remove = acpi_battery_remove,
88 },
1da177e4
LT
89};
90
a1f0eff2 91struct acpi_battery_state {
4be44fcd
LB
92 acpi_integer state;
93 acpi_integer present_rate;
94 acpi_integer remaining_capacity;
95 acpi_integer present_voltage;
1da177e4
LT
96};
97
98struct acpi_battery_info {
4be44fcd
LB
99 acpi_integer power_unit;
100 acpi_integer design_capacity;
101 acpi_integer last_full_capacity;
102 acpi_integer battery_technology;
103 acpi_integer design_voltage;
104 acpi_integer design_capacity_warning;
105 acpi_integer design_capacity_low;
106 acpi_integer battery_capacity_granularity_1;
107 acpi_integer battery_capacity_granularity_2;
108 acpi_string model_number;
109 acpi_string serial_number;
110 acpi_string battery_type;
111 acpi_string oem_info;
1da177e4
LT
112};
113
114struct acpi_battery_flags {
b6ce4083
VL
115 u8 battery_present_prev;
116 u8 alarm_present;
117 u8 init_update;
118 u8 info_update;
119 u8 state_update;
120 u8 alarm_update;
121 u8 power_unit;
1da177e4
LT
122};
123
124struct acpi_battery {
b6ce4083 125 struct mutex mutex;
9ea7d575 126 struct acpi_device *device;
1da177e4 127 struct acpi_battery_flags flags;
b6ce4083
VL
128 struct acpi_buffer bif_data;
129 struct acpi_buffer bst_data;
4be44fcd 130 unsigned long alarm;
b6ce4083
VL
131 unsigned long info_update_time;
132 unsigned long state_update_time;
133 unsigned long alarm_update_time;
1da177e4
LT
134};
135
b6ce4083
VL
136#define acpi_battery_present(battery) battery->device->status.battery_present
137#define acpi_battery_present_prev(battery) battery->flags.battery_present_prev
138#define acpi_battery_alarm_present(battery) battery->flags.alarm_present
139#define acpi_battery_init_update_flag(battery) battery->flags.init_update
140#define acpi_battery_info_update_flag(battery) battery->flags.info_update
141#define acpi_battery_state_update_flag(battery) battery->flags.state_update
142#define acpi_battery_alarm_update_flag(battery) battery->flags.alarm_update
143#define acpi_battery_power_units(battery) battery->flags.power_unit ? \
144 ACPI_BATTERY_UNITS_AMPS : ACPI_BATTERY_UNITS_WATTS
145#define acpi_battery_handle(battery) battery->device->handle
146#define acpi_battery_inserted(battery) (!acpi_battery_present_prev(battery) & acpi_battery_present(battery))
147#define acpi_battery_removed(battery) (acpi_battery_present_prev(battery) & !acpi_battery_present(battery))
148#define acpi_battery_bid(battery) acpi_device_bid(battery->device)
149#define acpi_battery_status_str(battery) acpi_battery_present(battery) ? "present" : "absent"
150
1da177e4
LT
151/* --------------------------------------------------------------------------
152 Battery Management
153 -------------------------------------------------------------------------- */
154
b6ce4083
VL
155static void acpi_battery_mutex_lock(struct acpi_battery *battery)
156{
157 mutex_lock(&battery->mutex);
158}
159
160static void acpi_battery_mutex_unlock(struct acpi_battery *battery)
161{
162 mutex_unlock(&battery->mutex);
163}
164
165static void acpi_battery_check_result(struct acpi_battery *battery, int result)
166{
167 if (!battery)
168 return;
169
170 if (result) {
171 acpi_battery_init_update_flag(battery) = 1;
172 }
173}
174
175static int acpi_battery_extract_package(struct acpi_battery *battery,
176 union acpi_object *package,
177 struct acpi_buffer *format,
178 struct acpi_buffer *data,
179 char *package_name)
180{
181 acpi_status status = AE_OK;
182 struct acpi_buffer data_null = { 0, NULL };
183
184 status = acpi_extract_package(package, format, &data_null);
185 if (status != AE_BUFFER_OVERFLOW) {
186 ACPI_EXCEPTION((AE_INFO, status, "Extracting size %s",
187 package_name));
188 return -ENODEV;
189 }
190
191 if (data_null.length != data->length) {
192 if (data->pointer) {
193 kfree(data->pointer);
194 }
195 data->pointer = kzalloc(data_null.length, GFP_KERNEL);
196 if (!data->pointer) {
197 ACPI_EXCEPTION((AE_INFO, AE_NO_MEMORY, "kzalloc()"));
198 return -ENOMEM;
199 }
200 data->length = data_null.length;
201 }
202
203 status = acpi_extract_package(package, format, data);
204 if (ACPI_FAILURE(status)) {
205 ACPI_EXCEPTION((AE_INFO, status, "Extracting %s",
206 package_name));
207 return -ENODEV;
208 }
209
210 return 0;
211}
212
213static int acpi_battery_get_status(struct acpi_battery *battery)
214{
215 int result = 0;
216
217 result = acpi_bus_get_status(battery->device);
218 if (result) {
219 ACPI_EXCEPTION((AE_INFO, AE_ERROR, "Evaluating _STA"));
220 return -ENODEV;
221 }
222 return result;
223}
224
225static int acpi_battery_get_info(struct acpi_battery *battery)
1da177e4 226{
4be44fcd
LB
227 int result = 0;
228 acpi_status status = 0;
229 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
230 struct acpi_buffer format = { sizeof(ACPI_BATTERY_FORMAT_BIF),
231 ACPI_BATTERY_FORMAT_BIF
232 };
4be44fcd 233 union acpi_object *package = NULL;
b6ce4083
VL
234 struct acpi_buffer *data = NULL;
235 struct acpi_battery_info *bif = NULL;
1da177e4 236
b6ce4083 237 battery->info_update_time = get_seconds();
1da177e4 238
b6ce4083
VL
239 if (!acpi_battery_present(battery))
240 return 0;
1da177e4
LT
241
242 /* Evalute _BIF */
243
9ea7d575
VL
244 status =
245 acpi_evaluate_object(acpi_battery_handle(battery), "_BIF", NULL,
246 &buffer);
1da177e4 247 if (ACPI_FAILURE(status)) {
a6fc6720 248 ACPI_EXCEPTION((AE_INFO, status, "Evaluating _BIF"));
d550d98d 249 return -ENODEV;
1da177e4
LT
250 }
251
50dd0969 252 package = buffer.pointer;
1da177e4 253
b6ce4083
VL
254 data = &battery->bif_data;
255
1da177e4
LT
256 /* Extract Package Data */
257
9ea7d575
VL
258 result =
259 acpi_battery_extract_package(battery, package, &format, data,
260 "_BIF");
b6ce4083 261 if (result)
1da177e4 262 goto end;
1da177e4 263
b6ce4083 264 end:
1da177e4 265
b6ce4083
VL
266 if (buffer.pointer) {
267 kfree(buffer.pointer);
1da177e4
LT
268 }
269
b6ce4083
VL
270 if (!result) {
271 bif = data->pointer;
272 battery->flags.power_unit = bif->power_unit;
273 }
1da177e4 274
d550d98d 275 return result;
1da177e4
LT
276}
277
b6ce4083 278static int acpi_battery_get_state(struct acpi_battery *battery)
1da177e4 279{
4be44fcd
LB
280 int result = 0;
281 acpi_status status = 0;
282 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
283 struct acpi_buffer format = { sizeof(ACPI_BATTERY_FORMAT_BST),
284 ACPI_BATTERY_FORMAT_BST
285 };
4be44fcd 286 union acpi_object *package = NULL;
b6ce4083 287 struct acpi_buffer *data = NULL;
1da177e4 288
b6ce4083 289 battery->state_update_time = get_seconds();
1da177e4 290
b6ce4083
VL
291 if (!acpi_battery_present(battery))
292 return 0;
1da177e4
LT
293
294 /* Evalute _BST */
295
9ea7d575
VL
296 status =
297 acpi_evaluate_object(acpi_battery_handle(battery), "_BST", NULL,
298 &buffer);
1da177e4 299 if (ACPI_FAILURE(status)) {
a6fc6720 300 ACPI_EXCEPTION((AE_INFO, status, "Evaluating _BST"));
d550d98d 301 return -ENODEV;
1da177e4
LT
302 }
303
50dd0969 304 package = buffer.pointer;
1da177e4 305
b6ce4083 306 data = &battery->bst_data;
1da177e4 307
b6ce4083 308 /* Extract Package Data */
1da177e4 309
9ea7d575
VL
310 result =
311 acpi_battery_extract_package(battery, package, &format, data,
312 "_BST");
b6ce4083 313 if (result)
1da177e4 314 goto end;
1da177e4 315
b6ce4083
VL
316 end:
317 if (buffer.pointer) {
318 kfree(buffer.pointer);
1da177e4
LT
319 }
320
b6ce4083
VL
321 return result;
322}
1da177e4 323
b6ce4083
VL
324static int acpi_battery_get_alarm(struct acpi_battery *battery)
325{
326 battery->alarm_update_time = get_seconds();
1da177e4 327
b6ce4083 328 return 0;
1da177e4
LT
329}
330
9ea7d575
VL
331static int acpi_battery_set_alarm(struct acpi_battery *battery,
332 unsigned long alarm)
1da177e4 333{
4be44fcd
LB
334 acpi_status status = 0;
335 union acpi_object arg0 = { ACPI_TYPE_INTEGER };
336 struct acpi_object_list arg_list = { 1, &arg0 };
1da177e4 337
b6ce4083 338 battery->alarm_update_time = get_seconds();
1da177e4 339
b6ce4083
VL
340 if (!acpi_battery_present(battery))
341 return -ENODEV;
1da177e4 342
b6ce4083 343 if (!acpi_battery_alarm_present(battery))
d550d98d 344 return -ENODEV;
1da177e4
LT
345
346 arg0.integer.value = alarm;
347
9ea7d575
VL
348 status =
349 acpi_evaluate_object(acpi_battery_handle(battery), "_BTP",
350 &arg_list, NULL);
1da177e4 351 if (ACPI_FAILURE(status))
d550d98d 352 return -ENODEV;
1da177e4
LT
353
354 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Alarm set to %d\n", (u32) alarm));
355
356 battery->alarm = alarm;
357
d550d98d 358 return 0;
1da177e4
LT
359}
360
b6ce4083 361static int acpi_battery_init_alarm(struct acpi_battery *battery)
1da177e4 362{
4be44fcd
LB
363 int result = 0;
364 acpi_status status = AE_OK;
365 acpi_handle handle = NULL;
b6ce4083
VL
366 struct acpi_battery_info *bif = battery->bif_data.pointer;
367 unsigned long alarm = battery->alarm;
4be44fcd 368
b6ce4083 369 /* See if alarms are supported, and if so, set default */
1da177e4 370
b6ce4083
VL
371 status = acpi_get_handle(acpi_battery_handle(battery), "_BTP", &handle);
372 if (ACPI_SUCCESS(status)) {
373 acpi_battery_alarm_present(battery) = 1;
374 if (!alarm && bif) {
375 alarm = bif->design_capacity_warning;
376 }
377 result = acpi_battery_set_alarm(battery, alarm);
378 if (result)
379 goto end;
380 } else {
381 acpi_battery_alarm_present(battery) = 0;
382 }
1da177e4 383
b6ce4083 384 end:
1da177e4 385
b6ce4083
VL
386 return result;
387}
1da177e4 388
b6ce4083
VL
389static int acpi_battery_init_update(struct acpi_battery *battery)
390{
391 int result = 0;
1da177e4 392
b6ce4083
VL
393 result = acpi_battery_get_status(battery);
394 if (result)
395 return result;
1da177e4 396
b6ce4083 397 acpi_battery_present_prev(battery) = acpi_battery_present(battery);
1da177e4 398
b6ce4083
VL
399 if (acpi_battery_present(battery)) {
400 result = acpi_battery_get_info(battery);
401 if (result)
402 return result;
403 result = acpi_battery_get_state(battery);
1da177e4 404 if (result)
d550d98d 405 return result;
1da177e4 406
b6ce4083
VL
407 acpi_battery_init_alarm(battery);
408 }
409
410 return result;
411}
412
413static int acpi_battery_update(struct acpi_battery *battery,
9ea7d575 414 int update, int *update_result_ptr)
b6ce4083
VL
415{
416 int result = 0;
417 int update_result = ACPI_BATTERY_NONE_UPDATE;
1da177e4 418
b6ce4083
VL
419 if (!acpi_battery_present(battery)) {
420 update = 1;
421 }
1da177e4 422
b6ce4083
VL
423 if (acpi_battery_init_update_flag(battery)) {
424 result = acpi_battery_init_update(battery);
425 if (result)
426 goto end;;
427 update_result = ACPI_BATTERY_INIT_UPDATE;
428 } else if (update) {
429 result = acpi_battery_get_status(battery);
430 if (result)
431 goto end;;
9ea7d575
VL
432 if (acpi_battery_inserted(battery)
433 || acpi_battery_removed(battery)) {
b6ce4083
VL
434 result = acpi_battery_init_update(battery);
435 if (result)
436 goto end;;
437 update_result = ACPI_BATTERY_INIT_UPDATE;
438 } else {
439 update_result = ACPI_BATTERY_EASY_UPDATE;
1da177e4
LT
440 }
441 }
442
b6ce4083 443 end:
1da177e4 444
b6ce4083 445 acpi_battery_init_update_flag(battery) = (result != 0);
1da177e4 446
b6ce4083 447 *update_result_ptr = update_result;
1da177e4 448
d550d98d 449 return result;
1da177e4
LT
450}
451
b6ce4083 452static void acpi_battery_notify_update(struct acpi_battery *battery)
4bd35cdb 453{
b6ce4083
VL
454 acpi_battery_get_status(battery);
455
456 if (acpi_battery_init_update_flag(battery)) {
457 return;
458 }
459
460 if (acpi_battery_inserted(battery) || acpi_battery_removed(battery)) {
461 acpi_battery_init_update_flag(battery) = 1;
462 } else {
463 acpi_battery_info_update_flag(battery) = 1;
464 acpi_battery_state_update_flag(battery) = 1;
465 acpi_battery_alarm_update_flag(battery) = 1;
4bd35cdb
VL
466 }
467}
468
1da177e4
LT
469/* --------------------------------------------------------------------------
470 FS Interface (/proc)
471 -------------------------------------------------------------------------- */
472
4be44fcd 473static struct proc_dir_entry *acpi_battery_dir;
b6ce4083
VL
474
475static int acpi_battery_read_info_print(struct seq_file *seq, int result)
1da177e4 476{
50dd0969 477 struct acpi_battery *battery = seq->private;
1da177e4 478 struct acpi_battery_info *bif = NULL;
4be44fcd 479 char *units = "?";
1da177e4 480
b6ce4083 481 if (result)
1da177e4
LT
482 goto end;
483
b6ce4083 484 if (acpi_battery_present(battery))
1da177e4
LT
485 seq_printf(seq, "present: yes\n");
486 else {
487 seq_printf(seq, "present: no\n");
488 goto end;
489 }
490
b6ce4083
VL
491 bif = battery->bif_data.pointer;
492 if (!bif) {
493 ACPI_EXCEPTION((AE_INFO, AE_ERROR, "BIF buffer is NULL"));
494 result = -ENODEV;
1da177e4
LT
495 goto end;
496 }
497
b6ce4083
VL
498 /* Battery Units */
499
500 units = acpi_battery_power_units(battery);
4be44fcd 501
1da177e4
LT
502 if (bif->design_capacity == ACPI_BATTERY_VALUE_UNKNOWN)
503 seq_printf(seq, "design capacity: unknown\n");
504 else
505 seq_printf(seq, "design capacity: %d %sh\n",
4be44fcd 506 (u32) bif->design_capacity, units);
1da177e4
LT
507
508 if (bif->last_full_capacity == ACPI_BATTERY_VALUE_UNKNOWN)
509 seq_printf(seq, "last full capacity: unknown\n");
510 else
511 seq_printf(seq, "last full capacity: %d %sh\n",
4be44fcd 512 (u32) bif->last_full_capacity, units);
1da177e4
LT
513
514 switch ((u32) bif->battery_technology) {
515 case 0:
516 seq_printf(seq, "battery technology: non-rechargeable\n");
517 break;
518 case 1:
519 seq_printf(seq, "battery technology: rechargeable\n");
520 break;
521 default:
522 seq_printf(seq, "battery technology: unknown\n");
523 break;
524 }
525
526 if (bif->design_voltage == ACPI_BATTERY_VALUE_UNKNOWN)
527 seq_printf(seq, "design voltage: unknown\n");
528 else
529 seq_printf(seq, "design voltage: %d mV\n",
4be44fcd 530 (u32) bif->design_voltage);
1da177e4 531 seq_printf(seq, "design capacity warning: %d %sh\n",
4be44fcd 532 (u32) bif->design_capacity_warning, units);
1da177e4 533 seq_printf(seq, "design capacity low: %d %sh\n",
4be44fcd 534 (u32) bif->design_capacity_low, units);
1da177e4 535 seq_printf(seq, "capacity granularity 1: %d %sh\n",
4be44fcd 536 (u32) bif->battery_capacity_granularity_1, units);
1da177e4 537 seq_printf(seq, "capacity granularity 2: %d %sh\n",
4be44fcd
LB
538 (u32) bif->battery_capacity_granularity_2, units);
539 seq_printf(seq, "model number: %s\n", bif->model_number);
540 seq_printf(seq, "serial number: %s\n", bif->serial_number);
541 seq_printf(seq, "battery type: %s\n", bif->battery_type);
542 seq_printf(seq, "OEM info: %s\n", bif->oem_info);
543
544 end:
1da177e4 545
b6ce4083
VL
546 if (result)
547 seq_printf(seq, "ERROR: Unable to read battery info\n");
548
549 return result;
550}
551
552static int acpi_battery_read_info(struct seq_file *seq, void *offset)
553{
554 struct acpi_battery *battery = seq->private;
555 int result = 0;
556 int update_result = ACPI_BATTERY_NONE_UPDATE;
557 int update = 0;
558
559 acpi_battery_mutex_lock(battery);
560
561 update = (get_seconds() - battery->info_update_time >= update_time);
562 update = (update | acpi_battery_info_update_flag(battery));
563
564 result = acpi_battery_update(battery, update, &update_result);
565 if (result)
566 goto end;
567
568 /* Battery Info (_BIF) */
569
570 if (update_result == ACPI_BATTERY_EASY_UPDATE) {
571 result = acpi_battery_get_info(battery);
572 if (result)
573 goto end;
574 }
575
576 end:
577
578 result = acpi_battery_read_info_print(seq, result);
579
580 acpi_battery_check_result(battery, result);
581
582 acpi_battery_info_update_flag(battery) = result;
583
584 acpi_battery_mutex_unlock(battery);
585
586 return result;
1da177e4
LT
587}
588
589static int acpi_battery_info_open_fs(struct inode *inode, struct file *file)
590{
591 return single_open(file, acpi_battery_read_info, PDE(inode)->data);
592}
593
b6ce4083 594static int acpi_battery_read_state_print(struct seq_file *seq, int result)
1da177e4 595{
50dd0969 596 struct acpi_battery *battery = seq->private;
a1f0eff2 597 struct acpi_battery_state *bst = NULL;
4be44fcd 598 char *units = "?";
1da177e4 599
b6ce4083 600 if (result)
1da177e4
LT
601 goto end;
602
b6ce4083 603 if (acpi_battery_present(battery))
1da177e4
LT
604 seq_printf(seq, "present: yes\n");
605 else {
606 seq_printf(seq, "present: no\n");
607 goto end;
608 }
609
b6ce4083
VL
610 bst = battery->bst_data.pointer;
611 if (!bst) {
612 ACPI_EXCEPTION((AE_INFO, AE_ERROR, "BST buffer is NULL"));
613 result = -ENODEV;
1da177e4
LT
614 goto end;
615 }
616
b6ce4083
VL
617 /* Battery Units */
618
619 units = acpi_battery_power_units(battery);
620
1da177e4
LT
621 if (!(bst->state & 0x04))
622 seq_printf(seq, "capacity state: ok\n");
623 else
624 seq_printf(seq, "capacity state: critical\n");
625
4be44fcd
LB
626 if ((bst->state & 0x01) && (bst->state & 0x02)) {
627 seq_printf(seq,
628 "charging state: charging/discharging\n");
4be44fcd 629 } else if (bst->state & 0x01)
1da177e4
LT
630 seq_printf(seq, "charging state: discharging\n");
631 else if (bst->state & 0x02)
632 seq_printf(seq, "charging state: charging\n");
633 else {
634 seq_printf(seq, "charging state: charged\n");
635 }
636
637 if (bst->present_rate == ACPI_BATTERY_VALUE_UNKNOWN)
638 seq_printf(seq, "present rate: unknown\n");
639 else
640 seq_printf(seq, "present rate: %d %s\n",
4be44fcd 641 (u32) bst->present_rate, units);
1da177e4
LT
642
643 if (bst->remaining_capacity == ACPI_BATTERY_VALUE_UNKNOWN)
644 seq_printf(seq, "remaining capacity: unknown\n");
645 else
646 seq_printf(seq, "remaining capacity: %d %sh\n",
4be44fcd 647 (u32) bst->remaining_capacity, units);
1da177e4
LT
648
649 if (bst->present_voltage == ACPI_BATTERY_VALUE_UNKNOWN)
650 seq_printf(seq, "present voltage: unknown\n");
651 else
652 seq_printf(seq, "present voltage: %d mV\n",
4be44fcd 653 (u32) bst->present_voltage);
1da177e4 654
4be44fcd 655 end:
1da177e4 656
b6ce4083
VL
657 if (result) {
658 seq_printf(seq, "ERROR: Unable to read battery state\n");
659 }
660
661 return result;
662}
663
664static int acpi_battery_read_state(struct seq_file *seq, void *offset)
665{
666 struct acpi_battery *battery = seq->private;
667 int result = 0;
668 int update_result = ACPI_BATTERY_NONE_UPDATE;
669 int update = 0;
670
671 acpi_battery_mutex_lock(battery);
672
673 update = (get_seconds() - battery->state_update_time >= update_time);
674 update = (update | acpi_battery_state_update_flag(battery));
675
676 result = acpi_battery_update(battery, update, &update_result);
677 if (result)
678 goto end;
679
680 /* Battery State (_BST) */
681
682 if (update_result == ACPI_BATTERY_EASY_UPDATE) {
683 result = acpi_battery_get_state(battery);
684 if (result)
685 goto end;
686 }
687
688 end:
689
690 result = acpi_battery_read_state_print(seq, result);
691
692 acpi_battery_check_result(battery, result);
693
694 acpi_battery_state_update_flag(battery) = result;
695
696 acpi_battery_mutex_unlock(battery);
697
698 return result;
1da177e4
LT
699}
700
701static int acpi_battery_state_open_fs(struct inode *inode, struct file *file)
702{
703 return single_open(file, acpi_battery_read_state, PDE(inode)->data);
704}
705
b6ce4083 706static int acpi_battery_read_alarm_print(struct seq_file *seq, int result)
1da177e4 707{
50dd0969 708 struct acpi_battery *battery = seq->private;
4be44fcd 709 char *units = "?";
1da177e4 710
b6ce4083 711 if (result)
1da177e4
LT
712 goto end;
713
b6ce4083 714 if (!acpi_battery_present(battery)) {
1da177e4
LT
715 seq_printf(seq, "present: no\n");
716 goto end;
717 }
718
719 /* Battery Units */
4be44fcd 720
b6ce4083 721 units = acpi_battery_power_units(battery);
1da177e4
LT
722
723 seq_printf(seq, "alarm: ");
724 if (!battery->alarm)
725 seq_printf(seq, "unsupported\n");
726 else
b6ce4083 727 seq_printf(seq, "%lu %sh\n", battery->alarm, units);
1da177e4 728
4be44fcd 729 end:
b6ce4083
VL
730
731 if (result)
732 seq_printf(seq, "ERROR: Unable to read battery alarm\n");
733
734 return result;
735}
736
737static int acpi_battery_read_alarm(struct seq_file *seq, void *offset)
738{
739 struct acpi_battery *battery = seq->private;
740 int result = 0;
741 int update_result = ACPI_BATTERY_NONE_UPDATE;
742 int update = 0;
743
744 acpi_battery_mutex_lock(battery);
745
746 update = (get_seconds() - battery->alarm_update_time >= update_time);
747 update = (update | acpi_battery_alarm_update_flag(battery));
748
749 result = acpi_battery_update(battery, update, &update_result);
750 if (result)
751 goto end;
752
753 /* Battery Alarm */
754
755 if (update_result == ACPI_BATTERY_EASY_UPDATE) {
756 result = acpi_battery_get_alarm(battery);
757 if (result)
758 goto end;
759 }
760
761 end:
762
763 result = acpi_battery_read_alarm_print(seq, result);
764
765 acpi_battery_check_result(battery, result);
766
767 acpi_battery_alarm_update_flag(battery) = result;
768
769 acpi_battery_mutex_unlock(battery);
770
771 return result;
1da177e4
LT
772}
773
1da177e4 774static ssize_t
4be44fcd
LB
775acpi_battery_write_alarm(struct file *file,
776 const char __user * buffer,
777 size_t count, loff_t * ppos)
1da177e4 778{
4be44fcd
LB
779 int result = 0;
780 char alarm_string[12] = { '\0' };
50dd0969
JE
781 struct seq_file *m = file->private_data;
782 struct acpi_battery *battery = m->private;
b6ce4083 783 int update_result = ACPI_BATTERY_NONE_UPDATE;
1da177e4 784
1da177e4 785 if (!battery || (count > sizeof(alarm_string) - 1))
d550d98d 786 return -EINVAL;
1da177e4 787
b6ce4083 788 acpi_battery_mutex_lock(battery);
4bd35cdb 789
b6ce4083
VL
790 result = acpi_battery_update(battery, 1, &update_result);
791 if (result) {
792 result = -ENODEV;
793 goto end;
794 }
1da177e4 795
b6ce4083
VL
796 if (!acpi_battery_present(battery)) {
797 result = -ENODEV;
798 goto end;
799 }
800
801 if (copy_from_user(alarm_string, buffer, count)) {
802 result = -EFAULT;
803 goto end;
804 }
4be44fcd 805
1da177e4
LT
806 alarm_string[count] = '\0';
807
4be44fcd
LB
808 result = acpi_battery_set_alarm(battery,
809 simple_strtoul(alarm_string, NULL, 0));
1da177e4 810 if (result)
b6ce4083
VL
811 goto end;
812
813 end:
814
815 acpi_battery_check_result(battery, result);
1da177e4 816
b6ce4083
VL
817 if (!result)
818 result = count;
819
820 acpi_battery_mutex_unlock(battery);
821
822 return result;
1da177e4
LT
823}
824
825static int acpi_battery_alarm_open_fs(struct inode *inode, struct file *file)
826{
827 return single_open(file, acpi_battery_read_alarm, PDE(inode)->data);
828}
829
d7508032 830static const struct file_operations acpi_battery_info_ops = {
4be44fcd
LB
831 .open = acpi_battery_info_open_fs,
832 .read = seq_read,
833 .llseek = seq_lseek,
834 .release = single_release,
1da177e4
LT
835 .owner = THIS_MODULE,
836};
837
d7508032 838static const struct file_operations acpi_battery_state_ops = {
4be44fcd
LB
839 .open = acpi_battery_state_open_fs,
840 .read = seq_read,
841 .llseek = seq_lseek,
842 .release = single_release,
1da177e4
LT
843 .owner = THIS_MODULE,
844};
845
d7508032 846static const struct file_operations acpi_battery_alarm_ops = {
4be44fcd
LB
847 .open = acpi_battery_alarm_open_fs,
848 .read = seq_read,
849 .write = acpi_battery_write_alarm,
850 .llseek = seq_lseek,
851 .release = single_release,
1da177e4
LT
852 .owner = THIS_MODULE,
853};
854
4be44fcd 855static int acpi_battery_add_fs(struct acpi_device *device)
1da177e4 856{
4be44fcd 857 struct proc_dir_entry *entry = NULL;
1da177e4 858
1da177e4
LT
859 if (!acpi_device_dir(device)) {
860 acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device),
4be44fcd 861 acpi_battery_dir);
1da177e4 862 if (!acpi_device_dir(device))
d550d98d 863 return -ENODEV;
1da177e4
LT
864 acpi_device_dir(device)->owner = THIS_MODULE;
865 }
866
867 /* 'info' [R] */
868 entry = create_proc_entry(ACPI_BATTERY_FILE_INFO,
4be44fcd 869 S_IRUGO, acpi_device_dir(device));
1da177e4 870 if (!entry)
d550d98d 871 return -ENODEV;
1da177e4 872 else {
4be44fcd 873 entry->proc_fops = &acpi_battery_info_ops;
1da177e4
LT
874 entry->data = acpi_driver_data(device);
875 entry->owner = THIS_MODULE;
876 }
877
878 /* 'status' [R] */
a1f0eff2 879 entry = create_proc_entry(ACPI_BATTERY_FILE_STATE,
4be44fcd 880 S_IRUGO, acpi_device_dir(device));
1da177e4 881 if (!entry)
d550d98d 882 return -ENODEV;
1da177e4
LT
883 else {
884 entry->proc_fops = &acpi_battery_state_ops;
885 entry->data = acpi_driver_data(device);
886 entry->owner = THIS_MODULE;
887 }
888
889 /* 'alarm' [R/W] */
890 entry = create_proc_entry(ACPI_BATTERY_FILE_ALARM,
4be44fcd
LB
891 S_IFREG | S_IRUGO | S_IWUSR,
892 acpi_device_dir(device));
1da177e4 893 if (!entry)
d550d98d 894 return -ENODEV;
1da177e4
LT
895 else {
896 entry->proc_fops = &acpi_battery_alarm_ops;
897 entry->data = acpi_driver_data(device);
898 entry->owner = THIS_MODULE;
899 }
900
d550d98d 901 return 0;
1da177e4
LT
902}
903
4be44fcd 904static int acpi_battery_remove_fs(struct acpi_device *device)
1da177e4 905{
1da177e4
LT
906 if (acpi_device_dir(device)) {
907 remove_proc_entry(ACPI_BATTERY_FILE_ALARM,
908 acpi_device_dir(device));
a1f0eff2 909 remove_proc_entry(ACPI_BATTERY_FILE_STATE,
1da177e4
LT
910 acpi_device_dir(device));
911 remove_proc_entry(ACPI_BATTERY_FILE_INFO,
912 acpi_device_dir(device));
913
914 remove_proc_entry(acpi_device_bid(device), acpi_battery_dir);
915 acpi_device_dir(device) = NULL;
916 }
917
d550d98d 918 return 0;
1da177e4
LT
919}
920
1da177e4
LT
921/* --------------------------------------------------------------------------
922 Driver Interface
923 -------------------------------------------------------------------------- */
924
4be44fcd 925static void acpi_battery_notify(acpi_handle handle, u32 event, void *data)
1da177e4 926{
50dd0969 927 struct acpi_battery *battery = data;
4be44fcd 928 struct acpi_device *device = NULL;
1da177e4 929
1da177e4 930 if (!battery)
d550d98d 931 return;
1da177e4 932
145def84 933 device = battery->device;
1da177e4
LT
934
935 switch (event) {
936 case ACPI_BATTERY_NOTIFY_STATUS:
937 case ACPI_BATTERY_NOTIFY_INFO:
9fdae727
VL
938 case ACPI_NOTIFY_BUS_CHECK:
939 case ACPI_NOTIFY_DEVICE_CHECK:
b6ce4083
VL
940 device = battery->device;
941 acpi_battery_notify_update(battery);
9ea7d575
VL
942 acpi_bus_generate_event(device, event,
943 acpi_battery_present(battery));
1da177e4
LT
944 break;
945 default:
946 ACPI_DEBUG_PRINT((ACPI_DB_INFO,
4be44fcd 947 "Unsupported event [0x%x]\n", event));
1da177e4
LT
948 break;
949 }
950
d550d98d 951 return;
1da177e4
LT
952}
953
4be44fcd 954static int acpi_battery_add(struct acpi_device *device)
1da177e4 955{
4be44fcd
LB
956 int result = 0;
957 acpi_status status = 0;
958 struct acpi_battery *battery = NULL;
1da177e4 959
1da177e4 960 if (!device)
d550d98d 961 return -EINVAL;
1da177e4 962
36bcbec7 963 battery = kzalloc(sizeof(struct acpi_battery), GFP_KERNEL);
1da177e4 964 if (!battery)
d550d98d 965 return -ENOMEM;
1da177e4 966
b6ce4083
VL
967 mutex_init(&battery->mutex);
968
969 acpi_battery_mutex_lock(battery);
970
145def84 971 battery->device = device;
1da177e4
LT
972 strcpy(acpi_device_name(device), ACPI_BATTERY_DEVICE_NAME);
973 strcpy(acpi_device_class(device), ACPI_BATTERY_CLASS);
974 acpi_driver_data(device) = battery;
975
b6ce4083 976 result = acpi_battery_get_status(battery);
1da177e4
LT
977 if (result)
978 goto end;
979
b6ce4083
VL
980 acpi_battery_init_update_flag(battery) = 1;
981
1da177e4
LT
982 result = acpi_battery_add_fs(device);
983 if (result)
984 goto end;
985
3b073ec3 986 status = acpi_install_notify_handler(device->handle,
9fdae727 987 ACPI_ALL_NOTIFY,
4be44fcd 988 acpi_battery_notify, battery);
1da177e4 989 if (ACPI_FAILURE(status)) {
b6ce4083 990 ACPI_EXCEPTION((AE_INFO, status, "Installing notify handler"));
1da177e4
LT
991 result = -ENODEV;
992 goto end;
993 }
994
995 printk(KERN_INFO PREFIX "%s Slot [%s] (battery %s)\n",
4be44fcd
LB
996 ACPI_BATTERY_DEVICE_NAME, acpi_device_bid(device),
997 device->status.battery_present ? "present" : "absent");
998
999 end:
b6ce4083 1000
1da177e4
LT
1001 if (result) {
1002 acpi_battery_remove_fs(device);
1003 kfree(battery);
1004 }
1005
b6ce4083
VL
1006 acpi_battery_mutex_unlock(battery);
1007
d550d98d 1008 return result;
1da177e4
LT
1009}
1010
4be44fcd 1011static int acpi_battery_remove(struct acpi_device *device, int type)
1da177e4 1012{
4be44fcd
LB
1013 acpi_status status = 0;
1014 struct acpi_battery *battery = NULL;
1da177e4 1015
1da177e4 1016 if (!device || !acpi_driver_data(device))
d550d98d 1017 return -EINVAL;
1da177e4 1018
50dd0969 1019 battery = acpi_driver_data(device);
1da177e4 1020
b6ce4083
VL
1021 acpi_battery_mutex_lock(battery);
1022
3b073ec3 1023 status = acpi_remove_notify_handler(device->handle,
9fdae727 1024 ACPI_ALL_NOTIFY,
4be44fcd 1025 acpi_battery_notify);
1da177e4
LT
1026
1027 acpi_battery_remove_fs(device);
1028
b6ce4083
VL
1029 if (battery->bif_data.pointer)
1030 kfree(battery->bif_data.pointer);
1031
1032 if (battery->bst_data.pointer)
1033 kfree(battery->bst_data.pointer);
1034
1035 acpi_battery_mutex_unlock(battery);
1036
1037 mutex_destroy(&battery->mutex);
1038
1da177e4
LT
1039 kfree(battery);
1040
d550d98d 1041 return 0;
1da177e4
LT
1042}
1043
34c4415a 1044/* this is needed to learn about changes made in suspended state */
5d9464a4 1045static int acpi_battery_resume(struct acpi_device *device)
34c4415a
JK
1046{
1047 struct acpi_battery *battery;
1048
1049 if (!device)
1050 return -EINVAL;
1051
1052 battery = device->driver_data;
b6ce4083
VL
1053
1054 acpi_battery_init_update_flag(battery) = 1;
1055
1056 return 0;
34c4415a
JK
1057}
1058
4be44fcd 1059static int __init acpi_battery_init(void)
1da177e4 1060{
3f86b832 1061 int result;
1da177e4 1062
4d8316d5
PM
1063 if (acpi_disabled)
1064 return -ENODEV;
1065
3f86b832 1066 acpi_battery_dir = acpi_lock_battery_dir();
1da177e4 1067 if (!acpi_battery_dir)
d550d98d 1068 return -ENODEV;
1da177e4
LT
1069
1070 result = acpi_bus_register_driver(&acpi_battery_driver);
1071 if (result < 0) {
3f86b832 1072 acpi_unlock_battery_dir(acpi_battery_dir);
d550d98d 1073 return -ENODEV;
1da177e4
LT
1074 }
1075
d550d98d 1076 return 0;
1da177e4
LT
1077}
1078
4be44fcd 1079static void __exit acpi_battery_exit(void)
1da177e4 1080{
1da177e4
LT
1081 acpi_bus_unregister_driver(&acpi_battery_driver);
1082
3f86b832 1083 acpi_unlock_battery_dir(acpi_battery_dir);
1da177e4 1084
d550d98d 1085 return;
1da177e4
LT
1086}
1087
1da177e4
LT
1088module_init(acpi_battery_init);
1089module_exit(acpi_battery_exit);