15b45337dSDoug Rabson /*- 25b45337dSDoug Rabson * Copyright (c) 1999 Doug Rabson 35b45337dSDoug Rabson * All rights reserved. 45b45337dSDoug Rabson * 55b45337dSDoug Rabson * Redistribution and use in source and binary forms, with or without 65b45337dSDoug Rabson * modification, are permitted provided that the following conditions 75b45337dSDoug Rabson * are met: 85b45337dSDoug Rabson * 1. Redistributions of source code must retain the above copyright 95b45337dSDoug Rabson * notice, this list of conditions and the following disclaimer. 105b45337dSDoug Rabson * 2. Redistributions in binary form must reproduce the above copyright 115b45337dSDoug Rabson * notice, this list of conditions and the following disclaimer in the 125b45337dSDoug Rabson * documentation and/or other materials provided with the distribution. 135b45337dSDoug Rabson * 145b45337dSDoug Rabson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 155b45337dSDoug Rabson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 165b45337dSDoug Rabson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 175b45337dSDoug Rabson * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 185b45337dSDoug Rabson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 195b45337dSDoug Rabson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 205b45337dSDoug Rabson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 215b45337dSDoug Rabson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 225b45337dSDoug Rabson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 235b45337dSDoug Rabson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 245b45337dSDoug Rabson * SUCH DAMAGE. 255b45337dSDoug Rabson */ 265b45337dSDoug Rabson 278c9bbf48SDavid E. O'Brien #include <sys/cdefs.h> 288c9bbf48SDavid E. O'Brien __FBSDID("$FreeBSD$"); 298c9bbf48SDavid E. O'Brien 305b45337dSDoug Rabson #include <sys/param.h> 315b45337dSDoug Rabson #include <sys/systm.h> 32ca403ff8SDoug Rabson #include <sys/malloc.h> 335b45337dSDoug Rabson #include <sys/module.h> 345b45337dSDoug Rabson #include <sys/bus.h> 35c3959391SKazutaka YOKOTA 36c3959391SKazutaka YOKOTA #include <machine/stdarg.h> 37c3959391SKazutaka YOKOTA 385b45337dSDoug Rabson #include <isa/isavar.h> 395b45337dSDoug Rabson #include <isa/pnpreg.h> 405b45337dSDoug Rabson #include <isa/pnpvar.h> 415b45337dSDoug Rabson 42acd3131bSDoug Rabson #define MAXDEP 8 43acd3131bSDoug Rabson 44bb2b9030SDoug Rabson #define I16(p) ((p)[0] + ((p)[1] << 8)) 456dbb527eSPoul-Henning Kamp #define I32(p) (I16(p) + (I16((p)+2) << 16)) 46bb2b9030SDoug Rabson 475b45337dSDoug Rabson void 48c3959391SKazutaka YOKOTA pnp_printf(u_int32_t id, char *fmt, ...) 495b45337dSDoug Rabson { 50c3959391SKazutaka YOKOTA va_list ap; 51c3959391SKazutaka YOKOTA 52c3959391SKazutaka YOKOTA va_start(ap, fmt); 53c3959391SKazutaka YOKOTA printf("%s: ", pnp_eisaformat(id)); 54c3959391SKazutaka YOKOTA vprintf(fmt, ap); 55c3959391SKazutaka YOKOTA va_end(ap); 56c3959391SKazutaka YOKOTA } 57c3959391SKazutaka YOKOTA 58c3959391SKazutaka YOKOTA /* parse a single descriptor */ 59c3959391SKazutaka YOKOTA 60c3959391SKazutaka YOKOTA static int 61c3959391SKazutaka YOKOTA pnp_parse_desc(device_t dev, u_char tag, u_char *res, int len, 62c3959391SKazutaka YOKOTA struct isa_config *config, int ldn) 63c3959391SKazutaka YOKOTA { 645b45337dSDoug Rabson char buf[100]; 65c3959391SKazutaka YOKOTA u_int32_t id; 66c3959391SKazutaka YOKOTA u_int32_t compat_id; 67c3959391SKazutaka YOKOTA int temp; 685b45337dSDoug Rabson 69bb2b9030SDoug Rabson id = isa_get_logicalid(dev); 705b45337dSDoug Rabson 71c3959391SKazutaka YOKOTA if (PNP_RES_TYPE(tag) == 0) { 72c3959391SKazutaka YOKOTA 73c3959391SKazutaka YOKOTA /* Small resource */ 745b45337dSDoug Rabson switch (PNP_SRES_NUM(tag)) { 75c3959391SKazutaka YOKOTA 76c3959391SKazutaka YOKOTA case PNP_TAG_VERSION: 77c3959391SKazutaka YOKOTA case PNP_TAG_VENDOR: 78c3959391SKazutaka YOKOTA /* these descriptors are quietly ignored */ 79c3959391SKazutaka YOKOTA break; 80c3959391SKazutaka YOKOTA 81c3959391SKazutaka YOKOTA case PNP_TAG_LOGICAL_DEVICE: 82c3959391SKazutaka YOKOTA case PNP_TAG_START_DEPENDANT: 83c3959391SKazutaka YOKOTA case PNP_TAG_END_DEPENDANT: 84c3959391SKazutaka YOKOTA if (bootverbose) 85c3959391SKazutaka YOKOTA pnp_printf(id, "unexpected small tag %d\n", 86c3959391SKazutaka YOKOTA PNP_SRES_NUM(tag)); 87c3959391SKazutaka YOKOTA /* shouldn't happen; quit now */ 88c3959391SKazutaka YOKOTA return (1); 89c3959391SKazutaka YOKOTA 905b45337dSDoug Rabson case PNP_TAG_COMPAT_DEVICE: 915b45337dSDoug Rabson /* 92c3959391SKazutaka YOKOTA * Got a compatible device id resource. 93c3959391SKazutaka YOKOTA * Should keep a list of compat ids in the device. 945b45337dSDoug Rabson */ 95c3959391SKazutaka YOKOTA bcopy(res, &compat_id, 4); 96c3959391SKazutaka YOKOTA if (isa_get_compatid(dev) == 0) 975b45337dSDoug Rabson isa_set_compatid(dev, compat_id); 985b45337dSDoug Rabson break; 995b45337dSDoug Rabson 1005b45337dSDoug Rabson case PNP_TAG_IRQ_FORMAT: 1015b45337dSDoug Rabson if (config->ic_nirq == ISA_NIRQ) { 102c3959391SKazutaka YOKOTA pnp_printf(id, "too many irqs\n"); 103c3959391SKazutaka YOKOTA return (1); 104c3959391SKazutaka YOKOTA } 105c3959391SKazutaka YOKOTA if (I16(res) == 0) { 106c3959391SKazutaka YOKOTA /* a null descriptor */ 107c3959391SKazutaka YOKOTA config->ic_irqmask[config->ic_nirq] = 0; 108c3959391SKazutaka YOKOTA config->ic_nirq++; 1095b45337dSDoug Rabson break; 1105b45337dSDoug Rabson } 111c3959391SKazutaka YOKOTA if (bootverbose) 112c3959391SKazutaka YOKOTA pnp_printf(id, "adding irq mask %#02x\n", 113c3959391SKazutaka YOKOTA I16(res)); 114c3959391SKazutaka YOKOTA config->ic_irqmask[config->ic_nirq] = I16(res); 1155b45337dSDoug Rabson config->ic_nirq++; 1165b45337dSDoug Rabson break; 1175b45337dSDoug Rabson 1185b45337dSDoug Rabson case PNP_TAG_DMA_FORMAT: 1195b45337dSDoug Rabson if (config->ic_ndrq == ISA_NDRQ) { 120c3959391SKazutaka YOKOTA pnp_printf(id, "too many drqs\n"); 121c3959391SKazutaka YOKOTA return (1); 122c3959391SKazutaka YOKOTA } 123c3959391SKazutaka YOKOTA if (res[0] == 0) { 124c3959391SKazutaka YOKOTA /* a null descriptor */ 125c3959391SKazutaka YOKOTA config->ic_drqmask[config->ic_ndrq] = 0; 126c3959391SKazutaka YOKOTA config->ic_ndrq++; 1275b45337dSDoug Rabson break; 1285b45337dSDoug Rabson } 129c3959391SKazutaka YOKOTA if (bootverbose) 130c3959391SKazutaka YOKOTA pnp_printf(id, "adding dma mask %#02x\n", 131c3959391SKazutaka YOKOTA res[0]); 132c3959391SKazutaka YOKOTA config->ic_drqmask[config->ic_ndrq] = res[0]; 1335b45337dSDoug Rabson config->ic_ndrq++; 1345b45337dSDoug Rabson break; 1355b45337dSDoug Rabson 1365b45337dSDoug Rabson case PNP_TAG_IO_RANGE: 137c3959391SKazutaka YOKOTA if (config->ic_nport == ISA_NPORT) { 138c3959391SKazutaka YOKOTA pnp_printf(id, "too many ports\n"); 139c3959391SKazutaka YOKOTA return (1); 140c3959391SKazutaka YOKOTA } 141c3959391SKazutaka YOKOTA if (res[6] == 0) { 142c3959391SKazutaka YOKOTA /* a null descriptor */ 143c3959391SKazutaka YOKOTA config->ic_port[config->ic_nport].ir_start = 0; 144c3959391SKazutaka YOKOTA config->ic_port[config->ic_nport].ir_end = 0; 145c3959391SKazutaka YOKOTA config->ic_port[config->ic_nport].ir_size = 0; 146c3959391SKazutaka YOKOTA config->ic_port[config->ic_nport].ir_align = 0; 147c3959391SKazutaka YOKOTA config->ic_nport++; 148c3959391SKazutaka YOKOTA break; 149c3959391SKazutaka YOKOTA } 150bb2b9030SDoug Rabson if (bootverbose) { 151c3959391SKazutaka YOKOTA pnp_printf(id, "adding io range " 152bb2b9030SDoug Rabson "%#x-%#x, size=%#x, " 153bb2b9030SDoug Rabson "align=%#x\n", 154c3959391SKazutaka YOKOTA I16(res + 1), 155c3959391SKazutaka YOKOTA I16(res + 3) + res[6]-1, 156c3959391SKazutaka YOKOTA res[6], res[5]); 1575b45337dSDoug Rabson } 1585b45337dSDoug Rabson config->ic_port[config->ic_nport].ir_start = 159c3959391SKazutaka YOKOTA I16(res + 1); 1605b45337dSDoug Rabson config->ic_port[config->ic_nport].ir_end = 161c3959391SKazutaka YOKOTA I16(res + 3) + res[6] - 1; 162c3959391SKazutaka YOKOTA config->ic_port[config->ic_nport].ir_size = res[6]; 163c3959391SKazutaka YOKOTA if (res[5] == 0) { 164bb2b9030SDoug Rabson /* Make sure align is at least one */ 165c3959391SKazutaka YOKOTA res[5] = 1; 166bb2b9030SDoug Rabson } 167c3959391SKazutaka YOKOTA config->ic_port[config->ic_nport].ir_align = res[5]; 1685b45337dSDoug Rabson config->ic_nport++; 169c3959391SKazutaka YOKOTA pnp_check_quirks(isa_get_vendorid(dev), 170c3959391SKazutaka YOKOTA isa_get_logicalid(dev), ldn, config); 1715b45337dSDoug Rabson break; 1725b45337dSDoug Rabson 1735b45337dSDoug Rabson case PNP_TAG_IO_FIXED: 1745b45337dSDoug Rabson if (config->ic_nport == ISA_NPORT) { 175c3959391SKazutaka YOKOTA pnp_printf(id, "too many ports\n"); 176c3959391SKazutaka YOKOTA return (1); 177c3959391SKazutaka YOKOTA } 178c3959391SKazutaka YOKOTA if (res[2] == 0) { 179c3959391SKazutaka YOKOTA /* a null descriptor */ 180c3959391SKazutaka YOKOTA config->ic_port[config->ic_nport].ir_start = 0; 181c3959391SKazutaka YOKOTA config->ic_port[config->ic_nport].ir_end = 0; 182c3959391SKazutaka YOKOTA config->ic_port[config->ic_nport].ir_size = 0; 183c3959391SKazutaka YOKOTA config->ic_port[config->ic_nport].ir_align = 0; 184c3959391SKazutaka YOKOTA config->ic_nport++; 1855b45337dSDoug Rabson break; 1865b45337dSDoug Rabson } 187c3959391SKazutaka YOKOTA if (bootverbose) { 188c3959391SKazutaka YOKOTA pnp_printf(id, "adding fixed io range " 189c3959391SKazutaka YOKOTA "%#x-%#x, size=%#x, " 190c3959391SKazutaka YOKOTA "align=%#x\n", 191c3959391SKazutaka YOKOTA I16(res), 192c3959391SKazutaka YOKOTA I16(res) + res[2] - 1, 193c3959391SKazutaka YOKOTA res[2], 1); 194c3959391SKazutaka YOKOTA } 195c3959391SKazutaka YOKOTA config->ic_port[config->ic_nport].ir_start = I16(res); 1965b45337dSDoug Rabson config->ic_port[config->ic_nport].ir_end = 197c3959391SKazutaka YOKOTA I16(res) + res[2] - 1; 198c3959391SKazutaka YOKOTA config->ic_port[config->ic_nport].ir_size = res[2]; 1995b45337dSDoug Rabson config->ic_port[config->ic_nport].ir_align = 1; 2005b45337dSDoug Rabson config->ic_nport++; 2015b45337dSDoug Rabson break; 2025b45337dSDoug Rabson 203bb2b9030SDoug Rabson case PNP_TAG_END: 204c3959391SKazutaka YOKOTA if (bootverbose) 205c3959391SKazutaka YOKOTA pnp_printf(id, "end config\n"); 206c3959391SKazutaka YOKOTA return (1); 207bb2b9030SDoug Rabson 2085b45337dSDoug Rabson default: 2095b45337dSDoug Rabson /* Skip this resource */ 210c3959391SKazutaka YOKOTA pnp_printf(id, "unexpected small tag %d\n", 2115b45337dSDoug Rabson PNP_SRES_NUM(tag)); 2125b45337dSDoug Rabson break; 2135b45337dSDoug Rabson } 2145b45337dSDoug Rabson } else { 2155b45337dSDoug Rabson /* Large resource */ 216bb2b9030SDoug Rabson switch (PNP_LRES_NUM(tag)) { 217c3959391SKazutaka YOKOTA 218c3959391SKazutaka YOKOTA case PNP_TAG_ID_UNICODE: 219c3959391SKazutaka YOKOTA case PNP_TAG_LARGE_VENDOR: 220c3959391SKazutaka YOKOTA /* these descriptors are quietly ignored */ 221c3959391SKazutaka YOKOTA break; 222c3959391SKazutaka YOKOTA 223bb2b9030SDoug Rabson case PNP_TAG_ID_ANSI: 224c3959391SKazutaka YOKOTA if (len > sizeof(buf) - 1) 225c3959391SKazutaka YOKOTA len = sizeof(buf) - 1; 226c3959391SKazutaka YOKOTA bcopy(res, buf, len); 2275b45337dSDoug Rabson 2285b45337dSDoug Rabson /* 229acd3131bSDoug Rabson * Trim trailing spaces and garbage. 2305b45337dSDoug Rabson */ 231c3959391SKazutaka YOKOTA while (len > 0 && buf[len - 1] <= ' ') 232c3959391SKazutaka YOKOTA len--; 233c3959391SKazutaka YOKOTA buf[len] = '\0'; 2345b45337dSDoug Rabson device_set_desc_copy(dev, buf); 235bb2b9030SDoug Rabson break; 2365b45337dSDoug Rabson 237bb2b9030SDoug Rabson case PNP_TAG_MEMORY_RANGE: 2385b45337dSDoug Rabson if (config->ic_nmem == ISA_NMEM) { 239c3959391SKazutaka YOKOTA pnp_printf(id, "too many memory ranges\n"); 240c3959391SKazutaka YOKOTA return (1); 241c3959391SKazutaka YOKOTA } 242c3959391SKazutaka YOKOTA if (I16(res + 7) == 0) { 243c3959391SKazutaka YOKOTA /* a null descriptor */ 244c3959391SKazutaka YOKOTA config->ic_mem[config->ic_nmem].ir_start = 0; 245c3959391SKazutaka YOKOTA config->ic_mem[config->ic_nmem].ir_end = 0; 246c3959391SKazutaka YOKOTA config->ic_mem[config->ic_nmem].ir_size = 0; 247c3959391SKazutaka YOKOTA config->ic_mem[config->ic_nmem].ir_align = 0; 248c3959391SKazutaka YOKOTA config->ic_nmem++; 2495b45337dSDoug Rabson break; 2505b45337dSDoug Rabson } 251c3959391SKazutaka YOKOTA if (bootverbose) { 252c3959391SKazutaka YOKOTA temp = I16(res + 7) << 8; 253c3959391SKazutaka YOKOTA pnp_printf(id, "adding memory range " 254c3959391SKazutaka YOKOTA "%#x-%#x, size=%#x, " 255c3959391SKazutaka YOKOTA "align=%#x\n", 256c3959391SKazutaka YOKOTA I16(res + 1) << 8, 257c3959391SKazutaka YOKOTA (I16(res + 3) << 8) + temp - 1, 258c3959391SKazutaka YOKOTA temp, I16(res + 5)); 259c3959391SKazutaka YOKOTA } 2605b45337dSDoug Rabson config->ic_mem[config->ic_nmem].ir_start = 261c3959391SKazutaka YOKOTA I16(res + 1) << 8; 2625b45337dSDoug Rabson config->ic_mem[config->ic_nmem].ir_end = 263c3959391SKazutaka YOKOTA (I16(res + 3) << 8) + (I16(res + 7) << 8) - 1; 2645b45337dSDoug Rabson config->ic_mem[config->ic_nmem].ir_size = 265c3959391SKazutaka YOKOTA I16(res + 7) << 8; 266c3959391SKazutaka YOKOTA config->ic_mem[config->ic_nmem].ir_align = I16(res + 5); 2675b45337dSDoug Rabson if (!config->ic_mem[config->ic_nmem].ir_align) 268c3959391SKazutaka YOKOTA config->ic_mem[config->ic_nmem].ir_align = 269c3959391SKazutaka YOKOTA 0x10000; 2705b45337dSDoug Rabson config->ic_nmem++; 271bb2b9030SDoug Rabson break; 272bb2b9030SDoug Rabson 273bb2b9030SDoug Rabson case PNP_TAG_MEMORY32_RANGE: 274bb2b9030SDoug Rabson if (config->ic_nmem == ISA_NMEM) { 275c3959391SKazutaka YOKOTA pnp_printf(id, "too many memory ranges\n"); 276c3959391SKazutaka YOKOTA return (1); 277c3959391SKazutaka YOKOTA } 278c3959391SKazutaka YOKOTA if (I32(res + 13) == 0) { 279c3959391SKazutaka YOKOTA /* a null descriptor */ 280c3959391SKazutaka YOKOTA config->ic_mem[config->ic_nmem].ir_start = 0; 281c3959391SKazutaka YOKOTA config->ic_mem[config->ic_nmem].ir_end = 0; 282c3959391SKazutaka YOKOTA config->ic_mem[config->ic_nmem].ir_size = 0; 283c3959391SKazutaka YOKOTA config->ic_mem[config->ic_nmem].ir_align = 0; 284c3959391SKazutaka YOKOTA config->ic_nmem++; 285bb2b9030SDoug Rabson break; 286bb2b9030SDoug Rabson } 287c3959391SKazutaka YOKOTA if (bootverbose) { 288c3959391SKazutaka YOKOTA pnp_printf(id, "adding memory32 range " 289c3959391SKazutaka YOKOTA "%#x-%#x, size=%#x, " 290c3959391SKazutaka YOKOTA "align=%#x\n", 291c3959391SKazutaka YOKOTA I32(res + 1), 292c3959391SKazutaka YOKOTA I32(res + 5) + I32(res + 13) - 1, 293c3959391SKazutaka YOKOTA I32(res + 13), I32(res + 9)); 294c3959391SKazutaka YOKOTA } 295c3959391SKazutaka YOKOTA config->ic_mem[config->ic_nmem].ir_start = I32(res + 1); 296bb2b9030SDoug Rabson config->ic_mem[config->ic_nmem].ir_end = 297c3959391SKazutaka YOKOTA I32(res + 5) + I32(res + 13) - 1; 298c3959391SKazutaka YOKOTA config->ic_mem[config->ic_nmem].ir_size = I32(res + 13); 299c3959391SKazutaka YOKOTA config->ic_mem[config->ic_nmem].ir_align = I32(res + 9); 300bb2b9030SDoug Rabson config->ic_nmem++; 301bb2b9030SDoug Rabson break; 302bb2b9030SDoug Rabson 303bb2b9030SDoug Rabson case PNP_TAG_MEMORY32_FIXED: 304bb2b9030SDoug Rabson if (config->ic_nmem == ISA_NMEM) { 305c3959391SKazutaka YOKOTA pnp_printf(id, "too many memory ranges\n"); 306c3959391SKazutaka YOKOTA return (1); 307c3959391SKazutaka YOKOTA } 308c3959391SKazutaka YOKOTA if (I32(res + 5) == 0) { 309c3959391SKazutaka YOKOTA /* a null descriptor */ 310c3959391SKazutaka YOKOTA config->ic_mem[config->ic_nmem].ir_start = 0; 311c3959391SKazutaka YOKOTA config->ic_mem[config->ic_nmem].ir_end = 0; 312c3959391SKazutaka YOKOTA config->ic_mem[config->ic_nmem].ir_size = 0; 313c3959391SKazutaka YOKOTA config->ic_mem[config->ic_nmem].ir_align = 0; 314bb2b9030SDoug Rabson break; 315bb2b9030SDoug Rabson } 316c3959391SKazutaka YOKOTA if (bootverbose) { 317c3959391SKazutaka YOKOTA pnp_printf(id, "adding fixed memory32 range " 318c3959391SKazutaka YOKOTA "%#x-%#x, size=%#x\n", 319c3959391SKazutaka YOKOTA I32(res + 1), 320c3959391SKazutaka YOKOTA I32(res + 1) + I32(res + 5) - 1, 321c3959391SKazutaka YOKOTA I32(res + 5)); 322c3959391SKazutaka YOKOTA } 323c3959391SKazutaka YOKOTA config->ic_mem[config->ic_nmem].ir_start = I32(res + 1); 324bb2b9030SDoug Rabson config->ic_mem[config->ic_nmem].ir_end = 325c3959391SKazutaka YOKOTA I32(res + 1) + I32(res + 5) - 1; 326c3959391SKazutaka YOKOTA config->ic_mem[config->ic_nmem].ir_size = I32(res + 5); 327bb2b9030SDoug Rabson config->ic_mem[config->ic_nmem].ir_align = 1; 328bb2b9030SDoug Rabson config->ic_nmem++; 329bb2b9030SDoug Rabson break; 330bb2b9030SDoug Rabson 331bb2b9030SDoug Rabson default: 332bb2b9030SDoug Rabson /* Skip this resource */ 333c3959391SKazutaka YOKOTA pnp_printf(id, "unexpected large tag %d\n", 334bb2b9030SDoug Rabson PNP_SRES_NUM(tag)); 335c3959391SKazutaka YOKOTA break; 336bb2b9030SDoug Rabson } 3375b45337dSDoug Rabson } 338c3959391SKazutaka YOKOTA 339c3959391SKazutaka YOKOTA return (0); 3405b45337dSDoug Rabson } 341c3959391SKazutaka YOKOTA 342c3959391SKazutaka YOKOTA /* 343c3959391SKazutaka YOKOTA * Parse a single "dependent" resource combination. 344c3959391SKazutaka YOKOTA */ 345c3959391SKazutaka YOKOTA 346c3959391SKazutaka YOKOTA u_char 347c3959391SKazutaka YOKOTA *pnp_parse_dependant(device_t dev, u_char *resources, int len, 348c3959391SKazutaka YOKOTA struct isa_config *config, int ldn) 349c3959391SKazutaka YOKOTA { 350c3959391SKazutaka YOKOTA 351c3959391SKazutaka YOKOTA return pnp_scan_resources(dev, resources, len, config, ldn, 352c3959391SKazutaka YOKOTA pnp_parse_desc); 353c3959391SKazutaka YOKOTA } 354c3959391SKazutaka YOKOTA 355c3959391SKazutaka YOKOTA static void 356c3959391SKazutaka YOKOTA pnp_merge_resources(device_t dev, struct isa_config *from, 357c3959391SKazutaka YOKOTA struct isa_config *to) 358c3959391SKazutaka YOKOTA { 359c3959391SKazutaka YOKOTA device_t parent; 360c3959391SKazutaka YOKOTA int i; 361c3959391SKazutaka YOKOTA 362c3959391SKazutaka YOKOTA parent = device_get_parent(dev); 363c3959391SKazutaka YOKOTA for (i = 0; i < from->ic_nmem; i++) { 364c3959391SKazutaka YOKOTA if (to->ic_nmem == ISA_NMEM) { 365c3959391SKazutaka YOKOTA device_printf(parent, "too many memory ranges\n"); 366c3959391SKazutaka YOKOTA return; 367c3959391SKazutaka YOKOTA } 368c3959391SKazutaka YOKOTA to->ic_mem[to->ic_nmem] = from->ic_mem[i]; 369c3959391SKazutaka YOKOTA to->ic_nmem++; 370c3959391SKazutaka YOKOTA } 371c3959391SKazutaka YOKOTA for (i = 0; i < from->ic_nport; i++) { 372c3959391SKazutaka YOKOTA if (to->ic_nport == ISA_NPORT) { 373c3959391SKazutaka YOKOTA device_printf(parent, "too many port ranges\n"); 374c3959391SKazutaka YOKOTA return; 375c3959391SKazutaka YOKOTA } 376c3959391SKazutaka YOKOTA to->ic_port[to->ic_nport] = from->ic_port[i]; 377c3959391SKazutaka YOKOTA to->ic_nport++; 378c3959391SKazutaka YOKOTA } 379c3959391SKazutaka YOKOTA for (i = 0; i < from->ic_nirq; i++) { 380c3959391SKazutaka YOKOTA if (to->ic_nirq == ISA_NIRQ) { 381c3959391SKazutaka YOKOTA device_printf(parent, "too many irq ranges\n"); 382c3959391SKazutaka YOKOTA return; 383c3959391SKazutaka YOKOTA } 384c3959391SKazutaka YOKOTA to->ic_irqmask[to->ic_nirq] = from->ic_irqmask[i]; 385c3959391SKazutaka YOKOTA to->ic_nirq++; 386c3959391SKazutaka YOKOTA } 387c3959391SKazutaka YOKOTA for (i = 0; i < from->ic_ndrq; i++) { 388c3959391SKazutaka YOKOTA if (to->ic_ndrq == ISA_NDRQ) { 389c3959391SKazutaka YOKOTA device_printf(parent, "too many drq ranges\n"); 390c3959391SKazutaka YOKOTA return; 391c3959391SKazutaka YOKOTA } 392c3959391SKazutaka YOKOTA to->ic_drqmask[to->ic_ndrq] = from->ic_drqmask[i]; 393c3959391SKazutaka YOKOTA to->ic_ndrq++; 394c3959391SKazutaka YOKOTA } 395c3959391SKazutaka YOKOTA } 396c3959391SKazutaka YOKOTA 397c3959391SKazutaka YOKOTA /* 398c3959391SKazutaka YOKOTA * Parse resource data for Logical Devices, make a list of available 399c3959391SKazutaka YOKOTA * resource configurations, and add them to the device. 400c3959391SKazutaka YOKOTA * 401c3959391SKazutaka YOKOTA * This function exits as soon as it gets an error reading *ANY* 402c3959391SKazutaka YOKOTA * Resource Data or it reaches the end of Resource Data. 403c3959391SKazutaka YOKOTA */ 404c3959391SKazutaka YOKOTA 405c3959391SKazutaka YOKOTA void 406c3959391SKazutaka YOKOTA pnp_parse_resources(device_t dev, u_char *resources, int len, int ldn) 407c3959391SKazutaka YOKOTA { 408c3959391SKazutaka YOKOTA struct isa_config *configs; 409c3959391SKazutaka YOKOTA struct isa_config *config; 410c3959391SKazutaka YOKOTA device_t parent; 411c3959391SKazutaka YOKOTA int priorities[1 + MAXDEP]; 412c3959391SKazutaka YOKOTA u_char *start; 413c3959391SKazutaka YOKOTA u_char *p; 414c3959391SKazutaka YOKOTA u_char tag; 415c3959391SKazutaka YOKOTA u_int32_t id; 416c3959391SKazutaka YOKOTA int ncfgs; 417c3959391SKazutaka YOKOTA int l; 418c3959391SKazutaka YOKOTA int i; 419c3959391SKazutaka YOKOTA 420c3959391SKazutaka YOKOTA parent = device_get_parent(dev); 421c3959391SKazutaka YOKOTA id = isa_get_logicalid(dev); 422c3959391SKazutaka YOKOTA 423c3959391SKazutaka YOKOTA configs = (struct isa_config *)malloc(sizeof(*configs)*(1 + MAXDEP), 424c3959391SKazutaka YOKOTA M_DEVBUF, M_NOWAIT | M_ZERO); 425c3959391SKazutaka YOKOTA if (configs == NULL) { 426c3959391SKazutaka YOKOTA device_printf(parent, "No memory to parse PNP data\n"); 427c3959391SKazutaka YOKOTA return; 428c3959391SKazutaka YOKOTA } 429c3959391SKazutaka YOKOTA config = &configs[0]; 430c3959391SKazutaka YOKOTA priorities[0] = 0; 431c3959391SKazutaka YOKOTA ncfgs = 1; 432c3959391SKazutaka YOKOTA 433c3959391SKazutaka YOKOTA p = resources; 434c3959391SKazutaka YOKOTA start = NULL; 435c3959391SKazutaka YOKOTA while (len > 0) { 436c3959391SKazutaka YOKOTA tag = *p++; 437c3959391SKazutaka YOKOTA len--; 438c3959391SKazutaka YOKOTA if (PNP_RES_TYPE(tag) == 0) { 439c3959391SKazutaka YOKOTA /* Small resource */ 440c3959391SKazutaka YOKOTA l = PNP_SRES_LEN(tag); 441c3959391SKazutaka YOKOTA if (len < l) { 442c3959391SKazutaka YOKOTA len = 0; 443c3959391SKazutaka YOKOTA continue; 444c3959391SKazutaka YOKOTA } 445c3959391SKazutaka YOKOTA len -= l; 446c3959391SKazutaka YOKOTA 447c3959391SKazutaka YOKOTA switch (PNP_SRES_NUM(tag)) { 448c3959391SKazutaka YOKOTA 449c3959391SKazutaka YOKOTA case PNP_TAG_START_DEPENDANT: 450c3959391SKazutaka YOKOTA if (start != NULL) { 451c3959391SKazutaka YOKOTA /* 452c3959391SKazutaka YOKOTA * Copy the common resources first, 453c3959391SKazutaka YOKOTA * then parse the "dependent" resources. 454c3959391SKazutaka YOKOTA */ 455c3959391SKazutaka YOKOTA pnp_merge_resources(dev, &configs[0], 456c3959391SKazutaka YOKOTA config); 457c3959391SKazutaka YOKOTA pnp_parse_dependant(dev, start, 458c3959391SKazutaka YOKOTA p - start - 1, 459c3959391SKazutaka YOKOTA config, ldn); 460c3959391SKazutaka YOKOTA } 461c3959391SKazutaka YOKOTA start = p + l; 462c3959391SKazutaka YOKOTA if (ncfgs > MAXDEP) { 46318929073SCeri Davies device_printf(parent, "too many dependent configs (%d)\n", MAXDEP); 464c3959391SKazutaka YOKOTA len = 0; 465c3959391SKazutaka YOKOTA break; 466c3959391SKazutaka YOKOTA } 467c3959391SKazutaka YOKOTA config = &configs[ncfgs]; 468c3959391SKazutaka YOKOTA /* 469c3959391SKazutaka YOKOTA * If the priority is not specified, 470c3959391SKazutaka YOKOTA * then use the default of 'acceptable' 471c3959391SKazutaka YOKOTA */ 472c3959391SKazutaka YOKOTA if (l > 0) 473c3959391SKazutaka YOKOTA priorities[ncfgs] = p[0]; 474c3959391SKazutaka YOKOTA else 475c3959391SKazutaka YOKOTA priorities[ncfgs] = 1; 476c3959391SKazutaka YOKOTA if (bootverbose) 477c3959391SKazutaka YOKOTA pnp_printf(id, "start dependent (%d)\n", 478c3959391SKazutaka YOKOTA priorities[ncfgs]); 479c3959391SKazutaka YOKOTA ncfgs++; 480c3959391SKazutaka YOKOTA break; 481c3959391SKazutaka YOKOTA 482c3959391SKazutaka YOKOTA case PNP_TAG_END_DEPENDANT: 483c3959391SKazutaka YOKOTA if (start == NULL) { 484c3959391SKazutaka YOKOTA device_printf(parent, 485c3959391SKazutaka YOKOTA "malformed resources\n"); 486c3959391SKazutaka YOKOTA len = 0; 487c3959391SKazutaka YOKOTA break; 488c3959391SKazutaka YOKOTA } 489c3959391SKazutaka YOKOTA /* 490c3959391SKazutaka YOKOTA * Copy the common resources first, 491c3959391SKazutaka YOKOTA * then parse the "dependent" resources. 492c3959391SKazutaka YOKOTA */ 493c3959391SKazutaka YOKOTA pnp_merge_resources(dev, &configs[0], config); 494c3959391SKazutaka YOKOTA pnp_parse_dependant(dev, start, p - start - 1, 495c3959391SKazutaka YOKOTA config, ldn); 496c3959391SKazutaka YOKOTA start = NULL; 497c3959391SKazutaka YOKOTA if (bootverbose) 498c3959391SKazutaka YOKOTA pnp_printf(id, "end dependent\n"); 499c3959391SKazutaka YOKOTA /* 500c3959391SKazutaka YOKOTA * Back to the common part; clear it 501c3959391SKazutaka YOKOTA * as its contents has already been copied 502*55b05458SPedro F. Giffuni * to each dependent. 503c3959391SKazutaka YOKOTA */ 504c3959391SKazutaka YOKOTA config = &configs[0]; 505c3959391SKazutaka YOKOTA bzero(config, sizeof(*config)); 506c3959391SKazutaka YOKOTA break; 507c3959391SKazutaka YOKOTA 508c3959391SKazutaka YOKOTA case PNP_TAG_END: 509c3959391SKazutaka YOKOTA if (start != NULL) { 510c3959391SKazutaka YOKOTA device_printf(parent, 511c3959391SKazutaka YOKOTA "malformed resources\n"); 512c3959391SKazutaka YOKOTA } 513c3959391SKazutaka YOKOTA len = 0; 514c3959391SKazutaka YOKOTA break; 515c3959391SKazutaka YOKOTA 516c3959391SKazutaka YOKOTA default: 517c3959391SKazutaka YOKOTA if (start != NULL) 518c3959391SKazutaka YOKOTA /* defer parsing a dependent section */ 519c3959391SKazutaka YOKOTA break; 520c3959391SKazutaka YOKOTA if (pnp_parse_desc(dev, tag, p, l, config, ldn)) 521c3959391SKazutaka YOKOTA len = 0; 522c3959391SKazutaka YOKOTA break; 523c3959391SKazutaka YOKOTA } 524c3959391SKazutaka YOKOTA p += l; 525c3959391SKazutaka YOKOTA } else { 526c3959391SKazutaka YOKOTA /* Large resource */ 527c3959391SKazutaka YOKOTA if (len < 2) { 528c3959391SKazutaka YOKOTA len = 0; 529c3959391SKazutaka YOKOTA break; 530c3959391SKazutaka YOKOTA } 531c3959391SKazutaka YOKOTA l = I16(p); 532c3959391SKazutaka YOKOTA p += 2; 533c3959391SKazutaka YOKOTA len -= 2; 534c3959391SKazutaka YOKOTA if (len < l) { 535c3959391SKazutaka YOKOTA len = 0; 536c3959391SKazutaka YOKOTA break; 537c3959391SKazutaka YOKOTA } 538c3959391SKazutaka YOKOTA len -= l; 539c3959391SKazutaka YOKOTA if (start == NULL && 540c3959391SKazutaka YOKOTA pnp_parse_desc(dev, tag, p, l, config, ldn)) { 541c3959391SKazutaka YOKOTA len = 0; 542c3959391SKazutaka YOKOTA break; 543c3959391SKazutaka YOKOTA } 544c3959391SKazutaka YOKOTA p += l; 545c3959391SKazutaka YOKOTA } 546c3959391SKazutaka YOKOTA } 547c3959391SKazutaka YOKOTA 548acd3131bSDoug Rabson if (ncfgs == 1) { 549acd3131bSDoug Rabson /* Single config without dependants */ 550c3959391SKazutaka YOKOTA ISA_ADD_CONFIG(parent, dev, priorities[0], &configs[0]); 551ca403ff8SDoug Rabson free(configs, M_DEVBUF); 552acd3131bSDoug Rabson return; 5535b45337dSDoug Rabson } 554c3959391SKazutaka YOKOTA 555acd3131bSDoug Rabson for (i = 1; i < ncfgs; i++) { 556c3959391SKazutaka YOKOTA /* 557c3959391SKazutaka YOKOTA * Merge the remaining part of the common resources, 558c3959391SKazutaka YOKOTA * if any. Strictly speaking, there shouldn't be common/main 559c3959391SKazutaka YOKOTA * resources after the END_DEPENDENT tag. 560c3959391SKazutaka YOKOTA */ 561c3959391SKazutaka YOKOTA pnp_merge_resources(dev, &configs[0], &configs[i]); 562c3959391SKazutaka YOKOTA ISA_ADD_CONFIG(parent, dev, priorities[i], &configs[i]); 563c3959391SKazutaka YOKOTA } 564c3959391SKazutaka YOKOTA 565ca403ff8SDoug Rabson free(configs, M_DEVBUF); 566acd3131bSDoug Rabson } 567c3959391SKazutaka YOKOTA 568c3959391SKazutaka YOKOTA u_char 569c3959391SKazutaka YOKOTA *pnp_scan_resources(device_t dev, u_char *resources, int len, 570c3959391SKazutaka YOKOTA struct isa_config *config, int ldn, pnp_scan_cb *cb) 571c3959391SKazutaka YOKOTA { 572c3959391SKazutaka YOKOTA u_char *p; 573c3959391SKazutaka YOKOTA u_char tag; 574c3959391SKazutaka YOKOTA int l; 575c3959391SKazutaka YOKOTA 576c3959391SKazutaka YOKOTA p = resources; 577c3959391SKazutaka YOKOTA while (len > 0) { 578c3959391SKazutaka YOKOTA tag = *p++; 579c3959391SKazutaka YOKOTA len--; 580c3959391SKazutaka YOKOTA if (PNP_RES_TYPE(tag) == 0) { 581c3959391SKazutaka YOKOTA /* small resource */ 582c3959391SKazutaka YOKOTA l = PNP_SRES_LEN(tag); 583c3959391SKazutaka YOKOTA if (len < l) 584c3959391SKazutaka YOKOTA break; 585c3959391SKazutaka YOKOTA if ((*cb)(dev, tag, p, l, config, ldn)) 586c3959391SKazutaka YOKOTA return (p + l); 587c3959391SKazutaka YOKOTA if (PNP_SRES_NUM(tag) == PNP_TAG_END) 588c3959391SKazutaka YOKOTA return (p + l); 589c3959391SKazutaka YOKOTA } else { 590c3959391SKazutaka YOKOTA /* large resource */ 591c3959391SKazutaka YOKOTA if (len < 2) 592c3959391SKazutaka YOKOTA break; 593c3959391SKazutaka YOKOTA l = I16(p); 594c3959391SKazutaka YOKOTA p += 2; 595c3959391SKazutaka YOKOTA len -= 2; 596c3959391SKazutaka YOKOTA if (len < l) 597c3959391SKazutaka YOKOTA break; 598c3959391SKazutaka YOKOTA if ((*cb)(dev, tag, p, l, config, ldn)) 599c3959391SKazutaka YOKOTA return (p + l); 600acd3131bSDoug Rabson } 601c3959391SKazutaka YOKOTA p += l; 602c3959391SKazutaka YOKOTA len -= l; 603acd3131bSDoug Rabson } 604c3959391SKazutaka YOKOTA return NULL; 605acd3131bSDoug Rabson } 606