diff options
-rw-r--r-- | drivers/acpi/battery.c | 342 |
1 files changed, 125 insertions, 217 deletions
diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index faa70a50b807..db725bfe5840 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 | * |
@@ -48,6 +50,7 @@ | |||
48 | ACPI_MODULE_NAME("battery"); | 50 | ACPI_MODULE_NAME("battery"); |
49 | 51 | ||
50 | MODULE_AUTHOR("Paul Diefenbaugh"); | 52 | MODULE_AUTHOR("Paul Diefenbaugh"); |
53 | MODULE_AUTHOR("Alexey Starikovskiy <astarikovskiy@suse.de>"); | ||
51 | MODULE_DESCRIPTION("ACPI Battery Driver"); | 54 | MODULE_DESCRIPTION("ACPI Battery Driver"); |
52 | MODULE_LICENSE("GPL"); | 55 | MODULE_LICENSE("GPL"); |
53 | 56 | ||
@@ -58,31 +61,17 @@ MODULE_PARM_DESC(cache_time, "cache time in milliseconds"); | |||
58 | extern struct proc_dir_entry *acpi_lock_battery_dir(void); | 61 | extern struct proc_dir_entry *acpi_lock_battery_dir(void); |
59 | extern void *acpi_unlock_battery_dir(struct proc_dir_entry *acpi_battery_dir); | 62 | extern void *acpi_unlock_battery_dir(struct proc_dir_entry *acpi_battery_dir); |
60 | 63 | ||
61 | static int acpi_battery_add(struct acpi_device *device); | ||
62 | static int acpi_battery_remove(struct acpi_device *device, int type); | ||
63 | static int acpi_battery_resume(struct acpi_device *device); | ||
64 | |||
65 | static const struct acpi_device_id battery_device_ids[] = { | 64 | static const struct acpi_device_id battery_device_ids[] = { |
66 | {"PNP0C0A", 0}, | 65 | {"PNP0C0A", 0}, |
67 | {"", 0}, | 66 | {"", 0}, |
68 | }; | 67 | }; |
69 | MODULE_DEVICE_TABLE(acpi, battery_device_ids); | ||
70 | 68 | ||
71 | static struct acpi_driver acpi_battery_driver = { | 69 | MODULE_DEVICE_TABLE(acpi, battery_device_ids); |
72 | .name = "battery", | ||
73 | .class = ACPI_BATTERY_CLASS, | ||
74 | .ids = battery_device_ids, | ||
75 | .ops = { | ||
76 | .add = acpi_battery_add, | ||
77 | .resume = acpi_battery_resume, | ||
78 | .remove = acpi_battery_remove, | ||
79 | }, | ||
80 | }; | ||
81 | 70 | ||
82 | enum acpi_battery_files { | 71 | enum acpi_battery_files { |
83 | ACPI_BATTERY_INFO = 0, | 72 | info_tag = 0, |
84 | ACPI_BATTERY_STATE, | 73 | state_tag, |
85 | ACPI_BATTERY_ALARM, | 74 | alarm_tag, |
86 | ACPI_BATTERY_NUMFILES, | 75 | ACPI_BATTERY_NUMFILES, |
87 | }; | 76 | }; |
88 | 77 | ||
@@ -124,7 +113,6 @@ inline char *acpi_battery_units(struct acpi_battery *battery) | |||
124 | /* -------------------------------------------------------------------------- | 113 | /* -------------------------------------------------------------------------- |
125 | Battery Management | 114 | Battery Management |
126 | -------------------------------------------------------------------------- */ | 115 | -------------------------------------------------------------------------- */ |
127 | |||
128 | struct acpi_offsets { | 116 | struct acpi_offsets { |
129 | size_t offset; /* offset inside struct acpi_sbs_battery */ | 117 | size_t offset; /* offset inside struct acpi_sbs_battery */ |
130 | u8 mode; /* int or string? */ | 118 | u8 mode; /* int or string? */ |
@@ -183,19 +171,16 @@ static int extract_package(struct acpi_battery *battery, | |||
183 | 171 | ||
184 | static int acpi_battery_get_status(struct acpi_battery *battery) | 172 | static int acpi_battery_get_status(struct acpi_battery *battery) |
185 | { | 173 | { |
186 | int result = 0; | 174 | if (acpi_bus_get_status(battery->device)) { |
187 | |||
188 | result = acpi_bus_get_status(battery->device); | ||
189 | if (result) { | ||
190 | ACPI_EXCEPTION((AE_INFO, AE_ERROR, "Evaluating _STA")); | 175 | ACPI_EXCEPTION((AE_INFO, AE_ERROR, "Evaluating _STA")); |
191 | return -ENODEV; | 176 | return -ENODEV; |
192 | } | 177 | } |
193 | return result; | 178 | return 0; |
194 | } | 179 | } |
195 | 180 | ||
196 | static int acpi_battery_get_info(struct acpi_battery *battery) | 181 | static int acpi_battery_get_info(struct acpi_battery *battery) |
197 | { | 182 | { |
198 | int result = 0; | 183 | int result = -EFAULT; |
199 | acpi_status status = 0; | 184 | acpi_status status = 0; |
200 | struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; | 185 | struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; |
201 | 186 | ||
@@ -205,10 +190,12 @@ static int acpi_battery_get_info(struct acpi_battery *battery) | |||
205 | status = acpi_evaluate_object(battery->device->handle, "_BIF", | 190 | status = acpi_evaluate_object(battery->device->handle, "_BIF", |
206 | NULL, &buffer); | 191 | NULL, &buffer); |
207 | mutex_unlock(&battery->lock); | 192 | mutex_unlock(&battery->lock); |
193 | |||
208 | if (ACPI_FAILURE(status)) { | 194 | if (ACPI_FAILURE(status)) { |
209 | ACPI_EXCEPTION((AE_INFO, status, "Evaluating _BIF")); | 195 | ACPI_EXCEPTION((AE_INFO, status, "Evaluating _BIF")); |
210 | return -ENODEV; | 196 | return -ENODEV; |
211 | } | 197 | } |
198 | |||
212 | result = extract_package(battery, buffer.pointer, | 199 | result = extract_package(battery, buffer.pointer, |
213 | info_offsets, ARRAY_SIZE(info_offsets)); | 200 | info_offsets, ARRAY_SIZE(info_offsets)); |
214 | kfree(buffer.pointer); | 201 | kfree(buffer.pointer); |
@@ -238,6 +225,7 @@ static int acpi_battery_get_state(struct acpi_battery *battery) | |||
238 | ACPI_EXCEPTION((AE_INFO, status, "Evaluating _BST")); | 225 | ACPI_EXCEPTION((AE_INFO, status, "Evaluating _BST")); |
239 | return -ENODEV; | 226 | return -ENODEV; |
240 | } | 227 | } |
228 | |||
241 | result = extract_package(battery, buffer.pointer, | 229 | result = extract_package(battery, buffer.pointer, |
242 | state_offsets, ARRAY_SIZE(state_offsets)); | 230 | state_offsets, ARRAY_SIZE(state_offsets)); |
243 | battery->update_time = jiffies; | 231 | battery->update_time = jiffies; |
@@ -245,37 +233,26 @@ static int acpi_battery_get_state(struct acpi_battery *battery) | |||
245 | return result; | 233 | return result; |
246 | } | 234 | } |
247 | 235 | ||
248 | static int acpi_battery_get_alarm(struct acpi_battery *battery) | 236 | static int acpi_battery_set_alarm(struct acpi_battery *battery) |
249 | { | ||
250 | return 0; | ||
251 | } | ||
252 | |||
253 | static int acpi_battery_set_alarm(struct acpi_battery *battery, | ||
254 | unsigned long alarm) | ||
255 | { | 237 | { |
256 | acpi_status status = 0; | 238 | acpi_status status = 0; |
257 | union acpi_object arg0 = { ACPI_TYPE_INTEGER }; | 239 | union acpi_object arg0 = { .type = ACPI_TYPE_INTEGER }; |
258 | struct acpi_object_list arg_list = { 1, &arg0 }; | 240 | struct acpi_object_list arg_list = { 1, &arg0 }; |
259 | 241 | ||
260 | if (!acpi_battery_present(battery)) | 242 | if (!acpi_battery_present(battery)|| !battery->alarm_present) |
261 | return -ENODEV; | ||
262 | |||
263 | if (!battery->alarm_present) | ||
264 | return -ENODEV; | 243 | return -ENODEV; |
265 | 244 | ||
266 | arg0.integer.value = alarm; | 245 | arg0.integer.value = battery->alarm; |
267 | 246 | ||
268 | mutex_lock(&battery->lock); | 247 | mutex_lock(&battery->lock); |
269 | status = acpi_evaluate_object(battery->device->handle, "_BTP", | 248 | status = acpi_evaluate_object(battery->device->handle, "_BTP", |
270 | &arg_list, NULL); | 249 | &arg_list, NULL); |
271 | mutex_unlock(&battery->lock); | 250 | mutex_unlock(&battery->lock); |
251 | |||
272 | if (ACPI_FAILURE(status)) | 252 | if (ACPI_FAILURE(status)) |
273 | return -ENODEV; | 253 | return -ENODEV; |
274 | 254 | ||
275 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Alarm set to %d\n", (u32) alarm)); | 255 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Alarm set to %d\n", battery->alarm)); |
276 | |||
277 | battery->alarm = alarm; | ||
278 | |||
279 | return 0; | 256 | return 0; |
280 | } | 257 | } |
281 | 258 | ||
@@ -293,7 +270,7 @@ static int acpi_battery_init_alarm(struct acpi_battery *battery) | |||
293 | battery->alarm_present = 1; | 270 | battery->alarm_present = 1; |
294 | if (!battery->alarm) | 271 | if (!battery->alarm) |
295 | battery->alarm = battery->design_capacity_warning; | 272 | battery->alarm = battery->design_capacity_warning; |
296 | return acpi_battery_set_alarm(battery, battery->alarm); | 273 | return acpi_battery_set_alarm(battery); |
297 | } | 274 | } |
298 | 275 | ||
299 | static int acpi_battery_update(struct acpi_battery *battery) | 276 | static int acpi_battery_update(struct acpi_battery *battery) |
@@ -322,130 +299,101 @@ static struct proc_dir_entry *acpi_battery_dir; | |||
322 | static int acpi_battery_print_info(struct seq_file *seq, int result) | 299 | static int acpi_battery_print_info(struct seq_file *seq, int result) |
323 | { | 300 | { |
324 | struct acpi_battery *battery = seq->private; | 301 | struct acpi_battery *battery = seq->private; |
325 | char *units = "?"; | ||
326 | 302 | ||
327 | if (result) | 303 | if (result) |
328 | goto end; | 304 | goto end; |
329 | 305 | ||
330 | if (acpi_battery_present(battery)) | 306 | seq_printf(seq, "present: %s\n", |
331 | seq_printf(seq, "present: yes\n"); | 307 | acpi_battery_present(battery)?"yes":"no"); |
332 | else { | 308 | if (!acpi_battery_present(battery)) |
333 | seq_printf(seq, "present: no\n"); | ||
334 | goto end; | 309 | goto end; |
335 | } | ||
336 | |||
337 | /* Battery Units */ | ||
338 | |||
339 | units = acpi_battery_units(battery); | ||
340 | |||
341 | if (battery->design_capacity == ACPI_BATTERY_VALUE_UNKNOWN) | 310 | if (battery->design_capacity == ACPI_BATTERY_VALUE_UNKNOWN) |
342 | seq_printf(seq, "design capacity: unknown\n"); | 311 | seq_printf(seq, "design capacity: unknown\n"); |
343 | else | 312 | else |
344 | seq_printf(seq, "design capacity: %d %sh\n", | 313 | seq_printf(seq, "design capacity: %d %sh\n", |
345 | (u32) battery->design_capacity, units); | 314 | battery->design_capacity, |
315 | acpi_battery_units(battery)); | ||
346 | 316 | ||
347 | if (battery->last_full_capacity == ACPI_BATTERY_VALUE_UNKNOWN) | 317 | if (battery->last_full_capacity == ACPI_BATTERY_VALUE_UNKNOWN) |
348 | seq_printf(seq, "last full capacity: unknown\n"); | 318 | seq_printf(seq, "last full capacity: unknown\n"); |
349 | else | 319 | else |
350 | seq_printf(seq, "last full capacity: %d %sh\n", | 320 | seq_printf(seq, "last full capacity: %d %sh\n", |
351 | (u32) battery->last_full_capacity, units); | 321 | battery->last_full_capacity, |
352 | 322 | acpi_battery_units(battery)); | |
353 | switch ((u32) battery->technology) { | 323 | |
354 | case 0: | 324 | seq_printf(seq, "battery technology: %srechargeable\n", |
355 | seq_printf(seq, "battery technology: non-rechargeable\n"); | 325 | (!battery->technology)?"non-":""); |
356 | break; | ||
357 | case 1: | ||
358 | seq_printf(seq, "battery technology: rechargeable\n"); | ||
359 | break; | ||
360 | default: | ||
361 | seq_printf(seq, "battery technology: unknown\n"); | ||
362 | break; | ||
363 | } | ||
364 | 326 | ||
365 | if (battery->design_voltage == ACPI_BATTERY_VALUE_UNKNOWN) | 327 | if (battery->design_voltage == ACPI_BATTERY_VALUE_UNKNOWN) |
366 | seq_printf(seq, "design voltage: unknown\n"); | 328 | seq_printf(seq, "design voltage: unknown\n"); |
367 | else | 329 | else |
368 | seq_printf(seq, "design voltage: %d mV\n", | 330 | seq_printf(seq, "design voltage: %d mV\n", |
369 | (u32) battery->design_voltage); | 331 | battery->design_voltage); |
370 | seq_printf(seq, "design capacity warning: %d %sh\n", | 332 | seq_printf(seq, "design capacity warning: %d %sh\n", |
371 | (u32) battery->design_capacity_warning, units); | 333 | battery->design_capacity_warning, |
334 | acpi_battery_units(battery)); | ||
372 | seq_printf(seq, "design capacity low: %d %sh\n", | 335 | seq_printf(seq, "design capacity low: %d %sh\n", |
373 | (u32) battery->design_capacity_low, units); | 336 | battery->design_capacity_low, |
337 | acpi_battery_units(battery)); | ||
374 | seq_printf(seq, "capacity granularity 1: %d %sh\n", | 338 | seq_printf(seq, "capacity granularity 1: %d %sh\n", |
375 | (u32) battery->capacity_granularity_1, units); | 339 | battery->capacity_granularity_1, |
340 | acpi_battery_units(battery)); | ||
376 | seq_printf(seq, "capacity granularity 2: %d %sh\n", | 341 | seq_printf(seq, "capacity granularity 2: %d %sh\n", |
377 | (u32) battery->capacity_granularity_2, units); | 342 | battery->capacity_granularity_2, |
343 | acpi_battery_units(battery)); | ||
378 | seq_printf(seq, "model number: %s\n", battery->model_number); | 344 | seq_printf(seq, "model number: %s\n", battery->model_number); |
379 | seq_printf(seq, "serial number: %s\n", battery->serial_number); | 345 | seq_printf(seq, "serial number: %s\n", battery->serial_number); |
380 | seq_printf(seq, "battery type: %s\n", battery->type); | 346 | seq_printf(seq, "battery type: %s\n", battery->type); |
381 | seq_printf(seq, "OEM info: %s\n", battery->oem_info); | 347 | seq_printf(seq, "OEM info: %s\n", battery->oem_info); |
382 | |||
383 | end: | 348 | end: |
384 | |||
385 | if (result) | 349 | if (result) |
386 | seq_printf(seq, "ERROR: Unable to read battery info\n"); | 350 | seq_printf(seq, "ERROR: Unable to read battery info\n"); |
387 | |||
388 | return result; | 351 | return result; |
389 | } | 352 | } |
390 | 353 | ||
391 | static int acpi_battery_print_state(struct seq_file *seq, int result) | 354 | static int acpi_battery_print_state(struct seq_file *seq, int result) |
392 | { | 355 | { |
393 | struct acpi_battery *battery = seq->private; | 356 | struct acpi_battery *battery = seq->private; |
394 | char *units = "?"; | ||
395 | 357 | ||
396 | if (result) | 358 | if (result) |
397 | goto end; | 359 | goto end; |
398 | 360 | ||
399 | if (acpi_battery_present(battery)) | 361 | seq_printf(seq, "present: %s\n", |
400 | seq_printf(seq, "present: yes\n"); | 362 | acpi_battery_present(battery)?"yes":"no"); |
401 | else { | 363 | if (!acpi_battery_present(battery)) |
402 | seq_printf(seq, "present: no\n"); | ||
403 | goto end; | 364 | goto end; |
404 | } | ||
405 | |||
406 | /* Battery Units */ | ||
407 | |||
408 | units = acpi_battery_units(battery); | ||
409 | 365 | ||
410 | if (!(battery->state & 0x04)) | 366 | seq_printf(seq, "capacity state: %s\n", |
411 | seq_printf(seq, "capacity state: ok\n"); | 367 | (battery->state & 0x04)?"critical":"ok"); |
412 | else | 368 | if ((battery->state & 0x01) && (battery->state & 0x02)) |
413 | seq_printf(seq, "capacity state: critical\n"); | ||
414 | |||
415 | if ((battery->state & 0x01) && (battery->state & 0x02)) { | ||
416 | seq_printf(seq, | 369 | seq_printf(seq, |
417 | "charging state: charging/discharging\n"); | 370 | "charging state: charging/discharging\n"); |
418 | } else if (battery->state & 0x01) | 371 | else if (battery->state & 0x01) |
419 | seq_printf(seq, "charging state: discharging\n"); | 372 | seq_printf(seq, "charging state: discharging\n"); |
420 | else if (battery->state & 0x02) | 373 | else if (battery->state & 0x02) |
421 | seq_printf(seq, "charging state: charging\n"); | 374 | seq_printf(seq, "charging state: charging\n"); |
422 | else { | 375 | else |
423 | seq_printf(seq, "charging state: charged\n"); | 376 | seq_printf(seq, "charging state: charged\n"); |
424 | } | ||
425 | 377 | ||
426 | if (battery->present_rate == ACPI_BATTERY_VALUE_UNKNOWN) | 378 | if (battery->present_rate == ACPI_BATTERY_VALUE_UNKNOWN) |
427 | seq_printf(seq, "present rate: unknown\n"); | 379 | seq_printf(seq, "present rate: unknown\n"); |
428 | else | 380 | else |
429 | seq_printf(seq, "present rate: %d %s\n", | 381 | seq_printf(seq, "present rate: %d %s\n", |
430 | (u32) battery->present_rate, units); | 382 | battery->present_rate, acpi_battery_units(battery)); |
431 | 383 | ||
432 | if (battery->remaining_capacity == ACPI_BATTERY_VALUE_UNKNOWN) | 384 | if (battery->remaining_capacity == ACPI_BATTERY_VALUE_UNKNOWN) |
433 | seq_printf(seq, "remaining capacity: unknown\n"); | 385 | seq_printf(seq, "remaining capacity: unknown\n"); |
434 | else | 386 | else |
435 | seq_printf(seq, "remaining capacity: %d %sh\n", | 387 | seq_printf(seq, "remaining capacity: %d %sh\n", |
436 | (u32) battery->remaining_capacity, units); | 388 | battery->remaining_capacity, acpi_battery_units(battery)); |
437 | |||
438 | if (battery->present_voltage == ACPI_BATTERY_VALUE_UNKNOWN) | 389 | if (battery->present_voltage == ACPI_BATTERY_VALUE_UNKNOWN) |
439 | seq_printf(seq, "present voltage: unknown\n"); | 390 | seq_printf(seq, "present voltage: unknown\n"); |
440 | else | 391 | else |
441 | seq_printf(seq, "present voltage: %d mV\n", | 392 | seq_printf(seq, "present voltage: %d mV\n", |
442 | (u32) battery->present_voltage); | 393 | battery->present_voltage); |
443 | |||
444 | end: | 394 | end: |
445 | 395 | if (result) | |
446 | if (result) { | ||
447 | seq_printf(seq, "ERROR: Unable to read battery state\n"); | 396 | seq_printf(seq, "ERROR: Unable to read battery state\n"); |
448 | } | ||
449 | 397 | ||
450 | return result; | 398 | return result; |
451 | } | 399 | } |
@@ -453,7 +401,6 @@ static int acpi_battery_print_state(struct seq_file *seq, int result) | |||
453 | static int acpi_battery_print_alarm(struct seq_file *seq, int result) | 401 | static int acpi_battery_print_alarm(struct seq_file *seq, int result) |
454 | { | 402 | { |
455 | struct acpi_battery *battery = seq->private; | 403 | struct acpi_battery *battery = seq->private; |
456 | char *units = "?"; | ||
457 | 404 | ||
458 | if (result) | 405 | if (result) |
459 | goto end; | 406 | goto end; |
@@ -462,22 +409,15 @@ static int acpi_battery_print_alarm(struct seq_file *seq, int result) | |||
462 | seq_printf(seq, "present: no\n"); | 409 | seq_printf(seq, "present: no\n"); |
463 | goto end; | 410 | goto end; |
464 | } | 411 | } |
465 | |||
466 | /* Battery Units */ | ||
467 | |||
468 | units = acpi_battery_units(battery); | ||
469 | |||
470 | seq_printf(seq, "alarm: "); | 412 | seq_printf(seq, "alarm: "); |
471 | if (!battery->alarm) | 413 | if (!battery->alarm) |
472 | seq_printf(seq, "unsupported\n"); | 414 | seq_printf(seq, "unsupported\n"); |
473 | else | 415 | else |
474 | seq_printf(seq, "%u %sh\n", battery->alarm, units); | 416 | seq_printf(seq, "%u %sh\n", battery->alarm, |
475 | 417 | acpi_battery_units(battery)); | |
476 | end: | 418 | end: |
477 | |||
478 | if (result) | 419 | if (result) |
479 | seq_printf(seq, "ERROR: Unable to read battery alarm\n"); | 420 | seq_printf(seq, "ERROR: Unable to read battery alarm\n"); |
480 | |||
481 | return result; | 421 | return result; |
482 | } | 422 | } |
483 | 423 | ||
@@ -506,7 +446,7 @@ static ssize_t acpi_battery_write_alarm(struct file *file, | |||
506 | } | 446 | } |
507 | alarm_string[count] = '\0'; | 447 | alarm_string[count] = '\0'; |
508 | battery->alarm = simple_strtol(alarm_string, NULL, 0); | 448 | battery->alarm = simple_strtol(alarm_string, NULL, 0); |
509 | result = acpi_battery_set_alarm(battery, battery->alarm); | 449 | result = acpi_battery_set_alarm(battery); |
510 | end: | 450 | end: |
511 | if (!result) | 451 | if (!result) |
512 | return count; | 452 | return count; |
@@ -514,95 +454,76 @@ static ssize_t acpi_battery_write_alarm(struct file *file, | |||
514 | } | 454 | } |
515 | 455 | ||
516 | typedef int(*print_func)(struct seq_file *seq, int result); | 456 | typedef int(*print_func)(struct seq_file *seq, int result); |
517 | typedef int(*get_func)(struct acpi_battery *battery); | 457 | |
518 | 458 | static print_func acpi_print_funcs[ACPI_BATTERY_NUMFILES] = { | |
519 | static struct acpi_read_mux { | 459 | acpi_battery_print_info, |
520 | print_func print; | 460 | acpi_battery_print_state, |
521 | get_func get; | 461 | acpi_battery_print_alarm, |
522 | } acpi_read_funcs[ACPI_BATTERY_NUMFILES] = { | ||
523 | {.get = acpi_battery_get_info, .print = acpi_battery_print_info}, | ||
524 | {.get = acpi_battery_get_state, .print = acpi_battery_print_state}, | ||
525 | {.get = acpi_battery_get_alarm, .print = acpi_battery_print_alarm}, | ||
526 | }; | 462 | }; |
527 | 463 | ||
528 | static int acpi_battery_read(int fid, struct seq_file *seq) | 464 | static int acpi_battery_read(int fid, struct seq_file *seq) |
529 | { | 465 | { |
530 | struct acpi_battery *battery = seq->private; | 466 | struct acpi_battery *battery = seq->private; |
531 | int result = acpi_battery_update(battery); | 467 | int result = acpi_battery_update(battery); |
532 | return acpi_read_funcs[fid].print(seq, result); | 468 | return acpi_print_funcs[fid](seq, result); |
533 | } | ||
534 | |||
535 | static int acpi_battery_read_info(struct seq_file *seq, void *offset) | ||
536 | { | ||
537 | return acpi_battery_read(ACPI_BATTERY_INFO, seq); | ||
538 | } | ||
539 | |||
540 | static int acpi_battery_read_state(struct seq_file *seq, void *offset) | ||
541 | { | ||
542 | return acpi_battery_read(ACPI_BATTERY_STATE, seq); | ||
543 | } | ||
544 | |||
545 | static int acpi_battery_read_alarm(struct seq_file *seq, void *offset) | ||
546 | { | ||
547 | return acpi_battery_read(ACPI_BATTERY_ALARM, seq); | ||
548 | } | 469 | } |
549 | 470 | ||
550 | static int acpi_battery_info_open_fs(struct inode *inode, struct file *file) | 471 | #define DECLARE_FILE_FUNCTIONS(_name) \ |
551 | { | 472 | static int acpi_battery_read_##_name(struct seq_file *seq, void *offset) \ |
552 | return single_open(file, acpi_battery_read_info, PDE(inode)->data); | 473 | { \ |
474 | return acpi_battery_read(_name##_tag, seq); \ | ||
475 | } \ | ||
476 | static int acpi_battery_##_name##_open_fs(struct inode *inode, struct file *file) \ | ||
477 | { \ | ||
478 | return single_open(file, acpi_battery_read_##_name, PDE(inode)->data); \ | ||
553 | } | 479 | } |
554 | 480 | ||
555 | static int acpi_battery_state_open_fs(struct inode *inode, struct file *file) | 481 | DECLARE_FILE_FUNCTIONS(info); |
556 | { | 482 | DECLARE_FILE_FUNCTIONS(state); |
557 | return single_open(file, acpi_battery_read_state, PDE(inode)->data); | 483 | DECLARE_FILE_FUNCTIONS(alarm); |
558 | } | 484 | |
485 | #undef DECLARE_FILE_FUNCTIONS | ||
486 | |||
487 | #define FILE_DESCRIPTION_RO(_name) \ | ||
488 | { \ | ||
489 | .name = __stringify(_name), \ | ||
490 | .mode = S_IRUGO, \ | ||
491 | .ops = { \ | ||
492 | .open = acpi_battery_##_name##_open_fs, \ | ||
493 | .read = seq_read, \ | ||
494 | .llseek = seq_lseek, \ | ||
495 | .release = single_release, \ | ||
496 | .owner = THIS_MODULE, \ | ||
497 | }, \ | ||
498 | } | ||
559 | 499 | ||
560 | static int acpi_battery_alarm_open_fs(struct inode *inode, struct file *file) | 500 | #define FILE_DESCRIPTION_RW(_name) \ |
561 | { | 501 | { \ |
562 | return single_open(file, acpi_battery_read_alarm, PDE(inode)->data); | 502 | .name = __stringify(_name), \ |
563 | } | 503 | .mode = S_IFREG | S_IRUGO | S_IWUSR, \ |
504 | .ops = { \ | ||
505 | .open = acpi_battery_##_name##_open_fs, \ | ||
506 | .read = seq_read, \ | ||
507 | .llseek = seq_lseek, \ | ||
508 | .write = acpi_battery_write_##_name, \ | ||
509 | .release = single_release, \ | ||
510 | .owner = THIS_MODULE, \ | ||
511 | }, \ | ||
512 | } | ||
564 | 513 | ||
565 | static struct battery_file { | 514 | static struct battery_file { |
566 | struct file_operations ops; | 515 | struct file_operations ops; |
567 | mode_t mode; | 516 | mode_t mode; |
568 | char *name; | 517 | char *name; |
569 | } acpi_battery_file[] = { | 518 | } acpi_battery_file[] = { |
570 | { | 519 | FILE_DESCRIPTION_RO(info), |
571 | .name = "info", | 520 | FILE_DESCRIPTION_RO(state), |
572 | .mode = S_IRUGO, | 521 | FILE_DESCRIPTION_RW(alarm), |
573 | .ops = { | ||
574 | .open = acpi_battery_info_open_fs, | ||
575 | .read = seq_read, | ||
576 | .llseek = seq_lseek, | ||
577 | .release = single_release, | ||
578 | .owner = THIS_MODULE, | ||
579 | }, | ||
580 | }, | ||
581 | { | ||
582 | .name = "state", | ||
583 | .mode = S_IRUGO, | ||
584 | .ops = { | ||
585 | .open = acpi_battery_state_open_fs, | ||
586 | .read = seq_read, | ||
587 | .llseek = seq_lseek, | ||
588 | .release = single_release, | ||
589 | .owner = THIS_MODULE, | ||
590 | }, | ||
591 | }, | ||
592 | { | ||
593 | .name = "alarm", | ||
594 | .mode = S_IFREG | S_IRUGO | S_IWUSR, | ||
595 | .ops = { | ||
596 | .open = acpi_battery_alarm_open_fs, | ||
597 | .read = seq_read, | ||
598 | .write = acpi_battery_write_alarm, | ||
599 | .llseek = seq_lseek, | ||
600 | .release = single_release, | ||
601 | .owner = THIS_MODULE, | ||
602 | }, | ||
603 | }, | ||
604 | }; | 522 | }; |
605 | 523 | ||
524 | #undef FILE_DESCRIPTION_RO | ||
525 | #undef FILE_DESCRIPTION_RW | ||
526 | |||
606 | static int acpi_battery_add_fs(struct acpi_device *device) | 527 | static int acpi_battery_add_fs(struct acpi_device *device) |
607 | { | 528 | { |
608 | struct proc_dir_entry *entry = NULL; | 529 | struct proc_dir_entry *entry = NULL; |
@@ -627,23 +548,20 @@ static int acpi_battery_add_fs(struct acpi_device *device) | |||
627 | entry->owner = THIS_MODULE; | 548 | entry->owner = THIS_MODULE; |
628 | } | 549 | } |
629 | } | 550 | } |
630 | |||
631 | return 0; | 551 | return 0; |
632 | } | 552 | } |
633 | 553 | ||
634 | static int acpi_battery_remove_fs(struct acpi_device *device) | 554 | static void acpi_battery_remove_fs(struct acpi_device *device) |
635 | { | 555 | { |
636 | int i; | 556 | int i; |
637 | if (acpi_device_dir(device)) { | 557 | if (!acpi_device_dir(device)) |
638 | for (i = 0; i < ACPI_BATTERY_NUMFILES; ++i) { | 558 | return; |
639 | remove_proc_entry(acpi_battery_file[i].name, | 559 | for (i = 0; i < ACPI_BATTERY_NUMFILES; ++i) |
560 | remove_proc_entry(acpi_battery_file[i].name, | ||
640 | acpi_device_dir(device)); | 561 | acpi_device_dir(device)); |
641 | } | ||
642 | remove_proc_entry(acpi_device_bid(device), acpi_battery_dir); | ||
643 | acpi_device_dir(device) = NULL; | ||
644 | } | ||
645 | 562 | ||
646 | return 0; | 563 | remove_proc_entry(acpi_device_bid(device), acpi_battery_dir); |
564 | acpi_device_dir(device) = NULL; | ||
647 | } | 565 | } |
648 | 566 | ||
649 | /* -------------------------------------------------------------------------- | 567 | /* -------------------------------------------------------------------------- |
@@ -670,14 +588,11 @@ static int acpi_battery_add(struct acpi_device *device) | |||
670 | int result = 0; | 588 | int result = 0; |
671 | acpi_status status = 0; | 589 | acpi_status status = 0; |
672 | struct acpi_battery *battery = NULL; | 590 | struct acpi_battery *battery = NULL; |
673 | |||
674 | if (!device) | 591 | if (!device) |
675 | return -EINVAL; | 592 | return -EINVAL; |
676 | |||
677 | battery = kzalloc(sizeof(struct acpi_battery), GFP_KERNEL); | 593 | battery = kzalloc(sizeof(struct acpi_battery), GFP_KERNEL); |
678 | if (!battery) | 594 | if (!battery) |
679 | return -ENOMEM; | 595 | return -ENOMEM; |
680 | |||
681 | battery->device = device; | 596 | battery->device = device; |
682 | strcpy(acpi_device_name(device), ACPI_BATTERY_DEVICE_NAME); | 597 | strcpy(acpi_device_name(device), ACPI_BATTERY_DEVICE_NAME); |
683 | strcpy(acpi_device_class(device), ACPI_BATTERY_CLASS); | 598 | strcpy(acpi_device_class(device), ACPI_BATTERY_CLASS); |
@@ -687,7 +602,6 @@ static int acpi_battery_add(struct acpi_device *device) | |||
687 | result = acpi_battery_add_fs(device); | 602 | result = acpi_battery_add_fs(device); |
688 | if (result) | 603 | if (result) |
689 | goto end; | 604 | goto end; |
690 | |||
691 | status = acpi_install_notify_handler(device->handle, | 605 | status = acpi_install_notify_handler(device->handle, |
692 | ACPI_ALL_NOTIFY, | 606 | ACPI_ALL_NOTIFY, |
693 | acpi_battery_notify, battery); | 607 | acpi_battery_notify, battery); |
@@ -696,18 +610,14 @@ static int acpi_battery_add(struct acpi_device *device) | |||
696 | result = -ENODEV; | 610 | result = -ENODEV; |
697 | goto end; | 611 | goto end; |
698 | } | 612 | } |
699 | |||
700 | printk(KERN_INFO PREFIX "%s Slot [%s] (battery %s)\n", | 613 | printk(KERN_INFO PREFIX "%s Slot [%s] (battery %s)\n", |
701 | ACPI_BATTERY_DEVICE_NAME, acpi_device_bid(device), | 614 | ACPI_BATTERY_DEVICE_NAME, acpi_device_bid(device), |
702 | device->status.battery_present ? "present" : "absent"); | 615 | device->status.battery_present ? "present" : "absent"); |
703 | |||
704 | end: | 616 | end: |
705 | |||
706 | if (result) { | 617 | if (result) { |
707 | acpi_battery_remove_fs(device); | 618 | acpi_battery_remove_fs(device); |
708 | kfree(battery); | 619 | kfree(battery); |
709 | } | 620 | } |
710 | |||
711 | return result; | 621 | return result; |
712 | } | 622 | } |
713 | 623 | ||
@@ -718,17 +628,13 @@ static int acpi_battery_remove(struct acpi_device *device, int type) | |||
718 | 628 | ||
719 | if (!device || !acpi_driver_data(device)) | 629 | if (!device || !acpi_driver_data(device)) |
720 | return -EINVAL; | 630 | return -EINVAL; |
721 | |||
722 | battery = acpi_driver_data(device); | 631 | battery = acpi_driver_data(device); |
723 | |||
724 | status = acpi_remove_notify_handler(device->handle, | 632 | status = acpi_remove_notify_handler(device->handle, |
725 | ACPI_ALL_NOTIFY, | 633 | ACPI_ALL_NOTIFY, |
726 | acpi_battery_notify); | 634 | acpi_battery_notify); |
727 | |||
728 | acpi_battery_remove_fs(device); | 635 | acpi_battery_remove_fs(device); |
729 | mutex_destroy(&battery->lock); | 636 | mutex_destroy(&battery->lock); |
730 | kfree(battery); | 637 | kfree(battery); |
731 | |||
732 | return 0; | 638 | return 0; |
733 | } | 639 | } |
734 | 640 | ||
@@ -743,33 +649,35 @@ static int acpi_battery_resume(struct acpi_device *device) | |||
743 | return 0; | 649 | return 0; |
744 | } | 650 | } |
745 | 651 | ||
652 | static struct acpi_driver acpi_battery_driver = { | ||
653 | .name = "battery", | ||
654 | .class = ACPI_BATTERY_CLASS, | ||
655 | .ids = battery_device_ids, | ||
656 | .ops = { | ||
657 | .add = acpi_battery_add, | ||
658 | .resume = acpi_battery_resume, | ||
659 | .remove = acpi_battery_remove, | ||
660 | }, | ||
661 | }; | ||
662 | |||
746 | static int __init acpi_battery_init(void) | 663 | static int __init acpi_battery_init(void) |
747 | { | 664 | { |
748 | int result; | ||
749 | |||
750 | if (acpi_disabled) | 665 | if (acpi_disabled) |
751 | return -ENODEV; | 666 | return -ENODEV; |
752 | |||
753 | acpi_battery_dir = acpi_lock_battery_dir(); | 667 | acpi_battery_dir = acpi_lock_battery_dir(); |
754 | if (!acpi_battery_dir) | 668 | if (!acpi_battery_dir) |
755 | return -ENODEV; | 669 | return -ENODEV; |
756 | 670 | if (acpi_bus_register_driver(&acpi_battery_driver) < 0) { | |
757 | result = acpi_bus_register_driver(&acpi_battery_driver); | ||
758 | if (result < 0) { | ||
759 | acpi_unlock_battery_dir(acpi_battery_dir); | 671 | acpi_unlock_battery_dir(acpi_battery_dir); |
760 | return -ENODEV; | 672 | return -ENODEV; |
761 | } | 673 | } |
762 | |||
763 | return 0; | 674 | return 0; |
764 | } | 675 | } |
765 | 676 | ||
766 | static void __exit acpi_battery_exit(void) | 677 | static void __exit acpi_battery_exit(void) |
767 | { | 678 | { |
768 | acpi_bus_unregister_driver(&acpi_battery_driver); | 679 | acpi_bus_unregister_driver(&acpi_battery_driver); |
769 | |||
770 | acpi_unlock_battery_dir(acpi_battery_dir); | 680 | acpi_unlock_battery_dir(acpi_battery_dir); |
771 | |||
772 | return; | ||
773 | } | 681 | } |
774 | 682 | ||
775 | module_init(acpi_battery_init); | 683 | module_init(acpi_battery_init); |