Home | History | Annotate | Line # | Download | only in isapnp
isapnpres.c revision 1.17.16.2
      1  1.17.16.1       mjf /*	$NetBSD: isapnpres.c,v 1.17.16.2 2008/06/02 13:23:33 mjf Exp $	*/
      2        1.1  christos 
      3        1.9  christos /*-
      4        1.9  christos  * Copyright (c) 1996 The NetBSD Foundation, Inc.
      5        1.9  christos  * All rights reserved.
      6        1.9  christos  *
      7        1.9  christos  * This code is derived from software contributed to The NetBSD Foundation
      8        1.9  christos  * by Christos Zoulas.
      9        1.1  christos  *
     10        1.1  christos  * Redistribution and use in source and binary forms, with or without
     11        1.1  christos  * modification, are permitted provided that the following conditions
     12        1.1  christos  * are met:
     13        1.1  christos  * 1. Redistributions of source code must retain the above copyright
     14        1.1  christos  *    notice, this list of conditions and the following disclaimer.
     15        1.1  christos  * 2. Redistributions in binary form must reproduce the above copyright
     16        1.1  christos  *    notice, this list of conditions and the following disclaimer in the
     17        1.1  christos  *    documentation and/or other materials provided with the distribution.
     18        1.1  christos  *
     19        1.9  christos  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20        1.9  christos  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21        1.9  christos  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22        1.9  christos  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23        1.9  christos  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24        1.9  christos  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25        1.9  christos  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26        1.9  christos  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27        1.9  christos  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28        1.9  christos  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29        1.9  christos  * POSSIBILITY OF SUCH DAMAGE.
     30        1.1  christos  */
     31        1.1  christos 
     32        1.1  christos /*
     33        1.1  christos  * Resource parser for Plug and Play cards.
     34        1.1  christos  */
     35       1.11     lukem 
     36       1.11     lukem #include <sys/cdefs.h>
     37  1.17.16.1       mjf __KERNEL_RCSID(0, "$NetBSD: isapnpres.c,v 1.17.16.2 2008/06/02 13:23:33 mjf Exp $");
     38        1.1  christos 
     39        1.1  christos #include <sys/param.h>
     40        1.1  christos #include <sys/systm.h>
     41        1.1  christos #include <sys/device.h>
     42        1.1  christos #include <sys/malloc.h>
     43        1.1  christos 
     44       1.17        ad #include <sys/bus.h>
     45        1.1  christos 
     46        1.1  christos #include <dev/isa/isavar.h>
     47        1.1  christos 
     48        1.1  christos #include <dev/isapnp/isapnpreg.h>
     49        1.1  christos #include <dev/isapnp/isapnpvar.h>
     50        1.1  christos 
     51        1.1  christos 
     52       1.13     perry static int isapnp_wait_status(struct isapnp_softc *);
     53        1.4  christos static struct isapnp_attach_args *
     54       1.13     perry     isapnp_newdev(struct isapnp_attach_args *);
     55        1.4  christos static struct isapnp_attach_args *
     56       1.13     perry     isapnp_newconf(struct isapnp_attach_args *);
     57       1.13     perry static void isapnp_merge(struct isapnp_attach_args *,
     58       1.13     perry     const struct isapnp_attach_args *);
     59        1.4  christos static struct isapnp_attach_args *
     60       1.13     perry     isapnp_flatten(struct isapnp_attach_args *);
     61       1.13     perry static int isapnp_process_tag(u_char, u_char, u_char *,
     62        1.4  christos     struct isapnp_attach_args **, struct isapnp_attach_args **,
     63       1.13     perry     struct isapnp_attach_args **);
     64        1.1  christos 
     65        1.1  christos 
     66        1.1  christos /* isapnp_wait_status():
     67        1.1  christos  *	Wait for the next byte of resource data to become available
     68        1.1  christos  */
     69        1.1  christos static int
     70        1.1  christos isapnp_wait_status(sc)
     71        1.1  christos 	struct isapnp_softc *sc;
     72        1.1  christos {
     73        1.1  christos 	int i;
     74        1.1  christos 
     75        1.8     mikel 	/* wait up to 1 ms for each resource byte */
     76        1.1  christos 	for (i = 0; i < 10; i++) {
     77        1.1  christos 		if (isapnp_read_reg(sc, ISAPNP_STATUS) & 1)
     78        1.1  christos 			return 0;
     79        1.8     mikel 		DELAY(100);
     80        1.1  christos 	}
     81        1.1  christos 	return 1;
     82        1.1  christos }
     83        1.1  christos 
     84        1.4  christos 
     85        1.4  christos /* isapnp_newdev():
     86        1.4  christos  *	Add a new logical device to the current card; expand the configuration
     87        1.4  christos  *	resources of the current card if needed.
     88        1.4  christos  */
     89        1.4  christos static struct isapnp_attach_args *
     90        1.4  christos isapnp_newdev(card)
     91        1.4  christos 	struct isapnp_attach_args *card;
     92        1.4  christos {
     93        1.4  christos 	struct isapnp_attach_args *ipa, *dev = ISAPNP_MALLOC(sizeof(*dev));
     94        1.4  christos 
     95        1.4  christos 	memset(dev, 0, sizeof(*dev));
     96        1.4  christos 
     97        1.4  christos 	dev->ipa_pref = ISAPNP_DEP_ACCEPTABLE;
     98        1.4  christos 	memcpy(dev->ipa_devident, card->ipa_devident,
     99        1.4  christos 	    sizeof(card->ipa_devident));
    100        1.4  christos 
    101        1.4  christos 	if (card->ipa_child == NULL)
    102        1.4  christos 		card->ipa_child = dev;
    103        1.4  christos 	else {
    104       1.14     perry 		for (ipa = card->ipa_child; ipa->ipa_sibling != NULL;
    105        1.4  christos 		    ipa = ipa->ipa_sibling)
    106        1.4  christos 			continue;
    107        1.4  christos 		ipa->ipa_sibling = dev;
    108        1.4  christos 	}
    109        1.4  christos 
    110        1.4  christos 
    111        1.4  christos 	return dev;
    112        1.4  christos }
    113        1.4  christos 
    114        1.4  christos 
    115        1.4  christos /* isapnp_newconf():
    116        1.4  christos  *	Add a new alternate configuration to a logical device
    117        1.4  christos  */
    118        1.4  christos static struct isapnp_attach_args *
    119        1.4  christos isapnp_newconf(dev)
    120        1.4  christos 	struct isapnp_attach_args *dev;
    121        1.4  christos {
    122        1.4  christos 	struct isapnp_attach_args *ipa, *conf = ISAPNP_MALLOC(sizeof(*conf));
    123        1.4  christos 
    124        1.4  christos 	memset(conf, 0, sizeof(*conf));
    125        1.4  christos 
    126        1.4  christos 	memcpy(conf->ipa_devident, dev->ipa_devident,
    127        1.4  christos 	    sizeof(conf->ipa_devident));
    128        1.4  christos 	memcpy(conf->ipa_devlogic, dev->ipa_devlogic,
    129        1.4  christos 	    sizeof(conf->ipa_devlogic));
    130        1.7     mikel 	memcpy(conf->ipa_devcompat, dev->ipa_devcompat,
    131        1.7     mikel 	    sizeof(conf->ipa_devcompat));
    132        1.4  christos 	memcpy(conf->ipa_devclass, dev->ipa_devclass,
    133        1.4  christos 	    sizeof(conf->ipa_devclass));
    134        1.4  christos 
    135        1.4  christos 	if (dev->ipa_child == NULL)
    136        1.4  christos 		dev->ipa_child = conf;
    137        1.4  christos 	else {
    138        1.4  christos 		for (ipa = dev->ipa_child; ipa->ipa_sibling;
    139        1.4  christos 		    ipa = ipa->ipa_sibling)
    140        1.4  christos 			continue;
    141        1.4  christos 		ipa->ipa_sibling = conf;
    142        1.4  christos 	}
    143        1.4  christos 
    144        1.4  christos 	return conf;
    145        1.4  christos }
    146        1.4  christos 
    147        1.4  christos 
    148        1.4  christos /* isapnp_merge():
    149        1.4  christos  *	Merge the common device configurations to the subconfigurations
    150        1.4  christos  */
    151        1.4  christos static void
    152        1.5  christos isapnp_merge(c, d)
    153        1.5  christos 	struct isapnp_attach_args *c;
    154        1.5  christos 	const struct isapnp_attach_args *d;
    155        1.4  christos {
    156        1.4  christos 	int i;
    157        1.4  christos 
    158        1.4  christos 	for (i = 0; i < d->ipa_nio; i++)
    159        1.4  christos 		c->ipa_io[c->ipa_nio++] = d->ipa_io[i];
    160        1.4  christos 
    161        1.4  christos 	for (i = 0; i < d->ipa_nmem; i++)
    162        1.4  christos 		c->ipa_mem[c->ipa_nmem++] = d->ipa_mem[i];
    163        1.4  christos 
    164        1.4  christos 	for (i = 0; i < d->ipa_nmem32; i++)
    165        1.4  christos 		c->ipa_mem32[c->ipa_nmem32++] = d->ipa_mem32[i];
    166        1.4  christos 
    167        1.4  christos 	for (i = 0; i < d->ipa_nirq; i++)
    168        1.4  christos 		c->ipa_irq[c->ipa_nirq++] = d->ipa_irq[i];
    169        1.4  christos 
    170        1.4  christos 	for (i = 0; i < d->ipa_ndrq; i++)
    171        1.4  christos 		c->ipa_drq[c->ipa_ndrq++] = d->ipa_drq[i];
    172        1.4  christos }
    173        1.4  christos 
    174        1.4  christos 
    175        1.4  christos /* isapnp_flatten():
    176        1.4  christos  *	Flatten the tree to a list of config entries.
    177        1.4  christos  */
    178        1.4  christos static struct isapnp_attach_args *
    179        1.4  christos isapnp_flatten(card)
    180        1.4  christos 	struct isapnp_attach_args *card;
    181        1.4  christos {
    182        1.4  christos 	struct isapnp_attach_args *dev, *conf, *d, *c, *pa;
    183        1.4  christos 
    184        1.4  christos 	dev = card->ipa_child;
    185        1.4  christos 	ISAPNP_FREE(card);
    186        1.4  christos 
    187        1.4  christos 	for (conf = c = NULL, d = dev; d; d = dev) {
    188        1.4  christos 		dev = d->ipa_sibling;
    189        1.4  christos 		if (d->ipa_child == NULL) {
    190        1.4  christos 			/*
    191        1.4  christos 			 * No subconfigurations; all configuration info
    192        1.4  christos 			 * is in the device node.
    193        1.4  christos 			 */
    194        1.4  christos 			d->ipa_sibling = NULL;
    195        1.4  christos 			pa = d;
    196        1.4  christos 		}
    197        1.4  christos 		else {
    198        1.4  christos 			/*
    199        1.4  christos 			 * Push down device configuration info to the
    200        1.4  christos 			 * subconfigurations
    201        1.4  christos 			 */
    202        1.4  christos 			for (pa = d->ipa_child; pa; pa = pa->ipa_sibling)
    203        1.5  christos 				isapnp_merge(pa, d);
    204        1.4  christos 
    205        1.4  christos 			pa = d->ipa_child;
    206        1.4  christos 			ISAPNP_FREE(d);
    207        1.4  christos 		}
    208        1.4  christos 
    209        1.4  christos 		if (c == NULL)
    210        1.4  christos 			c = conf = pa;
    211        1.4  christos 		else
    212        1.4  christos 			c->ipa_sibling = pa;
    213        1.4  christos 
    214        1.4  christos 		while (c->ipa_sibling)
    215        1.4  christos 			c = c->ipa_sibling;
    216        1.4  christos 	}
    217        1.4  christos 	return conf;
    218        1.4  christos }
    219        1.4  christos 
    220        1.4  christos 
    221        1.1  christos /* isapnp_process_tag():
    222        1.1  christos  *	Process a resource tag
    223        1.1  christos  */
    224        1.4  christos static int
    225        1.4  christos isapnp_process_tag(tag, len, buf, card, dev, conf)
    226        1.1  christos 	u_char tag, len, *buf;
    227        1.4  christos 	struct isapnp_attach_args **card, **dev, **conf;
    228        1.1  christos {
    229        1.1  christos 	char str[64];
    230        1.1  christos 	struct isapnp_region *r;
    231        1.1  christos 	struct isapnp_pin *p;
    232        1.4  christos 	struct isapnp_attach_args *pa;
    233        1.1  christos 
    234        1.1  christos #define COPY(a, b) strncpy((a), (b), sizeof(a)), (a)[sizeof(a) - 1] = '\0'
    235        1.1  christos 
    236        1.1  christos 	switch (tag) {
    237        1.1  christos 	case ISAPNP_TAG_VERSION_NUM:
    238        1.1  christos 		DPRINTF(("PnP version %d.%d, Vendor version %d.%d\n",
    239        1.1  christos 		    buf[0] >> 4, buf[0] & 0xf, buf[1] >> 4,  buf[1] & 0xf));
    240        1.4  christos 		return 0;
    241        1.1  christos 
    242        1.1  christos 	case ISAPNP_TAG_LOGICAL_DEV_ID:
    243        1.1  christos 		(void) isapnp_id_to_vendor(str, buf);
    244        1.1  christos 		DPRINTF(("Logical device id %s\n", str));
    245        1.4  christos 
    246        1.4  christos 		*dev = isapnp_newdev(*card);
    247        1.4  christos 		COPY((*dev)->ipa_devlogic, str);
    248        1.4  christos 		return 0;
    249        1.1  christos 
    250        1.1  christos 	case ISAPNP_TAG_COMPAT_DEV_ID:
    251        1.1  christos 		(void) isapnp_id_to_vendor(str, buf);
    252        1.1  christos 		DPRINTF(("Compatible device id %s\n", str));
    253        1.7     mikel 
    254        1.7     mikel 		if (*dev == NULL)
    255        1.7     mikel 			return -1;
    256        1.7     mikel 
    257        1.7     mikel 		if (*(*dev)->ipa_devcompat == '\0')
    258        1.7     mikel 			COPY((*dev)->ipa_devcompat, str);
    259        1.4  christos 		return 0;
    260        1.4  christos 
    261        1.4  christos 	case ISAPNP_TAG_DEP_START:
    262        1.4  christos 		if (len == 0)
    263        1.4  christos 			buf[0] = ISAPNP_DEP_ACCEPTABLE;
    264        1.4  christos 
    265        1.4  christos 		if (*dev == NULL)
    266        1.4  christos 			return -1;
    267        1.4  christos 
    268        1.4  christos 		*conf = isapnp_newconf(*dev);
    269        1.4  christos 		(*conf)->ipa_pref = buf[0];
    270        1.4  christos #ifdef DEBUG_ISAPNP
    271        1.6     mikel 		isapnp_print_dep_start(">>> Start dependent function ",
    272        1.4  christos 		    (*conf)->ipa_pref);
    273        1.4  christos #endif
    274        1.4  christos 		return 0;
    275       1.14     perry 
    276        1.4  christos 	case ISAPNP_TAG_DEP_END:
    277        1.6     mikel 		DPRINTF(("<<<End dependent functions\n"));
    278        1.4  christos 		*conf = NULL;
    279        1.4  christos 		return 0;
    280        1.4  christos 
    281        1.4  christos 	case ISAPNP_TAG_ANSI_IDENT_STRING:
    282        1.4  christos 		buf[len] = '\0';
    283        1.4  christos 		DPRINTF(("ANSI Ident: %s\n", buf));
    284        1.4  christos 		if (*dev == NULL)
    285        1.4  christos 			COPY((*card)->ipa_devident, buf);
    286        1.4  christos 		else
    287        1.4  christos 			COPY((*dev)->ipa_devclass, buf);
    288        1.4  christos 		return 0;
    289        1.4  christos 
    290        1.4  christos 	case ISAPNP_TAG_END:
    291        1.4  christos 		*dev = NULL;
    292        1.4  christos 		return 0;
    293        1.4  christos 
    294        1.4  christos 	default:
    295        1.4  christos 		/* Handled below */
    296        1.1  christos 		break;
    297        1.4  christos 	}
    298        1.4  christos 
    299        1.4  christos 
    300        1.4  christos 	/*
    301        1.4  christos 	 * Decide which configuration we add the tag to
    302        1.4  christos 	 */
    303        1.4  christos 	if (*conf)
    304        1.4  christos 		pa = *conf;
    305        1.4  christos 	else if (*dev)
    306        1.4  christos 		pa = *dev;
    307        1.4  christos 	else
    308        1.4  christos 		/* error */
    309        1.4  christos 		return -1;
    310        1.4  christos 
    311        1.4  christos 	switch (tag) {
    312        1.1  christos 	case ISAPNP_TAG_IRQ_FORMAT:
    313        1.1  christos 		if (len < 2)
    314        1.1  christos 			break;
    315        1.1  christos 
    316        1.1  christos 		if (len != 3)
    317        1.1  christos 			buf[2] = ISAPNP_IRQTYPE_EDGE_PLUS;
    318        1.1  christos 
    319        1.1  christos 		p = &pa->ipa_irq[pa->ipa_nirq++];
    320        1.1  christos 		p->bits = buf[0] | (buf[1] << 8);
    321        1.1  christos 		p->flags = buf[2];
    322        1.1  christos #ifdef DEBUG_ISAPNP
    323        1.1  christos 		isapnp_print_irq("", p);
    324        1.1  christos #endif
    325        1.1  christos 		break;
    326        1.1  christos 
    327        1.1  christos 	case ISAPNP_TAG_DMA_FORMAT:
    328        1.1  christos 		if (buf[0] == 0)
    329        1.1  christos 			break;
    330        1.1  christos 
    331        1.1  christos 		p = &pa->ipa_drq[pa->ipa_ndrq++];
    332        1.1  christos 		p->bits = buf[0];
    333        1.1  christos 		p->flags = buf[1];
    334        1.1  christos #ifdef DEBUG_ISAPNP
    335        1.1  christos 		isapnp_print_drq("", p);
    336        1.1  christos #endif
    337        1.1  christos 		break;
    338        1.1  christos 
    339        1.1  christos 
    340        1.1  christos 	case ISAPNP_TAG_IO_PORT_DESC:
    341        1.1  christos 		r = &pa->ipa_io[pa->ipa_nio++];
    342        1.1  christos 		r->flags = buf[0];
    343        1.1  christos 		r->minbase = (buf[2] << 8) | buf[1];
    344        1.1  christos 		r->maxbase = (buf[4] << 8) | buf[3];
    345        1.1  christos 		r->align = buf[5];
    346        1.1  christos 		r->length = buf[6];
    347       1.10  christos 		if (r->length == 0)
    348       1.10  christos 		    pa->ipa_nio--;
    349        1.1  christos #ifdef DEBUG_ISAPNP
    350        1.1  christos 		isapnp_print_io("", r);
    351        1.1  christos #endif
    352        1.1  christos 		break;
    353        1.1  christos 
    354        1.1  christos 	case ISAPNP_TAG_FIXED_IO_PORT_DESC:
    355        1.1  christos 		r = &pa->ipa_io[pa->ipa_nio++];
    356        1.1  christos 		r->flags = 0;
    357        1.6     mikel 		r->minbase = (buf[1] << 8) | buf[0];
    358        1.1  christos 		r->maxbase = r->minbase;
    359        1.1  christos 		r->align = 1;
    360        1.6     mikel 		r->length = buf[2];
    361       1.10  christos 		if (r->length == 0)
    362       1.10  christos 		    pa->ipa_nio--;
    363        1.1  christos #ifdef DEBUG_ISAPNP
    364        1.6     mikel 		isapnp_print_io("FIXED ", r);
    365        1.1  christos #endif
    366        1.1  christos 		break;
    367        1.1  christos 
    368        1.1  christos 	case ISAPNP_TAG_VENDOR_DEF:
    369        1.6     mikel 		DPRINTF(("Vendor defined (short)\n"));
    370        1.1  christos 		break;
    371        1.1  christos 
    372        1.1  christos 	case ISAPNP_TAG_MEM_RANGE_DESC:
    373        1.1  christos 		r = &pa->ipa_mem[pa->ipa_nmem++];
    374        1.6     mikel 		r->flags = buf[0];
    375        1.6     mikel 		r->minbase = (buf[2] << 16) | (buf[1] << 8);
    376        1.6     mikel 		r->maxbase = (buf[4] << 16) | (buf[3] << 8);
    377        1.1  christos 		r->align = (buf[6] << 8) | buf[5];
    378        1.6     mikel 		r->length = (buf[8] << 16) | (buf[7] << 8);
    379       1.10  christos 		if (r->length == 0)
    380       1.10  christos 		    pa->ipa_nmem--;
    381        1.1  christos #ifdef DEBUG_ISAPNP
    382        1.6     mikel 		isapnp_print_mem("", r);
    383        1.1  christos #endif
    384        1.1  christos 		break;
    385        1.1  christos 
    386        1.1  christos 
    387        1.1  christos 	case ISAPNP_TAG_UNICODE_IDENT_STRING:
    388        1.6     mikel 		DPRINTF(("Unicode Ident\n"));
    389        1.1  christos 		break;
    390        1.1  christos 
    391        1.1  christos 	case ISAPNP_TAG_VENDOR_DEFINED:
    392        1.6     mikel 		DPRINTF(("Vendor defined (long)\n"));
    393        1.1  christos 		break;
    394        1.1  christos 
    395        1.1  christos 	case ISAPNP_TAG_MEM32_RANGE_DESC:
    396        1.1  christos 		r = &pa->ipa_mem32[pa->ipa_nmem32++];
    397        1.1  christos 		r->flags = buf[0];
    398        1.1  christos 		r->minbase = (buf[4] << 24) | (buf[3] << 16) |
    399        1.1  christos 		    (buf[2] << 8) | buf[1];
    400        1.1  christos 		r->maxbase = (buf[8] << 24) | (buf[7] << 16) |
    401        1.1  christos 		    (buf[6] << 8) | buf[5];
    402       1.14     perry 		r->align = (buf[12] << 24) | (buf[11] << 16) |
    403        1.1  christos 		    (buf[10] << 8) | buf[9];
    404        1.1  christos 		r->length = (buf[16] << 24) | (buf[15] << 16) |
    405        1.1  christos 		    (buf[14] << 8) | buf[13];
    406       1.10  christos 		if (r->length == 0)
    407       1.10  christos 		    pa->ipa_nmem32--;
    408        1.1  christos #ifdef DEBUG_ISAPNP
    409        1.6     mikel 		isapnp_print_mem("32-bit ", r);
    410        1.1  christos #endif
    411        1.1  christos 		break;
    412        1.1  christos 
    413        1.1  christos 	case ISAPNP_TAG_FIXED_MEM32_RANGE_DESC:
    414        1.1  christos 		r = &pa->ipa_mem32[pa->ipa_nmem32++];
    415        1.1  christos 		r->flags = buf[0];
    416        1.1  christos 		r->minbase = (buf[4] << 24) | (buf[3] << 16) |
    417        1.1  christos 		    (buf[2] << 8) | buf[1];
    418        1.1  christos 		r->maxbase = r->minbase;
    419        1.1  christos 		r->align = 1;
    420        1.1  christos 		r->length = (buf[8] << 24) | (buf[7] << 16) |
    421        1.1  christos 		    (buf[6] << 8) | buf[5];
    422       1.10  christos 		if (r->length == 0)
    423       1.10  christos 		    pa->ipa_nmem32--;
    424        1.1  christos #ifdef DEBUG_ISAPNP
    425        1.6     mikel 		isapnp_print_mem("FIXED 32-bit ", r);
    426        1.1  christos #endif
    427        1.1  christos 		break;
    428        1.1  christos 
    429        1.1  christos 	default:
    430        1.1  christos #ifdef DEBUG_ISAPNP
    431        1.1  christos 		{
    432        1.1  christos 			int i;
    433        1.1  christos 			printf("tag %.2x, len %d: ", tag, len);
    434        1.1  christos 			for (i = 0; i < len; i++)
    435        1.1  christos 				printf("%.2x ", buf[i]);
    436        1.1  christos 			printf("\n");
    437        1.1  christos 		}
    438        1.1  christos #endif
    439        1.1  christos 		break;
    440        1.1  christos 	}
    441        1.4  christos 	return 0;
    442        1.1  christos }
    443        1.1  christos 
    444        1.1  christos 
    445        1.1  christos /* isapnp_get_resource():
    446        1.1  christos  *	Read the resources for card c
    447        1.1  christos  */
    448        1.1  christos struct isapnp_attach_args *
    449        1.1  christos isapnp_get_resource(sc, c)
    450        1.1  christos 	struct isapnp_softc *sc;
    451        1.1  christos 	int c;
    452        1.1  christos {
    453        1.1  christos 	u_char d, tag;
    454        1.1  christos 	u_short len;
    455        1.1  christos 	int i;
    456        1.4  christos 	int warned = 0;
    457        1.4  christos 	struct isapnp_attach_args *card, *dev = NULL, *conf = NULL;
    458        1.4  christos 	u_char buf[ISAPNP_MAX_TAGSIZE], *p;
    459        1.1  christos 
    460        1.4  christos 	memset(buf, 0, sizeof(buf));
    461        1.4  christos 
    462        1.4  christos 	card = ISAPNP_MALLOC(sizeof(*card));
    463        1.4  christos 	memset(card, 0, sizeof(*card));
    464        1.4  christos 
    465        1.4  christos #define NEXT_BYTE \
    466        1.4  christos 		if (isapnp_wait_status(sc)) \
    467        1.4  christos 			goto bad; \
    468        1.4  christos 		d = isapnp_read_reg(sc, ISAPNP_RESOURCE_DATA)
    469        1.1  christos 
    470        1.1  christos 	for (i = 0; i < ISAPNP_SERIAL_SIZE; i++) {
    471        1.4  christos 		NEXT_BYTE;
    472        1.1  christos 
    473        1.1  christos 		if (d != sc->sc_id[c][i] && i != ISAPNP_SERIAL_SIZE - 1) {
    474        1.4  christos 			if (!warned) {
    475  1.17.16.1       mjf 				aprint_error_dev(sc->sc_dev,
    476  1.17.16.1       mjf 				    "card %d violates PnP spec; byte %d\n",
    477  1.17.16.1       mjf 				    c + 1, i);
    478        1.4  christos 				warned++;
    479        1.4  christos 			}
    480        1.4  christos 			if (i == 0) {
    481        1.4  christos 				/*
    482        1.4  christos 				 * Magic! If this is the first byte, we
    483        1.4  christos 				 * assume that the tag data begins here.
    484        1.4  christos 				 */
    485        1.4  christos 				goto parse;
    486        1.4  christos 			}
    487        1.1  christos 		}
    488        1.1  christos 	}
    489        1.1  christos 
    490        1.1  christos 	do {
    491        1.1  christos 		NEXT_BYTE;
    492        1.4  christos parse:
    493        1.1  christos 
    494        1.1  christos 		if (d & ISAPNP_LARGE_TAG) {
    495        1.1  christos 			tag = d;
    496        1.1  christos 			NEXT_BYTE;
    497        1.1  christos 			buf[0] = d;
    498        1.1  christos 			NEXT_BYTE;
    499        1.1  christos 			buf[1] = d;
    500        1.1  christos 			len = (buf[1] << 8) | buf[0];
    501        1.1  christos 		}
    502        1.1  christos 		else {
    503        1.1  christos 			tag = (d >> 3) & 0xf;
    504        1.1  christos 			len = d & 0x7;
    505        1.1  christos 		}
    506        1.1  christos 
    507        1.1  christos 		for (p = buf, i = 0; i < len; i++) {
    508        1.1  christos 			NEXT_BYTE;
    509        1.1  christos 			if (i < ISAPNP_MAX_TAGSIZE)
    510        1.1  christos 				*p++ = d;
    511        1.1  christos 		}
    512        1.1  christos 
    513        1.1  christos 		if (len >= ISAPNP_MAX_TAGSIZE) {
    514  1.17.16.1       mjf 			aprint_error_dev(sc->sc_dev,
    515  1.17.16.1       mjf 			    "Maximum tag size exceeded, card %d\n",
    516  1.17.16.1       mjf 			    c + 1);
    517       1.16  christos 			len = ISAPNP_MAX_TAGSIZE - 1;
    518        1.4  christos 			if (++warned == 10)
    519        1.4  christos 				goto bad;
    520        1.1  christos 		}
    521        1.1  christos 
    522       1.12  christos 		if (isapnp_process_tag(tag, len, buf, &card, &dev,
    523       1.12  christos 		    &conf) == -1) {
    524  1.17.16.1       mjf 			aprint_error_dev(sc->sc_dev,
    525  1.17.16.1       mjf 			    "No current device for tag, card %d\n",
    526  1.17.16.1       mjf 			    c + 1);
    527       1.12  christos 			if (++warned == 10)
    528       1.12  christos 				goto bad;
    529       1.12  christos 		}
    530        1.1  christos 	}
    531        1.1  christos 	while (tag != ISAPNP_TAG_END);
    532        1.4  christos 	return isapnp_flatten(card);
    533        1.4  christos 
    534        1.1  christos bad:
    535        1.4  christos 	for (card = isapnp_flatten(card); card; ) {
    536        1.4  christos 		dev = card->ipa_sibling;
    537        1.4  christos 		ISAPNP_FREE(card);
    538        1.4  christos 		card = dev;
    539        1.1  christos 	}
    540  1.17.16.1       mjf 	aprint_normal_dev(sc->sc_dev, "%s, card %d\n",
    541        1.4  christos 	    warned >= 10 ? "Too many tag errors" : "Resource timeout", c + 1);
    542        1.1  christos 	return NULL;
    543        1.1  christos }
    544