xref: /openbsd-src/sys/dev/isa/isapnp.c (revision b2ea75c1b17e1a9a339660e7ed45cd24946b230e)
1 /*	$OpenBSD: isapnp.c,v 1.30 2001/01/29 06:16:14 mickey Exp $	*/
2 /*	$NetBSD: isapnp.c,v 1.9.4.3 1997/10/29 00:40:43 thorpej Exp $	*/
3 
4 /*
5  * Copyright (c) 1996 Christos Zoulas.  All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. All advertising materials mentioning features or use of this software
16  *    must display the following acknowledgement:
17  *	This product includes software developed by Christos Zoulas.
18  * 4. The name of the author may not be used to endorse or promote products
19  *    derived from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 /*
34  * ISA PnP bus autoconfiguration.
35  */
36 
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/device.h>
40 #include <sys/malloc.h>
41 
42 #include <machine/bus.h>
43 
44 #include <dev/isa/isapnpreg.h>
45 
46 #include <dev/isa/isavar.h>
47 #include <dev/isa/isadmavar.h>
48 
49 #include <dev/isa/pnpdevs.h>
50 
51 void isapnp_init __P((struct isapnp_softc *));
52 static __inline u_char isapnp_shift_bit __P((struct isapnp_softc *));
53 int isapnp_findcard __P((struct isapnp_softc *));
54 void isapnp_free_region __P((bus_space_tag_t, struct isapnp_region *));
55 int isapnp_alloc_region __P((bus_space_tag_t, struct isapnp_region *));
56 int isapnp_alloc_irq __P((isa_chipset_tag_t, struct isapnp_pin *));
57 int isapnp_alloc_drq __P((struct device *, struct isapnp_pin *));
58 int isapnp_testconfig __P((bus_space_tag_t, bus_space_tag_t,
59     struct isa_attach_args *, int));
60 struct isa_attach_args *isapnp_bestconfig __P((struct device *,
61     struct isapnp_softc *, struct isa_attach_args **));
62 void isapnp_print_region __P((const char *, struct isapnp_region *,
63     size_t));
64 void isapnp_configure __P((struct isapnp_softc *,
65     const struct isa_attach_args *));
66 void isapnp_print_pin __P((const char *, struct isapnp_pin *, size_t));
67 int isapnp_print __P((void *, const char *));
68 int isapnp_submatch __P((struct device *, void *, void *));
69 int isapnp_com_submatch __P((struct device *, void *, void *));
70 int isapnp_find __P((struct isapnp_softc *, int));
71 int isapnp_match __P((struct device *, void *, void *));
72 void isapnp_attach __P((struct device *, struct device *, void *));
73 
74 #ifdef DEBUG_ISAPNP
75 # define DPRINTF(a) printf a
76 #else
77 # define DPRINTF(a)
78 #endif
79 
80 struct cfattach isapnp_ca = {
81 	sizeof(struct isapnp_softc), isapnp_match, isapnp_attach
82 };
83 
84 struct cfdriver isapnp_cd = {
85 	NULL, "isapnp", DV_DULL
86 };
87 
88 
89 /* isapnp_init():
90  *	Write the PNP initiation key to wake up the cards...
91  */
92 void
93 isapnp_init(sc)
94 	struct isapnp_softc *sc;
95 {
96 	int i;
97 	u_char v = ISAPNP_LFSR_INIT;
98 
99 	/* First write 0's twice to enter the Wait for Key state */
100 	ISAPNP_WRITE_ADDR(sc, 0);
101 	ISAPNP_WRITE_ADDR(sc, 0);
102 
103 	/* Send the 32 byte sequence to awake the logic */
104 	for (i = 0; i < ISAPNP_LFSR_LENGTH; i++) {
105 		ISAPNP_WRITE_ADDR(sc, v);
106 		v = ISAPNP_LFSR_NEXT(v);
107 	}
108 }
109 
110 
111 /* isapnp_shift_bit():
112  *	Read a bit at a time from the config card.
113  */
114 static __inline u_char
115 isapnp_shift_bit(sc)
116 	struct isapnp_softc *sc;
117 {
118 	u_char c1, c2;
119 
120 	DELAY(250);
121 	c1 = ISAPNP_READ_DATA(sc);
122 	DELAY(250);
123 	c2 = ISAPNP_READ_DATA(sc);
124 
125 	if (c1 == 0x55 && c2 == 0xAA)
126 		return 0x80;
127 	else
128 		return 0;
129 }
130 
131 
132 /* isapnp_findcard():
133  *	Attempt to read the vendor/serial/checksum for a card
134  *	If a card is found [the checksum matches], assign the
135  *	next card number to it and return 1
136  */
137 int
138 isapnp_findcard(sc)
139 	struct isapnp_softc *sc;
140 {
141 	u_char v = ISAPNP_LFSR_INIT, csum, w;
142 	int i, b;
143 
144 	if (sc->sc_ncards == ISAPNP_MAX_CARDS) {
145 		printf("%s: Too many pnp cards\n", sc->sc_dev.dv_xname);
146 		return 0;
147 	}
148 
149 	/* Set the read port */
150 	isapnp_write_reg(sc, ISAPNP_WAKE, 0);
151 	isapnp_write_reg(sc, ISAPNP_SET_RD_PORT, sc->sc_read_port >> 2);
152 	sc->sc_read_port |= 3;
153 	DELAY(1000);
154 
155 	ISAPNP_WRITE_ADDR(sc, ISAPNP_SERIAL_ISOLATION);
156 	DELAY(1000);
157 
158 	/* Read the 8 bytes of the Vendor ID and Serial Number */
159 	for(i = 0; i < 8; i++) {
160 		/* Read each bit separately */
161 		for (w = 0, b = 0; b < 8; b++) {
162 			u_char neg = isapnp_shift_bit(sc);
163 
164 			w >>= 1;
165 			w |= neg;
166 			v = ISAPNP_LFSR_NEXT(v) ^ neg;
167 		}
168 		sc->sc_id[sc->sc_ncards][i] = w;
169 	}
170 
171 	/* Read the remaining checksum byte */
172 	for (csum = 0, b = 0; b < 8; b++) {
173 		u_char neg = isapnp_shift_bit(sc);
174 
175 		csum >>= 1;
176 		csum |= neg;
177 	}
178 	sc->sc_id[sc->sc_ncards][8] = csum;
179 
180 	if (csum == v) {
181 		sc->sc_ncards++;
182 		isapnp_write_reg(sc, ISAPNP_CARD_SELECT_NUM, sc->sc_ncards);
183 		return 1;
184 	}
185 	return 0;
186 }
187 
188 
189 /* isapnp_free_region():
190  *	Free a region
191  */
192 void
193 isapnp_free_region(t, r)
194 	bus_space_tag_t t;
195 	struct isapnp_region *r;
196 {
197 	if (r->length == 0)
198 		return;
199 
200 	bus_space_unmap(t, r->h, r->length);
201 	r->h = NULL;
202 }
203 
204 
205 /* isapnp_alloc_region():
206  *	Allocate a single region if possible
207  */
208 int
209 isapnp_alloc_region(t, r)
210 	bus_space_tag_t t;
211 	struct isapnp_region *r;
212 {
213 	int error = 0;
214 
215 	if (r->length == 0)
216 		return 0;
217 
218 	r->h = NULL;
219 	for (r->base = r->minbase; r->base <= r->maxbase;
220 	     r->base += r->align) {
221 		error = bus_space_map(t, r->base, r->length, 0, &r->h);
222 		if (error == 0)
223 			return 0;
224 	}
225 	return error;
226 }
227 
228 
229 /* isapnp_alloc_irq():
230  *	Allocate an irq
231  */
232 int
233 isapnp_alloc_irq(ic, i)
234 	isa_chipset_tag_t ic;
235 	struct isapnp_pin *i;
236 {
237 	int irq;
238 #define LEVEL_IRQ (ISAPNP_IRQTYPE_LEVEL_PLUS|ISAPNP_IRQTYPE_LEVEL_MINUS)
239 	i->type = (i->flags & LEVEL_IRQ) ? IST_LEVEL : IST_EDGE;
240 
241 	if (i->bits == 0) {
242 		i->num = 0;
243 		return 0;
244 	}
245 
246 	if (isa_intr_alloc(ic, i->bits, i->type, &irq) == 0) {
247 		i->num = irq;
248 		return 0;
249 	}
250 
251 	return EINVAL;
252 }
253 
254 /* isapnp_alloc_drq():
255  *	Allocate a drq
256  */
257 int
258 isapnp_alloc_drq(isa, i)
259 	struct device *isa;
260 	struct isapnp_pin *i;
261 {
262 	int b;
263 
264 	if (i->bits == 0) {
265 		i->num = 0;
266 		return 0;
267 	}
268 
269 	for (b = 0; b < 16; b++)
270 		if ((i->bits & (1 << b)) && isa_drq_isfree(isa, b)) {
271 			i->num = b;
272 			return 0;
273 		}
274 
275 	return EINVAL;
276 }
277 
278 /* isapnp_testconfig():
279  *	Test/Allocate the regions used
280  */
281 int
282 isapnp_testconfig(iot, memt, ipa, alloc)
283 	bus_space_tag_t iot, memt;
284 	struct isa_attach_args *ipa;
285 	int alloc;
286 {
287 	int nio = 0, nmem = 0, nmem32 = 0, nirq = 0, ndrq = 0;
288 	int error = 0;
289 
290 #ifdef DEBUG_ISAPNP
291 	isapnp_print_attach(ipa);
292 #endif
293 
294 	for (; nio < ipa->ipa_nio; nio++) {
295 		error = isapnp_alloc_region(iot, &ipa->ipa_io[nio]);
296 		if (error)
297 			goto bad;
298 	}
299 
300 	for (; nmem < ipa->ipa_nmem; nmem++) {
301 		error = isapnp_alloc_region(memt, &ipa->ipa_mem[nmem]);
302 		if (error)
303 			goto bad;
304 	}
305 
306 	for (; nmem32 < ipa->ipa_nmem32; nmem32++) {
307 		error = isapnp_alloc_region(memt, &ipa->ipa_mem32[nmem32]);
308 		if (error)
309 			goto bad;
310 	}
311 
312 	for (; nirq < ipa->ipa_nirq; nirq++) {
313 		error = isapnp_alloc_irq(ipa->ia_ic, &ipa->ipa_irq[nirq]);
314 		if (error)
315 			goto bad;
316 	}
317 
318 	for (; ndrq < ipa->ipa_ndrq; ndrq++) {
319 		error = isapnp_alloc_drq(ipa->ia_isa, &ipa->ipa_drq[ndrq]);
320 		if (error)
321 			goto bad;
322 	}
323 
324 	if (alloc)
325 		return error;
326 
327 bad:
328 #ifdef notyet
329 	for (ndrq--; ndrq >= 0; ndrq--)
330 		isapnp_free_pin(&ipa->ipa_drq[ndrq]);
331 
332 	for (nirq--; nirq >= 0; nirq--)
333 		isapnp_free_pin(&ipa->ipa_irq[nirq]);
334 #endif
335 
336 	for (nmem32--; nmem32 >= 0; nmem32--)
337 		isapnp_free_region(memt, &ipa->ipa_mem32[nmem32]);
338 
339 	for (nmem--; nmem >= 0; nmem--)
340 		isapnp_free_region(memt, &ipa->ipa_mem[nmem]);
341 
342 	for (nio--; nio >= 0; nio--)
343 		isapnp_free_region(iot, &ipa->ipa_io[nio]);
344 
345 	return error;
346 }
347 
348 
349 /* isapnp_config():
350  *	Test/Allocate the regions used
351  */
352 int
353 isapnp_config(iot, memt, ipa)
354 	bus_space_tag_t iot, memt;
355 	struct isa_attach_args *ipa;
356 {
357 	return isapnp_testconfig(iot, memt, ipa, 1);
358 }
359 
360 
361 /* isapnp_unconfig():
362  *	Free the regions used
363  */
364 void
365 isapnp_unconfig(iot, memt, ipa)
366 	bus_space_tag_t iot, memt;
367 	struct isa_attach_args *ipa;
368 {
369 	int i;
370 
371 #ifdef notyet
372 	for (i = 0; i < ipa->ipa_ndrq; i++)
373 		isapnp_free_pin(&ipa->ipa_drq[i]);
374 
375 	for (i = 0; i < ipa->ipa_nirq; i++)
376 		isapnp_free_pin(&ipa->ipa_irq[i]);
377 #endif
378 
379 	for (i = 0; i < ipa->ipa_nmem32; i++)
380 		isapnp_free_region(memt, &ipa->ipa_mem32[i]);
381 
382 	for (i = 0; i < ipa->ipa_nmem; i++)
383 		isapnp_free_region(memt, &ipa->ipa_mem[i]);
384 
385 	for (i = 0; i < ipa->ipa_nio; i++)
386 		isapnp_free_region(iot, &ipa->ipa_io[i]);
387 }
388 
389 
390 /* isapnp_bestconfig():
391  *	Return the best configuration for each logical device, remove and
392  *	free all other configurations.
393  */
394 struct isa_attach_args *
395 isapnp_bestconfig(isa, sc, ipa)
396 	struct device *isa;
397 	struct isapnp_softc *sc;
398 	struct isa_attach_args **ipa;
399 {
400 	struct isa_attach_args *c, *best, *f = *ipa;
401 	int error;
402 
403 	for (;;) {
404 		if (f == NULL)
405 			return NULL;
406 
407 #define SAMEDEV(a, b) (strcmp((a)->ipa_devlogic, (b)->ipa_devlogic) == 0)
408 
409 		/* Find the best config */
410 		for (best = c = f; c != NULL; c = c->ipa_sibling) {
411 			if (!SAMEDEV(c, f))
412 				continue;
413 			if (c->ipa_pref < best->ipa_pref)
414 				best = c;
415 		}
416 
417 		best->ia_isa = isa;
418 		/* Test the best config */
419 		error = isapnp_testconfig(sc->sc_iot, sc->sc_memt, best, 0);
420 
421 		/* Remove this config from the list */
422 		if (best == f)
423 			f = f->ipa_sibling;
424 		else {
425 			for (c = f; c->ipa_sibling != best; c = c->ipa_sibling)
426 				continue;
427 			c->ipa_sibling = best->ipa_sibling;
428 		}
429 
430 		if (error) {
431 			best->ipa_pref = ISAPNP_DEP_CONFLICTING;
432 
433 			for (c = f; c != NULL; c = c->ipa_sibling)
434 				if (c != best && SAMEDEV(c, best))
435 					break;
436 			/* Last config for this logical device is conflicting */
437 			if (c == NULL) {
438 				*ipa = f;
439 				return best;
440 			}
441 
442 			ISAPNP_FREE(best);
443 			continue;
444 		}
445 		else {
446 			/* Remove all other configs for this device */
447 			struct isa_attach_args *l = NULL, *n = NULL, *d;
448 
449 			for (c = f; c; ) {
450 				if (c == best)
451 					continue;
452 				d = c->ipa_sibling;
453 				if (SAMEDEV(c, best))
454 					ISAPNP_FREE(c);
455 				else {
456 					if (n)
457 						n->ipa_sibling = c;
458 
459 					else
460 						l = c;
461 					n = c;
462 					c->ipa_sibling = NULL;
463 				}
464 				c = d;
465 			}
466 			f = l;
467 		}
468 		*ipa = f;
469 		return best;
470 	}
471 }
472 
473 
474 /* isapnp_id_to_vendor():
475  *	Convert a pnp ``compressed ascii'' vendor id to a string
476  */
477 char *
478 isapnp_id_to_vendor(v, id)
479 	char   *v;
480 	const u_char *id;
481 {
482 	static const char hex[] = "0123456789ABCDEF";
483 	char *p = v;
484 
485 	*p++ = 'A' + (id[0] >> 2) - 1;
486 	*p++ = 'A' + ((id[0] & 3) << 3) + (id[1] >> 5) - 1;
487 	*p++ = 'A' + (id[1] & 0x1f) - 1;
488 	*p++ = hex[id[2] >> 4];
489 	*p++ = hex[id[2] & 0x0f];
490 	*p++ = hex[id[3] >> 4];
491 	*p++ = hex[id[3] & 0x0f];
492 	*p = '\0';
493 
494 	return v;
495 }
496 
497 
498 /* isapnp_print_region():
499  *	Print a region allocation
500  */
501 void
502 isapnp_print_region(str, r, n)
503 	const char *str;
504 	struct isapnp_region *r;
505 	size_t n;
506 {
507 	size_t i;
508 
509 	if (n == 0)
510 		return;
511 
512 	printf(" %s ", str);
513 	for (i = 0; i < n; i++, r++) {
514 		printf("0x%x", r->base);
515 		if (r->length)
516 			printf("/%d", r->length);
517 		if (i != n - 1)
518 			printf(",");
519 	}
520 }
521 
522 
523 /* isapnp_print_pin():
524  *	Print an irq/drq assignment
525  */
526 void
527 isapnp_print_pin(str, p, n)
528 	const char *str;
529 	struct isapnp_pin *p;
530 	size_t n;
531 {
532 	size_t i;
533 
534 	if (n == 0)
535 		return;
536 
537 	printf(" %s ", str);
538 	for (i = 0; i < n; i++, p++) {
539 		printf("%d", p->num);
540 		if (i != n - 1)
541 			printf(",");
542 	}
543 }
544 
545 /* isapnp_print():
546  *	Print the configuration line for an ISA PnP card.
547  */
548 int
549 isapnp_print(aux, str)
550 	void *aux;
551 	const char *str;
552 {
553 	struct isa_attach_args *ipa = aux;
554 
555 	if (!str)
556 		printf(" ");
557 	printf("\"%s, %s, %s, %s\"", ipa->ipa_devident,
558 	    ipa->ipa_devlogic, ipa->ipa_devcompat, ipa->ipa_devclass);
559 
560 	if (str)
561 		printf(" at %s", str);
562 
563 	isapnp_print_region("port", ipa->ipa_io, ipa->ipa_nio);
564 	isapnp_print_region("mem", ipa->ipa_mem, ipa->ipa_nmem);
565 	isapnp_print_region("mem32", ipa->ipa_mem32, ipa->ipa_nmem32);
566 	isapnp_print_pin("irq", ipa->ipa_irq, ipa->ipa_nirq);
567 	isapnp_print_pin("drq", ipa->ipa_drq, ipa->ipa_ndrq);
568 	return UNCONF;
569 }
570 
571 
572 /* isapnp_submatch():
573  * Special case.
574  * A lot of com/pccom devices do not have the PNPxxx identifiers
575  * they should have.  If it looks like a modem..... let's try it.
576  */
577 int
578 isapnp_com_submatch(parent, match, aux)
579 	struct device *parent;
580 	void *match, *aux;
581 {
582 	struct cfdata *cf = match;
583 	struct isa_attach_args *ipa = aux;
584 
585 	if ((strcmp("com", cf->cf_driver->cd_name) == 0 ||
586 	    strcmp("pccom", cf->cf_driver->cd_name) == 0) &&
587 	    ipa->ipa_nio == 1 && ipa->ipa_nirq == 1 &&
588 	    ipa->ipa_ndrq == 0 && ipa->ipa_nmem == 0 &&
589 	    ipa->ipa_io[0].length == 8) {
590 		if (isapnp_config(ipa->ia_iot, ipa->ia_memt, ipa)) {
591 			printf("%s: error in region allocation\n",
592 			    cf->cf_driver->cd_name);
593 			return (0);
594 		}
595 		return ((*cf->cf_attach->ca_match)(parent, match, ipa));
596 	}
597 	return (0);
598 }
599 
600 /* isapnp_submatch():
601  *	Probe the logical device...
602  */
603 int
604 isapnp_submatch(parent, match, aux)
605 	struct device *parent;
606 	void *match, *aux;
607 {
608 	struct cfdata *cf = match;
609 	struct isa_attach_args *ipa = aux;
610 	const char *dname;
611 	int i;
612 
613 	for (i = 0; i < sizeof(isapnp_knowndevs)/sizeof(isapnp_knowndevs[0]); i++) {
614 		dname = NULL;
615 
616 		if (strcmp(isapnp_knowndevs[i].pnpid, ipa->ipa_devlogic) == 0)
617 			dname = isapnp_knowndevs[i].driver;
618 		else if (strcmp(isapnp_knowndevs[i].pnpid, ipa->ipa_devcompat) == 0)
619 			dname = isapnp_knowndevs[i].driver;
620 
621 		if (dname && strcmp(dname, cf->cf_driver->cd_name) == 0) {
622 			/*
623 			 * We found a match.  Configure the card and call the
624 			 * ISA probe...
625 			 */
626 			if (isapnp_config(ipa->ia_iot, ipa->ia_memt, ipa)) {
627 				printf("%s: error in region allocation\n",
628 				    cf->cf_driver->cd_name);
629 				return (0);
630 			}
631 
632 			return ((*cf->cf_attach->ca_match)(parent, match, ipa));
633 		}
634 	}
635 
636 	return (0);
637 }
638 
639 /* isapnp_find():
640  *	Probe and add cards
641  */
642 int
643 isapnp_find(sc, all)
644 	struct isapnp_softc *sc;
645 	int all;
646 {
647 	int p;
648 
649 	isapnp_init(sc);
650 
651 	isapnp_write_reg(sc, ISAPNP_CONFIG_CONTROL, ISAPNP_CC_RESET_DRV);
652 	DELAY(2000);
653 
654 	isapnp_init(sc);
655 	DELAY(2000);
656 
657 	for (p = ISAPNP_RDDATA_MIN; p <= ISAPNP_RDDATA_MAX; p += 4) {
658 		sc->sc_read_port = p;
659 		if (isapnp_map_readport(sc))
660 			continue;
661 		DPRINTF(("%s: Trying port %x\n", sc->sc_dev.dv_xname, p));
662 		if (isapnp_findcard(sc))
663 			break;
664 		isapnp_unmap_readport(sc);
665 	}
666 
667 	if (p > ISAPNP_RDDATA_MAX) {
668 		sc->sc_read_port = 0;
669 		return 0;
670 	}
671 
672 	if (all)
673 		while (isapnp_findcard(sc))
674 			continue;
675 
676 	return 1;
677 }
678 
679 
680 /* isapnp_configure():
681  *	Configure a PnP card
682  *	XXX: The memory configuration code is wrong. We need to check the
683  *	     range/length bit an do appropriate sets.
684  */
685 void
686 isapnp_configure(sc, ipa)
687 	struct isapnp_softc *sc;
688 	const struct isa_attach_args *ipa;
689 {
690 	int i;
691 	static u_char isapnp_mem_range[] = ISAPNP_MEM_DESC;
692 	static u_char isapnp_io_range[] = ISAPNP_IO_DESC;
693 	static u_char isapnp_irq_range[] = ISAPNP_IRQ_DESC;
694 	static u_char isapnp_drq_range[] = ISAPNP_DRQ_DESC;
695 	static u_char isapnp_mem32_range[] = ISAPNP_MEM32_DESC;
696 	const struct isapnp_region *r;
697 	const struct isapnp_pin *p;
698 	struct isapnp_region rz;
699 	struct isapnp_pin pz;
700 
701 	bzero(&pz, sizeof(pz));
702 	bzero(&rz, sizeof(rz));
703 
704 #define B0(a) ((a) & 0xff)
705 #define B1(a) (((a) >> 8) & 0xff)
706 #define B2(a) (((a) >> 16) & 0xff)
707 #define B3(a) (((a) >> 24) & 0xff)
708 
709 	for (i = 0; i < sizeof(isapnp_io_range); i++) {
710 		if (i < ipa->ipa_nio)
711 			r = &ipa->ipa_io[i];
712 		else
713 			r = &rz;
714 
715 		isapnp_write_reg(sc,
716 		    isapnp_io_range[i] + ISAPNP_IO_BASE_15_8, B1(r->base));
717 		isapnp_write_reg(sc,
718 		    isapnp_io_range[i] + ISAPNP_IO_BASE_7_0, B0(r->base));
719 	}
720 
721 	for (i = 0; i < sizeof(isapnp_mem_range); i++) {
722 		if (i < ipa->ipa_nmem)
723 			r = &ipa->ipa_mem[i];
724 		else
725 			r = &rz;
726 
727 		isapnp_write_reg(sc,
728 		    isapnp_mem_range[i] + ISAPNP_MEM_BASE_23_16, B2(r->base));
729 		isapnp_write_reg(sc,
730 		    isapnp_mem_range[i] + ISAPNP_MEM_BASE_15_8, B1(r->base));
731 
732 		isapnp_write_reg(sc,
733 		    isapnp_mem_range[i] + ISAPNP_MEM_LRANGE_23_16,
734 		    B2(r->length));
735 		isapnp_write_reg(sc,
736 		    isapnp_mem_range[i] + ISAPNP_MEM_LRANGE_15_8,
737 		    B1(r->length));
738 	}
739 
740 	for (i = 0; i < sizeof(isapnp_irq_range); i++) {
741 		u_char v;
742 
743 		if (i < ipa->ipa_nirq)
744 			p = &ipa->ipa_irq[i];
745 		else
746 			p = &pz;
747 
748 		isapnp_write_reg(sc,
749 		    isapnp_irq_range[i] + ISAPNP_IRQ_NUMBER, p->num);
750 
751 		switch (p->flags) {
752 		case ISAPNP_IRQTYPE_LEVEL_PLUS:
753 			v = ISAPNP_IRQ_LEVEL|ISAPNP_IRQ_HIGH;
754 			break;
755 
756 		case ISAPNP_IRQTYPE_EDGE_PLUS:
757 			v = ISAPNP_IRQ_HIGH;
758 			break;
759 
760 		case ISAPNP_IRQTYPE_LEVEL_MINUS:
761 			v = ISAPNP_IRQ_LEVEL;
762 			break;
763 
764 		default:
765 		case ISAPNP_IRQTYPE_EDGE_MINUS:
766 			v = 0;
767 			break;
768 		}
769 		isapnp_write_reg(sc,
770 		    isapnp_irq_range[i] + ISAPNP_IRQ_CONTROL, v);
771 	}
772 
773 	for (i = 0; i < sizeof(isapnp_drq_range); i++) {
774 		u_char v;
775 
776 		if (i < ipa->ipa_ndrq)
777 			v = ipa->ipa_drq[i].num;
778 		else
779 			v = 4;
780 
781 		isapnp_write_reg(sc, isapnp_drq_range[i], v);
782 	}
783 
784 	for (i = 0; i < sizeof(isapnp_mem32_range); i++) {
785 		if (i < ipa->ipa_nmem32)
786 			r = &ipa->ipa_mem32[i];
787 		else
788 			r = &rz;
789 
790 		isapnp_write_reg(sc,
791 		    isapnp_mem32_range[i] + ISAPNP_MEM32_BASE_31_24,
792 		    B3(r->base));
793 		isapnp_write_reg(sc,
794 		    isapnp_mem32_range[i] + ISAPNP_MEM32_BASE_23_16,
795 		    B2(r->base));
796 		isapnp_write_reg(sc,
797 		    isapnp_mem32_range[i] + ISAPNP_MEM32_BASE_15_8,
798 		    B1(r->base));
799 		isapnp_write_reg(sc,
800 		    isapnp_mem32_range[i] + ISAPNP_MEM32_BASE_7_0,
801 		    B0(r->base));
802 
803 		isapnp_write_reg(sc,
804 		    isapnp_mem32_range[i] + ISAPNP_MEM32_LRANGE_31_24,
805 		    B3(r->length));
806 		isapnp_write_reg(sc,
807 		    isapnp_mem32_range[i] + ISAPNP_MEM32_LRANGE_23_16,
808 		    B2(r->length));
809 		isapnp_write_reg(sc,
810 		    isapnp_mem32_range[i] + ISAPNP_MEM32_LRANGE_15_8,
811 		    B1(r->length));
812 		isapnp_write_reg(sc,
813 		    isapnp_mem32_range[i] + ISAPNP_MEM32_LRANGE_7_0,
814 		    B0(r->length));
815 	}
816 }
817 
818 
819 /*
820  * Some BIOSes take the liberty of configuring our ISA cards for us.
821  * This code undoes the PNP card configuration.
822  */
823 
824 void
825 isapnp_isa_attach_hook(isa_sc)
826 	struct isa_softc *isa_sc;
827 
828 {
829 	struct isapnp_softc sc;
830 
831 	bzero(&sc, sizeof sc);
832 	sc.sc_iot = isa_sc->sc_iot;
833 	sc.sc_ncards = 0;
834 
835 	if (isapnp_map(&sc))
836 		return;
837 
838 	isapnp_init(&sc);
839 
840 	isapnp_write_reg(&sc, ISAPNP_CONFIG_CONTROL, ISAPNP_CC_RESET_DRV);
841 	DELAY(2000);
842 
843 	isapnp_unmap(&sc);
844 }
845 
846 /* isapnp_match():
847  *	Probe routine
848  */
849 int
850 isapnp_match(parent, match, aux)
851 	struct device *parent;
852 	void *match;
853 	void *aux;
854 {
855 	int rv;
856 	struct isapnp_softc sc;
857 	struct isa_attach_args *ia = aux;
858 
859 	sc.sc_iot = ia->ia_iot;
860 	sc.sc_ncards = 0;
861 	(void) strcpy(sc.sc_dev.dv_xname, "(isapnp probe)");
862 
863 	if (isapnp_map(&sc))
864 		return 0;
865 
866 	rv = isapnp_find(&sc, 0);
867 	ia->ia_iobase = ISAPNP_ADDR;
868 	ia->ia_iosize = 1;
869 
870 	isapnp_unmap(&sc);
871 	if (rv)
872 		isapnp_unmap_readport(&sc);
873 
874 	return (rv);
875 }
876 
877 
878 /* isapnp_attach
879  *	Find and attach PnP cards.
880  */
881 void
882 isapnp_attach(parent, self, aux)
883 	struct device *parent, *self;
884 	void *aux;
885 {
886 	struct isapnp_softc *sc = (struct isapnp_softc *) self;
887 	struct isa_attach_args *ia = aux;
888 	void *match;
889 	int c, d;
890 
891 	sc->sc_iot = ia->ia_iot;
892 	sc->sc_memt = ia->ia_memt;
893 #if NISADMA > 0
894 	sc->sc_dmat = ia->ia_dmat;
895 #endif
896 	sc->sc_ncards = 0;
897 
898 	if (isapnp_map(sc))
899 		panic("%s: bus map failed", sc->sc_dev.dv_xname);
900 
901 	if (!isapnp_find(sc, 1)) {
902 		printf(": no cards found\n", sc->sc_dev.dv_xname);
903 		return;
904 	}
905 
906 	printf(": read port 0x%x\n", sc->sc_read_port);
907 
908 	for (c = 0; c < sc->sc_ncards; c++) {
909 		struct isa_attach_args *ipa, *lpa;
910 
911 		/* Good morning card c */
912 		isapnp_write_reg(sc, ISAPNP_WAKE, c + 1);
913 
914 		if ((ipa = isapnp_get_resource(sc, c)) == NULL)
915 			continue;
916 
917 		DPRINTF(("Selecting attachments\n"));
918 		for (d = 0;
919 		    (lpa = isapnp_bestconfig(parent, sc, &ipa)) != NULL; d++) {
920 			isapnp_write_reg(sc, ISAPNP_LOGICAL_DEV_NUM, d);
921 			isapnp_configure(sc, lpa);
922 #ifdef DEBUG_ISAPNP
923 			{
924 				struct isa_attach_args pa;
925 
926 				isapnp_get_config(sc, &pa);
927 				isapnp_print_config(&pa);
928 			}
929 #endif
930 
931 			DPRINTF(("%s: configuring <%s, %s, %s, %s>\n",
932 			    sc->sc_dev.dv_xname,
933 			    lpa->ipa_devident, lpa->ipa_devlogic,
934 			    lpa->ipa_devcompat, lpa->ipa_devclass));
935 			if (lpa->ipa_pref == ISAPNP_DEP_CONFLICTING) {
936 				isapnp_print(lpa, self->dv_xname);
937 				printf(" resource conflict\n");
938 				ISAPNP_FREE(lpa);
939 				continue;
940 			}
941 
942 			lpa->ia_ic = ia->ia_ic;
943 			lpa->ia_iot = ia->ia_iot;
944 			lpa->ia_memt = ia->ia_memt;
945 #if NISADMA > 0
946 			lpa->ia_dmat = ia->ia_dmat;
947 #endif
948 			lpa->ia_delaybah = ia->ia_delaybah;
949 
950 			isapnp_write_reg(sc, ISAPNP_ACTIVATE, 1);
951 
952 			if ((match = config_search(isapnp_submatch,
953 			    self, lpa)))
954 				config_attach(self, match, lpa, isapnp_print);
955 			else if ((match = config_search(isapnp_com_submatch,
956 			    self, lpa)))
957 				config_attach(self, match, lpa, isapnp_print);
958 			else {
959 				isapnp_print(lpa, self->dv_xname);
960 				printf(" not configured\n");
961 				isapnp_write_reg(sc, ISAPNP_ACTIVATE, 0);
962 			}
963 			ISAPNP_FREE(lpa);
964 		}
965 		isapnp_write_reg(sc, ISAPNP_WAKE, 0);    /* Good night cards */
966 	}
967 }
968