1 | /* $NetBSD: acpi_resource.c,v 1.37 2015/07/27 04:50:50 msaitoh Exp $ */ |
2 | |
3 | /* |
4 | * Copyright 2001 Wasabi Systems, Inc. |
5 | * All rights reserved. |
6 | * |
7 | * Written by Jason R. Thorpe for Wasabi Systems, Inc. |
8 | * |
9 | * Redistribution and use in source and binary forms, with or without |
10 | * modification, are permitted provided that the following conditions |
11 | * are met: |
12 | * 1. Redistributions of source code must retain the above copyright |
13 | * notice, this list of conditions and the following disclaimer. |
14 | * 2. Redistributions in binary form must reproduce the above copyright |
15 | * notice, this list of conditions and the following disclaimer in the |
16 | * documentation and/or other materials provided with the distribution. |
17 | * 3. All advertising materials mentioning features or use of this software |
18 | * must display the following acknowledgement: |
19 | * This product includes software developed for the NetBSD Project by |
20 | * Wasabi Systems, Inc. |
21 | * 4. The name of Wasabi Systems, Inc. may not be used to endorse |
22 | * or promote products derived from this software without specific prior |
23 | * written permission. |
24 | * |
25 | * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND |
26 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
27 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
28 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC |
29 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
30 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
31 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
32 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
33 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
34 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
35 | * POSSIBILITY OF SUCH DAMAGE. |
36 | */ |
37 | |
38 | /*- |
39 | * Copyright (c) 2000 Michael Smith |
40 | * Copyright (c) 2000 BSDi |
41 | * All rights reserved. |
42 | * |
43 | * Redistribution and use in source and binary forms, with or without |
44 | * modification, are permitted provided that the following conditions |
45 | * are met: |
46 | * 1. Redistributions of source code must retain the above copyright |
47 | * notice, this list of conditions and the following disclaimer. |
48 | * 2. Redistributions in binary form must reproduce the above copyright |
49 | * notice, this list of conditions and the following disclaimer in the |
50 | * documentation and/or other materials provided with the distribution. |
51 | * |
52 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND |
53 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
54 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
55 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE |
56 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
57 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
58 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
59 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
60 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
61 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
62 | * SUCH DAMAGE. |
63 | */ |
64 | |
65 | /* |
66 | * ACPI resource parsing. |
67 | */ |
68 | |
69 | #include <sys/cdefs.h> |
70 | __KERNEL_RCSID(0, "$NetBSD: acpi_resource.c,v 1.37 2015/07/27 04:50:50 msaitoh Exp $" ); |
71 | |
72 | #include <sys/param.h> |
73 | #include <sys/device.h> |
74 | #include <sys/systm.h> |
75 | |
76 | #include <dev/acpi/acpireg.h> |
77 | #include <dev/acpi/acpivar.h> |
78 | |
79 | #define _COMPONENT ACPI_RESOURCE_COMPONENT |
80 | ACPI_MODULE_NAME("RESOURCE" ) |
81 | |
82 | static ACPI_STATUS acpi_resource_parse_callback(ACPI_RESOURCE *, void *); |
83 | |
84 | struct resource_parse_callback_arg { |
85 | const struct acpi_resource_parse_ops *ops; |
86 | device_t dev; |
87 | void *context; |
88 | }; |
89 | |
90 | static ACPI_STATUS |
91 | acpi_resource_parse_callback(ACPI_RESOURCE *res, void *context) |
92 | { |
93 | struct resource_parse_callback_arg *arg = context; |
94 | const struct acpi_resource_parse_ops *ops; |
95 | int i; |
96 | |
97 | ACPI_FUNCTION_TRACE(__func__); |
98 | |
99 | ops = arg->ops; |
100 | |
101 | switch (res->Type) { |
102 | case ACPI_RESOURCE_TYPE_END_TAG: |
103 | ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "EndTag\n" )); |
104 | break; |
105 | case ACPI_RESOURCE_TYPE_FIXED_IO: |
106 | ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, |
107 | "FixedIo 0x%x/%u\n" , |
108 | res->Data.FixedIo.Address, |
109 | res->Data.FixedIo.AddressLength)); |
110 | if (ops->ioport) |
111 | (*ops->ioport)(arg->dev, arg->context, |
112 | res->Data.FixedIo.Address, |
113 | res->Data.FixedIo.AddressLength); |
114 | break; |
115 | |
116 | case ACPI_RESOURCE_TYPE_IO: |
117 | if (res->Data.Io.Minimum == |
118 | res->Data.Io.Maximum) { |
119 | ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, |
120 | "Io 0x%x/%u\n" , |
121 | res->Data.Io.Minimum, |
122 | res->Data.Io.AddressLength)); |
123 | if (ops->ioport) |
124 | (*ops->ioport)(arg->dev, arg->context, |
125 | res->Data.Io.Minimum, |
126 | res->Data.Io.AddressLength); |
127 | } else { |
128 | ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, |
129 | "Io 0x%x-0x%x/%u\n" , |
130 | res->Data.Io.Minimum, |
131 | res->Data.Io.Maximum, |
132 | res->Data.Io.AddressLength)); |
133 | if (ops->iorange) |
134 | (*ops->iorange)(arg->dev, arg->context, |
135 | res->Data.Io.Minimum, |
136 | res->Data.Io.Maximum, |
137 | res->Data.Io.AddressLength, |
138 | res->Data.Io.Alignment); |
139 | } |
140 | break; |
141 | |
142 | case ACPI_RESOURCE_TYPE_FIXED_MEMORY32: |
143 | ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, |
144 | "FixedMemory32 0x%x/%u\n" , |
145 | res->Data.FixedMemory32.Address, |
146 | res->Data.FixedMemory32.AddressLength)); |
147 | if (ops->memory) |
148 | (*ops->memory)(arg->dev, arg->context, |
149 | res->Data.FixedMemory32.Address, |
150 | res->Data.FixedMemory32.AddressLength); |
151 | break; |
152 | |
153 | case ACPI_RESOURCE_TYPE_MEMORY32: |
154 | if (res->Data.Memory32.Minimum == |
155 | res->Data.Memory32.Maximum) { |
156 | ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, |
157 | "Memory32 0x%x/%u\n" , |
158 | res->Data.Memory32.Minimum, |
159 | res->Data.Memory32.AddressLength)); |
160 | if (ops->memory) |
161 | (*ops->memory)(arg->dev, arg->context, |
162 | res->Data.Memory32.Minimum, |
163 | res->Data.Memory32.AddressLength); |
164 | } else { |
165 | ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, |
166 | "Memory32 0x%x-0x%x/%u\n" , |
167 | res->Data.Memory32.Minimum, |
168 | res->Data.Memory32.Maximum, |
169 | res->Data.Memory32.AddressLength)); |
170 | if (ops->memrange) |
171 | (*ops->memrange)(arg->dev, arg->context, |
172 | res->Data.Memory32.Minimum, |
173 | res->Data.Memory32.Maximum, |
174 | res->Data.Memory32.AddressLength, |
175 | res->Data.Memory32.Alignment); |
176 | } |
177 | break; |
178 | |
179 | case ACPI_RESOURCE_TYPE_MEMORY24: |
180 | if (res->Data.Memory24.Minimum == |
181 | res->Data.Memory24.Maximum) { |
182 | ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, |
183 | "Memory24 0x%x/%u\n" , |
184 | res->Data.Memory24.Minimum, |
185 | res->Data.Memory24.AddressLength)); |
186 | if (ops->memory) |
187 | (*ops->memory)(arg->dev, arg->context, |
188 | res->Data.Memory24.Minimum, |
189 | res->Data.Memory24.AddressLength); |
190 | } else { |
191 | ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, |
192 | "Memory24 0x%x-0x%x/%u\n" , |
193 | res->Data.Memory24.Minimum, |
194 | res->Data.Memory24.Maximum, |
195 | res->Data.Memory24.AddressLength)); |
196 | if (ops->memrange) |
197 | (*ops->memrange)(arg->dev, arg->context, |
198 | res->Data.Memory24.Minimum, |
199 | res->Data.Memory24.Maximum, |
200 | res->Data.Memory24.AddressLength, |
201 | res->Data.Memory24.Alignment); |
202 | } |
203 | break; |
204 | |
205 | case ACPI_RESOURCE_TYPE_IRQ: |
206 | for (i = 0; i < res->Data.Irq.InterruptCount; i++) { |
207 | ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, |
208 | "IRQ %u\n" , |
209 | res->Data.Irq.Interrupts[i])); |
210 | if (ops->irq) |
211 | (*ops->irq)(arg->dev, arg->context, |
212 | res->Data.Irq.Interrupts[i], |
213 | res->Data.Irq.Triggering); |
214 | } |
215 | break; |
216 | |
217 | case ACPI_RESOURCE_TYPE_DMA: |
218 | for (i = 0; i < res->Data.Dma.ChannelCount; i++) { |
219 | ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, |
220 | "DRQ %u\n" , |
221 | res->Data.Dma.Channels[i])); |
222 | if (ops->drq) |
223 | (*ops->drq)(arg->dev, arg->context, |
224 | res->Data.Dma.Channels[i]); |
225 | } |
226 | break; |
227 | |
228 | case ACPI_RESOURCE_TYPE_START_DEPENDENT: |
229 | ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, |
230 | "Start dependent functions: %u\n" , |
231 | res->Data.StartDpf.CompatibilityPriority)); |
232 | if (ops->start_dep) |
233 | (*ops->start_dep)(arg->dev, arg->context, |
234 | res->Data.StartDpf.CompatibilityPriority); |
235 | break; |
236 | |
237 | case ACPI_RESOURCE_TYPE_END_DEPENDENT: |
238 | ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, |
239 | "End dependent functions\n" )); |
240 | if (ops->end_dep) |
241 | (*ops->end_dep)(arg->dev, arg->context); |
242 | break; |
243 | |
244 | case ACPI_RESOURCE_TYPE_ADDRESS32: |
245 | /* XXX Only fixed size supported for now */ |
246 | if (res->Data.Address32.Address.AddressLength == 0 || |
247 | res->Data.Address32.ProducerConsumer != ACPI_CONSUMER) |
248 | break; |
249 | #define ADRRESS32_FIXED2(r) \ |
250 | ((r)->Data.Address32.MinAddressFixed == ACPI_ADDRESS_FIXED && \ |
251 | (r)->Data.Address32.MaxAddressFixed == ACPI_ADDRESS_FIXED) |
252 | switch (res->Data.Address32.ResourceType) { |
253 | case ACPI_MEMORY_RANGE: |
254 | if (ADRRESS32_FIXED2(res)) { |
255 | if (ops->memory) |
256 | (*ops->memory)(arg->dev, arg->context, |
257 | res->Data.Address32.Address.Minimum, |
258 | res->Data.Address32.Address.AddressLength); |
259 | } else { |
260 | if (ops->memrange) |
261 | (*ops->memrange)(arg->dev, arg->context, |
262 | res->Data.Address32.Address.Minimum, |
263 | res->Data.Address32.Address.Maximum, |
264 | res->Data.Address32.Address.AddressLength, |
265 | res->Data.Address32.Address.Granularity); |
266 | } |
267 | break; |
268 | case ACPI_IO_RANGE: |
269 | if (ADRRESS32_FIXED2(res)) { |
270 | if (ops->ioport) |
271 | (*ops->ioport)(arg->dev, arg->context, |
272 | res->Data.Address32.Address.Minimum, |
273 | res->Data.Address32.Address.AddressLength); |
274 | } else { |
275 | if (ops->iorange) |
276 | (*ops->iorange)(arg->dev, arg->context, |
277 | res->Data.Address32.Address.Minimum, |
278 | res->Data.Address32.Address.Maximum, |
279 | res->Data.Address32.Address.AddressLength, |
280 | res->Data.Address32.Address.Granularity); |
281 | } |
282 | break; |
283 | case ACPI_BUS_NUMBER_RANGE: |
284 | ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, |
285 | "Address32/BusNumber unimplemented\n" )); |
286 | break; |
287 | } |
288 | #undef ADRRESS32_FIXED2 |
289 | break; |
290 | |
291 | case ACPI_RESOURCE_TYPE_ADDRESS16: |
292 | ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, |
293 | "Address16 unimplemented\n" )); |
294 | break; |
295 | |
296 | case ACPI_RESOURCE_TYPE_ADDRESS64: |
297 | ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, |
298 | "Address64 unimplemented\n" )); |
299 | break; |
300 | case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64: |
301 | ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, |
302 | "Extended address64 unimplemented\n" )); |
303 | break; |
304 | |
305 | case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: |
306 | if (res->Data.ExtendedIrq.ProducerConsumer != ACPI_CONSUMER) { |
307 | ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, |
308 | "ignored ExtIRQ producer\n" )); |
309 | break; |
310 | } |
311 | for (i = 0; i < res->Data.ExtendedIrq.InterruptCount; i++) { |
312 | ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, |
313 | "ExtIRQ %u\n" , |
314 | res->Data.ExtendedIrq.Interrupts[i])); |
315 | if (ops->irq) |
316 | (*ops->irq)(arg->dev, arg->context, |
317 | res->Data.ExtendedIrq.Interrupts[i], |
318 | res->Data.ExtendedIrq.Triggering); |
319 | } |
320 | break; |
321 | |
322 | case ACPI_RESOURCE_TYPE_GENERIC_REGISTER: |
323 | ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, |
324 | "GenericRegister unimplemented\n" )); |
325 | break; |
326 | |
327 | case ACPI_RESOURCE_TYPE_VENDOR: |
328 | ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, |
329 | "VendorSpecific unimplemented\n" )); |
330 | break; |
331 | |
332 | default: |
333 | ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, |
334 | "Unknown resource type: %u\n" , res->Type)); |
335 | break; |
336 | } |
337 | |
338 | return_ACPI_STATUS(AE_OK); |
339 | } |
340 | |
341 | |
342 | /* |
343 | * acpi_resource_parse: |
344 | * |
345 | * Parse a device node's resources and fill them in for the |
346 | * client. |
347 | * |
348 | * This API supports _CRS (current resources) and |
349 | * _PRS (possible resources). |
350 | * |
351 | * Note that it might be nice to also locate ACPI-specific resource |
352 | * items, such as GPE bits. |
353 | */ |
354 | ACPI_STATUS |
355 | acpi_resource_parse(device_t dev, ACPI_HANDLE handle, const char *path, |
356 | void *arg, const struct acpi_resource_parse_ops *ops) |
357 | { |
358 | struct resource_parse_callback_arg cbarg; |
359 | ACPI_STATUS rv; |
360 | |
361 | ACPI_FUNCTION_TRACE(__func__); |
362 | |
363 | if (ops->init) |
364 | (*ops->init)(dev, arg, &cbarg.context); |
365 | else |
366 | cbarg.context = arg; |
367 | cbarg.ops = ops; |
368 | cbarg.dev = dev; |
369 | |
370 | rv = AcpiWalkResources(handle, path, acpi_resource_parse_callback, |
371 | &cbarg); |
372 | if (ACPI_FAILURE(rv)) { |
373 | aprint_error_dev(dev, "ACPI: unable to get %s resources: %s\n" , |
374 | path, AcpiFormatException(rv)); |
375 | return_ACPI_STATUS(rv); |
376 | } |
377 | |
378 | if (ops->fini) |
379 | (*ops->fini)(dev, cbarg.context); |
380 | |
381 | return_ACPI_STATUS(AE_OK); |
382 | } |
383 | |
384 | /* |
385 | * acpi_resource_print: |
386 | * |
387 | * Print the resources assigned to a device. |
388 | */ |
389 | void |
390 | acpi_resource_print(device_t dev, struct acpi_resources *res) |
391 | { |
392 | const char *sep; |
393 | |
394 | if (SIMPLEQ_EMPTY(&res->ar_io) && |
395 | SIMPLEQ_EMPTY(&res->ar_iorange) && |
396 | SIMPLEQ_EMPTY(&res->ar_mem) && |
397 | SIMPLEQ_EMPTY(&res->ar_memrange) && |
398 | SIMPLEQ_EMPTY(&res->ar_irq) && |
399 | SIMPLEQ_EMPTY(&res->ar_drq)) |
400 | return; |
401 | |
402 | aprint_normal(":" ); |
403 | |
404 | if (SIMPLEQ_EMPTY(&res->ar_io) == 0) { |
405 | struct acpi_io *ar; |
406 | |
407 | sep = "" ; |
408 | aprint_normal(" io " ); |
409 | SIMPLEQ_FOREACH(ar, &res->ar_io, ar_list) { |
410 | aprint_normal("%s0x%x" , sep, ar->ar_base); |
411 | if (ar->ar_length > 1) |
412 | aprint_normal("-0x%x" , ar->ar_base + |
413 | ar->ar_length - 1); |
414 | sep = "," ; |
415 | } |
416 | } |
417 | |
418 | /* XXX iorange */ |
419 | |
420 | if (SIMPLEQ_EMPTY(&res->ar_mem) == 0) { |
421 | struct acpi_mem *ar; |
422 | |
423 | sep = "" ; |
424 | aprint_normal(" mem " ); |
425 | SIMPLEQ_FOREACH(ar, &res->ar_mem, ar_list) { |
426 | aprint_normal("%s0x%x" , sep, ar->ar_base); |
427 | if (ar->ar_length > 1) |
428 | aprint_normal("-0x%x" , ar->ar_base + |
429 | ar->ar_length - 1); |
430 | sep = "," ; |
431 | } |
432 | } |
433 | |
434 | /* XXX memrange */ |
435 | |
436 | if (SIMPLEQ_EMPTY(&res->ar_irq) == 0) { |
437 | struct acpi_irq *ar; |
438 | |
439 | sep = "" ; |
440 | aprint_normal(" irq " ); |
441 | SIMPLEQ_FOREACH(ar, &res->ar_irq, ar_list) { |
442 | aprint_normal("%s%d" , sep, ar->ar_irq); |
443 | sep = "," ; |
444 | } |
445 | } |
446 | |
447 | if (SIMPLEQ_EMPTY(&res->ar_drq) == 0) { |
448 | struct acpi_drq *ar; |
449 | |
450 | sep = "" ; |
451 | aprint_normal(" drq " ); |
452 | SIMPLEQ_FOREACH(ar, &res->ar_drq, ar_list) { |
453 | aprint_normal("%s%d" , sep, ar->ar_drq); |
454 | sep = "," ; |
455 | } |
456 | } |
457 | |
458 | aprint_normal("\n" ); |
459 | aprint_naive("\n" ); |
460 | } |
461 | |
462 | /* |
463 | * acpi_resource_cleanup: |
464 | * |
465 | * Free all allocated buffers |
466 | */ |
467 | void |
468 | acpi_resource_cleanup(struct acpi_resources *res) |
469 | { |
470 | while (!SIMPLEQ_EMPTY(&res->ar_io)) { |
471 | struct acpi_io *ar; |
472 | ar = SIMPLEQ_FIRST(&res->ar_io); |
473 | SIMPLEQ_REMOVE_HEAD(&res->ar_io, ar_list); |
474 | ACPI_FREE(ar); |
475 | } |
476 | |
477 | while (!SIMPLEQ_EMPTY(&res->ar_iorange)) { |
478 | struct acpi_iorange *ar; |
479 | ar = SIMPLEQ_FIRST(&res->ar_iorange); |
480 | SIMPLEQ_REMOVE_HEAD(&res->ar_iorange, ar_list); |
481 | ACPI_FREE(ar); |
482 | } |
483 | |
484 | while (!SIMPLEQ_EMPTY(&res->ar_mem)) { |
485 | struct acpi_mem *ar; |
486 | ar = SIMPLEQ_FIRST(&res->ar_mem); |
487 | SIMPLEQ_REMOVE_HEAD(&res->ar_mem, ar_list); |
488 | ACPI_FREE(ar); |
489 | } |
490 | |
491 | while (!SIMPLEQ_EMPTY(&res->ar_memrange)) { |
492 | struct acpi_memrange *ar; |
493 | ar = SIMPLEQ_FIRST(&res->ar_memrange); |
494 | SIMPLEQ_REMOVE_HEAD(&res->ar_memrange, ar_list); |
495 | ACPI_FREE(ar); |
496 | } |
497 | |
498 | while (!SIMPLEQ_EMPTY(&res->ar_irq)) { |
499 | struct acpi_irq *ar; |
500 | ar = SIMPLEQ_FIRST(&res->ar_irq); |
501 | SIMPLEQ_REMOVE_HEAD(&res->ar_irq, ar_list); |
502 | ACPI_FREE(ar); |
503 | } |
504 | |
505 | while (!SIMPLEQ_EMPTY(&res->ar_drq)) { |
506 | struct acpi_drq *ar; |
507 | ar = SIMPLEQ_FIRST(&res->ar_drq); |
508 | SIMPLEQ_REMOVE_HEAD(&res->ar_drq, ar_list); |
509 | ACPI_FREE(ar); |
510 | } |
511 | |
512 | res->ar_nio = res->ar_niorange = res->ar_nmem = |
513 | res->ar_nmemrange = res->ar_nirq = res->ar_ndrq = 0; |
514 | } |
515 | |
516 | struct acpi_io * |
517 | acpi_res_io(struct acpi_resources *res, int idx) |
518 | { |
519 | struct acpi_io *ar; |
520 | |
521 | SIMPLEQ_FOREACH(ar, &res->ar_io, ar_list) { |
522 | if (ar->ar_index == idx) |
523 | return ar; |
524 | } |
525 | return NULL; |
526 | } |
527 | |
528 | struct acpi_iorange * |
529 | acpi_res_iorange(struct acpi_resources *res, int idx) |
530 | { |
531 | struct acpi_iorange *ar; |
532 | |
533 | SIMPLEQ_FOREACH(ar, &res->ar_iorange, ar_list) { |
534 | if (ar->ar_index == idx) |
535 | return ar; |
536 | } |
537 | return NULL; |
538 | } |
539 | |
540 | struct acpi_mem * |
541 | acpi_res_mem(struct acpi_resources *res, int idx) |
542 | { |
543 | struct acpi_mem *ar; |
544 | |
545 | SIMPLEQ_FOREACH(ar, &res->ar_mem, ar_list) { |
546 | if (ar->ar_index == idx) |
547 | return ar; |
548 | } |
549 | return NULL; |
550 | } |
551 | |
552 | struct acpi_memrange * |
553 | acpi_res_memrange(struct acpi_resources *res, int idx) |
554 | { |
555 | struct acpi_memrange *ar; |
556 | |
557 | SIMPLEQ_FOREACH(ar, &res->ar_memrange, ar_list) { |
558 | if (ar->ar_index == idx) |
559 | return ar; |
560 | } |
561 | return NULL; |
562 | } |
563 | |
564 | struct acpi_irq * |
565 | acpi_res_irq(struct acpi_resources *res, int idx) |
566 | { |
567 | struct acpi_irq *ar; |
568 | |
569 | SIMPLEQ_FOREACH(ar, &res->ar_irq, ar_list) { |
570 | if (ar->ar_index == idx) |
571 | return ar; |
572 | } |
573 | return NULL; |
574 | } |
575 | |
576 | struct acpi_drq * |
577 | acpi_res_drq(struct acpi_resources *res, int idx) |
578 | { |
579 | struct acpi_drq *ar; |
580 | |
581 | SIMPLEQ_FOREACH(ar, &res->ar_drq, ar_list) { |
582 | if (ar->ar_index == idx) |
583 | return ar; |
584 | } |
585 | return NULL; |
586 | } |
587 | |
588 | /***************************************************************************** |
589 | * Default ACPI resource parse operations. |
590 | *****************************************************************************/ |
591 | |
592 | static void acpi_res_parse_init(device_t, void *, void **); |
593 | static void acpi_res_parse_fini(device_t, void *); |
594 | |
595 | static void acpi_res_parse_ioport(device_t, void *, uint32_t, |
596 | uint32_t); |
597 | static void acpi_res_parse_iorange(device_t, void *, uint32_t, |
598 | uint32_t, uint32_t, uint32_t); |
599 | |
600 | static void acpi_res_parse_memory(device_t, void *, uint32_t, |
601 | uint32_t); |
602 | static void acpi_res_parse_memrange(device_t, void *, uint32_t, |
603 | uint32_t, uint32_t, uint32_t); |
604 | |
605 | static void acpi_res_parse_irq(device_t, void *, uint32_t, uint32_t); |
606 | static void acpi_res_parse_drq(device_t, void *, uint32_t); |
607 | |
608 | static void acpi_res_parse_start_dep(device_t, void *, int); |
609 | static void acpi_res_parse_end_dep(device_t, void *); |
610 | |
611 | const struct acpi_resource_parse_ops acpi_resource_parse_ops_default = { |
612 | .init = acpi_res_parse_init, |
613 | .fini = acpi_res_parse_fini, |
614 | |
615 | .ioport = acpi_res_parse_ioport, |
616 | .iorange = acpi_res_parse_iorange, |
617 | |
618 | .memory = acpi_res_parse_memory, |
619 | .memrange = acpi_res_parse_memrange, |
620 | |
621 | .irq = acpi_res_parse_irq, |
622 | .drq = acpi_res_parse_drq, |
623 | |
624 | .start_dep = acpi_res_parse_start_dep, |
625 | .end_dep = acpi_res_parse_end_dep, |
626 | }; |
627 | |
628 | const struct acpi_resource_parse_ops acpi_resource_parse_ops_quiet = { |
629 | .init = acpi_res_parse_init, |
630 | .fini = NULL, |
631 | |
632 | .ioport = acpi_res_parse_ioport, |
633 | .iorange = acpi_res_parse_iorange, |
634 | |
635 | .memory = acpi_res_parse_memory, |
636 | .memrange = acpi_res_parse_memrange, |
637 | |
638 | .irq = acpi_res_parse_irq, |
639 | .drq = acpi_res_parse_drq, |
640 | |
641 | .start_dep = acpi_res_parse_start_dep, |
642 | .end_dep = acpi_res_parse_end_dep, |
643 | }; |
644 | |
645 | static void |
646 | acpi_res_parse_init(device_t dev, void *arg, void **contextp) |
647 | { |
648 | struct acpi_resources *res = arg; |
649 | |
650 | SIMPLEQ_INIT(&res->ar_io); |
651 | res->ar_nio = 0; |
652 | |
653 | SIMPLEQ_INIT(&res->ar_iorange); |
654 | res->ar_niorange = 0; |
655 | |
656 | SIMPLEQ_INIT(&res->ar_mem); |
657 | res->ar_nmem = 0; |
658 | |
659 | SIMPLEQ_INIT(&res->ar_memrange); |
660 | res->ar_nmemrange = 0; |
661 | |
662 | SIMPLEQ_INIT(&res->ar_irq); |
663 | res->ar_nirq = 0; |
664 | |
665 | SIMPLEQ_INIT(&res->ar_drq); |
666 | res->ar_ndrq = 0; |
667 | |
668 | *contextp = res; |
669 | } |
670 | |
671 | static void |
672 | acpi_res_parse_fini(device_t dev, void *context) |
673 | { |
674 | struct acpi_resources *res = context; |
675 | |
676 | /* Print the resources we're using. */ |
677 | acpi_resource_print(dev, res); |
678 | } |
679 | |
680 | static void |
681 | acpi_res_parse_ioport(device_t dev, void *context, uint32_t base, |
682 | uint32_t length) |
683 | { |
684 | struct acpi_resources *res = context; |
685 | struct acpi_io *ar; |
686 | |
687 | /* |
688 | * Check if there is another I/O port directly below/under |
689 | * this one. |
690 | */ |
691 | SIMPLEQ_FOREACH(ar, &res->ar_io, ar_list) { |
692 | if (ar->ar_base == base + length ) { |
693 | /* |
694 | * Entry just below existing entry - adjust |
695 | * the entry and return. |
696 | */ |
697 | ar->ar_base = base; |
698 | ar->ar_length += length; |
699 | return; |
700 | } else if (ar->ar_base + ar->ar_length == base) { |
701 | /* |
702 | * Entry just above existing entry - adjust |
703 | * the entry and return. |
704 | */ |
705 | ar->ar_length += length; |
706 | return; |
707 | } |
708 | } |
709 | |
710 | ar = ACPI_ALLOCATE(sizeof(*ar)); |
711 | if (ar == NULL) { |
712 | aprint_error_dev(dev, "ACPI: unable to allocate I/O resource %d\n" , |
713 | res->ar_nio); |
714 | res->ar_nio++; |
715 | return; |
716 | } |
717 | |
718 | ar->ar_index = res->ar_nio++; |
719 | ar->ar_base = base; |
720 | ar->ar_length = length; |
721 | |
722 | SIMPLEQ_INSERT_TAIL(&res->ar_io, ar, ar_list); |
723 | } |
724 | |
725 | static void |
726 | acpi_res_parse_iorange(device_t dev, void *context, uint32_t low, |
727 | uint32_t high, uint32_t length, uint32_t align) |
728 | { |
729 | struct acpi_resources *res = context; |
730 | struct acpi_iorange *ar; |
731 | |
732 | ar = ACPI_ALLOCATE(sizeof(*ar)); |
733 | if (ar == NULL) { |
734 | aprint_error_dev(dev, "ACPI: unable to allocate I/O range resource %d\n" , |
735 | res->ar_niorange); |
736 | res->ar_niorange++; |
737 | return; |
738 | } |
739 | |
740 | ar->ar_index = res->ar_niorange++; |
741 | ar->ar_low = low; |
742 | ar->ar_high = high; |
743 | ar->ar_length = length; |
744 | ar->ar_align = align; |
745 | |
746 | SIMPLEQ_INSERT_TAIL(&res->ar_iorange, ar, ar_list); |
747 | } |
748 | |
749 | static void |
750 | acpi_res_parse_memory(device_t dev, void *context, uint32_t base, |
751 | uint32_t length) |
752 | { |
753 | struct acpi_resources *res = context; |
754 | struct acpi_mem *ar; |
755 | |
756 | ar = ACPI_ALLOCATE(sizeof(*ar)); |
757 | if (ar == NULL) { |
758 | aprint_error_dev(dev, "ACPI: unable to allocate Memory resource %d\n" , |
759 | res->ar_nmem); |
760 | res->ar_nmem++; |
761 | return; |
762 | } |
763 | |
764 | ar->ar_index = res->ar_nmem++; |
765 | ar->ar_base = base; |
766 | ar->ar_length = length; |
767 | |
768 | SIMPLEQ_INSERT_TAIL(&res->ar_mem, ar, ar_list); |
769 | } |
770 | |
771 | static void |
772 | acpi_res_parse_memrange(device_t dev, void *context, uint32_t low, |
773 | uint32_t high, uint32_t length, uint32_t align) |
774 | { |
775 | struct acpi_resources *res = context; |
776 | struct acpi_memrange *ar; |
777 | |
778 | ar = ACPI_ALLOCATE(sizeof(*ar)); |
779 | if (ar == NULL) { |
780 | aprint_error_dev(dev, "ACPI: unable to allocate Memory range resource %d\n" , |
781 | res->ar_nmemrange); |
782 | res->ar_nmemrange++; |
783 | return; |
784 | } |
785 | |
786 | ar->ar_index = res->ar_nmemrange++; |
787 | ar->ar_low = low; |
788 | ar->ar_high = high; |
789 | ar->ar_length = length; |
790 | ar->ar_align = align; |
791 | |
792 | SIMPLEQ_INSERT_TAIL(&res->ar_memrange, ar, ar_list); |
793 | } |
794 | |
795 | static void |
796 | acpi_res_parse_irq(device_t dev, void *context, uint32_t irq, uint32_t type) |
797 | { |
798 | struct acpi_resources *res = context; |
799 | struct acpi_irq *ar; |
800 | |
801 | ar = ACPI_ALLOCATE(sizeof(*ar)); |
802 | if (ar == NULL) { |
803 | aprint_error_dev(dev, "ACPI: unable to allocate IRQ resource %d\n" , |
804 | res->ar_nirq); |
805 | res->ar_nirq++; |
806 | return; |
807 | } |
808 | |
809 | ar->ar_index = res->ar_nirq++; |
810 | ar->ar_irq = irq; |
811 | ar->ar_type = type; |
812 | |
813 | SIMPLEQ_INSERT_TAIL(&res->ar_irq, ar, ar_list); |
814 | } |
815 | |
816 | static void |
817 | acpi_res_parse_drq(device_t dev, void *context, uint32_t drq) |
818 | { |
819 | struct acpi_resources *res = context; |
820 | struct acpi_drq *ar; |
821 | |
822 | ar = ACPI_ALLOCATE(sizeof(*ar)); |
823 | if (ar == NULL) { |
824 | aprint_error_dev(dev, "ACPI: unable to allocate DRQ resource %d\n" , |
825 | res->ar_ndrq); |
826 | res->ar_ndrq++; |
827 | return; |
828 | } |
829 | |
830 | ar->ar_index = res->ar_ndrq++; |
831 | ar->ar_drq = drq; |
832 | |
833 | SIMPLEQ_INSERT_TAIL(&res->ar_drq, ar, ar_list); |
834 | } |
835 | |
836 | static void |
837 | acpi_res_parse_start_dep(device_t dev, void *context, |
838 | int preference) |
839 | { |
840 | |
841 | aprint_error_dev(dev, "ACPI: dependent functions not supported\n" ); |
842 | } |
843 | |
844 | static void |
845 | acpi_res_parse_end_dep(device_t dev, void *context) |
846 | { |
847 | |
848 | /* Nothing to do. */ |
849 | } |
850 | |