File: /usr/src/linux/drivers/acpi/ospm/battery/bt.c
1 /*****************************************************************************
2 *
3 * Module Name: bt.c
4 * $Revision: 27 $
5 *
6 *****************************************************************************/
7
8 /*
9 * Copyright (C) 2000, 2001 Andrew Grover
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 */
25
26 #include <acpi.h>
27 #include "bt.h"
28
29
30 #define _COMPONENT ACPI_BATTERY
31 MODULE_NAME ("bt")
32
33
34 /****************************************************************************
35 * Internal Functions
36 ****************************************************************************/
37
38 /****************************************************************************
39 *
40 * FUNCTION: bt_print
41 *
42 * PARAMETERS:
43 *
44 * RETURN:
45 *
46 * DESCRIPTION: Prints out information on a specific battery.
47 *
48 ****************************************************************************/
49
50 void
51 bt_print (
52 BT_CONTEXT *battery)
53 {
54 #ifdef ACPI_DEBUG
55 acpi_buffer buffer;
56
57 PROC_NAME("bt_print");
58
59 if (!battery) {
60 return;
61 }
62
63 buffer.length = 256;
64 buffer.pointer = acpi_os_callocate(buffer.length);
65 if (!buffer.pointer) {
66 return;
67 }
68
69 /*
70 * Get the full pathname for this ACPI object.
71 */
72 acpi_get_name(battery->acpi_handle, ACPI_FULL_PATHNAME, &buffer);
73
74 /*
75 * Print out basic battery information.
76 */
77
78 ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INFO, "+------------------------------------------------------------\n"));
79 ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INFO, "| Battery[%02x]:[%p] %s\n", battery->device_handle, battery->acpi_handle, buffer.pointer));
80 ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INFO, "| uid[%s] is_present[%d] power_units[%s]\n", battery->uid, battery->is_present, battery->power_units));
81 ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INFO, "+------------------------------------------------------------\n"));
82
83 acpi_os_free(buffer.pointer);
84 #endif /*ACPI_DEBUG*/
85
86 return;
87 }
88
89
90 /****************************************************************************
91 *
92 * FUNCTION: bt_get_info
93 *
94 * PARAMETERS:
95 *
96 * RETURN:
97 *
98 * DESCRIPTION:
99 *
100 * NOTES: Allocates battery_info - which must be freed by the caller.
101 *
102 ****************************************************************************/
103
104 acpi_status
105 bt_get_info (
106 BT_CONTEXT *battery,
107 BT_BATTERY_INFO **battery_info)
108 {
109 acpi_status status = AE_OK;
110 acpi_buffer bif_buffer, package_format, package_data;
111 acpi_object *package = NULL;
112
113 FUNCTION_TRACE("bt_get_info");
114
115 if (!battery || !battery_info || *battery_info) {
116 return_ACPI_STATUS(AE_BAD_PARAMETER);
117 }
118
119 MEMSET(&bif_buffer, 0, sizeof(acpi_buffer));
120
121 /*
122 * Evalute _BIF:
123 * -------------
124 * And be sure to deallocate bif_buffer.pointer!
125 */
126 status = bm_evaluate_object(battery->acpi_handle, "_BIF", NULL,
127 &bif_buffer);
128 if (ACPI_FAILURE(status)) {
129 return_ACPI_STATUS(status);
130 }
131
132 /*
133 * Extract Package Data:
134 * ---------------------
135 * Type-cast this bif_buffer to a package and use helper
136 * functions to convert results into BT_BATTERY_INFO structure.
137 * The first attempt is just to get the size of the package
138 * data; the second gets the data (once we know the required
139 * bif_buffer size).
140 */
141 status = bm_cast_buffer(&bif_buffer, (void**)&package,
142 sizeof(acpi_object));
143 if (ACPI_FAILURE(status)) {
144 goto end;
145 }
146
147 package_format.length = sizeof("NNNNNNNNNSSSS");
148 package_format.pointer = "NNNNNNNNNSSSS";
149
150 MEMSET(&package_data, 0, sizeof(acpi_buffer));
151
152 status = bm_extract_package_data(package, &package_format,
153 &package_data);
154 if (status != AE_BUFFER_OVERFLOW) {
155 if (status == AE_OK) {
156 status = AE_ERROR;
157 }
158 goto end;
159 }
160
161 package_data.pointer = acpi_os_callocate(package_data.length);
162 if (!package_data.pointer) {
163 return_ACPI_STATUS(AE_NO_MEMORY);
164 }
165
166 status = bm_extract_package_data(package, &package_format,
167 &package_data);
168 if (ACPI_FAILURE(status)) {
169 acpi_os_free(package_data.pointer);
170 goto end;
171 }
172
173 *battery_info = package_data.pointer;
174
175 end:
176 acpi_os_free(bif_buffer.pointer);
177
178 return_ACPI_STATUS(status);
179 }
180
181
182 /****************************************************************************
183 *
184 * FUNCTION: bt_get_status
185 *
186 * PARAMETERS:
187 *
188 * RETURN:
189 *
190 * DESCRIPTION:
191 *
192 ****************************************************************************/
193
194 acpi_status
195 bt_get_status (
196 BT_CONTEXT *battery,
197 BT_BATTERY_STATUS **battery_status)
198 {
199 acpi_status status = AE_OK;
200 acpi_buffer bst_buffer, package_format, package_data;
201 acpi_object *package = NULL;
202
203 FUNCTION_TRACE("bt_get_status");
204
205 if (!battery || !battery_status || *battery_status) {
206 return_ACPI_STATUS(AE_BAD_PARAMETER);
207 }
208
209 MEMSET(&bst_buffer, 0, sizeof(acpi_buffer));
210
211 /*
212 * Evalute _BST:
213 * -------------
214 * And be sure to deallocate bst_buffer.pointer!
215 */
216 status = bm_evaluate_object(battery->acpi_handle, "_BST",
217 NULL, &bst_buffer);
218 if (ACPI_FAILURE(status)) {
219 return_ACPI_STATUS(status);
220 }
221
222 /*
223 * Extract Package Data:
224 * ---------------------
225 * Type-cast this bst_buffer to a package and use helper
226 * functions to convert results into BT_BATTERY_STATUS structure.
227 * The first attempt is just to get the size of the package data;
228 * the second gets the data (once we know the required bst_buffer
229 * size).
230 */
231 status = bm_cast_buffer(&bst_buffer, (void**)&package,
232 sizeof(acpi_object));
233 if (ACPI_FAILURE(status)) {
234 goto end;
235 }
236
237 package_format.length = sizeof("NNNN");
238 package_format.pointer = "NNNN";
239
240 MEMSET(&package_data, 0, sizeof(acpi_buffer));
241
242 status = bm_extract_package_data(package, &package_format,
243 &package_data);
244 if (status != AE_BUFFER_OVERFLOW) {
245 if (status == AE_OK) {
246 status = AE_ERROR;
247 }
248 goto end;
249 }
250
251 package_data.pointer = acpi_os_callocate(package_data.length);
252 if (!package_data.pointer) {
253 return_ACPI_STATUS(AE_NO_MEMORY);
254 }
255
256 status = bm_extract_package_data(package, &package_format,
257 &package_data);
258 if (ACPI_FAILURE(status)) {
259 acpi_os_free(package_data.pointer);
260 goto end;
261 }
262
263 *battery_status = package_data.pointer;
264
265 end:
266 acpi_os_free(bst_buffer.pointer);
267
268 return_ACPI_STATUS(status);
269 }
270
271
272 /****************************************************************************
273 *
274 * FUNCTION: bt_check_device
275 *
276 * PARAMETERS:
277 *
278 * RETURN:
279 *
280 * DESCRIPTION:
281 *
282 ****************************************************************************/
283
284 acpi_status
285 bt_check_device (
286 BT_CONTEXT *battery)
287 {
288 acpi_status status = AE_OK;
289 BM_DEVICE_STATUS battery_status = BM_STATUS_UNKNOWN;
290 u32 was_present = FALSE;
291 BT_BATTERY_INFO *battery_info = NULL;
292
293 FUNCTION_TRACE("bt_check_device");
294
295 if (!battery) {
296 return_ACPI_STATUS(AE_BAD_PARAMETER);
297 }
298
299 was_present = battery->is_present;
300
301 /*
302 * Battery Present?
303 * ----------------
304 * Get the device status and check if battery slot is occupied.
305 */
306 status = bm_get_device_status(battery->device_handle, &battery_status);
307 if (ACPI_FAILURE(status)) {
308 ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Unable to get battery status.\n"));
309 return_ACPI_STATUS(status);
310 }
311
312 if (battery_status & BM_STATUS_BATTERY_PRESENT) {
313 ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Battery socket occupied.\n"));
314 battery->is_present = TRUE;
315 }
316 else {
317 ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Battery socket not occupied.\n"));
318 battery->is_present = FALSE;
319 }
320
321 /*
322 * Battery Appeared?
323 * -----------------
324 */
325 if (!was_present && battery->is_present) {
326
327 ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Battery insertion detected.\n"));
328
329 /*
330 * Units of Power?
331 * ---------------
332 * Get the 'units of power', as we'll need this to report
333 * status information.
334 */
335 status = bt_get_info(battery, &battery_info);
336 if (ACPI_SUCCESS(status)) {
337 battery->power_units = (battery_info->power_unit)
338 ? BT_POWER_UNITS_AMPS : BT_POWER_UNITS_WATTS;
339 acpi_os_free(battery_info);
340 }
341 }
342
343 /*
344 * Battery Disappeared?
345 * --------------------
346 */
347 else if (was_present && !battery->is_present) {
348 ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Battery removal detected.\n"));
349 battery->power_units = BT_POWER_UNITS_DEFAULT;
350 }
351
352 return_ACPI_STATUS(status);
353 }
354
355
356 /*****************************************************************************
357 *
358 * FUNCTION: bt_add_device
359 *
360 * PARAMETERS:
361 *
362 * RETURN:
363 *
364 * DESCRIPTION:
365 *
366 ****************************************************************************/
367
368 acpi_status
369 bt_add_device (
370 BM_HANDLE device_handle,
371 void **context)
372 {
373 acpi_status status = AE_OK;
374 BM_DEVICE *device = NULL;
375 BT_CONTEXT *battery = NULL;
376
377 FUNCTION_TRACE("bt_add_device");
378
379 ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Adding battery device [%02x].\n", device_handle));
380
381 if (!context || *context) {
382 return_ACPI_STATUS(AE_BAD_PARAMETER);
383 }
384
385 /*
386 * Get information on this device.
387 */
388 status = bm_get_device_info(device_handle, &device);
389 if (ACPI_FAILURE(status)) {
390 return_ACPI_STATUS(status);
391 }
392
393 /*
394 * Allocate a new BT_CONTEXT structure.
395 */
396 battery = acpi_os_callocate(sizeof(BT_CONTEXT));
397 if (!battery) {
398 return_ACPI_STATUS(AE_NO_MEMORY);
399 }
400
401 battery->device_handle = device->handle;
402 battery->acpi_handle = device->acpi_handle;
403 strncpy(battery->uid, device->id.uid, sizeof(battery->uid));
404
405 battery->power_units = BT_POWER_UNITS_DEFAULT;
406 battery->is_present = FALSE;
407
408 /*
409 * See if battery is really present.
410 */
411 status = bt_check_device(battery);
412 if (ACPI_FAILURE(status)) {
413 goto end;
414 }
415
416 status = bt_osl_add_device(battery);
417 if (ACPI_FAILURE(status)) {
418 goto end;
419 }
420
421 *context = battery;
422
423 bt_print(battery);
424
425 end:
426 if (ACPI_FAILURE(status)) {
427 acpi_os_free(battery);
428 }
429
430 return_ACPI_STATUS(status);
431 }
432
433
434 /*****************************************************************************
435 *
436 * FUNCTION: bt_remove_device
437 *
438 * PARAMETERS:
439 *
440 * RETURN:
441 *
442 * DESCRIPTION:
443 *
444 ****************************************************************************/
445
446 acpi_status
447 bt_remove_device (
448 void **context)
449 {
450 acpi_status status = AE_OK;
451 BT_CONTEXT *battery = NULL;
452
453 FUNCTION_TRACE("bt_remove_device");
454
455 if (!context || !*context) {
456 return_ACPI_STATUS(AE_BAD_PARAMETER);
457 }
458
459 battery = (BT_CONTEXT*)*context;
460
461 ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Removing battery device [%02x].\n", battery->device_handle));
462
463 bt_osl_remove_device(battery);
464
465 acpi_os_free(battery);
466
467 *context = NULL;
468
469 return_ACPI_STATUS(status);
470 }
471
472
473 /*****************************************************************************
474 * External Functions
475 *****************************************************************************/
476
477 /*****************************************************************************
478 *
479 * FUNCTION: bt_initialize
480 *
481 * PARAMETERS: <none>
482 *
483 * RETURN:
484 *
485 * DESCRIPTION:
486 *
487 ****************************************************************************/
488
489 acpi_status
490 bt_initialize (void)
491 {
492 acpi_status status = AE_OK;
493 BM_DEVICE_ID criteria;
494 BM_DRIVER driver;
495
496 FUNCTION_TRACE("bt_initialize");
497
498 MEMSET(&criteria, 0, sizeof(BM_DEVICE_ID));
499 MEMSET(&driver, 0, sizeof(BM_DRIVER));
500
501 /*
502 * Register driver for driver method battery devices.
503 */
504 MEMCPY(criteria.hid, BT_HID_CM_BATTERY, sizeof(BT_HID_CM_BATTERY));
505
506 driver.notify = &bt_notify;
507 driver.request = &bt_request;
508
509 status = bm_register_driver(&criteria, &driver);
510
511 return_ACPI_STATUS(status);
512 }
513
514
515 /****************************************************************************
516 *
517 * FUNCTION: bt_terminate
518 *
519 * PARAMETERS: <none>
520 *
521 * RETURN:
522 *
523 * DESCRIPTION:
524 *
525 ****************************************************************************/
526
527 acpi_status
528 bt_terminate (void)
529 {
530 acpi_status status = AE_OK;
531 BM_DEVICE_ID criteria;
532 BM_DRIVER driver;
533
534 FUNCTION_TRACE("bt_terminate");
535
536 MEMSET(&criteria, 0, sizeof(BM_DEVICE_ID));
537 MEMSET(&driver, 0, sizeof(BM_DRIVER));
538
539 /*
540 * Unregister driver for driver method battery devices.
541 */
542 MEMCPY(criteria.hid, BT_HID_CM_BATTERY, sizeof(BT_HID_CM_BATTERY));
543
544 driver.notify = &bt_notify;
545 driver.request = &bt_request;
546
547 status = bm_unregister_driver(&criteria, &driver);
548
549 return_ACPI_STATUS(status);
550 }
551
552
553 /****************************************************************************
554 *
555 * FUNCTION: bt_notify
556 *
557 * PARAMETERS: <none>
558 *
559 * RETURN:
560 *
561 * DESCRIPTION:
562 *
563 ****************************************************************************/
564
565 acpi_status
566 bt_notify (
567 BM_NOTIFY notify_type,
568 BM_HANDLE device_handle,
569 void **context)
570 {
571 acpi_status status = AE_OK;
572
573 FUNCTION_TRACE("bt_notify");
574
575 if (!context) {
576 return_ACPI_STATUS(AE_BAD_PARAMETER);
577 }
578
579 switch (notify_type) {
580
581 case BM_NOTIFY_DEVICE_ADDED:
582 status = bt_add_device(device_handle, context);
583 break;
584
585 case BM_NOTIFY_DEVICE_REMOVED:
586 status = bt_remove_device(context);
587 break;
588
589 case BT_NOTIFY_STATUS_CHANGE:
590 ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Status change (_BST) event detected.\n"));
591 status = bt_osl_generate_event(notify_type,
592 ((BT_CONTEXT*)*context));
593 break;
594
595 case BT_NOTIFY_INFORMATION_CHANGE:
596 ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Information change (_BIF) event detected.\n"));
597 status = bt_check_device((BT_CONTEXT*)*context);
598 if (ACPI_SUCCESS(status)) {
599 status = bt_osl_generate_event(notify_type,
600 ((BT_CONTEXT*)*context));
601 }
602 break;
603
604 default:
605 status = AE_SUPPORT;
606 break;
607 }
608
609 return_ACPI_STATUS(status);
610 }
611
612
613 /****************************************************************************
614 *
615 * FUNCTION: bt_request
616 *
617 * PARAMETERS:
618 *
619 * RETURN:
620 *
621 * DESCRIPTION:
622 *
623 ****************************************************************************/
624
625 acpi_status
626 bt_request (
627 BM_REQUEST *request,
628 void *context)
629 {
630 acpi_status status = AE_OK;
631
632 FUNCTION_TRACE("bt_request");
633
634 /*
635 * Must have a valid request structure and context.
636 */
637 if (!request || !context)
638 return_ACPI_STATUS(AE_BAD_PARAMETER);
639
640 /*
641 * Handle request:
642 * ---------------
643 */
644 switch (request->command) {
645
646 default:
647 status = AE_SUPPORT;
648 break;
649 }
650
651 request->status = status;
652
653 return_ACPI_STATUS(status);
654 }
655