diff options
author | Len Brown <len.brown@intel.com> | 2007-10-10 00:30:19 -0400 |
---|---|---|
committer | Len Brown <len.brown@intel.com> | 2007-10-10 00:30:19 -0400 |
commit | e270051d9c6e5f0b31668ec1f0d864ab9920ffca (patch) | |
tree | 49c2a5fb6ca6790f9cf070b49552388dadc7fa5b /drivers/acpi/battery.c | |
parent | a2883dfa2e4a94b24109b2bfe735561e50cc44b4 (diff) | |
parent | d5b4a3d0efa36de31b86d5677dad6c36cb8735d7 (diff) |
Pull battery-sbs-ac into release branch
Diffstat (limited to 'drivers/acpi/battery.c')
-rw-r--r-- | drivers/acpi/battery.c | 1038 |
1 files changed, 436 insertions, 602 deletions
diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index 9b2c0f74f869..681e26b56b11 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c | |||
@@ -1,6 +1,8 @@ | |||
1 | /* | 1 | /* |
2 | * acpi_battery.c - ACPI Battery Driver ($Revision: 37 $) | 2 | * battery.c - ACPI Battery Driver (Revision: 2.0) |
3 | * | 3 | * |
4 | * Copyright (C) 2007 Alexey Starikovskiy <astarikovskiy@suse.de> | ||
5 | * Copyright (C) 2004-2007 Vladimir Lebedev <vladimir.p.lebedev@intel.com> | ||
4 | * Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com> | 6 | * Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com> |
5 | * Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com> | 7 | * Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com> |
6 | * | 8 | * |
@@ -27,244 +29,288 @@ | |||
27 | #include <linux/module.h> | 29 | #include <linux/module.h> |
28 | #include <linux/init.h> | 30 | #include <linux/init.h> |
29 | #include <linux/types.h> | 31 | #include <linux/types.h> |
32 | #include <linux/jiffies.h> | ||
33 | |||
34 | #ifdef CONFIG_ACPI_PROCFS | ||
30 | #include <linux/proc_fs.h> | 35 | #include <linux/proc_fs.h> |
31 | #include <linux/seq_file.h> | 36 | #include <linux/seq_file.h> |
32 | #include <asm/uaccess.h> | 37 | #include <asm/uaccess.h> |
38 | #endif | ||
33 | 39 | ||
34 | #include <acpi/acpi_bus.h> | 40 | #include <acpi/acpi_bus.h> |
35 | #include <acpi/acpi_drivers.h> | 41 | #include <acpi/acpi_drivers.h> |
36 | 42 | ||
37 | #define ACPI_BATTERY_VALUE_UNKNOWN 0xFFFFFFFF | 43 | #include <linux/power_supply.h> |
38 | 44 | ||
39 | #define ACPI_BATTERY_FORMAT_BIF "NNNNNNNNNSSSS" | 45 | #define ACPI_BATTERY_VALUE_UNKNOWN 0xFFFFFFFF |
40 | #define ACPI_BATTERY_FORMAT_BST "NNNN" | ||
41 | 46 | ||
42 | #define ACPI_BATTERY_COMPONENT 0x00040000 | 47 | #define ACPI_BATTERY_COMPONENT 0x00040000 |
43 | #define ACPI_BATTERY_CLASS "battery" | 48 | #define ACPI_BATTERY_CLASS "battery" |
44 | #define ACPI_BATTERY_DEVICE_NAME "Battery" | 49 | #define ACPI_BATTERY_DEVICE_NAME "Battery" |
45 | #define ACPI_BATTERY_NOTIFY_STATUS 0x80 | 50 | #define ACPI_BATTERY_NOTIFY_STATUS 0x80 |
46 | #define ACPI_BATTERY_NOTIFY_INFO 0x81 | 51 | #define ACPI_BATTERY_NOTIFY_INFO 0x81 |
47 | #define ACPI_BATTERY_UNITS_WATTS "mW" | ||
48 | #define ACPI_BATTERY_UNITS_AMPS "mA" | ||
49 | 52 | ||
50 | #define _COMPONENT ACPI_BATTERY_COMPONENT | 53 | #define _COMPONENT ACPI_BATTERY_COMPONENT |
51 | 54 | ||
52 | #define ACPI_BATTERY_UPDATE_TIME 0 | ||
53 | |||
54 | #define ACPI_BATTERY_NONE_UPDATE 0 | ||
55 | #define ACPI_BATTERY_EASY_UPDATE 1 | ||
56 | #define ACPI_BATTERY_INIT_UPDATE 2 | ||
57 | |||
58 | ACPI_MODULE_NAME("battery"); | 55 | ACPI_MODULE_NAME("battery"); |
59 | 56 | ||
60 | MODULE_AUTHOR("Paul Diefenbaugh"); | 57 | MODULE_AUTHOR("Paul Diefenbaugh"); |
58 | MODULE_AUTHOR("Alexey Starikovskiy <astarikovskiy@suse.de>"); | ||
61 | MODULE_DESCRIPTION("ACPI Battery Driver"); | 59 | MODULE_DESCRIPTION("ACPI Battery Driver"); |
62 | MODULE_LICENSE("GPL"); | 60 | MODULE_LICENSE("GPL"); |
63 | 61 | ||
64 | static unsigned int update_time = ACPI_BATTERY_UPDATE_TIME; | 62 | static unsigned int cache_time = 1000; |
65 | 63 | module_param(cache_time, uint, 0644); | |
66 | /* 0 - every time, > 0 - by update_time */ | 64 | MODULE_PARM_DESC(cache_time, "cache time in milliseconds"); |
67 | module_param(update_time, uint, 0644); | ||
68 | 65 | ||
66 | #ifdef CONFIG_ACPI_PROCFS | ||
69 | extern struct proc_dir_entry *acpi_lock_battery_dir(void); | 67 | extern struct proc_dir_entry *acpi_lock_battery_dir(void); |
70 | extern void *acpi_unlock_battery_dir(struct proc_dir_entry *acpi_battery_dir); | 68 | extern void *acpi_unlock_battery_dir(struct proc_dir_entry *acpi_battery_dir); |
71 | 69 | ||
72 | static int acpi_battery_add(struct acpi_device *device); | 70 | enum acpi_battery_files { |
73 | static int acpi_battery_remove(struct acpi_device *device, int type); | 71 | info_tag = 0, |
74 | static int acpi_battery_resume(struct acpi_device *device); | 72 | state_tag, |
73 | alarm_tag, | ||
74 | ACPI_BATTERY_NUMFILES, | ||
75 | }; | ||
76 | |||
77 | #endif | ||
75 | 78 | ||
76 | static const struct acpi_device_id battery_device_ids[] = { | 79 | static const struct acpi_device_id battery_device_ids[] = { |
77 | {"PNP0C0A", 0}, | 80 | {"PNP0C0A", 0}, |
78 | {"", 0}, | 81 | {"", 0}, |
79 | }; | 82 | }; |
80 | MODULE_DEVICE_TABLE(acpi, battery_device_ids); | ||
81 | |||
82 | static struct acpi_driver acpi_battery_driver = { | ||
83 | .name = "battery", | ||
84 | .class = ACPI_BATTERY_CLASS, | ||
85 | .ids = battery_device_ids, | ||
86 | .ops = { | ||
87 | .add = acpi_battery_add, | ||
88 | .resume = acpi_battery_resume, | ||
89 | .remove = acpi_battery_remove, | ||
90 | }, | ||
91 | }; | ||
92 | 83 | ||
93 | struct acpi_battery_state { | 84 | MODULE_DEVICE_TABLE(acpi, battery_device_ids); |
94 | acpi_integer state; | ||
95 | acpi_integer present_rate; | ||
96 | acpi_integer remaining_capacity; | ||
97 | acpi_integer present_voltage; | ||
98 | }; | ||
99 | |||
100 | struct acpi_battery_info { | ||
101 | acpi_integer power_unit; | ||
102 | acpi_integer design_capacity; | ||
103 | acpi_integer last_full_capacity; | ||
104 | acpi_integer battery_technology; | ||
105 | acpi_integer design_voltage; | ||
106 | acpi_integer design_capacity_warning; | ||
107 | acpi_integer design_capacity_low; | ||
108 | acpi_integer battery_capacity_granularity_1; | ||
109 | acpi_integer battery_capacity_granularity_2; | ||
110 | acpi_string model_number; | ||
111 | acpi_string serial_number; | ||
112 | acpi_string battery_type; | ||
113 | acpi_string oem_info; | ||
114 | }; | ||
115 | |||
116 | enum acpi_battery_files{ | ||
117 | ACPI_BATTERY_INFO = 0, | ||
118 | ACPI_BATTERY_STATE, | ||
119 | ACPI_BATTERY_ALARM, | ||
120 | ACPI_BATTERY_NUMFILES, | ||
121 | }; | ||
122 | 85 | ||
123 | struct acpi_battery_flags { | ||
124 | u8 battery_present_prev; | ||
125 | u8 alarm_present; | ||
126 | u8 init_update; | ||
127 | u8 update[ACPI_BATTERY_NUMFILES]; | ||
128 | u8 power_unit; | ||
129 | }; | ||
130 | 86 | ||
131 | struct acpi_battery { | 87 | struct acpi_battery { |
132 | struct mutex mutex; | 88 | struct mutex lock; |
89 | struct power_supply bat; | ||
133 | struct acpi_device *device; | 90 | struct acpi_device *device; |
134 | struct acpi_battery_flags flags; | 91 | unsigned long update_time; |
135 | struct acpi_buffer bif_data; | 92 | int current_now; |
136 | struct acpi_buffer bst_data; | 93 | int capacity_now; |
137 | unsigned long alarm; | 94 | int voltage_now; |
138 | unsigned long update_time[ACPI_BATTERY_NUMFILES]; | 95 | int design_capacity; |
96 | int full_charge_capacity; | ||
97 | int technology; | ||
98 | int design_voltage; | ||
99 | int design_capacity_warning; | ||
100 | int design_capacity_low; | ||
101 | int capacity_granularity_1; | ||
102 | int capacity_granularity_2; | ||
103 | int alarm; | ||
104 | char model_number[32]; | ||
105 | char serial_number[32]; | ||
106 | char type[32]; | ||
107 | char oem_info[32]; | ||
108 | int state; | ||
109 | int power_unit; | ||
110 | u8 alarm_present; | ||
139 | }; | 111 | }; |
140 | 112 | ||
113 | #define to_acpi_battery(x) container_of(x, struct acpi_battery, bat); | ||
114 | |||
141 | inline int acpi_battery_present(struct acpi_battery *battery) | 115 | inline int acpi_battery_present(struct acpi_battery *battery) |
142 | { | 116 | { |
143 | return battery->device->status.battery_present; | 117 | return battery->device->status.battery_present; |
144 | } | 118 | } |
145 | inline char *acpi_battery_power_units(struct acpi_battery *battery) | ||
146 | { | ||
147 | if (battery->flags.power_unit) | ||
148 | return ACPI_BATTERY_UNITS_AMPS; | ||
149 | else | ||
150 | return ACPI_BATTERY_UNITS_WATTS; | ||
151 | } | ||
152 | 119 | ||
153 | inline acpi_handle acpi_battery_handle(struct acpi_battery *battery) | 120 | static int acpi_battery_technology(struct acpi_battery *battery) |
154 | { | 121 | { |
155 | return battery->device->handle; | 122 | if (!strcasecmp("NiCd", battery->type)) |
123 | return POWER_SUPPLY_TECHNOLOGY_NiCd; | ||
124 | if (!strcasecmp("NiMH", battery->type)) | ||
125 | return POWER_SUPPLY_TECHNOLOGY_NiMH; | ||
126 | if (!strcasecmp("LION", battery->type)) | ||
127 | return POWER_SUPPLY_TECHNOLOGY_LION; | ||
128 | if (!strcasecmp("LiP", battery->type)) | ||
129 | return POWER_SUPPLY_TECHNOLOGY_LIPO; | ||
130 | return POWER_SUPPLY_TECHNOLOGY_UNKNOWN; | ||
156 | } | 131 | } |
157 | 132 | ||
158 | /* -------------------------------------------------------------------------- | 133 | static int acpi_battery_get_property(struct power_supply *psy, |
159 | Battery Management | 134 | enum power_supply_property psp, |
160 | -------------------------------------------------------------------------- */ | 135 | union power_supply_propval *val) |
161 | |||
162 | static void acpi_battery_check_result(struct acpi_battery *battery, int result) | ||
163 | { | 136 | { |
164 | if (!battery) | 137 | struct acpi_battery *battery = to_acpi_battery(psy); |
165 | return; | ||
166 | 138 | ||
167 | if (result) { | 139 | if ((!acpi_battery_present(battery)) && |
168 | battery->flags.init_update = 1; | 140 | psp != POWER_SUPPLY_PROP_PRESENT) |
141 | return -ENODEV; | ||
142 | switch (psp) { | ||
143 | case POWER_SUPPLY_PROP_STATUS: | ||
144 | if (battery->state & 0x01) | ||
145 | val->intval = POWER_SUPPLY_STATUS_DISCHARGING; | ||
146 | else if (battery->state & 0x02) | ||
147 | val->intval = POWER_SUPPLY_STATUS_CHARGING; | ||
148 | else if (battery->state == 0) | ||
149 | val->intval = POWER_SUPPLY_STATUS_FULL; | ||
150 | break; | ||
151 | case POWER_SUPPLY_PROP_PRESENT: | ||
152 | val->intval = acpi_battery_present(battery); | ||
153 | break; | ||
154 | case POWER_SUPPLY_PROP_TECHNOLOGY: | ||
155 | val->intval = acpi_battery_technology(battery); | ||
156 | break; | ||
157 | case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN: | ||
158 | val->intval = battery->design_voltage * 1000; | ||
159 | break; | ||
160 | case POWER_SUPPLY_PROP_VOLTAGE_NOW: | ||
161 | val->intval = battery->voltage_now * 1000; | ||
162 | break; | ||
163 | case POWER_SUPPLY_PROP_CURRENT_NOW: | ||
164 | val->intval = battery->current_now * 1000; | ||
165 | break; | ||
166 | case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN: | ||
167 | case POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN: | ||
168 | val->intval = battery->design_capacity * 1000; | ||
169 | break; | ||
170 | case POWER_SUPPLY_PROP_CHARGE_FULL: | ||
171 | case POWER_SUPPLY_PROP_ENERGY_FULL: | ||
172 | val->intval = battery->full_charge_capacity * 1000; | ||
173 | break; | ||
174 | case POWER_SUPPLY_PROP_CHARGE_NOW: | ||
175 | case POWER_SUPPLY_PROP_ENERGY_NOW: | ||
176 | val->intval = battery->capacity_now * 1000; | ||
177 | break; | ||
178 | case POWER_SUPPLY_PROP_MODEL_NAME: | ||
179 | val->strval = battery->model_number; | ||
180 | break; | ||
181 | case POWER_SUPPLY_PROP_MANUFACTURER: | ||
182 | val->strval = battery->oem_info; | ||
183 | break; | ||
184 | default: | ||
185 | return -EINVAL; | ||
169 | } | 186 | } |
187 | return 0; | ||
170 | } | 188 | } |
171 | 189 | ||
172 | static int acpi_battery_extract_package(struct acpi_battery *battery, | 190 | static enum power_supply_property charge_battery_props[] = { |
173 | union acpi_object *package, | 191 | POWER_SUPPLY_PROP_STATUS, |
174 | struct acpi_buffer *format, | 192 | POWER_SUPPLY_PROP_PRESENT, |
175 | struct acpi_buffer *data, | 193 | POWER_SUPPLY_PROP_TECHNOLOGY, |
176 | char *package_name) | 194 | POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN, |
195 | POWER_SUPPLY_PROP_VOLTAGE_NOW, | ||
196 | POWER_SUPPLY_PROP_CURRENT_NOW, | ||
197 | POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, | ||
198 | POWER_SUPPLY_PROP_CHARGE_FULL, | ||
199 | POWER_SUPPLY_PROP_CHARGE_NOW, | ||
200 | POWER_SUPPLY_PROP_MODEL_NAME, | ||
201 | POWER_SUPPLY_PROP_MANUFACTURER, | ||
202 | }; | ||
203 | |||
204 | static enum power_supply_property energy_battery_props[] = { | ||
205 | POWER_SUPPLY_PROP_STATUS, | ||
206 | POWER_SUPPLY_PROP_PRESENT, | ||
207 | POWER_SUPPLY_PROP_TECHNOLOGY, | ||
208 | POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN, | ||
209 | POWER_SUPPLY_PROP_VOLTAGE_NOW, | ||
210 | POWER_SUPPLY_PROP_CURRENT_NOW, | ||
211 | POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN, | ||
212 | POWER_SUPPLY_PROP_ENERGY_FULL, | ||
213 | POWER_SUPPLY_PROP_ENERGY_NOW, | ||
214 | POWER_SUPPLY_PROP_MODEL_NAME, | ||
215 | POWER_SUPPLY_PROP_MANUFACTURER, | ||
216 | }; | ||
217 | |||
218 | #ifdef CONFIG_ACPI_PROCFS | ||
219 | inline char *acpi_battery_units(struct acpi_battery *battery) | ||
177 | { | 220 | { |
178 | acpi_status status = AE_OK; | 221 | return (battery->power_unit)?"mA":"mW"; |
179 | struct acpi_buffer data_null = { 0, NULL }; | 222 | } |
223 | #endif | ||
180 | 224 | ||
181 | status = acpi_extract_package(package, format, &data_null); | 225 | /* -------------------------------------------------------------------------- |
182 | if (status != AE_BUFFER_OVERFLOW) { | 226 | Battery Management |
183 | ACPI_EXCEPTION((AE_INFO, status, "Extracting size %s", | 227 | -------------------------------------------------------------------------- */ |
184 | package_name)); | 228 | struct acpi_offsets { |
185 | return -ENODEV; | 229 | size_t offset; /* offset inside struct acpi_sbs_battery */ |
186 | } | 230 | u8 mode; /* int or string? */ |
231 | }; | ||
187 | 232 | ||
188 | if (data_null.length != data->length) { | 233 | static struct acpi_offsets state_offsets[] = { |
189 | kfree(data->pointer); | 234 | {offsetof(struct acpi_battery, state), 0}, |
190 | data->pointer = kzalloc(data_null.length, GFP_KERNEL); | 235 | {offsetof(struct acpi_battery, current_now), 0}, |
191 | if (!data->pointer) { | 236 | {offsetof(struct acpi_battery, capacity_now), 0}, |
192 | ACPI_EXCEPTION((AE_INFO, AE_NO_MEMORY, "kzalloc()")); | 237 | {offsetof(struct acpi_battery, voltage_now), 0}, |
193 | return -ENOMEM; | 238 | }; |
194 | } | ||
195 | data->length = data_null.length; | ||
196 | } | ||
197 | 239 | ||
198 | status = acpi_extract_package(package, format, data); | 240 | static struct acpi_offsets info_offsets[] = { |
199 | if (ACPI_FAILURE(status)) { | 241 | {offsetof(struct acpi_battery, power_unit), 0}, |
200 | ACPI_EXCEPTION((AE_INFO, status, "Extracting %s", | 242 | {offsetof(struct acpi_battery, design_capacity), 0}, |
201 | package_name)); | 243 | {offsetof(struct acpi_battery, full_charge_capacity), 0}, |
202 | return -ENODEV; | 244 | {offsetof(struct acpi_battery, technology), 0}, |
203 | } | 245 | {offsetof(struct acpi_battery, design_voltage), 0}, |
246 | {offsetof(struct acpi_battery, design_capacity_warning), 0}, | ||
247 | {offsetof(struct acpi_battery, design_capacity_low), 0}, | ||
248 | {offsetof(struct acpi_battery, capacity_granularity_1), 0}, | ||
249 | {offsetof(struct acpi_battery, capacity_granularity_2), 0}, | ||
250 | {offsetof(struct acpi_battery, model_number), 1}, | ||
251 | {offsetof(struct acpi_battery, serial_number), 1}, | ||
252 | {offsetof(struct acpi_battery, type), 1}, | ||
253 | {offsetof(struct acpi_battery, oem_info), 1}, | ||
254 | }; | ||
204 | 255 | ||
256 | static int extract_package(struct acpi_battery *battery, | ||
257 | union acpi_object *package, | ||
258 | struct acpi_offsets *offsets, int num) | ||
259 | { | ||
260 | int i, *x; | ||
261 | union acpi_object *element; | ||
262 | if (package->type != ACPI_TYPE_PACKAGE) | ||
263 | return -EFAULT; | ||
264 | for (i = 0; i < num; ++i) { | ||
265 | if (package->package.count <= i) | ||
266 | return -EFAULT; | ||
267 | element = &package->package.elements[i]; | ||
268 | if (offsets[i].mode) { | ||
269 | if (element->type != ACPI_TYPE_STRING && | ||
270 | element->type != ACPI_TYPE_BUFFER) | ||
271 | return -EFAULT; | ||
272 | strncpy((u8 *)battery + offsets[i].offset, | ||
273 | element->string.pointer, 32); | ||
274 | } else { | ||
275 | if (element->type != ACPI_TYPE_INTEGER) | ||
276 | return -EFAULT; | ||
277 | x = (int *)((u8 *)battery + offsets[i].offset); | ||
278 | *x = element->integer.value; | ||
279 | } | ||
280 | } | ||
205 | return 0; | 281 | return 0; |
206 | } | 282 | } |
207 | 283 | ||
208 | static int acpi_battery_get_status(struct acpi_battery *battery) | 284 | static int acpi_battery_get_status(struct acpi_battery *battery) |
209 | { | 285 | { |
210 | int result = 0; | 286 | if (acpi_bus_get_status(battery->device)) { |
211 | |||
212 | result = acpi_bus_get_status(battery->device); | ||
213 | if (result) { | ||
214 | ACPI_EXCEPTION((AE_INFO, AE_ERROR, "Evaluating _STA")); | 287 | ACPI_EXCEPTION((AE_INFO, AE_ERROR, "Evaluating _STA")); |
215 | return -ENODEV; | 288 | return -ENODEV; |
216 | } | 289 | } |
217 | return result; | 290 | return 0; |
218 | } | 291 | } |
219 | 292 | ||
220 | static int acpi_battery_get_info(struct acpi_battery *battery) | 293 | static int acpi_battery_get_info(struct acpi_battery *battery) |
221 | { | 294 | { |
222 | int result = 0; | 295 | int result = -EFAULT; |
223 | acpi_status status = 0; | 296 | acpi_status status = 0; |
224 | struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; | 297 | struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; |
225 | struct acpi_buffer format = { sizeof(ACPI_BATTERY_FORMAT_BIF), | ||
226 | ACPI_BATTERY_FORMAT_BIF | ||
227 | }; | ||
228 | union acpi_object *package = NULL; | ||
229 | struct acpi_buffer *data = NULL; | ||
230 | struct acpi_battery_info *bif = NULL; | ||
231 | |||
232 | battery->update_time[ACPI_BATTERY_INFO] = get_seconds(); | ||
233 | 298 | ||
234 | if (!acpi_battery_present(battery)) | 299 | if (!acpi_battery_present(battery)) |
235 | return 0; | 300 | return 0; |
301 | mutex_lock(&battery->lock); | ||
302 | status = acpi_evaluate_object(battery->device->handle, "_BIF", | ||
303 | NULL, &buffer); | ||
304 | mutex_unlock(&battery->lock); | ||
236 | 305 | ||
237 | /* Evaluate _BIF */ | ||
238 | |||
239 | status = | ||
240 | acpi_evaluate_object(acpi_battery_handle(battery), "_BIF", NULL, | ||
241 | &buffer); | ||
242 | if (ACPI_FAILURE(status)) { | 306 | if (ACPI_FAILURE(status)) { |
243 | ACPI_EXCEPTION((AE_INFO, status, "Evaluating _BIF")); | 307 | ACPI_EXCEPTION((AE_INFO, status, "Evaluating _BIF")); |
244 | return -ENODEV; | 308 | return -ENODEV; |
245 | } | 309 | } |
246 | 310 | ||
247 | package = buffer.pointer; | 311 | result = extract_package(battery, buffer.pointer, |
248 | 312 | info_offsets, ARRAY_SIZE(info_offsets)); | |
249 | data = &battery->bif_data; | ||
250 | |||
251 | /* Extract Package Data */ | ||
252 | |||
253 | result = | ||
254 | acpi_battery_extract_package(battery, package, &format, data, | ||
255 | "_BIF"); | ||
256 | if (result) | ||
257 | goto end; | ||
258 | |||
259 | end: | ||
260 | |||
261 | kfree(buffer.pointer); | 313 | kfree(buffer.pointer); |
262 | |||
263 | if (!result) { | ||
264 | bif = data->pointer; | ||
265 | battery->flags.power_unit = bif->power_unit; | ||
266 | } | ||
267 | |||
268 | return result; | 314 | return result; |
269 | } | 315 | } |
270 | 316 | ||
@@ -273,342 +319,203 @@ static int acpi_battery_get_state(struct acpi_battery *battery) | |||
273 | int result = 0; | 319 | int result = 0; |
274 | acpi_status status = 0; | 320 | acpi_status status = 0; |
275 | struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; | 321 | struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; |
276 | struct acpi_buffer format = { sizeof(ACPI_BATTERY_FORMAT_BST), | ||
277 | ACPI_BATTERY_FORMAT_BST | ||
278 | }; | ||
279 | union acpi_object *package = NULL; | ||
280 | struct acpi_buffer *data = NULL; | ||
281 | |||
282 | battery->update_time[ACPI_BATTERY_STATE] = get_seconds(); | ||
283 | 322 | ||
284 | if (!acpi_battery_present(battery)) | 323 | if (!acpi_battery_present(battery)) |
285 | return 0; | 324 | return 0; |
286 | 325 | ||
287 | /* Evaluate _BST */ | 326 | if (battery->update_time && |
327 | time_before(jiffies, battery->update_time + | ||
328 | msecs_to_jiffies(cache_time))) | ||
329 | return 0; | ||
330 | |||
331 | mutex_lock(&battery->lock); | ||
332 | status = acpi_evaluate_object(battery->device->handle, "_BST", | ||
333 | NULL, &buffer); | ||
334 | mutex_unlock(&battery->lock); | ||
288 | 335 | ||
289 | status = | ||
290 | acpi_evaluate_object(acpi_battery_handle(battery), "_BST", NULL, | ||
291 | &buffer); | ||
292 | if (ACPI_FAILURE(status)) { | 336 | if (ACPI_FAILURE(status)) { |
293 | ACPI_EXCEPTION((AE_INFO, status, "Evaluating _BST")); | 337 | ACPI_EXCEPTION((AE_INFO, status, "Evaluating _BST")); |
294 | return -ENODEV; | 338 | return -ENODEV; |
295 | } | 339 | } |
296 | 340 | ||
297 | package = buffer.pointer; | 341 | result = extract_package(battery, buffer.pointer, |
298 | 342 | state_offsets, ARRAY_SIZE(state_offsets)); | |
299 | data = &battery->bst_data; | 343 | battery->update_time = jiffies; |
300 | |||
301 | /* Extract Package Data */ | ||
302 | |||
303 | result = | ||
304 | acpi_battery_extract_package(battery, package, &format, data, | ||
305 | "_BST"); | ||
306 | if (result) | ||
307 | goto end; | ||
308 | |||
309 | end: | ||
310 | kfree(buffer.pointer); | 344 | kfree(buffer.pointer); |
311 | |||
312 | return result; | 345 | return result; |
313 | } | 346 | } |
314 | 347 | ||
315 | static int acpi_battery_get_alarm(struct acpi_battery *battery) | 348 | static int acpi_battery_set_alarm(struct acpi_battery *battery) |
316 | { | ||
317 | battery->update_time[ACPI_BATTERY_ALARM] = get_seconds(); | ||
318 | |||
319 | return 0; | ||
320 | } | ||
321 | |||
322 | static int acpi_battery_set_alarm(struct acpi_battery *battery, | ||
323 | unsigned long alarm) | ||
324 | { | 349 | { |
325 | acpi_status status = 0; | 350 | acpi_status status = 0; |
326 | union acpi_object arg0 = { ACPI_TYPE_INTEGER }; | 351 | union acpi_object arg0 = { .type = ACPI_TYPE_INTEGER }; |
327 | struct acpi_object_list arg_list = { 1, &arg0 }; | 352 | struct acpi_object_list arg_list = { 1, &arg0 }; |
328 | 353 | ||
329 | battery->update_time[ACPI_BATTERY_ALARM] = get_seconds(); | 354 | if (!acpi_battery_present(battery)|| !battery->alarm_present) |
330 | |||
331 | if (!acpi_battery_present(battery)) | ||
332 | return -ENODEV; | 355 | return -ENODEV; |
333 | 356 | ||
334 | if (!battery->flags.alarm_present) | 357 | arg0.integer.value = battery->alarm; |
335 | return -ENODEV; | ||
336 | |||
337 | arg0.integer.value = alarm; | ||
338 | 358 | ||
339 | status = | 359 | mutex_lock(&battery->lock); |
340 | acpi_evaluate_object(acpi_battery_handle(battery), "_BTP", | 360 | status = acpi_evaluate_object(battery->device->handle, "_BTP", |
341 | &arg_list, NULL); | 361 | &arg_list, NULL); |
362 | mutex_unlock(&battery->lock); | ||
363 | |||
342 | if (ACPI_FAILURE(status)) | 364 | if (ACPI_FAILURE(status)) |
343 | return -ENODEV; | 365 | return -ENODEV; |
344 | 366 | ||
345 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Alarm set to %d\n", (u32) alarm)); | 367 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Alarm set to %d\n", battery->alarm)); |
346 | |||
347 | battery->alarm = alarm; | ||
348 | |||
349 | return 0; | 368 | return 0; |
350 | } | 369 | } |
351 | 370 | ||
352 | static int acpi_battery_init_alarm(struct acpi_battery *battery) | 371 | static int acpi_battery_init_alarm(struct acpi_battery *battery) |
353 | { | 372 | { |
354 | int result = 0; | ||
355 | acpi_status status = AE_OK; | 373 | acpi_status status = AE_OK; |
356 | acpi_handle handle = NULL; | 374 | acpi_handle handle = NULL; |
357 | struct acpi_battery_info *bif = battery->bif_data.pointer; | ||
358 | unsigned long alarm = battery->alarm; | ||
359 | 375 | ||
360 | /* See if alarms are supported, and if so, set default */ | 376 | /* See if alarms are supported, and if so, set default */ |
361 | 377 | status = acpi_get_handle(battery->device->handle, "_BTP", &handle); | |
362 | status = acpi_get_handle(acpi_battery_handle(battery), "_BTP", &handle); | 378 | if (ACPI_FAILURE(status)) { |
363 | if (ACPI_SUCCESS(status)) { | 379 | battery->alarm_present = 0; |
364 | battery->flags.alarm_present = 1; | 380 | return 0; |
365 | if (!alarm && bif) { | ||
366 | alarm = bif->design_capacity_warning; | ||
367 | } | ||
368 | result = acpi_battery_set_alarm(battery, alarm); | ||
369 | if (result) | ||
370 | goto end; | ||
371 | } else { | ||
372 | battery->flags.alarm_present = 0; | ||
373 | } | 381 | } |
374 | 382 | battery->alarm_present = 1; | |
375 | end: | 383 | if (!battery->alarm) |
376 | 384 | battery->alarm = battery->design_capacity_warning; | |
377 | return result; | 385 | return acpi_battery_set_alarm(battery); |
378 | } | 386 | } |
379 | 387 | ||
380 | static int acpi_battery_init_update(struct acpi_battery *battery) | 388 | static int acpi_battery_update(struct acpi_battery *battery) |
381 | { | 389 | { |
382 | int result = 0; | 390 | int saved_present = acpi_battery_present(battery); |
383 | 391 | int result = acpi_battery_get_status(battery); | |
384 | result = acpi_battery_get_status(battery); | 392 | if (result || !acpi_battery_present(battery)) |
385 | if (result) | ||
386 | return result; | 393 | return result; |
387 | 394 | if (saved_present != acpi_battery_present(battery) || | |
388 | battery->flags.battery_present_prev = acpi_battery_present(battery); | 395 | !battery->update_time) { |
389 | 396 | battery->update_time = 0; | |
390 | if (acpi_battery_present(battery)) { | ||
391 | result = acpi_battery_get_info(battery); | 397 | result = acpi_battery_get_info(battery); |
392 | if (result) | 398 | if (result) |
393 | return result; | 399 | return result; |
394 | result = acpi_battery_get_state(battery); | 400 | if (battery->power_unit) { |
395 | if (result) | 401 | battery->bat.properties = charge_battery_props; |
396 | return result; | 402 | battery->bat.num_properties = |
397 | 403 | ARRAY_SIZE(charge_battery_props); | |
398 | acpi_battery_init_alarm(battery); | ||
399 | } | ||
400 | |||
401 | return result; | ||
402 | } | ||
403 | |||
404 | static int acpi_battery_update(struct acpi_battery *battery, | ||
405 | int update, int *update_result_ptr) | ||
406 | { | ||
407 | int result = 0; | ||
408 | int update_result = ACPI_BATTERY_NONE_UPDATE; | ||
409 | |||
410 | if (!acpi_battery_present(battery)) { | ||
411 | update = 1; | ||
412 | } | ||
413 | |||
414 | if (battery->flags.init_update) { | ||
415 | result = acpi_battery_init_update(battery); | ||
416 | if (result) | ||
417 | goto end; | ||
418 | update_result = ACPI_BATTERY_INIT_UPDATE; | ||
419 | } else if (update) { | ||
420 | result = acpi_battery_get_status(battery); | ||
421 | if (result) | ||
422 | goto end; | ||
423 | if ((!battery->flags.battery_present_prev & acpi_battery_present(battery)) | ||
424 | || (battery->flags.battery_present_prev & !acpi_battery_present(battery))) { | ||
425 | result = acpi_battery_init_update(battery); | ||
426 | if (result) | ||
427 | goto end; | ||
428 | update_result = ACPI_BATTERY_INIT_UPDATE; | ||
429 | } else { | 404 | } else { |
430 | update_result = ACPI_BATTERY_EASY_UPDATE; | 405 | battery->bat.properties = energy_battery_props; |
406 | battery->bat.num_properties = | ||
407 | ARRAY_SIZE(energy_battery_props); | ||
431 | } | 408 | } |
409 | acpi_battery_init_alarm(battery); | ||
432 | } | 410 | } |
433 | 411 | return acpi_battery_get_state(battery); | |
434 | end: | ||
435 | |||
436 | battery->flags.init_update = (result != 0); | ||
437 | |||
438 | *update_result_ptr = update_result; | ||
439 | |||
440 | return result; | ||
441 | } | ||
442 | |||
443 | static void acpi_battery_notify_update(struct acpi_battery *battery) | ||
444 | { | ||
445 | acpi_battery_get_status(battery); | ||
446 | |||
447 | if (battery->flags.init_update) { | ||
448 | return; | ||
449 | } | ||
450 | |||
451 | if ((!battery->flags.battery_present_prev & | ||
452 | acpi_battery_present(battery)) || | ||
453 | (battery->flags.battery_present_prev & | ||
454 | !acpi_battery_present(battery))) { | ||
455 | battery->flags.init_update = 1; | ||
456 | } else { | ||
457 | battery->flags.update[ACPI_BATTERY_INFO] = 1; | ||
458 | battery->flags.update[ACPI_BATTERY_STATE] = 1; | ||
459 | battery->flags.update[ACPI_BATTERY_ALARM] = 1; | ||
460 | } | ||
461 | } | 412 | } |
462 | 413 | ||
463 | /* -------------------------------------------------------------------------- | 414 | /* -------------------------------------------------------------------------- |
464 | FS Interface (/proc) | 415 | FS Interface (/proc) |
465 | -------------------------------------------------------------------------- */ | 416 | -------------------------------------------------------------------------- */ |
466 | 417 | ||
418 | #ifdef CONFIG_ACPI_PROCFS | ||
467 | static struct proc_dir_entry *acpi_battery_dir; | 419 | static struct proc_dir_entry *acpi_battery_dir; |
468 | 420 | ||
469 | static int acpi_battery_print_info(struct seq_file *seq, int result) | 421 | static int acpi_battery_print_info(struct seq_file *seq, int result) |
470 | { | 422 | { |
471 | struct acpi_battery *battery = seq->private; | 423 | struct acpi_battery *battery = seq->private; |
472 | struct acpi_battery_info *bif = NULL; | ||
473 | char *units = "?"; | ||
474 | 424 | ||
475 | if (result) | 425 | if (result) |
476 | goto end; | 426 | goto end; |
477 | 427 | ||
478 | if (acpi_battery_present(battery)) | 428 | seq_printf(seq, "present: %s\n", |
479 | seq_printf(seq, "present: yes\n"); | 429 | acpi_battery_present(battery)?"yes":"no"); |
480 | else { | 430 | if (!acpi_battery_present(battery)) |
481 | seq_printf(seq, "present: no\n"); | ||
482 | goto end; | ||
483 | } | ||
484 | |||
485 | bif = battery->bif_data.pointer; | ||
486 | if (!bif) { | ||
487 | ACPI_EXCEPTION((AE_INFO, AE_ERROR, "BIF buffer is NULL")); | ||
488 | result = -ENODEV; | ||
489 | goto end; | 431 | goto end; |
490 | } | 432 | if (battery->design_capacity == ACPI_BATTERY_VALUE_UNKNOWN) |
491 | |||
492 | /* Battery Units */ | ||
493 | |||
494 | units = acpi_battery_power_units(battery); | ||
495 | |||
496 | if (bif->design_capacity == ACPI_BATTERY_VALUE_UNKNOWN) | ||
497 | seq_printf(seq, "design capacity: unknown\n"); | 433 | seq_printf(seq, "design capacity: unknown\n"); |
498 | else | 434 | else |
499 | seq_printf(seq, "design capacity: %d %sh\n", | 435 | seq_printf(seq, "design capacity: %d %sh\n", |
500 | (u32) bif->design_capacity, units); | 436 | battery->design_capacity, |
437 | acpi_battery_units(battery)); | ||
501 | 438 | ||
502 | if (bif->last_full_capacity == ACPI_BATTERY_VALUE_UNKNOWN) | 439 | if (battery->full_charge_capacity == ACPI_BATTERY_VALUE_UNKNOWN) |
503 | seq_printf(seq, "last full capacity: unknown\n"); | 440 | seq_printf(seq, "last full capacity: unknown\n"); |
504 | else | 441 | else |
505 | seq_printf(seq, "last full capacity: %d %sh\n", | 442 | seq_printf(seq, "last full capacity: %d %sh\n", |
506 | (u32) bif->last_full_capacity, units); | 443 | battery->full_charge_capacity, |
444 | acpi_battery_units(battery)); | ||
507 | 445 | ||
508 | switch ((u32) bif->battery_technology) { | 446 | seq_printf(seq, "battery technology: %srechargeable\n", |
509 | case 0: | 447 | (!battery->technology)?"non-":""); |
510 | seq_printf(seq, "battery technology: non-rechargeable\n"); | ||
511 | break; | ||
512 | case 1: | ||
513 | seq_printf(seq, "battery technology: rechargeable\n"); | ||
514 | break; | ||
515 | default: | ||
516 | seq_printf(seq, "battery technology: unknown\n"); | ||
517 | break; | ||
518 | } | ||
519 | 448 | ||
520 | if (bif->design_voltage == ACPI_BATTERY_VALUE_UNKNOWN) | 449 | if (battery->design_voltage == ACPI_BATTERY_VALUE_UNKNOWN) |
521 | seq_printf(seq, "design voltage: unknown\n"); | 450 | seq_printf(seq, "design voltage: unknown\n"); |
522 | else | 451 | else |
523 | seq_printf(seq, "design voltage: %d mV\n", | 452 | seq_printf(seq, "design voltage: %d mV\n", |
524 | (u32) bif->design_voltage); | 453 | battery->design_voltage); |
525 | seq_printf(seq, "design capacity warning: %d %sh\n", | 454 | seq_printf(seq, "design capacity warning: %d %sh\n", |
526 | (u32) bif->design_capacity_warning, units); | 455 | battery->design_capacity_warning, |
456 | acpi_battery_units(battery)); | ||
527 | seq_printf(seq, "design capacity low: %d %sh\n", | 457 | seq_printf(seq, "design capacity low: %d %sh\n", |
528 | (u32) bif->design_capacity_low, units); | 458 | battery->design_capacity_low, |
459 | acpi_battery_units(battery)); | ||
529 | seq_printf(seq, "capacity granularity 1: %d %sh\n", | 460 | seq_printf(seq, "capacity granularity 1: %d %sh\n", |
530 | (u32) bif->battery_capacity_granularity_1, units); | 461 | battery->capacity_granularity_1, |
462 | acpi_battery_units(battery)); | ||
531 | seq_printf(seq, "capacity granularity 2: %d %sh\n", | 463 | seq_printf(seq, "capacity granularity 2: %d %sh\n", |
532 | (u32) bif->battery_capacity_granularity_2, units); | 464 | battery->capacity_granularity_2, |
533 | seq_printf(seq, "model number: %s\n", bif->model_number); | 465 | acpi_battery_units(battery)); |
534 | seq_printf(seq, "serial number: %s\n", bif->serial_number); | 466 | seq_printf(seq, "model number: %s\n", battery->model_number); |
535 | seq_printf(seq, "battery type: %s\n", bif->battery_type); | 467 | seq_printf(seq, "serial number: %s\n", battery->serial_number); |
536 | seq_printf(seq, "OEM info: %s\n", bif->oem_info); | 468 | seq_printf(seq, "battery type: %s\n", battery->type); |
537 | 469 | seq_printf(seq, "OEM info: %s\n", battery->oem_info); | |
538 | end: | 470 | end: |
539 | |||
540 | if (result) | 471 | if (result) |
541 | seq_printf(seq, "ERROR: Unable to read battery info\n"); | 472 | seq_printf(seq, "ERROR: Unable to read battery info\n"); |
542 | |||
543 | return result; | 473 | return result; |
544 | } | 474 | } |
545 | 475 | ||
546 | static int acpi_battery_print_state(struct seq_file *seq, int result) | 476 | static int acpi_battery_print_state(struct seq_file *seq, int result) |
547 | { | 477 | { |
548 | struct acpi_battery *battery = seq->private; | 478 | struct acpi_battery *battery = seq->private; |
549 | struct acpi_battery_state *bst = NULL; | ||
550 | char *units = "?"; | ||
551 | 479 | ||
552 | if (result) | 480 | if (result) |
553 | goto end; | 481 | goto end; |
554 | 482 | ||
555 | if (acpi_battery_present(battery)) | 483 | seq_printf(seq, "present: %s\n", |
556 | seq_printf(seq, "present: yes\n"); | 484 | acpi_battery_present(battery)?"yes":"no"); |
557 | else { | 485 | if (!acpi_battery_present(battery)) |
558 | seq_printf(seq, "present: no\n"); | ||
559 | goto end; | ||
560 | } | ||
561 | |||
562 | bst = battery->bst_data.pointer; | ||
563 | if (!bst) { | ||
564 | ACPI_EXCEPTION((AE_INFO, AE_ERROR, "BST buffer is NULL")); | ||
565 | result = -ENODEV; | ||
566 | goto end; | 486 | goto end; |
567 | } | ||
568 | |||
569 | /* Battery Units */ | ||
570 | |||
571 | units = acpi_battery_power_units(battery); | ||
572 | |||
573 | if (!(bst->state & 0x04)) | ||
574 | seq_printf(seq, "capacity state: ok\n"); | ||
575 | else | ||
576 | seq_printf(seq, "capacity state: critical\n"); | ||
577 | 487 | ||
578 | if ((bst->state & 0x01) && (bst->state & 0x02)) { | 488 | seq_printf(seq, "capacity state: %s\n", |
489 | (battery->state & 0x04)?"critical":"ok"); | ||
490 | if ((battery->state & 0x01) && (battery->state & 0x02)) | ||
579 | seq_printf(seq, | 491 | seq_printf(seq, |
580 | "charging state: charging/discharging\n"); | 492 | "charging state: charging/discharging\n"); |
581 | } else if (bst->state & 0x01) | 493 | else if (battery->state & 0x01) |
582 | seq_printf(seq, "charging state: discharging\n"); | 494 | seq_printf(seq, "charging state: discharging\n"); |
583 | else if (bst->state & 0x02) | 495 | else if (battery->state & 0x02) |
584 | seq_printf(seq, "charging state: charging\n"); | 496 | seq_printf(seq, "charging state: charging\n"); |
585 | else { | 497 | else |
586 | seq_printf(seq, "charging state: charged\n"); | 498 | seq_printf(seq, "charging state: charged\n"); |
587 | } | ||
588 | 499 | ||
589 | if (bst->present_rate == ACPI_BATTERY_VALUE_UNKNOWN) | 500 | if (battery->current_now == ACPI_BATTERY_VALUE_UNKNOWN) |
590 | seq_printf(seq, "present rate: unknown\n"); | 501 | seq_printf(seq, "present rate: unknown\n"); |
591 | else | 502 | else |
592 | seq_printf(seq, "present rate: %d %s\n", | 503 | seq_printf(seq, "present rate: %d %s\n", |
593 | (u32) bst->present_rate, units); | 504 | battery->current_now, acpi_battery_units(battery)); |
594 | 505 | ||
595 | if (bst->remaining_capacity == ACPI_BATTERY_VALUE_UNKNOWN) | 506 | if (battery->capacity_now == ACPI_BATTERY_VALUE_UNKNOWN) |
596 | seq_printf(seq, "remaining capacity: unknown\n"); | 507 | seq_printf(seq, "remaining capacity: unknown\n"); |
597 | else | 508 | else |
598 | seq_printf(seq, "remaining capacity: %d %sh\n", | 509 | seq_printf(seq, "remaining capacity: %d %sh\n", |
599 | (u32) bst->remaining_capacity, units); | 510 | battery->capacity_now, acpi_battery_units(battery)); |
600 | 511 | if (battery->voltage_now == ACPI_BATTERY_VALUE_UNKNOWN) | |
601 | if (bst->present_voltage == ACPI_BATTERY_VALUE_UNKNOWN) | ||
602 | seq_printf(seq, "present voltage: unknown\n"); | 512 | seq_printf(seq, "present voltage: unknown\n"); |
603 | else | 513 | else |
604 | seq_printf(seq, "present voltage: %d mV\n", | 514 | seq_printf(seq, "present voltage: %d mV\n", |
605 | (u32) bst->present_voltage); | 515 | battery->voltage_now); |
606 | |||
607 | end: | 516 | end: |
608 | 517 | if (result) | |
609 | if (result) { | ||
610 | seq_printf(seq, "ERROR: Unable to read battery state\n"); | 518 | seq_printf(seq, "ERROR: Unable to read battery state\n"); |
611 | } | ||
612 | 519 | ||
613 | return result; | 520 | return result; |
614 | } | 521 | } |
@@ -616,7 +523,6 @@ static int acpi_battery_print_state(struct seq_file *seq, int result) | |||
616 | static int acpi_battery_print_alarm(struct seq_file *seq, int result) | 523 | static int acpi_battery_print_alarm(struct seq_file *seq, int result) |
617 | { | 524 | { |
618 | struct acpi_battery *battery = seq->private; | 525 | struct acpi_battery *battery = seq->private; |
619 | char *units = "?"; | ||
620 | 526 | ||
621 | if (result) | 527 | if (result) |
622 | goto end; | 528 | goto end; |
@@ -625,189 +531,121 @@ static int acpi_battery_print_alarm(struct seq_file *seq, int result) | |||
625 | seq_printf(seq, "present: no\n"); | 531 | seq_printf(seq, "present: no\n"); |
626 | goto end; | 532 | goto end; |
627 | } | 533 | } |
628 | |||
629 | /* Battery Units */ | ||
630 | |||
631 | units = acpi_battery_power_units(battery); | ||
632 | |||
633 | seq_printf(seq, "alarm: "); | 534 | seq_printf(seq, "alarm: "); |
634 | if (!battery->alarm) | 535 | if (!battery->alarm) |
635 | seq_printf(seq, "unsupported\n"); | 536 | seq_printf(seq, "unsupported\n"); |
636 | else | 537 | else |
637 | seq_printf(seq, "%lu %sh\n", battery->alarm, units); | 538 | seq_printf(seq, "%u %sh\n", battery->alarm, |
638 | 539 | acpi_battery_units(battery)); | |
639 | end: | 540 | end: |
640 | |||
641 | if (result) | 541 | if (result) |
642 | seq_printf(seq, "ERROR: Unable to read battery alarm\n"); | 542 | seq_printf(seq, "ERROR: Unable to read battery alarm\n"); |
643 | |||
644 | return result; | 543 | return result; |
645 | } | 544 | } |
646 | 545 | ||
647 | static ssize_t | 546 | static ssize_t acpi_battery_write_alarm(struct file *file, |
648 | acpi_battery_write_alarm(struct file *file, | 547 | const char __user * buffer, |
649 | const char __user * buffer, | 548 | size_t count, loff_t * ppos) |
650 | size_t count, loff_t * ppos) | ||
651 | { | 549 | { |
652 | int result = 0; | 550 | int result = 0; |
653 | char alarm_string[12] = { '\0' }; | 551 | char alarm_string[12] = { '\0' }; |
654 | struct seq_file *m = file->private_data; | 552 | struct seq_file *m = file->private_data; |
655 | struct acpi_battery *battery = m->private; | 553 | struct acpi_battery *battery = m->private; |
656 | int update_result = ACPI_BATTERY_NONE_UPDATE; | ||
657 | 554 | ||
658 | if (!battery || (count > sizeof(alarm_string) - 1)) | 555 | if (!battery || (count > sizeof(alarm_string) - 1)) |
659 | return -EINVAL; | 556 | return -EINVAL; |
660 | |||
661 | mutex_lock(&battery->mutex); | ||
662 | |||
663 | result = acpi_battery_update(battery, 1, &update_result); | ||
664 | if (result) { | 557 | if (result) { |
665 | result = -ENODEV; | 558 | result = -ENODEV; |
666 | goto end; | 559 | goto end; |
667 | } | 560 | } |
668 | |||
669 | if (!acpi_battery_present(battery)) { | 561 | if (!acpi_battery_present(battery)) { |
670 | result = -ENODEV; | 562 | result = -ENODEV; |
671 | goto end; | 563 | goto end; |
672 | } | 564 | } |
673 | |||
674 | if (copy_from_user(alarm_string, buffer, count)) { | 565 | if (copy_from_user(alarm_string, buffer, count)) { |
675 | result = -EFAULT; | 566 | result = -EFAULT; |
676 | goto end; | 567 | goto end; |
677 | } | 568 | } |
678 | |||
679 | alarm_string[count] = '\0'; | 569 | alarm_string[count] = '\0'; |
680 | 570 | battery->alarm = simple_strtol(alarm_string, NULL, 0); | |
681 | result = acpi_battery_set_alarm(battery, | 571 | result = acpi_battery_set_alarm(battery); |
682 | simple_strtoul(alarm_string, NULL, 0)); | ||
683 | if (result) | ||
684 | goto end; | ||
685 | |||
686 | end: | 572 | end: |
687 | |||
688 | acpi_battery_check_result(battery, result); | ||
689 | |||
690 | if (!result) | 573 | if (!result) |
691 | result = count; | 574 | return count; |
692 | |||
693 | mutex_unlock(&battery->mutex); | ||
694 | |||
695 | return result; | 575 | return result; |
696 | } | 576 | } |
697 | 577 | ||
698 | typedef int(*print_func)(struct seq_file *seq, int result); | 578 | typedef int(*print_func)(struct seq_file *seq, int result); |
699 | typedef int(*get_func)(struct acpi_battery *battery); | 579 | |
700 | 580 | static print_func acpi_print_funcs[ACPI_BATTERY_NUMFILES] = { | |
701 | static struct acpi_read_mux { | 581 | acpi_battery_print_info, |
702 | print_func print; | 582 | acpi_battery_print_state, |
703 | get_func get; | 583 | acpi_battery_print_alarm, |
704 | } acpi_read_funcs[ACPI_BATTERY_NUMFILES] = { | ||
705 | {.get = acpi_battery_get_info, .print = acpi_battery_print_info}, | ||
706 | {.get = acpi_battery_get_state, .print = acpi_battery_print_state}, | ||
707 | {.get = acpi_battery_get_alarm, .print = acpi_battery_print_alarm}, | ||
708 | }; | 584 | }; |
709 | 585 | ||
710 | static int acpi_battery_read(int fid, struct seq_file *seq) | 586 | static int acpi_battery_read(int fid, struct seq_file *seq) |
711 | { | 587 | { |
712 | struct acpi_battery *battery = seq->private; | 588 | struct acpi_battery *battery = seq->private; |
713 | int result = 0; | 589 | int result = acpi_battery_update(battery); |
714 | int update_result = ACPI_BATTERY_NONE_UPDATE; | 590 | return acpi_print_funcs[fid](seq, result); |
715 | int update = 0; | 591 | } |
716 | 592 | ||
717 | mutex_lock(&battery->mutex); | 593 | #define DECLARE_FILE_FUNCTIONS(_name) \ |
718 | 594 | static int acpi_battery_read_##_name(struct seq_file *seq, void *offset) \ | |
719 | update = (get_seconds() - battery->update_time[fid] >= update_time); | 595 | { \ |
720 | update = (update | battery->flags.update[fid]); | 596 | return acpi_battery_read(_name##_tag, seq); \ |
721 | 597 | } \ | |
722 | result = acpi_battery_update(battery, update, &update_result); | 598 | static int acpi_battery_##_name##_open_fs(struct inode *inode, struct file *file) \ |
723 | if (result) | 599 | { \ |
724 | goto end; | 600 | return single_open(file, acpi_battery_read_##_name, PDE(inode)->data); \ |
725 | 601 | } | |
726 | if (update_result == ACPI_BATTERY_EASY_UPDATE) { | 602 | |
727 | result = acpi_read_funcs[fid].get(battery); | 603 | DECLARE_FILE_FUNCTIONS(info); |
728 | if (result) | 604 | DECLARE_FILE_FUNCTIONS(state); |
729 | goto end; | 605 | DECLARE_FILE_FUNCTIONS(alarm); |
606 | |||
607 | #undef DECLARE_FILE_FUNCTIONS | ||
608 | |||
609 | #define FILE_DESCRIPTION_RO(_name) \ | ||
610 | { \ | ||
611 | .name = __stringify(_name), \ | ||
612 | .mode = S_IRUGO, \ | ||
613 | .ops = { \ | ||
614 | .open = acpi_battery_##_name##_open_fs, \ | ||
615 | .read = seq_read, \ | ||
616 | .llseek = seq_lseek, \ | ||
617 | .release = single_release, \ | ||
618 | .owner = THIS_MODULE, \ | ||
619 | }, \ | ||
620 | } | ||
621 | |||
622 | #define FILE_DESCRIPTION_RW(_name) \ | ||
623 | { \ | ||
624 | .name = __stringify(_name), \ | ||
625 | .mode = S_IFREG | S_IRUGO | S_IWUSR, \ | ||
626 | .ops = { \ | ||
627 | .open = acpi_battery_##_name##_open_fs, \ | ||
628 | .read = seq_read, \ | ||
629 | .llseek = seq_lseek, \ | ||
630 | .write = acpi_battery_write_##_name, \ | ||
631 | .release = single_release, \ | ||
632 | .owner = THIS_MODULE, \ | ||
633 | }, \ | ||
730 | } | 634 | } |
731 | 635 | ||
732 | end: | ||
733 | result = acpi_read_funcs[fid].print(seq, result); | ||
734 | acpi_battery_check_result(battery, result); | ||
735 | battery->flags.update[fid] = result; | ||
736 | mutex_unlock(&battery->mutex); | ||
737 | return result; | ||
738 | } | ||
739 | |||
740 | static int acpi_battery_read_info(struct seq_file *seq, void *offset) | ||
741 | { | ||
742 | return acpi_battery_read(ACPI_BATTERY_INFO, seq); | ||
743 | } | ||
744 | |||
745 | static int acpi_battery_read_state(struct seq_file *seq, void *offset) | ||
746 | { | ||
747 | return acpi_battery_read(ACPI_BATTERY_STATE, seq); | ||
748 | } | ||
749 | |||
750 | static int acpi_battery_read_alarm(struct seq_file *seq, void *offset) | ||
751 | { | ||
752 | return acpi_battery_read(ACPI_BATTERY_ALARM, seq); | ||
753 | } | ||
754 | |||
755 | static int acpi_battery_info_open_fs(struct inode *inode, struct file *file) | ||
756 | { | ||
757 | return single_open(file, acpi_battery_read_info, PDE(inode)->data); | ||
758 | } | ||
759 | |||
760 | static int acpi_battery_state_open_fs(struct inode *inode, struct file *file) | ||
761 | { | ||
762 | return single_open(file, acpi_battery_read_state, PDE(inode)->data); | ||
763 | } | ||
764 | |||
765 | static int acpi_battery_alarm_open_fs(struct inode *inode, struct file *file) | ||
766 | { | ||
767 | return single_open(file, acpi_battery_read_alarm, PDE(inode)->data); | ||
768 | } | ||
769 | |||
770 | static struct battery_file { | 636 | static struct battery_file { |
771 | struct file_operations ops; | 637 | struct file_operations ops; |
772 | mode_t mode; | 638 | mode_t mode; |
773 | char *name; | 639 | char *name; |
774 | } acpi_battery_file[] = { | 640 | } acpi_battery_file[] = { |
775 | { | 641 | FILE_DESCRIPTION_RO(info), |
776 | .name = "info", | 642 | FILE_DESCRIPTION_RO(state), |
777 | .mode = S_IRUGO, | 643 | FILE_DESCRIPTION_RW(alarm), |
778 | .ops = { | ||
779 | .open = acpi_battery_info_open_fs, | ||
780 | .read = seq_read, | ||
781 | .llseek = seq_lseek, | ||
782 | .release = single_release, | ||
783 | .owner = THIS_MODULE, | ||
784 | }, | ||
785 | }, | ||
786 | { | ||
787 | .name = "state", | ||
788 | .mode = S_IRUGO, | ||
789 | .ops = { | ||
790 | .open = acpi_battery_state_open_fs, | ||
791 | .read = seq_read, | ||
792 | .llseek = seq_lseek, | ||
793 | .release = single_release, | ||
794 | .owner = THIS_MODULE, | ||
795 | }, | ||
796 | }, | ||
797 | { | ||
798 | .name = "alarm", | ||
799 | .mode = S_IFREG | S_IRUGO | S_IWUSR, | ||
800 | .ops = { | ||
801 | .open = acpi_battery_alarm_open_fs, | ||
802 | .read = seq_read, | ||
803 | .write = acpi_battery_write_alarm, | ||
804 | .llseek = seq_lseek, | ||
805 | .release = single_release, | ||
806 | .owner = THIS_MODULE, | ||
807 | }, | ||
808 | }, | ||
809 | }; | 644 | }; |
810 | 645 | ||
646 | #undef FILE_DESCRIPTION_RO | ||
647 | #undef FILE_DESCRIPTION_RW | ||
648 | |||
811 | static int acpi_battery_add_fs(struct acpi_device *device) | 649 | static int acpi_battery_add_fs(struct acpi_device *device) |
812 | { | 650 | { |
813 | struct proc_dir_entry *entry = NULL; | 651 | struct proc_dir_entry *entry = NULL; |
@@ -832,25 +670,51 @@ static int acpi_battery_add_fs(struct acpi_device *device) | |||
832 | entry->owner = THIS_MODULE; | 670 | entry->owner = THIS_MODULE; |
833 | } | 671 | } |
834 | } | 672 | } |
835 | |||
836 | return 0; | 673 | return 0; |
837 | } | 674 | } |
838 | 675 | ||
839 | static int acpi_battery_remove_fs(struct acpi_device *device) | 676 | static void acpi_battery_remove_fs(struct acpi_device *device) |
840 | { | 677 | { |
841 | int i; | 678 | int i; |
842 | if (acpi_device_dir(device)) { | 679 | if (!acpi_device_dir(device)) |
843 | for (i = 0; i < ACPI_BATTERY_NUMFILES; ++i) { | 680 | return; |
844 | remove_proc_entry(acpi_battery_file[i].name, | 681 | for (i = 0; i < ACPI_BATTERY_NUMFILES; ++i) |
682 | remove_proc_entry(acpi_battery_file[i].name, | ||
845 | acpi_device_dir(device)); | 683 | acpi_device_dir(device)); |
846 | } | ||
847 | remove_proc_entry(acpi_device_bid(device), acpi_battery_dir); | ||
848 | acpi_device_dir(device) = NULL; | ||
849 | } | ||
850 | 684 | ||
851 | return 0; | 685 | remove_proc_entry(acpi_device_bid(device), acpi_battery_dir); |
686 | acpi_device_dir(device) = NULL; | ||
687 | } | ||
688 | |||
689 | #endif | ||
690 | |||
691 | static ssize_t acpi_battery_alarm_show(struct device *dev, | ||
692 | struct device_attribute *attr, | ||
693 | char *buf) | ||
694 | { | ||
695 | struct acpi_battery *battery = to_acpi_battery(dev_get_drvdata(dev)); | ||
696 | return sprintf(buf, "%d\n", battery->alarm * 1000); | ||
697 | } | ||
698 | |||
699 | static ssize_t acpi_battery_alarm_store(struct device *dev, | ||
700 | struct device_attribute *attr, | ||
701 | const char *buf, size_t count) | ||
702 | { | ||
703 | unsigned long x; | ||
704 | struct acpi_battery *battery = to_acpi_battery(dev_get_drvdata(dev)); | ||
705 | if (sscanf(buf, "%ld\n", &x) == 1) | ||
706 | battery->alarm = x/1000; | ||
707 | if (acpi_battery_present(battery)) | ||
708 | acpi_battery_set_alarm(battery); | ||
709 | return count; | ||
852 | } | 710 | } |
853 | 711 | ||
712 | static struct device_attribute alarm_attr = { | ||
713 | .attr = {.name = "alarm", .mode = 0644, .owner = THIS_MODULE}, | ||
714 | .show = acpi_battery_alarm_show, | ||
715 | .store = acpi_battery_alarm_store, | ||
716 | }; | ||
717 | |||
854 | /* -------------------------------------------------------------------------- | 718 | /* -------------------------------------------------------------------------- |
855 | Driver Interface | 719 | Driver Interface |
856 | -------------------------------------------------------------------------- */ | 720 | -------------------------------------------------------------------------- */ |
@@ -858,33 +722,17 @@ static int acpi_battery_remove_fs(struct acpi_device *device) | |||
858 | static void acpi_battery_notify(acpi_handle handle, u32 event, void *data) | 722 | static void acpi_battery_notify(acpi_handle handle, u32 event, void *data) |
859 | { | 723 | { |
860 | struct acpi_battery *battery = data; | 724 | struct acpi_battery *battery = data; |
861 | struct acpi_device *device = NULL; | 725 | struct acpi_device *device; |
862 | |||
863 | if (!battery) | 726 | if (!battery) |
864 | return; | 727 | return; |
865 | |||
866 | device = battery->device; | 728 | device = battery->device; |
867 | 729 | acpi_battery_update(battery); | |
868 | switch (event) { | 730 | acpi_bus_generate_proc_event(device, event, |
869 | case ACPI_BATTERY_NOTIFY_STATUS: | 731 | acpi_battery_present(battery)); |
870 | case ACPI_BATTERY_NOTIFY_INFO: | 732 | acpi_bus_generate_netlink_event(device->pnp.device_class, |
871 | case ACPI_NOTIFY_BUS_CHECK: | 733 | device->dev.bus_id, event, |
872 | case ACPI_NOTIFY_DEVICE_CHECK: | ||
873 | device = battery->device; | ||
874 | acpi_battery_notify_update(battery); | ||
875 | acpi_bus_generate_proc_event(device, event, | ||
876 | acpi_battery_present(battery)); | 734 | acpi_battery_present(battery)); |
877 | acpi_bus_generate_netlink_event(device->pnp.device_class, | 735 | kobject_uevent(&battery->bat.dev->kobj, KOBJ_CHANGE); |
878 | device->dev.bus_id, event, | ||
879 | acpi_battery_present(battery)); | ||
880 | break; | ||
881 | default: | ||
882 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, | ||
883 | "Unsupported event [0x%x]\n", event)); | ||
884 | break; | ||
885 | } | ||
886 | |||
887 | return; | ||
888 | } | 736 | } |
889 | 737 | ||
890 | static int acpi_battery_add(struct acpi_device *device) | 738 | static int acpi_battery_add(struct acpi_device *device) |
@@ -892,33 +740,27 @@ static int acpi_battery_add(struct acpi_device *device) | |||
892 | int result = 0; | 740 | int result = 0; |
893 | acpi_status status = 0; | 741 | acpi_status status = 0; |
894 | struct acpi_battery *battery = NULL; | 742 | struct acpi_battery *battery = NULL; |
895 | |||
896 | if (!device) | 743 | if (!device) |
897 | return -EINVAL; | 744 | return -EINVAL; |
898 | |||
899 | battery = kzalloc(sizeof(struct acpi_battery), GFP_KERNEL); | 745 | battery = kzalloc(sizeof(struct acpi_battery), GFP_KERNEL); |
900 | if (!battery) | 746 | if (!battery) |
901 | return -ENOMEM; | 747 | return -ENOMEM; |
902 | |||
903 | mutex_init(&battery->mutex); | ||
904 | |||
905 | mutex_lock(&battery->mutex); | ||
906 | |||
907 | battery->device = device; | 748 | battery->device = device; |
908 | strcpy(acpi_device_name(device), ACPI_BATTERY_DEVICE_NAME); | 749 | strcpy(acpi_device_name(device), ACPI_BATTERY_DEVICE_NAME); |
909 | strcpy(acpi_device_class(device), ACPI_BATTERY_CLASS); | 750 | strcpy(acpi_device_class(device), ACPI_BATTERY_CLASS); |
910 | acpi_driver_data(device) = battery; | 751 | acpi_driver_data(device) = battery; |
911 | 752 | mutex_init(&battery->lock); | |
912 | result = acpi_battery_get_status(battery); | 753 | acpi_battery_update(battery); |
913 | if (result) | 754 | #ifdef CONFIG_ACPI_PROCFS |
914 | goto end; | ||
915 | |||
916 | battery->flags.init_update = 1; | ||
917 | |||
918 | result = acpi_battery_add_fs(device); | 755 | result = acpi_battery_add_fs(device); |
919 | if (result) | 756 | if (result) |
920 | goto end; | 757 | goto end; |
921 | 758 | #endif | |
759 | battery->bat.name = acpi_device_bid(device); | ||
760 | battery->bat.type = POWER_SUPPLY_TYPE_BATTERY; | ||
761 | battery->bat.get_property = acpi_battery_get_property; | ||
762 | result = power_supply_register(&battery->device->dev, &battery->bat); | ||
763 | result = device_create_file(battery->bat.dev, &alarm_attr); | ||
922 | status = acpi_install_notify_handler(device->handle, | 764 | status = acpi_install_notify_handler(device->handle, |
923 | ACPI_ALL_NOTIFY, | 765 | ACPI_ALL_NOTIFY, |
924 | acpi_battery_notify, battery); | 766 | acpi_battery_notify, battery); |
@@ -927,20 +769,16 @@ static int acpi_battery_add(struct acpi_device *device) | |||
927 | result = -ENODEV; | 769 | result = -ENODEV; |
928 | goto end; | 770 | goto end; |
929 | } | 771 | } |
930 | |||
931 | printk(KERN_INFO PREFIX "%s Slot [%s] (battery %s)\n", | 772 | printk(KERN_INFO PREFIX "%s Slot [%s] (battery %s)\n", |
932 | ACPI_BATTERY_DEVICE_NAME, acpi_device_bid(device), | 773 | ACPI_BATTERY_DEVICE_NAME, acpi_device_bid(device), |
933 | device->status.battery_present ? "present" : "absent"); | 774 | device->status.battery_present ? "present" : "absent"); |
934 | |||
935 | end: | 775 | end: |
936 | |||
937 | if (result) { | 776 | if (result) { |
777 | #ifdef CONFIG_ACPI_PROCFS | ||
938 | acpi_battery_remove_fs(device); | 778 | acpi_battery_remove_fs(device); |
779 | #endif | ||
939 | kfree(battery); | 780 | kfree(battery); |
940 | } | 781 | } |
941 | |||
942 | mutex_unlock(&battery->mutex); | ||
943 | |||
944 | return result; | 782 | return result; |
945 | } | 783 | } |
946 | 784 | ||
@@ -951,27 +789,19 @@ static int acpi_battery_remove(struct acpi_device *device, int type) | |||
951 | 789 | ||
952 | if (!device || !acpi_driver_data(device)) | 790 | if (!device || !acpi_driver_data(device)) |
953 | return -EINVAL; | 791 | return -EINVAL; |
954 | |||
955 | battery = acpi_driver_data(device); | 792 | battery = acpi_driver_data(device); |
956 | |||
957 | mutex_lock(&battery->mutex); | ||
958 | |||
959 | status = acpi_remove_notify_handler(device->handle, | 793 | status = acpi_remove_notify_handler(device->handle, |
960 | ACPI_ALL_NOTIFY, | 794 | ACPI_ALL_NOTIFY, |
961 | acpi_battery_notify); | 795 | acpi_battery_notify); |
962 | 796 | #ifdef CONFIG_ACPI_PROCFS | |
963 | acpi_battery_remove_fs(device); | 797 | acpi_battery_remove_fs(device); |
964 | 798 | #endif | |
965 | kfree(battery->bif_data.pointer); | 799 | if (battery->bat.dev) { |
966 | 800 | device_remove_file(battery->bat.dev, &alarm_attr); | |
967 | kfree(battery->bst_data.pointer); | 801 | power_supply_unregister(&battery->bat); |
968 | 802 | } | |
969 | mutex_unlock(&battery->mutex); | 803 | mutex_destroy(&battery->lock); |
970 | |||
971 | mutex_destroy(&battery->mutex); | ||
972 | |||
973 | kfree(battery); | 804 | kfree(battery); |
974 | |||
975 | return 0; | 805 | return 0; |
976 | } | 806 | } |
977 | 807 | ||
@@ -979,44 +809,48 @@ static int acpi_battery_remove(struct acpi_device *device, int type) | |||
979 | static int acpi_battery_resume(struct acpi_device *device) | 809 | static int acpi_battery_resume(struct acpi_device *device) |
980 | { | 810 | { |
981 | struct acpi_battery *battery; | 811 | struct acpi_battery *battery; |
982 | |||
983 | if (!device) | 812 | if (!device) |
984 | return -EINVAL; | 813 | return -EINVAL; |
985 | 814 | battery = acpi_driver_data(device); | |
986 | battery = device->driver_data; | 815 | battery->update_time = 0; |
987 | |||
988 | battery->flags.init_update = 1; | ||
989 | |||
990 | return 0; | 816 | return 0; |
991 | } | 817 | } |
992 | 818 | ||
819 | static struct acpi_driver acpi_battery_driver = { | ||
820 | .name = "battery", | ||
821 | .class = ACPI_BATTERY_CLASS, | ||
822 | .ids = battery_device_ids, | ||
823 | .ops = { | ||
824 | .add = acpi_battery_add, | ||
825 | .resume = acpi_battery_resume, | ||
826 | .remove = acpi_battery_remove, | ||
827 | }, | ||
828 | }; | ||
829 | |||
993 | static int __init acpi_battery_init(void) | 830 | static int __init acpi_battery_init(void) |
994 | { | 831 | { |
995 | int result; | ||
996 | |||
997 | if (acpi_disabled) | 832 | if (acpi_disabled) |
998 | return -ENODEV; | 833 | return -ENODEV; |
999 | 834 | #ifdef CONFIG_ACPI_PROCFS | |
1000 | acpi_battery_dir = acpi_lock_battery_dir(); | 835 | acpi_battery_dir = acpi_lock_battery_dir(); |
1001 | if (!acpi_battery_dir) | 836 | if (!acpi_battery_dir) |
1002 | return -ENODEV; | 837 | return -ENODEV; |
1003 | 838 | #endif | |
1004 | result = acpi_bus_register_driver(&acpi_battery_driver); | 839 | if (acpi_bus_register_driver(&acpi_battery_driver) < 0) { |
1005 | if (result < 0) { | 840 | #ifdef CONFIG_ACPI_PROCFS |
1006 | acpi_unlock_battery_dir(acpi_battery_dir); | 841 | acpi_unlock_battery_dir(acpi_battery_dir); |
842 | #endif | ||
1007 | return -ENODEV; | 843 | return -ENODEV; |
1008 | } | 844 | } |
1009 | |||
1010 | return 0; | 845 | return 0; |
1011 | } | 846 | } |
1012 | 847 | ||
1013 | static void __exit acpi_battery_exit(void) | 848 | static void __exit acpi_battery_exit(void) |
1014 | { | 849 | { |
1015 | acpi_bus_unregister_driver(&acpi_battery_driver); | 850 | acpi_bus_unregister_driver(&acpi_battery_driver); |
1016 | 851 | #ifdef CONFIG_ACPI_PROCFS | |
1017 | acpi_unlock_battery_dir(acpi_battery_dir); | 852 | acpi_unlock_battery_dir(acpi_battery_dir); |
1018 | 853 | #endif | |
1019 | return; | ||
1020 | } | 854 | } |
1021 | 855 | ||
1022 | module_init(acpi_battery_init); | 856 | module_init(acpi_battery_init); |