blob: faa70a50b807cd83a3dea0fc87548e298082a75f [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
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>
Alexey Starikovskiyf1d46612007-09-26 19:42:52 +040030#include <linux/jiffies.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070031#include <linux/proc_fs.h>
32#include <linux/seq_file.h>
33#include <asm/uaccess.h>
34
35#include <acpi/acpi_bus.h>
36#include <acpi/acpi_drivers.h>
37
Linus Torvalds1da177e2005-04-16 15:20:36 -070038#define ACPI_BATTERY_VALUE_UNKNOWN 0xFFFFFFFF
39
Linus Torvalds1da177e2005-04-16 15:20:36 -070040#define ACPI_BATTERY_COMPONENT 0x00040000
41#define ACPI_BATTERY_CLASS "battery"
Linus Torvalds1da177e2005-04-16 15:20:36 -070042#define ACPI_BATTERY_DEVICE_NAME "Battery"
Linus Torvalds1da177e2005-04-16 15:20:36 -070043#define ACPI_BATTERY_NOTIFY_STATUS 0x80
44#define ACPI_BATTERY_NOTIFY_INFO 0x81
Linus Torvalds1da177e2005-04-16 15:20:36 -070045
Linus Torvalds1da177e2005-04-16 15:20:36 -070046#define _COMPONENT ACPI_BATTERY_COMPONENT
Vladimir Lebedevb6ce4082007-02-20 15:48:06 +030047
Len Brownf52fd662007-02-12 22:42:12 -050048ACPI_MODULE_NAME("battery");
Linus Torvalds1da177e2005-04-16 15:20:36 -070049
Len Brownf52fd662007-02-12 22:42:12 -050050MODULE_AUTHOR("Paul Diefenbaugh");
Len Brown7cda93e2007-02-12 23:50:02 -050051MODULE_DESCRIPTION("ACPI Battery Driver");
Linus Torvalds1da177e2005-04-16 15:20:36 -070052MODULE_LICENSE("GPL");
53
Alexey Starikovskiyf1d46612007-09-26 19:42:52 +040054static unsigned int cache_time = 1000;
55module_param(cache_time, uint, 0644);
56MODULE_PARM_DESC(cache_time, "cache time in milliseconds");
Vladimir Lebedevb6ce4082007-02-20 15:48:06 +030057
Rich Townsend3f86b832006-07-01 11:36:54 -040058extern struct proc_dir_entry *acpi_lock_battery_dir(void);
59extern void *acpi_unlock_battery_dir(struct proc_dir_entry *acpi_battery_dir);
60
Len Brown4be44fc2005-08-05 00:44:28 -040061static int acpi_battery_add(struct acpi_device *device);
62static int acpi_battery_remove(struct acpi_device *device, int type);
Patrick Mochel5d9464a2006-12-07 20:56:27 +080063static int acpi_battery_resume(struct acpi_device *device);
Linus Torvalds1da177e2005-04-16 15:20:36 -070064
Thomas Renninger1ba90e32007-07-23 14:44:41 +020065static const struct acpi_device_id battery_device_ids[] = {
66 {"PNP0C0A", 0},
67 {"", 0},
68};
69MODULE_DEVICE_TABLE(acpi, battery_device_ids);
70
Linus Torvalds1da177e2005-04-16 15:20:36 -070071static struct acpi_driver acpi_battery_driver = {
Len Brownc2b67052007-02-12 23:33:40 -050072 .name = "battery",
Len Brown4be44fc2005-08-05 00:44:28 -040073 .class = ACPI_BATTERY_CLASS,
Thomas Renninger1ba90e32007-07-23 14:44:41 +020074 .ids = battery_device_ids,
Len Brown4be44fc2005-08-05 00:44:28 -040075 .ops = {
76 .add = acpi_battery_add,
Jiri Kosina34c44152006-10-10 14:20:41 -070077 .resume = acpi_battery_resume,
Len Brown4be44fc2005-08-05 00:44:28 -040078 .remove = acpi_battery_remove,
79 },
Linus Torvalds1da177e2005-04-16 15:20:36 -070080};
81
Alexey Starikovskiy038fdea2007-09-26 19:42:46 +040082enum acpi_battery_files {
Alexey Starikovskiy78490d82007-05-11 13:18:55 -040083 ACPI_BATTERY_INFO = 0,
84 ACPI_BATTERY_STATE,
85 ACPI_BATTERY_ALARM,
86 ACPI_BATTERY_NUMFILES,
87};
88
Alexey Starikovskiy038fdea2007-09-26 19:42:46 +040089struct acpi_battery {
Alexey Starikovskiy038fdea2007-09-26 19:42:46 +040090 struct mutex lock;
Alexey Starikovskiyf1d46612007-09-26 19:42:52 +040091 struct acpi_device *device;
92 unsigned long update_time;
Alexey Starikovskiy038fdea2007-09-26 19:42:46 +040093 int present_rate;
94 int remaining_capacity;
95 int present_voltage;
Alexey Starikovskiy038fdea2007-09-26 19:42:46 +040096 int design_capacity;
97 int last_full_capacity;
98 int technology;
99 int design_voltage;
100 int design_capacity_warning;
101 int design_capacity_low;
102 int capacity_granularity_1;
103 int capacity_granularity_2;
Alexey Starikovskiyf1d46612007-09-26 19:42:52 +0400104 int alarm;
Alexey Starikovskiy038fdea2007-09-26 19:42:46 +0400105 char model_number[32];
106 char serial_number[32];
107 char type[32];
108 char oem_info[32];
Alexey Starikovskiyf1d46612007-09-26 19:42:52 +0400109 int state;
110 int power_unit;
Vladimir Lebedevb6ce4082007-02-20 15:48:06 +0300111 u8 alarm_present;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700112};
113
Alexey Starikovskiy78490d82007-05-11 13:18:55 -0400114inline int acpi_battery_present(struct acpi_battery *battery)
115{
116 return battery->device->status.battery_present;
117}
Alexey Starikovskiy038fdea2007-09-26 19:42:46 +0400118
Alexey Starikovskiyf1d46612007-09-26 19:42:52 +0400119inline char *acpi_battery_units(struct acpi_battery *battery)
Alexey Starikovskiy78490d82007-05-11 13:18:55 -0400120{
Alexey Starikovskiyf1d46612007-09-26 19:42:52 +0400121 return (battery->power_unit)?"mA":"mW";
Alexey Starikovskiy78490d82007-05-11 13:18:55 -0400122}
Vladimir Lebedevb6ce4082007-02-20 15:48:06 +0300123
Linus Torvalds1da177e2005-04-16 15:20:36 -0700124/* --------------------------------------------------------------------------
125 Battery Management
126 -------------------------------------------------------------------------- */
127
Alexey Starikovskiy038fdea2007-09-26 19:42:46 +0400128struct acpi_offsets {
129 size_t offset; /* offset inside struct acpi_sbs_battery */
130 u8 mode; /* int or string? */
131};
132
133static struct acpi_offsets state_offsets[] = {
134 {offsetof(struct acpi_battery, state), 0},
135 {offsetof(struct acpi_battery, present_rate), 0},
136 {offsetof(struct acpi_battery, remaining_capacity), 0},
137 {offsetof(struct acpi_battery, present_voltage), 0},
138};
139
140static struct acpi_offsets info_offsets[] = {
141 {offsetof(struct acpi_battery, power_unit), 0},
142 {offsetof(struct acpi_battery, design_capacity), 0},
143 {offsetof(struct acpi_battery, last_full_capacity), 0},
144 {offsetof(struct acpi_battery, technology), 0},
145 {offsetof(struct acpi_battery, design_voltage), 0},
146 {offsetof(struct acpi_battery, design_capacity_warning), 0},
147 {offsetof(struct acpi_battery, design_capacity_low), 0},
148 {offsetof(struct acpi_battery, capacity_granularity_1), 0},
149 {offsetof(struct acpi_battery, capacity_granularity_2), 0},
150 {offsetof(struct acpi_battery, model_number), 1},
151 {offsetof(struct acpi_battery, serial_number), 1},
152 {offsetof(struct acpi_battery, type), 1},
153 {offsetof(struct acpi_battery, oem_info), 1},
154};
155
156static int extract_package(struct acpi_battery *battery,
157 union acpi_object *package,
158 struct acpi_offsets *offsets, int num)
Vladimir Lebedevb6ce4082007-02-20 15:48:06 +0300159{
Alexey Starikovskiy038fdea2007-09-26 19:42:46 +0400160 int i, *x;
161 union acpi_object *element;
162 if (package->type != ACPI_TYPE_PACKAGE)
163 return -EFAULT;
164 for (i = 0; i < num; ++i) {
165 if (package->package.count <= i)
166 return -EFAULT;
167 element = &package->package.elements[i];
168 if (offsets[i].mode) {
169 if (element->type != ACPI_TYPE_STRING &&
170 element->type != ACPI_TYPE_BUFFER)
171 return -EFAULT;
172 strncpy((u8 *)battery + offsets[i].offset,
173 element->string.pointer, 32);
174 } else {
175 if (element->type != ACPI_TYPE_INTEGER)
176 return -EFAULT;
177 x = (int *)((u8 *)battery + offsets[i].offset);
178 *x = element->integer.value;
Vladimir Lebedevb6ce4082007-02-20 15:48:06 +0300179 }
Vladimir Lebedevb6ce4082007-02-20 15:48:06 +0300180 }
Vladimir Lebedevb6ce4082007-02-20 15:48:06 +0300181 return 0;
182}
183
184static int acpi_battery_get_status(struct acpi_battery *battery)
185{
186 int result = 0;
187
188 result = acpi_bus_get_status(battery->device);
189 if (result) {
190 ACPI_EXCEPTION((AE_INFO, AE_ERROR, "Evaluating _STA"));
191 return -ENODEV;
192 }
193 return result;
194}
195
196static int acpi_battery_get_info(struct acpi_battery *battery)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700197{
Len Brown4be44fc2005-08-05 00:44:28 -0400198 int result = 0;
199 acpi_status status = 0;
200 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
Linus Torvalds1da177e2005-04-16 15:20:36 -0700201
Vladimir Lebedevb6ce4082007-02-20 15:48:06 +0300202 if (!acpi_battery_present(battery))
203 return 0;
Alexey Starikovskiy038fdea2007-09-26 19:42:46 +0400204 mutex_lock(&battery->lock);
Alexey Starikovskiyf1d46612007-09-26 19:42:52 +0400205 status = acpi_evaluate_object(battery->device->handle, "_BIF",
Alexey Starikovskiy038fdea2007-09-26 19:42:46 +0400206 NULL, &buffer);
207 mutex_unlock(&battery->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700208 if (ACPI_FAILURE(status)) {
Thomas Renningera6fc6722006-06-26 23:58:43 -0400209 ACPI_EXCEPTION((AE_INFO, status, "Evaluating _BIF"));
Patrick Mocheld550d982006-06-27 00:41:40 -0400210 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700211 }
Alexey Starikovskiy038fdea2007-09-26 19:42:46 +0400212 result = extract_package(battery, buffer.pointer,
213 info_offsets, ARRAY_SIZE(info_offsets));
Alexey Starikovskiy78490d82007-05-11 13:18:55 -0400214 kfree(buffer.pointer);
Patrick Mocheld550d982006-06-27 00:41:40 -0400215 return result;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700216}
217
Vladimir Lebedevb6ce4082007-02-20 15:48:06 +0300218static int acpi_battery_get_state(struct acpi_battery *battery)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700219{
Len Brown4be44fc2005-08-05 00:44:28 -0400220 int result = 0;
221 acpi_status status = 0;
222 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
Linus Torvalds1da177e2005-04-16 15:20:36 -0700223
Vladimir Lebedevb6ce4082007-02-20 15:48:06 +0300224 if (!acpi_battery_present(battery))
225 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700226
Alexey Starikovskiyf1d46612007-09-26 19:42:52 +0400227 if (battery->update_time &&
228 time_before(jiffies, battery->update_time +
229 msecs_to_jiffies(cache_time)))
230 return 0;
231
Alexey Starikovskiy038fdea2007-09-26 19:42:46 +0400232 mutex_lock(&battery->lock);
Alexey Starikovskiyf1d46612007-09-26 19:42:52 +0400233 status = acpi_evaluate_object(battery->device->handle, "_BST",
Alexey Starikovskiy038fdea2007-09-26 19:42:46 +0400234 NULL, &buffer);
235 mutex_unlock(&battery->lock);
Len Brown5b31d892007-08-15 00:19:26 -0400236
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237 if (ACPI_FAILURE(status)) {
Thomas Renningera6fc6722006-06-26 23:58:43 -0400238 ACPI_EXCEPTION((AE_INFO, status, "Evaluating _BST"));
Patrick Mocheld550d982006-06-27 00:41:40 -0400239 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700240 }
Alexey Starikovskiy038fdea2007-09-26 19:42:46 +0400241 result = extract_package(battery, buffer.pointer,
242 state_offsets, ARRAY_SIZE(state_offsets));
Alexey Starikovskiyf1d46612007-09-26 19:42:52 +0400243 battery->update_time = jiffies;
Alexey Starikovskiy78490d82007-05-11 13:18:55 -0400244 kfree(buffer.pointer);
Patrick Mocheld550d982006-06-27 00:41:40 -0400245 return result;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700246}
247
Vladimir Lebedevb6ce4082007-02-20 15:48:06 +0300248static int acpi_battery_get_alarm(struct acpi_battery *battery)
249{
Vladimir Lebedevb6ce4082007-02-20 15:48:06 +0300250 return 0;
251}
252
Vladimir Lebedev9ea7d572007-02-20 15:48:06 +0300253static int acpi_battery_set_alarm(struct acpi_battery *battery,
254 unsigned long alarm)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700255{
Len Brown4be44fc2005-08-05 00:44:28 -0400256 acpi_status status = 0;
257 union acpi_object arg0 = { ACPI_TYPE_INTEGER };
258 struct acpi_object_list arg_list = { 1, &arg0 };
Linus Torvalds1da177e2005-04-16 15:20:36 -0700259
Vladimir Lebedevb6ce4082007-02-20 15:48:06 +0300260 if (!acpi_battery_present(battery))
261 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700262
Alexey Starikovskiy038fdea2007-09-26 19:42:46 +0400263 if (!battery->alarm_present)
Patrick Mocheld550d982006-06-27 00:41:40 -0400264 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700265
266 arg0.integer.value = alarm;
267
Alexey Starikovskiy038fdea2007-09-26 19:42:46 +0400268 mutex_lock(&battery->lock);
Alexey Starikovskiyf1d46612007-09-26 19:42:52 +0400269 status = acpi_evaluate_object(battery->device->handle, "_BTP",
270 &arg_list, NULL);
Alexey Starikovskiy038fdea2007-09-26 19:42:46 +0400271 mutex_unlock(&battery->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272 if (ACPI_FAILURE(status))
Patrick Mocheld550d982006-06-27 00:41:40 -0400273 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700274
275 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Alarm set to %d\n", (u32) alarm));
276
277 battery->alarm = alarm;
278
Patrick Mocheld550d982006-06-27 00:41:40 -0400279 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700280}
281
Vladimir Lebedevb6ce4082007-02-20 15:48:06 +0300282static int acpi_battery_init_alarm(struct acpi_battery *battery)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700283{
Len Brown4be44fc2005-08-05 00:44:28 -0400284 acpi_status status = AE_OK;
285 acpi_handle handle = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700286
Vladimir Lebedevb6ce4082007-02-20 15:48:06 +0300287 /* See if alarms are supported, and if so, set default */
Alexey Starikovskiyf1d46612007-09-26 19:42:52 +0400288 status = acpi_get_handle(battery->device->handle, "_BTP", &handle);
289 if (ACPI_FAILURE(status)) {
Alexey Starikovskiy038fdea2007-09-26 19:42:46 +0400290 battery->alarm_present = 0;
Alexey Starikovskiyf1d46612007-09-26 19:42:52 +0400291 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700292 }
Alexey Starikovskiyf1d46612007-09-26 19:42:52 +0400293 battery->alarm_present = 1;
294 if (!battery->alarm)
295 battery->alarm = battery->design_capacity_warning;
296 return acpi_battery_set_alarm(battery, battery->alarm);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700297}
298
Alexey Starikovskiyf1d46612007-09-26 19:42:52 +0400299static int acpi_battery_update(struct acpi_battery *battery)
Vladimir Lebedev4bd35cd2007-02-10 01:43:48 -0500300{
Alexey Starikovskiyf1d46612007-09-26 19:42:52 +0400301 int saved_present = acpi_battery_present(battery);
302 int result = acpi_battery_get_status(battery);
303 if (result || !acpi_battery_present(battery))
Vladimir Lebedevb6ce4082007-02-20 15:48:06 +0300304 return result;
Alexey Starikovskiyf1d46612007-09-26 19:42:52 +0400305 if (saved_present != acpi_battery_present(battery) ||
306 !battery->update_time) {
307 battery->update_time = 0;
Vladimir Lebedevb6ce4082007-02-20 15:48:06 +0300308 result = acpi_battery_get_info(battery);
309 if (result)
310 return result;
Vladimir Lebedevb6ce4082007-02-20 15:48:06 +0300311 acpi_battery_init_alarm(battery);
312 }
Alexey Starikovskiyf1d46612007-09-26 19:42:52 +0400313 return acpi_battery_get_state(battery);
Vladimir Lebedev4bd35cd2007-02-10 01:43:48 -0500314}
315
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316/* --------------------------------------------------------------------------
317 FS Interface (/proc)
318 -------------------------------------------------------------------------- */
319
Len Brown4be44fc2005-08-05 00:44:28 -0400320static struct proc_dir_entry *acpi_battery_dir;
Vladimir Lebedevb6ce4082007-02-20 15:48:06 +0300321
Alexey Starikovskiy78490d82007-05-11 13:18:55 -0400322static int acpi_battery_print_info(struct seq_file *seq, int result)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700323{
Jan Engelhardt50dd0962006-10-01 00:28:50 +0200324 struct acpi_battery *battery = seq->private;
Len Brown4be44fc2005-08-05 00:44:28 -0400325 char *units = "?";
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326
Vladimir Lebedevb6ce4082007-02-20 15:48:06 +0300327 if (result)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700328 goto end;
329
Vladimir Lebedevb6ce4082007-02-20 15:48:06 +0300330 if (acpi_battery_present(battery))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700331 seq_printf(seq, "present: yes\n");
332 else {
333 seq_printf(seq, "present: no\n");
334 goto end;
335 }
336
Vladimir Lebedevb6ce4082007-02-20 15:48:06 +0300337 /* Battery Units */
338
Alexey Starikovskiyf1d46612007-09-26 19:42:52 +0400339 units = acpi_battery_units(battery);
Len Brown4be44fc2005-08-05 00:44:28 -0400340
Alexey Starikovskiy038fdea2007-09-26 19:42:46 +0400341 if (battery->design_capacity == ACPI_BATTERY_VALUE_UNKNOWN)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700342 seq_printf(seq, "design capacity: unknown\n");
343 else
344 seq_printf(seq, "design capacity: %d %sh\n",
Alexey Starikovskiy038fdea2007-09-26 19:42:46 +0400345 (u32) battery->design_capacity, units);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700346
Alexey Starikovskiy038fdea2007-09-26 19:42:46 +0400347 if (battery->last_full_capacity == ACPI_BATTERY_VALUE_UNKNOWN)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700348 seq_printf(seq, "last full capacity: unknown\n");
349 else
350 seq_printf(seq, "last full capacity: %d %sh\n",
Alexey Starikovskiy038fdea2007-09-26 19:42:46 +0400351 (u32) battery->last_full_capacity, units);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352
Alexey Starikovskiy038fdea2007-09-26 19:42:46 +0400353 switch ((u32) battery->technology) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700354 case 0:
355 seq_printf(seq, "battery technology: non-rechargeable\n");
356 break;
357 case 1:
358 seq_printf(seq, "battery technology: rechargeable\n");
359 break;
360 default:
361 seq_printf(seq, "battery technology: unknown\n");
362 break;
363 }
364
Alexey Starikovskiy038fdea2007-09-26 19:42:46 +0400365 if (battery->design_voltage == ACPI_BATTERY_VALUE_UNKNOWN)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700366 seq_printf(seq, "design voltage: unknown\n");
367 else
368 seq_printf(seq, "design voltage: %d mV\n",
Alexey Starikovskiy038fdea2007-09-26 19:42:46 +0400369 (u32) battery->design_voltage);
Len Brown4be44fc2005-08-05 00:44:28 -0400370 seq_printf(seq, "design capacity warning: %d %sh\n",
Alexey Starikovskiy038fdea2007-09-26 19:42:46 +0400371 (u32) battery->design_capacity_warning, units);
Len Brown4be44fc2005-08-05 00:44:28 -0400372 seq_printf(seq, "design capacity low: %d %sh\n",
Alexey Starikovskiy038fdea2007-09-26 19:42:46 +0400373 (u32) battery->design_capacity_low, units);
Len Brown4be44fc2005-08-05 00:44:28 -0400374 seq_printf(seq, "capacity granularity 1: %d %sh\n",
Alexey Starikovskiy038fdea2007-09-26 19:42:46 +0400375 (u32) battery->capacity_granularity_1, units);
Len Brown4be44fc2005-08-05 00:44:28 -0400376 seq_printf(seq, "capacity granularity 2: %d %sh\n",
Alexey Starikovskiy038fdea2007-09-26 19:42:46 +0400377 (u32) battery->capacity_granularity_2, units);
378 seq_printf(seq, "model number: %s\n", battery->model_number);
379 seq_printf(seq, "serial number: %s\n", battery->serial_number);
380 seq_printf(seq, "battery type: %s\n", battery->type);
381 seq_printf(seq, "OEM info: %s\n", battery->oem_info);
Len Brown4be44fc2005-08-05 00:44:28 -0400382
383 end:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384
Vladimir Lebedevb6ce4082007-02-20 15:48:06 +0300385 if (result)
386 seq_printf(seq, "ERROR: Unable to read battery info\n");
387
388 return result;
389}
390
Alexey Starikovskiy78490d82007-05-11 13:18:55 -0400391static int acpi_battery_print_state(struct seq_file *seq, int result)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700392{
Jan Engelhardt50dd0962006-10-01 00:28:50 +0200393 struct acpi_battery *battery = seq->private;
Len Brown4be44fc2005-08-05 00:44:28 -0400394 char *units = "?";
Linus Torvalds1da177e2005-04-16 15:20:36 -0700395
Vladimir Lebedevb6ce4082007-02-20 15:48:06 +0300396 if (result)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397 goto end;
398
Vladimir Lebedevb6ce4082007-02-20 15:48:06 +0300399 if (acpi_battery_present(battery))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700400 seq_printf(seq, "present: yes\n");
401 else {
402 seq_printf(seq, "present: no\n");
403 goto end;
404 }
405
Vladimir Lebedevb6ce4082007-02-20 15:48:06 +0300406 /* Battery Units */
407
Alexey Starikovskiyf1d46612007-09-26 19:42:52 +0400408 units = acpi_battery_units(battery);
Vladimir Lebedevb6ce4082007-02-20 15:48:06 +0300409
Alexey Starikovskiy038fdea2007-09-26 19:42:46 +0400410 if (!(battery->state & 0x04))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700411 seq_printf(seq, "capacity state: ok\n");
412 else
413 seq_printf(seq, "capacity state: critical\n");
414
Alexey Starikovskiy038fdea2007-09-26 19:42:46 +0400415 if ((battery->state & 0x01) && (battery->state & 0x02)) {
Len Brown4be44fc2005-08-05 00:44:28 -0400416 seq_printf(seq,
417 "charging state: charging/discharging\n");
Alexey Starikovskiy038fdea2007-09-26 19:42:46 +0400418 } else if (battery->state & 0x01)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700419 seq_printf(seq, "charging state: discharging\n");
Alexey Starikovskiy038fdea2007-09-26 19:42:46 +0400420 else if (battery->state & 0x02)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700421 seq_printf(seq, "charging state: charging\n");
422 else {
423 seq_printf(seq, "charging state: charged\n");
424 }
425
Alexey Starikovskiy038fdea2007-09-26 19:42:46 +0400426 if (battery->present_rate == ACPI_BATTERY_VALUE_UNKNOWN)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700427 seq_printf(seq, "present rate: unknown\n");
428 else
429 seq_printf(seq, "present rate: %d %s\n",
Alexey Starikovskiy038fdea2007-09-26 19:42:46 +0400430 (u32) battery->present_rate, units);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700431
Alexey Starikovskiy038fdea2007-09-26 19:42:46 +0400432 if (battery->remaining_capacity == ACPI_BATTERY_VALUE_UNKNOWN)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700433 seq_printf(seq, "remaining capacity: unknown\n");
434 else
435 seq_printf(seq, "remaining capacity: %d %sh\n",
Alexey Starikovskiy038fdea2007-09-26 19:42:46 +0400436 (u32) battery->remaining_capacity, units);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437
Alexey Starikovskiy038fdea2007-09-26 19:42:46 +0400438 if (battery->present_voltage == ACPI_BATTERY_VALUE_UNKNOWN)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439 seq_printf(seq, "present voltage: unknown\n");
440 else
441 seq_printf(seq, "present voltage: %d mV\n",
Alexey Starikovskiy038fdea2007-09-26 19:42:46 +0400442 (u32) battery->present_voltage);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700443
Len Brown4be44fc2005-08-05 00:44:28 -0400444 end:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700445
Vladimir Lebedevb6ce4082007-02-20 15:48:06 +0300446 if (result) {
447 seq_printf(seq, "ERROR: Unable to read battery state\n");
448 }
449
450 return result;
451}
452
Alexey Starikovskiy78490d82007-05-11 13:18:55 -0400453static int acpi_battery_print_alarm(struct seq_file *seq, int result)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700454{
Jan Engelhardt50dd0962006-10-01 00:28:50 +0200455 struct acpi_battery *battery = seq->private;
Len Brown4be44fc2005-08-05 00:44:28 -0400456 char *units = "?";
Linus Torvalds1da177e2005-04-16 15:20:36 -0700457
Vladimir Lebedevb6ce4082007-02-20 15:48:06 +0300458 if (result)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700459 goto end;
460
Vladimir Lebedevb6ce4082007-02-20 15:48:06 +0300461 if (!acpi_battery_present(battery)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700462 seq_printf(seq, "present: no\n");
463 goto end;
464 }
465
466 /* Battery Units */
Len Brown4be44fc2005-08-05 00:44:28 -0400467
Alexey Starikovskiyf1d46612007-09-26 19:42:52 +0400468 units = acpi_battery_units(battery);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700469
470 seq_printf(seq, "alarm: ");
471 if (!battery->alarm)
472 seq_printf(seq, "unsupported\n");
473 else
Alexey Starikovskiyf1d46612007-09-26 19:42:52 +0400474 seq_printf(seq, "%u %sh\n", battery->alarm, units);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700475
Len Brown4be44fc2005-08-05 00:44:28 -0400476 end:
Vladimir Lebedevb6ce4082007-02-20 15:48:06 +0300477
478 if (result)
479 seq_printf(seq, "ERROR: Unable to read battery alarm\n");
480
481 return result;
482}
483
Alexey Starikovskiyf1d46612007-09-26 19:42:52 +0400484static ssize_t acpi_battery_write_alarm(struct file *file,
485 const char __user * buffer,
486 size_t count, loff_t * ppos)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700487{
Len Brown4be44fc2005-08-05 00:44:28 -0400488 int result = 0;
489 char alarm_string[12] = { '\0' };
Jan Engelhardt50dd0962006-10-01 00:28:50 +0200490 struct seq_file *m = file->private_data;
491 struct acpi_battery *battery = m->private;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700492
Linus Torvalds1da177e2005-04-16 15:20:36 -0700493 if (!battery || (count > sizeof(alarm_string) - 1))
Patrick Mocheld550d982006-06-27 00:41:40 -0400494 return -EINVAL;
Vladimir Lebedevb6ce4082007-02-20 15:48:06 +0300495 if (result) {
496 result = -ENODEV;
497 goto end;
498 }
Vladimir Lebedevb6ce4082007-02-20 15:48:06 +0300499 if (!acpi_battery_present(battery)) {
500 result = -ENODEV;
501 goto end;
502 }
Vladimir Lebedevb6ce4082007-02-20 15:48:06 +0300503 if (copy_from_user(alarm_string, buffer, count)) {
504 result = -EFAULT;
505 goto end;
506 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507 alarm_string[count] = '\0';
Alexey Starikovskiyf1d46612007-09-26 19:42:52 +0400508 battery->alarm = simple_strtol(alarm_string, NULL, 0);
509 result = acpi_battery_set_alarm(battery, battery->alarm);
Vladimir Lebedevb6ce4082007-02-20 15:48:06 +0300510 end:
Vladimir Lebedevb6ce4082007-02-20 15:48:06 +0300511 if (!result)
Alexey Starikovskiyf1d46612007-09-26 19:42:52 +0400512 return count;
Vladimir Lebedevb6ce4082007-02-20 15:48:06 +0300513 return result;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700514}
515
Alexey Starikovskiy78490d82007-05-11 13:18:55 -0400516typedef int(*print_func)(struct seq_file *seq, int result);
517typedef int(*get_func)(struct acpi_battery *battery);
518
519static struct acpi_read_mux {
520 print_func print;
521 get_func get;
522} acpi_read_funcs[ACPI_BATTERY_NUMFILES] = {
523 {.get = acpi_battery_get_info, .print = acpi_battery_print_info},
524 {.get = acpi_battery_get_state, .print = acpi_battery_print_state},
525 {.get = acpi_battery_get_alarm, .print = acpi_battery_print_alarm},
526};
527
528static int acpi_battery_read(int fid, struct seq_file *seq)
529{
530 struct acpi_battery *battery = seq->private;
Alexey Starikovskiyf1d46612007-09-26 19:42:52 +0400531 int result = acpi_battery_update(battery);
532 return acpi_read_funcs[fid].print(seq, result);
Alexey Starikovskiy78490d82007-05-11 13:18:55 -0400533}
534
535static int acpi_battery_read_info(struct seq_file *seq, void *offset)
536{
537 return acpi_battery_read(ACPI_BATTERY_INFO, seq);
538}
539
540static int acpi_battery_read_state(struct seq_file *seq, void *offset)
541{
542 return acpi_battery_read(ACPI_BATTERY_STATE, seq);
543}
544
545static int acpi_battery_read_alarm(struct seq_file *seq, void *offset)
546{
547 return acpi_battery_read(ACPI_BATTERY_ALARM, seq);
548}
549
550static int acpi_battery_info_open_fs(struct inode *inode, struct file *file)
551{
552 return single_open(file, acpi_battery_read_info, PDE(inode)->data);
553}
554
555static int acpi_battery_state_open_fs(struct inode *inode, struct file *file)
556{
557 return single_open(file, acpi_battery_read_state, PDE(inode)->data);
558}
559
Linus Torvalds1da177e2005-04-16 15:20:36 -0700560static int acpi_battery_alarm_open_fs(struct inode *inode, struct file *file)
561{
562 return single_open(file, acpi_battery_read_alarm, PDE(inode)->data);
563}
564
Alexey Starikovskiy78490d82007-05-11 13:18:55 -0400565static struct battery_file {
566 struct file_operations ops;
567 mode_t mode;
568 char *name;
569} acpi_battery_file[] = {
570 {
571 .name = "info",
572 .mode = S_IRUGO,
573 .ops = {
Len Brown4be44fc2005-08-05 00:44:28 -0400574 .open = acpi_battery_info_open_fs,
575 .read = seq_read,
576 .llseek = seq_lseek,
577 .release = single_release,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700578 .owner = THIS_MODULE,
Alexey Starikovskiy78490d82007-05-11 13:18:55 -0400579 },
580 },
581 {
582 .name = "state",
583 .mode = S_IRUGO,
584 .ops = {
Len Brown4be44fc2005-08-05 00:44:28 -0400585 .open = acpi_battery_state_open_fs,
586 .read = seq_read,
587 .llseek = seq_lseek,
588 .release = single_release,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700589 .owner = THIS_MODULE,
Alexey Starikovskiy78490d82007-05-11 13:18:55 -0400590 },
591 },
592 {
593 .name = "alarm",
594 .mode = S_IFREG | S_IRUGO | S_IWUSR,
595 .ops = {
Len Brown4be44fc2005-08-05 00:44:28 -0400596 .open = acpi_battery_alarm_open_fs,
597 .read = seq_read,
598 .write = acpi_battery_write_alarm,
599 .llseek = seq_lseek,
600 .release = single_release,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601 .owner = THIS_MODULE,
Alexey Starikovskiy78490d82007-05-11 13:18:55 -0400602 },
603 },
Linus Torvalds1da177e2005-04-16 15:20:36 -0700604};
605
Len Brown4be44fc2005-08-05 00:44:28 -0400606static int acpi_battery_add_fs(struct acpi_device *device)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700607{
Len Brown4be44fc2005-08-05 00:44:28 -0400608 struct proc_dir_entry *entry = NULL;
Alexey Starikovskiy78490d82007-05-11 13:18:55 -0400609 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700610
Linus Torvalds1da177e2005-04-16 15:20:36 -0700611 if (!acpi_device_dir(device)) {
612 acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device),
Len Brown4be44fc2005-08-05 00:44:28 -0400613 acpi_battery_dir);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700614 if (!acpi_device_dir(device))
Patrick Mocheld550d982006-06-27 00:41:40 -0400615 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700616 acpi_device_dir(device)->owner = THIS_MODULE;
617 }
618
Alexey Starikovskiy78490d82007-05-11 13:18:55 -0400619 for (i = 0; i < ACPI_BATTERY_NUMFILES; ++i) {
620 entry = create_proc_entry(acpi_battery_file[i].name,
621 acpi_battery_file[i].mode, acpi_device_dir(device));
622 if (!entry)
623 return -ENODEV;
624 else {
625 entry->proc_fops = &acpi_battery_file[i].ops;
626 entry->data = acpi_driver_data(device);
627 entry->owner = THIS_MODULE;
628 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700629 }
630
Patrick Mocheld550d982006-06-27 00:41:40 -0400631 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700632}
633
Len Brown4be44fc2005-08-05 00:44:28 -0400634static int acpi_battery_remove_fs(struct acpi_device *device)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700635{
Alexey Starikovskiy78490d82007-05-11 13:18:55 -0400636 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700637 if (acpi_device_dir(device)) {
Alexey Starikovskiy78490d82007-05-11 13:18:55 -0400638 for (i = 0; i < ACPI_BATTERY_NUMFILES; ++i) {
639 remove_proc_entry(acpi_battery_file[i].name,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640 acpi_device_dir(device));
Alexey Starikovskiy78490d82007-05-11 13:18:55 -0400641 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700642 remove_proc_entry(acpi_device_bid(device), acpi_battery_dir);
643 acpi_device_dir(device) = NULL;
644 }
645
Patrick Mocheld550d982006-06-27 00:41:40 -0400646 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647}
648
Linus Torvalds1da177e2005-04-16 15:20:36 -0700649/* --------------------------------------------------------------------------
650 Driver Interface
651 -------------------------------------------------------------------------- */
652
Len Brown4be44fc2005-08-05 00:44:28 -0400653static void acpi_battery_notify(acpi_handle handle, u32 event, void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700654{
Jan Engelhardt50dd0962006-10-01 00:28:50 +0200655 struct acpi_battery *battery = data;
Alexey Starikovskiyf1d46612007-09-26 19:42:52 +0400656 struct acpi_device *device;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700657 if (!battery)
Patrick Mocheld550d982006-06-27 00:41:40 -0400658 return;
Patrick Mochel145def82006-05-19 16:54:39 -0400659 device = battery->device;
Alexey Starikovskiyf1d46612007-09-26 19:42:52 +0400660 acpi_battery_update(battery);
661 acpi_bus_generate_proc_event(device, event,
662 acpi_battery_present(battery));
663 acpi_bus_generate_netlink_event(device->pnp.device_class,
664 device->dev.bus_id, event,
Vladimir Lebedev9ea7d572007-02-20 15:48:06 +0300665 acpi_battery_present(battery));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666}
667
Len Brown4be44fc2005-08-05 00:44:28 -0400668static int acpi_battery_add(struct acpi_device *device)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700669{
Len Brown4be44fc2005-08-05 00:44:28 -0400670 int result = 0;
671 acpi_status status = 0;
672 struct acpi_battery *battery = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700673
Linus Torvalds1da177e2005-04-16 15:20:36 -0700674 if (!device)
Patrick Mocheld550d982006-06-27 00:41:40 -0400675 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700676
Burman Yan36bcbec2006-12-19 12:56:11 -0800677 battery = kzalloc(sizeof(struct acpi_battery), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700678 if (!battery)
Patrick Mocheld550d982006-06-27 00:41:40 -0400679 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680
Patrick Mochel145def82006-05-19 16:54:39 -0400681 battery->device = device;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682 strcpy(acpi_device_name(device), ACPI_BATTERY_DEVICE_NAME);
683 strcpy(acpi_device_class(device), ACPI_BATTERY_CLASS);
684 acpi_driver_data(device) = battery;
Alexey Starikovskiy038fdea2007-09-26 19:42:46 +0400685 mutex_init(&battery->lock);
Alexey Starikovskiyf1d46612007-09-26 19:42:52 +0400686 acpi_battery_update(battery);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687 result = acpi_battery_add_fs(device);
688 if (result)
689 goto end;
690
Patrick Mochel3b073ec2006-05-19 16:54:41 -0400691 status = acpi_install_notify_handler(device->handle,
Vladimir Lebedev9fdae722006-06-27 04:49:00 -0400692 ACPI_ALL_NOTIFY,
Len Brown4be44fc2005-08-05 00:44:28 -0400693 acpi_battery_notify, battery);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700694 if (ACPI_FAILURE(status)) {
Vladimir Lebedevb6ce4082007-02-20 15:48:06 +0300695 ACPI_EXCEPTION((AE_INFO, status, "Installing notify handler"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700696 result = -ENODEV;
697 goto end;
698 }
699
700 printk(KERN_INFO PREFIX "%s Slot [%s] (battery %s)\n",
Len Brown4be44fc2005-08-05 00:44:28 -0400701 ACPI_BATTERY_DEVICE_NAME, acpi_device_bid(device),
702 device->status.battery_present ? "present" : "absent");
703
704 end:
Vladimir Lebedevb6ce4082007-02-20 15:48:06 +0300705
Linus Torvalds1da177e2005-04-16 15:20:36 -0700706 if (result) {
707 acpi_battery_remove_fs(device);
708 kfree(battery);
709 }
710
Patrick Mocheld550d982006-06-27 00:41:40 -0400711 return result;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700712}
713
Len Brown4be44fc2005-08-05 00:44:28 -0400714static int acpi_battery_remove(struct acpi_device *device, int type)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700715{
Len Brown4be44fc2005-08-05 00:44:28 -0400716 acpi_status status = 0;
717 struct acpi_battery *battery = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718
Linus Torvalds1da177e2005-04-16 15:20:36 -0700719 if (!device || !acpi_driver_data(device))
Patrick Mocheld550d982006-06-27 00:41:40 -0400720 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721
Jan Engelhardt50dd0962006-10-01 00:28:50 +0200722 battery = acpi_driver_data(device);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723
Patrick Mochel3b073ec2006-05-19 16:54:41 -0400724 status = acpi_remove_notify_handler(device->handle,
Vladimir Lebedev9fdae722006-06-27 04:49:00 -0400725 ACPI_ALL_NOTIFY,
Len Brown4be44fc2005-08-05 00:44:28 -0400726 acpi_battery_notify);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700727
728 acpi_battery_remove_fs(device);
Alexey Starikovskiy038fdea2007-09-26 19:42:46 +0400729 mutex_destroy(&battery->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700730 kfree(battery);
731
Patrick Mocheld550d982006-06-27 00:41:40 -0400732 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700733}
734
Jiri Kosina34c44152006-10-10 14:20:41 -0700735/* this is needed to learn about changes made in suspended state */
Patrick Mochel5d9464a2006-12-07 20:56:27 +0800736static int acpi_battery_resume(struct acpi_device *device)
Jiri Kosina34c44152006-10-10 14:20:41 -0700737{
738 struct acpi_battery *battery;
Jiri Kosina34c44152006-10-10 14:20:41 -0700739 if (!device)
740 return -EINVAL;
Alexey Starikovskiyf1d46612007-09-26 19:42:52 +0400741 battery = acpi_driver_data(device);
742 battery->update_time = 0;
Vladimir Lebedevb6ce4082007-02-20 15:48:06 +0300743 return 0;
Jiri Kosina34c44152006-10-10 14:20:41 -0700744}
745
Len Brown4be44fc2005-08-05 00:44:28 -0400746static int __init acpi_battery_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700747{
Rich Townsend3f86b832006-07-01 11:36:54 -0400748 int result;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700749
Pavel Machek4d8316d2006-08-14 22:37:22 -0700750 if (acpi_disabled)
751 return -ENODEV;
752
Rich Townsend3f86b832006-07-01 11:36:54 -0400753 acpi_battery_dir = acpi_lock_battery_dir();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700754 if (!acpi_battery_dir)
Patrick Mocheld550d982006-06-27 00:41:40 -0400755 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700756
757 result = acpi_bus_register_driver(&acpi_battery_driver);
758 if (result < 0) {
Rich Townsend3f86b832006-07-01 11:36:54 -0400759 acpi_unlock_battery_dir(acpi_battery_dir);
Patrick Mocheld550d982006-06-27 00:41:40 -0400760 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700761 }
762
Patrick Mocheld550d982006-06-27 00:41:40 -0400763 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700764}
765
Len Brown4be44fc2005-08-05 00:44:28 -0400766static void __exit acpi_battery_exit(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700767{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700768 acpi_bus_unregister_driver(&acpi_battery_driver);
769
Rich Townsend3f86b832006-07-01 11:36:54 -0400770 acpi_unlock_battery_dir(acpi_battery_dir);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700771
Patrick Mocheld550d982006-06-27 00:41:40 -0400772 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700773}
774
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775module_init(acpi_battery_init);
776module_exit(acpi_battery_exit);