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