:pserver:cvsanon@mok.lvcm.com:/CVS/ReactOS reactos
[reactos.git] / drivers / bus / acpi / events / evrgnini.c
1 /******************************************************************************
2  *
3  * Module Name: evrgnini- ACPI Address_space (Op_region) init
4  *              $Revision$
5  *
6  *****************************************************************************/
7
8 /*
9  *  Copyright (C) 2000, 2001 R. Byron Moore
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 "acevents.h"
29 #include "acnamesp.h"
30 #include "acinterp.h"
31 #include "amlcode.h"
32
33 #define _COMPONENT          ACPI_EVENTS
34          MODULE_NAME         ("evrgnini")
35
36
37 /*****************************************************************************
38  *
39  * FUNCTION:    Acpi_ev_system_memory_region_setup
40  *
41  * PARAMETERS:  Region_obj          - region we are interested in
42  *              Function            - start or stop
43  *              Handler_context     - Address space handler context
44  *              Region_context      - Region specific context
45  *
46  * RETURN:      Status
47  *
48  * DESCRIPTION: Do any prep work for region handling, a nop for now
49  *
50  ****************************************************************************/
51
52 ACPI_STATUS
53 acpi_ev_system_memory_region_setup (
54         ACPI_HANDLE             handle,
55         u32                     function,
56         void                    *handler_context,
57         void                    **region_context)
58 {
59
60         if (function == ACPI_REGION_DEACTIVATE) {
61                 if (*region_context) {
62                         acpi_cm_free (*region_context);
63                         *region_context = NULL;
64                 }
65                 return (AE_OK);
66         }
67
68
69         /* Activate.  Create a new context */
70
71         *region_context = acpi_cm_callocate (sizeof (MEM_HANDLER_CONTEXT));
72         if (!(*region_context)) {
73                 return (AE_NO_MEMORY);
74         }
75
76         return (AE_OK);
77 }
78
79
80 /*****************************************************************************
81  *
82  * FUNCTION:    Acpi_ev_io_space_region_setup
83  *
84  * PARAMETERS:  Region_obj          - region we are interested in
85  *              Function            - start or stop
86  *              Handler_context     - Address space handler context
87  *              Region_context      - Region specific context
88  *
89  * RETURN:      Status
90  *
91  * DESCRIPTION: Do any prep work for region handling
92  *
93  ****************************************************************************/
94
95 ACPI_STATUS
96 acpi_ev_io_space_region_setup (
97         ACPI_HANDLE             handle,
98         u32                     function,
99         void                    *handler_context,
100         void                    **region_context)
101 {
102         if (function == ACPI_REGION_DEACTIVATE) {
103                 *region_context = NULL;
104         }
105         else {
106                 *region_context = handler_context;
107         }
108
109         return (AE_OK);
110 }
111
112
113 /*****************************************************************************
114  *
115  * FUNCTION:    Acpi_ev_pci_config_region_setup
116  *
117  * PARAMETERS:  Region_obj          - region we are interested in
118  *              Function            - start or stop
119  *              Handler_context     - Address space handler context
120  *              Region_context      - Region specific context
121  *
122  * RETURN:      Status
123  *
124  * DESCRIPTION: Do any prep work for region handling
125  *
126  * MUTEX:       Assumes namespace is not locked
127  *
128  ****************************************************************************/
129
130 ACPI_STATUS
131 acpi_ev_pci_config_region_setup (
132         ACPI_HANDLE             handle,
133         u32                     function,
134         void                    *handler_context,
135         void                    **region_context)
136 {
137         ACPI_STATUS             status = AE_OK;
138         ACPI_INTEGER            temp;
139         PCI_HANDLER_CONTEXT     *pci_context = *region_context;
140         ACPI_OPERAND_OBJECT     *handler_obj;
141         ACPI_NAMESPACE_NODE     *node;
142         ACPI_OPERAND_OBJECT     *region_obj = (ACPI_OPERAND_OBJECT *) handle;
143         DEVICE_ID               object_hID;
144
145         handler_obj = region_obj->region.addr_handler;
146
147         if (!handler_obj) {
148                 /*
149                  *  No installed handler. This shouldn't happen because the dispatch
150                  *  routine checks before we get here, but we check again just in case.
151                  */
152                 return(AE_NOT_EXIST);
153         }
154
155         if (function == ACPI_REGION_DEACTIVATE) {
156                 if (pci_context) {
157                         acpi_cm_free (pci_context);
158                         *region_context = NULL;
159                 }
160
161                 return (status);
162         }
163
164
165         /* Create a new context */
166
167         pci_context = acpi_cm_callocate (sizeof(PCI_HANDLER_CONTEXT));
168         if (!pci_context) {
169                 return (AE_NO_MEMORY);
170         }
171
172         /*
173          *  For PCI Config space access, we have to pass the segment, bus,
174          *  device and function numbers.  This routine must acquire those.
175          */
176
177         /*
178          *  First get device and function numbers from the _ADR object
179          *  in the parent's scope.
180          */
181         ACPI_ASSERT(region_obj->region.node);
182
183         node = acpi_ns_get_parent_object (region_obj->region.node);
184
185
186         /* Acpi_evaluate the _ADR object */
187
188         status = acpi_cm_evaluate_numeric_object (METHOD_NAME__ADR, node, &temp);
189         /*
190          *  The default is zero, since the allocation above zeroed the data, just
191          *  do nothing on failures.
192          */
193         if (ACPI_SUCCESS (status)) {
194                 /*
195                  *  Got it..
196                  */
197                 pci_context->dev_func = (u32) temp;
198         }
199
200         /*
201          *  Get the _SEG and _BBN values from the device upon which the handler
202          *  is installed.
203          *
204          *  We need to get the _SEG and _BBN objects relative to the PCI BUS device.
205          *  This is the device the handler has been registered to handle.
206          */
207
208         /*
209          *  If the Addr_handler.Node is still pointing to the root, we need
210          *  to scan upward for a PCI Root bridge and re-associate the Op_region
211          *  handlers with that device.
212          */
213         if (handler_obj->addr_handler.node == acpi_gbl_root_node) {
214                 /*
215                  * Node is currently the parent object
216                  */
217                 while (node != acpi_gbl_root_node) {
218                         status = acpi_cm_execute_HID(node, &object_hID);
219
220                         if (ACPI_SUCCESS (status)) {
221                                 if (!(STRNCMP(object_hID.buffer, PCI_ROOT_HID_STRING,
222                                                    sizeof (PCI_ROOT_HID_STRING)))) {
223                                         acpi_install_address_space_handler(node,
224                                                            ADDRESS_SPACE_PCI_CONFIG,
225                                                            ACPI_DEFAULT_HANDLER, NULL, NULL);
226
227                                         break;
228                                 }
229                         }
230
231                         node = acpi_ns_get_parent_object(node);
232                 }
233         }
234         else {
235                 node = handler_obj->addr_handler.node;
236         }
237
238         status = acpi_cm_evaluate_numeric_object (METHOD_NAME__SEG, node, &temp);
239         if (ACPI_SUCCESS (status)) {
240                 /*
241                  *  Got it..
242                  */
243                 pci_context->seg = (u32) temp;
244         }
245
246         status = acpi_cm_evaluate_numeric_object (METHOD_NAME__BBN, node, &temp);
247         if (ACPI_SUCCESS (status)) {
248                 /*
249                  *  Got it..
250                  */
251                 pci_context->bus = (u32) temp;
252         }
253
254         *region_context = pci_context;
255
256         return (AE_OK);
257 }
258
259
260 /*****************************************************************************
261  *
262  * FUNCTION:    Acpi_ev_default_region_setup
263  *
264  * PARAMETERS:  Region_obj          - region we are interested in
265  *              Function            - start or stop
266  *              Handler_context     - Address space handler context
267  *              Region_context      - Region specific context
268  *
269  * RETURN:      Status
270  *
271  * DESCRIPTION: Do any prep work for region handling
272  *
273  ****************************************************************************/
274
275 ACPI_STATUS
276 acpi_ev_default_region_setup (
277         ACPI_HANDLE             handle,
278         u32                     function,
279         void                    *handler_context,
280         void                    **region_context)
281 {
282         if (function == ACPI_REGION_DEACTIVATE) {
283                 *region_context = NULL;
284         }
285         else {
286                 *region_context = handler_context;
287         }
288
289         return (AE_OK);
290 }
291
292
293 /******************************************************************************
294  *
295  * FUNCTION:    Acpi_ev_initialize_region
296  *
297  * PARAMETERS:  Region_obj - Region we are initializing
298  *
299  * RETURN:      Status
300  *
301  * DESCRIPTION: Initializes the region, finds any _REG methods and saves them
302  *              for execution at a later time
303  *
304  *              Get the appropriate address space handler for a newly
305  *              created region.
306  *
307  *              This also performs address space specific intialization.  For
308  *              example, PCI regions must have an _ADR object that contains
309  *              a PCI address in the scope of the defintion.  This address is
310  *              required to perform an access to PCI config space.
311  *
312  ******************************************************************************/
313
314 ACPI_STATUS
315 acpi_ev_initialize_region (
316         ACPI_OPERAND_OBJECT     *region_obj,
317         u8                      acpi_ns_locked)
318 {
319         ACPI_OPERAND_OBJECT    *handler_obj;
320         ACPI_OPERAND_OBJECT    *obj_desc;
321         ACPI_ADDRESS_SPACE_TYPE space_id;
322         ACPI_NAMESPACE_NODE    *node;
323         ACPI_STATUS             status;
324         ACPI_NAMESPACE_NODE    *method_node;
325         ACPI_NAME              *reg_name_ptr = (ACPI_NAME *) METHOD_NAME__REG;
326
327
328         if (!region_obj) {
329                 return (AE_BAD_PARAMETER);
330         }
331
332         ACPI_ASSERT(region_obj->region.node);
333
334         node = acpi_ns_get_parent_object (region_obj->region.node);
335         space_id = region_obj->region.space_id;
336
337         region_obj->region.addr_handler = NULL;
338         region_obj->region.extra->extra.method_REG = NULL;
339         region_obj->region.flags &= ~(AOPOBJ_INITIALIZED);
340
341         /*
342          *  Find any "_REG" associated with this region definition
343          */
344         status = acpi_ns_search_node (*reg_name_ptr, node,
345                           ACPI_TYPE_METHOD, &method_node);
346         if (ACPI_SUCCESS (status)) {
347                 /*
348                  *  The _REG method is optional and there can be only one per region
349                  *  definition.  This will be executed when the handler is attached
350                  *  or removed
351                  */
352                 region_obj->region.extra->extra.method_REG = method_node;
353         }
354
355         /*
356          *  The following loop depends upon the root Node having no parent
357          *  ie: Acpi_gbl_Root_node->Parent_entry being set to NULL
358          */
359         while (node) {
360                 /*
361                  *  Check to see if a handler exists
362                  */
363                 handler_obj = NULL;
364                 obj_desc = acpi_ns_get_attached_object ((ACPI_HANDLE) node);
365                 if (obj_desc) {
366                         /*
367                          *  can only be a handler if the object exists
368                          */
369                         switch (node->type) {
370                         case ACPI_TYPE_DEVICE:
371
372                                 handler_obj = obj_desc->device.addr_handler;
373                                 break;
374
375                         case ACPI_TYPE_PROCESSOR:
376
377                                 handler_obj = obj_desc->processor.addr_handler;
378                                 break;
379
380                         case ACPI_TYPE_THERMAL:
381
382                                 handler_obj = obj_desc->thermal_zone.addr_handler;
383                                 break;
384                         }
385
386                         while (handler_obj) {
387                                 /*
388                                  *  This guy has at least one address handler
389                                  *  see if it has the type we want
390                                  */
391                                 if (handler_obj->addr_handler.space_id == space_id) {
392                                         /*
393                                          *  Found it! Now update the region and the handler
394                                          */
395                                         acpi_ev_associate_region_and_handler (handler_obj, region_obj, acpi_ns_locked);
396                                         return (AE_OK);
397                                 }
398
399                                 handler_obj = handler_obj->addr_handler.next;
400
401                         } /* while handlerobj */
402                 }
403
404                 /*
405                  *  This one does not have the handler we need
406                  *  Pop up one level
407                  */
408                 node = acpi_ns_get_parent_object (node);
409
410         } /* while Node != ROOT */
411
412         /*
413          *  If we get here, there is no handler for this region
414          */
415         return (AE_NOT_EXIST);
416 }
417