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