diff options
author | Len Brown <len.brown@intel.com> | 2007-07-22 02:24:31 -0400 |
---|---|---|
committer | Len Brown <len.brown@intel.com> | 2007-07-22 02:24:31 -0400 |
commit | 8269cc4e2b0ddcdcb9e7f2034c464ef8613737a1 (patch) | |
tree | 6e41103c15f6b73187c635159e4f08b727c5598a | |
parent | 939ab20152390c8ccccfa6fac0830405ca91d903 (diff) | |
parent | 78490d82129f7331d1366737c8704c1c053221a3 (diff) |
Pull battery into release branch
-rw-r--r-- | drivers/acpi/battery.c | 673 |
1 files changed, 438 insertions, 235 deletions
diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index e64c76c8b726..cad932de383d 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c | |||
@@ -43,21 +43,30 @@ | |||
43 | #define ACPI_BATTERY_CLASS "battery" | 43 | #define ACPI_BATTERY_CLASS "battery" |
44 | #define ACPI_BATTERY_HID "PNP0C0A" | 44 | #define ACPI_BATTERY_HID "PNP0C0A" |
45 | #define ACPI_BATTERY_DEVICE_NAME "Battery" | 45 | #define ACPI_BATTERY_DEVICE_NAME "Battery" |
46 | #define ACPI_BATTERY_FILE_INFO "info" | ||
47 | #define ACPI_BATTERY_FILE_STATUS "state" | ||
48 | #define ACPI_BATTERY_FILE_ALARM "alarm" | ||
49 | #define ACPI_BATTERY_NOTIFY_STATUS 0x80 | 46 | #define ACPI_BATTERY_NOTIFY_STATUS 0x80 |
50 | #define ACPI_BATTERY_NOTIFY_INFO 0x81 | 47 | #define ACPI_BATTERY_NOTIFY_INFO 0x81 |
51 | #define ACPI_BATTERY_UNITS_WATTS "mW" | 48 | #define ACPI_BATTERY_UNITS_WATTS "mW" |
52 | #define ACPI_BATTERY_UNITS_AMPS "mA" | 49 | #define ACPI_BATTERY_UNITS_AMPS "mA" |
53 | 50 | ||
54 | #define _COMPONENT ACPI_BATTERY_COMPONENT | 51 | #define _COMPONENT ACPI_BATTERY_COMPONENT |
52 | |||
53 | #define ACPI_BATTERY_UPDATE_TIME 0 | ||
54 | |||
55 | #define ACPI_BATTERY_NONE_UPDATE 0 | ||
56 | #define ACPI_BATTERY_EASY_UPDATE 1 | ||
57 | #define ACPI_BATTERY_INIT_UPDATE 2 | ||
58 | |||
55 | ACPI_MODULE_NAME("battery"); | 59 | ACPI_MODULE_NAME("battery"); |
56 | 60 | ||
57 | MODULE_AUTHOR("Paul Diefenbaugh"); | 61 | MODULE_AUTHOR("Paul Diefenbaugh"); |
58 | MODULE_DESCRIPTION("ACPI Battery Driver"); | 62 | MODULE_DESCRIPTION("ACPI Battery Driver"); |
59 | MODULE_LICENSE("GPL"); | 63 | MODULE_LICENSE("GPL"); |
60 | 64 | ||
65 | static unsigned int update_time = ACPI_BATTERY_UPDATE_TIME; | ||
66 | |||
67 | /* 0 - every time, > 0 - by update_time */ | ||
68 | module_param(update_time, uint, 0644); | ||
69 | |||
61 | extern struct proc_dir_entry *acpi_lock_battery_dir(void); | 70 | extern struct proc_dir_entry *acpi_lock_battery_dir(void); |
62 | extern void *acpi_unlock_battery_dir(struct proc_dir_entry *acpi_battery_dir); | 71 | extern void *acpi_unlock_battery_dir(struct proc_dir_entry *acpi_battery_dir); |
63 | 72 | ||
@@ -76,7 +85,7 @@ static struct acpi_driver acpi_battery_driver = { | |||
76 | }, | 85 | }, |
77 | }; | 86 | }; |
78 | 87 | ||
79 | struct acpi_battery_status { | 88 | struct acpi_battery_state { |
80 | acpi_integer state; | 89 | acpi_integer state; |
81 | acpi_integer present_rate; | 90 | acpi_integer present_rate; |
82 | acpi_integer remaining_capacity; | 91 | acpi_integer remaining_capacity; |
@@ -99,33 +108,111 @@ struct acpi_battery_info { | |||
99 | acpi_string oem_info; | 108 | acpi_string oem_info; |
100 | }; | 109 | }; |
101 | 110 | ||
102 | struct acpi_battery_flags { | 111 | enum acpi_battery_files{ |
103 | u8 present:1; /* Bay occupied? */ | 112 | ACPI_BATTERY_INFO = 0, |
104 | u8 power_unit:1; /* 0=watts, 1=apms */ | 113 | ACPI_BATTERY_STATE, |
105 | u8 alarm:1; /* _BTP present? */ | 114 | ACPI_BATTERY_ALARM, |
106 | u8 reserved:5; | 115 | ACPI_BATTERY_NUMFILES, |
107 | }; | 116 | }; |
108 | 117 | ||
109 | struct acpi_battery_trips { | 118 | struct acpi_battery_flags { |
110 | unsigned long warning; | 119 | u8 battery_present_prev; |
111 | unsigned long low; | 120 | u8 alarm_present; |
121 | u8 init_update; | ||
122 | u8 update[ACPI_BATTERY_NUMFILES]; | ||
123 | u8 power_unit; | ||
112 | }; | 124 | }; |
113 | 125 | ||
114 | struct acpi_battery { | 126 | struct acpi_battery { |
115 | struct acpi_device * device; | 127 | struct mutex mutex; |
128 | struct acpi_device *device; | ||
116 | struct acpi_battery_flags flags; | 129 | struct acpi_battery_flags flags; |
117 | struct acpi_battery_trips trips; | 130 | struct acpi_buffer bif_data; |
131 | struct acpi_buffer bst_data; | ||
118 | unsigned long alarm; | 132 | unsigned long alarm; |
119 | struct acpi_battery_info *info; | 133 | unsigned long update_time[ACPI_BATTERY_NUMFILES]; |
120 | }; | 134 | }; |
121 | 135 | ||
136 | inline int acpi_battery_present(struct acpi_battery *battery) | ||
137 | { | ||
138 | return battery->device->status.battery_present; | ||
139 | } | ||
140 | inline char *acpi_battery_power_units(struct acpi_battery *battery) | ||
141 | { | ||
142 | if (battery->flags.power_unit) | ||
143 | return ACPI_BATTERY_UNITS_AMPS; | ||
144 | else | ||
145 | return ACPI_BATTERY_UNITS_WATTS; | ||
146 | } | ||
147 | |||
148 | inline acpi_handle acpi_battery_handle(struct acpi_battery *battery) | ||
149 | { | ||
150 | return battery->device->handle; | ||
151 | } | ||
152 | |||
122 | /* -------------------------------------------------------------------------- | 153 | /* -------------------------------------------------------------------------- |
123 | Battery Management | 154 | Battery Management |
124 | -------------------------------------------------------------------------- */ | 155 | -------------------------------------------------------------------------- */ |
125 | 156 | ||
126 | static int | 157 | static void acpi_battery_check_result(struct acpi_battery *battery, int result) |
127 | acpi_battery_get_info(struct acpi_battery *battery, | 158 | { |
128 | struct acpi_battery_info **bif) | 159 | if (!battery) |
160 | return; | ||
161 | |||
162 | if (result) { | ||
163 | battery->flags.init_update = 1; | ||
164 | } | ||
165 | } | ||
166 | |||
167 | static int acpi_battery_extract_package(struct acpi_battery *battery, | ||
168 | union acpi_object *package, | ||
169 | struct acpi_buffer *format, | ||
170 | struct acpi_buffer *data, | ||
171 | char *package_name) | ||
172 | { | ||
173 | acpi_status status = AE_OK; | ||
174 | struct acpi_buffer data_null = { 0, NULL }; | ||
175 | |||
176 | status = acpi_extract_package(package, format, &data_null); | ||
177 | if (status != AE_BUFFER_OVERFLOW) { | ||
178 | ACPI_EXCEPTION((AE_INFO, status, "Extracting size %s", | ||
179 | package_name)); | ||
180 | return -ENODEV; | ||
181 | } | ||
182 | |||
183 | if (data_null.length != data->length) { | ||
184 | kfree(data->pointer); | ||
185 | data->pointer = kzalloc(data_null.length, GFP_KERNEL); | ||
186 | if (!data->pointer) { | ||
187 | ACPI_EXCEPTION((AE_INFO, AE_NO_MEMORY, "kzalloc()")); | ||
188 | return -ENOMEM; | ||
189 | } | ||
190 | data->length = data_null.length; | ||
191 | } | ||
192 | |||
193 | status = acpi_extract_package(package, format, data); | ||
194 | if (ACPI_FAILURE(status)) { | ||
195 | ACPI_EXCEPTION((AE_INFO, status, "Extracting %s", | ||
196 | package_name)); | ||
197 | return -ENODEV; | ||
198 | } | ||
199 | |||
200 | return 0; | ||
201 | } | ||
202 | |||
203 | static int acpi_battery_get_status(struct acpi_battery *battery) | ||
204 | { | ||
205 | int result = 0; | ||
206 | |||
207 | result = acpi_bus_get_status(battery->device); | ||
208 | if (result) { | ||
209 | ACPI_EXCEPTION((AE_INFO, AE_ERROR, "Evaluating _STA")); | ||
210 | return -ENODEV; | ||
211 | } | ||
212 | return result; | ||
213 | } | ||
214 | |||
215 | static int acpi_battery_get_info(struct acpi_battery *battery) | ||
129 | { | 216 | { |
130 | int result = 0; | 217 | int result = 0; |
131 | acpi_status status = 0; | 218 | acpi_status status = 0; |
@@ -133,16 +220,20 @@ acpi_battery_get_info(struct acpi_battery *battery, | |||
133 | struct acpi_buffer format = { sizeof(ACPI_BATTERY_FORMAT_BIF), | 220 | struct acpi_buffer format = { sizeof(ACPI_BATTERY_FORMAT_BIF), |
134 | ACPI_BATTERY_FORMAT_BIF | 221 | ACPI_BATTERY_FORMAT_BIF |
135 | }; | 222 | }; |
136 | struct acpi_buffer data = { 0, NULL }; | ||
137 | union acpi_object *package = NULL; | 223 | union acpi_object *package = NULL; |
224 | struct acpi_buffer *data = NULL; | ||
225 | struct acpi_battery_info *bif = NULL; | ||
138 | 226 | ||
227 | battery->update_time[ACPI_BATTERY_INFO] = get_seconds(); | ||
139 | 228 | ||
140 | if (!battery || !bif) | 229 | if (!acpi_battery_present(battery)) |
141 | return -EINVAL; | 230 | return 0; |
142 | 231 | ||
143 | /* Evalute _BIF */ | 232 | /* Evaluate _BIF */ |
144 | 233 | ||
145 | status = acpi_evaluate_object(battery->device->handle, "_BIF", NULL, &buffer); | 234 | status = |
235 | acpi_evaluate_object(acpi_battery_handle(battery), "_BIF", NULL, | ||
236 | &buffer); | ||
146 | if (ACPI_FAILURE(status)) { | 237 | if (ACPI_FAILURE(status)) { |
147 | ACPI_EXCEPTION((AE_INFO, status, "Evaluating _BIF")); | 238 | ACPI_EXCEPTION((AE_INFO, status, "Evaluating _BIF")); |
148 | return -ENODEV; | 239 | return -ENODEV; |
@@ -150,41 +241,29 @@ acpi_battery_get_info(struct acpi_battery *battery, | |||
150 | 241 | ||
151 | package = buffer.pointer; | 242 | package = buffer.pointer; |
152 | 243 | ||
153 | /* Extract Package Data */ | 244 | data = &battery->bif_data; |
154 | |||
155 | status = acpi_extract_package(package, &format, &data); | ||
156 | if (status != AE_BUFFER_OVERFLOW) { | ||
157 | ACPI_EXCEPTION((AE_INFO, status, "Extracting _BIF")); | ||
158 | result = -ENODEV; | ||
159 | goto end; | ||
160 | } | ||
161 | 245 | ||
162 | data.pointer = kzalloc(data.length, GFP_KERNEL); | 246 | /* Extract Package Data */ |
163 | if (!data.pointer) { | ||
164 | result = -ENOMEM; | ||
165 | goto end; | ||
166 | } | ||
167 | 247 | ||
168 | status = acpi_extract_package(package, &format, &data); | 248 | result = |
169 | if (ACPI_FAILURE(status)) { | 249 | acpi_battery_extract_package(battery, package, &format, data, |
170 | ACPI_EXCEPTION((AE_INFO, status, "Extracting _BIF")); | 250 | "_BIF"); |
171 | kfree(data.pointer); | 251 | if (result) |
172 | result = -ENODEV; | ||
173 | goto end; | 252 | goto end; |
174 | } | ||
175 | 253 | ||
176 | end: | 254 | end: |
255 | |||
177 | kfree(buffer.pointer); | 256 | kfree(buffer.pointer); |
178 | 257 | ||
179 | if (!result) | 258 | if (!result) { |
180 | (*bif) = data.pointer; | 259 | bif = data->pointer; |
260 | battery->flags.power_unit = bif->power_unit; | ||
261 | } | ||
181 | 262 | ||
182 | return result; | 263 | return result; |
183 | } | 264 | } |
184 | 265 | ||
185 | static int | 266 | static int acpi_battery_get_state(struct acpi_battery *battery) |
186 | acpi_battery_get_status(struct acpi_battery *battery, | ||
187 | struct acpi_battery_status **bst) | ||
188 | { | 267 | { |
189 | int result = 0; | 268 | int result = 0; |
190 | acpi_status status = 0; | 269 | acpi_status status = 0; |
@@ -192,16 +271,19 @@ acpi_battery_get_status(struct acpi_battery *battery, | |||
192 | struct acpi_buffer format = { sizeof(ACPI_BATTERY_FORMAT_BST), | 271 | struct acpi_buffer format = { sizeof(ACPI_BATTERY_FORMAT_BST), |
193 | ACPI_BATTERY_FORMAT_BST | 272 | ACPI_BATTERY_FORMAT_BST |
194 | }; | 273 | }; |
195 | struct acpi_buffer data = { 0, NULL }; | ||
196 | union acpi_object *package = NULL; | 274 | union acpi_object *package = NULL; |
275 | struct acpi_buffer *data = NULL; | ||
197 | 276 | ||
277 | battery->update_time[ACPI_BATTERY_STATE] = get_seconds(); | ||
198 | 278 | ||
199 | if (!battery || !bst) | 279 | if (!acpi_battery_present(battery)) |
200 | return -EINVAL; | 280 | return 0; |
201 | 281 | ||
202 | /* Evalute _BST */ | 282 | /* Evaluate _BST */ |
203 | 283 | ||
204 | status = acpi_evaluate_object(battery->device->handle, "_BST", NULL, &buffer); | 284 | status = |
285 | acpi_evaluate_object(acpi_battery_handle(battery), "_BST", NULL, | ||
286 | &buffer); | ||
205 | if (ACPI_FAILURE(status)) { | 287 | if (ACPI_FAILURE(status)) { |
206 | ACPI_EXCEPTION((AE_INFO, status, "Evaluating _BST")); | 288 | ACPI_EXCEPTION((AE_INFO, status, "Evaluating _BST")); |
207 | return -ENODEV; | 289 | return -ENODEV; |
@@ -209,55 +291,49 @@ acpi_battery_get_status(struct acpi_battery *battery, | |||
209 | 291 | ||
210 | package = buffer.pointer; | 292 | package = buffer.pointer; |
211 | 293 | ||
212 | /* Extract Package Data */ | 294 | data = &battery->bst_data; |
213 | |||
214 | status = acpi_extract_package(package, &format, &data); | ||
215 | if (status != AE_BUFFER_OVERFLOW) { | ||
216 | ACPI_EXCEPTION((AE_INFO, status, "Extracting _BST")); | ||
217 | result = -ENODEV; | ||
218 | goto end; | ||
219 | } | ||
220 | 295 | ||
221 | data.pointer = kzalloc(data.length, GFP_KERNEL); | 296 | /* Extract Package Data */ |
222 | if (!data.pointer) { | ||
223 | result = -ENOMEM; | ||
224 | goto end; | ||
225 | } | ||
226 | 297 | ||
227 | status = acpi_extract_package(package, &format, &data); | 298 | result = |
228 | if (ACPI_FAILURE(status)) { | 299 | acpi_battery_extract_package(battery, package, &format, data, |
229 | ACPI_EXCEPTION((AE_INFO, status, "Extracting _BST")); | 300 | "_BST"); |
230 | kfree(data.pointer); | 301 | if (result) |
231 | result = -ENODEV; | ||
232 | goto end; | 302 | goto end; |
233 | } | ||
234 | 303 | ||
235 | end: | 304 | end: |
236 | kfree(buffer.pointer); | 305 | kfree(buffer.pointer); |
237 | 306 | ||
238 | if (!result) | ||
239 | (*bst) = data.pointer; | ||
240 | |||
241 | return result; | 307 | return result; |
242 | } | 308 | } |
243 | 309 | ||
244 | static int | 310 | static int acpi_battery_get_alarm(struct acpi_battery *battery) |
245 | acpi_battery_set_alarm(struct acpi_battery *battery, unsigned long alarm) | 311 | { |
312 | battery->update_time[ACPI_BATTERY_ALARM] = get_seconds(); | ||
313 | |||
314 | return 0; | ||
315 | } | ||
316 | |||
317 | static int acpi_battery_set_alarm(struct acpi_battery *battery, | ||
318 | unsigned long alarm) | ||
246 | { | 319 | { |
247 | acpi_status status = 0; | 320 | acpi_status status = 0; |
248 | union acpi_object arg0 = { ACPI_TYPE_INTEGER }; | 321 | union acpi_object arg0 = { ACPI_TYPE_INTEGER }; |
249 | struct acpi_object_list arg_list = { 1, &arg0 }; | 322 | struct acpi_object_list arg_list = { 1, &arg0 }; |
250 | 323 | ||
324 | battery->update_time[ACPI_BATTERY_ALARM] = get_seconds(); | ||
251 | 325 | ||
252 | if (!battery) | 326 | if (!acpi_battery_present(battery)) |
253 | return -EINVAL; | 327 | return -ENODEV; |
254 | 328 | ||
255 | if (!battery->flags.alarm) | 329 | if (!battery->flags.alarm_present) |
256 | return -ENODEV; | 330 | return -ENODEV; |
257 | 331 | ||
258 | arg0.integer.value = alarm; | 332 | arg0.integer.value = alarm; |
259 | 333 | ||
260 | status = acpi_evaluate_object(battery->device->handle, "_BTP", &arg_list, NULL); | 334 | status = |
335 | acpi_evaluate_object(acpi_battery_handle(battery), "_BTP", | ||
336 | &arg_list, NULL); | ||
261 | if (ACPI_FAILURE(status)) | 337 | if (ACPI_FAILURE(status)) |
262 | return -ENODEV; | 338 | return -ENODEV; |
263 | 339 | ||
@@ -268,65 +344,114 @@ acpi_battery_set_alarm(struct acpi_battery *battery, unsigned long alarm) | |||
268 | return 0; | 344 | return 0; |
269 | } | 345 | } |
270 | 346 | ||
271 | static int acpi_battery_check(struct acpi_battery *battery) | 347 | static int acpi_battery_init_alarm(struct acpi_battery *battery) |
272 | { | 348 | { |
273 | int result = 0; | 349 | int result = 0; |
274 | acpi_status status = AE_OK; | 350 | acpi_status status = AE_OK; |
275 | acpi_handle handle = NULL; | 351 | acpi_handle handle = NULL; |
276 | struct acpi_device *device = NULL; | 352 | struct acpi_battery_info *bif = battery->bif_data.pointer; |
277 | struct acpi_battery_info *bif = NULL; | 353 | unsigned long alarm = battery->alarm; |
278 | 354 | ||
355 | /* See if alarms are supported, and if so, set default */ | ||
279 | 356 | ||
280 | if (!battery) | 357 | status = acpi_get_handle(acpi_battery_handle(battery), "_BTP", &handle); |
281 | return -EINVAL; | 358 | if (ACPI_SUCCESS(status)) { |
282 | 359 | battery->flags.alarm_present = 1; | |
283 | device = battery->device; | 360 | if (!alarm && bif) { |
361 | alarm = bif->design_capacity_warning; | ||
362 | } | ||
363 | result = acpi_battery_set_alarm(battery, alarm); | ||
364 | if (result) | ||
365 | goto end; | ||
366 | } else { | ||
367 | battery->flags.alarm_present = 0; | ||
368 | } | ||
284 | 369 | ||
285 | result = acpi_bus_get_status(device); | 370 | end: |
286 | if (result) | ||
287 | return result; | ||
288 | 371 | ||
289 | /* Insertion? */ | 372 | return result; |
373 | } | ||
290 | 374 | ||
291 | if (!battery->flags.present && device->status.battery_present) { | 375 | static int acpi_battery_init_update(struct acpi_battery *battery) |
376 | { | ||
377 | int result = 0; | ||
292 | 378 | ||
293 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Battery inserted\n")); | 379 | result = acpi_battery_get_status(battery); |
380 | if (result) | ||
381 | return result; | ||
294 | 382 | ||
295 | /* Evalute _BIF to get certain static information */ | 383 | battery->flags.battery_present_prev = acpi_battery_present(battery); |
296 | 384 | ||
297 | result = acpi_battery_get_info(battery, &bif); | 385 | if (acpi_battery_present(battery)) { |
386 | result = acpi_battery_get_info(battery); | ||
387 | if (result) | ||
388 | return result; | ||
389 | result = acpi_battery_get_state(battery); | ||
298 | if (result) | 390 | if (result) |
299 | return result; | 391 | return result; |
300 | 392 | ||
301 | battery->flags.power_unit = bif->power_unit; | 393 | acpi_battery_init_alarm(battery); |
302 | battery->trips.warning = bif->design_capacity_warning; | 394 | } |
303 | battery->trips.low = bif->design_capacity_low; | 395 | |
304 | kfree(bif); | 396 | return result; |
397 | } | ||
305 | 398 | ||
306 | /* See if alarms are supported, and if so, set default */ | 399 | static int acpi_battery_update(struct acpi_battery *battery, |
400 | int update, int *update_result_ptr) | ||
401 | { | ||
402 | int result = 0; | ||
403 | int update_result = ACPI_BATTERY_NONE_UPDATE; | ||
404 | |||
405 | if (!acpi_battery_present(battery)) { | ||
406 | update = 1; | ||
407 | } | ||
307 | 408 | ||
308 | status = acpi_get_handle(battery->device->handle, "_BTP", &handle); | 409 | if (battery->flags.init_update) { |
309 | if (ACPI_SUCCESS(status)) { | 410 | result = acpi_battery_init_update(battery); |
310 | battery->flags.alarm = 1; | 411 | if (result) |
311 | acpi_battery_set_alarm(battery, battery->trips.warning); | 412 | goto end; |
413 | update_result = ACPI_BATTERY_INIT_UPDATE; | ||
414 | } else if (update) { | ||
415 | result = acpi_battery_get_status(battery); | ||
416 | if (result) | ||
417 | goto end; | ||
418 | if ((!battery->flags.battery_present_prev & acpi_battery_present(battery)) | ||
419 | || (battery->flags.battery_present_prev & !acpi_battery_present(battery))) { | ||
420 | result = acpi_battery_init_update(battery); | ||
421 | if (result) | ||
422 | goto end; | ||
423 | update_result = ACPI_BATTERY_INIT_UPDATE; | ||
424 | } else { | ||
425 | update_result = ACPI_BATTERY_EASY_UPDATE; | ||
312 | } | 426 | } |
313 | } | 427 | } |
314 | 428 | ||
315 | /* Removal? */ | 429 | end: |
316 | 430 | ||
317 | else if (battery->flags.present && !device->status.battery_present) { | 431 | battery->flags.init_update = (result != 0); |
318 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Battery removed\n")); | ||
319 | } | ||
320 | 432 | ||
321 | battery->flags.present = device->status.battery_present; | 433 | *update_result_ptr = update_result; |
322 | 434 | ||
323 | return result; | 435 | return result; |
324 | } | 436 | } |
325 | 437 | ||
326 | static void acpi_battery_check_present(struct acpi_battery *battery) | 438 | static void acpi_battery_notify_update(struct acpi_battery *battery) |
327 | { | 439 | { |
328 | if (!battery->flags.present) { | 440 | acpi_battery_get_status(battery); |
329 | acpi_battery_check(battery); | 441 | |
442 | if (battery->flags.init_update) { | ||
443 | return; | ||
444 | } | ||
445 | |||
446 | if ((!battery->flags.battery_present_prev & | ||
447 | acpi_battery_present(battery)) || | ||
448 | (battery->flags.battery_present_prev & | ||
449 | !acpi_battery_present(battery))) { | ||
450 | battery->flags.init_update = 1; | ||
451 | } else { | ||
452 | battery->flags.update[ACPI_BATTERY_INFO] = 1; | ||
453 | battery->flags.update[ACPI_BATTERY_STATE] = 1; | ||
454 | battery->flags.update[ACPI_BATTERY_ALARM] = 1; | ||
330 | } | 455 | } |
331 | } | 456 | } |
332 | 457 | ||
@@ -335,37 +460,33 @@ static void acpi_battery_check_present(struct acpi_battery *battery) | |||
335 | -------------------------------------------------------------------------- */ | 460 | -------------------------------------------------------------------------- */ |
336 | 461 | ||
337 | static struct proc_dir_entry *acpi_battery_dir; | 462 | static struct proc_dir_entry *acpi_battery_dir; |
338 | static int acpi_battery_read_info(struct seq_file *seq, void *offset) | 463 | |
464 | static int acpi_battery_print_info(struct seq_file *seq, int result) | ||
339 | { | 465 | { |
340 | int result = 0; | ||
341 | struct acpi_battery *battery = seq->private; | 466 | struct acpi_battery *battery = seq->private; |
342 | struct acpi_battery_info *bif = NULL; | 467 | struct acpi_battery_info *bif = NULL; |
343 | char *units = "?"; | 468 | char *units = "?"; |
344 | 469 | ||
345 | 470 | if (result) | |
346 | if (!battery) | ||
347 | goto end; | 471 | goto end; |
348 | 472 | ||
349 | acpi_battery_check_present(battery); | 473 | if (acpi_battery_present(battery)) |
350 | |||
351 | if (battery->flags.present) | ||
352 | seq_printf(seq, "present: yes\n"); | 474 | seq_printf(seq, "present: yes\n"); |
353 | else { | 475 | else { |
354 | seq_printf(seq, "present: no\n"); | 476 | seq_printf(seq, "present: no\n"); |
355 | goto end; | 477 | goto end; |
356 | } | 478 | } |
357 | 479 | ||
358 | /* Battery Info (_BIF) */ | 480 | bif = battery->bif_data.pointer; |
359 | 481 | if (!bif) { | |
360 | result = acpi_battery_get_info(battery, &bif); | 482 | ACPI_EXCEPTION((AE_INFO, AE_ERROR, "BIF buffer is NULL")); |
361 | if (result || !bif) { | 483 | result = -ENODEV; |
362 | seq_printf(seq, "ERROR: Unable to read battery information\n"); | ||
363 | goto end; | 484 | goto end; |
364 | } | 485 | } |
365 | 486 | ||
366 | units = | 487 | /* Battery Units */ |
367 | bif-> | 488 | |
368 | power_unit ? ACPI_BATTERY_UNITS_AMPS : ACPI_BATTERY_UNITS_WATTS; | 489 | units = acpi_battery_power_units(battery); |
369 | 490 | ||
370 | if (bif->design_capacity == ACPI_BATTERY_VALUE_UNKNOWN) | 491 | if (bif->design_capacity == ACPI_BATTERY_VALUE_UNKNOWN) |
371 | seq_printf(seq, "design capacity: unknown\n"); | 492 | seq_printf(seq, "design capacity: unknown\n"); |
@@ -396,7 +517,6 @@ static int acpi_battery_read_info(struct seq_file *seq, void *offset) | |||
396 | else | 517 | else |
397 | seq_printf(seq, "design voltage: %d mV\n", | 518 | seq_printf(seq, "design voltage: %d mV\n", |
398 | (u32) bif->design_voltage); | 519 | (u32) bif->design_voltage); |
399 | |||
400 | seq_printf(seq, "design capacity warning: %d %sh\n", | 520 | seq_printf(seq, "design capacity warning: %d %sh\n", |
401 | (u32) bif->design_capacity_warning, units); | 521 | (u32) bif->design_capacity_warning, units); |
402 | seq_printf(seq, "design capacity low: %d %sh\n", | 522 | seq_printf(seq, "design capacity low: %d %sh\n", |
@@ -411,50 +531,40 @@ static int acpi_battery_read_info(struct seq_file *seq, void *offset) | |||
411 | seq_printf(seq, "OEM info: %s\n", bif->oem_info); | 531 | seq_printf(seq, "OEM info: %s\n", bif->oem_info); |
412 | 532 | ||
413 | end: | 533 | end: |
414 | kfree(bif); | ||
415 | 534 | ||
416 | return 0; | 535 | if (result) |
417 | } | 536 | seq_printf(seq, "ERROR: Unable to read battery info\n"); |
418 | 537 | ||
419 | static int acpi_battery_info_open_fs(struct inode *inode, struct file *file) | 538 | return result; |
420 | { | ||
421 | return single_open(file, acpi_battery_read_info, PDE(inode)->data); | ||
422 | } | 539 | } |
423 | 540 | ||
424 | static int acpi_battery_read_state(struct seq_file *seq, void *offset) | 541 | static int acpi_battery_print_state(struct seq_file *seq, int result) |
425 | { | 542 | { |
426 | int result = 0; | ||
427 | struct acpi_battery *battery = seq->private; | 543 | struct acpi_battery *battery = seq->private; |
428 | struct acpi_battery_status *bst = NULL; | 544 | struct acpi_battery_state *bst = NULL; |
429 | char *units = "?"; | 545 | char *units = "?"; |
430 | 546 | ||
431 | 547 | if (result) | |
432 | if (!battery) | ||
433 | goto end; | 548 | goto end; |
434 | 549 | ||
435 | acpi_battery_check_present(battery); | 550 | if (acpi_battery_present(battery)) |
436 | |||
437 | if (battery->flags.present) | ||
438 | seq_printf(seq, "present: yes\n"); | 551 | seq_printf(seq, "present: yes\n"); |
439 | else { | 552 | else { |
440 | seq_printf(seq, "present: no\n"); | 553 | seq_printf(seq, "present: no\n"); |
441 | goto end; | 554 | goto end; |
442 | } | 555 | } |
443 | 556 | ||
444 | /* Battery Units */ | 557 | bst = battery->bst_data.pointer; |
445 | 558 | if (!bst) { | |
446 | units = | 559 | ACPI_EXCEPTION((AE_INFO, AE_ERROR, "BST buffer is NULL")); |
447 | battery->flags. | 560 | result = -ENODEV; |
448 | power_unit ? ACPI_BATTERY_UNITS_AMPS : ACPI_BATTERY_UNITS_WATTS; | ||
449 | |||
450 | /* Battery Status (_BST) */ | ||
451 | |||
452 | result = acpi_battery_get_status(battery, &bst); | ||
453 | if (result || !bst) { | ||
454 | seq_printf(seq, "ERROR: Unable to read battery status\n"); | ||
455 | goto end; | 561 | goto end; |
456 | } | 562 | } |
457 | 563 | ||
564 | /* Battery Units */ | ||
565 | |||
566 | units = acpi_battery_power_units(battery); | ||
567 | |||
458 | if (!(bst->state & 0x04)) | 568 | if (!(bst->state & 0x04)) |
459 | seq_printf(seq, "capacity state: ok\n"); | 569 | seq_printf(seq, "capacity state: ok\n"); |
460 | else | 570 | else |
@@ -490,48 +600,43 @@ static int acpi_battery_read_state(struct seq_file *seq, void *offset) | |||
490 | (u32) bst->present_voltage); | 600 | (u32) bst->present_voltage); |
491 | 601 | ||
492 | end: | 602 | end: |
493 | kfree(bst); | ||
494 | 603 | ||
495 | return 0; | 604 | if (result) { |
496 | } | 605 | seq_printf(seq, "ERROR: Unable to read battery state\n"); |
606 | } | ||
497 | 607 | ||
498 | static int acpi_battery_state_open_fs(struct inode *inode, struct file *file) | 608 | return result; |
499 | { | ||
500 | return single_open(file, acpi_battery_read_state, PDE(inode)->data); | ||
501 | } | 609 | } |
502 | 610 | ||
503 | static int acpi_battery_read_alarm(struct seq_file *seq, void *offset) | 611 | static int acpi_battery_print_alarm(struct seq_file *seq, int result) |
504 | { | 612 | { |
505 | struct acpi_battery *battery = seq->private; | 613 | struct acpi_battery *battery = seq->private; |
506 | char *units = "?"; | 614 | char *units = "?"; |
507 | 615 | ||
508 | 616 | if (result) | |
509 | if (!battery) | ||
510 | goto end; | 617 | goto end; |
511 | 618 | ||
512 | acpi_battery_check_present(battery); | 619 | if (!acpi_battery_present(battery)) { |
513 | |||
514 | if (!battery->flags.present) { | ||
515 | seq_printf(seq, "present: no\n"); | 620 | seq_printf(seq, "present: no\n"); |
516 | goto end; | 621 | goto end; |
517 | } | 622 | } |
518 | 623 | ||
519 | /* Battery Units */ | 624 | /* Battery Units */ |
520 | 625 | ||
521 | units = | 626 | units = acpi_battery_power_units(battery); |
522 | battery->flags. | ||
523 | power_unit ? ACPI_BATTERY_UNITS_AMPS : ACPI_BATTERY_UNITS_WATTS; | ||
524 | |||
525 | /* Battery Alarm */ | ||
526 | 627 | ||
527 | seq_printf(seq, "alarm: "); | 628 | seq_printf(seq, "alarm: "); |
528 | if (!battery->alarm) | 629 | if (!battery->alarm) |
529 | seq_printf(seq, "unsupported\n"); | 630 | seq_printf(seq, "unsupported\n"); |
530 | else | 631 | else |
531 | seq_printf(seq, "%d %sh\n", (u32) battery->alarm, units); | 632 | seq_printf(seq, "%lu %sh\n", battery->alarm, units); |
532 | 633 | ||
533 | end: | 634 | end: |
534 | return 0; | 635 | |
636 | if (result) | ||
637 | seq_printf(seq, "ERROR: Unable to read battery alarm\n"); | ||
638 | |||
639 | return result; | ||
535 | } | 640 | } |
536 | 641 | ||
537 | static ssize_t | 642 | static ssize_t |
@@ -543,27 +648,113 @@ acpi_battery_write_alarm(struct file *file, | |||
543 | char alarm_string[12] = { '\0' }; | 648 | char alarm_string[12] = { '\0' }; |
544 | struct seq_file *m = file->private_data; | 649 | struct seq_file *m = file->private_data; |
545 | struct acpi_battery *battery = m->private; | 650 | struct acpi_battery *battery = m->private; |
546 | 651 | int update_result = ACPI_BATTERY_NONE_UPDATE; | |
547 | 652 | ||
548 | if (!battery || (count > sizeof(alarm_string) - 1)) | 653 | if (!battery || (count > sizeof(alarm_string) - 1)) |
549 | return -EINVAL; | 654 | return -EINVAL; |
550 | 655 | ||
551 | acpi_battery_check_present(battery); | 656 | mutex_lock(&battery->mutex); |
552 | 657 | ||
553 | if (!battery->flags.present) | 658 | result = acpi_battery_update(battery, 1, &update_result); |
554 | return -ENODEV; | 659 | if (result) { |
660 | result = -ENODEV; | ||
661 | goto end; | ||
662 | } | ||
663 | |||
664 | if (!acpi_battery_present(battery)) { | ||
665 | result = -ENODEV; | ||
666 | goto end; | ||
667 | } | ||
555 | 668 | ||
556 | if (copy_from_user(alarm_string, buffer, count)) | 669 | if (copy_from_user(alarm_string, buffer, count)) { |
557 | return -EFAULT; | 670 | result = -EFAULT; |
671 | goto end; | ||
672 | } | ||
558 | 673 | ||
559 | alarm_string[count] = '\0'; | 674 | alarm_string[count] = '\0'; |
560 | 675 | ||
561 | result = acpi_battery_set_alarm(battery, | 676 | result = acpi_battery_set_alarm(battery, |
562 | simple_strtoul(alarm_string, NULL, 0)); | 677 | simple_strtoul(alarm_string, NULL, 0)); |
563 | if (result) | 678 | if (result) |
564 | return result; | 679 | goto end; |
680 | |||
681 | end: | ||
565 | 682 | ||
566 | return count; | 683 | acpi_battery_check_result(battery, result); |
684 | |||
685 | if (!result) | ||
686 | result = count; | ||
687 | |||
688 | mutex_unlock(&battery->mutex); | ||
689 | |||
690 | return result; | ||
691 | } | ||
692 | |||
693 | typedef int(*print_func)(struct seq_file *seq, int result); | ||
694 | typedef int(*get_func)(struct acpi_battery *battery); | ||
695 | |||
696 | static struct acpi_read_mux { | ||
697 | print_func print; | ||
698 | get_func get; | ||
699 | } acpi_read_funcs[ACPI_BATTERY_NUMFILES] = { | ||
700 | {.get = acpi_battery_get_info, .print = acpi_battery_print_info}, | ||
701 | {.get = acpi_battery_get_state, .print = acpi_battery_print_state}, | ||
702 | {.get = acpi_battery_get_alarm, .print = acpi_battery_print_alarm}, | ||
703 | }; | ||
704 | |||
705 | static int acpi_battery_read(int fid, struct seq_file *seq) | ||
706 | { | ||
707 | struct acpi_battery *battery = seq->private; | ||
708 | int result = 0; | ||
709 | int update_result = ACPI_BATTERY_NONE_UPDATE; | ||
710 | int update = 0; | ||
711 | |||
712 | mutex_lock(&battery->mutex); | ||
713 | |||
714 | update = (get_seconds() - battery->update_time[fid] >= update_time); | ||
715 | update = (update | battery->flags.update[fid]); | ||
716 | |||
717 | result = acpi_battery_update(battery, update, &update_result); | ||
718 | if (result) | ||
719 | goto end; | ||
720 | |||
721 | if (update_result == ACPI_BATTERY_EASY_UPDATE) { | ||
722 | result = acpi_read_funcs[fid].get(battery); | ||
723 | if (result) | ||
724 | goto end; | ||
725 | } | ||
726 | |||
727 | end: | ||
728 | result = acpi_read_funcs[fid].print(seq, result); | ||
729 | acpi_battery_check_result(battery, result); | ||
730 | battery->flags.update[fid] = result; | ||
731 | mutex_unlock(&battery->mutex); | ||
732 | return result; | ||
733 | } | ||
734 | |||
735 | static int acpi_battery_read_info(struct seq_file *seq, void *offset) | ||
736 | { | ||
737 | return acpi_battery_read(ACPI_BATTERY_INFO, seq); | ||
738 | } | ||
739 | |||
740 | static int acpi_battery_read_state(struct seq_file *seq, void *offset) | ||
741 | { | ||
742 | return acpi_battery_read(ACPI_BATTERY_STATE, seq); | ||
743 | } | ||
744 | |||
745 | static int acpi_battery_read_alarm(struct seq_file *seq, void *offset) | ||
746 | { | ||
747 | return acpi_battery_read(ACPI_BATTERY_ALARM, seq); | ||
748 | } | ||
749 | |||
750 | static int acpi_battery_info_open_fs(struct inode *inode, struct file *file) | ||
751 | { | ||
752 | return single_open(file, acpi_battery_read_info, PDE(inode)->data); | ||
753 | } | ||
754 | |||
755 | static int acpi_battery_state_open_fs(struct inode *inode, struct file *file) | ||
756 | { | ||
757 | return single_open(file, acpi_battery_read_state, PDE(inode)->data); | ||
567 | } | 758 | } |
568 | 759 | ||
569 | static int acpi_battery_alarm_open_fs(struct inode *inode, struct file *file) | 760 | static int acpi_battery_alarm_open_fs(struct inode *inode, struct file *file) |
@@ -571,35 +762,51 @@ static int acpi_battery_alarm_open_fs(struct inode *inode, struct file *file) | |||
571 | return single_open(file, acpi_battery_read_alarm, PDE(inode)->data); | 762 | return single_open(file, acpi_battery_read_alarm, PDE(inode)->data); |
572 | } | 763 | } |
573 | 764 | ||
574 | static const struct file_operations acpi_battery_info_ops = { | 765 | static struct battery_file { |
766 | struct file_operations ops; | ||
767 | mode_t mode; | ||
768 | char *name; | ||
769 | } acpi_battery_file[] = { | ||
770 | { | ||
771 | .name = "info", | ||
772 | .mode = S_IRUGO, | ||
773 | .ops = { | ||
575 | .open = acpi_battery_info_open_fs, | 774 | .open = acpi_battery_info_open_fs, |
576 | .read = seq_read, | 775 | .read = seq_read, |
577 | .llseek = seq_lseek, | 776 | .llseek = seq_lseek, |
578 | .release = single_release, | 777 | .release = single_release, |
579 | .owner = THIS_MODULE, | 778 | .owner = THIS_MODULE, |
580 | }; | 779 | }, |
581 | 780 | }, | |
582 | static const struct file_operations acpi_battery_state_ops = { | 781 | { |
782 | .name = "state", | ||
783 | .mode = S_IRUGO, | ||
784 | .ops = { | ||
583 | .open = acpi_battery_state_open_fs, | 785 | .open = acpi_battery_state_open_fs, |
584 | .read = seq_read, | 786 | .read = seq_read, |
585 | .llseek = seq_lseek, | 787 | .llseek = seq_lseek, |
586 | .release = single_release, | 788 | .release = single_release, |
587 | .owner = THIS_MODULE, | 789 | .owner = THIS_MODULE, |
588 | }; | 790 | }, |
589 | 791 | }, | |
590 | static const struct file_operations acpi_battery_alarm_ops = { | 792 | { |
793 | .name = "alarm", | ||
794 | .mode = S_IFREG | S_IRUGO | S_IWUSR, | ||
795 | .ops = { | ||
591 | .open = acpi_battery_alarm_open_fs, | 796 | .open = acpi_battery_alarm_open_fs, |
592 | .read = seq_read, | 797 | .read = seq_read, |
593 | .write = acpi_battery_write_alarm, | 798 | .write = acpi_battery_write_alarm, |
594 | .llseek = seq_lseek, | 799 | .llseek = seq_lseek, |
595 | .release = single_release, | 800 | .release = single_release, |
596 | .owner = THIS_MODULE, | 801 | .owner = THIS_MODULE, |
802 | }, | ||
803 | }, | ||
597 | }; | 804 | }; |
598 | 805 | ||
599 | static int acpi_battery_add_fs(struct acpi_device *device) | 806 | static int acpi_battery_add_fs(struct acpi_device *device) |
600 | { | 807 | { |
601 | struct proc_dir_entry *entry = NULL; | 808 | struct proc_dir_entry *entry = NULL; |
602 | 809 | int i; | |
603 | 810 | ||
604 | if (!acpi_device_dir(device)) { | 811 | if (!acpi_device_dir(device)) { |
605 | acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device), | 812 | acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device), |
@@ -609,38 +816,16 @@ static int acpi_battery_add_fs(struct acpi_device *device) | |||
609 | acpi_device_dir(device)->owner = THIS_MODULE; | 816 | acpi_device_dir(device)->owner = THIS_MODULE; |
610 | } | 817 | } |
611 | 818 | ||
612 | /* 'info' [R] */ | 819 | for (i = 0; i < ACPI_BATTERY_NUMFILES; ++i) { |
613 | entry = create_proc_entry(ACPI_BATTERY_FILE_INFO, | 820 | entry = create_proc_entry(acpi_battery_file[i].name, |
614 | S_IRUGO, acpi_device_dir(device)); | 821 | acpi_battery_file[i].mode, acpi_device_dir(device)); |
615 | if (!entry) | 822 | if (!entry) |
616 | return -ENODEV; | 823 | return -ENODEV; |
617 | else { | 824 | else { |
618 | entry->proc_fops = &acpi_battery_info_ops; | 825 | entry->proc_fops = &acpi_battery_file[i].ops; |
619 | entry->data = acpi_driver_data(device); | 826 | entry->data = acpi_driver_data(device); |
620 | entry->owner = THIS_MODULE; | 827 | entry->owner = THIS_MODULE; |
621 | } | 828 | } |
622 | |||
623 | /* 'status' [R] */ | ||
624 | entry = create_proc_entry(ACPI_BATTERY_FILE_STATUS, | ||
625 | S_IRUGO, acpi_device_dir(device)); | ||
626 | if (!entry) | ||
627 | return -ENODEV; | ||
628 | else { | ||
629 | entry->proc_fops = &acpi_battery_state_ops; | ||
630 | entry->data = acpi_driver_data(device); | ||
631 | entry->owner = THIS_MODULE; | ||
632 | } | ||
633 | |||
634 | /* 'alarm' [R/W] */ | ||
635 | entry = create_proc_entry(ACPI_BATTERY_FILE_ALARM, | ||
636 | S_IFREG | S_IRUGO | S_IWUSR, | ||
637 | acpi_device_dir(device)); | ||
638 | if (!entry) | ||
639 | return -ENODEV; | ||
640 | else { | ||
641 | entry->proc_fops = &acpi_battery_alarm_ops; | ||
642 | entry->data = acpi_driver_data(device); | ||
643 | entry->owner = THIS_MODULE; | ||
644 | } | 829 | } |
645 | 830 | ||
646 | return 0; | 831 | return 0; |
@@ -648,15 +833,12 @@ static int acpi_battery_add_fs(struct acpi_device *device) | |||
648 | 833 | ||
649 | static int acpi_battery_remove_fs(struct acpi_device *device) | 834 | static int acpi_battery_remove_fs(struct acpi_device *device) |
650 | { | 835 | { |
651 | 836 | int i; | |
652 | if (acpi_device_dir(device)) { | 837 | if (acpi_device_dir(device)) { |
653 | remove_proc_entry(ACPI_BATTERY_FILE_ALARM, | 838 | for (i = 0; i < ACPI_BATTERY_NUMFILES; ++i) { |
839 | remove_proc_entry(acpi_battery_file[i].name, | ||
654 | acpi_device_dir(device)); | 840 | acpi_device_dir(device)); |
655 | remove_proc_entry(ACPI_BATTERY_FILE_STATUS, | 841 | } |
656 | acpi_device_dir(device)); | ||
657 | remove_proc_entry(ACPI_BATTERY_FILE_INFO, | ||
658 | acpi_device_dir(device)); | ||
659 | |||
660 | remove_proc_entry(acpi_device_bid(device), acpi_battery_dir); | 842 | remove_proc_entry(acpi_device_bid(device), acpi_battery_dir); |
661 | acpi_device_dir(device) = NULL; | 843 | acpi_device_dir(device) = NULL; |
662 | } | 844 | } |
@@ -673,7 +855,6 @@ static void acpi_battery_notify(acpi_handle handle, u32 event, void *data) | |||
673 | struct acpi_battery *battery = data; | 855 | struct acpi_battery *battery = data; |
674 | struct acpi_device *device = NULL; | 856 | struct acpi_device *device = NULL; |
675 | 857 | ||
676 | |||
677 | if (!battery) | 858 | if (!battery) |
678 | return; | 859 | return; |
679 | 860 | ||
@@ -684,8 +865,10 @@ static void acpi_battery_notify(acpi_handle handle, u32 event, void *data) | |||
684 | case ACPI_BATTERY_NOTIFY_INFO: | 865 | case ACPI_BATTERY_NOTIFY_INFO: |
685 | case ACPI_NOTIFY_BUS_CHECK: | 866 | case ACPI_NOTIFY_BUS_CHECK: |
686 | case ACPI_NOTIFY_DEVICE_CHECK: | 867 | case ACPI_NOTIFY_DEVICE_CHECK: |
687 | acpi_battery_check(battery); | 868 | device = battery->device; |
688 | acpi_bus_generate_event(device, event, battery->flags.present); | 869 | acpi_battery_notify_update(battery); |
870 | acpi_bus_generate_event(device, event, | ||
871 | acpi_battery_present(battery)); | ||
689 | break; | 872 | break; |
690 | default: | 873 | default: |
691 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, | 874 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, |
@@ -702,7 +885,6 @@ static int acpi_battery_add(struct acpi_device *device) | |||
702 | acpi_status status = 0; | 885 | acpi_status status = 0; |
703 | struct acpi_battery *battery = NULL; | 886 | struct acpi_battery *battery = NULL; |
704 | 887 | ||
705 | |||
706 | if (!device) | 888 | if (!device) |
707 | return -EINVAL; | 889 | return -EINVAL; |
708 | 890 | ||
@@ -710,15 +892,21 @@ static int acpi_battery_add(struct acpi_device *device) | |||
710 | if (!battery) | 892 | if (!battery) |
711 | return -ENOMEM; | 893 | return -ENOMEM; |
712 | 894 | ||
895 | mutex_init(&battery->mutex); | ||
896 | |||
897 | mutex_lock(&battery->mutex); | ||
898 | |||
713 | battery->device = device; | 899 | battery->device = device; |
714 | strcpy(acpi_device_name(device), ACPI_BATTERY_DEVICE_NAME); | 900 | strcpy(acpi_device_name(device), ACPI_BATTERY_DEVICE_NAME); |
715 | strcpy(acpi_device_class(device), ACPI_BATTERY_CLASS); | 901 | strcpy(acpi_device_class(device), ACPI_BATTERY_CLASS); |
716 | acpi_driver_data(device) = battery; | 902 | acpi_driver_data(device) = battery; |
717 | 903 | ||
718 | result = acpi_battery_check(battery); | 904 | result = acpi_battery_get_status(battery); |
719 | if (result) | 905 | if (result) |
720 | goto end; | 906 | goto end; |
721 | 907 | ||
908 | battery->flags.init_update = 1; | ||
909 | |||
722 | result = acpi_battery_add_fs(device); | 910 | result = acpi_battery_add_fs(device); |
723 | if (result) | 911 | if (result) |
724 | goto end; | 912 | goto end; |
@@ -727,6 +915,7 @@ static int acpi_battery_add(struct acpi_device *device) | |||
727 | ACPI_ALL_NOTIFY, | 915 | ACPI_ALL_NOTIFY, |
728 | acpi_battery_notify, battery); | 916 | acpi_battery_notify, battery); |
729 | if (ACPI_FAILURE(status)) { | 917 | if (ACPI_FAILURE(status)) { |
918 | ACPI_EXCEPTION((AE_INFO, status, "Installing notify handler")); | ||
730 | result = -ENODEV; | 919 | result = -ENODEV; |
731 | goto end; | 920 | goto end; |
732 | } | 921 | } |
@@ -736,11 +925,14 @@ static int acpi_battery_add(struct acpi_device *device) | |||
736 | device->status.battery_present ? "present" : "absent"); | 925 | device->status.battery_present ? "present" : "absent"); |
737 | 926 | ||
738 | end: | 927 | end: |
928 | |||
739 | if (result) { | 929 | if (result) { |
740 | acpi_battery_remove_fs(device); | 930 | acpi_battery_remove_fs(device); |
741 | kfree(battery); | 931 | kfree(battery); |
742 | } | 932 | } |
743 | 933 | ||
934 | mutex_unlock(&battery->mutex); | ||
935 | |||
744 | return result; | 936 | return result; |
745 | } | 937 | } |
746 | 938 | ||
@@ -749,18 +941,27 @@ static int acpi_battery_remove(struct acpi_device *device, int type) | |||
749 | acpi_status status = 0; | 941 | acpi_status status = 0; |
750 | struct acpi_battery *battery = NULL; | 942 | struct acpi_battery *battery = NULL; |
751 | 943 | ||
752 | |||
753 | if (!device || !acpi_driver_data(device)) | 944 | if (!device || !acpi_driver_data(device)) |
754 | return -EINVAL; | 945 | return -EINVAL; |
755 | 946 | ||
756 | battery = acpi_driver_data(device); | 947 | battery = acpi_driver_data(device); |
757 | 948 | ||
949 | mutex_lock(&battery->mutex); | ||
950 | |||
758 | status = acpi_remove_notify_handler(device->handle, | 951 | status = acpi_remove_notify_handler(device->handle, |
759 | ACPI_ALL_NOTIFY, | 952 | ACPI_ALL_NOTIFY, |
760 | acpi_battery_notify); | 953 | acpi_battery_notify); |
761 | 954 | ||
762 | acpi_battery_remove_fs(device); | 955 | acpi_battery_remove_fs(device); |
763 | 956 | ||
957 | kfree(battery->bif_data.pointer); | ||
958 | |||
959 | kfree(battery->bst_data.pointer); | ||
960 | |||
961 | mutex_unlock(&battery->mutex); | ||
962 | |||
963 | mutex_destroy(&battery->mutex); | ||
964 | |||
764 | kfree(battery); | 965 | kfree(battery); |
765 | 966 | ||
766 | return 0; | 967 | return 0; |
@@ -775,7 +976,10 @@ static int acpi_battery_resume(struct acpi_device *device) | |||
775 | return -EINVAL; | 976 | return -EINVAL; |
776 | 977 | ||
777 | battery = device->driver_data; | 978 | battery = device->driver_data; |
778 | return acpi_battery_check(battery); | 979 | |
980 | battery->flags.init_update = 1; | ||
981 | |||
982 | return 0; | ||
779 | } | 983 | } |
780 | 984 | ||
781 | static int __init acpi_battery_init(void) | 985 | static int __init acpi_battery_init(void) |
@@ -800,7 +1004,6 @@ static int __init acpi_battery_init(void) | |||
800 | 1004 | ||
801 | static void __exit acpi_battery_exit(void) | 1005 | static void __exit acpi_battery_exit(void) |
802 | { | 1006 | { |
803 | |||
804 | acpi_bus_unregister_driver(&acpi_battery_driver); | 1007 | acpi_bus_unregister_driver(&acpi_battery_driver); |
805 | 1008 | ||
806 | acpi_unlock_battery_dir(acpi_battery_dir); | 1009 | acpi_unlock_battery_dir(acpi_battery_dir); |