:pserver:cvsanon@mok.lvcm.com:/CVS/ReactOS reactos
[reactos.git] / drivers / bus / acpi / ospm / busmgr / bm.c
1 /******************************************************************************
2  *
3  * Module Name: bm.c
4  *   $Revision$
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
27 #include <acpi.h>
28 #include "bm.h"
29
30
31 #define _COMPONENT              ACPI_BUS_MANAGER
32         MODULE_NAME             ("bm")
33
34
35 /****************************************************************************
36  *                                  Globals
37  ****************************************************************************/
38
39 extern FADT_DESCRIPTOR_REV2     acpi_fadt;
40 /* TODO: Make dynamically sizeable. */
41 static BM_NODE_LIST             node_list;
42
43
44 /****************************************************************************
45  *                            Internal Functions
46  ****************************************************************************/
47
48 /****************************************************************************
49  *
50  * FUNCTION:    bm_print
51  *
52  * PARAMETERS:  <TBD>
53  *
54  * RETURN:      <TBD>
55  *
56  * DESCRIPTION: <TBD>
57  *
58  ****************************************************************************/
59
60 void
61 bm_print (
62         BM_NODE                 *node,
63         u32                     flags)
64 {
65         ACPI_BUFFER             buffer;
66         BM_DEVICE               *device = NULL;
67         char                    *type_string = NULL;
68
69         if (!node) {
70                 return;
71         }
72
73         device = &(node->device);
74
75         if (flags & BM_PRINT_PRESENT) {
76                 if (!BM_DEVICE_PRESENT(device)) {
77                         return;
78                 }
79         }
80
81         buffer.length = 256;
82         buffer.pointer = acpi_os_callocate(buffer.length);
83         if (!buffer.pointer) {
84                 return;
85         }
86
87         acpi_get_name(device->acpi_handle, ACPI_FULL_PATHNAME, &buffer);
88
89         switch(device->id.type) {
90         case BM_TYPE_SYSTEM:
91                 type_string = "System";
92                 break;
93         case BM_TYPE_SCOPE:
94                 type_string = "Scope";
95                 break;
96         case BM_TYPE_PROCESSOR:
97                 type_string = "Processor";
98                 break;
99         case BM_TYPE_THERMAL_ZONE:
100                 type_string = "ThermalZone";
101                 break;
102         case BM_TYPE_POWER_RESOURCE:
103                 type_string = "PowerResource";
104                 break;
105         case BM_TYPE_FIXED_BUTTON:
106                 type_string = "Button";
107                 break;
108         case BM_TYPE_DEVICE:
109                 type_string = "Device";
110                 break;
111         default:
112                 type_string = "Unknown";
113                 break;
114         }
115
116         if (!(flags & BM_PRINT_GROUP)) {
117                 DEBUG_PRINT(ACPI_INFO, ("+------------------------------------------------------------\n"));
118         }
119
120                 DEBUG_PRINT(ACPI_INFO, ("%s[0x%02x] hid[%s] %s\n", type_string, device->handle, device->id.hid, buffer.pointer));
121                 DEBUG_PRINT(ACPI_INFO, ("  acpi_handle[0x%08x] flags[0x%02x] status[0x%02x]\n", device->acpi_handle, device->flags, device->status));
122
123         if (flags & BM_PRINT_IDENTIFICATION) {
124                 DEBUG_PRINT(ACPI_INFO, ("  identification: uid[%s] adr[0x%08x]\n", device->id.uid, device->id.adr));
125         }
126
127         if (flags & BM_PRINT_LINKAGE) {
128                 DEBUG_PRINT(ACPI_INFO, ("  linkage: this[%p] parent[%p] next[%p]\n", node, node->parent, node->next));
129                 DEBUG_PRINT(ACPI_INFO, ("    scope.head[%p] scope.tail[%p]\n", node->scope.head, node->scope.tail));
130         }
131
132         if (flags & BM_PRINT_POWER) {
133                 DEBUG_PRINT(ACPI_INFO, ("  power: state[D%d] flags[0x%08X]\n", device->power.state, device->power.flags));
134                 DEBUG_PRINT(ACPI_INFO, ("    S0[0x%02x] S1[0x%02x] S2[0x%02x]\n", device->power.dx_supported[0], device->power.dx_supported[1], device->power.dx_supported[2]));
135                 DEBUG_PRINT(ACPI_INFO, ("    S3[0x%02x] S4[0x%02x] S5[0x%02x]\n", device->power.dx_supported[3], device->power.dx_supported[4], device->power.dx_supported[5]));
136         }
137
138         if (!(flags & BM_PRINT_GROUP)) {
139                 DEBUG_PRINT(ACPI_INFO, ("+------------------------------------------------------------\n"));
140         }
141
142         acpi_os_free(buffer.pointer);
143
144         return;
145 }
146
147
148 /****************************************************************************
149  *
150  * FUNCTION:    bm_print_hierarchy
151  *
152  * PARAMETERS:  <TBD>
153  *
154  * RETURN:      <TBD>
155  *
156  * DESCRIPTION: <TBD>
157  *
158  ****************************************************************************/
159
160 void
161 bm_print_hierarchy (void)
162 {
163         u32                     i = 0;
164
165         FUNCTION_TRACE("bm_print_hierarchy");
166
167         DEBUG_PRINT(ACPI_INFO, ("+------------------------------------------------------------\n"));
168
169         for (i = 0; i < node_list.count; i++) {
170                 bm_print(node_list.nodes[i], BM_PRINT_GROUP | BM_PRINT_PRESENT);
171         }
172
173         DEBUG_PRINT(ACPI_INFO, ("+------------------------------------------------------------\n"));
174
175         return_VOID;
176 }
177
178
179 /****************************************************************************
180  *
181  * FUNCTION:    bm_get_status
182  *
183  * PARAMETERS:  <TBD>
184  *
185  * RETURN:      <TBD>
186  *
187  * DESCRIPTION: <TBD>
188  *
189  ****************************************************************************/
190
191 ACPI_STATUS
192 bm_get_status (
193         BM_DEVICE               *device)
194 {
195         ACPI_STATUS             status = AE_OK;
196
197         if (!device) {
198                 return AE_BAD_PARAMETER;
199         }
200
201         device->status = BM_STATUS_UNKNOWN;
202
203         /*
204          * Dynamic Status?
205          * ---------------
206          * If _STA isn't present we just return the default status.
207          */
208         if (!(device->flags & BM_FLAGS_DYNAMIC_STATUS)) {
209                 device->status = BM_STATUS_DEFAULT;
210                 return AE_OK;
211         }
212
213         /*
214          * Evaluate _STA:
215          * --------------
216          */
217         status = bm_evaluate_simple_integer(device->acpi_handle, "_STA", 
218                 &(device->status));
219
220         return status;
221 }
222
223
224 /****************************************************************************
225  *
226  * FUNCTION:    bm_get_identification
227  *
228  * PARAMETERS:  <TBD>
229  *
230  * RETURN:      <TBD>
231  *
232  * DESCRIPTION: <TBD>
233  *
234  ****************************************************************************/
235
236 ACPI_STATUS
237 bm_get_identification (
238         BM_DEVICE               *device)
239 {
240         ACPI_STATUS             status = AE_OK;
241         ACPI_DEVICE_INFO        info;
242
243         if (!device) {
244                 return AE_BAD_PARAMETER;
245         }
246
247         if (!(device->flags & BM_FLAGS_IDENTIFIABLE)) {
248                 return AE_OK;
249         }
250
251         MEMSET(&(device->id.uid), 0, sizeof(device->id.uid));
252         MEMSET(&(device->id.hid), 0, sizeof(device->id.hid));
253         device->id.adr = BM_ADDRESS_UNKNOWN;
254
255         /*
256          * Get Object Info:
257          * ----------------
258          * Evalute _UID, _HID, _ADR, and _STA...
259          */
260         status = acpi_get_object_info(device->acpi_handle, &info);
261         if (ACPI_FAILURE(status)) {
262                 return status;
263         }
264
265         if (info.valid & ACPI_VALID_UID) {
266                 MEMCPY((void*)device->id.uid, (void*)info.unique_id, 
267                         sizeof(BM_DEVICE_UID));
268         }
269
270         if (info.valid & ACPI_VALID_HID) {
271                 MEMCPY((void*)device->id.hid, (void*)info.hardware_id, 
272                         sizeof(BM_DEVICE_HID));
273         }
274
275         if (info.valid & ACPI_VALID_ADR) {
276                 device->id.adr = info.address;
277         }
278
279         return status;
280 }
281
282
283 /****************************************************************************
284  *
285  * FUNCTION:    bm_get_flags
286  *
287  * PARAMETERS:  <TBD>
288  *
289  * RETURN:      <TBD>
290  *
291  * DESCRIPTION: <TBD>
292  *
293  ****************************************************************************/
294
295 ACPI_STATUS
296 bm_get_flags (
297         BM_DEVICE               *device)
298 {
299         ACPI_HANDLE             acpi_handle = NULL;
300
301         if (!device) {
302                 return AE_BAD_PARAMETER;
303         }
304
305         device->flags = BM_FLAGS_UNKNOWN;
306
307         switch (device->id.type) {
308
309         case BM_TYPE_DEVICE:
310
311                 /*
312                  * Presence of _DCK indicates a docking station.
313                  */
314                 if (ACPI_SUCCESS(acpi_get_handle(device->acpi_handle, 
315                         "_DCK", &acpi_handle))) {
316                         device->flags |= BM_FLAGS_DOCKING_STATION;
317                 }
318
319                 /*
320                  * Presence of _EJD and/or _EJx indicates 'ejectable'.
321                  * TODO: _EJx...
322                  */
323                 if (ACPI_SUCCESS(acpi_get_handle(device->acpi_handle, 
324                         "_EJD", &acpi_handle))) {
325                         device->flags |= BM_FLAGS_EJECTABLE;
326                 }
327
328                 /*
329                  * Presence of _PR0 or _PS0 indicates 'power manageable'.
330                  */
331                 if (ACPI_SUCCESS(acpi_get_handle(device->acpi_handle, 
332                         "_PR0", &acpi_handle)) ||
333                         ACPI_SUCCESS(acpi_get_handle(device->acpi_handle, 
334                         "_PS0", &acpi_handle))) {
335                         device->flags |= BM_FLAGS_POWER_CONTROL;
336                 }
337
338                 /*
339                  * Presence of _CRS indicates 'configurable'.
340                  */
341                 if (ACPI_SUCCESS(acpi_get_handle(device->acpi_handle, 
342                         "_CRS", &acpi_handle))) {
343                         device->flags |= BM_FLAGS_CONFIGURABLE;
344                 }
345
346                 /* Fall through to next case statement. */
347
348         case BM_TYPE_PROCESSOR:
349         case BM_TYPE_THERMAL_ZONE:
350         case BM_TYPE_POWER_RESOURCE:
351                 /*
352                  * Presence of _HID or _ADR indicates 'identifiable'.
353                  */
354                 if (ACPI_SUCCESS(acpi_get_handle(device->acpi_handle, 
355                         "_HID", &acpi_handle)) ||
356                    ACPI_SUCCESS(acpi_get_handle(device->acpi_handle, 
357                    "_ADR", &acpi_handle))) {
358                         device->flags |= BM_FLAGS_IDENTIFIABLE;
359                 }
360
361                 /*
362                  * Presence of _STA indicates 'dynamic status'.
363                  */
364                 if (ACPI_SUCCESS(acpi_get_handle(device->acpi_handle, 
365                         "_STA", &acpi_handle))) {
366                         device->flags |= BM_FLAGS_DYNAMIC_STATUS;
367                 }
368
369                 break;
370         }
371
372         return AE_OK;
373 }
374
375
376 /****************************************************************************
377  *
378  * FUNCTION:    bm_add_namespace_device
379  *
380  * PARAMETERS:  <TBD>
381  *
382  * RETURN:      <TBD>
383  *
384  * DESCRIPTION: <TBD>
385  *
386  ****************************************************************************/
387
388 ACPI_STATUS
389 bm_add_namespace_device (
390         ACPI_HANDLE             acpi_handle,
391         ACPI_OBJECT_TYPE        acpi_type,
392         BM_NODE                 *parent,
393         BM_NODE                 **child)
394 {
395         ACPI_STATUS             status = AE_OK;
396         BM_NODE                 *node = NULL;
397         BM_DEVICE               *device = NULL;
398
399         FUNCTION_TRACE("bm_add_namespace_device");
400
401         if (!parent || !child) {
402                 return_ACPI_STATUS(AE_BAD_PARAMETER);
403         }
404
405         if (node_list.count > BM_HANDLES_MAX) {
406                 return_ACPI_STATUS(AE_NO_MEMORY);
407         }
408
409         (*child) = NULL;
410
411         /*
412          * Create Node:
413          * ------------
414          */
415         node = acpi_os_callocate(sizeof(BM_NODE));
416         if (!node) {
417                 return_ACPI_STATUS(AE_NO_MEMORY);
418         }
419
420         node->parent = parent;
421         node->next = NULL;
422
423         device = &(node->device);
424
425         device->handle = node_list.count;
426         device->acpi_handle = acpi_handle;
427
428         /*
429          * Device Type:
430          * ------------
431          */ 
432         switch (acpi_type) {
433         case INTERNAL_TYPE_SCOPE:
434                 device->id.type = BM_TYPE_SCOPE;
435                 break;
436         case ACPI_TYPE_PROCESSOR:
437                 device->id.type = BM_TYPE_PROCESSOR;
438                 break;
439         case ACPI_TYPE_THERMAL:
440                 device->id.type = BM_TYPE_THERMAL_ZONE;
441                 break;
442         case ACPI_TYPE_POWER:
443                 device->id.type = BM_TYPE_POWER_RESOURCE;
444                 break;
445         case ACPI_TYPE_DEVICE:
446                 device->id.type = BM_TYPE_DEVICE;
447                 break;
448         }
449
450         /*
451          * Get Other Device Info:
452          * ----------------------
453          * But only if this device's parent is present (which implies
454          * this device MAY be present).
455          */
456         if (BM_NODE_PRESENT(node->parent)) {
457                 /*
458                  * Device Flags
459                  */
460                 status = bm_get_flags(device);
461                 if (ACPI_FAILURE(status)) {
462                         goto end;
463                 }
464
465                 /*
466                  * Device Identification
467                  */
468                 status = bm_get_identification(device);
469                 if (ACPI_FAILURE(status)) {
470                         goto end;
471                 }
472
473                 /*
474                  * Device Status
475                  */
476                 status = bm_get_status(device);
477                 if (ACPI_FAILURE(status)) {
478                         goto end;
479                 }
480
481                 /*
482                  * Power Management:
483                  * -----------------
484                  * If this node doesn't provide direct power control  
485                  * then we inherit PM capabilities from its parent.
486                  *
487                  * TODO: Inherit!
488                  */
489                 if (device->flags & BM_FLAGS_POWER_CONTROL) {
490                         status = bm_get_pm_capabilities(node);
491                         if (ACPI_FAILURE(status)) {
492                                 goto end;
493                         }
494                 }
495         }
496
497 end:
498         if (ACPI_FAILURE(status)) {
499                 acpi_os_free(node);
500         }
501         else {
502                 /*
503                  * Add to the node_list.
504                  */
505                 node_list.nodes[node_list.count++] = node;
506
507                 /*
508                  * Formulate Hierarchy:
509                  * --------------------
510                  * Arrange within the namespace by assigning the parent and
511                  * adding to the parent device's list of children (scope).
512                  */
513                 if (!parent->scope.head) {
514                         parent->scope.head = node;
515                 }
516                 else {
517                         if (!parent->scope.tail) {
518                                 (parent->scope.head)->next = node;
519                         }
520                         else {
521                                 (parent->scope.tail)->next = node;
522                         }
523                 }
524                 parent->scope.tail = node;
525
526                 (*child) = node;
527         }
528
529         return_ACPI_STATUS(status);
530 }
531
532
533 /****************************************************************************
534  *
535  * FUNCTION:    bm_enumerate_namespace
536  *
537  * PARAMETERS:  <none>
538  *
539  * RETURN:      <TBD>
540  *
541  * DESCRIPTION: <TBD>
542  *
543  ****************************************************************************/
544
545 ACPI_STATUS
546 bm_enumerate_namespace (void)
547 {
548         ACPI_STATUS             status = AE_OK;
549         ACPI_HANDLE             parent_handle = ACPI_ROOT_OBJECT;
550         ACPI_HANDLE             child_handle = NULL;
551         BM_NODE                 *parent = NULL;
552         BM_NODE                 *child = NULL;
553         ACPI_OBJECT_TYPE        acpi_type = 0;
554         u32                     level = 1;
555
556         FUNCTION_TRACE("bm_enumerate_namespace");
557
558         parent = node_list.nodes[0];
559
560         /*
561          * Enumerate ACPI Namespace:
562          * -------------------------
563          * Parse through the ACPI namespace, identify all 'devices',
564          * and create a new entry for each in our collection.
565          */
566         while (level > 0) {
567
568                 /*
569                  * Get the next object at this level.
570                  */
571                 status = acpi_get_next_object(ACPI_TYPE_ANY, parent_handle, child_handle, &child_handle);
572                 if (ACPI_SUCCESS(status)) {
573
574                         /*
575                          * TODO: This is a hack to get around the problem 
576                          *       identifying scope objects.  Scopes 
577                          *       somehow need to be uniquely identified.
578                          */
579                         status = acpi_get_type(child_handle, &acpi_type);
580                         if (ACPI_SUCCESS(status) && (acpi_type == ACPI_TYPE_ANY)) {
581                                 status = acpi_get_next_object(ACPI_TYPE_ANY, child_handle, 0, NULL);
582                                 if (ACPI_SUCCESS(status)) {
583                                         acpi_type = INTERNAL_TYPE_SCOPE;
584                                 }
585                         }
586
587                         /*
588                          * Device?
589                          * -------
590                          * If this object is a 'device', insert into the
591                          * ACPI Bus Manager's local hierarchy and search
592                          * the object's scope for any child devices (a
593                          * depth-first search).
594                          */
595                         switch (acpi_type) {
596                         case INTERNAL_TYPE_SCOPE:
597                         case ACPI_TYPE_DEVICE:
598                         case ACPI_TYPE_PROCESSOR:
599                         case ACPI_TYPE_THERMAL:
600                         case ACPI_TYPE_POWER:
601                                 status = bm_add_namespace_device(child_handle, acpi_type, parent, &child);
602                                 if (ACPI_SUCCESS(status)) {
603                                         status = acpi_get_next_object(ACPI_TYPE_ANY, child_handle, 0, NULL);
604                                         if (ACPI_SUCCESS(status)) {
605                                                 level++;
606                                                 parent_handle = child_handle;
607                                                 child_handle = 0;
608                                                 parent = child;
609                                         }
610                                 }
611                                 break;
612                         }
613                 }
614
615                 /*
616                  * Scope Exhausted:
617                  * ----------------
618                  * No more children in this object's scope, Go back up
619                  * in the namespace tree to the object's parent.
620                  */
621                 else {
622                         level--;
623                         child_handle = parent_handle;
624                         acpi_get_parent(parent_handle, 
625                                 &parent_handle);
626
627                         if (parent) {
628                                 parent = parent->parent;
629                         }
630                         else {
631                                 return_ACPI_STATUS(AE_NULL_ENTRY);
632                         }
633                 }
634         }
635
636         return_ACPI_STATUS(AE_OK);
637 }
638
639
640 /****************************************************************************
641  *
642  * FUNCTION:    bm_add_fixed_feature_device
643  *
644  * PARAMETERS:  <TBD>
645  *
646  * RETURN:      <TBD>
647  *
648  * DESCRIPTION: <TBD>
649  *
650  ****************************************************************************/
651
652 ACPI_STATUS
653 bm_add_fixed_feature_device (
654         BM_NODE                 *parent,
655         BM_DEVICE_TYPE          device_type,
656         char                    *device_hid)
657 {
658         ACPI_STATUS             status = AE_OK;
659         BM_NODE                 *node = NULL;
660
661         FUNCTION_TRACE("bm_add_fixed_feature_device");
662
663         if (!parent) {
664                 return_ACPI_STATUS(AE_BAD_PARAMETER);
665         }
666
667         if (node_list.count > BM_HANDLES_MAX) {
668                 return_ACPI_STATUS(AE_NO_MEMORY);
669         }
670
671         /*
672          * Allocate the new device and add to the device array.
673          */
674         node = acpi_os_callocate(sizeof(BM_NODE));
675         if (!node) {
676                 return_ACPI_STATUS(AE_NO_MEMORY);
677         }
678
679         /*
680          * Get device info.
681          */
682         node->device.handle = node_list.count;
683         node->device.acpi_handle = ACPI_ROOT_OBJECT;
684         node->device.id.type = BM_TYPE_FIXED_BUTTON;
685         if (device_hid) {
686                 MEMCPY((void*)node->device.id.hid, device_hid, 
687                         sizeof(node->device.id.hid));
688         }
689         node->device.flags = BM_FLAGS_FIXED_FEATURE;
690         node->device.status = BM_STATUS_DEFAULT;
691         /* TODO: Device PM capabilities */
692
693         /*
694          * Add to the node_list.
695          */
696         node_list.nodes[node_list.count++] = node;
697
698         /*
699          * Formulate Hierarchy:
700          * --------------------
701          * Arrange within the namespace by assigning the parent and
702          * adding to the parent device's list of children (scope).
703          */
704         node->parent = parent;
705         node->next = NULL;
706
707         if (parent) {
708                 if (!parent->scope.head) {
709                         parent->scope.head = node;
710                 }
711                 else {
712                         if (!parent->scope.tail) {
713                                 (parent->scope.head)->next = node;
714                         }
715                         else {
716                                 (parent->scope.tail)->next = node;
717                         }
718                 }
719                 parent->scope.tail = node;
720         }
721
722         return_ACPI_STATUS(status);
723 }
724
725
726 /****************************************************************************
727  *
728  * FUNCTION:    bm_enumerate_fixed_features
729  *
730  * PARAMETERS:  <none>
731  *
732  * RETURN:      <TBD>
733  *
734  * DESCRIPTION: <TBD>
735  *
736  ****************************************************************************/
737
738 ACPI_STATUS
739 bm_enumerate_fixed_features (void)
740 {
741         FUNCTION_TRACE("bm_enumerate_fixed_features");
742
743         /*
744          * Root Object:
745          * ------------
746          * Fabricate the root object, which happens to always get a
747          * device_handle of zero.
748          */
749         node_list.nodes[0] = acpi_os_callocate(sizeof(BM_NODE));
750         if (NULL == (node_list.nodes[0])) {
751                 return_ACPI_STATUS(AE_NO_MEMORY);
752         }
753
754         node_list.nodes[0]->device.handle = BM_HANDLE_ROOT;
755         node_list.nodes[0]->device.acpi_handle = ACPI_ROOT_OBJECT;
756         node_list.nodes[0]->device.flags = BM_FLAGS_UNKNOWN;
757         node_list.nodes[0]->device.status = BM_STATUS_DEFAULT;
758         node_list.nodes[0]->device.id.type = BM_TYPE_SYSTEM;
759         /* TODO: Get system PM capabilities (Sx states?) */
760
761         node_list.count++;
762
763         /*
764          * Fixed Features:
765          * ---------------
766          * Enumerate fixed-feature devices (e.g. power and sleep buttons).
767          */
768         if (acpi_fadt.pwr_button == 0) {
769                 bm_add_fixed_feature_device(node_list.nodes[0],
770                         BM_TYPE_FIXED_BUTTON, BM_HID_POWER_BUTTON);
771         }
772
773         if (acpi_fadt.sleep_button == 0) {
774                 bm_add_fixed_feature_device(node_list.nodes[0],
775                         BM_TYPE_FIXED_BUTTON, BM_HID_SLEEP_BUTTON);
776         }
777
778         return_ACPI_STATUS(AE_OK);
779 }
780
781
782 /****************************************************************************
783  *
784  * FUNCTION:    bm_get_handle
785  *
786  * PARAMETERS:  <TBD>
787  *
788  * RETURN:      <TBD>
789  *
790  * DESCRIPTION: <TBD>
791  *
792  ****************************************************************************/
793
794 ACPI_STATUS
795 bm_get_handle (
796         ACPI_HANDLE             acpi_handle,
797         BM_HANDLE               *device_handle)
798 {
799         ACPI_STATUS             status = AE_OK;
800         u32                     i = 0;
801
802         FUNCTION_TRACE("bm_get_handle");
803
804         if (!device_handle) {
805                 return_ACPI_STATUS(AE_BAD_PARAMETER);
806         }
807
808         *device_handle = BM_HANDLE_UNKNOWN;
809
810         /*
811          * Search all devices for a match on the ACPI handle.
812          */
813         for (i=0; i<node_list.count; i++) {
814
815                 if (!node_list.nodes[i]) {
816                         DEBUG_PRINT(ACPI_ERROR, ("Invalid (NULL) node entry [0x%02x] detected.\n", device_handle));
817                         status = AE_NULL_ENTRY;
818                         break;
819                 }
820
821                 if (node_list.nodes[i]->device.acpi_handle == acpi_handle) {
822                         *device_handle = node_list.nodes[i]->device.handle;
823                         break;
824                 }
825         }
826
827         return_ACPI_STATUS(status);
828 }
829
830
831 /****************************************************************************
832  *
833  * FUNCTION:    bm_get_node
834  *
835  * PARAMETERS:  <TBD>
836  *
837  * RETURN:      <TBD>
838  *
839  * DESCRIPTION: <TBD>
840  *
841  ****************************************************************************/
842
843 ACPI_STATUS
844 bm_get_node (
845         BM_HANDLE               device_handle,
846         ACPI_HANDLE             acpi_handle,
847         BM_NODE                 **node)
848 {
849         ACPI_STATUS             status = AE_OK;
850
851         FUNCTION_TRACE("bm_get_node");
852
853         if (!node) {
854                 return_ACPI_STATUS(AE_BAD_PARAMETER);
855         }
856
857         /*
858          * If no device handle, resolve acpi handle to device handle.
859          */
860         if (!device_handle && acpi_handle) {
861                 status = bm_get_handle(acpi_handle, &device_handle);
862                 if (ACPI_FAILURE(status))
863                         return_ACPI_STATUS(status);
864         }
865
866         /*
867          * Valid device handle?
868          */
869         if (device_handle > BM_HANDLES_MAX) {
870                 DEBUG_PRINT(ACPI_ERROR, ("Invalid node handle [0x%02x] detected.\n", device_handle));
871                 return_ACPI_STATUS(AE_ERROR);
872         }
873
874         *node = node_list.nodes[device_handle];
875
876         /*
877          * Valid node?
878          */
879         if (!(*node)) {
880                 DEBUG_PRINT(ACPI_ERROR, ("Invalid (NULL) node entry [0x%02x] detected.\n", device_handle));
881                 return_ACPI_STATUS(AE_NULL_ENTRY);
882         }
883
884         return_ACPI_STATUS(AE_OK);
885 }
886
887
888 /****************************************************************************
889  *                            External Functions
890  ****************************************************************************/
891
892 /****************************************************************************
893  *
894  * FUNCTION:    bm_initialize
895  *
896  * PARAMETERS:  <none>
897  *
898  * RETURN:      Exception code.
899  *
900  * DESCRIPTION: <TBD>
901  *
902  ****************************************************************************/
903
904 ACPI_STATUS
905 bm_initialize (void)
906 {
907         ACPI_STATUS             status = AE_OK;
908         u32                     start = 0;
909         u32                     stop = 0;
910         u32                     elapsed = 0;
911
912         FUNCTION_TRACE("bm_initialize");
913
914         MEMSET(&node_list, 0, sizeof(BM_HANDLE_LIST));
915
916         acpi_get_timer(&start);
917
918         DEBUG_PRINT(ACPI_INFO, ("Building device hierarchy.\n"));
919
920         /*
921          * Enumerate ACPI fixed-feature devices.
922          */
923         status = bm_enumerate_fixed_features();
924         if (ACPI_FAILURE(status)) {
925                 return_ACPI_STATUS(status);
926         }
927
928         /*
929          * Enumerate the ACPI namespace.
930          */
931         status = bm_enumerate_namespace();
932         if (ACPI_FAILURE(status)) {
933                 return_ACPI_STATUS(status);
934         }
935
936         acpi_get_timer(&stop);
937         acpi_get_timer_duration(start, stop, &elapsed);
938
939         DEBUG_PRINT(ACPI_INFO, ("Device heirarchy build took [%d] microseconds.\n", elapsed));
940
941         /*
942          * Display hierarchy.
943          */
944 #ifdef ACPI_DEBUG
945         bm_print_hierarchy();
946 #endif /*ACPI_DEBUG*/
947
948         /*
949          * Register for all standard and device-specific notifications.
950          */
951         DEBUG_PRINT(ACPI_INFO, ("Registering for all device notifications.\n"));
952
953         status = acpi_install_notify_handler(ACPI_ROOT_OBJECT, 
954                 ACPI_SYSTEM_NOTIFY, &bm_notify, NULL);
955         if (ACPI_FAILURE(status)) {
956                 DEBUG_PRINT(ACPI_ERROR, ("Unable to register for standard notifications.\n"));
957                 return_ACPI_STATUS(status);
958         }
959
960         status = acpi_install_notify_handler(ACPI_ROOT_OBJECT, 
961                 ACPI_DEVICE_NOTIFY, &bm_notify, NULL);
962         if (ACPI_FAILURE(status)) {
963                 DEBUG_PRINT(ACPI_ERROR, ("Unable to register for device-specific notifications.\n"));
964                 return_ACPI_STATUS(status);
965         }
966
967         /*
968          * Initialize /proc interface.
969          */
970         //DEBUG_PRINT(ACPI_INFO, ("Initializing /proc interface.\n"));
971         //status = bm_proc_initialize();
972
973         DEBUG_PRINT(ACPI_INFO, ("ACPI Bus Manager enabled.\n"));
974
975         /*
976          * Initialize built-in power resource driver.
977          */
978         bm_pr_initialize();
979
980         return_ACPI_STATUS(status);
981 }
982
983
984 /****************************************************************************
985  *
986  * FUNCTION:    bm_terminate
987  *
988  * PARAMETERS:  <none>
989  *
990  * RETURN:      Exception code.
991  *
992  * DESCRIPTION: <TBD>
993  *
994  ****************************************************************************/
995
996 ACPI_STATUS
997 bm_terminate (void)
998 {
999         ACPI_STATUS             status = AE_OK;
1000         u32                     i = 0;
1001
1002         FUNCTION_TRACE("bm_terminate");
1003
1004         /*
1005          * Terminate built-in power resource driver.
1006          */
1007         bm_pr_terminate();
1008
1009         /*
1010          * Remove the /proc interface.
1011          */
1012         //DEBUG_PRINT(ACPI_INFO, ("Removing /proc interface.\n"));
1013         //status = bm_proc_terminate();
1014
1015
1016         /*
1017          * Unregister for all notifications.
1018          */
1019
1020         DEBUG_PRINT(ACPI_INFO, ("Unregistering for device notifications.\n"));
1021
1022         status = acpi_remove_notify_handler(ACPI_ROOT_OBJECT, 
1023                 ACPI_SYSTEM_NOTIFY, &bm_notify);
1024         if (ACPI_FAILURE(status)) {
1025                 DEBUG_PRINT(ACPI_ERROR, ("Unable to un-register for standard notifications.\n"));
1026         }
1027
1028         status = acpi_remove_notify_handler(ACPI_ROOT_OBJECT, 
1029                 ACPI_DEVICE_NOTIFY, &bm_notify);
1030         if (ACPI_FAILURE(status)) {
1031                 DEBUG_PRINT(ACPI_ERROR, ("Unable to un-register for device-specific notifications.\n"));
1032         }
1033
1034         /*
1035          * Parse through the device array, freeing all entries.
1036          */
1037         DEBUG_PRINT(ACPI_INFO, ("Removing device hierarchy.\n"));
1038         for (i = 0; i < node_list.count; i++) {
1039                 if (node_list.nodes[i]) {
1040                         acpi_os_free(node_list.nodes[i]);
1041                 }
1042         }
1043
1044         DEBUG_PRINT(ACPI_INFO, ("ACPI Bus Manager disabled.\n"));
1045
1046         return_ACPI_STATUS(AE_OK);
1047 }