diff options
Diffstat (limited to 'sys/isa/pnpparse.c')
-rw-r--r-- | sys/isa/pnpparse.c | 823 |
1 files changed, 497 insertions, 326 deletions
diff --git a/sys/isa/pnpparse.c b/sys/isa/pnpparse.c index 976b0eb8c0c4f..9efc2fef18bd2 100644 --- a/sys/isa/pnpparse.c +++ b/sys/isa/pnpparse.c @@ -31,6 +31,9 @@ #include <sys/malloc.h> #include <sys/module.h> #include <sys/bus.h> + +#include <machine/stdarg.h> + #include <isa/isavar.h> #include <isa/pnpreg.h> #include <isa/pnpvar.h> @@ -40,394 +43,562 @@ #define I16(p) ((p)[0] + ((p)[1] << 8)) #define I32(p) (I16(p) + (I16(p+2) << 16)) +void +pnp_printf(u_int32_t id, char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + printf("%s: ", pnp_eisaformat(id)); + vprintf(fmt, ap); + va_end(ap); +} + +/* parse a single descriptor */ + +static int +pnp_parse_desc(device_t dev, u_char tag, u_char *res, int len, + struct isa_config *config, int ldn) +{ + char buf[100]; + u_int32_t id; + u_int32_t compat_id; + int temp; + + id = isa_get_logicalid(dev); + + if (PNP_RES_TYPE(tag) == 0) { + + /* Small resource */ + switch (PNP_SRES_NUM(tag)) { + + case PNP_TAG_VERSION: + case PNP_TAG_VENDOR: + /* these descriptors are quietly ignored */ + break; + + case PNP_TAG_LOGICAL_DEVICE: + case PNP_TAG_START_DEPENDANT: + case PNP_TAG_END_DEPENDANT: + if (bootverbose) + pnp_printf(id, "unexpected small tag %d\n", + PNP_SRES_NUM(tag)); + /* shouldn't happen; quit now */ + return (1); + + case PNP_TAG_COMPAT_DEVICE: + /* + * Got a compatible device id resource. + * Should keep a list of compat ids in the device. + */ + bcopy(res, &compat_id, 4); + if (isa_get_compatid(dev) == 0) + isa_set_compatid(dev, compat_id); + break; + + case PNP_TAG_IRQ_FORMAT: + if (config->ic_nirq == ISA_NIRQ) { + pnp_printf(id, "too many irqs\n"); + return (1); + } + if (I16(res) == 0) { + /* a null descriptor */ + config->ic_irqmask[config->ic_nirq] = 0; + config->ic_nirq++; + break; + } + if (bootverbose) + pnp_printf(id, "adding irq mask %#02x\n", + I16(res)); + config->ic_irqmask[config->ic_nirq] = I16(res); + config->ic_nirq++; + break; + + case PNP_TAG_DMA_FORMAT: + if (config->ic_ndrq == ISA_NDRQ) { + pnp_printf(id, "too many drqs\n"); + return (1); + } + if (res[0] == 0) { + /* a null descriptor */ + config->ic_drqmask[config->ic_ndrq] = 0; + config->ic_ndrq++; + break; + } + if (bootverbose) + pnp_printf(id, "adding dma mask %#02x\n", + res[0]); + config->ic_drqmask[config->ic_ndrq] = res[0]; + config->ic_ndrq++; + break; + + case PNP_TAG_IO_RANGE: + if (config->ic_nport == ISA_NPORT) { + pnp_printf(id, "too many ports\n"); + return (1); + } + if (res[6] == 0) { + /* a null descriptor */ + config->ic_port[config->ic_nport].ir_start = 0; + config->ic_port[config->ic_nport].ir_end = 0; + config->ic_port[config->ic_nport].ir_size = 0; + config->ic_port[config->ic_nport].ir_align = 0; + config->ic_nport++; + break; + } + if (bootverbose) { + pnp_printf(id, "adding io range " + "%#x-%#x, size=%#x, " + "align=%#x\n", + I16(res + 1), + I16(res + 3) + res[6]-1, + res[6], res[5]); + } + config->ic_port[config->ic_nport].ir_start = + I16(res + 1); + config->ic_port[config->ic_nport].ir_end = + I16(res + 3) + res[6] - 1; + config->ic_port[config->ic_nport].ir_size = res[6]; + if (res[5] == 0) { + /* Make sure align is at least one */ + res[5] = 1; + } + config->ic_port[config->ic_nport].ir_align = res[5]; + config->ic_nport++; + pnp_check_quirks(isa_get_vendorid(dev), + isa_get_logicalid(dev), ldn, config); + break; + + case PNP_TAG_IO_FIXED: + if (config->ic_nport == ISA_NPORT) { + pnp_printf(id, "too many ports\n"); + return (1); + } + if (res[2] == 0) { + /* a null descriptor */ + config->ic_port[config->ic_nport].ir_start = 0; + config->ic_port[config->ic_nport].ir_end = 0; + config->ic_port[config->ic_nport].ir_size = 0; + config->ic_port[config->ic_nport].ir_align = 0; + config->ic_nport++; + break; + } + if (bootverbose) { + pnp_printf(id, "adding fixed io range " + "%#x-%#x, size=%#x, " + "align=%#x\n", + I16(res), + I16(res) + res[2] - 1, + res[2], 1); + } + config->ic_port[config->ic_nport].ir_start = I16(res); + config->ic_port[config->ic_nport].ir_end = + I16(res) + res[2] - 1; + config->ic_port[config->ic_nport].ir_size = res[2]; + config->ic_port[config->ic_nport].ir_align = 1; + config->ic_nport++; + break; + + case PNP_TAG_END: + if (bootverbose) + pnp_printf(id, "end config\n"); + return (1); + + default: + /* Skip this resource */ + pnp_printf(id, "unexpected small tag %d\n", + PNP_SRES_NUM(tag)); + break; + } + } else { + /* Large resource */ + switch (PNP_LRES_NUM(tag)) { + + case PNP_TAG_ID_UNICODE: + case PNP_TAG_LARGE_VENDOR: + /* these descriptors are quietly ignored */ + break; + + case PNP_TAG_ID_ANSI: + if (len > sizeof(buf) - 1) + len = sizeof(buf) - 1; + bcopy(res, buf, len); + + /* + * Trim trailing spaces and garbage. + */ + while (len > 0 && buf[len - 1] <= ' ') + len--; + buf[len] = '\0'; + device_set_desc_copy(dev, buf); + break; + + case PNP_TAG_MEMORY_RANGE: + if (config->ic_nmem == ISA_NMEM) { + pnp_printf(id, "too many memory ranges\n"); + return (1); + } + if (I16(res + 7) == 0) { + /* a null descriptor */ + config->ic_mem[config->ic_nmem].ir_start = 0; + config->ic_mem[config->ic_nmem].ir_end = 0; + config->ic_mem[config->ic_nmem].ir_size = 0; + config->ic_mem[config->ic_nmem].ir_align = 0; + config->ic_nmem++; + break; + } + if (bootverbose) { + temp = I16(res + 7) << 8; + pnp_printf(id, "adding memory range " + "%#x-%#x, size=%#x, " + "align=%#x\n", + I16(res + 1) << 8, + (I16(res + 3) << 8) + temp - 1, + temp, I16(res + 5)); + } + config->ic_mem[config->ic_nmem].ir_start = + I16(res + 1) << 8; + config->ic_mem[config->ic_nmem].ir_end = + (I16(res + 3) << 8) + (I16(res + 7) << 8) - 1; + config->ic_mem[config->ic_nmem].ir_size = + I16(res + 7) << 8; + config->ic_mem[config->ic_nmem].ir_align = I16(res + 5); + if (!config->ic_mem[config->ic_nmem].ir_align) + config->ic_mem[config->ic_nmem].ir_align = + 0x10000; + config->ic_nmem++; + break; + + case PNP_TAG_MEMORY32_RANGE: + if (config->ic_nmem == ISA_NMEM) { + pnp_printf(id, "too many memory ranges\n"); + return (1); + } + if (I32(res + 13) == 0) { + /* a null descriptor */ + config->ic_mem[config->ic_nmem].ir_start = 0; + config->ic_mem[config->ic_nmem].ir_end = 0; + config->ic_mem[config->ic_nmem].ir_size = 0; + config->ic_mem[config->ic_nmem].ir_align = 0; + config->ic_nmem++; + break; + } + if (bootverbose) { + pnp_printf(id, "adding memory32 range " + "%#x-%#x, size=%#x, " + "align=%#x\n", + I32(res + 1), + I32(res + 5) + I32(res + 13) - 1, + I32(res + 13), I32(res + 9)); + } + config->ic_mem[config->ic_nmem].ir_start = I32(res + 1); + config->ic_mem[config->ic_nmem].ir_end = + I32(res + 5) + I32(res + 13) - 1; + config->ic_mem[config->ic_nmem].ir_size = I32(res + 13); + config->ic_mem[config->ic_nmem].ir_align = I32(res + 9); + config->ic_nmem++; + break; + + case PNP_TAG_MEMORY32_FIXED: + if (config->ic_nmem == ISA_NMEM) { + pnp_printf(id, "too many memory ranges\n"); + return (1); + } + if (I32(res + 5) == 0) { + /* a null descriptor */ + config->ic_mem[config->ic_nmem].ir_start = 0; + config->ic_mem[config->ic_nmem].ir_end = 0; + config->ic_mem[config->ic_nmem].ir_size = 0; + config->ic_mem[config->ic_nmem].ir_align = 0; + break; + } + if (bootverbose) { + pnp_printf(id, "adding fixed memory32 range " + "%#x-%#x, size=%#x\n", + I32(res + 1), + I32(res + 1) + I32(res + 5) - 1, + I32(res + 5)); + } + config->ic_mem[config->ic_nmem].ir_start = I32(res + 1); + config->ic_mem[config->ic_nmem].ir_end = + I32(res + 1) + I32(res + 5) - 1; + config->ic_mem[config->ic_nmem].ir_size = I32(res + 5); + config->ic_mem[config->ic_nmem].ir_align = 1; + config->ic_nmem++; + break; + + default: + /* Skip this resource */ + pnp_printf(id, "unexpected large tag %d\n", + PNP_SRES_NUM(tag)); + break; + } + } + + return (0); +} + +/* + * Parse a single "dependent" resource combination. + */ + +u_char +*pnp_parse_dependant(device_t dev, u_char *resources, int len, + struct isa_config *config, int ldn) +{ + + return pnp_scan_resources(dev, resources, len, config, ldn, + pnp_parse_desc); +} + +static void +pnp_merge_resources(device_t dev, struct isa_config *from, + struct isa_config *to) +{ + device_t parent; + int i; + + parent = device_get_parent(dev); + for (i = 0; i < from->ic_nmem; i++) { + if (to->ic_nmem == ISA_NMEM) { + device_printf(parent, "too many memory ranges\n"); + return; + } + to->ic_mem[to->ic_nmem] = from->ic_mem[i]; + to->ic_nmem++; + } + for (i = 0; i < from->ic_nport; i++) { + if (to->ic_nport == ISA_NPORT) { + device_printf(parent, "too many port ranges\n"); + return; + } + to->ic_port[to->ic_nport] = from->ic_port[i]; + to->ic_nport++; + } + for (i = 0; i < from->ic_nirq; i++) { + if (to->ic_nirq == ISA_NIRQ) { + device_printf(parent, "too many irq ranges\n"); + return; + } + to->ic_irqmask[to->ic_nirq] = from->ic_irqmask[i]; + to->ic_nirq++; + } + for (i = 0; i < from->ic_ndrq; i++) { + if (to->ic_ndrq == ISA_NDRQ) { + device_printf(parent, "too many drq ranges\n"); + return; + } + to->ic_drqmask[to->ic_ndrq] = from->ic_drqmask[i]; + to->ic_ndrq++; + } +} + /* - * Parse resource data for Logical Devices. + * Parse resource data for Logical Devices, make a list of available + * resource configurations, and add them to the device. * * This function exits as soon as it gets an error reading *ANY* * Resource Data or it reaches the end of Resource Data. */ + void -pnp_parse_resources(device_t dev, u_char *resources, int len, u_int32_t vendor_id, u_int32_t logical_id, int ldn) +pnp_parse_resources(device_t dev, u_char *resources, int len, int ldn) { - device_t parent = device_get_parent(dev); - u_char tag, *resp, *resinfo; - int large_len, scanning = len; - u_int32_t id, compat_id; + struct isa_config *configs; struct isa_config *config; - int ncfgs = 1; + device_t parent; int priorities[1 + MAXDEP]; - struct isa_config *configs; - char buf[100]; + u_char *start; + u_char *p; + u_char tag; + u_int32_t id; + int ncfgs; + int l; int i; + parent = device_get_parent(dev); id = isa_get_logicalid(dev); - configs = (struct isa_config *)malloc(sizeof(*configs) * (1 + MAXDEP), - M_DEVBUF, M_NOWAIT | M_ZERO); + + configs = (struct isa_config *)malloc(sizeof(*configs)*(1 + MAXDEP), + M_DEVBUF, M_NOWAIT | M_ZERO); if (configs == NULL) { - device_printf(dev, "No memory to parse PNP data\n"); + device_printf(parent, "No memory to parse PNP data\n"); return; } config = &configs[0]; priorities[0] = 0; - resp = resources; - while (scanning > 0) { - tag = *resp++; - scanning--; + ncfgs = 1; + + p = resources; + start = NULL; + while (len > 0) { + tag = *p++; + len--; if (PNP_RES_TYPE(tag) == 0) { /* Small resource */ - if (scanning < PNP_SRES_LEN(tag)) { - scanning = 0; + l = PNP_SRES_LEN(tag); + if (len < l) { + len = 0; continue; } - resinfo = resp; - resp += PNP_SRES_LEN(tag); - scanning -= PNP_SRES_LEN(tag);; - - switch (PNP_SRES_NUM(tag)) { - case PNP_TAG_COMPAT_DEVICE: - /* - * Got a compatible device id - * resource. Should keep a list of - * compat ids in the device. - */ - bcopy(resinfo, &compat_id, 4); - isa_set_compatid(dev, compat_id); - break; - - case PNP_TAG_IRQ_FORMAT: - if (!I16(resinfo)) - break; - if (bootverbose) { - printf("%s: adding irq mask %#02x\n", - pnp_eisaformat(id), - I16(resinfo)); - } - if (config->ic_nirq == ISA_NIRQ) { - device_printf(parent, "too many irqs\n"); - scanning = 0; - break; - } - config->ic_irqmask[config->ic_nirq] = - I16(resinfo); - config->ic_nirq++; - break; + len -= l; - case PNP_TAG_DMA_FORMAT: - if (bootverbose) { - printf("%s: adding dma mask %#02x\n", - pnp_eisaformat(id), - resinfo[0]); - } - if (config->ic_ndrq == ISA_NDRQ) { - device_printf(parent, "too many drqs\n"); - scanning = 0; - break; - } - config->ic_drqmask[config->ic_ndrq] = - resinfo[0]; - config->ic_ndrq++; - break; + switch (PNP_SRES_NUM(tag)) { case PNP_TAG_START_DEPENDANT: - if (bootverbose) { - printf("%s: start dependant\n", - pnp_eisaformat(id)); + if (start != NULL) { + /* + * Copy the common resources first, + * then parse the "dependent" resources. + */ + pnp_merge_resources(dev, &configs[0], + config); + pnp_parse_dependant(dev, start, + p - start - 1, + config, ldn); } + start = p + l; if (ncfgs > MAXDEP) { device_printf(parent, "too many dependant configs (%d)\n", MAXDEP); - scanning = 0; + len = 0; break; } config = &configs[ncfgs]; /* * If the priority is not specified, - * then use the default of - * 'acceptable' + * then use the default of 'acceptable' */ - if (PNP_SRES_LEN(tag) > 0) - priorities[ncfgs] = resinfo[0]; + if (l > 0) + priorities[ncfgs] = p[0]; else priorities[ncfgs] = 1; + if (bootverbose) + pnp_printf(id, "start dependent (%d)\n", + priorities[ncfgs]); ncfgs++; break; case PNP_TAG_END_DEPENDANT: - if (bootverbose) { - printf("%s: end dependant\n", - pnp_eisaformat(id)); - } - config = &configs[0]; /* back to main config */ - break; - - case PNP_TAG_IO_RANGE: - if (bootverbose) { - printf("%s: adding io range " - "%#x-%#x, size=%#x, " - "align=%#x\n", - pnp_eisaformat(id), - I16(resinfo + 1), - I16(resinfo + 3) + resinfo[6]-1, - resinfo[6], - resinfo[5]); - } - if (config->ic_nport == ISA_NPORT) { - device_printf(parent, "too many ports\n"); - scanning = 0; + if (start == NULL) { + device_printf(parent, + "malformed resources\n"); + len = 0; break; } - config->ic_port[config->ic_nport].ir_start = - I16(resinfo + 1); - config->ic_port[config->ic_nport].ir_end = - I16(resinfo + 3) + resinfo[6] - 1; - config->ic_port[config->ic_nport].ir_size = - resinfo[6]; - if (resinfo[5] == 0) { - /* Make sure align is at least one */ - resinfo[5] = 1; - } - config->ic_port[config->ic_nport].ir_align = - resinfo[5]; - config->ic_nport++; - pnp_check_quirks(vendor_id, - logical_id, - ldn, config); - break; - - case PNP_TAG_IO_FIXED: - if (bootverbose) { - printf("%s: adding fixed io range " - "%#x-%#x, size=%#x, " - "align=%#x\n", - pnp_eisaformat(id), - I16(resinfo), - I16(resinfo) + resinfo[2] - 1, - resinfo[2], - 1); - } - if (config->ic_nport == ISA_NPORT) { - device_printf(parent, "too many ports\n"); - scanning = 0; - break; - } - config->ic_port[config->ic_nport].ir_start = - I16(resinfo); - config->ic_port[config->ic_nport].ir_end = - I16(resinfo) + resinfo[2] - 1; - config->ic_port[config->ic_nport].ir_size - = resinfo[2]; - config->ic_port[config->ic_nport].ir_align = 1; - config->ic_nport++; + /* + * Copy the common resources first, + * then parse the "dependent" resources. + */ + pnp_merge_resources(dev, &configs[0], config); + pnp_parse_dependant(dev, start, p - start - 1, + config, ldn); + start = NULL; + if (bootverbose) + pnp_printf(id, "end dependent\n"); + /* + * Back to the common part; clear it + * as its contents has already been copied + * to each dependant. + */ + config = &configs[0]; + bzero(config, sizeof(*config)); break; case PNP_TAG_END: - if (bootverbose) { - printf("%s: end config\n", - pnp_eisaformat(id)); + if (start != NULL) { + device_printf(parent, + "malformed resources\n"); } - scanning = 0; + len = 0; break; default: - /* Skip this resource */ - device_printf(parent, "unexpected small tag %d\n", - PNP_SRES_NUM(tag)); + if (start != NULL) + /* defer parsing a dependent section */ + break; + if (pnp_parse_desc(dev, tag, p, l, config, ldn)) + len = 0; break; } + p += l; } else { /* Large resource */ - if (scanning < 2) { - scanning = 0; - continue; - } - large_len = I16(resp); - resp += 2; - scanning -= 2; - - if (scanning < large_len) { - scanning = 0; - continue; - } - resinfo = resp; - resp += large_len; - scanning -= large_len; - - switch (PNP_LRES_NUM(tag)) { - case PNP_TAG_ID_ANSI: - if (large_len > sizeof(buf) - 1) - large_len = sizeof(buf) - 1; - bcopy(resinfo, buf, large_len); - - /* - * Trim trailing spaces and garbage. - */ - while (large_len > 0 && buf[large_len - 1] <= ' ') - large_len--; - buf[large_len] = '\0'; - device_set_desc_copy(dev, buf); - break; - - case PNP_TAG_MEMORY_RANGE: - if (bootverbose) { - int temp = I16(resinfo + 7) << 8; - - printf("%s: adding memory range " - "%#x-%#x, size=%#x, " - "align=%#x\n", - pnp_eisaformat(id), - I16(resinfo + 1)<<8, - (I16(resinfo + 3)<<8) + temp - 1, - temp, - I16(resinfo + 5)); - } - - if (config->ic_nmem == ISA_NMEM) { - device_printf(parent, "too many memory ranges\n"); - scanning = 0; - break; - } - - config->ic_mem[config->ic_nmem].ir_start = - I16(resinfo + 1)<<8; - config->ic_mem[config->ic_nmem].ir_end = - (I16(resinfo + 3)<<8) - + (I16(resinfo + 7) << 8) - 1; - config->ic_mem[config->ic_nmem].ir_size = - I16(resinfo + 7) << 8; - config->ic_mem[config->ic_nmem].ir_align = - I16(resinfo + 5); - if (!config->ic_mem[config->ic_nmem].ir_align) - config->ic_mem[config->ic_nmem] - .ir_align = 0x10000; - config->ic_nmem++; + if (len < 2) { + len = 0; break; - - case PNP_TAG_MEMORY32_RANGE: - if (I32(resinfo + 13) == 0) { - if (bootverbose) { - printf("%s: skipping empty range\n", - pnp_eisaformat(id)); - } - continue; - } - if (bootverbose) { - printf("%s: adding memory32 range " - "%#x-%#x, size=%#x, " - "align=%#x\n", - pnp_eisaformat(id), - I32(resinfo + 1), - I32(resinfo + 5) - + I32(resinfo + 13) - 1, - I32(resinfo + 13), - I32(resinfo + 9)); - } - - if (config->ic_nmem == ISA_NMEM) { - device_printf(parent, "too many memory ranges\n"); - scanning = 0; - break; - } - - config->ic_mem[config->ic_nmem].ir_start = - I32(resinfo + 1); - config->ic_mem[config->ic_nmem].ir_end = - I32(resinfo + 5) - + I32(resinfo + 13) - 1; - config->ic_mem[config->ic_nmem].ir_size = - I32(resinfo + 13); - config->ic_mem[config->ic_nmem].ir_align = - I32(resinfo + 9); - config->ic_nmem++; + } + l = I16(p); + p += 2; + len -= 2; + if (len < l) { + len = 0; break; - - case PNP_TAG_MEMORY32_FIXED: - if (I32(resinfo + 5) == 0) { - if (bootverbose) { - printf("%s: skipping empty range\n", - pnp_eisaformat(id)); - } - continue; - } - if (bootverbose) { - printf("%s: adding fixed memory32 range " - "%#x-%#x, size=%#x\n", - pnp_eisaformat(id), - I32(resinfo + 1), - I32(resinfo + 1) - + I32(resinfo + 5) - 1, - I32(resinfo + 5)); - } - - if (config->ic_nmem == ISA_NMEM) { - device_printf(parent, "too many memory ranges\n"); - scanning = 0; - break; - } - - config->ic_mem[config->ic_nmem].ir_start = - I32(resinfo + 1); - config->ic_mem[config->ic_nmem].ir_end = - I32(resinfo + 1) - + I32(resinfo + 5) - 1; - config->ic_mem[config->ic_nmem].ir_size = - I32(resinfo + 5); - config->ic_mem[config->ic_nmem].ir_align = 1; - config->ic_nmem++; + } + len -= l; + if (start == NULL && + pnp_parse_desc(dev, tag, p, l, config, ldn)) { + len = 0; break; - - default: - /* Skip this resource */ - device_printf(parent, "unexpected large tag %d\n", - PNP_SRES_NUM(tag)); } + p += l; } } - if(ncfgs == 1) { + + if (ncfgs == 1) { /* Single config without dependants */ - (void)ISA_ADD_CONFIG(parent, dev, priorities[0], &configs[0]); + ISA_ADD_CONFIG(parent, dev, priorities[0], &configs[0]); free(configs, M_DEVBUF); return; } - /* Cycle through dependant configs merging primary details */ - for(i = 1; i < ncfgs; i++) { - int j; - config = &configs[i]; - for(j = 0; j < configs[0].ic_nmem; j++) { - if (config->ic_nmem == ISA_NMEM) { - device_printf(parent, "too many memory ranges\n"); - free(configs, M_DEVBUF); - return; - } - config->ic_mem[config->ic_nmem] = configs[0].ic_mem[j]; - config->ic_nmem++; - } - for(j = 0; j < configs[0].ic_nport; j++) { - if (config->ic_nport == ISA_NPORT) { - device_printf(parent, "too many port ranges\n"); - free(configs, M_DEVBUF); - return; - } - config->ic_port[config->ic_nport] = configs[0].ic_port[j]; - config->ic_nport++; - } - for(j = 0; j < configs[0].ic_nirq; j++) { - if (config->ic_nirq == ISA_NIRQ) { - device_printf(parent, "too many irq ranges\n"); - free(configs, M_DEVBUF); - return; - } - config->ic_irqmask[config->ic_nirq] = configs[0].ic_irqmask[j]; - config->ic_nirq++; - } - for(j = 0; j < configs[0].ic_ndrq; j++) { - if (config->ic_ndrq == ISA_NDRQ) { - device_printf(parent, "too many drq ranges\n"); - free(configs, M_DEVBUF); - return; - } - config->ic_drqmask[config->ic_ndrq] = configs[0].ic_drqmask[j]; - config->ic_ndrq++; - } - (void)ISA_ADD_CONFIG(parent, dev, priorities[i], &configs[i]); + + for (i = 1; i < ncfgs; i++) { + /* + * Merge the remaining part of the common resources, + * if any. Strictly speaking, there shouldn't be common/main + * resources after the END_DEPENDENT tag. + */ + pnp_merge_resources(dev, &configs[0], &configs[i]); + ISA_ADD_CONFIG(parent, dev, priorities[i], &configs[i]); } + free(configs, M_DEVBUF); } + +u_char +*pnp_scan_resources(device_t dev, u_char *resources, int len, + struct isa_config *config, int ldn, pnp_scan_cb *cb) +{ + u_char *p; + u_char tag; + int l; + + p = resources; + while (len > 0) { + tag = *p++; + len--; + if (PNP_RES_TYPE(tag) == 0) { + /* small resource */ + l = PNP_SRES_LEN(tag); + if (len < l) + break; + if ((*cb)(dev, tag, p, l, config, ldn)) + return (p + l); + if (PNP_SRES_NUM(tag) == PNP_TAG_END) + return (p + l); + } else { + /* large resource */ + if (len < 2) + break; + l = I16(p); + p += 2; + len -= 2; + if (len < l) + break; + if ((*cb)(dev, tag, p, l, config, ldn)) + return (p + l); + } + p += l; + len -= l; + } + return NULL; +} |