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