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 * $FreeBSD$ 275b45337dSDoug Rabson */ 285b45337dSDoug Rabson 295b45337dSDoug Rabson #include <sys/param.h> 305b45337dSDoug Rabson #include <sys/systm.h> 31ca403ff8SDoug Rabson #include <sys/malloc.h> 325b45337dSDoug Rabson #include <sys/module.h> 335b45337dSDoug Rabson #include <sys/bus.h> 34c3959391SKazutaka YOKOTA 35c3959391SKazutaka YOKOTA #include <machine/stdarg.h> 36c3959391SKazutaka YOKOTA 375b45337dSDoug Rabson #include <isa/isavar.h> 385b45337dSDoug Rabson #include <isa/pnpreg.h> 395b45337dSDoug Rabson #include <isa/pnpvar.h> 405b45337dSDoug Rabson 41acd3131bSDoug Rabson #define MAXDEP 8 42acd3131bSDoug Rabson 43bb2b9030SDoug Rabson #define I16(p) ((p)[0] + ((p)[1] << 8)) 446dbb527eSPoul-Henning Kamp #define I32(p) (I16(p) + (I16((p)+2) << 16)) 45bb2b9030SDoug Rabson 465b45337dSDoug Rabson void 47c3959391SKazutaka YOKOTA pnp_printf(u_int32_t id, char *fmt, ...) 485b45337dSDoug Rabson { 49c3959391SKazutaka YOKOTA va_list ap; 50c3959391SKazutaka YOKOTA 51c3959391SKazutaka YOKOTA va_start(ap, fmt); 52c3959391SKazutaka YOKOTA printf("%s: ", pnp_eisaformat(id)); 53c3959391SKazutaka YOKOTA vprintf(fmt, ap); 54c3959391SKazutaka YOKOTA va_end(ap); 55c3959391SKazutaka YOKOTA } 56c3959391SKazutaka YOKOTA 57c3959391SKazutaka YOKOTA /* parse a single descriptor */ 58c3959391SKazutaka YOKOTA 59c3959391SKazutaka YOKOTA static int 60c3959391SKazutaka YOKOTA pnp_parse_desc(device_t dev, u_char tag, u_char *res, int len, 61c3959391SKazutaka YOKOTA struct isa_config *config, int ldn) 62c3959391SKazutaka YOKOTA { 635b45337dSDoug Rabson char buf[100]; 64c3959391SKazutaka YOKOTA u_int32_t id; 65c3959391SKazutaka YOKOTA u_int32_t compat_id; 66c3959391SKazutaka YOKOTA int temp; 675b45337dSDoug Rabson 68bb2b9030SDoug Rabson id = isa_get_logicalid(dev); 695b45337dSDoug Rabson 70c3959391SKazutaka YOKOTA if (PNP_RES_TYPE(tag) == 0) { 71c3959391SKazutaka YOKOTA 72c3959391SKazutaka YOKOTA /* Small resource */ 735b45337dSDoug Rabson switch (PNP_SRES_NUM(tag)) { 74c3959391SKazutaka YOKOTA 75c3959391SKazutaka YOKOTA case PNP_TAG_VERSION: 76c3959391SKazutaka YOKOTA case PNP_TAG_VENDOR: 77c3959391SKazutaka YOKOTA /* these descriptors are quietly ignored */ 78c3959391SKazutaka YOKOTA break; 79c3959391SKazutaka YOKOTA 80c3959391SKazutaka YOKOTA case PNP_TAG_LOGICAL_DEVICE: 81c3959391SKazutaka YOKOTA case PNP_TAG_START_DEPENDANT: 82c3959391SKazutaka YOKOTA case PNP_TAG_END_DEPENDANT: 83c3959391SKazutaka YOKOTA if (bootverbose) 84c3959391SKazutaka YOKOTA pnp_printf(id, "unexpected small tag %d\n", 85c3959391SKazutaka YOKOTA PNP_SRES_NUM(tag)); 86c3959391SKazutaka YOKOTA /* shouldn't happen; quit now */ 87c3959391SKazutaka YOKOTA return (1); 88c3959391SKazutaka YOKOTA 895b45337dSDoug Rabson case PNP_TAG_COMPAT_DEVICE: 905b45337dSDoug Rabson /* 91c3959391SKazutaka YOKOTA * Got a compatible device id resource. 92c3959391SKazutaka YOKOTA * Should keep a list of compat ids in the device. 935b45337dSDoug Rabson */ 94c3959391SKazutaka YOKOTA bcopy(res, &compat_id, 4); 95c3959391SKazutaka YOKOTA if (isa_get_compatid(dev) == 0) 965b45337dSDoug Rabson isa_set_compatid(dev, compat_id); 975b45337dSDoug Rabson break; 985b45337dSDoug Rabson 995b45337dSDoug Rabson case PNP_TAG_IRQ_FORMAT: 1005b45337dSDoug Rabson if (config->ic_nirq == ISA_NIRQ) { 101c3959391SKazutaka YOKOTA pnp_printf(id, "too many irqs\n"); 102c3959391SKazutaka YOKOTA return (1); 103c3959391SKazutaka YOKOTA } 104c3959391SKazutaka YOKOTA if (I16(res) == 0) { 105c3959391SKazutaka YOKOTA /* a null descriptor */ 106c3959391SKazutaka YOKOTA config->ic_irqmask[config->ic_nirq] = 0; 107c3959391SKazutaka YOKOTA config->ic_nirq++; 1085b45337dSDoug Rabson break; 1095b45337dSDoug Rabson } 110c3959391SKazutaka YOKOTA if (bootverbose) 111c3959391SKazutaka YOKOTA pnp_printf(id, "adding irq mask %#02x\n", 112c3959391SKazutaka YOKOTA I16(res)); 113c3959391SKazutaka YOKOTA config->ic_irqmask[config->ic_nirq] = I16(res); 1145b45337dSDoug Rabson config->ic_nirq++; 1155b45337dSDoug Rabson break; 1165b45337dSDoug Rabson 1175b45337dSDoug Rabson case PNP_TAG_DMA_FORMAT: 1185b45337dSDoug Rabson if (config->ic_ndrq == ISA_NDRQ) { 119c3959391SKazutaka YOKOTA pnp_printf(id, "too many drqs\n"); 120c3959391SKazutaka YOKOTA return (1); 121c3959391SKazutaka YOKOTA } 122c3959391SKazutaka YOKOTA if (res[0] == 0) { 123c3959391SKazutaka YOKOTA /* a null descriptor */ 124c3959391SKazutaka YOKOTA config->ic_drqmask[config->ic_ndrq] = 0; 125c3959391SKazutaka YOKOTA config->ic_ndrq++; 1265b45337dSDoug Rabson break; 1275b45337dSDoug Rabson } 128c3959391SKazutaka YOKOTA if (bootverbose) 129c3959391SKazutaka YOKOTA pnp_printf(id, "adding dma mask %#02x\n", 130c3959391SKazutaka YOKOTA res[0]); 131c3959391SKazutaka YOKOTA config->ic_drqmask[config->ic_ndrq] = res[0]; 1325b45337dSDoug Rabson config->ic_ndrq++; 1335b45337dSDoug Rabson break; 1345b45337dSDoug Rabson 1355b45337dSDoug Rabson case PNP_TAG_IO_RANGE: 136c3959391SKazutaka YOKOTA if (config->ic_nport == ISA_NPORT) { 137c3959391SKazutaka YOKOTA pnp_printf(id, "too many ports\n"); 138c3959391SKazutaka YOKOTA return (1); 139c3959391SKazutaka YOKOTA } 140c3959391SKazutaka YOKOTA if (res[6] == 0) { 141c3959391SKazutaka YOKOTA /* a null descriptor */ 142c3959391SKazutaka YOKOTA config->ic_port[config->ic_nport].ir_start = 0; 143c3959391SKazutaka YOKOTA config->ic_port[config->ic_nport].ir_end = 0; 144c3959391SKazutaka YOKOTA config->ic_port[config->ic_nport].ir_size = 0; 145c3959391SKazutaka YOKOTA config->ic_port[config->ic_nport].ir_align = 0; 146c3959391SKazutaka YOKOTA config->ic_nport++; 147c3959391SKazutaka YOKOTA break; 148c3959391SKazutaka YOKOTA } 149bb2b9030SDoug Rabson if (bootverbose) { 150c3959391SKazutaka YOKOTA pnp_printf(id, "adding io range " 151bb2b9030SDoug Rabson "%#x-%#x, size=%#x, " 152bb2b9030SDoug Rabson "align=%#x\n", 153c3959391SKazutaka YOKOTA I16(res + 1), 154c3959391SKazutaka YOKOTA I16(res + 3) + res[6]-1, 155c3959391SKazutaka YOKOTA res[6], res[5]); 1565b45337dSDoug Rabson } 1575b45337dSDoug Rabson config->ic_port[config->ic_nport].ir_start = 158c3959391SKazutaka YOKOTA I16(res + 1); 1595b45337dSDoug Rabson config->ic_port[config->ic_nport].ir_end = 160c3959391SKazutaka YOKOTA I16(res + 3) + res[6] - 1; 161c3959391SKazutaka YOKOTA config->ic_port[config->ic_nport].ir_size = res[6]; 162c3959391SKazutaka YOKOTA if (res[5] == 0) { 163bb2b9030SDoug Rabson /* Make sure align is at least one */ 164c3959391SKazutaka YOKOTA res[5] = 1; 165bb2b9030SDoug Rabson } 166c3959391SKazutaka YOKOTA config->ic_port[config->ic_nport].ir_align = res[5]; 1675b45337dSDoug Rabson config->ic_nport++; 168c3959391SKazutaka YOKOTA pnp_check_quirks(isa_get_vendorid(dev), 169c3959391SKazutaka YOKOTA isa_get_logicalid(dev), ldn, config); 1705b45337dSDoug Rabson break; 1715b45337dSDoug Rabson 1725b45337dSDoug Rabson case PNP_TAG_IO_FIXED: 1735b45337dSDoug Rabson if (config->ic_nport == ISA_NPORT) { 174c3959391SKazutaka YOKOTA pnp_printf(id, "too many ports\n"); 175c3959391SKazutaka YOKOTA return (1); 176c3959391SKazutaka YOKOTA } 177c3959391SKazutaka YOKOTA if (res[2] == 0) { 178c3959391SKazutaka YOKOTA /* a null descriptor */ 179c3959391SKazutaka YOKOTA config->ic_port[config->ic_nport].ir_start = 0; 180c3959391SKazutaka YOKOTA config->ic_port[config->ic_nport].ir_end = 0; 181c3959391SKazutaka YOKOTA config->ic_port[config->ic_nport].ir_size = 0; 182c3959391SKazutaka YOKOTA config->ic_port[config->ic_nport].ir_align = 0; 183c3959391SKazutaka YOKOTA config->ic_nport++; 1845b45337dSDoug Rabson break; 1855b45337dSDoug Rabson } 186c3959391SKazutaka YOKOTA if (bootverbose) { 187c3959391SKazutaka YOKOTA pnp_printf(id, "adding fixed io range " 188c3959391SKazutaka YOKOTA "%#x-%#x, size=%#x, " 189c3959391SKazutaka YOKOTA "align=%#x\n", 190c3959391SKazutaka YOKOTA I16(res), 191c3959391SKazutaka YOKOTA I16(res) + res[2] - 1, 192c3959391SKazutaka YOKOTA res[2], 1); 193c3959391SKazutaka YOKOTA } 194c3959391SKazutaka YOKOTA config->ic_port[config->ic_nport].ir_start = I16(res); 1955b45337dSDoug Rabson config->ic_port[config->ic_nport].ir_end = 196c3959391SKazutaka YOKOTA I16(res) + res[2] - 1; 197c3959391SKazutaka YOKOTA config->ic_port[config->ic_nport].ir_size = res[2]; 1985b45337dSDoug Rabson config->ic_port[config->ic_nport].ir_align = 1; 1995b45337dSDoug Rabson config->ic_nport++; 2005b45337dSDoug Rabson break; 2015b45337dSDoug Rabson 202bb2b9030SDoug Rabson case PNP_TAG_END: 203c3959391SKazutaka YOKOTA if (bootverbose) 204c3959391SKazutaka YOKOTA pnp_printf(id, "end config\n"); 205c3959391SKazutaka YOKOTA return (1); 206bb2b9030SDoug Rabson 2075b45337dSDoug Rabson default: 2085b45337dSDoug Rabson /* Skip this resource */ 209c3959391SKazutaka YOKOTA pnp_printf(id, "unexpected small tag %d\n", 2105b45337dSDoug Rabson PNP_SRES_NUM(tag)); 2115b45337dSDoug Rabson break; 2125b45337dSDoug Rabson } 2135b45337dSDoug Rabson } else { 2145b45337dSDoug Rabson /* Large resource */ 215bb2b9030SDoug Rabson switch (PNP_LRES_NUM(tag)) { 216c3959391SKazutaka YOKOTA 217c3959391SKazutaka YOKOTA case PNP_TAG_ID_UNICODE: 218c3959391SKazutaka YOKOTA case PNP_TAG_LARGE_VENDOR: 219c3959391SKazutaka YOKOTA /* these descriptors are quietly ignored */ 220c3959391SKazutaka YOKOTA break; 221c3959391SKazutaka YOKOTA 222bb2b9030SDoug Rabson case PNP_TAG_ID_ANSI: 223c3959391SKazutaka YOKOTA if (len > sizeof(buf) - 1) 224c3959391SKazutaka YOKOTA len = sizeof(buf) - 1; 225c3959391SKazutaka YOKOTA bcopy(res, buf, len); 2265b45337dSDoug Rabson 2275b45337dSDoug Rabson /* 228acd3131bSDoug Rabson * Trim trailing spaces and garbage. 2295b45337dSDoug Rabson */ 230c3959391SKazutaka YOKOTA while (len > 0 && buf[len - 1] <= ' ') 231c3959391SKazutaka YOKOTA len--; 232c3959391SKazutaka YOKOTA buf[len] = '\0'; 2335b45337dSDoug Rabson device_set_desc_copy(dev, buf); 234bb2b9030SDoug Rabson break; 2355b45337dSDoug Rabson 236bb2b9030SDoug Rabson case PNP_TAG_MEMORY_RANGE: 2375b45337dSDoug Rabson if (config->ic_nmem == ISA_NMEM) { 238c3959391SKazutaka YOKOTA pnp_printf(id, "too many memory ranges\n"); 239c3959391SKazutaka YOKOTA return (1); 240c3959391SKazutaka YOKOTA } 241c3959391SKazutaka YOKOTA if (I16(res + 7) == 0) { 242c3959391SKazutaka YOKOTA /* a null descriptor */ 243c3959391SKazutaka YOKOTA config->ic_mem[config->ic_nmem].ir_start = 0; 244c3959391SKazutaka YOKOTA config->ic_mem[config->ic_nmem].ir_end = 0; 245c3959391SKazutaka YOKOTA config->ic_mem[config->ic_nmem].ir_size = 0; 246c3959391SKazutaka YOKOTA config->ic_mem[config->ic_nmem].ir_align = 0; 247c3959391SKazutaka YOKOTA config->ic_nmem++; 2485b45337dSDoug Rabson break; 2495b45337dSDoug Rabson } 250c3959391SKazutaka YOKOTA if (bootverbose) { 251c3959391SKazutaka YOKOTA temp = I16(res + 7) << 8; 252c3959391SKazutaka YOKOTA pnp_printf(id, "adding memory range " 253c3959391SKazutaka YOKOTA "%#x-%#x, size=%#x, " 254c3959391SKazutaka YOKOTA "align=%#x\n", 255c3959391SKazutaka YOKOTA I16(res + 1) << 8, 256c3959391SKazutaka YOKOTA (I16(res + 3) << 8) + temp - 1, 257c3959391SKazutaka YOKOTA temp, I16(res + 5)); 258c3959391SKazutaka YOKOTA } 2595b45337dSDoug Rabson config->ic_mem[config->ic_nmem].ir_start = 260c3959391SKazutaka YOKOTA I16(res + 1) << 8; 2615b45337dSDoug Rabson config->ic_mem[config->ic_nmem].ir_end = 262c3959391SKazutaka YOKOTA (I16(res + 3) << 8) + (I16(res + 7) << 8) - 1; 2635b45337dSDoug Rabson config->ic_mem[config->ic_nmem].ir_size = 264c3959391SKazutaka YOKOTA I16(res + 7) << 8; 265c3959391SKazutaka YOKOTA config->ic_mem[config->ic_nmem].ir_align = I16(res + 5); 2665b45337dSDoug Rabson if (!config->ic_mem[config->ic_nmem].ir_align) 267c3959391SKazutaka YOKOTA config->ic_mem[config->ic_nmem].ir_align = 268c3959391SKazutaka YOKOTA 0x10000; 2695b45337dSDoug Rabson config->ic_nmem++; 270bb2b9030SDoug Rabson break; 271bb2b9030SDoug Rabson 272bb2b9030SDoug Rabson case PNP_TAG_MEMORY32_RANGE: 273bb2b9030SDoug Rabson if (config->ic_nmem == ISA_NMEM) { 274c3959391SKazutaka YOKOTA pnp_printf(id, "too many memory ranges\n"); 275c3959391SKazutaka YOKOTA return (1); 276c3959391SKazutaka YOKOTA } 277c3959391SKazutaka YOKOTA if (I32(res + 13) == 0) { 278c3959391SKazutaka YOKOTA /* a null descriptor */ 279c3959391SKazutaka YOKOTA config->ic_mem[config->ic_nmem].ir_start = 0; 280c3959391SKazutaka YOKOTA config->ic_mem[config->ic_nmem].ir_end = 0; 281c3959391SKazutaka YOKOTA config->ic_mem[config->ic_nmem].ir_size = 0; 282c3959391SKazutaka YOKOTA config->ic_mem[config->ic_nmem].ir_align = 0; 283c3959391SKazutaka YOKOTA config->ic_nmem++; 284bb2b9030SDoug Rabson break; 285bb2b9030SDoug Rabson } 286c3959391SKazutaka YOKOTA if (bootverbose) { 287c3959391SKazutaka YOKOTA pnp_printf(id, "adding memory32 range " 288c3959391SKazutaka YOKOTA "%#x-%#x, size=%#x, " 289c3959391SKazutaka YOKOTA "align=%#x\n", 290c3959391SKazutaka YOKOTA I32(res + 1), 291c3959391SKazutaka YOKOTA I32(res + 5) + I32(res + 13) - 1, 292c3959391SKazutaka YOKOTA I32(res + 13), I32(res + 9)); 293c3959391SKazutaka YOKOTA } 294c3959391SKazutaka YOKOTA config->ic_mem[config->ic_nmem].ir_start = I32(res + 1); 295bb2b9030SDoug Rabson config->ic_mem[config->ic_nmem].ir_end = 296c3959391SKazutaka YOKOTA I32(res + 5) + I32(res + 13) - 1; 297c3959391SKazutaka YOKOTA config->ic_mem[config->ic_nmem].ir_size = I32(res + 13); 298c3959391SKazutaka YOKOTA config->ic_mem[config->ic_nmem].ir_align = I32(res + 9); 299bb2b9030SDoug Rabson config->ic_nmem++; 300bb2b9030SDoug Rabson break; 301bb2b9030SDoug Rabson 302bb2b9030SDoug Rabson case PNP_TAG_MEMORY32_FIXED: 303bb2b9030SDoug Rabson if (config->ic_nmem == ISA_NMEM) { 304c3959391SKazutaka YOKOTA pnp_printf(id, "too many memory ranges\n"); 305c3959391SKazutaka YOKOTA return (1); 306c3959391SKazutaka YOKOTA } 307c3959391SKazutaka YOKOTA if (I32(res + 5) == 0) { 308c3959391SKazutaka YOKOTA /* a null descriptor */ 309c3959391SKazutaka YOKOTA config->ic_mem[config->ic_nmem].ir_start = 0; 310c3959391SKazutaka YOKOTA config->ic_mem[config->ic_nmem].ir_end = 0; 311c3959391SKazutaka YOKOTA config->ic_mem[config->ic_nmem].ir_size = 0; 312c3959391SKazutaka YOKOTA config->ic_mem[config->ic_nmem].ir_align = 0; 313bb2b9030SDoug Rabson break; 314bb2b9030SDoug Rabson } 315c3959391SKazutaka YOKOTA if (bootverbose) { 316c3959391SKazutaka YOKOTA pnp_printf(id, "adding fixed memory32 range " 317c3959391SKazutaka YOKOTA "%#x-%#x, size=%#x\n", 318c3959391SKazutaka YOKOTA I32(res + 1), 319c3959391SKazutaka YOKOTA I32(res + 1) + I32(res + 5) - 1, 320c3959391SKazutaka YOKOTA I32(res + 5)); 321c3959391SKazutaka YOKOTA } 322c3959391SKazutaka YOKOTA config->ic_mem[config->ic_nmem].ir_start = I32(res + 1); 323bb2b9030SDoug Rabson config->ic_mem[config->ic_nmem].ir_end = 324c3959391SKazutaka YOKOTA I32(res + 1) + I32(res + 5) - 1; 325c3959391SKazutaka YOKOTA config->ic_mem[config->ic_nmem].ir_size = I32(res + 5); 326bb2b9030SDoug Rabson config->ic_mem[config->ic_nmem].ir_align = 1; 327bb2b9030SDoug Rabson config->ic_nmem++; 328bb2b9030SDoug Rabson break; 329bb2b9030SDoug Rabson 330bb2b9030SDoug Rabson default: 331bb2b9030SDoug Rabson /* Skip this resource */ 332c3959391SKazutaka YOKOTA pnp_printf(id, "unexpected large tag %d\n", 333bb2b9030SDoug Rabson PNP_SRES_NUM(tag)); 334c3959391SKazutaka YOKOTA break; 335bb2b9030SDoug Rabson } 3365b45337dSDoug Rabson } 337c3959391SKazutaka YOKOTA 338c3959391SKazutaka YOKOTA return (0); 3395b45337dSDoug Rabson } 340c3959391SKazutaka YOKOTA 341c3959391SKazutaka YOKOTA /* 342c3959391SKazutaka YOKOTA * Parse a single "dependent" resource combination. 343c3959391SKazutaka YOKOTA */ 344c3959391SKazutaka YOKOTA 345c3959391SKazutaka YOKOTA u_char 346c3959391SKazutaka YOKOTA *pnp_parse_dependant(device_t dev, u_char *resources, int len, 347c3959391SKazutaka YOKOTA struct isa_config *config, int ldn) 348c3959391SKazutaka YOKOTA { 349c3959391SKazutaka YOKOTA 350c3959391SKazutaka YOKOTA return pnp_scan_resources(dev, resources, len, config, ldn, 351c3959391SKazutaka YOKOTA pnp_parse_desc); 352c3959391SKazutaka YOKOTA } 353c3959391SKazutaka YOKOTA 354c3959391SKazutaka YOKOTA static void 355c3959391SKazutaka YOKOTA pnp_merge_resources(device_t dev, struct isa_config *from, 356c3959391SKazutaka YOKOTA struct isa_config *to) 357c3959391SKazutaka YOKOTA { 358c3959391SKazutaka YOKOTA device_t parent; 359c3959391SKazutaka YOKOTA int i; 360c3959391SKazutaka YOKOTA 361c3959391SKazutaka YOKOTA parent = device_get_parent(dev); 362c3959391SKazutaka YOKOTA for (i = 0; i < from->ic_nmem; i++) { 363c3959391SKazutaka YOKOTA if (to->ic_nmem == ISA_NMEM) { 364c3959391SKazutaka YOKOTA device_printf(parent, "too many memory ranges\n"); 365c3959391SKazutaka YOKOTA return; 366c3959391SKazutaka YOKOTA } 367c3959391SKazutaka YOKOTA to->ic_mem[to->ic_nmem] = from->ic_mem[i]; 368c3959391SKazutaka YOKOTA to->ic_nmem++; 369c3959391SKazutaka YOKOTA } 370c3959391SKazutaka YOKOTA for (i = 0; i < from->ic_nport; i++) { 371c3959391SKazutaka YOKOTA if (to->ic_nport == ISA_NPORT) { 372c3959391SKazutaka YOKOTA device_printf(parent, "too many port ranges\n"); 373c3959391SKazutaka YOKOTA return; 374c3959391SKazutaka YOKOTA } 375c3959391SKazutaka YOKOTA to->ic_port[to->ic_nport] = from->ic_port[i]; 376c3959391SKazutaka YOKOTA to->ic_nport++; 377c3959391SKazutaka YOKOTA } 378c3959391SKazutaka YOKOTA for (i = 0; i < from->ic_nirq; i++) { 379c3959391SKazutaka YOKOTA if (to->ic_nirq == ISA_NIRQ) { 380c3959391SKazutaka YOKOTA device_printf(parent, "too many irq ranges\n"); 381c3959391SKazutaka YOKOTA return; 382c3959391SKazutaka YOKOTA } 383c3959391SKazutaka YOKOTA to->ic_irqmask[to->ic_nirq] = from->ic_irqmask[i]; 384c3959391SKazutaka YOKOTA to->ic_nirq++; 385c3959391SKazutaka YOKOTA } 386c3959391SKazutaka YOKOTA for (i = 0; i < from->ic_ndrq; i++) { 387c3959391SKazutaka YOKOTA if (to->ic_ndrq == ISA_NDRQ) { 388c3959391SKazutaka YOKOTA device_printf(parent, "too many drq ranges\n"); 389c3959391SKazutaka YOKOTA return; 390c3959391SKazutaka YOKOTA } 391c3959391SKazutaka YOKOTA to->ic_drqmask[to->ic_ndrq] = from->ic_drqmask[i]; 392c3959391SKazutaka YOKOTA to->ic_ndrq++; 393c3959391SKazutaka YOKOTA } 394c3959391SKazutaka YOKOTA } 395c3959391SKazutaka YOKOTA 396c3959391SKazutaka YOKOTA /* 397c3959391SKazutaka YOKOTA * Parse resource data for Logical Devices, make a list of available 398c3959391SKazutaka YOKOTA * resource configurations, and add them to the device. 399c3959391SKazutaka YOKOTA * 400c3959391SKazutaka YOKOTA * This function exits as soon as it gets an error reading *ANY* 401c3959391SKazutaka YOKOTA * Resource Data or it reaches the end of Resource Data. 402c3959391SKazutaka YOKOTA */ 403c3959391SKazutaka YOKOTA 404c3959391SKazutaka YOKOTA void 405c3959391SKazutaka YOKOTA pnp_parse_resources(device_t dev, u_char *resources, int len, int ldn) 406c3959391SKazutaka YOKOTA { 407c3959391SKazutaka YOKOTA struct isa_config *configs; 408c3959391SKazutaka YOKOTA struct isa_config *config; 409c3959391SKazutaka YOKOTA device_t parent; 410c3959391SKazutaka YOKOTA int priorities[1 + MAXDEP]; 411c3959391SKazutaka YOKOTA u_char *start; 412c3959391SKazutaka YOKOTA u_char *p; 413c3959391SKazutaka YOKOTA u_char tag; 414c3959391SKazutaka YOKOTA u_int32_t id; 415c3959391SKazutaka YOKOTA int ncfgs; 416c3959391SKazutaka YOKOTA int l; 417c3959391SKazutaka YOKOTA int i; 418c3959391SKazutaka YOKOTA 419c3959391SKazutaka YOKOTA parent = device_get_parent(dev); 420c3959391SKazutaka YOKOTA id = isa_get_logicalid(dev); 421c3959391SKazutaka YOKOTA 422c3959391SKazutaka YOKOTA configs = (struct isa_config *)malloc(sizeof(*configs)*(1 + MAXDEP), 423c3959391SKazutaka YOKOTA M_DEVBUF, M_NOWAIT | M_ZERO); 424c3959391SKazutaka YOKOTA if (configs == NULL) { 425c3959391SKazutaka YOKOTA device_printf(parent, "No memory to parse PNP data\n"); 426c3959391SKazutaka YOKOTA return; 427c3959391SKazutaka YOKOTA } 428c3959391SKazutaka YOKOTA config = &configs[0]; 429c3959391SKazutaka YOKOTA priorities[0] = 0; 430c3959391SKazutaka YOKOTA ncfgs = 1; 431c3959391SKazutaka YOKOTA 432c3959391SKazutaka YOKOTA p = resources; 433c3959391SKazutaka YOKOTA start = NULL; 434c3959391SKazutaka YOKOTA while (len > 0) { 435c3959391SKazutaka YOKOTA tag = *p++; 436c3959391SKazutaka YOKOTA len--; 437c3959391SKazutaka YOKOTA if (PNP_RES_TYPE(tag) == 0) { 438c3959391SKazutaka YOKOTA /* Small resource */ 439c3959391SKazutaka YOKOTA l = PNP_SRES_LEN(tag); 440c3959391SKazutaka YOKOTA if (len < l) { 441c3959391SKazutaka YOKOTA len = 0; 442c3959391SKazutaka YOKOTA continue; 443c3959391SKazutaka YOKOTA } 444c3959391SKazutaka YOKOTA len -= l; 445c3959391SKazutaka YOKOTA 446c3959391SKazutaka YOKOTA switch (PNP_SRES_NUM(tag)) { 447c3959391SKazutaka YOKOTA 448c3959391SKazutaka YOKOTA case PNP_TAG_START_DEPENDANT: 449c3959391SKazutaka YOKOTA if (start != NULL) { 450c3959391SKazutaka YOKOTA /* 451c3959391SKazutaka YOKOTA * Copy the common resources first, 452c3959391SKazutaka YOKOTA * then parse the "dependent" resources. 453c3959391SKazutaka YOKOTA */ 454c3959391SKazutaka YOKOTA pnp_merge_resources(dev, &configs[0], 455c3959391SKazutaka YOKOTA config); 456c3959391SKazutaka YOKOTA pnp_parse_dependant(dev, start, 457c3959391SKazutaka YOKOTA p - start - 1, 458c3959391SKazutaka YOKOTA config, ldn); 459c3959391SKazutaka YOKOTA } 460c3959391SKazutaka YOKOTA start = p + l; 461c3959391SKazutaka YOKOTA if (ncfgs > MAXDEP) { 462c3959391SKazutaka YOKOTA device_printf(parent, "too many dependant configs (%d)\n", MAXDEP); 463c3959391SKazutaka YOKOTA len = 0; 464c3959391SKazutaka YOKOTA break; 465c3959391SKazutaka YOKOTA } 466c3959391SKazutaka YOKOTA config = &configs[ncfgs]; 467c3959391SKazutaka YOKOTA /* 468c3959391SKazutaka YOKOTA * If the priority is not specified, 469c3959391SKazutaka YOKOTA * then use the default of 'acceptable' 470c3959391SKazutaka YOKOTA */ 471c3959391SKazutaka YOKOTA if (l > 0) 472c3959391SKazutaka YOKOTA priorities[ncfgs] = p[0]; 473c3959391SKazutaka YOKOTA else 474c3959391SKazutaka YOKOTA priorities[ncfgs] = 1; 475c3959391SKazutaka YOKOTA if (bootverbose) 476c3959391SKazutaka YOKOTA pnp_printf(id, "start dependent (%d)\n", 477c3959391SKazutaka YOKOTA priorities[ncfgs]); 478c3959391SKazutaka YOKOTA ncfgs++; 479c3959391SKazutaka YOKOTA break; 480c3959391SKazutaka YOKOTA 481c3959391SKazutaka YOKOTA case PNP_TAG_END_DEPENDANT: 482c3959391SKazutaka YOKOTA if (start == NULL) { 483c3959391SKazutaka YOKOTA device_printf(parent, 484c3959391SKazutaka YOKOTA "malformed resources\n"); 485c3959391SKazutaka YOKOTA len = 0; 486c3959391SKazutaka YOKOTA break; 487c3959391SKazutaka YOKOTA } 488c3959391SKazutaka YOKOTA /* 489c3959391SKazutaka YOKOTA * Copy the common resources first, 490c3959391SKazutaka YOKOTA * then parse the "dependent" resources. 491c3959391SKazutaka YOKOTA */ 492c3959391SKazutaka YOKOTA pnp_merge_resources(dev, &configs[0], config); 493c3959391SKazutaka YOKOTA pnp_parse_dependant(dev, start, p - start - 1, 494c3959391SKazutaka YOKOTA config, ldn); 495c3959391SKazutaka YOKOTA start = NULL; 496c3959391SKazutaka YOKOTA if (bootverbose) 497c3959391SKazutaka YOKOTA pnp_printf(id, "end dependent\n"); 498c3959391SKazutaka YOKOTA /* 499c3959391SKazutaka YOKOTA * Back to the common part; clear it 500c3959391SKazutaka YOKOTA * as its contents has already been copied 501c3959391SKazutaka YOKOTA * to each dependant. 502c3959391SKazutaka YOKOTA */ 503c3959391SKazutaka YOKOTA config = &configs[0]; 504c3959391SKazutaka YOKOTA bzero(config, sizeof(*config)); 505c3959391SKazutaka YOKOTA break; 506c3959391SKazutaka YOKOTA 507c3959391SKazutaka YOKOTA case PNP_TAG_END: 508c3959391SKazutaka YOKOTA if (start != NULL) { 509c3959391SKazutaka YOKOTA device_printf(parent, 510c3959391SKazutaka YOKOTA "malformed resources\n"); 511c3959391SKazutaka YOKOTA } 512c3959391SKazutaka YOKOTA len = 0; 513c3959391SKazutaka YOKOTA break; 514c3959391SKazutaka YOKOTA 515c3959391SKazutaka YOKOTA default: 516c3959391SKazutaka YOKOTA if (start != NULL) 517c3959391SKazutaka YOKOTA /* defer parsing a dependent section */ 518c3959391SKazutaka YOKOTA break; 519c3959391SKazutaka YOKOTA if (pnp_parse_desc(dev, tag, p, l, config, ldn)) 520c3959391SKazutaka YOKOTA len = 0; 521c3959391SKazutaka YOKOTA break; 522c3959391SKazutaka YOKOTA } 523c3959391SKazutaka YOKOTA p += l; 524c3959391SKazutaka YOKOTA } else { 525c3959391SKazutaka YOKOTA /* Large resource */ 526c3959391SKazutaka YOKOTA if (len < 2) { 527c3959391SKazutaka YOKOTA len = 0; 528c3959391SKazutaka YOKOTA break; 529c3959391SKazutaka YOKOTA } 530c3959391SKazutaka YOKOTA l = I16(p); 531c3959391SKazutaka YOKOTA p += 2; 532c3959391SKazutaka YOKOTA len -= 2; 533c3959391SKazutaka YOKOTA if (len < l) { 534c3959391SKazutaka YOKOTA len = 0; 535c3959391SKazutaka YOKOTA break; 536c3959391SKazutaka YOKOTA } 537c3959391SKazutaka YOKOTA len -= l; 538c3959391SKazutaka YOKOTA if (start == NULL && 539c3959391SKazutaka YOKOTA pnp_parse_desc(dev, tag, p, l, config, ldn)) { 540c3959391SKazutaka YOKOTA len = 0; 541c3959391SKazutaka YOKOTA break; 542c3959391SKazutaka YOKOTA } 543c3959391SKazutaka YOKOTA p += l; 544c3959391SKazutaka YOKOTA } 545c3959391SKazutaka YOKOTA } 546c3959391SKazutaka YOKOTA 547acd3131bSDoug Rabson if (ncfgs == 1) { 548acd3131bSDoug Rabson /* Single config without dependants */ 549c3959391SKazutaka YOKOTA ISA_ADD_CONFIG(parent, dev, priorities[0], &configs[0]); 550ca403ff8SDoug Rabson free(configs, M_DEVBUF); 551acd3131bSDoug Rabson return; 5525b45337dSDoug Rabson } 553c3959391SKazutaka YOKOTA 554acd3131bSDoug Rabson for (i = 1; i < ncfgs; i++) { 555c3959391SKazutaka YOKOTA /* 556c3959391SKazutaka YOKOTA * Merge the remaining part of the common resources, 557c3959391SKazutaka YOKOTA * if any. Strictly speaking, there shouldn't be common/main 558c3959391SKazutaka YOKOTA * resources after the END_DEPENDENT tag. 559c3959391SKazutaka YOKOTA */ 560c3959391SKazutaka YOKOTA pnp_merge_resources(dev, &configs[0], &configs[i]); 561c3959391SKazutaka YOKOTA ISA_ADD_CONFIG(parent, dev, priorities[i], &configs[i]); 562c3959391SKazutaka YOKOTA } 563c3959391SKazutaka YOKOTA 564ca403ff8SDoug Rabson free(configs, M_DEVBUF); 565acd3131bSDoug Rabson } 566c3959391SKazutaka YOKOTA 567c3959391SKazutaka YOKOTA u_char 568c3959391SKazutaka YOKOTA *pnp_scan_resources(device_t dev, u_char *resources, int len, 569c3959391SKazutaka YOKOTA struct isa_config *config, int ldn, pnp_scan_cb *cb) 570c3959391SKazutaka YOKOTA { 571c3959391SKazutaka YOKOTA u_char *p; 572c3959391SKazutaka YOKOTA u_char tag; 573c3959391SKazutaka YOKOTA int l; 574c3959391SKazutaka YOKOTA 575c3959391SKazutaka YOKOTA p = resources; 576c3959391SKazutaka YOKOTA while (len > 0) { 577c3959391SKazutaka YOKOTA tag = *p++; 578c3959391SKazutaka YOKOTA len--; 579c3959391SKazutaka YOKOTA if (PNP_RES_TYPE(tag) == 0) { 580c3959391SKazutaka YOKOTA /* small resource */ 581c3959391SKazutaka YOKOTA l = PNP_SRES_LEN(tag); 582c3959391SKazutaka YOKOTA if (len < l) 583c3959391SKazutaka YOKOTA break; 584c3959391SKazutaka YOKOTA if ((*cb)(dev, tag, p, l, config, ldn)) 585c3959391SKazutaka YOKOTA return (p + l); 586c3959391SKazutaka YOKOTA if (PNP_SRES_NUM(tag) == PNP_TAG_END) 587c3959391SKazutaka YOKOTA return (p + l); 588c3959391SKazutaka YOKOTA } else { 589c3959391SKazutaka YOKOTA /* large resource */ 590c3959391SKazutaka YOKOTA if (len < 2) 591c3959391SKazutaka YOKOTA break; 592c3959391SKazutaka YOKOTA l = I16(p); 593c3959391SKazutaka YOKOTA p += 2; 594c3959391SKazutaka YOKOTA len -= 2; 595c3959391SKazutaka YOKOTA if (len < l) 596c3959391SKazutaka YOKOTA break; 597c3959391SKazutaka YOKOTA if ((*cb)(dev, tag, p, l, config, ldn)) 598c3959391SKazutaka YOKOTA return (p + l); 599acd3131bSDoug Rabson } 600c3959391SKazutaka YOKOTA p += l; 601c3959391SKazutaka YOKOTA len -= l; 602acd3131bSDoug Rabson } 603c3959391SKazutaka YOKOTA return NULL; 604acd3131bSDoug Rabson } 605