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