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