acpi_resource.c revision 78993
1/*-
2 * Copyright (c) 2000 Michael Smith
3 * Copyright (c) 2000 BSDi
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 *	$FreeBSD: head/sys/dev/acpica/acpi_resource.c 78993 2001-06-29 20:32:29Z msmith $
28 */
29
30#include "opt_acpi.h"
31#include <sys/param.h>
32#include <sys/kernel.h>
33#include <sys/bus.h>
34#include <machine/bus.h>
35#include <machine/resource.h>
36
37#include "acpi.h"
38
39#include <dev/acpica/acpivar.h>
40
41/*
42 * Hooks for the ACPI CA debugging infrastructure
43 */
44#define _COMPONENT	ACPI_BUS
45MODULE_NAME("RESOURCE")
46
47/*
48 * Fetch a device's resources and associate them with the device.
49 *
50 * Note that it might be nice to also locate ACPI-specific resource items, such
51 * as GPE bits.
52 */
53ACPI_STATUS
54acpi_parse_resources(device_t dev, ACPI_HANDLE handle, struct acpi_parse_resource_set *set)
55{
56    ACPI_BUFFER		buf;
57    ACPI_RESOURCE	*res;
58    char		*curr, *last;
59    ACPI_STATUS		status;
60    int			i;
61    void		*context;
62
63    FUNCTION_TRACE(__func__);
64
65    /*
66     * Fetch the device resources
67     */
68    if (((status = acpi_GetIntoBuffer(handle, AcpiGetPossibleResources, &buf)) != AE_OK) &&
69	((status = acpi_GetIntoBuffer(handle, AcpiGetCurrentResources, &buf)) != AE_OK)) {
70	device_printf(dev, "can't fetch ACPI resources - %s\n", acpi_strerror(status));
71	return_ACPI_STATUS(status);
72    }
73    DEBUG_PRINT(TRACE_RESOURCES, ("got %d bytes of resources\n", buf.Length));
74    set->set_init(dev, &context);
75
76    /*
77     * Iterate through the resources
78     */
79    curr = buf.Pointer;
80    last = (char *)buf.Pointer + buf.Length;
81    while (curr < last) {
82	res = (ACPI_RESOURCE *)curr;
83	curr += res->Length;
84
85	/*
86	 * Handle the individual resource types
87	 */
88	switch(res->Id) {
89	case ACPI_RSTYPE_END_TAG:
90	    DEBUG_PRINT(TRACE_RESOURCES, ("EndTag\n"));
91	    curr = last;
92	    break;
93
94	case ACPI_RSTYPE_FIXED_IO:
95	    DEBUG_PRINT(TRACE_RESOURCES, ("FixedIo 0x%x/%d\n", res->Data.FixedIo.BaseAddress, res->Data.FixedIo.RangeLength));
96	    set->set_ioport(dev, context, res->Data.FixedIo.BaseAddress, res->Data.FixedIo.RangeLength);
97	    break;
98
99	case ACPI_RSTYPE_IO:
100	    if (res->Data.Io.MinBaseAddress == res->Data.Io.MaxBaseAddress) {
101		DEBUG_PRINT(TRACE_RESOURCES, ("Io 0x%x/%d\n", res->Data.Io.MinBaseAddress, res->Data.Io.RangeLength));
102		set->set_ioport(dev, context, res->Data.Io.MinBaseAddress, res->Data.Io.RangeLength);
103	    } else {
104		DEBUG_PRINT(TRACE_RESOURCES, ("Io 0x%x-0x%x/%d\n", res->Data.Io.MinBaseAddress, res->Data.Io.MaxBaseAddress,
105					      res->Data.Io.RangeLength));
106		set->set_iorange(dev, context, res->Data.Io.MinBaseAddress, res->Data.Io.MaxBaseAddress,
107				 res->Data.Io.RangeLength, res->Data.Io.Alignment);
108	    }
109	    break;
110
111	case ACPI_RSTYPE_FIXED_MEM32:
112	    DEBUG_PRINT(TRACE_RESOURCES, ("FixedMemory32 0x%x/%d\n", res->Data.FixedMemory32.RangeBaseAddress,
113					  res->Data.FixedMemory32.RangeLength));
114	    set->set_memory(dev, context, res->Data.FixedMemory32.RangeBaseAddress,
115			    res->Data.FixedMemory32.RangeLength);
116	    break;
117
118	case ACPI_RSTYPE_MEM32:
119	    if (res->Data.Memory32.MinBaseAddress == res->Data.Memory32.MaxBaseAddress) {
120		DEBUG_PRINT(TRACE_RESOURCES, ("Memory32 0x%x/%d\n", res->Data.Memory32.MinBaseAddress,
121					      res->Data.Memory32.RangeLength));
122		set->set_memory(dev, context, res->Data.Memory32.MinBaseAddress, res->Data.Memory32.RangeLength);
123	    } else {
124		DEBUG_PRINT(TRACE_RESOURCES, ("Memory32 0x%x-0x%x/%d\n", res->Data.Memory32.MinBaseAddress,
125					      res->Data.Memory32.MaxBaseAddress, res->Data.Memory32.RangeLength));
126		set->set_memoryrange(dev, context, res->Data.Memory32.MinBaseAddress, res->Data.Memory32.MaxBaseAddress,
127				     res->Data.Memory32.RangeLength, res->Data.Memory32.Alignment);
128	    }
129	    break;
130
131	case ACPI_RSTYPE_MEM24:
132	    if (res->Data.Memory24.MinBaseAddress == res->Data.Memory24.MaxBaseAddress) {
133		DEBUG_PRINT(TRACE_RESOURCES, ("Memory24 0x%x/%d\n", res->Data.Memory24.MinBaseAddress,
134					      res->Data.Memory24.RangeLength));
135		set->set_memory(dev, context, res->Data.Memory24.MinBaseAddress, res->Data.Memory24.RangeLength);
136	    } else {
137		DEBUG_PRINT(TRACE_RESOURCES, ("Memory24 0x%x-0x%x/%d\n", res->Data.Memory24.MinBaseAddress,
138					      res->Data.Memory24.MaxBaseAddress, res->Data.Memory24.RangeLength));
139		set->set_memoryrange(dev, context, res->Data.Memory24.MinBaseAddress, res->Data.Memory24.MaxBaseAddress,
140				     res->Data.Memory24.RangeLength, res->Data.Memory24.Alignment);
141	    }
142	    break;
143
144	case ACPI_RSTYPE_IRQ:
145	    for (i = 0; i < res->Data.Irq.NumberOfInterrupts; i++) {
146		DEBUG_PRINT(TRACE_RESOURCES, ("Irq %d\n", res->Data.Irq.Interrupts[i]));
147		set->set_irq(dev, context, res->Data.Irq.Interrupts[i]);
148	    }
149	    break;
150
151	case ACPI_RSTYPE_DMA:
152	    for (i = 0; i < res->Data.Dma.NumberOfChannels; i++) {
153		DEBUG_PRINT(TRACE_RESOURCES, ("Drq %d\n", res->Data.Dma.Channels[i]));
154		set->set_drq(dev, context, res->Data.Dma.Channels[i]);
155	    }
156	    break;
157
158	case ACPI_RSTYPE_START_DPF:
159	    DEBUG_PRINT(TRACE_RESOURCES, ("start dependant functions"));
160	    set->set_start_dependant(dev, context, res->Data.StartDpf.CompatibilityPriority);
161	    break;
162
163	case ACPI_RSTYPE_END_DPF:
164	    DEBUG_PRINT(TRACE_RESOURCES, ("end dependant functions"));
165	    set->set_end_dependant(dev, context);
166	    break;
167
168	case ACPI_RSTYPE_ADDRESS32:
169	    DEBUG_PRINT(TRACE_RESOURCES, ("unimplemented Address32 resource\n"));
170	    break;
171
172	case ACPI_RSTYPE_ADDRESS16:
173	    DEBUG_PRINT(TRACE_RESOURCES, ("unimplemented Address16 resource\n"));
174	    break;
175
176	case ACPI_RSTYPE_EXT_IRQ:
177	    DEBUG_PRINT(TRACE_RESOURCES, ("unimplemented ExtendedIrq resource\n"));
178	    break;
179
180	case ACPI_RSTYPE_VENDOR:
181	    DEBUG_PRINT(TRACE_RESOURCES, ("unimplemented VendorSpecific resource\n"));
182	    break;
183	default:
184	    break;
185	}
186    }
187    AcpiOsFree(buf.Pointer);
188    set->set_done(dev, context);
189    return_ACPI_STATUS(AE_OK);
190}
191
192static void	acpi_res_set_init(device_t dev, void **context);
193static void	acpi_res_set_done(device_t dev, void *context);
194static void	acpi_res_set_ioport(device_t dev, void *context, u_int32_t base, u_int32_t length);
195static void	acpi_res_set_iorange(device_t dev, void *context, u_int32_t low, u_int32_t high,
196				     u_int32_t length, u_int32_t align);
197static void	acpi_res_set_memory(device_t dev, void *context, u_int32_t base, u_int32_t length);
198static void	acpi_res_set_memoryrange(device_t dev, void *context, u_int32_t low, u_int32_t high,
199					 u_int32_t length, u_int32_t align);
200static void	acpi_res_set_irq(device_t dev, void *context, u_int32_t irq);
201static void	acpi_res_set_drq(device_t dev, void *context, u_int32_t drq);
202static void	acpi_res_set_start_dependant(device_t dev, void *context, int preference);
203static void	acpi_res_set_end_dependant(device_t dev, void *context);
204
205struct acpi_parse_resource_set acpi_res_parse_set = {
206    acpi_res_set_init,
207    acpi_res_set_done,
208    acpi_res_set_ioport,
209    acpi_res_set_iorange,
210    acpi_res_set_memory,
211    acpi_res_set_memoryrange,
212    acpi_res_set_irq,
213    acpi_res_set_drq,
214    acpi_res_set_start_dependant,
215    acpi_res_set_end_dependant
216};
217
218struct acpi_res_context {
219    int		ar_nio;
220    int		ar_nmem;
221    int		ar_nirq;
222};
223
224static void
225acpi_res_set_init(device_t dev, void **context)
226{
227    struct acpi_res_context	*cp;
228
229    if ((cp = AcpiOsAllocate(sizeof(*cp))) != NULL) {
230	bzero(cp, sizeof(*cp));
231	*context = cp;
232    }
233}
234
235static void
236acpi_res_set_done(device_t dev, void *context)
237{
238    struct acpi_res_context	*cp = (struct acpi_res_context *)context;
239
240    if (cp == NULL)
241	return;
242    AcpiOsFree(cp);
243}
244
245static void
246acpi_res_set_ioport(device_t dev, void *context, u_int32_t base, u_int32_t length)
247{
248    struct acpi_res_context	*cp = (struct acpi_res_context *)context;
249
250    if (cp == NULL)
251	return;
252    bus_set_resource(dev, SYS_RES_IOPORT, cp->ar_nio++, base, length);
253}
254
255static void
256acpi_res_set_iorange(device_t dev, void *context, u_int32_t low, u_int32_t high, u_int32_t length, u_int32_t align)
257{
258    struct acpi_res_context	*cp = (struct acpi_res_context *)context;
259
260    if (cp == NULL)
261	return;
262    device_printf(dev, "I/O range not supported\n");
263}
264
265static void
266acpi_res_set_memory(device_t dev, void *context, u_int32_t base, u_int32_t length)
267{
268    struct acpi_res_context	*cp = (struct acpi_res_context *)context;
269
270    if (cp == NULL)
271	return;
272    bus_set_resource(dev, SYS_RES_MEMORY, cp->ar_nmem++, base, length);
273}
274
275static void
276acpi_res_set_memoryrange(device_t dev, void *context, u_int32_t low, u_int32_t high, u_int32_t length, u_int32_t align)
277{
278    struct acpi_res_context	*cp = (struct acpi_res_context *)context;
279
280    if (cp == NULL)
281	return;
282    device_printf(dev, "memory range not supported\n");
283}
284
285static void
286acpi_res_set_irq(device_t dev, void *context, u_int32_t irq)
287{
288    struct acpi_res_context	*cp = (struct acpi_res_context *)context;
289
290    if (cp == NULL)
291	return;
292    bus_set_resource(dev, SYS_RES_IRQ, cp->ar_nirq++, irq, 1);
293}
294
295static void
296acpi_res_set_drq(device_t dev, void *context, u_int32_t drq)
297{
298    struct acpi_res_context	*cp = (struct acpi_res_context *)context;
299
300    if (cp == NULL)
301	return;
302    device_printf(dev, "DRQ not supported\n");
303}
304
305static void
306acpi_res_set_start_dependant(device_t dev, void *context, int preference)
307{
308    struct acpi_res_context	*cp = (struct acpi_res_context *)context;
309
310    if (cp == NULL)
311	return;
312    device_printf(dev, "dependant functions not supported");
313}
314
315static void
316acpi_res_set_end_dependant(device_t dev, void *context)
317{
318    struct acpi_res_context	*cp = (struct acpi_res_context *)context;
319
320    if (cp == NULL)
321	return;
322}
323