The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/isa/isapnp.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: dfa63101b546b5ce9a4f74fc355bf97f


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.