xref: /freebsd/sys/contrib/dev/acpica/components/events/evhandler.c (revision a9d8d09c46ec699e45f3fd46ca9abcf02e5baca9)
1efcc2a30SJung-uk Kim /******************************************************************************
2efcc2a30SJung-uk Kim  *
3efcc2a30SJung-uk Kim  * Module Name: evhandler - Support for Address Space handlers
4efcc2a30SJung-uk Kim  *
5efcc2a30SJung-uk Kim  *****************************************************************************/
6efcc2a30SJung-uk Kim 
7efcc2a30SJung-uk Kim /*
8efcc2a30SJung-uk Kim  * Copyright (C) 2000 - 2013, Intel Corp.
9efcc2a30SJung-uk Kim  * All rights reserved.
10efcc2a30SJung-uk Kim  *
11efcc2a30SJung-uk Kim  * Redistribution and use in source and binary forms, with or without
12efcc2a30SJung-uk Kim  * modification, are permitted provided that the following conditions
13efcc2a30SJung-uk Kim  * are met:
14efcc2a30SJung-uk Kim  * 1. Redistributions of source code must retain the above copyright
15efcc2a30SJung-uk Kim  *    notice, this list of conditions, and the following disclaimer,
16efcc2a30SJung-uk Kim  *    without modification.
17efcc2a30SJung-uk Kim  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
18efcc2a30SJung-uk Kim  *    substantially similar to the "NO WARRANTY" disclaimer below
19efcc2a30SJung-uk Kim  *    ("Disclaimer") and any redistribution must be conditioned upon
20efcc2a30SJung-uk Kim  *    including a substantially similar Disclaimer requirement for further
21efcc2a30SJung-uk Kim  *    binary redistribution.
22efcc2a30SJung-uk Kim  * 3. Neither the names of the above-listed copyright holders nor the names
23efcc2a30SJung-uk Kim  *    of any contributors may be used to endorse or promote products derived
24efcc2a30SJung-uk Kim  *    from this software without specific prior written permission.
25efcc2a30SJung-uk Kim  *
26efcc2a30SJung-uk Kim  * Alternatively, this software may be distributed under the terms of the
27efcc2a30SJung-uk Kim  * GNU General Public License ("GPL") version 2 as published by the Free
28efcc2a30SJung-uk Kim  * Software Foundation.
29efcc2a30SJung-uk Kim  *
30efcc2a30SJung-uk Kim  * NO WARRANTY
31efcc2a30SJung-uk Kim  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
32efcc2a30SJung-uk Kim  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
33efcc2a30SJung-uk Kim  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
34efcc2a30SJung-uk Kim  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
35efcc2a30SJung-uk Kim  * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36efcc2a30SJung-uk Kim  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37efcc2a30SJung-uk Kim  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38efcc2a30SJung-uk Kim  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39efcc2a30SJung-uk Kim  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
40efcc2a30SJung-uk Kim  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
41efcc2a30SJung-uk Kim  * POSSIBILITY OF SUCH DAMAGES.
42efcc2a30SJung-uk Kim  */
43efcc2a30SJung-uk Kim 
44efcc2a30SJung-uk Kim 
45efcc2a30SJung-uk Kim #define __EVHANDLER_C__
46efcc2a30SJung-uk Kim 
47efcc2a30SJung-uk Kim #include <contrib/dev/acpica/include/acpi.h>
48efcc2a30SJung-uk Kim #include <contrib/dev/acpica/include/accommon.h>
49efcc2a30SJung-uk Kim #include <contrib/dev/acpica/include/acevents.h>
50efcc2a30SJung-uk Kim #include <contrib/dev/acpica/include/acnamesp.h>
51efcc2a30SJung-uk Kim #include <contrib/dev/acpica/include/acinterp.h>
52efcc2a30SJung-uk Kim 
53efcc2a30SJung-uk Kim #define _COMPONENT          ACPI_EVENTS
54efcc2a30SJung-uk Kim         ACPI_MODULE_NAME    ("evhandler")
55efcc2a30SJung-uk Kim 
56efcc2a30SJung-uk Kim 
57efcc2a30SJung-uk Kim /* Local prototypes */
58efcc2a30SJung-uk Kim 
59efcc2a30SJung-uk Kim static ACPI_STATUS
60efcc2a30SJung-uk Kim AcpiEvInstallHandler (
61efcc2a30SJung-uk Kim     ACPI_HANDLE             ObjHandle,
62efcc2a30SJung-uk Kim     UINT32                  Level,
63efcc2a30SJung-uk Kim     void                    *Context,
64efcc2a30SJung-uk Kim     void                    **ReturnValue);
65efcc2a30SJung-uk Kim 
66efcc2a30SJung-uk Kim /* These are the address spaces that will get default handlers */
67efcc2a30SJung-uk Kim 
68efcc2a30SJung-uk Kim UINT8        AcpiGbl_DefaultAddressSpaces[ACPI_NUM_DEFAULT_SPACES] =
69efcc2a30SJung-uk Kim {
70efcc2a30SJung-uk Kim     ACPI_ADR_SPACE_SYSTEM_MEMORY,
71efcc2a30SJung-uk Kim     ACPI_ADR_SPACE_SYSTEM_IO,
72efcc2a30SJung-uk Kim     ACPI_ADR_SPACE_PCI_CONFIG,
73efcc2a30SJung-uk Kim     ACPI_ADR_SPACE_DATA_TABLE
74efcc2a30SJung-uk Kim };
75efcc2a30SJung-uk Kim 
76efcc2a30SJung-uk Kim 
77efcc2a30SJung-uk Kim /*******************************************************************************
78efcc2a30SJung-uk Kim  *
79efcc2a30SJung-uk Kim  * FUNCTION:    AcpiEvInstallRegionHandlers
80efcc2a30SJung-uk Kim  *
81efcc2a30SJung-uk Kim  * PARAMETERS:  None
82efcc2a30SJung-uk Kim  *
83efcc2a30SJung-uk Kim  * RETURN:      Status
84efcc2a30SJung-uk Kim  *
85efcc2a30SJung-uk Kim  * DESCRIPTION: Installs the core subsystem default address space handlers.
86efcc2a30SJung-uk Kim  *
87efcc2a30SJung-uk Kim  ******************************************************************************/
88efcc2a30SJung-uk Kim 
89efcc2a30SJung-uk Kim ACPI_STATUS
90efcc2a30SJung-uk Kim AcpiEvInstallRegionHandlers (
91efcc2a30SJung-uk Kim     void)
92efcc2a30SJung-uk Kim {
93efcc2a30SJung-uk Kim     ACPI_STATUS             Status;
94efcc2a30SJung-uk Kim     UINT32                  i;
95efcc2a30SJung-uk Kim 
96efcc2a30SJung-uk Kim 
97efcc2a30SJung-uk Kim     ACPI_FUNCTION_TRACE (EvInstallRegionHandlers);
98efcc2a30SJung-uk Kim 
99efcc2a30SJung-uk Kim 
100efcc2a30SJung-uk Kim     Status = AcpiUtAcquireMutex (ACPI_MTX_NAMESPACE);
101efcc2a30SJung-uk Kim     if (ACPI_FAILURE (Status))
102efcc2a30SJung-uk Kim     {
103efcc2a30SJung-uk Kim         return_ACPI_STATUS (Status);
104efcc2a30SJung-uk Kim     }
105efcc2a30SJung-uk Kim 
106efcc2a30SJung-uk Kim     /*
107efcc2a30SJung-uk Kim      * All address spaces (PCI Config, EC, SMBus) are scope dependent and
108efcc2a30SJung-uk Kim      * registration must occur for a specific device.
109efcc2a30SJung-uk Kim      *
110efcc2a30SJung-uk Kim      * In the case of the system memory and IO address spaces there is
111efcc2a30SJung-uk Kim      * currently no device associated with the address space. For these we
112efcc2a30SJung-uk Kim      * use the root.
113efcc2a30SJung-uk Kim      *
114efcc2a30SJung-uk Kim      * We install the default PCI config space handler at the root so that
115efcc2a30SJung-uk Kim      * this space is immediately available even though the we have not
116efcc2a30SJung-uk Kim      * enumerated all the PCI Root Buses yet. This is to conform to the ACPI
117efcc2a30SJung-uk Kim      * specification which states that the PCI config space must be always
118efcc2a30SJung-uk Kim      * available -- even though we are nowhere near ready to find the PCI root
119efcc2a30SJung-uk Kim      * buses at this point.
120efcc2a30SJung-uk Kim      *
121efcc2a30SJung-uk Kim      * NOTE: We ignore AE_ALREADY_EXISTS because this means that a handler
122efcc2a30SJung-uk Kim      * has already been installed (via AcpiInstallAddressSpaceHandler).
123efcc2a30SJung-uk Kim      * Similar for AE_SAME_HANDLER.
124efcc2a30SJung-uk Kim      */
125efcc2a30SJung-uk Kim     for (i = 0; i < ACPI_NUM_DEFAULT_SPACES; i++)
126efcc2a30SJung-uk Kim     {
127efcc2a30SJung-uk Kim         Status = AcpiEvInstallSpaceHandler (AcpiGbl_RootNode,
128efcc2a30SJung-uk Kim                     AcpiGbl_DefaultAddressSpaces[i],
129efcc2a30SJung-uk Kim                     ACPI_DEFAULT_HANDLER, NULL, NULL);
130efcc2a30SJung-uk Kim         switch (Status)
131efcc2a30SJung-uk Kim         {
132efcc2a30SJung-uk Kim         case AE_OK:
133efcc2a30SJung-uk Kim         case AE_SAME_HANDLER:
134efcc2a30SJung-uk Kim         case AE_ALREADY_EXISTS:
135efcc2a30SJung-uk Kim 
136efcc2a30SJung-uk Kim             /* These exceptions are all OK */
137efcc2a30SJung-uk Kim 
138efcc2a30SJung-uk Kim             Status = AE_OK;
139efcc2a30SJung-uk Kim             break;
140efcc2a30SJung-uk Kim 
141efcc2a30SJung-uk Kim         default:
142efcc2a30SJung-uk Kim 
143efcc2a30SJung-uk Kim             goto UnlockAndExit;
144efcc2a30SJung-uk Kim         }
145efcc2a30SJung-uk Kim     }
146efcc2a30SJung-uk Kim 
147efcc2a30SJung-uk Kim UnlockAndExit:
148efcc2a30SJung-uk Kim     (void) AcpiUtReleaseMutex (ACPI_MTX_NAMESPACE);
149efcc2a30SJung-uk Kim     return_ACPI_STATUS (Status);
150efcc2a30SJung-uk Kim }
151efcc2a30SJung-uk Kim 
152efcc2a30SJung-uk Kim 
153efcc2a30SJung-uk Kim /*******************************************************************************
154efcc2a30SJung-uk Kim  *
155efcc2a30SJung-uk Kim  * FUNCTION:    AcpiEvHasDefaultHandler
156efcc2a30SJung-uk Kim  *
157efcc2a30SJung-uk Kim  * PARAMETERS:  Node                - Namespace node for the device
158efcc2a30SJung-uk Kim  *              SpaceId             - The address space ID
159efcc2a30SJung-uk Kim  *
160efcc2a30SJung-uk Kim  * RETURN:      TRUE if default handler is installed, FALSE otherwise
161efcc2a30SJung-uk Kim  *
162efcc2a30SJung-uk Kim  * DESCRIPTION: Check if the default handler is installed for the requested
163efcc2a30SJung-uk Kim  *              space ID.
164efcc2a30SJung-uk Kim  *
165efcc2a30SJung-uk Kim  ******************************************************************************/
166efcc2a30SJung-uk Kim 
167efcc2a30SJung-uk Kim BOOLEAN
168efcc2a30SJung-uk Kim AcpiEvHasDefaultHandler (
169efcc2a30SJung-uk Kim     ACPI_NAMESPACE_NODE     *Node,
170efcc2a30SJung-uk Kim     ACPI_ADR_SPACE_TYPE     SpaceId)
171efcc2a30SJung-uk Kim {
172efcc2a30SJung-uk Kim     ACPI_OPERAND_OBJECT     *ObjDesc;
173efcc2a30SJung-uk Kim     ACPI_OPERAND_OBJECT     *HandlerObj;
174efcc2a30SJung-uk Kim 
175efcc2a30SJung-uk Kim 
176efcc2a30SJung-uk Kim     /* Must have an existing internal object */
177efcc2a30SJung-uk Kim 
178efcc2a30SJung-uk Kim     ObjDesc = AcpiNsGetAttachedObject (Node);
179efcc2a30SJung-uk Kim     if (ObjDesc)
180efcc2a30SJung-uk Kim     {
181efcc2a30SJung-uk Kim         HandlerObj = ObjDesc->Device.Handler;
182efcc2a30SJung-uk Kim 
183efcc2a30SJung-uk Kim         /* Walk the linked list of handlers for this object */
184efcc2a30SJung-uk Kim 
185efcc2a30SJung-uk Kim         while (HandlerObj)
186efcc2a30SJung-uk Kim         {
187efcc2a30SJung-uk Kim             if (HandlerObj->AddressSpace.SpaceId == SpaceId)
188efcc2a30SJung-uk Kim             {
189efcc2a30SJung-uk Kim                 if (HandlerObj->AddressSpace.HandlerFlags &
190efcc2a30SJung-uk Kim                         ACPI_ADDR_HANDLER_DEFAULT_INSTALLED)
191efcc2a30SJung-uk Kim                 {
192efcc2a30SJung-uk Kim                     return (TRUE);
193efcc2a30SJung-uk Kim                 }
194efcc2a30SJung-uk Kim             }
195efcc2a30SJung-uk Kim 
196efcc2a30SJung-uk Kim             HandlerObj = HandlerObj->AddressSpace.Next;
197efcc2a30SJung-uk Kim         }
198efcc2a30SJung-uk Kim     }
199efcc2a30SJung-uk Kim 
200efcc2a30SJung-uk Kim     return (FALSE);
201efcc2a30SJung-uk Kim }
202efcc2a30SJung-uk Kim 
203efcc2a30SJung-uk Kim 
204efcc2a30SJung-uk Kim /*******************************************************************************
205efcc2a30SJung-uk Kim  *
206efcc2a30SJung-uk Kim  * FUNCTION:    AcpiEvInstallHandler
207efcc2a30SJung-uk Kim  *
208efcc2a30SJung-uk Kim  * PARAMETERS:  WalkNamespace callback
209efcc2a30SJung-uk Kim  *
210efcc2a30SJung-uk Kim  * DESCRIPTION: This routine installs an address handler into objects that are
211efcc2a30SJung-uk Kim  *              of type Region or Device.
212efcc2a30SJung-uk Kim  *
213efcc2a30SJung-uk Kim  *              If the Object is a Device, and the device has a handler of
214efcc2a30SJung-uk Kim  *              the same type then the search is terminated in that branch.
215efcc2a30SJung-uk Kim  *
216efcc2a30SJung-uk Kim  *              This is because the existing handler is closer in proximity
217efcc2a30SJung-uk Kim  *              to any more regions than the one we are trying to install.
218efcc2a30SJung-uk Kim  *
219efcc2a30SJung-uk Kim  ******************************************************************************/
220efcc2a30SJung-uk Kim 
221efcc2a30SJung-uk Kim static ACPI_STATUS
222efcc2a30SJung-uk Kim AcpiEvInstallHandler (
223efcc2a30SJung-uk Kim     ACPI_HANDLE             ObjHandle,
224efcc2a30SJung-uk Kim     UINT32                  Level,
225efcc2a30SJung-uk Kim     void                    *Context,
226efcc2a30SJung-uk Kim     void                    **ReturnValue)
227efcc2a30SJung-uk Kim {
228efcc2a30SJung-uk Kim     ACPI_OPERAND_OBJECT     *HandlerObj;
229efcc2a30SJung-uk Kim     ACPI_OPERAND_OBJECT     *NextHandlerObj;
230efcc2a30SJung-uk Kim     ACPI_OPERAND_OBJECT     *ObjDesc;
231efcc2a30SJung-uk Kim     ACPI_NAMESPACE_NODE     *Node;
232efcc2a30SJung-uk Kim     ACPI_STATUS             Status;
233efcc2a30SJung-uk Kim 
234efcc2a30SJung-uk Kim 
235efcc2a30SJung-uk Kim     ACPI_FUNCTION_NAME (EvInstallHandler);
236efcc2a30SJung-uk Kim 
237efcc2a30SJung-uk Kim 
238efcc2a30SJung-uk Kim     HandlerObj = (ACPI_OPERAND_OBJECT  *) Context;
239efcc2a30SJung-uk Kim 
240efcc2a30SJung-uk Kim     /* Parameter validation */
241efcc2a30SJung-uk Kim 
242efcc2a30SJung-uk Kim     if (!HandlerObj)
243efcc2a30SJung-uk Kim     {
244efcc2a30SJung-uk Kim         return (AE_OK);
245efcc2a30SJung-uk Kim     }
246efcc2a30SJung-uk Kim 
247efcc2a30SJung-uk Kim     /* Convert and validate the device handle */
248efcc2a30SJung-uk Kim 
249efcc2a30SJung-uk Kim     Node = AcpiNsValidateHandle (ObjHandle);
250efcc2a30SJung-uk Kim     if (!Node)
251efcc2a30SJung-uk Kim     {
252efcc2a30SJung-uk Kim         return (AE_BAD_PARAMETER);
253efcc2a30SJung-uk Kim     }
254efcc2a30SJung-uk Kim 
255efcc2a30SJung-uk Kim     /*
256efcc2a30SJung-uk Kim      * We only care about regions and objects that are allowed to have
257efcc2a30SJung-uk Kim      * address space handlers
258efcc2a30SJung-uk Kim      */
259efcc2a30SJung-uk Kim     if ((Node->Type != ACPI_TYPE_DEVICE) &&
260efcc2a30SJung-uk Kim         (Node->Type != ACPI_TYPE_REGION) &&
261efcc2a30SJung-uk Kim         (Node != AcpiGbl_RootNode))
262efcc2a30SJung-uk Kim     {
263efcc2a30SJung-uk Kim         return (AE_OK);
264efcc2a30SJung-uk Kim     }
265efcc2a30SJung-uk Kim 
266efcc2a30SJung-uk Kim     /* Check for an existing internal object */
267efcc2a30SJung-uk Kim 
268efcc2a30SJung-uk Kim     ObjDesc = AcpiNsGetAttachedObject (Node);
269efcc2a30SJung-uk Kim     if (!ObjDesc)
270efcc2a30SJung-uk Kim     {
271efcc2a30SJung-uk Kim         /* No object, just exit */
272efcc2a30SJung-uk Kim 
273efcc2a30SJung-uk Kim         return (AE_OK);
274efcc2a30SJung-uk Kim     }
275efcc2a30SJung-uk Kim 
276efcc2a30SJung-uk Kim     /* Devices are handled different than regions */
277efcc2a30SJung-uk Kim 
278efcc2a30SJung-uk Kim     if (ObjDesc->Common.Type == ACPI_TYPE_DEVICE)
279efcc2a30SJung-uk Kim     {
280efcc2a30SJung-uk Kim         /* Check if this Device already has a handler for this address space */
281efcc2a30SJung-uk Kim 
282efcc2a30SJung-uk Kim         NextHandlerObj = ObjDesc->Device.Handler;
283efcc2a30SJung-uk Kim         while (NextHandlerObj)
284efcc2a30SJung-uk Kim         {
285efcc2a30SJung-uk Kim             /* Found a handler, is it for the same address space? */
286efcc2a30SJung-uk Kim 
287efcc2a30SJung-uk Kim             if (NextHandlerObj->AddressSpace.SpaceId ==
288efcc2a30SJung-uk Kim                     HandlerObj->AddressSpace.SpaceId)
289efcc2a30SJung-uk Kim             {
290efcc2a30SJung-uk Kim                 ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION,
291efcc2a30SJung-uk Kim                     "Found handler for region [%s] in device %p(%p) "
292efcc2a30SJung-uk Kim                     "handler %p\n",
293efcc2a30SJung-uk Kim                     AcpiUtGetRegionName (HandlerObj->AddressSpace.SpaceId),
294efcc2a30SJung-uk Kim                     ObjDesc, NextHandlerObj, HandlerObj));
295efcc2a30SJung-uk Kim 
296efcc2a30SJung-uk Kim                 /*
297efcc2a30SJung-uk Kim                  * Since the object we found it on was a device, then it
298efcc2a30SJung-uk Kim                  * means that someone has already installed a handler for
299efcc2a30SJung-uk Kim                  * the branch of the namespace from this device on. Just
300efcc2a30SJung-uk Kim                  * bail out telling the walk routine to not traverse this
301efcc2a30SJung-uk Kim                  * branch. This preserves the scoping rule for handlers.
302efcc2a30SJung-uk Kim                  */
303efcc2a30SJung-uk Kim                 return (AE_CTRL_DEPTH);
304efcc2a30SJung-uk Kim             }
305efcc2a30SJung-uk Kim 
306efcc2a30SJung-uk Kim             /* Walk the linked list of handlers attached to this device */
307efcc2a30SJung-uk Kim 
308efcc2a30SJung-uk Kim             NextHandlerObj = NextHandlerObj->AddressSpace.Next;
309efcc2a30SJung-uk Kim         }
310efcc2a30SJung-uk Kim 
311efcc2a30SJung-uk Kim         /*
312efcc2a30SJung-uk Kim          * As long as the device didn't have a handler for this space we
313efcc2a30SJung-uk Kim          * don't care about it. We just ignore it and proceed.
314efcc2a30SJung-uk Kim          */
315efcc2a30SJung-uk Kim         return (AE_OK);
316efcc2a30SJung-uk Kim     }
317efcc2a30SJung-uk Kim 
318efcc2a30SJung-uk Kim     /* Object is a Region */
319efcc2a30SJung-uk Kim 
320efcc2a30SJung-uk Kim     if (ObjDesc->Region.SpaceId != HandlerObj->AddressSpace.SpaceId)
321efcc2a30SJung-uk Kim     {
322efcc2a30SJung-uk Kim         /* This region is for a different address space, just ignore it */
323efcc2a30SJung-uk Kim 
324efcc2a30SJung-uk Kim         return (AE_OK);
325efcc2a30SJung-uk Kim     }
326efcc2a30SJung-uk Kim 
327efcc2a30SJung-uk Kim     /*
328efcc2a30SJung-uk Kim      * Now we have a region and it is for the handler's address space type.
329efcc2a30SJung-uk Kim      *
330efcc2a30SJung-uk Kim      * First disconnect region for any previous handler (if any)
331efcc2a30SJung-uk Kim      */
332efcc2a30SJung-uk Kim     AcpiEvDetachRegion (ObjDesc, FALSE);
333efcc2a30SJung-uk Kim 
334efcc2a30SJung-uk Kim     /* Connect the region to the new handler */
335efcc2a30SJung-uk Kim 
336efcc2a30SJung-uk Kim     Status = AcpiEvAttachRegion (HandlerObj, ObjDesc, FALSE);
337efcc2a30SJung-uk Kim     return (Status);
338efcc2a30SJung-uk Kim }
339efcc2a30SJung-uk Kim 
340efcc2a30SJung-uk Kim 
341efcc2a30SJung-uk Kim /*******************************************************************************
342efcc2a30SJung-uk Kim  *
343efcc2a30SJung-uk Kim  * FUNCTION:    AcpiEvInstallSpaceHandler
344efcc2a30SJung-uk Kim  *
345efcc2a30SJung-uk Kim  * PARAMETERS:  Node            - Namespace node for the device
346efcc2a30SJung-uk Kim  *              SpaceId         - The address space ID
347efcc2a30SJung-uk Kim  *              Handler         - Address of the handler
348efcc2a30SJung-uk Kim  *              Setup           - Address of the setup function
349efcc2a30SJung-uk Kim  *              Context         - Value passed to the handler on each access
350efcc2a30SJung-uk Kim  *
351efcc2a30SJung-uk Kim  * RETURN:      Status
352efcc2a30SJung-uk Kim  *
353efcc2a30SJung-uk Kim  * DESCRIPTION: Install a handler for all OpRegions of a given SpaceId.
354efcc2a30SJung-uk Kim  *              Assumes namespace is locked
355efcc2a30SJung-uk Kim  *
356efcc2a30SJung-uk Kim  ******************************************************************************/
357efcc2a30SJung-uk Kim 
358efcc2a30SJung-uk Kim ACPI_STATUS
359efcc2a30SJung-uk Kim AcpiEvInstallSpaceHandler (
360efcc2a30SJung-uk Kim     ACPI_NAMESPACE_NODE     *Node,
361efcc2a30SJung-uk Kim     ACPI_ADR_SPACE_TYPE     SpaceId,
362efcc2a30SJung-uk Kim     ACPI_ADR_SPACE_HANDLER  Handler,
363efcc2a30SJung-uk Kim     ACPI_ADR_SPACE_SETUP    Setup,
364efcc2a30SJung-uk Kim     void                    *Context)
365efcc2a30SJung-uk Kim {
366efcc2a30SJung-uk Kim     ACPI_OPERAND_OBJECT     *ObjDesc;
367efcc2a30SJung-uk Kim     ACPI_OPERAND_OBJECT     *HandlerObj;
368efcc2a30SJung-uk Kim     ACPI_STATUS             Status;
369efcc2a30SJung-uk Kim     ACPI_OBJECT_TYPE        Type;
370efcc2a30SJung-uk Kim     UINT8                  Flags = 0;
371efcc2a30SJung-uk Kim 
372efcc2a30SJung-uk Kim 
373efcc2a30SJung-uk Kim     ACPI_FUNCTION_TRACE (EvInstallSpaceHandler);
374efcc2a30SJung-uk Kim 
375efcc2a30SJung-uk Kim 
376efcc2a30SJung-uk Kim     /*
377efcc2a30SJung-uk Kim      * This registration is valid for only the types below and the root. This
378efcc2a30SJung-uk Kim      * is where the default handlers get placed.
379efcc2a30SJung-uk Kim      */
380efcc2a30SJung-uk Kim     if ((Node->Type != ACPI_TYPE_DEVICE)     &&
381efcc2a30SJung-uk Kim         (Node->Type != ACPI_TYPE_PROCESSOR)  &&
382efcc2a30SJung-uk Kim         (Node->Type != ACPI_TYPE_THERMAL)    &&
383efcc2a30SJung-uk Kim         (Node != AcpiGbl_RootNode))
384efcc2a30SJung-uk Kim     {
385efcc2a30SJung-uk Kim         Status = AE_BAD_PARAMETER;
386efcc2a30SJung-uk Kim         goto UnlockAndExit;
387efcc2a30SJung-uk Kim     }
388efcc2a30SJung-uk Kim 
389efcc2a30SJung-uk Kim     if (Handler == ACPI_DEFAULT_HANDLER)
390efcc2a30SJung-uk Kim     {
391efcc2a30SJung-uk Kim         Flags = ACPI_ADDR_HANDLER_DEFAULT_INSTALLED;
392efcc2a30SJung-uk Kim 
393efcc2a30SJung-uk Kim         switch (SpaceId)
394efcc2a30SJung-uk Kim         {
395efcc2a30SJung-uk Kim         case ACPI_ADR_SPACE_SYSTEM_MEMORY:
396*a9d8d09cSJung-uk Kim 
397efcc2a30SJung-uk Kim             Handler = AcpiExSystemMemorySpaceHandler;
398efcc2a30SJung-uk Kim             Setup   = AcpiEvSystemMemoryRegionSetup;
399efcc2a30SJung-uk Kim             break;
400efcc2a30SJung-uk Kim 
401efcc2a30SJung-uk Kim         case ACPI_ADR_SPACE_SYSTEM_IO:
402*a9d8d09cSJung-uk Kim 
403efcc2a30SJung-uk Kim             Handler = AcpiExSystemIoSpaceHandler;
404efcc2a30SJung-uk Kim             Setup   = AcpiEvIoSpaceRegionSetup;
405efcc2a30SJung-uk Kim             break;
406efcc2a30SJung-uk Kim 
407efcc2a30SJung-uk Kim         case ACPI_ADR_SPACE_PCI_CONFIG:
408*a9d8d09cSJung-uk Kim 
409efcc2a30SJung-uk Kim             Handler = AcpiExPciConfigSpaceHandler;
410efcc2a30SJung-uk Kim             Setup   = AcpiEvPciConfigRegionSetup;
411efcc2a30SJung-uk Kim             break;
412efcc2a30SJung-uk Kim 
413efcc2a30SJung-uk Kim         case ACPI_ADR_SPACE_CMOS:
414*a9d8d09cSJung-uk Kim 
415efcc2a30SJung-uk Kim             Handler = AcpiExCmosSpaceHandler;
416efcc2a30SJung-uk Kim             Setup   = AcpiEvCmosRegionSetup;
417efcc2a30SJung-uk Kim             break;
418efcc2a30SJung-uk Kim 
419efcc2a30SJung-uk Kim         case ACPI_ADR_SPACE_PCI_BAR_TARGET:
420*a9d8d09cSJung-uk Kim 
421efcc2a30SJung-uk Kim             Handler = AcpiExPciBarSpaceHandler;
422efcc2a30SJung-uk Kim             Setup   = AcpiEvPciBarRegionSetup;
423efcc2a30SJung-uk Kim             break;
424efcc2a30SJung-uk Kim 
425efcc2a30SJung-uk Kim         case ACPI_ADR_SPACE_DATA_TABLE:
426*a9d8d09cSJung-uk Kim 
427efcc2a30SJung-uk Kim             Handler = AcpiExDataTableSpaceHandler;
428efcc2a30SJung-uk Kim             Setup   = NULL;
429efcc2a30SJung-uk Kim             break;
430efcc2a30SJung-uk Kim 
431efcc2a30SJung-uk Kim         default:
432*a9d8d09cSJung-uk Kim 
433efcc2a30SJung-uk Kim             Status = AE_BAD_PARAMETER;
434efcc2a30SJung-uk Kim             goto UnlockAndExit;
435efcc2a30SJung-uk Kim         }
436efcc2a30SJung-uk Kim     }
437efcc2a30SJung-uk Kim 
438efcc2a30SJung-uk Kim     /* If the caller hasn't specified a setup routine, use the default */
439efcc2a30SJung-uk Kim 
440efcc2a30SJung-uk Kim     if (!Setup)
441efcc2a30SJung-uk Kim     {
442efcc2a30SJung-uk Kim         Setup = AcpiEvDefaultRegionSetup;
443efcc2a30SJung-uk Kim     }
444efcc2a30SJung-uk Kim 
445efcc2a30SJung-uk Kim     /* Check for an existing internal object */
446efcc2a30SJung-uk Kim 
447efcc2a30SJung-uk Kim     ObjDesc = AcpiNsGetAttachedObject (Node);
448efcc2a30SJung-uk Kim     if (ObjDesc)
449efcc2a30SJung-uk Kim     {
450efcc2a30SJung-uk Kim         /*
451efcc2a30SJung-uk Kim          * The attached device object already exists. Make sure the handler
452efcc2a30SJung-uk Kim          * is not already installed.
453efcc2a30SJung-uk Kim          */
454efcc2a30SJung-uk Kim         HandlerObj = ObjDesc->Device.Handler;
455efcc2a30SJung-uk Kim 
456efcc2a30SJung-uk Kim         /* Walk the handler list for this device */
457efcc2a30SJung-uk Kim 
458efcc2a30SJung-uk Kim         while (HandlerObj)
459efcc2a30SJung-uk Kim         {
460efcc2a30SJung-uk Kim             /* Same SpaceId indicates a handler already installed */
461efcc2a30SJung-uk Kim 
462efcc2a30SJung-uk Kim             if (HandlerObj->AddressSpace.SpaceId == SpaceId)
463efcc2a30SJung-uk Kim             {
464efcc2a30SJung-uk Kim                 if (HandlerObj->AddressSpace.Handler == Handler)
465efcc2a30SJung-uk Kim                 {
466efcc2a30SJung-uk Kim                     /*
467efcc2a30SJung-uk Kim                      * It is (relatively) OK to attempt to install the SAME
468efcc2a30SJung-uk Kim                      * handler twice. This can easily happen with the
469efcc2a30SJung-uk Kim                      * PCI_Config space.
470efcc2a30SJung-uk Kim                      */
471efcc2a30SJung-uk Kim                     Status = AE_SAME_HANDLER;
472efcc2a30SJung-uk Kim                     goto UnlockAndExit;
473efcc2a30SJung-uk Kim                 }
474efcc2a30SJung-uk Kim                 else
475efcc2a30SJung-uk Kim                 {
476efcc2a30SJung-uk Kim                     /* A handler is already installed */
477efcc2a30SJung-uk Kim 
478efcc2a30SJung-uk Kim                     Status = AE_ALREADY_EXISTS;
479efcc2a30SJung-uk Kim                 }
480efcc2a30SJung-uk Kim                 goto UnlockAndExit;
481efcc2a30SJung-uk Kim             }
482efcc2a30SJung-uk Kim 
483efcc2a30SJung-uk Kim             /* Walk the linked list of handlers */
484efcc2a30SJung-uk Kim 
485efcc2a30SJung-uk Kim             HandlerObj = HandlerObj->AddressSpace.Next;
486efcc2a30SJung-uk Kim         }
487efcc2a30SJung-uk Kim     }
488efcc2a30SJung-uk Kim     else
489efcc2a30SJung-uk Kim     {
490efcc2a30SJung-uk Kim         ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION,
491efcc2a30SJung-uk Kim             "Creating object on Device %p while installing handler\n", Node));
492efcc2a30SJung-uk Kim 
493efcc2a30SJung-uk Kim         /* ObjDesc does not exist, create one */
494efcc2a30SJung-uk Kim 
495efcc2a30SJung-uk Kim         if (Node->Type == ACPI_TYPE_ANY)
496efcc2a30SJung-uk Kim         {
497efcc2a30SJung-uk Kim             Type = ACPI_TYPE_DEVICE;
498efcc2a30SJung-uk Kim         }
499efcc2a30SJung-uk Kim         else
500efcc2a30SJung-uk Kim         {
501efcc2a30SJung-uk Kim             Type = Node->Type;
502efcc2a30SJung-uk Kim         }
503efcc2a30SJung-uk Kim 
504efcc2a30SJung-uk Kim         ObjDesc = AcpiUtCreateInternalObject (Type);
505efcc2a30SJung-uk Kim         if (!ObjDesc)
506efcc2a30SJung-uk Kim         {
507efcc2a30SJung-uk Kim             Status = AE_NO_MEMORY;
508efcc2a30SJung-uk Kim             goto UnlockAndExit;
509efcc2a30SJung-uk Kim         }
510efcc2a30SJung-uk Kim 
511efcc2a30SJung-uk Kim         /* Init new descriptor */
512efcc2a30SJung-uk Kim 
513efcc2a30SJung-uk Kim         ObjDesc->Common.Type = (UINT8) Type;
514efcc2a30SJung-uk Kim 
515efcc2a30SJung-uk Kim         /* Attach the new object to the Node */
516efcc2a30SJung-uk Kim 
517efcc2a30SJung-uk Kim         Status = AcpiNsAttachObject (Node, ObjDesc, Type);
518efcc2a30SJung-uk Kim 
519efcc2a30SJung-uk Kim         /* Remove local reference to the object */
520efcc2a30SJung-uk Kim 
521efcc2a30SJung-uk Kim         AcpiUtRemoveReference (ObjDesc);
522efcc2a30SJung-uk Kim 
523efcc2a30SJung-uk Kim         if (ACPI_FAILURE (Status))
524efcc2a30SJung-uk Kim         {
525efcc2a30SJung-uk Kim             goto UnlockAndExit;
526efcc2a30SJung-uk Kim         }
527efcc2a30SJung-uk Kim     }
528efcc2a30SJung-uk Kim 
529efcc2a30SJung-uk Kim     ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION,
530efcc2a30SJung-uk Kim         "Installing address handler for region %s(%X) on Device %4.4s %p(%p)\n",
531efcc2a30SJung-uk Kim         AcpiUtGetRegionName (SpaceId), SpaceId,
532efcc2a30SJung-uk Kim         AcpiUtGetNodeName (Node), Node, ObjDesc));
533efcc2a30SJung-uk Kim 
534efcc2a30SJung-uk Kim     /*
535efcc2a30SJung-uk Kim      * Install the handler
536efcc2a30SJung-uk Kim      *
537efcc2a30SJung-uk Kim      * At this point there is no existing handler. Just allocate the object
538efcc2a30SJung-uk Kim      * for the handler and link it into the list.
539efcc2a30SJung-uk Kim      */
540efcc2a30SJung-uk Kim     HandlerObj = AcpiUtCreateInternalObject (ACPI_TYPE_LOCAL_ADDRESS_HANDLER);
541efcc2a30SJung-uk Kim     if (!HandlerObj)
542efcc2a30SJung-uk Kim     {
543efcc2a30SJung-uk Kim         Status = AE_NO_MEMORY;
544efcc2a30SJung-uk Kim         goto UnlockAndExit;
545efcc2a30SJung-uk Kim     }
546efcc2a30SJung-uk Kim 
547efcc2a30SJung-uk Kim     /* Init handler obj */
548efcc2a30SJung-uk Kim 
549efcc2a30SJung-uk Kim     HandlerObj->AddressSpace.SpaceId = (UINT8) SpaceId;
550efcc2a30SJung-uk Kim     HandlerObj->AddressSpace.HandlerFlags = Flags;
551efcc2a30SJung-uk Kim     HandlerObj->AddressSpace.RegionList = NULL;
552efcc2a30SJung-uk Kim     HandlerObj->AddressSpace.Node = Node;
553efcc2a30SJung-uk Kim     HandlerObj->AddressSpace.Handler = Handler;
554efcc2a30SJung-uk Kim     HandlerObj->AddressSpace.Context = Context;
555efcc2a30SJung-uk Kim     HandlerObj->AddressSpace.Setup  = Setup;
556efcc2a30SJung-uk Kim 
557efcc2a30SJung-uk Kim     /* Install at head of Device.AddressSpace list */
558efcc2a30SJung-uk Kim 
559efcc2a30SJung-uk Kim     HandlerObj->AddressSpace.Next = ObjDesc->Device.Handler;
560efcc2a30SJung-uk Kim 
561efcc2a30SJung-uk Kim     /*
562efcc2a30SJung-uk Kim      * The Device object is the first reference on the HandlerObj.
563efcc2a30SJung-uk Kim      * Each region that uses the handler adds a reference.
564efcc2a30SJung-uk Kim      */
565efcc2a30SJung-uk Kim     ObjDesc->Device.Handler = HandlerObj;
566efcc2a30SJung-uk Kim 
567efcc2a30SJung-uk Kim     /*
568efcc2a30SJung-uk Kim      * Walk the namespace finding all of the regions this
569efcc2a30SJung-uk Kim      * handler will manage.
570efcc2a30SJung-uk Kim      *
571efcc2a30SJung-uk Kim      * Start at the device and search the branch toward
572efcc2a30SJung-uk Kim      * the leaf nodes until either the leaf is encountered or
573efcc2a30SJung-uk Kim      * a device is detected that has an address handler of the
574efcc2a30SJung-uk Kim      * same type.
575efcc2a30SJung-uk Kim      *
576efcc2a30SJung-uk Kim      * In either case, back up and search down the remainder
577efcc2a30SJung-uk Kim      * of the branch
578efcc2a30SJung-uk Kim      */
579efcc2a30SJung-uk Kim     Status = AcpiNsWalkNamespace (ACPI_TYPE_ANY, Node, ACPI_UINT32_MAX,
580efcc2a30SJung-uk Kim                 ACPI_NS_WALK_UNLOCK, AcpiEvInstallHandler, NULL,
581efcc2a30SJung-uk Kim                 HandlerObj, NULL);
582efcc2a30SJung-uk Kim 
583efcc2a30SJung-uk Kim UnlockAndExit:
584efcc2a30SJung-uk Kim     return_ACPI_STATUS (Status);
585efcc2a30SJung-uk Kim }
586