pnpparse.c revision 105220
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 *	$FreeBSD: head/sys/isa/pnpparse.c 105220 2002-10-16 09:07:30Z phk $
2752059Sdfr */
2852059Sdfr
2952059Sdfr#include <sys/param.h>
3052059Sdfr#include <sys/systm.h>
3158873Sdfr#include <sys/malloc.h>
3252059Sdfr#include <sys/module.h>
3352059Sdfr#include <sys/bus.h>
3483051Syokota
3583051Syokota#include <machine/stdarg.h>
3683051Syokota
3752059Sdfr#include <isa/isavar.h>
3852059Sdfr#include <isa/pnpreg.h>
3952059Sdfr#include <isa/pnpvar.h>
4052059Sdfr
4158850Sdfr#define	MAXDEP	8
4258850Sdfr
4352241Sdfr#define I16(p)	((p)[0] + ((p)[1] << 8))
44105220Sphk#define I32(p)	(I16(p) + (I16((p)+2) << 16))
4552241Sdfr
4683051Syokotavoid
4783051Syokotapnp_printf(u_int32_t id, char *fmt, ...)
4883051Syokota{
4983051Syokota	va_list ap;
5083051Syokota
5183051Syokota	va_start(ap, fmt);
5283051Syokota	printf("%s: ", pnp_eisaformat(id));
5383051Syokota	vprintf(fmt, ap);
5483051Syokota	va_end(ap);
5583051Syokota}
5683051Syokota
5783051Syokota/* parse a single descriptor */
5883051Syokota
5983051Syokotastatic int
6083051Syokotapnp_parse_desc(device_t dev, u_char tag, u_char *res, int len,
6183051Syokota	       struct isa_config *config, int ldn)
6283051Syokota{
6383051Syokota	char buf[100];
6483051Syokota	u_int32_t id;
6583051Syokota	u_int32_t compat_id;
6683051Syokota	int temp;
6783051Syokota
6883051Syokota	id = isa_get_logicalid(dev);
6983051Syokota
7083051Syokota	if (PNP_RES_TYPE(tag) == 0) {
7183051Syokota
7283051Syokota		/* Small resource */
7383051Syokota		switch (PNP_SRES_NUM(tag)) {
7483051Syokota
7583051Syokota		case PNP_TAG_VERSION:
7683051Syokota		case PNP_TAG_VENDOR:
7783051Syokota			/* these descriptors are quietly ignored */
7883051Syokota			break;
7983051Syokota
8083051Syokota		case PNP_TAG_LOGICAL_DEVICE:
8183051Syokota		case PNP_TAG_START_DEPENDANT:
8283051Syokota		case PNP_TAG_END_DEPENDANT:
8383051Syokota			if (bootverbose)
8483051Syokota				pnp_printf(id, "unexpected small tag %d\n",
8583051Syokota					   PNP_SRES_NUM(tag));
8683051Syokota			/* shouldn't happen; quit now */
8783051Syokota			return (1);
8883051Syokota
8983051Syokota		case PNP_TAG_COMPAT_DEVICE:
9083051Syokota			/*
9183051Syokota			 * Got a compatible device id resource.
9283051Syokota			 * Should keep a list of compat ids in the device.
9383051Syokota			 */
9483051Syokota			bcopy(res, &compat_id, 4);
9583051Syokota			if (isa_get_compatid(dev) == 0)
9683051Syokota				isa_set_compatid(dev, compat_id);
9783051Syokota			break;
9883051Syokota
9983051Syokota		case PNP_TAG_IRQ_FORMAT:
10083051Syokota			if (config->ic_nirq == ISA_NIRQ) {
10183051Syokota				pnp_printf(id, "too many irqs\n");
10283051Syokota				return (1);
10383051Syokota			}
10483051Syokota			if (I16(res) == 0) {
10583051Syokota				/* a null descriptor */
10683051Syokota				config->ic_irqmask[config->ic_nirq] = 0;
10783051Syokota				config->ic_nirq++;
10883051Syokota				break;
10983051Syokota			}
11083051Syokota			if (bootverbose)
11183051Syokota				pnp_printf(id, "adding irq mask %#02x\n",
11283051Syokota					   I16(res));
11383051Syokota			config->ic_irqmask[config->ic_nirq] = I16(res);
11483051Syokota			config->ic_nirq++;
11583051Syokota			break;
11683051Syokota
11783051Syokota		case PNP_TAG_DMA_FORMAT:
11883051Syokota			if (config->ic_ndrq == ISA_NDRQ) {
11983051Syokota				pnp_printf(id, "too many drqs\n");
12083051Syokota				return (1);
12183051Syokota			}
12283051Syokota			if (res[0] == 0) {
12383051Syokota				/* a null descriptor */
12483051Syokota				config->ic_drqmask[config->ic_ndrq] = 0;
12583051Syokota				config->ic_ndrq++;
12683051Syokota				break;
12783051Syokota			}
12883051Syokota			if (bootverbose)
12983051Syokota				pnp_printf(id, "adding dma mask %#02x\n",
13083051Syokota					   res[0]);
13183051Syokota			config->ic_drqmask[config->ic_ndrq] = res[0];
13283051Syokota			config->ic_ndrq++;
13383051Syokota			break;
13483051Syokota
13583051Syokota		case PNP_TAG_IO_RANGE:
13683051Syokota			if (config->ic_nport == ISA_NPORT) {
13783051Syokota				pnp_printf(id, "too many ports\n");
13883051Syokota				return (1);
13983051Syokota			}
14083051Syokota			if (res[6] == 0) {
14183051Syokota				/* a null descriptor */
14283051Syokota				config->ic_port[config->ic_nport].ir_start = 0;
14383051Syokota				config->ic_port[config->ic_nport].ir_end = 0;
14483051Syokota				config->ic_port[config->ic_nport].ir_size = 0;
14583051Syokota				config->ic_port[config->ic_nport].ir_align = 0;
14683051Syokota				config->ic_nport++;
14783051Syokota				break;
14883051Syokota			}
14983051Syokota			if (bootverbose) {
15083051Syokota				pnp_printf(id, "adding io range "
15183051Syokota					   "%#x-%#x, size=%#x, "
15283051Syokota					   "align=%#x\n",
15383051Syokota					   I16(res + 1),
15483051Syokota					   I16(res + 3) + res[6]-1,
15583051Syokota					   res[6], res[5]);
15683051Syokota			}
15783051Syokota			config->ic_port[config->ic_nport].ir_start =
15883051Syokota			    I16(res + 1);
15983051Syokota			config->ic_port[config->ic_nport].ir_end =
16083051Syokota			    I16(res + 3) + res[6] - 1;
16183051Syokota			config->ic_port[config->ic_nport].ir_size = res[6];
16283051Syokota			if (res[5] == 0) {
16383051Syokota			    /* Make sure align is at least one */
16483051Syokota			    res[5] = 1;
16583051Syokota			}
16683051Syokota			config->ic_port[config->ic_nport].ir_align = res[5];
16783051Syokota			config->ic_nport++;
16883051Syokota			pnp_check_quirks(isa_get_vendorid(dev),
16983051Syokota					 isa_get_logicalid(dev), ldn, config);
17083051Syokota			break;
17183051Syokota
17283051Syokota		case PNP_TAG_IO_FIXED:
17383051Syokota			if (config->ic_nport == ISA_NPORT) {
17483051Syokota				pnp_printf(id, "too many ports\n");
17583051Syokota				return (1);
17683051Syokota			}
17783051Syokota			if (res[2] == 0) {
17883051Syokota				/* a null descriptor */
17983051Syokota				config->ic_port[config->ic_nport].ir_start = 0;
18083051Syokota				config->ic_port[config->ic_nport].ir_end = 0;
18183051Syokota				config->ic_port[config->ic_nport].ir_size = 0;
18283051Syokota				config->ic_port[config->ic_nport].ir_align = 0;
18383051Syokota				config->ic_nport++;
18483051Syokota				break;
18583051Syokota			}
18683051Syokota			if (bootverbose) {
18783051Syokota				pnp_printf(id, "adding fixed io range "
18883051Syokota					   "%#x-%#x, size=%#x, "
18983051Syokota					   "align=%#x\n",
19083051Syokota					   I16(res),
19183051Syokota					   I16(res) + res[2] - 1,
19283051Syokota					   res[2], 1);
19383051Syokota			}
19483051Syokota			config->ic_port[config->ic_nport].ir_start = I16(res);
19583051Syokota			config->ic_port[config->ic_nport].ir_end =
19683051Syokota			    I16(res) + res[2] - 1;
19783051Syokota			config->ic_port[config->ic_nport].ir_size = res[2];
19883051Syokota			config->ic_port[config->ic_nport].ir_align = 1;
19983051Syokota			config->ic_nport++;
20083051Syokota			break;
20183051Syokota
20283051Syokota		case PNP_TAG_END:
20383051Syokota			if (bootverbose)
20483051Syokota				pnp_printf(id, "end config\n");
20583051Syokota			return (1);
20683051Syokota
20783051Syokota		default:
20883051Syokota			/* Skip this resource */
20983051Syokota			pnp_printf(id, "unexpected small tag %d\n",
21083051Syokota				      PNP_SRES_NUM(tag));
21183051Syokota			break;
21283051Syokota		}
21383051Syokota	} else {
21483051Syokota		/* Large resource */
21583051Syokota		switch (PNP_LRES_NUM(tag)) {
21683051Syokota
21783051Syokota		case PNP_TAG_ID_UNICODE:
21883051Syokota		case PNP_TAG_LARGE_VENDOR:
21983051Syokota			/* these descriptors are quietly ignored */
22083051Syokota			break;
22183051Syokota
22283051Syokota		case PNP_TAG_ID_ANSI:
22383051Syokota			if (len > sizeof(buf) - 1)
22483051Syokota				len = sizeof(buf) - 1;
22583051Syokota			bcopy(res, buf, len);
22683051Syokota
22783051Syokota			/*
22883051Syokota			 * Trim trailing spaces and garbage.
22983051Syokota			 */
23083051Syokota			while (len > 0 && buf[len - 1] <= ' ')
23183051Syokota				len--;
23283051Syokota			buf[len] = '\0';
23383051Syokota			device_set_desc_copy(dev, buf);
23483051Syokota			break;
23583051Syokota
23683051Syokota		case PNP_TAG_MEMORY_RANGE:
23783051Syokota			if (config->ic_nmem == ISA_NMEM) {
23883051Syokota				pnp_printf(id, "too many memory ranges\n");
23983051Syokota				return (1);
24083051Syokota			}
24183051Syokota			if (I16(res + 7) == 0) {
24283051Syokota				/* a null descriptor */
24383051Syokota				config->ic_mem[config->ic_nmem].ir_start = 0;
24483051Syokota				config->ic_mem[config->ic_nmem].ir_end = 0;
24583051Syokota				config->ic_mem[config->ic_nmem].ir_size = 0;
24683051Syokota				config->ic_mem[config->ic_nmem].ir_align = 0;
24783051Syokota				config->ic_nmem++;
24883051Syokota				break;
24983051Syokota			}
25083051Syokota			if (bootverbose) {
25183051Syokota				temp = I16(res + 7) << 8;
25283051Syokota				pnp_printf(id, "adding memory range "
25383051Syokota					   "%#x-%#x, size=%#x, "
25483051Syokota					   "align=%#x\n",
25583051Syokota					   I16(res + 1) << 8,
25683051Syokota					   (I16(res + 3) << 8) + temp - 1,
25783051Syokota					   temp, I16(res + 5));
25883051Syokota			}
25983051Syokota			config->ic_mem[config->ic_nmem].ir_start =
26083051Syokota			    I16(res + 1) << 8;
26183051Syokota			config->ic_mem[config->ic_nmem].ir_end =
26283051Syokota			    (I16(res + 3) << 8) + (I16(res + 7) << 8) - 1;
26383051Syokota			config->ic_mem[config->ic_nmem].ir_size =
26483051Syokota			    I16(res + 7) << 8;
26583051Syokota			config->ic_mem[config->ic_nmem].ir_align = I16(res + 5);
26683051Syokota			if (!config->ic_mem[config->ic_nmem].ir_align)
26783051Syokota				config->ic_mem[config->ic_nmem].ir_align =
26883051Syokota				    0x10000;
26983051Syokota			config->ic_nmem++;
27083051Syokota			break;
27183051Syokota
27283051Syokota		case PNP_TAG_MEMORY32_RANGE:
27383051Syokota			if (config->ic_nmem == ISA_NMEM) {
27483051Syokota				pnp_printf(id, "too many memory ranges\n");
27583051Syokota				return (1);
27683051Syokota			}
27783051Syokota			if (I32(res + 13) == 0) {
27883051Syokota				/* a null descriptor */
27983051Syokota				config->ic_mem[config->ic_nmem].ir_start = 0;
28083051Syokota				config->ic_mem[config->ic_nmem].ir_end = 0;
28183051Syokota				config->ic_mem[config->ic_nmem].ir_size = 0;
28283051Syokota				config->ic_mem[config->ic_nmem].ir_align = 0;
28383051Syokota				config->ic_nmem++;
28483051Syokota				break;
28583051Syokota			}
28683051Syokota			if (bootverbose) {
28783051Syokota				pnp_printf(id, "adding memory32 range "
28883051Syokota					   "%#x-%#x, size=%#x, "
28983051Syokota					   "align=%#x\n",
29083051Syokota					   I32(res + 1),
29183051Syokota					   I32(res + 5) + I32(res + 13) - 1,
29283051Syokota					   I32(res + 13), I32(res + 9));
29383051Syokota			}
29483051Syokota			config->ic_mem[config->ic_nmem].ir_start = I32(res + 1);
29583051Syokota			config->ic_mem[config->ic_nmem].ir_end =
29683051Syokota			    I32(res + 5) + I32(res + 13) - 1;
29783051Syokota			config->ic_mem[config->ic_nmem].ir_size = I32(res + 13);
29883051Syokota			config->ic_mem[config->ic_nmem].ir_align = I32(res + 9);
29983051Syokota			config->ic_nmem++;
30083051Syokota			break;
30183051Syokota
30283051Syokota		case PNP_TAG_MEMORY32_FIXED:
30383051Syokota			if (config->ic_nmem == ISA_NMEM) {
30483051Syokota				pnp_printf(id, "too many memory ranges\n");
30583051Syokota				return (1);
30683051Syokota			}
30783051Syokota			if (I32(res + 5) == 0) {
30883051Syokota				/* a null descriptor */
30983051Syokota				config->ic_mem[config->ic_nmem].ir_start = 0;
31083051Syokota				config->ic_mem[config->ic_nmem].ir_end = 0;
31183051Syokota				config->ic_mem[config->ic_nmem].ir_size = 0;
31283051Syokota				config->ic_mem[config->ic_nmem].ir_align = 0;
31383051Syokota				break;
31483051Syokota			}
31583051Syokota			if (bootverbose) {
31683051Syokota				pnp_printf(id, "adding fixed memory32 range "
31783051Syokota					   "%#x-%#x, size=%#x\n",
31883051Syokota					   I32(res + 1),
31983051Syokota					   I32(res + 1) + I32(res + 5) - 1,
32083051Syokota					   I32(res + 5));
32183051Syokota			}
32283051Syokota			config->ic_mem[config->ic_nmem].ir_start = I32(res + 1);
32383051Syokota			config->ic_mem[config->ic_nmem].ir_end =
32483051Syokota			    I32(res + 1) + I32(res + 5) - 1;
32583051Syokota			config->ic_mem[config->ic_nmem].ir_size = I32(res + 5);
32683051Syokota			config->ic_mem[config->ic_nmem].ir_align = 1;
32783051Syokota			config->ic_nmem++;
32883051Syokota			break;
32983051Syokota
33083051Syokota		default:
33183051Syokota			/* Skip this resource */
33283051Syokota			pnp_printf(id, "unexpected large tag %d\n",
33383051Syokota				   PNP_SRES_NUM(tag));
33483051Syokota			break;
33583051Syokota		}
33683051Syokota	}
33783051Syokota
33883051Syokota	return (0);
33983051Syokota}
34083051Syokota
34152059Sdfr/*
34283051Syokota * Parse a single "dependent" resource combination.
34383051Syokota */
34483051Syokota
34583051Syokotau_char
34683051Syokota*pnp_parse_dependant(device_t dev, u_char *resources, int len,
34783051Syokota		     struct isa_config *config, int ldn)
34883051Syokota{
34983051Syokota
35083051Syokota	return pnp_scan_resources(dev, resources, len, config, ldn,
35183051Syokota				  pnp_parse_desc);
35283051Syokota}
35383051Syokota
35483051Syokotastatic void
35583051Syokotapnp_merge_resources(device_t dev, struct isa_config *from,
35683051Syokota		    struct isa_config *to)
35783051Syokota{
35883051Syokota	device_t parent;
35983051Syokota	int i;
36083051Syokota
36183051Syokota	parent = device_get_parent(dev);
36283051Syokota	for (i = 0; i < from->ic_nmem; i++) {
36383051Syokota		if (to->ic_nmem == ISA_NMEM) {
36483051Syokota			device_printf(parent, "too many memory ranges\n");
36583051Syokota			return;
36683051Syokota		}
36783051Syokota		to->ic_mem[to->ic_nmem] = from->ic_mem[i];
36883051Syokota		to->ic_nmem++;
36983051Syokota	}
37083051Syokota	for (i = 0; i < from->ic_nport; i++) {
37183051Syokota		if (to->ic_nport == ISA_NPORT) {
37283051Syokota			device_printf(parent, "too many port ranges\n");
37383051Syokota			return;
37483051Syokota		}
37583051Syokota		to->ic_port[to->ic_nport] = from->ic_port[i];
37683051Syokota		to->ic_nport++;
37783051Syokota	}
37883051Syokota	for (i = 0; i < from->ic_nirq; i++) {
37983051Syokota		if (to->ic_nirq == ISA_NIRQ) {
38083051Syokota			device_printf(parent, "too many irq ranges\n");
38183051Syokota			return;
38283051Syokota		}
38383051Syokota		to->ic_irqmask[to->ic_nirq] = from->ic_irqmask[i];
38483051Syokota		to->ic_nirq++;
38583051Syokota	}
38683051Syokota	for (i = 0; i < from->ic_ndrq; i++) {
38783051Syokota		if (to->ic_ndrq == ISA_NDRQ) {
38883051Syokota			device_printf(parent, "too many drq ranges\n");
38983051Syokota			return;
39083051Syokota		}
39183051Syokota		to->ic_drqmask[to->ic_ndrq] = from->ic_drqmask[i];
39283051Syokota		to->ic_ndrq++;
39383051Syokota	}
39483051Syokota}
39583051Syokota
39683051Syokota/*
39783051Syokota * Parse resource data for Logical Devices, make a list of available
39883051Syokota * resource configurations, and add them to the device.
39952059Sdfr *
40052059Sdfr * This function exits as soon as it gets an error reading *ANY*
40158850Sdfr * Resource Data or it reaches the end of Resource Data.
40252059Sdfr */
40383051Syokota
40452059Sdfrvoid
40583051Syokotapnp_parse_resources(device_t dev, u_char *resources, int len, int ldn)
40652059Sdfr{
40783051Syokota	struct isa_config *configs;
40852059Sdfr	struct isa_config *config;
40983051Syokota	device_t parent;
41058850Sdfr	int priorities[1 + MAXDEP];
41183051Syokota	u_char *start;
41283051Syokota	u_char *p;
41383051Syokota	u_char tag;
41483051Syokota	u_int32_t id;
41583051Syokota	int ncfgs;
41683051Syokota	int l;
41758850Sdfr	int i;
41852059Sdfr
41983051Syokota	parent = device_get_parent(dev);
42052241Sdfr	id = isa_get_logicalid(dev);
42183051Syokota
42283051Syokota	configs = (struct isa_config *)malloc(sizeof(*configs)*(1 + MAXDEP),
42383051Syokota					      M_DEVBUF, M_NOWAIT | M_ZERO);
42458873Sdfr	if (configs == NULL) {
42583051Syokota		device_printf(parent, "No memory to parse PNP data\n");
42658873Sdfr		return;
42758873Sdfr	}
42858850Sdfr	config = &configs[0];
42958850Sdfr	priorities[0] = 0;
43083051Syokota	ncfgs = 1;
43183051Syokota
43283051Syokota	p = resources;
43383051Syokota	start = NULL;
43483051Syokota	while (len > 0) {
43583051Syokota		tag = *p++;
43683051Syokota		len--;
43752059Sdfr		if (PNP_RES_TYPE(tag) == 0) {
43852059Sdfr			/* Small resource */
43983051Syokota			l = PNP_SRES_LEN(tag);
44083051Syokota			if (len < l) {
44183051Syokota				len = 0;
44252059Sdfr				continue;
44352059Sdfr			}
44483051Syokota			len -= l;
44583051Syokota
44652059Sdfr			switch (PNP_SRES_NUM(tag)) {
44752059Sdfr
44852059Sdfr			case PNP_TAG_START_DEPENDANT:
44983051Syokota				if (start != NULL) {
45083051Syokota					/*
45183051Syokota					 * Copy the common resources first,
45283051Syokota					 * then parse the "dependent" resources.
45383051Syokota					 */
45483051Syokota					pnp_merge_resources(dev, &configs[0],
45583051Syokota							    config);
45683051Syokota					pnp_parse_dependant(dev, start,
45783051Syokota							    p - start - 1,
45883051Syokota							    config, ldn);
45952241Sdfr				}
46083051Syokota				start = p + l;
46159002Sdfr				if (ncfgs > MAXDEP) {
46258850Sdfr					device_printf(parent, "too many dependant configs (%d)\n", MAXDEP);
46383051Syokota					len = 0;
46452059Sdfr					break;
46552059Sdfr				}
46658850Sdfr				config = &configs[ncfgs];
46752059Sdfr				/*
46852059Sdfr				 * If the priority is not specified,
46983051Syokota				 * then use the default of 'acceptable'
47052059Sdfr				 */
47183051Syokota				if (l > 0)
47283051Syokota					priorities[ncfgs] = p[0];
47352059Sdfr				else
47458850Sdfr					priorities[ncfgs] = 1;
47583051Syokota				if (bootverbose)
47683051Syokota					pnp_printf(id, "start dependent (%d)\n",
47783051Syokota						   priorities[ncfgs]);
47858850Sdfr				ncfgs++;
47952059Sdfr				break;
48052059Sdfr
48152059Sdfr			case PNP_TAG_END_DEPENDANT:
48283051Syokota				if (start == NULL) {
48383051Syokota					device_printf(parent,
48483051Syokota						      "malformed resources\n");
48583051Syokota					len = 0;
48652059Sdfr					break;
48752059Sdfr				}
48883051Syokota				/*
48983051Syokota				 * Copy the common resources first,
49083051Syokota				 * then parse the "dependent" resources.
49183051Syokota				 */
49283051Syokota				pnp_merge_resources(dev, &configs[0], config);
49383051Syokota				pnp_parse_dependant(dev, start, p - start - 1,
49483051Syokota						    config, ldn);
49583051Syokota				start = NULL;
49683051Syokota				if (bootverbose)
49783051Syokota					pnp_printf(id, "end dependent\n");
49883051Syokota				/*
49983051Syokota				 * Back to the common part; clear it
50083051Syokota				 * as its contents has already been copied
50183051Syokota				 * to each dependant.
50283051Syokota				 */
50383051Syokota				config = &configs[0];
50483051Syokota				bzero(config, sizeof(*config));
50552059Sdfr				break;
50652059Sdfr
50752241Sdfr			case PNP_TAG_END:
50883051Syokota				if (start != NULL) {
50983051Syokota					device_printf(parent,
51083051Syokota						      "malformed resources\n");
51152241Sdfr				}
51283051Syokota				len = 0;
51352241Sdfr				break;
51452241Sdfr
51552059Sdfr			default:
51683051Syokota				if (start != NULL)
51783051Syokota					/* defer parsing a dependent section */
51883051Syokota					break;
51983051Syokota				if (pnp_parse_desc(dev, tag, p, l, config, ldn))
52083051Syokota					len = 0;
52152059Sdfr				break;
52252059Sdfr			}
52383051Syokota			p += l;
52452059Sdfr		} else {
52552059Sdfr			/* Large resource */
52683051Syokota			if (len < 2) {
52783051Syokota				len = 0;
52883051Syokota				break;
52952059Sdfr			}
53083051Syokota			l = I16(p);
53183051Syokota			p += 2;
53283051Syokota			len -= 2;
53383051Syokota			if (len < l) {
53483051Syokota				len = 0;
53583051Syokota				break;
53652059Sdfr			}
53783051Syokota			len -= l;
53883051Syokota			if (start == NULL &&
53983051Syokota			    pnp_parse_desc(dev, tag, p, l, config, ldn)) {
54083051Syokota				len = 0;
54152241Sdfr				break;
54252241Sdfr			}
54383051Syokota			p += l;
54452059Sdfr		}
54552059Sdfr	}
54683051Syokota
54783051Syokota	if (ncfgs == 1) {
54858850Sdfr		/* Single config without dependants */
54983051Syokota		ISA_ADD_CONFIG(parent, dev, priorities[0], &configs[0]);
55058873Sdfr		free(configs, M_DEVBUF);
55158850Sdfr		return;
55258850Sdfr	}
55383051Syokota
55483051Syokota	for (i = 1; i < ncfgs; i++) {
55583051Syokota		/*
55683051Syokota		 * Merge the remaining part of the common resources,
55783051Syokota		 * if any. Strictly speaking, there shouldn't be common/main
55883051Syokota		 * resources after the END_DEPENDENT tag.
55983051Syokota		 */
56083051Syokota		pnp_merge_resources(dev, &configs[0], &configs[i]);
56183051Syokota		ISA_ADD_CONFIG(parent, dev, priorities[i], &configs[i]);
56258850Sdfr	}
56383051Syokota
56458873Sdfr	free(configs, M_DEVBUF);
56552059Sdfr}
56683051Syokota
56783051Syokotau_char
56883051Syokota*pnp_scan_resources(device_t dev, u_char *resources, int len,
56983051Syokota		    struct isa_config *config, int ldn, pnp_scan_cb *cb)
57083051Syokota{
57183051Syokota	u_char *p;
57283051Syokota	u_char tag;
57383051Syokota	int l;
57483051Syokota
57583051Syokota	p = resources;
57683051Syokota	while (len > 0) {
57783051Syokota		tag = *p++;
57883051Syokota		len--;
57983051Syokota		if (PNP_RES_TYPE(tag) == 0) {
58083051Syokota			/* small resource */
58183051Syokota			l = PNP_SRES_LEN(tag);
58283051Syokota			if (len < l)
58383051Syokota				break;
58483051Syokota			if ((*cb)(dev, tag, p, l, config, ldn))
58583051Syokota				return (p + l);
58683051Syokota			if (PNP_SRES_NUM(tag) == PNP_TAG_END)
58783051Syokota				return (p + l);
58883051Syokota		} else {
58983051Syokota			/* large resource */
59083051Syokota			if (len < 2)
59183051Syokota				break;
59283051Syokota			l = I16(p);
59383051Syokota			p += 2;
59483051Syokota			len -= 2;
59583051Syokota			if (len < l)
59683051Syokota				break;
59783051Syokota			if ((*cb)(dev, tag, p, l, config, ldn))
59883051Syokota				return (p + l);
59983051Syokota		}
60083051Syokota		p += l;
60183051Syokota		len -= l;
60283051Syokota	}
60383051Syokota	return NULL;
60483051Syokota}
605