]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - sys/contrib/dev/acpica/tables/tbxface.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / sys / contrib / dev / acpica / tables / tbxface.c
1 /******************************************************************************
2  *
3  * Module Name: tbxface - Public interfaces to the ACPI subsystem
4  *                         ACPI table oriented interfaces
5  *
6  *****************************************************************************/
7
8 /*
9  * Copyright (C) 2000 - 2011, Intel Corp.
10  * All rights reserved.
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted provided that the following conditions
14  * are met:
15  * 1. Redistributions of source code must retain the above copyright
16  *    notice, this list of conditions, and the following disclaimer,
17  *    without modification.
18  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
19  *    substantially similar to the "NO WARRANTY" disclaimer below
20  *    ("Disclaimer") and any redistribution must be conditioned upon
21  *    including a substantially similar Disclaimer requirement for further
22  *    binary redistribution.
23  * 3. Neither the names of the above-listed copyright holders nor the names
24  *    of any contributors may be used to endorse or promote products derived
25  *    from this software without specific prior written permission.
26  *
27  * Alternatively, this software may be distributed under the terms of the
28  * GNU General Public License ("GPL") version 2 as published by the Free
29  * Software Foundation.
30  *
31  * NO WARRANTY
32  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
33  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
34  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
35  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
36  * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
37  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
38  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
39  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
40  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
41  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
42  * POSSIBILITY OF SUCH DAMAGES.
43  */
44
45 #define __TBXFACE_C__
46
47 #include <contrib/dev/acpica/include/acpi.h>
48 #include <contrib/dev/acpica/include/accommon.h>
49 #include <contrib/dev/acpica/include/acnamesp.h>
50 #include <contrib/dev/acpica/include/actables.h>
51
52 #define _COMPONENT          ACPI_TABLES
53         ACPI_MODULE_NAME    ("tbxface")
54
55 /* Local prototypes */
56
57 static ACPI_STATUS
58 AcpiTbLoadNamespace (
59     void);
60
61
62 /*******************************************************************************
63  *
64  * FUNCTION:    AcpiAllocateRootTable
65  *
66  * PARAMETERS:  InitialTableCount   - Size of InitialTableArray, in number of
67  *                                    ACPI_TABLE_DESC structures
68  *
69  * RETURN:      Status
70  *
71  * DESCRIPTION: Allocate a root table array. Used by iASL compiler and
72  *              AcpiInitializeTables.
73  *
74  ******************************************************************************/
75
76 ACPI_STATUS
77 AcpiAllocateRootTable (
78     UINT32                  InitialTableCount)
79 {
80
81     AcpiGbl_RootTableList.MaxTableCount = InitialTableCount;
82     AcpiGbl_RootTableList.Flags = ACPI_ROOT_ALLOW_RESIZE;
83
84     return (AcpiTbResizeRootTableList ());
85 }
86
87
88 /*******************************************************************************
89  *
90  * FUNCTION:    AcpiInitializeTables
91  *
92  * PARAMETERS:  InitialTableArray   - Pointer to an array of pre-allocated
93  *                                    ACPI_TABLE_DESC structures. If NULL, the
94  *                                    array is dynamically allocated.
95  *              InitialTableCount   - Size of InitialTableArray, in number of
96  *                                    ACPI_TABLE_DESC structures
97  *              AllowRealloc        - Flag to tell Table Manager if resize of
98  *                                    pre-allocated array is allowed. Ignored
99  *                                    if InitialTableArray is NULL.
100  *
101  * RETURN:      Status
102  *
103  * DESCRIPTION: Initialize the table manager, get the RSDP and RSDT/XSDT.
104  *
105  * NOTE:        Allows static allocation of the initial table array in order
106  *              to avoid the use of dynamic memory in confined environments
107  *              such as the kernel boot sequence where it may not be available.
108  *
109  *              If the host OS memory managers are initialized, use NULL for
110  *              InitialTableArray, and the table will be dynamically allocated.
111  *
112  ******************************************************************************/
113
114 ACPI_STATUS
115 AcpiInitializeTables (
116     ACPI_TABLE_DESC         *InitialTableArray,
117     UINT32                  InitialTableCount,
118     BOOLEAN                 AllowResize)
119 {
120     ACPI_PHYSICAL_ADDRESS   RsdpAddress;
121     ACPI_STATUS             Status;
122
123
124     ACPI_FUNCTION_TRACE (AcpiInitializeTables);
125
126
127     /*
128      * Set up the Root Table Array
129      * Allocate the table array if requested
130      */
131     if (!InitialTableArray)
132     {
133         Status = AcpiAllocateRootTable (InitialTableCount);
134         if (ACPI_FAILURE (Status))
135         {
136             return_ACPI_STATUS (Status);
137         }
138     }
139     else
140     {
141         /* Root Table Array has been statically allocated by the host */
142
143         ACPI_MEMSET (InitialTableArray, 0,
144             (ACPI_SIZE) InitialTableCount * sizeof (ACPI_TABLE_DESC));
145
146         AcpiGbl_RootTableList.Tables = InitialTableArray;
147         AcpiGbl_RootTableList.MaxTableCount = InitialTableCount;
148         AcpiGbl_RootTableList.Flags = ACPI_ROOT_ORIGIN_UNKNOWN;
149         if (AllowResize)
150         {
151             AcpiGbl_RootTableList.Flags |= ACPI_ROOT_ALLOW_RESIZE;
152         }
153     }
154
155     /* Get the address of the RSDP */
156
157     RsdpAddress = AcpiOsGetRootPointer ();
158     if (!RsdpAddress)
159     {
160         return_ACPI_STATUS (AE_NOT_FOUND);
161     }
162
163     /*
164      * Get the root table (RSDT or XSDT) and extract all entries to the local
165      * Root Table Array. This array contains the information of the RSDT/XSDT
166      * in a common, more useable format.
167      */
168     Status = AcpiTbParseRootTable (RsdpAddress);
169     return_ACPI_STATUS (Status);
170 }
171
172 ACPI_EXPORT_SYMBOL (AcpiInitializeTables)
173
174
175 /*******************************************************************************
176  *
177  * FUNCTION:    AcpiReallocateRootTable
178  *
179  * PARAMETERS:  None
180  *
181  * RETURN:      Status
182  *
183  * DESCRIPTION: Reallocate Root Table List into dynamic memory. Copies the
184  *              root list from the previously provided scratch area. Should
185  *              be called once dynamic memory allocation is available in the
186  *              kernel
187  *
188  ******************************************************************************/
189
190 ACPI_STATUS
191 AcpiReallocateRootTable (
192     void)
193 {
194     ACPI_TABLE_DESC         *Tables;
195     ACPI_SIZE               NewSize;
196     ACPI_SIZE               CurrentSize;
197
198
199     ACPI_FUNCTION_TRACE (AcpiReallocateRootTable);
200
201
202     /*
203      * Only reallocate the root table if the host provided a static buffer
204      * for the table array in the call to AcpiInitializeTables.
205      */
206     if (AcpiGbl_RootTableList.Flags & ACPI_ROOT_ORIGIN_ALLOCATED)
207     {
208         return_ACPI_STATUS (AE_SUPPORT);
209     }
210
211     /*
212      * Get the current size of the root table and add the default
213      * increment to create the new table size.
214      */
215     CurrentSize = (ACPI_SIZE)
216         AcpiGbl_RootTableList.CurrentTableCount * sizeof (ACPI_TABLE_DESC);
217
218     NewSize = CurrentSize +
219         (ACPI_ROOT_TABLE_SIZE_INCREMENT * sizeof (ACPI_TABLE_DESC));
220
221     /* Create new array and copy the old array */
222
223     Tables = ACPI_ALLOCATE_ZEROED (NewSize);
224     if (!Tables)
225     {
226         return_ACPI_STATUS (AE_NO_MEMORY);
227     }
228
229     ACPI_MEMCPY (Tables, AcpiGbl_RootTableList.Tables, CurrentSize);
230
231     /*
232      * Update the root table descriptor. The new size will be the current
233      * number of tables plus the increment, independent of the reserved
234      * size of the original table list.
235      */
236     AcpiGbl_RootTableList.Tables = Tables;
237     AcpiGbl_RootTableList.MaxTableCount =
238         AcpiGbl_RootTableList.CurrentTableCount + ACPI_ROOT_TABLE_SIZE_INCREMENT;
239     AcpiGbl_RootTableList.Flags =
240         ACPI_ROOT_ORIGIN_ALLOCATED | ACPI_ROOT_ALLOW_RESIZE;
241
242     return_ACPI_STATUS (AE_OK);
243 }
244
245 ACPI_EXPORT_SYMBOL (AcpiReallocateRootTable)
246
247
248 /*******************************************************************************
249  *
250  * FUNCTION:    AcpiGetTableHeader
251  *
252  * PARAMETERS:  Signature           - ACPI signature of needed table
253  *              Instance            - Which instance (for SSDTs)
254  *              OutTableHeader      - The pointer to the table header to fill
255  *
256  * RETURN:      Status and pointer to mapped table header
257  *
258  * DESCRIPTION: Finds an ACPI table header.
259  *
260  * NOTE:        Caller is responsible in unmapping the header with
261  *              AcpiOsUnmapMemory
262  *
263  ******************************************************************************/
264
265 ACPI_STATUS
266 AcpiGetTableHeader (
267     char                    *Signature,
268     UINT32                  Instance,
269     ACPI_TABLE_HEADER       *OutTableHeader)
270 {
271     UINT32                  i;
272     UINT32                  j;
273     ACPI_TABLE_HEADER       *Header;
274
275
276     /* Parameter validation */
277
278     if (!Signature || !OutTableHeader)
279     {
280         return (AE_BAD_PARAMETER);
281     }
282
283     /* Walk the root table list */
284
285     for (i = 0, j = 0; i < AcpiGbl_RootTableList.CurrentTableCount; i++)
286     {
287         if (!ACPI_COMPARE_NAME (&(AcpiGbl_RootTableList.Tables[i].Signature),
288                     Signature))
289         {
290             continue;
291         }
292
293         if (++j < Instance)
294         {
295             continue;
296         }
297
298         if (!AcpiGbl_RootTableList.Tables[i].Pointer)
299         {
300             if ((AcpiGbl_RootTableList.Tables[i].Flags &
301                     ACPI_TABLE_ORIGIN_MASK) ==
302                 ACPI_TABLE_ORIGIN_MAPPED)
303             {
304                 Header = AcpiOsMapMemory (
305                             AcpiGbl_RootTableList.Tables[i].Address,
306                             sizeof (ACPI_TABLE_HEADER));
307                 if (!Header)
308                 {
309                     return AE_NO_MEMORY;
310                 }
311
312                 ACPI_MEMCPY (OutTableHeader, Header, sizeof(ACPI_TABLE_HEADER));
313                 AcpiOsUnmapMemory (Header, sizeof(ACPI_TABLE_HEADER));
314             }
315             else
316             {
317                 return AE_NOT_FOUND;
318             }
319         }
320         else
321         {
322             ACPI_MEMCPY (OutTableHeader,
323                 AcpiGbl_RootTableList.Tables[i].Pointer,
324                 sizeof(ACPI_TABLE_HEADER));
325         }
326
327         return (AE_OK);
328     }
329
330     return (AE_NOT_FOUND);
331 }
332
333 ACPI_EXPORT_SYMBOL (AcpiGetTableHeader)
334
335
336 /*******************************************************************************
337  *
338  * FUNCTION:    AcpiGetTable
339  *
340  * PARAMETERS:  Signature           - ACPI signature of needed table
341  *              Instance            - Which instance (for SSDTs)
342  *              OutTable            - Where the pointer to the table is returned
343  *
344  * RETURN:      Status and pointer to table
345  *
346  * DESCRIPTION: Finds and verifies an ACPI table.
347  *
348  ******************************************************************************/
349
350 ACPI_STATUS
351 AcpiGetTable (
352     char                    *Signature,
353     UINT32                  Instance,
354     ACPI_TABLE_HEADER       **OutTable)
355 {
356     UINT32                  i;
357     UINT32                  j;
358     ACPI_STATUS             Status;
359
360
361     /* Parameter validation */
362
363     if (!Signature || !OutTable)
364     {
365         return (AE_BAD_PARAMETER);
366     }
367
368     /* Walk the root table list */
369
370     for (i = 0, j = 0; i < AcpiGbl_RootTableList.CurrentTableCount; i++)
371     {
372         if (!ACPI_COMPARE_NAME (&(AcpiGbl_RootTableList.Tables[i].Signature),
373                 Signature))
374         {
375             continue;
376         }
377
378         if (++j < Instance)
379         {
380             continue;
381         }
382
383         Status = AcpiTbVerifyTable (&AcpiGbl_RootTableList.Tables[i]);
384         if (ACPI_SUCCESS (Status))
385         {
386             *OutTable = AcpiGbl_RootTableList.Tables[i].Pointer;
387         }
388
389         return (Status);
390     }
391
392     return (AE_NOT_FOUND);
393 }
394
395 ACPI_EXPORT_SYMBOL (AcpiGetTable)
396
397
398 /*******************************************************************************
399  *
400  * FUNCTION:    AcpiGetTableByIndex
401  *
402  * PARAMETERS:  TableIndex          - Table index
403  *              Table               - Where the pointer to the table is returned
404  *
405  * RETURN:      Status and pointer to the table
406  *
407  * DESCRIPTION: Obtain a table by an index into the global table list.
408  *
409  ******************************************************************************/
410
411 ACPI_STATUS
412 AcpiGetTableByIndex (
413     UINT32                  TableIndex,
414     ACPI_TABLE_HEADER       **Table)
415 {
416     ACPI_STATUS             Status;
417
418
419     ACPI_FUNCTION_TRACE (AcpiGetTableByIndex);
420
421
422     /* Parameter validation */
423
424     if (!Table)
425     {
426         return_ACPI_STATUS (AE_BAD_PARAMETER);
427     }
428
429     (void) AcpiUtAcquireMutex (ACPI_MTX_TABLES);
430
431     /* Validate index */
432
433     if (TableIndex >= AcpiGbl_RootTableList.CurrentTableCount)
434     {
435         (void) AcpiUtReleaseMutex (ACPI_MTX_TABLES);
436         return_ACPI_STATUS (AE_BAD_PARAMETER);
437     }
438
439     if (!AcpiGbl_RootTableList.Tables[TableIndex].Pointer)
440     {
441         /* Table is not mapped, map it */
442
443         Status = AcpiTbVerifyTable (&AcpiGbl_RootTableList.Tables[TableIndex]);
444         if (ACPI_FAILURE (Status))
445         {
446             (void) AcpiUtReleaseMutex (ACPI_MTX_TABLES);
447             return_ACPI_STATUS (Status);
448         }
449     }
450
451     *Table = AcpiGbl_RootTableList.Tables[TableIndex].Pointer;
452     (void) AcpiUtReleaseMutex (ACPI_MTX_TABLES);
453     return_ACPI_STATUS (AE_OK);
454 }
455
456 ACPI_EXPORT_SYMBOL (AcpiGetTableByIndex)
457
458
459 /*******************************************************************************
460  *
461  * FUNCTION:    AcpiTbLoadNamespace
462  *
463  * PARAMETERS:  None
464  *
465  * RETURN:      Status
466  *
467  * DESCRIPTION: Load the namespace from the DSDT and all SSDTs/PSDTs found in
468  *              the RSDT/XSDT.
469  *
470  ******************************************************************************/
471
472 static ACPI_STATUS
473 AcpiTbLoadNamespace (
474     void)
475 {
476     ACPI_STATUS             Status;
477     UINT32                  i;
478     ACPI_TABLE_HEADER       *NewDsdt;
479
480
481     ACPI_FUNCTION_TRACE (TbLoadNamespace);
482
483
484     (void) AcpiUtAcquireMutex (ACPI_MTX_TABLES);
485
486     /*
487      * Load the namespace. The DSDT is required, but any SSDT and
488      * PSDT tables are optional. Verify the DSDT.
489      */
490     if (!AcpiGbl_RootTableList.CurrentTableCount ||
491         !ACPI_COMPARE_NAME (
492             &(AcpiGbl_RootTableList.Tables[ACPI_TABLE_INDEX_DSDT].Signature),
493             ACPI_SIG_DSDT) ||
494          ACPI_FAILURE (AcpiTbVerifyTable (
495             &AcpiGbl_RootTableList.Tables[ACPI_TABLE_INDEX_DSDT])))
496     {
497         Status = AE_NO_ACPI_TABLES;
498         goto UnlockAndExit;
499     }
500
501     /*
502      * Save the DSDT pointer for simple access. This is the mapped memory
503      * address. We must take care here because the address of the .Tables
504      * array can change dynamically as tables are loaded at run-time. Note:
505      * .Pointer field is not validated until after call to AcpiTbVerifyTable.
506      */
507     AcpiGbl_DSDT = AcpiGbl_RootTableList.Tables[ACPI_TABLE_INDEX_DSDT].Pointer;
508
509     /*
510      * Optionally copy the entire DSDT to local memory (instead of simply
511      * mapping it.) There are some BIOSs that corrupt or replace the original
512      * DSDT, creating the need for this option. Default is FALSE, do not copy
513      * the DSDT.
514      */
515     if (AcpiGbl_CopyDsdtLocally)
516     {
517         NewDsdt = AcpiTbCopyDsdt (ACPI_TABLE_INDEX_DSDT);
518         if (NewDsdt)
519         {
520             AcpiGbl_DSDT = NewDsdt;
521         }
522     }
523
524     /*
525      * Save the original DSDT header for detection of table corruption
526      * and/or replacement of the DSDT from outside the OS.
527      */
528     ACPI_MEMCPY (&AcpiGbl_OriginalDsdtHeader, AcpiGbl_DSDT,
529         sizeof (ACPI_TABLE_HEADER));
530
531     (void) AcpiUtReleaseMutex (ACPI_MTX_TABLES);
532
533     /* Load and parse tables */
534
535     Status = AcpiNsLoadTable (ACPI_TABLE_INDEX_DSDT, AcpiGbl_RootNode);
536     if (ACPI_FAILURE (Status))
537     {
538         return_ACPI_STATUS (Status);
539     }
540
541     /* Load any SSDT or PSDT tables. Note: Loop leaves tables locked */
542
543     (void) AcpiUtAcquireMutex (ACPI_MTX_TABLES);
544     for (i = 2; i < AcpiGbl_RootTableList.CurrentTableCount; ++i)
545     {
546         if ((!ACPI_COMPARE_NAME (&(AcpiGbl_RootTableList.Tables[i].Signature),
547                     ACPI_SIG_SSDT) &&
548              !ACPI_COMPARE_NAME (&(AcpiGbl_RootTableList.Tables[i].Signature),
549                     ACPI_SIG_PSDT)) ||
550              ACPI_FAILURE (AcpiTbVerifyTable (
551                 &AcpiGbl_RootTableList.Tables[i])))
552         {
553             continue;
554         }
555
556         /* Skip SSDT when DSDT is overriden */
557
558         if (ACPI_COMPARE_NAME (&(AcpiGbl_RootTableList.Tables[i].Signature),
559                     ACPI_SIG_SSDT) &&
560             (AcpiGbl_RootTableList.Tables[ACPI_TABLE_INDEX_DSDT].Flags &
561                     ACPI_TABLE_ORIGIN_OVERRIDE))
562         {
563             continue;
564         }
565
566         /* Ignore errors while loading tables, get as many as possible */
567
568         (void) AcpiUtReleaseMutex (ACPI_MTX_TABLES);
569         (void) AcpiNsLoadTable (i, AcpiGbl_RootNode);
570         (void) AcpiUtAcquireMutex (ACPI_MTX_TABLES);
571     }
572
573     ACPI_DEBUG_PRINT ((ACPI_DB_INIT, "ACPI Tables successfully acquired\n"));
574
575 UnlockAndExit:
576     (void) AcpiUtReleaseMutex (ACPI_MTX_TABLES);
577     return_ACPI_STATUS (Status);
578 }
579
580
581 /*******************************************************************************
582  *
583  * FUNCTION:    AcpiLoadTables
584  *
585  * PARAMETERS:  None
586  *
587  * RETURN:      Status
588  *
589  * DESCRIPTION: Load the ACPI tables from the RSDT/XSDT
590  *
591  ******************************************************************************/
592
593 ACPI_STATUS
594 AcpiLoadTables (
595     void)
596 {
597     ACPI_STATUS             Status;
598
599
600     ACPI_FUNCTION_TRACE (AcpiLoadTables);
601
602
603     /* Load the namespace from the tables */
604
605     Status = AcpiTbLoadNamespace ();
606     if (ACPI_FAILURE (Status))
607     {
608         ACPI_EXCEPTION ((AE_INFO, Status,
609             "While loading namespace from ACPI tables"));
610     }
611
612     return_ACPI_STATUS (Status);
613 }
614
615 ACPI_EXPORT_SYMBOL (AcpiLoadTables)
616
617
618 /*******************************************************************************
619  *
620  * FUNCTION:    AcpiInstallTableHandler
621  *
622  * PARAMETERS:  Handler         - Table event handler
623  *              Context         - Value passed to the handler on each event
624  *
625  * RETURN:      Status
626  *
627  * DESCRIPTION: Install table event handler
628  *
629  ******************************************************************************/
630
631 ACPI_STATUS
632 AcpiInstallTableHandler (
633     ACPI_TABLE_HANDLER      Handler,
634     void                    *Context)
635 {
636     ACPI_STATUS             Status;
637
638
639     ACPI_FUNCTION_TRACE (AcpiInstallTableHandler);
640
641
642     if (!Handler)
643     {
644         return_ACPI_STATUS (AE_BAD_PARAMETER);
645     }
646
647     Status = AcpiUtAcquireMutex (ACPI_MTX_EVENTS);
648     if (ACPI_FAILURE (Status))
649     {
650         return_ACPI_STATUS (Status);
651     }
652
653     /* Don't allow more than one handler */
654
655     if (AcpiGbl_TableHandler)
656     {
657         Status = AE_ALREADY_EXISTS;
658         goto Cleanup;
659     }
660
661     /* Install the handler */
662
663     AcpiGbl_TableHandler = Handler;
664     AcpiGbl_TableHandlerContext = Context;
665
666 Cleanup:
667     (void) AcpiUtReleaseMutex (ACPI_MTX_EVENTS);
668     return_ACPI_STATUS (Status);
669 }
670
671 ACPI_EXPORT_SYMBOL (AcpiInstallTableHandler)
672
673
674 /*******************************************************************************
675  *
676  * FUNCTION:    AcpiRemoveTableHandler
677  *
678  * PARAMETERS:  Handler         - Table event handler that was installed
679  *                                previously.
680  *
681  * RETURN:      Status
682  *
683  * DESCRIPTION: Remove table event handler
684  *
685  ******************************************************************************/
686
687 ACPI_STATUS
688 AcpiRemoveTableHandler (
689     ACPI_TABLE_HANDLER      Handler)
690 {
691     ACPI_STATUS             Status;
692
693
694     ACPI_FUNCTION_TRACE (AcpiRemoveTableHandler);
695
696
697     Status = AcpiUtAcquireMutex (ACPI_MTX_EVENTS);
698     if (ACPI_FAILURE (Status))
699     {
700         return_ACPI_STATUS (Status);
701     }
702
703     /* Make sure that the installed handler is the same */
704
705     if (!Handler ||
706         Handler != AcpiGbl_TableHandler)
707     {
708         Status = AE_BAD_PARAMETER;
709         goto Cleanup;
710     }
711
712     /* Remove the handler */
713
714     AcpiGbl_TableHandler = NULL;
715
716 Cleanup:
717     (void) AcpiUtReleaseMutex (ACPI_MTX_EVENTS);
718     return_ACPI_STATUS (Status);
719 }
720
721 ACPI_EXPORT_SYMBOL (AcpiRemoveTableHandler)
722