xref: /netbsd-src/sys/dev/isapnp/isapnp.c (revision a5a68ff5f29de57339ca14f6c671c0a87714f1f8)
1 /*	$NetBSD: isapnp.c,v 1.9 1997/08/12 07:38:10 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  * ISA PnP bus autoconfiguration.
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 static void isapnp_init __P((struct isapnp_softc *));
49 static __inline u_char isapnp_shift_bit __P((struct isapnp_softc *));
50 static int isapnp_findcard __P((struct isapnp_softc *));
51 static void isapnp_free_region __P((bus_space_tag_t, struct isapnp_region *));
52 static int isapnp_alloc_region __P((bus_space_tag_t, struct isapnp_region *));
53 static int isapnp_alloc_pin __P((struct isapnp_pin *));
54 static int isapnp_testconfig __P((bus_space_tag_t, bus_space_tag_t,
55     struct isapnp_attach_args *, int));
56 static struct isapnp_attach_args *isapnp_bestconfig __P((struct isapnp_softc *,
57     struct isapnp_attach_args **));
58 static void isapnp_print_region __P((const char *, struct isapnp_region *,
59     size_t));
60 static void isapnp_configure __P((struct isapnp_softc *,
61     const struct isapnp_attach_args *));
62 static void isapnp_print_pin __P((const char *, struct isapnp_pin *, size_t));
63 static int isapnp_print __P((void *, const char *));
64 #ifdef _KERNEL
65 static int isapnp_submatch __P((struct device *, void *, void *));
66 #endif
67 static int isapnp_find __P((struct isapnp_softc *, int));
68 #ifdef __BROKEN_INDIRECT_CONFIG
69 static int isapnp_match __P((struct device *, void *, void *));
70 #else
71 static int isapnp_match __P((struct device *, struct cfdata *, void *));
72 #endif
73 static void isapnp_attach __P((struct device *, struct device *, void *));
74 
75 struct cfattach isapnp_ca = {
76 	sizeof(struct isapnp_softc), isapnp_match, isapnp_attach
77 };
78 
79 struct cfdriver isapnp_cd = {
80 	NULL, "isapnp", DV_DULL
81 };
82 
83 
84 /* isapnp_init():
85  *	Write the PNP initiation key to wake up the cards...
86  */
87 static void
88 isapnp_init(sc)
89 	struct isapnp_softc *sc;
90 {
91 	int i;
92 	u_char v = ISAPNP_LFSR_INIT;
93 
94 	/* First write 0's twice to enter the Wait for Key state */
95 	ISAPNP_WRITE_ADDR(sc, 0);
96 	ISAPNP_WRITE_ADDR(sc, 0);
97 
98 	/* Send the 32 byte sequence to awake the logic */
99 	for (i = 0; i < ISAPNP_LFSR_LENGTH; i++) {
100 		ISAPNP_WRITE_ADDR(sc, v);
101 		v = ISAPNP_LFSR_NEXT(v);
102 	}
103 }
104 
105 
106 /* isapnp_shift_bit():
107  *	Read a bit at a time from the config card.
108  */
109 static __inline u_char
110 isapnp_shift_bit(sc)
111 	struct isapnp_softc *sc;
112 {
113 	u_char c1, c2;
114 
115 	DELAY(250);
116 	c1 = ISAPNP_READ_DATA(sc);
117 	DELAY(250);
118 	c2 = ISAPNP_READ_DATA(sc);
119 
120 	if (c1 == 0x55 && c2 == 0xAA)
121 		return 0x80;
122 	else
123 		return 0;
124 }
125 
126 
127 /* isapnp_findcard():
128  *	Attempt to read the vendor/serial/checksum for a card
129  *	If a card is found [the checksum matches], assign the
130  *	next card number to it and return 1
131  */
132 static int
133 isapnp_findcard(sc)
134 	struct isapnp_softc *sc;
135 {
136 	u_char v = ISAPNP_LFSR_INIT, csum, w;
137 	int i, b;
138 
139 	if (sc->sc_ncards == ISAPNP_MAX_CARDS) {
140 		printf("%s: Too many pnp cards\n", sc->sc_dev.dv_xname);
141 		return 0;
142 	}
143 
144 	/* Set the read port */
145 	isapnp_write_reg(sc, ISAPNP_WAKE, 0);
146 	isapnp_write_reg(sc, ISAPNP_SET_RD_PORT, sc->sc_read_port >> 2);
147 	sc->sc_read_port |= 3;
148 	DELAY(1000);
149 
150 	ISAPNP_WRITE_ADDR(sc, ISAPNP_SERIAL_ISOLATION);
151 	DELAY(1000);
152 
153 	/* Read the 8 bytes of the Vendor ID and Serial Number */
154 	for(i = 0; i < 8; i++) {
155 		/* Read each bit separately */
156 		for (w = 0, b = 0; b < 8; b++) {
157 			u_char neg = isapnp_shift_bit(sc);
158 
159 			w >>= 1;
160 			w |= neg;
161 			v = ISAPNP_LFSR_NEXT(v) ^ neg;
162 		}
163 		sc->sc_id[sc->sc_ncards][i] = w;
164 	}
165 
166 	/* Read the remaining checksum byte */
167 	for (csum = 0, b = 0; b < 8; b++) {
168 		u_char neg = isapnp_shift_bit(sc);
169 
170 		csum >>= 1;
171 		csum |= neg;
172 	}
173 	sc->sc_id[sc->sc_ncards][8] = csum;
174 
175 	if (csum == v) {
176 		sc->sc_ncards++;
177 		isapnp_write_reg(sc, ISAPNP_CARD_SELECT_NUM, sc->sc_ncards);
178 		return 1;
179 	}
180 	return 0;
181 }
182 
183 
184 /* isapnp_free_region():
185  *	Free a region
186  */
187 static void
188 isapnp_free_region(t, r)
189 	bus_space_tag_t t;
190 	struct isapnp_region *r;
191 {
192 #ifdef _KERNEL
193 	bus_space_unmap(t, r->h, r->length);
194 #endif
195 }
196 
197 
198 /* isapnp_alloc_region():
199  *	Allocate a single region if possible
200  */
201 static int
202 isapnp_alloc_region(t, r)
203 	bus_space_tag_t t;
204 	struct isapnp_region *r;
205 {
206 	int error = 0;
207 
208 	for (r->base = r->minbase; r->base <= r->maxbase;
209 	     r->base += r->align) {
210 #ifdef _KERNEL
211 		error = bus_space_map(t, r->base, r->length, 0, &r->h);
212 #endif
213 		if (error == 0)
214 			return 0;
215 	}
216 	return error;
217 }
218 
219 
220 /* isapnp_alloc_pin():
221  *	Allocate an irq/drq
222  *	XXX: No resource conflict checks!
223  */
224 static int
225 isapnp_alloc_pin(i)
226 	struct isapnp_pin *i;
227 {
228 	int b;
229 
230 	if (i->bits == 0)
231 		i->num = 0;
232 	else
233 		for (b = 0; b < 16; b++)
234 			if (i->bits & (1 << b)) {
235 				i->num = b;
236 				break;
237 			}
238 	return 0;
239 }
240 
241 
242 /* isapnp_testconfig():
243  *	Test/Allocate the regions used
244  */
245 static int
246 isapnp_testconfig(iot, memt, ipa, alloc)
247 	bus_space_tag_t iot, memt;
248 	struct isapnp_attach_args *ipa;
249 	int alloc;
250 {
251 	int nio = 0, nmem = 0, nmem32 = 0, nirq = 0, ndrq = 0;
252 	int error = 0;
253 
254 #ifdef DEBUG_ISAPNP
255 	isapnp_print_attach(ipa);
256 #endif
257 
258 	for (; nio < ipa->ipa_nio; nio++) {
259 		error = isapnp_alloc_region(iot, &ipa->ipa_io[nio]);
260 		if (error)
261 			goto bad;
262 	}
263 
264 	for (; nmem < ipa->ipa_nmem; nmem++) {
265 		error = isapnp_alloc_region(memt, &ipa->ipa_mem[nmem]);
266 		if (error)
267 			goto bad;
268 	}
269 
270 	for (; nmem32 < ipa->ipa_nmem32; nmem32++) {
271 		error = isapnp_alloc_region(memt, &ipa->ipa_mem32[nmem32]);
272 		if (error)
273 			goto bad;
274 	}
275 
276 	for (; nirq < ipa->ipa_nirq; nirq++) {
277 		error = isapnp_alloc_pin(&ipa->ipa_irq[nirq]);
278 		if (error)
279 			goto bad;
280 	}
281 
282 	for (; ndrq < ipa->ipa_ndrq; ndrq++) {
283 		error = isapnp_alloc_pin(&ipa->ipa_drq[ndrq]);
284 		if (error)
285 			goto bad;
286 	}
287 
288 	if (alloc)
289 		return error;
290 
291 bad:
292 #ifdef notyet
293 	for (ndrq--; ndrq >= 0; ndrq--)
294 		isapnp_free_pin(&ipa->ipa_drq[ndrq]);
295 
296 	for (nirq--; nirq >= 0; nirq--)
297 		isapnp_free_pin(&ipa->ipa_irq[nirq]);
298 #endif
299 
300 	for (nmem32--; nmem32 >= 0; nmem32--)
301 		isapnp_free_region(memt, &ipa->ipa_mem32[nmem32]);
302 
303 	for (nmem--; nmem >= 0; nmem--)
304 		isapnp_free_region(memt, &ipa->ipa_mem[nmem]);
305 
306 	for (nio--; nio >= 0; nio--)
307 		isapnp_free_region(iot, &ipa->ipa_io[nio]);
308 
309 	return error;
310 }
311 
312 
313 /* isapnp_config():
314  *	Test/Allocate the regions used
315  */
316 int
317 isapnp_config(iot, memt, ipa)
318 	bus_space_tag_t iot, memt;
319 	struct isapnp_attach_args *ipa;
320 {
321 	return isapnp_testconfig(iot, memt, ipa, 1);
322 }
323 
324 
325 /* isapnp_unconfig():
326  *	Free the regions used
327  */
328 void
329 isapnp_unconfig(iot, memt, ipa)
330 	bus_space_tag_t iot, memt;
331 	struct isapnp_attach_args *ipa;
332 {
333 	int i;
334 
335 #ifdef notyet
336 	for (i = 0; i < ipa->ipa_ndrq; i++)
337 		isapnp_free_pin(&ipa->ipa_drq[i]);
338 
339 	for (i = 0; i < ipa->ipa_nirq; i++)
340 		isapnp_free_pin(&ipa->ipa_irq[i]);
341 #endif
342 
343 	for (i = 0; i < ipa->ipa_nmem32; i++)
344 		isapnp_free_region(memt, &ipa->ipa_mem32[i]);
345 
346 	for (i = 0; i < ipa->ipa_nmem; i++)
347 		isapnp_free_region(memt, &ipa->ipa_mem[i]);
348 
349 	for (i = 0; i < ipa->ipa_nio; i++)
350 		isapnp_free_region(iot, &ipa->ipa_io[i]);
351 }
352 
353 
354 /* isapnp_bestconfig():
355  *	Return the best configuration for each logical device, remove and
356  *	free all other configurations.
357  */
358 static struct isapnp_attach_args *
359 isapnp_bestconfig(sc, ipa)
360 	struct isapnp_softc *sc;
361 	struct isapnp_attach_args **ipa;
362 {
363 	struct isapnp_attach_args *c, *best, *f = *ipa;
364 	int error;
365 
366 	for (;;) {
367 		if (f == NULL)
368 			return NULL;
369 
370 #define SAMEDEV(a, b) (strcmp((a)->ipa_devlogic, (b)->ipa_devlogic) == 0)
371 
372 		/* Find the best config */
373 		for (best = c = f; c != NULL; c = c->ipa_sibling) {
374 			if (!SAMEDEV(c, f))
375 				continue;
376 			if (c->ipa_pref < best->ipa_pref)
377 				best = c;
378 		}
379 
380 		/* Test the best config */
381 		error = isapnp_testconfig(sc->sc_iot, sc->sc_memt, best, 0);
382 
383 		/* Remove this config from the list */
384 		if (best == f)
385 			f = f->ipa_sibling;
386 		else {
387 			for (c = f; c->ipa_sibling != best; c = c->ipa_sibling)
388 				continue;
389 			c->ipa_sibling = best->ipa_sibling;
390 		}
391 
392 		if (error) {
393 			best->ipa_pref = ISAPNP_DEP_CONFLICTING;
394 
395 			for (c = f; c != NULL; c = c->ipa_sibling)
396 				if (c != best && SAMEDEV(c, best))
397 					break;
398 			/* Last config for this logical device is conflicting */
399 			if (c == NULL) {
400 				*ipa = f;
401 				return best;
402 			}
403 
404 			ISAPNP_FREE(best);
405 			continue;
406 		}
407 		else {
408 			/* Remove all other configs for this device */
409 			struct isapnp_attach_args *l = NULL, *n = NULL, *d;
410 
411 			for (c = f; c; ) {
412 				if (c == best)
413 					continue;
414 				d = c->ipa_sibling;
415 				if (SAMEDEV(c, best))
416 					ISAPNP_FREE(c);
417 				else {
418 					if (n)
419 						n->ipa_sibling = c;
420 
421 					else
422 						l = c;
423 					n = c;
424 					c->ipa_sibling = NULL;
425 				}
426 				c = d;
427 			}
428 			f = l;
429 		}
430 		*ipa = f;
431 		return best;
432 	}
433 }
434 
435 
436 /* isapnp_id_to_vendor():
437  *	Convert a pnp ``compressed ascii'' vendor id to a string
438  */
439 char *
440 isapnp_id_to_vendor(v, id)
441 	char   *v;
442 	const u_char *id;
443 {
444 	static const char hex[] = "0123456789ABCDEF";
445 	char *p = v;
446 
447 	*p++ = 'A' + (id[0] >> 2) - 1;
448 	*p++ = 'A' + ((id[0] & 3) << 3) + (id[1] >> 5) - 1;
449 	*p++ = 'A' + (id[1] & 0x1f) - 1;
450 	*p++ = hex[id[2] >> 4];
451 	*p++ = hex[id[2] & 0x0f];
452 	*p++ = hex[id[3] >> 4];
453 	*p++ = hex[id[3] & 0x0f];
454 	*p = '\0';
455 
456 	return v;
457 }
458 
459 
460 /* isapnp_print_region():
461  *	Print a region allocation
462  */
463 static void
464 isapnp_print_region(str, r, n)
465 	const char *str;
466 	struct isapnp_region *r;
467 	size_t n;
468 {
469 	size_t i;
470 
471 	if (n == 0)
472 		return;
473 
474 	printf(" %s ", str);
475 	for (i = 0; i < n; i++, r++) {
476 		printf("0x%x", r->base);
477 		if (r->length)
478 			printf("/%d", r->length);
479 		if (i != n - 1)
480 			printf(",");
481 	}
482 }
483 
484 
485 /* isapnp_print_pin():
486  *	Print an irq/drq assignment
487  */
488 static void
489 isapnp_print_pin(str, p, n)
490 	const char *str;
491 	struct isapnp_pin *p;
492 	size_t n;
493 {
494 	size_t i;
495 
496 	if (n == 0)
497 		return;
498 
499 	printf(" %s ", str);
500 	for (i = 0; i < n; i++, p++) {
501 		printf("%d", p->num);
502 		if (i != n - 1)
503 			printf(",");
504 	}
505 }
506 
507 
508 /* isapnp_print():
509  *	Print the configuration line for an ISA PnP card.
510  */
511 static int
512 isapnp_print(aux, str)
513 	void *aux;
514 	const char *str;
515 {
516 	struct isapnp_attach_args *ipa = aux;
517 
518 	if (str != NULL)
519 		printf("%s: <%s, %s, %s, %s>",
520 		    str, ipa->ipa_devident, ipa->ipa_devlogic,
521 		    ipa->ipa_devcompat, ipa->ipa_devclass);
522 
523 	isapnp_print_region("port", ipa->ipa_io, ipa->ipa_nio);
524 	isapnp_print_region("mem", ipa->ipa_mem, ipa->ipa_nmem);
525 	isapnp_print_region("mem32", ipa->ipa_mem32, ipa->ipa_nmem32);
526 	isapnp_print_pin("irq", ipa->ipa_irq, ipa->ipa_nirq);
527 	isapnp_print_pin("drq", ipa->ipa_drq, ipa->ipa_ndrq);
528 
529 	return UNCONF;
530 }
531 
532 
533 #ifdef _KERNEL
534 /* isapnp_submatch():
535  *	Probe the logical device...
536  */
537 static int
538 isapnp_submatch(parent, match, aux)
539 	struct device *parent;
540 	void *match, *aux;
541 {
542 	struct cfdata *cf = match;
543 	return ((*cf->cf_attach->ca_match)(parent, match, aux));
544 }
545 #endif
546 
547 
548 /* isapnp_find():
549  *	Probe and add cards
550  */
551 static int
552 isapnp_find(sc, all)
553 	struct isapnp_softc *sc;
554 	int all;
555 {
556 	int p;
557 
558 	isapnp_init(sc);
559 
560 	isapnp_write_reg(sc, ISAPNP_CONFIG_CONTROL, ISAPNP_CC_RESET_DRV);
561 	DELAY(2000);
562 
563 	isapnp_init(sc);
564 	DELAY(2000);
565 
566 	for (p = ISAPNP_RDDATA_MIN; p <= ISAPNP_RDDATA_MAX; p += 4) {
567 		sc->sc_read_port = p;
568 		if (isapnp_map_readport(sc))
569 			continue;
570 		DPRINTF(("%s: Trying port %x\n", sc->sc_dev.dv_xname, p));
571 		if (isapnp_findcard(sc))
572 			break;
573 		isapnp_unmap_readport(sc);
574 	}
575 
576 	if (p > ISAPNP_RDDATA_MAX) {
577 		sc->sc_read_port = 0;
578 		return 0;
579 	}
580 
581 	if (all)
582 		while (isapnp_findcard(sc))
583 			continue;
584 
585 	return 1;
586 }
587 
588 
589 /* isapnp_configure():
590  *	Configure a PnP card
591  *	XXX: The memory configuration code is wrong. We need to check the
592  *	     range/length bit an do appropriate sets.
593  */
594 static void
595 isapnp_configure(sc, ipa)
596 	struct isapnp_softc *sc;
597 	const struct isapnp_attach_args *ipa;
598 {
599 	int i;
600 	static u_char isapnp_mem_range[] = ISAPNP_MEM_DESC;
601 	static u_char isapnp_io_range[] = ISAPNP_IO_DESC;
602 	static u_char isapnp_irq_range[] = ISAPNP_IRQ_DESC;
603 	static u_char isapnp_drq_range[] = ISAPNP_DRQ_DESC;
604 	static u_char isapnp_mem32_range[] = ISAPNP_MEM32_DESC;
605 	const struct isapnp_region *r;
606 	const struct isapnp_pin *p;
607 	struct isapnp_region rz;
608 	struct isapnp_pin pz;
609 
610 	memset(&pz, 0, sizeof(pz));
611 	memset(&rz, 0, sizeof(rz));
612 
613 #define B0(a) ((a) & 0xff)
614 #define B1(a) (((a) >> 8) & 0xff)
615 #define B2(a) (((a) >> 16) & 0xff)
616 #define B3(a) (((a) >> 24) & 0xff)
617 
618 	for (i = 0; i < sizeof(isapnp_io_range); i++) {
619 		if (i < ipa->ipa_nio)
620 			r = &ipa->ipa_io[i];
621 		else
622 			r = &rz;
623 
624 		isapnp_write_reg(sc,
625 		    isapnp_io_range[i] + ISAPNP_IO_BASE_15_8, B1(r->base));
626 		isapnp_write_reg(sc,
627 		    isapnp_io_range[i] + ISAPNP_IO_BASE_7_0, B0(r->base));
628 	}
629 
630 	for (i = 0; i < sizeof(isapnp_mem_range); i++) {
631 		if (i < ipa->ipa_nmem)
632 			r = &ipa->ipa_mem[i];
633 		else
634 			r = &rz;
635 
636 		isapnp_write_reg(sc,
637 		    isapnp_mem_range[i] + ISAPNP_MEM_BASE_23_16, B2(r->base));
638 		isapnp_write_reg(sc,
639 		    isapnp_mem_range[i] + ISAPNP_MEM_BASE_15_8, B1(r->base));
640 
641 		isapnp_write_reg(sc,
642 		    isapnp_mem_range[i] + ISAPNP_MEM_LRANGE_23_16,
643 		    B2(r->length));
644 		isapnp_write_reg(sc,
645 		    isapnp_mem_range[i] + ISAPNP_MEM_LRANGE_15_8,
646 		    B1(r->length));
647 	}
648 
649 	for (i = 0; i < sizeof(isapnp_irq_range); i++) {
650 		u_char v;
651 
652 		if (i < ipa->ipa_nirq)
653 			p = &ipa->ipa_irq[i];
654 		else
655 			p = &pz;
656 
657 		isapnp_write_reg(sc,
658 		    isapnp_irq_range[i] + ISAPNP_IRQ_NUMBER, p->num);
659 
660 		switch (p->flags) {
661 		case ISAPNP_IRQTYPE_LEVEL_PLUS:
662 			v = ISAPNP_IRQ_LEVEL|ISAPNP_IRQ_HIGH;
663 			break;
664 
665 		case ISAPNP_IRQTYPE_EDGE_PLUS:
666 			v = ISAPNP_IRQ_HIGH;
667 			break;
668 
669 		case ISAPNP_IRQTYPE_LEVEL_MINUS:
670 			v = ISAPNP_IRQ_LEVEL;
671 			break;
672 
673 		default:
674 		case ISAPNP_IRQTYPE_EDGE_MINUS:
675 			v = 0;
676 			break;
677 		}
678 		isapnp_write_reg(sc,
679 		    isapnp_irq_range[i] + ISAPNP_IRQ_CONTROL, v);
680 	}
681 
682 	for (i = 0; i < sizeof(isapnp_drq_range); i++) {
683 		u_char v;
684 
685 		if (i < ipa->ipa_ndrq)
686 			v = ipa->ipa_drq[i].num;
687 		else
688 			v = 4;
689 
690 		isapnp_write_reg(sc, isapnp_drq_range[i], v);
691 	}
692 
693 	for (i = 0; i < sizeof(isapnp_mem32_range); i++) {
694 		if (i < ipa->ipa_nmem32)
695 			r = &ipa->ipa_mem32[i];
696 		else
697 			r = &rz;
698 
699 		isapnp_write_reg(sc,
700 		    isapnp_mem32_range[i] + ISAPNP_MEM32_BASE_31_24,
701 		    B3(r->base));
702 		isapnp_write_reg(sc,
703 		    isapnp_mem32_range[i] + ISAPNP_MEM32_BASE_23_16,
704 		    B2(r->base));
705 		isapnp_write_reg(sc,
706 		    isapnp_mem32_range[i] + ISAPNP_MEM32_BASE_15_8,
707 		    B1(r->base));
708 		isapnp_write_reg(sc,
709 		    isapnp_mem32_range[i] + ISAPNP_MEM32_BASE_7_0,
710 		    B0(r->base));
711 
712 		isapnp_write_reg(sc,
713 		    isapnp_mem32_range[i] + ISAPNP_MEM32_LRANGE_31_24,
714 		    B3(r->length));
715 		isapnp_write_reg(sc,
716 		    isapnp_mem32_range[i] + ISAPNP_MEM32_LRANGE_23_16,
717 		    B2(r->length));
718 		isapnp_write_reg(sc,
719 		    isapnp_mem32_range[i] + ISAPNP_MEM32_LRANGE_15_8,
720 		    B1(r->length));
721 		isapnp_write_reg(sc,
722 		    isapnp_mem32_range[i] + ISAPNP_MEM32_LRANGE_7_0,
723 		    B0(r->length));
724 	}
725 }
726 
727 
728 /* isapnp_match():
729  *	Probe routine
730  */
731 static int
732 isapnp_match(parent, match, aux)
733 	struct device *parent;
734 #ifdef __BROKEN_INDIRECT_CONFIG
735 	void *match;
736 #else
737 	struct cfdata *match;
738 #endif
739 	void *aux;
740 {
741 	int rv;
742 	struct isapnp_softc sc;
743 	struct isa_attach_args *ia = aux;
744 
745 	sc.sc_iot = ia->ia_iot;
746 	sc.sc_ncards = 0;
747 	(void) strcpy(sc.sc_dev.dv_xname, "(isapnp probe)");
748 
749 	if (isapnp_map(&sc))
750 		return 0;
751 
752 	rv = isapnp_find(&sc, 0);
753 	ia->ia_iobase = ISAPNP_ADDR;
754 	ia->ia_iosize = 1;
755 
756 	isapnp_unmap(&sc);
757 	if (rv)
758 		isapnp_unmap_readport(&sc);
759 
760 	return (rv);
761 }
762 
763 
764 /* isapnp_attach
765  *	Find and attach PnP cards.
766  */
767 static void
768 isapnp_attach(parent, self, aux)
769 	struct device *parent, *self;
770 	void *aux;
771 {
772 	struct isapnp_softc *sc = (struct isapnp_softc *) self;
773 	struct isa_attach_args *ia = aux;
774 	int c, d;
775 
776 	sc->sc_iot = ia->ia_iot;
777 	sc->sc_memt = ia->ia_memt;
778 	sc->sc_ncards = 0;
779 
780 	if (isapnp_map(sc))
781 		panic("%s: bus map failed\n", sc->sc_dev.dv_xname);
782 
783 	if (!isapnp_find(sc, 1))
784 		panic("%s: no cards found\n", sc->sc_dev.dv_xname);
785 
786 	printf(": read port 0x%x\n", sc->sc_read_port);
787 
788 	for (c = 0; c < sc->sc_ncards; c++) {
789 		struct isapnp_attach_args *ipa, *lpa;
790 
791 		/* Good morning card c */
792 		isapnp_write_reg(sc, ISAPNP_WAKE, c + 1);
793 
794 		if ((ipa = isapnp_get_resource(sc, c)) == NULL)
795 			continue;
796 
797 		DPRINTF(("Selecting attachments\n"));
798 		for (d = 0; (lpa = isapnp_bestconfig(sc, &ipa)) != NULL; d++) {
799 			isapnp_write_reg(sc, ISAPNP_LOGICAL_DEV_NUM, d);
800 			isapnp_configure(sc, lpa);
801 #ifdef DEBUG_ISAPNP
802 			{
803 				struct isapnp_attach_args pa;
804 
805 				isapnp_get_config(sc, &pa);
806 				isapnp_print_config(&pa);
807 			}
808 #endif
809 
810 #ifdef DEBUG
811 			/* XXX do we even really need this?  --thorpej */
812 			printf("%s: configuring <%s, %s, %s, %s>\n",
813 			    sc->sc_dev.dv_xname,
814 			    lpa->ipa_devident, lpa->ipa_devlogic,
815 			    lpa->ipa_devcompat, lpa->ipa_devclass);
816 #endif
817 
818 			if (lpa->ipa_pref == ISAPNP_DEP_CONFLICTING) {
819 				printf("%s: <%s, %s, %s, %s> ignored; %s\n",
820 				    sc->sc_dev.dv_xname,
821 				    lpa->ipa_devident, lpa->ipa_devlogic,
822 				    lpa->ipa_devcompat, lpa->ipa_devclass,
823 				    "resource conflict");
824 				ISAPNP_FREE(lpa);
825 				continue;
826 			}
827 
828 			lpa->ipa_ic = ia->ia_ic;
829 			lpa->ipa_iot = ia->ia_iot;
830 			lpa->ipa_memt = ia->ia_memt;
831 			lpa->ipa_dmat = ia->ia_dmat;
832 
833 			isapnp_write_reg(sc, ISAPNP_ACTIVATE, 1);
834 #ifdef _KERNEL
835 			if (config_found_sm(self, lpa, isapnp_print,
836 			    isapnp_submatch) == NULL)
837 				isapnp_write_reg(sc, ISAPNP_ACTIVATE, 0);
838 #else
839 			isapnp_print(lpa, NULL);
840 			printf("\n");
841 #endif
842 			ISAPNP_FREE(lpa);
843 		}
844 		isapnp_write_reg(sc, ISAPNP_WAKE, 0);    /* Good night cards */
845 	}
846 }
847