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