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$ 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 45 MODULE_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 */ 53 ACPI_STATUS 54 acpi_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 192 static void acpi_res_set_init(device_t dev, void **context); 193 static void acpi_res_set_done(device_t dev, void *context); 194 static void acpi_res_set_ioport(device_t dev, void *context, u_int32_t base, u_int32_t length); 195 static 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); 197 static void acpi_res_set_memory(device_t dev, void *context, u_int32_t base, u_int32_t length); 198 static 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); 200 static void acpi_res_set_irq(device_t dev, void *context, u_int32_t irq); 201 static void acpi_res_set_drq(device_t dev, void *context, u_int32_t drq); 202 static void acpi_res_set_start_dependant(device_t dev, void *context, int preference); 203 static void acpi_res_set_end_dependant(device_t dev, void *context); 204 205 struct 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 218 struct acpi_res_context { 219 int ar_nio; 220 int ar_nmem; 221 int ar_nirq; 222 }; 223 224 static void 225 acpi_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 235 static void 236 acpi_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 245 static void 246 acpi_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 255 static void 256 acpi_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 265 static void 266 acpi_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 275 static void 276 acpi_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 285 static void 286 acpi_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 295 static void 296 acpi_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 305 static void 306 acpi_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 315 static void 316 acpi_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