:pserver:cvsanon@mok.lvcm.com:/CVS/ReactOS reactos
[reactos.git] / drivers / bus / acpi / executer / amconfig.c
1 /******************************************************************************
2  *
3  * Module Name: amconfig - Namespace reconfiguration (Load/Unload opcodes)
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 "acparser.h"
29 #include "acinterp.h"
30 #include "amlcode.h"
31 #include "acnamesp.h"
32 #include "acevents.h"
33 #include "actables.h"
34 #include "acdispat.h"
35
36
37 #define _COMPONENT          ACPI_EXECUTER
38          MODULE_NAME         ("amconfig")
39
40
41 /*****************************************************************************
42  *
43  * FUNCTION:    Acpi_aml_exec_load_table
44  *
45  * PARAMETERS:  Rgn_desc        - Op region where the table will be obtained
46  *              Ddb_handle      - Where a handle to the table will be returned
47  *
48  * RETURN:      Status
49  *
50  * DESCRIPTION: Load an ACPI table
51  *
52  ****************************************************************************/
53
54 static ACPI_STATUS
55 acpi_aml_exec_load_table (
56         ACPI_OPERAND_OBJECT     *rgn_desc,
57         ACPI_HANDLE             *ddb_handle)
58 {
59         ACPI_STATUS             status;
60         ACPI_OPERAND_OBJECT     *table_desc = NULL;
61         u8                      *table_ptr;
62         u8                      *table_data_ptr;
63         ACPI_TABLE_HEADER       table_header;
64         ACPI_TABLE_DESC         table_info;
65         u32                     i;
66
67
68         /* TBD: [Unhandled] Object can be either a field or an opregion */
69
70
71         /* Get the table header */
72
73         table_header.length = 0;
74         for (i = 0; i < sizeof (ACPI_TABLE_HEADER); i++) {
75                 status = acpi_ev_address_space_dispatch (rgn_desc, ADDRESS_SPACE_READ,
76                                    (ACPI_PHYSICAL_ADDRESS) i, 8,
77                                    (u32 *) ((u8 *) &table_header + i));
78                 if (ACPI_FAILURE (status)) {
79                         return (status);
80                 }
81         }
82
83         /* Allocate a buffer for the entire table */
84
85         table_ptr = acpi_cm_allocate (table_header.length);
86         if (!table_ptr) {
87                 return (AE_NO_MEMORY);
88         }
89
90         /* Copy the header to the buffer */
91
92         MEMCPY (table_ptr, &table_header, sizeof (ACPI_TABLE_HEADER));
93         table_data_ptr = table_ptr + sizeof (ACPI_TABLE_HEADER);
94
95
96         /* Get the table from the op region */
97
98         for (i = 0; i < table_header.length; i++) {
99                 status = acpi_ev_address_space_dispatch (rgn_desc, ADDRESS_SPACE_READ,
100                                    (ACPI_PHYSICAL_ADDRESS)i, 8,
101                                    (u32 *) (table_data_ptr + i));
102                 if (ACPI_FAILURE (status)) {
103                         goto cleanup;
104                 }
105         }
106
107
108         /* Table must be either an SSDT or a PSDT */
109
110         if ((!STRNCMP (table_header.signature,
111                           acpi_gbl_acpi_table_data[ACPI_TABLE_PSDT].signature,
112                           acpi_gbl_acpi_table_data[ACPI_TABLE_PSDT].sig_length)) &&
113                 (!STRNCMP (table_header.signature,
114                                  acpi_gbl_acpi_table_data[ACPI_TABLE_SSDT].signature,
115                                  acpi_gbl_acpi_table_data[ACPI_TABLE_SSDT].sig_length))) {
116                 status = AE_BAD_SIGNATURE;
117                 goto cleanup;
118         }
119
120         /* Create an object to be the table handle */
121
122         table_desc = acpi_cm_create_internal_object (INTERNAL_TYPE_REFERENCE);
123         if (!table_desc) {
124                 status = AE_NO_MEMORY;
125                 goto cleanup;
126         }
127
128
129         /* Install the new table into the local data structures */
130
131         table_info.pointer     = (ACPI_TABLE_HEADER *) table_ptr;
132         table_info.length      = table_header.length;
133         table_info.allocation  = ACPI_MEM_ALLOCATED;
134         table_info.base_pointer = table_ptr;
135
136         status = acpi_tb_install_table (NULL, &table_info);
137         if (ACPI_FAILURE (status)) {
138                 goto cleanup;
139         }
140
141         /* Add the table to the namespace */
142
143         /* TBD: [Restructure] - change to whatever new interface is appropriate */
144 /*
145         Status = Acpi_load_namespace ();
146         if (ACPI_FAILURE (Status))
147         {
148 */
149                 /* TBD: [Errors] Unload the table on failure ? */
150 /*
151                 goto Cleanup;
152         }
153 */
154
155
156         /* TBD: [Investigate] we need a pointer to the table desc */
157
158         /* Init the table handle */
159
160         table_desc->reference.opcode = AML_LOAD_OP;
161         table_desc->reference.object = table_info.installed_desc;
162
163         *ddb_handle = table_desc;
164
165         return (status);
166
167
168 cleanup:
169
170         acpi_cm_free (table_desc);
171         acpi_cm_free (table_ptr);
172         return (status);
173
174 }
175
176
177 /*****************************************************************************
178  *
179  * FUNCTION:    Acpi_aml_exec_unload_table
180  *
181  * PARAMETERS:  Ddb_handle          - Handle to a previously loaded table
182  *
183  * RETURN:      Status
184  *
185  * DESCRIPTION: Unload an ACPI table
186  *
187  ****************************************************************************/
188
189 static ACPI_STATUS
190 acpi_aml_exec_unload_table (
191         ACPI_HANDLE             ddb_handle)
192 {
193         ACPI_STATUS             status = AE_NOT_IMPLEMENTED;
194         ACPI_OPERAND_OBJECT     *table_desc = (ACPI_OPERAND_OBJECT *) ddb_handle;
195         ACPI_TABLE_DESC         *table_info;
196
197
198         /* Validate the handle */
199         /* Although the handle is partially validated in Acpi_aml_exec_reconfiguration(),
200          *  when it calls Acpi_aml_resolve_operands(), the handle is more completely
201          *  validated here.
202          */
203
204         if ((!ddb_handle) ||
205                 (!VALID_DESCRIPTOR_TYPE (ddb_handle, ACPI_DESC_TYPE_INTERNAL)) ||
206                 (((ACPI_OPERAND_OBJECT  *)ddb_handle)->common.type !=
207                                 INTERNAL_TYPE_REFERENCE)) {
208                 return (AE_BAD_PARAMETER);
209         }
210
211
212         /* Get the actual table descriptor from the Ddb_handle */
213
214         table_info = (ACPI_TABLE_DESC *) table_desc->reference.object;
215
216         /*
217          * Delete the entire namespace under this table Node
218          * (Offset contains the Table_id)
219          */
220
221         status = acpi_ns_delete_namespace_by_owner (table_info->table_id);
222         if (ACPI_FAILURE (status)) {
223                 return (status);
224         }
225
226         /* Delete the table itself */
227
228         acpi_tb_uninstall_table (table_info->installed_desc);
229
230         /* Delete the table descriptor (Ddb_handle) */
231
232         acpi_cm_remove_reference (table_desc);
233
234         return (status);
235 }
236
237
238 /*****************************************************************************
239  *
240  * FUNCTION:    Acpi_aml_exec_reconfiguration
241  *
242  * PARAMETERS:  Opcode              - The opcode to be executed
243  *              Walk_state          - Current state of the parse tree walk
244  *
245  * RETURN:      Status
246  *
247  * DESCRIPTION: Reconfiguration opcodes such as LOAD and UNLOAD
248  *
249  ****************************************************************************/
250
251 ACPI_STATUS
252 acpi_aml_exec_reconfiguration (
253         u16                     opcode,
254         ACPI_WALK_STATE         *walk_state)
255 {
256         ACPI_STATUS             status;
257         ACPI_OPERAND_OBJECT     *region_desc = NULL;
258         ACPI_HANDLE             *ddb_handle;
259
260
261         /* Resolve the operands */
262
263         status = acpi_aml_resolve_operands (opcode, WALK_OPERANDS, walk_state);
264         /* Get the table handle, common for both opcodes */
265
266         status |= acpi_ds_obj_stack_pop_object ((ACPI_OPERAND_OBJECT **) &ddb_handle,
267                          walk_state);
268
269         switch (opcode) {
270
271         case AML_LOAD_OP:
272
273                 /* Get the region or field descriptor */
274
275                 status |= acpi_ds_obj_stack_pop_object (&region_desc, walk_state);
276                 if (ACPI_FAILURE (status)) {
277                         acpi_cm_remove_reference (region_desc);
278                         return (status);
279                 }
280
281                 status = acpi_aml_exec_load_table (region_desc, ddb_handle);
282                 break;
283
284
285         case AML_UNLOAD_OP:
286
287                 if (ACPI_FAILURE (status)) {
288                         return (status);
289                 }
290
291                 status = acpi_aml_exec_unload_table (ddb_handle);
292                 break;
293
294
295         default:
296
297                 status = AE_AML_BAD_OPCODE;
298                 break;
299         }
300
301
302         return (status);
303 }
304