:pserver:cvsanon@mok.lvcm.com:/CVS/ReactOS reactos
[reactos.git] / drivers / bus / acpi / events / evxfregn.c
1 /******************************************************************************
2  *
3  * Module Name: evxfregn - External Interfaces, ACPI Operation Regions and
4  *                         Address Spaces.
5  *              $Revision$
6  *
7  *****************************************************************************/
8
9 /*
10  *  Copyright (C) 2000, 2001 R. Byron Moore
11  *
12  *  This program is free software; you can redistribute it and/or modify
13  *  it under the terms of the GNU General Public License as published by
14  *  the Free Software Foundation; either version 2 of the License, or
15  *  (at your option) any later version.
16  *
17  *  This program is distributed in the hope that it will be useful,
18  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
19  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  *  GNU General Public License for more details.
21  *
22  *  You should have received a copy of the GNU General Public License
23  *  along with this program; if not, write to the Free Software
24  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
25  */
26
27
28 #include "acpi.h"
29 #include "achware.h"
30 #include "acnamesp.h"
31 #include "acevents.h"
32 #include "amlcode.h"
33 #include "acinterp.h"
34
35 #define _COMPONENT          ACPI_EVENTS
36          MODULE_NAME         ("evxfregn")
37
38
39 /******************************************************************************
40  *
41  * FUNCTION:    Acpi_install_address_space_handler
42  *
43  * PARAMETERS:  Device          - Handle for the device
44  *              Space_id        - The address space ID
45  *              Handler         - Address of the handler
46  *              Setup           - Address of the setup function
47  *              Context         - Value passed to the handler on each access
48  *
49  * RETURN:      Status
50  *
51  * DESCRIPTION: Install a handler for all Op_regions of a given Space_id.
52  *
53  ******************************************************************************/
54
55 ACPI_STATUS
56 acpi_install_address_space_handler (
57         ACPI_HANDLE             device,
58         ACPI_ADDRESS_SPACE_TYPE space_id,
59         ADDRESS_SPACE_HANDLER   handler,
60         ADDRESS_SPACE_SETUP     setup,
61         void                    *context)
62 {
63         ACPI_OPERAND_OBJECT     *obj_desc;
64         ACPI_OPERAND_OBJECT     *handler_obj;
65         ACPI_NAMESPACE_NODE     *node;
66         ACPI_STATUS             status = AE_OK;
67         OBJECT_TYPE_INTERNAL    type;
68         u16                     flags = 0;
69
70
71         /* Parameter validation */
72
73         if ((!device)   ||
74                 ((!handler)  && (handler != ACPI_DEFAULT_HANDLER)) ||
75                 (space_id > ACPI_MAX_ADDRESS_SPACE)) {
76                 return (AE_BAD_PARAMETER);
77         }
78
79         acpi_cm_acquire_mutex (ACPI_MTX_NAMESPACE);
80
81         /* Convert and validate the device handle */
82
83         node = acpi_ns_convert_handle_to_entry (device);
84         if (!node) {
85                 status = AE_BAD_PARAMETER;
86                 goto unlock_and_exit;
87         }
88
89         /*
90          *  This registration is valid for only the types below
91          *  and the root.  This is where the default handlers
92          *  get placed.
93          */
94
95         if ((node->type != ACPI_TYPE_DEVICE)     &&
96                 (node->type != ACPI_TYPE_PROCESSOR)  &&
97                 (node->type != ACPI_TYPE_THERMAL)    &&
98                 (node != acpi_gbl_root_node)) {
99                 status = AE_BAD_PARAMETER;
100                 goto unlock_and_exit;
101         }
102
103         if (handler == ACPI_DEFAULT_HANDLER) {
104                 flags = ADDR_HANDLER_DEFAULT_INSTALLED;
105
106                 switch (space_id) {
107                 case ADDRESS_SPACE_SYSTEM_MEMORY:
108                         handler = acpi_aml_system_memory_space_handler;
109                         setup = acpi_ev_system_memory_region_setup;
110                         break;
111
112                 case ADDRESS_SPACE_SYSTEM_IO:
113                         handler = acpi_aml_system_io_space_handler;
114                         setup = acpi_ev_io_space_region_setup;
115                         break;
116
117                 case ADDRESS_SPACE_PCI_CONFIG:
118                         handler = acpi_aml_pci_config_space_handler;
119                         setup = acpi_ev_pci_config_region_setup;
120                         break;
121
122                 default:
123                         status = AE_NOT_EXIST;
124                         goto unlock_and_exit;
125                         break;
126                 }
127         }
128
129         /*
130          *  If the caller hasn't specified a setup routine, use the default
131          */
132         if (!setup) {
133                 setup = acpi_ev_default_region_setup;
134         }
135
136         /*
137          *  Check for an existing internal object
138          */
139
140         obj_desc = acpi_ns_get_attached_object ((ACPI_HANDLE) node);
141         if (obj_desc) {
142                 /*
143                  *  The object exists.
144                  *  Make sure the handler is not already installed.
145                  */
146
147                 /* check the address handler the user requested */
148
149                 handler_obj = obj_desc->device.addr_handler;
150                 while (handler_obj) {
151                         /*
152                          *  We have an Address handler, see if user requested this
153                          *  address space.
154                          */
155                         if(handler_obj->addr_handler.space_id == space_id) {
156                                 status = AE_EXIST;
157                                 goto unlock_and_exit;
158                         }
159
160                         /*
161                          *  Move through the linked list of handlers
162                          */
163                         handler_obj = handler_obj->addr_handler.next;
164                 }
165         }
166
167         else {
168                 /* Obj_desc does not exist, create one */
169
170                 if (node->type == ACPI_TYPE_ANY) {
171                         type = ACPI_TYPE_DEVICE;
172                 }
173
174                 else {
175                         type = node->type;
176                 }
177
178                 obj_desc = acpi_cm_create_internal_object (type);
179                 if (!obj_desc) {
180                         status = AE_NO_MEMORY;
181                         goto unlock_and_exit;
182                 }
183
184                 /* Init new descriptor */
185
186                 obj_desc->common.type = (u8) type;
187
188                 /* Attach the new object to the Node */
189
190                 status = acpi_ns_attach_object (node, obj_desc, (u8) type);
191                 if (ACPI_FAILURE (status)) {
192                         acpi_cm_remove_reference (obj_desc);
193                         goto unlock_and_exit;
194                 }
195         }
196
197         /*
198          *  Now we can install the handler
199          *
200          *  At this point we know that there is no existing handler.
201          *  So, we just allocate the object for the handler and link it
202          *  into the list.
203          */
204         handler_obj = acpi_cm_create_internal_object (INTERNAL_TYPE_ADDRESS_HANDLER);
205         if (!handler_obj) {
206                 status = AE_NO_MEMORY;
207                 goto unlock_and_exit;
208         }
209
210         handler_obj->addr_handler.space_id  = (u8) space_id;
211         handler_obj->addr_handler.hflags    = flags;
212         handler_obj->addr_handler.next      = obj_desc->device.addr_handler;
213         handler_obj->addr_handler.region_list = NULL;
214         handler_obj->addr_handler.node      = node;
215         handler_obj->addr_handler.handler   = handler;
216         handler_obj->addr_handler.context   = context;
217         handler_obj->addr_handler.setup     = setup;
218
219         /*
220          *  Now walk the namespace finding all of the regions this
221          *  handler will manage.
222          *
223          *  We start at the device and search the branch toward
224          *  the leaf nodes until either the leaf is encountered or
225          *  a device is detected that has an address handler of the
226          *  same type.
227          *
228          *  In either case we back up and search down the remainder
229          *  of the branch
230          */
231         status = acpi_ns_walk_namespace (ACPI_TYPE_ANY, device,
232                          ACPI_UINT32_MAX, NS_WALK_UNLOCK,
233                          acpi_ev_addr_handler_helper,
234                          handler_obj, NULL);
235
236         /*
237          *  Place this handler 1st on the list
238          */
239
240         handler_obj->common.reference_count =
241                          (u16) (handler_obj->common.reference_count +
242                          obj_desc->common.reference_count - 1);
243         obj_desc->device.addr_handler = handler_obj;
244
245
246 unlock_and_exit:
247         acpi_cm_release_mutex (ACPI_MTX_NAMESPACE);
248         return (status);
249 }
250
251
252 /******************************************************************************
253  *
254  * FUNCTION:    Acpi_remove_address_space_handler
255  *
256  * PARAMETERS:  Space_id        - The address space ID
257  *              Handler         - Address of the handler
258  *
259  * RETURN:      Status
260  *
261  * DESCRIPTION: Install a handler for accesses on an Operation Region
262  *
263  ******************************************************************************/
264
265 ACPI_STATUS
266 acpi_remove_address_space_handler (
267         ACPI_HANDLE             device,
268         ACPI_ADDRESS_SPACE_TYPE space_id,
269         ADDRESS_SPACE_HANDLER   handler)
270 {
271         ACPI_OPERAND_OBJECT     *obj_desc;
272         ACPI_OPERAND_OBJECT     *handler_obj;
273         ACPI_OPERAND_OBJECT     *region_obj;
274         ACPI_OPERAND_OBJECT     **last_obj_ptr;
275         ACPI_NAMESPACE_NODE     *node;
276         ACPI_STATUS             status = AE_OK;
277
278
279         /* Parameter validation */
280
281         if ((!device)   ||
282                 ((!handler)  && (handler != ACPI_DEFAULT_HANDLER)) ||
283                 (space_id > ACPI_MAX_ADDRESS_SPACE)) {
284                 return (AE_BAD_PARAMETER);
285         }
286
287         acpi_cm_acquire_mutex (ACPI_MTX_NAMESPACE);
288
289         /* Convert and validate the device handle */
290
291         node = acpi_ns_convert_handle_to_entry (device);
292         if (!node) {
293                 status = AE_BAD_PARAMETER;
294                 goto unlock_and_exit;
295         }
296
297
298         /* Make sure the internal object exists */
299
300         obj_desc = acpi_ns_get_attached_object ((ACPI_HANDLE) node);
301         if (!obj_desc) {
302                 /*
303                  *  The object DNE.
304                  */
305                 status = AE_NOT_EXIST;
306                 goto unlock_and_exit;
307         }
308
309         /*
310          *  find the address handler the user requested
311          */
312
313         handler_obj = obj_desc->device.addr_handler;
314         last_obj_ptr = &obj_desc->device.addr_handler;
315         while (handler_obj) {
316                 /*
317                  *  We have a handler, see if user requested this one
318                  */
319
320                 if(handler_obj->addr_handler.space_id == space_id) {
321                         /*
322                          *  Got it, first dereference this in the Regions
323                          */
324                         region_obj = handler_obj->addr_handler.region_list;
325
326                         /* Walk the handler's region list */
327
328                         while (region_obj) {
329                                 /*
330                                  *  First disassociate the handler from the region.
331                                  *
332                                  *  NOTE: this doesn't mean that the region goes away
333                                  *  The region is just inaccessible as indicated to
334                                  *  the _REG method
335                                  */
336                                 acpi_ev_disassociate_region_from_handler(region_obj, FALSE);
337
338                                 /*
339                                  *  Walk the list, since we took the first region and it
340                                  *  was removed from the list by the dissassociate call
341                                  *  we just get the first item on the list again
342                                  */
343                                 region_obj = handler_obj->addr_handler.region_list;
344
345                         }
346
347                         /*
348                          *  Remove this Handler object from the list
349                          */
350                         *last_obj_ptr = handler_obj->addr_handler.next;
351
352                         /*
353                          *  Now we can delete the handler object
354                          */
355                         acpi_cm_remove_reference (handler_obj);
356                         acpi_cm_remove_reference (handler_obj);
357
358                         goto unlock_and_exit;
359                 }
360
361                 /*
362                  *  Move through the linked list of handlers
363                  */
364                 last_obj_ptr = &handler_obj->addr_handler.next;
365                 handler_obj = handler_obj->addr_handler.next;
366         }
367
368
369         /*
370          *  The handler does not exist
371          */
372         status = AE_NOT_EXIST;
373
374
375 unlock_and_exit:
376         acpi_cm_release_mutex (ACPI_MTX_NAMESPACE);
377         return (status);
378 }
379
380