152059Sdfr/*- 252059Sdfr * Copyright (c) 1999 Doug Rabson 352059Sdfr * All rights reserved. 452059Sdfr * 552059Sdfr * Redistribution and use in source and binary forms, with or without 652059Sdfr * modification, are permitted provided that the following conditions 752059Sdfr * are met: 852059Sdfr * 1. Redistributions of source code must retain the above copyright 952059Sdfr * notice, this list of conditions and the following disclaimer. 1052059Sdfr * 2. Redistributions in binary form must reproduce the above copyright 1152059Sdfr * notice, this list of conditions and the following disclaimer in the 1252059Sdfr * documentation and/or other materials provided with the distribution. 1352059Sdfr * 1452059Sdfr * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1552059Sdfr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1652059Sdfr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1752059Sdfr * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1852059Sdfr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1952059Sdfr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2052059Sdfr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2152059Sdfr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2252059Sdfr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2352059Sdfr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2452059Sdfr * SUCH DAMAGE. 2552059Sdfr */ 2652059Sdfr 27116181Sobrien#include <sys/cdefs.h> 28116181Sobrien__FBSDID("$FreeBSD$"); 29116181Sobrien 3052059Sdfr#include <sys/param.h> 3152059Sdfr#include <sys/systm.h> 3258873Sdfr#include <sys/malloc.h> 3352059Sdfr#include <sys/module.h> 3452059Sdfr#include <sys/bus.h> 3583051Syokota 3683051Syokota#include <machine/stdarg.h> 3783051Syokota 3852059Sdfr#include <isa/isavar.h> 3952059Sdfr#include <isa/pnpreg.h> 4052059Sdfr#include <isa/pnpvar.h> 4152059Sdfr 4258850Sdfr#define MAXDEP 8 4358850Sdfr 4452241Sdfr#define I16(p) ((p)[0] + ((p)[1] << 8)) 45105220Sphk#define I32(p) (I16(p) + (I16((p)+2) << 16)) 4652241Sdfr 4783051Syokotavoid 4883051Syokotapnp_printf(u_int32_t id, char *fmt, ...) 4983051Syokota{ 5083051Syokota va_list ap; 5183051Syokota 5283051Syokota va_start(ap, fmt); 5383051Syokota printf("%s: ", pnp_eisaformat(id)); 5483051Syokota vprintf(fmt, ap); 5583051Syokota va_end(ap); 5683051Syokota} 5783051Syokota 5883051Syokota/* parse a single descriptor */ 5983051Syokota 6083051Syokotastatic int 6183051Syokotapnp_parse_desc(device_t dev, u_char tag, u_char *res, int len, 6283051Syokota struct isa_config *config, int ldn) 6383051Syokota{ 6483051Syokota char buf[100]; 6583051Syokota u_int32_t id; 6683051Syokota u_int32_t compat_id; 6783051Syokota int temp; 6883051Syokota 6983051Syokota id = isa_get_logicalid(dev); 7083051Syokota 7183051Syokota if (PNP_RES_TYPE(tag) == 0) { 7283051Syokota 7383051Syokota /* Small resource */ 7483051Syokota switch (PNP_SRES_NUM(tag)) { 7583051Syokota 7683051Syokota case PNP_TAG_VERSION: 7783051Syokota case PNP_TAG_VENDOR: 7883051Syokota /* these descriptors are quietly ignored */ 7983051Syokota break; 8083051Syokota 8183051Syokota case PNP_TAG_LOGICAL_DEVICE: 8283051Syokota case PNP_TAG_START_DEPENDANT: 8383051Syokota case PNP_TAG_END_DEPENDANT: 8483051Syokota if (bootverbose) 8583051Syokota pnp_printf(id, "unexpected small tag %d\n", 8683051Syokota PNP_SRES_NUM(tag)); 8783051Syokota /* shouldn't happen; quit now */ 8883051Syokota return (1); 8983051Syokota 9083051Syokota case PNP_TAG_COMPAT_DEVICE: 9183051Syokota /* 9283051Syokota * Got a compatible device id resource. 9383051Syokota * Should keep a list of compat ids in the device. 9483051Syokota */ 9583051Syokota bcopy(res, &compat_id, 4); 9683051Syokota if (isa_get_compatid(dev) == 0) 9783051Syokota isa_set_compatid(dev, compat_id); 9883051Syokota break; 9983051Syokota 10083051Syokota case PNP_TAG_IRQ_FORMAT: 10183051Syokota if (config->ic_nirq == ISA_NIRQ) { 10283051Syokota pnp_printf(id, "too many irqs\n"); 10383051Syokota return (1); 10483051Syokota } 10583051Syokota if (I16(res) == 0) { 10683051Syokota /* a null descriptor */ 10783051Syokota config->ic_irqmask[config->ic_nirq] = 0; 10883051Syokota config->ic_nirq++; 10983051Syokota break; 11083051Syokota } 11183051Syokota if (bootverbose) 11283051Syokota pnp_printf(id, "adding irq mask %#02x\n", 11383051Syokota I16(res)); 11483051Syokota config->ic_irqmask[config->ic_nirq] = I16(res); 11583051Syokota config->ic_nirq++; 11683051Syokota break; 11783051Syokota 11883051Syokota case PNP_TAG_DMA_FORMAT: 11983051Syokota if (config->ic_ndrq == ISA_NDRQ) { 12083051Syokota pnp_printf(id, "too many drqs\n"); 12183051Syokota return (1); 12283051Syokota } 12383051Syokota if (res[0] == 0) { 12483051Syokota /* a null descriptor */ 12583051Syokota config->ic_drqmask[config->ic_ndrq] = 0; 12683051Syokota config->ic_ndrq++; 12783051Syokota break; 12883051Syokota } 12983051Syokota if (bootverbose) 13083051Syokota pnp_printf(id, "adding dma mask %#02x\n", 13183051Syokota res[0]); 13283051Syokota config->ic_drqmask[config->ic_ndrq] = res[0]; 13383051Syokota config->ic_ndrq++; 13483051Syokota break; 13583051Syokota 13683051Syokota case PNP_TAG_IO_RANGE: 13783051Syokota if (config->ic_nport == ISA_NPORT) { 13883051Syokota pnp_printf(id, "too many ports\n"); 13983051Syokota return (1); 14083051Syokota } 14183051Syokota if (res[6] == 0) { 14283051Syokota /* a null descriptor */ 14383051Syokota config->ic_port[config->ic_nport].ir_start = 0; 14483051Syokota config->ic_port[config->ic_nport].ir_end = 0; 14583051Syokota config->ic_port[config->ic_nport].ir_size = 0; 14683051Syokota config->ic_port[config->ic_nport].ir_align = 0; 14783051Syokota config->ic_nport++; 14883051Syokota break; 14983051Syokota } 15083051Syokota if (bootverbose) { 15183051Syokota pnp_printf(id, "adding io range " 15283051Syokota "%#x-%#x, size=%#x, " 15383051Syokota "align=%#x\n", 15483051Syokota I16(res + 1), 15583051Syokota I16(res + 3) + res[6]-1, 15683051Syokota res[6], res[5]); 15783051Syokota } 15883051Syokota config->ic_port[config->ic_nport].ir_start = 15983051Syokota I16(res + 1); 16083051Syokota config->ic_port[config->ic_nport].ir_end = 16183051Syokota I16(res + 3) + res[6] - 1; 16283051Syokota config->ic_port[config->ic_nport].ir_size = res[6]; 16383051Syokota if (res[5] == 0) { 16483051Syokota /* Make sure align is at least one */ 16583051Syokota res[5] = 1; 16683051Syokota } 16783051Syokota config->ic_port[config->ic_nport].ir_align = res[5]; 16883051Syokota config->ic_nport++; 16983051Syokota pnp_check_quirks(isa_get_vendorid(dev), 17083051Syokota isa_get_logicalid(dev), ldn, config); 17183051Syokota break; 17283051Syokota 17383051Syokota case PNP_TAG_IO_FIXED: 17483051Syokota if (config->ic_nport == ISA_NPORT) { 17583051Syokota pnp_printf(id, "too many ports\n"); 17683051Syokota return (1); 17783051Syokota } 17883051Syokota if (res[2] == 0) { 17983051Syokota /* a null descriptor */ 18083051Syokota config->ic_port[config->ic_nport].ir_start = 0; 18183051Syokota config->ic_port[config->ic_nport].ir_end = 0; 18283051Syokota config->ic_port[config->ic_nport].ir_size = 0; 18383051Syokota config->ic_port[config->ic_nport].ir_align = 0; 18483051Syokota config->ic_nport++; 18583051Syokota break; 18683051Syokota } 18783051Syokota if (bootverbose) { 18883051Syokota pnp_printf(id, "adding fixed io range " 18983051Syokota "%#x-%#x, size=%#x, " 19083051Syokota "align=%#x\n", 19183051Syokota I16(res), 19283051Syokota I16(res) + res[2] - 1, 19383051Syokota res[2], 1); 19483051Syokota } 19583051Syokota config->ic_port[config->ic_nport].ir_start = I16(res); 19683051Syokota config->ic_port[config->ic_nport].ir_end = 19783051Syokota I16(res) + res[2] - 1; 19883051Syokota config->ic_port[config->ic_nport].ir_size = res[2]; 19983051Syokota config->ic_port[config->ic_nport].ir_align = 1; 20083051Syokota config->ic_nport++; 20183051Syokota break; 20283051Syokota 20383051Syokota case PNP_TAG_END: 20483051Syokota if (bootverbose) 20583051Syokota pnp_printf(id, "end config\n"); 20683051Syokota return (1); 20783051Syokota 20883051Syokota default: 20983051Syokota /* Skip this resource */ 21083051Syokota pnp_printf(id, "unexpected small tag %d\n", 21183051Syokota PNP_SRES_NUM(tag)); 21283051Syokota break; 21383051Syokota } 21483051Syokota } else { 21583051Syokota /* Large resource */ 21683051Syokota switch (PNP_LRES_NUM(tag)) { 21783051Syokota 21883051Syokota case PNP_TAG_ID_UNICODE: 21983051Syokota case PNP_TAG_LARGE_VENDOR: 22083051Syokota /* these descriptors are quietly ignored */ 22183051Syokota break; 22283051Syokota 22383051Syokota case PNP_TAG_ID_ANSI: 22483051Syokota if (len > sizeof(buf) - 1) 22583051Syokota len = sizeof(buf) - 1; 22683051Syokota bcopy(res, buf, len); 22783051Syokota 22883051Syokota /* 22983051Syokota * Trim trailing spaces and garbage. 23083051Syokota */ 23183051Syokota while (len > 0 && buf[len - 1] <= ' ') 23283051Syokota len--; 23383051Syokota buf[len] = '\0'; 23483051Syokota device_set_desc_copy(dev, buf); 23583051Syokota break; 23683051Syokota 23783051Syokota case PNP_TAG_MEMORY_RANGE: 23883051Syokota if (config->ic_nmem == ISA_NMEM) { 23983051Syokota pnp_printf(id, "too many memory ranges\n"); 24083051Syokota return (1); 24183051Syokota } 24283051Syokota if (I16(res + 7) == 0) { 24383051Syokota /* a null descriptor */ 24483051Syokota config->ic_mem[config->ic_nmem].ir_start = 0; 24583051Syokota config->ic_mem[config->ic_nmem].ir_end = 0; 24683051Syokota config->ic_mem[config->ic_nmem].ir_size = 0; 24783051Syokota config->ic_mem[config->ic_nmem].ir_align = 0; 24883051Syokota config->ic_nmem++; 24983051Syokota break; 25083051Syokota } 25183051Syokota if (bootverbose) { 25283051Syokota temp = I16(res + 7) << 8; 25383051Syokota pnp_printf(id, "adding memory range " 25483051Syokota "%#x-%#x, size=%#x, " 25583051Syokota "align=%#x\n", 25683051Syokota I16(res + 1) << 8, 25783051Syokota (I16(res + 3) << 8) + temp - 1, 25883051Syokota temp, I16(res + 5)); 25983051Syokota } 26083051Syokota config->ic_mem[config->ic_nmem].ir_start = 26183051Syokota I16(res + 1) << 8; 26283051Syokota config->ic_mem[config->ic_nmem].ir_end = 26383051Syokota (I16(res + 3) << 8) + (I16(res + 7) << 8) - 1; 26483051Syokota config->ic_mem[config->ic_nmem].ir_size = 26583051Syokota I16(res + 7) << 8; 26683051Syokota config->ic_mem[config->ic_nmem].ir_align = I16(res + 5); 26783051Syokota if (!config->ic_mem[config->ic_nmem].ir_align) 26883051Syokota config->ic_mem[config->ic_nmem].ir_align = 26983051Syokota 0x10000; 27083051Syokota config->ic_nmem++; 27183051Syokota break; 27283051Syokota 27383051Syokota case PNP_TAG_MEMORY32_RANGE: 27483051Syokota if (config->ic_nmem == ISA_NMEM) { 27583051Syokota pnp_printf(id, "too many memory ranges\n"); 27683051Syokota return (1); 27783051Syokota } 27883051Syokota if (I32(res + 13) == 0) { 27983051Syokota /* a null descriptor */ 28083051Syokota config->ic_mem[config->ic_nmem].ir_start = 0; 28183051Syokota config->ic_mem[config->ic_nmem].ir_end = 0; 28283051Syokota config->ic_mem[config->ic_nmem].ir_size = 0; 28383051Syokota config->ic_mem[config->ic_nmem].ir_align = 0; 28483051Syokota config->ic_nmem++; 28583051Syokota break; 28683051Syokota } 28783051Syokota if (bootverbose) { 28883051Syokota pnp_printf(id, "adding memory32 range " 28983051Syokota "%#x-%#x, size=%#x, " 29083051Syokota "align=%#x\n", 29183051Syokota I32(res + 1), 29283051Syokota I32(res + 5) + I32(res + 13) - 1, 29383051Syokota I32(res + 13), I32(res + 9)); 29483051Syokota } 29583051Syokota config->ic_mem[config->ic_nmem].ir_start = I32(res + 1); 29683051Syokota config->ic_mem[config->ic_nmem].ir_end = 29783051Syokota I32(res + 5) + I32(res + 13) - 1; 29883051Syokota config->ic_mem[config->ic_nmem].ir_size = I32(res + 13); 29983051Syokota config->ic_mem[config->ic_nmem].ir_align = I32(res + 9); 30083051Syokota config->ic_nmem++; 30183051Syokota break; 30283051Syokota 30383051Syokota case PNP_TAG_MEMORY32_FIXED: 30483051Syokota if (config->ic_nmem == ISA_NMEM) { 30583051Syokota pnp_printf(id, "too many memory ranges\n"); 30683051Syokota return (1); 30783051Syokota } 30883051Syokota if (I32(res + 5) == 0) { 30983051Syokota /* a null descriptor */ 31083051Syokota config->ic_mem[config->ic_nmem].ir_start = 0; 31183051Syokota config->ic_mem[config->ic_nmem].ir_end = 0; 31283051Syokota config->ic_mem[config->ic_nmem].ir_size = 0; 31383051Syokota config->ic_mem[config->ic_nmem].ir_align = 0; 31483051Syokota break; 31583051Syokota } 31683051Syokota if (bootverbose) { 31783051Syokota pnp_printf(id, "adding fixed memory32 range " 31883051Syokota "%#x-%#x, size=%#x\n", 31983051Syokota I32(res + 1), 32083051Syokota I32(res + 1) + I32(res + 5) - 1, 32183051Syokota I32(res + 5)); 32283051Syokota } 32383051Syokota config->ic_mem[config->ic_nmem].ir_start = I32(res + 1); 32483051Syokota config->ic_mem[config->ic_nmem].ir_end = 32583051Syokota I32(res + 1) + I32(res + 5) - 1; 32683051Syokota config->ic_mem[config->ic_nmem].ir_size = I32(res + 5); 32783051Syokota config->ic_mem[config->ic_nmem].ir_align = 1; 32883051Syokota config->ic_nmem++; 32983051Syokota break; 33083051Syokota 33183051Syokota default: 33283051Syokota /* Skip this resource */ 33383051Syokota pnp_printf(id, "unexpected large tag %d\n", 33483051Syokota PNP_SRES_NUM(tag)); 33583051Syokota break; 33683051Syokota } 33783051Syokota } 33883051Syokota 33983051Syokota return (0); 34083051Syokota} 34183051Syokota 34252059Sdfr/* 34383051Syokota * Parse a single "dependent" resource combination. 34483051Syokota */ 34583051Syokota 34683051Syokotau_char 34783051Syokota*pnp_parse_dependant(device_t dev, u_char *resources, int len, 34883051Syokota struct isa_config *config, int ldn) 34983051Syokota{ 35083051Syokota 35183051Syokota return pnp_scan_resources(dev, resources, len, config, ldn, 35283051Syokota pnp_parse_desc); 35383051Syokota} 35483051Syokota 35583051Syokotastatic void 35683051Syokotapnp_merge_resources(device_t dev, struct isa_config *from, 35783051Syokota struct isa_config *to) 35883051Syokota{ 35983051Syokota device_t parent; 36083051Syokota int i; 36183051Syokota 36283051Syokota parent = device_get_parent(dev); 36383051Syokota for (i = 0; i < from->ic_nmem; i++) { 36483051Syokota if (to->ic_nmem == ISA_NMEM) { 36583051Syokota device_printf(parent, "too many memory ranges\n"); 36683051Syokota return; 36783051Syokota } 36883051Syokota to->ic_mem[to->ic_nmem] = from->ic_mem[i]; 36983051Syokota to->ic_nmem++; 37083051Syokota } 37183051Syokota for (i = 0; i < from->ic_nport; i++) { 37283051Syokota if (to->ic_nport == ISA_NPORT) { 37383051Syokota device_printf(parent, "too many port ranges\n"); 37483051Syokota return; 37583051Syokota } 37683051Syokota to->ic_port[to->ic_nport] = from->ic_port[i]; 37783051Syokota to->ic_nport++; 37883051Syokota } 37983051Syokota for (i = 0; i < from->ic_nirq; i++) { 38083051Syokota if (to->ic_nirq == ISA_NIRQ) { 38183051Syokota device_printf(parent, "too many irq ranges\n"); 38283051Syokota return; 38383051Syokota } 38483051Syokota to->ic_irqmask[to->ic_nirq] = from->ic_irqmask[i]; 38583051Syokota to->ic_nirq++; 38683051Syokota } 38783051Syokota for (i = 0; i < from->ic_ndrq; i++) { 38883051Syokota if (to->ic_ndrq == ISA_NDRQ) { 38983051Syokota device_printf(parent, "too many drq ranges\n"); 39083051Syokota return; 39183051Syokota } 39283051Syokota to->ic_drqmask[to->ic_ndrq] = from->ic_drqmask[i]; 39383051Syokota to->ic_ndrq++; 39483051Syokota } 39583051Syokota} 39683051Syokota 39783051Syokota/* 39883051Syokota * Parse resource data for Logical Devices, make a list of available 39983051Syokota * resource configurations, and add them to the device. 40052059Sdfr * 40152059Sdfr * This function exits as soon as it gets an error reading *ANY* 40258850Sdfr * Resource Data or it reaches the end of Resource Data. 40352059Sdfr */ 40483051Syokota 40552059Sdfrvoid 40683051Syokotapnp_parse_resources(device_t dev, u_char *resources, int len, int ldn) 40752059Sdfr{ 40883051Syokota struct isa_config *configs; 40952059Sdfr struct isa_config *config; 41083051Syokota device_t parent; 41158850Sdfr int priorities[1 + MAXDEP]; 41283051Syokota u_char *start; 41383051Syokota u_char *p; 41483051Syokota u_char tag; 41583051Syokota u_int32_t id; 41683051Syokota int ncfgs; 41783051Syokota int l; 41858850Sdfr int i; 41952059Sdfr 42083051Syokota parent = device_get_parent(dev); 42152241Sdfr id = isa_get_logicalid(dev); 42283051Syokota 42383051Syokota configs = (struct isa_config *)malloc(sizeof(*configs)*(1 + MAXDEP), 42483051Syokota M_DEVBUF, M_NOWAIT | M_ZERO); 42558873Sdfr if (configs == NULL) { 42683051Syokota device_printf(parent, "No memory to parse PNP data\n"); 42758873Sdfr return; 42858873Sdfr } 42958850Sdfr config = &configs[0]; 43058850Sdfr priorities[0] = 0; 43183051Syokota ncfgs = 1; 43283051Syokota 43383051Syokota p = resources; 43483051Syokota start = NULL; 43583051Syokota while (len > 0) { 43683051Syokota tag = *p++; 43783051Syokota len--; 43852059Sdfr if (PNP_RES_TYPE(tag) == 0) { 43952059Sdfr /* Small resource */ 44083051Syokota l = PNP_SRES_LEN(tag); 44183051Syokota if (len < l) { 44283051Syokota len = 0; 44352059Sdfr continue; 44452059Sdfr } 44583051Syokota len -= l; 44683051Syokota 44752059Sdfr switch (PNP_SRES_NUM(tag)) { 44852059Sdfr 44952059Sdfr case PNP_TAG_START_DEPENDANT: 45083051Syokota if (start != NULL) { 45183051Syokota /* 45283051Syokota * Copy the common resources first, 45383051Syokota * then parse the "dependent" resources. 45483051Syokota */ 45583051Syokota pnp_merge_resources(dev, &configs[0], 45683051Syokota config); 45783051Syokota pnp_parse_dependant(dev, start, 45883051Syokota p - start - 1, 45983051Syokota config, ldn); 46052241Sdfr } 46183051Syokota start = p + l; 46259002Sdfr if (ncfgs > MAXDEP) { 463165654Sceri device_printf(parent, "too many dependent configs (%d)\n", MAXDEP); 46483051Syokota len = 0; 46552059Sdfr break; 46652059Sdfr } 46758850Sdfr config = &configs[ncfgs]; 46852059Sdfr /* 46952059Sdfr * If the priority is not specified, 47083051Syokota * then use the default of 'acceptable' 47152059Sdfr */ 47283051Syokota if (l > 0) 47383051Syokota priorities[ncfgs] = p[0]; 47452059Sdfr else 47558850Sdfr priorities[ncfgs] = 1; 47683051Syokota if (bootverbose) 47783051Syokota pnp_printf(id, "start dependent (%d)\n", 47883051Syokota priorities[ncfgs]); 47958850Sdfr ncfgs++; 48052059Sdfr break; 48152059Sdfr 48252059Sdfr case PNP_TAG_END_DEPENDANT: 48383051Syokota if (start == NULL) { 48483051Syokota device_printf(parent, 48583051Syokota "malformed resources\n"); 48683051Syokota len = 0; 48752059Sdfr break; 48852059Sdfr } 48983051Syokota /* 49083051Syokota * Copy the common resources first, 49183051Syokota * then parse the "dependent" resources. 49283051Syokota */ 49383051Syokota pnp_merge_resources(dev, &configs[0], config); 49483051Syokota pnp_parse_dependant(dev, start, p - start - 1, 49583051Syokota config, ldn); 49683051Syokota start = NULL; 49783051Syokota if (bootverbose) 49883051Syokota pnp_printf(id, "end dependent\n"); 49983051Syokota /* 50083051Syokota * Back to the common part; clear it 50183051Syokota * as its contents has already been copied 50283051Syokota * to each dependant. 50383051Syokota */ 50483051Syokota config = &configs[0]; 50583051Syokota bzero(config, sizeof(*config)); 50652059Sdfr break; 50752059Sdfr 50852241Sdfr case PNP_TAG_END: 50983051Syokota if (start != NULL) { 51083051Syokota device_printf(parent, 51183051Syokota "malformed resources\n"); 51252241Sdfr } 51383051Syokota len = 0; 51452241Sdfr break; 51552241Sdfr 51652059Sdfr default: 51783051Syokota if (start != NULL) 51883051Syokota /* defer parsing a dependent section */ 51983051Syokota break; 52083051Syokota if (pnp_parse_desc(dev, tag, p, l, config, ldn)) 52183051Syokota len = 0; 52252059Sdfr break; 52352059Sdfr } 52483051Syokota p += l; 52552059Sdfr } else { 52652059Sdfr /* Large resource */ 52783051Syokota if (len < 2) { 52883051Syokota len = 0; 52983051Syokota break; 53052059Sdfr } 53183051Syokota l = I16(p); 53283051Syokota p += 2; 53383051Syokota len -= 2; 53483051Syokota if (len < l) { 53583051Syokota len = 0; 53683051Syokota break; 53752059Sdfr } 53883051Syokota len -= l; 53983051Syokota if (start == NULL && 54083051Syokota pnp_parse_desc(dev, tag, p, l, config, ldn)) { 54183051Syokota len = 0; 54252241Sdfr break; 54352241Sdfr } 54483051Syokota p += l; 54552059Sdfr } 54652059Sdfr } 54783051Syokota 54883051Syokota if (ncfgs == 1) { 54958850Sdfr /* Single config without dependants */ 55083051Syokota ISA_ADD_CONFIG(parent, dev, priorities[0], &configs[0]); 55158873Sdfr free(configs, M_DEVBUF); 55258850Sdfr return; 55358850Sdfr } 55483051Syokota 55583051Syokota for (i = 1; i < ncfgs; i++) { 55683051Syokota /* 55783051Syokota * Merge the remaining part of the common resources, 55883051Syokota * if any. Strictly speaking, there shouldn't be common/main 55983051Syokota * resources after the END_DEPENDENT tag. 56083051Syokota */ 56183051Syokota pnp_merge_resources(dev, &configs[0], &configs[i]); 56283051Syokota ISA_ADD_CONFIG(parent, dev, priorities[i], &configs[i]); 56358850Sdfr } 56483051Syokota 56558873Sdfr free(configs, M_DEVBUF); 56652059Sdfr} 56783051Syokota 56883051Syokotau_char 56983051Syokota*pnp_scan_resources(device_t dev, u_char *resources, int len, 57083051Syokota struct isa_config *config, int ldn, pnp_scan_cb *cb) 57183051Syokota{ 57283051Syokota u_char *p; 57383051Syokota u_char tag; 57483051Syokota int l; 57583051Syokota 57683051Syokota p = resources; 57783051Syokota while (len > 0) { 57883051Syokota tag = *p++; 57983051Syokota len--; 58083051Syokota if (PNP_RES_TYPE(tag) == 0) { 58183051Syokota /* small resource */ 58283051Syokota l = PNP_SRES_LEN(tag); 58383051Syokota if (len < l) 58483051Syokota break; 58583051Syokota if ((*cb)(dev, tag, p, l, config, ldn)) 58683051Syokota return (p + l); 58783051Syokota if (PNP_SRES_NUM(tag) == PNP_TAG_END) 58883051Syokota return (p + l); 58983051Syokota } else { 59083051Syokota /* large resource */ 59183051Syokota if (len < 2) 59283051Syokota break; 59383051Syokota l = I16(p); 59483051Syokota p += 2; 59583051Syokota len -= 2; 59683051Syokota if (len < l) 59783051Syokota break; 59883051Syokota if ((*cb)(dev, tag, p, l, config, ldn)) 59983051Syokota return (p + l); 60083051Syokota } 60183051Syokota p += l; 60283051Syokota len -= l; 60383051Syokota } 60483051Syokota return NULL; 60583051Syokota} 606