root/dev/isa/isapnpres.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. isapnp_wait_status
  2. isapnp_newdev
  3. isapnp_newconf
  4. isapnp_merge
  5. isapnp_flatten
  6. isapnp_process_tag
  7. isapnp_get_resource

    1 /*      $OpenBSD: isapnpres.c,v 1.6 2002/06/30 16:05:59 miod Exp $      */
    2 /*      $NetBSD: isapnpres.c,v 1.7.4.1 1997/11/20 07:46:13 mellon 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  * Resource parser for Plug and Play cards.
   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 
   48 int isapnp_wait_status(struct isapnp_softc *);
   49 struct isa_attach_args *
   50     isapnp_newdev(struct isa_attach_args *);
   51 struct isa_attach_args *
   52     isapnp_newconf(struct isa_attach_args *);
   53 void isapnp_merge(struct isa_attach_args *,
   54     const struct isa_attach_args *);
   55 struct isa_attach_args *
   56     isapnp_flatten(struct isa_attach_args *);
   57 int isapnp_process_tag(u_char, u_char, u_char *,
   58     struct isa_attach_args **, struct isa_attach_args **,
   59     struct isa_attach_args **);
   60 
   61 #ifdef DEBUG_ISAPNP
   62 # define DPRINTF(a) printf a
   63 #else
   64 # define DPRINTF(a)
   65 #endif
   66 
   67 /* isapnp_wait_status():
   68  *      Wait for the next byte of resource data to become available
   69  */
   70 int
   71 isapnp_wait_status(sc)
   72         struct isapnp_softc *sc;
   73 {
   74         int i;
   75 
   76         /* wait up to 1 ms for each resource byte */
   77         for (i = 0; i < 10; i++) {
   78                 if (isapnp_read_reg(sc, ISAPNP_STATUS) & 1)
   79                         return 0;
   80                 DELAY(100);
   81         }
   82         return 1;
   83 }
   84 
   85 
   86 /* isapnp_newdev():
   87  *      Add a new logical device to the current card; expand the configuration
   88  *      resources of the current card if needed.
   89  */
   90 struct isa_attach_args *
   91 isapnp_newdev(card)
   92         struct isa_attach_args *card;
   93 {
   94         struct isa_attach_args *ipa, *dev = ISAPNP_MALLOC(sizeof(*dev));
   95 
   96         ISAPNP_CLONE_SETUP(dev, card);
   97 
   98         dev->ipa_pref = ISAPNP_DEP_ACCEPTABLE;
   99         bcopy(card->ipa_devident, dev->ipa_devident,
  100             sizeof(card->ipa_devident));
  101 
  102         if (card->ipa_child == NULL)
  103                 card->ipa_child = dev;
  104         else {
  105                 for (ipa = card->ipa_child; ipa->ipa_sibling != NULL; 
  106                     ipa = ipa->ipa_sibling)
  107                         continue;
  108                 ipa->ipa_sibling = dev;
  109         }
  110 
  111 
  112         return dev;
  113 }
  114 
  115 
  116 /* isapnp_newconf():
  117  *      Add a new alternate configuration to a logical device
  118  */
  119 struct isa_attach_args *
  120 isapnp_newconf(dev)
  121         struct isa_attach_args *dev;
  122 {
  123         struct isa_attach_args *ipa, *conf = ISAPNP_MALLOC(sizeof(*conf));
  124 
  125         ISAPNP_CLONE_SETUP(conf, dev);
  126 
  127         bcopy(dev->ipa_devident, conf->ipa_devident,
  128             sizeof(conf->ipa_devident));
  129         bcopy(dev->ipa_devlogic, conf->ipa_devlogic,
  130             sizeof(conf->ipa_devlogic));
  131         bcopy(dev->ipa_devcompat, conf->ipa_devcompat,
  132             sizeof(conf->ipa_devcompat));
  133         bcopy(dev->ipa_devclass, conf->ipa_devclass,
  134             sizeof(conf->ipa_devclass));
  135 
  136         if (dev->ipa_child == NULL)
  137                 dev->ipa_child = conf;
  138         else {
  139                 for (ipa = dev->ipa_child; ipa->ipa_sibling;
  140                     ipa = ipa->ipa_sibling)
  141                         continue;
  142                 ipa->ipa_sibling = conf;
  143         }
  144 
  145         return conf;
  146 }
  147 
  148 
  149 /* isapnp_merge():
  150  *      Merge the common device configurations to the subconfigurations
  151  */
  152 void
  153 isapnp_merge(c, d)
  154         struct isa_attach_args *c;
  155         const struct isa_attach_args *d;
  156 {
  157         int i;
  158 
  159         for (i = 0; i < d->ipa_nio; i++)
  160                 c->ipa_io[c->ipa_nio++] = d->ipa_io[i];
  161 
  162         for (i = 0; i < d->ipa_nmem; i++)
  163                 c->ipa_mem[c->ipa_nmem++] = d->ipa_mem[i];
  164 
  165         for (i = 0; i < d->ipa_nmem32; i++)
  166                 c->ipa_mem32[c->ipa_nmem32++] = d->ipa_mem32[i];
  167 
  168         for (i = 0; i < d->ipa_nirq; i++)
  169                 c->ipa_irq[c->ipa_nirq++] = d->ipa_irq[i];
  170 
  171         for (i = 0; i < d->ipa_ndrq; i++)
  172                 c->ipa_drq[c->ipa_ndrq++] = d->ipa_drq[i];
  173 }
  174 
  175 
  176 /* isapnp_flatten():
  177  *      Flatten the tree to a list of config entries.
  178  */
  179 struct isa_attach_args *
  180 isapnp_flatten(card)
  181         struct isa_attach_args *card;
  182 {
  183         struct isa_attach_args *dev, *conf, *d, *c, *pa;
  184 
  185         dev = card->ipa_child;
  186         ISAPNP_FREE(card);
  187 
  188         for (conf = c = NULL, d = dev; d; d = dev) {
  189                 dev = d->ipa_sibling;
  190                 if (d->ipa_child == NULL) {
  191                         /*
  192                          * No subconfigurations; all configuration info
  193                          * is in the device node.
  194                          */
  195                         d->ipa_sibling = NULL;
  196                         pa = d;
  197                 }
  198                 else {
  199                         /*
  200                          * Push down device configuration info to the
  201                          * subconfigurations
  202                          */
  203                         for (pa = d->ipa_child; pa; pa = pa->ipa_sibling)
  204                                 isapnp_merge(pa, d);
  205 
  206                         pa = d->ipa_child;
  207                         ISAPNP_FREE(d);
  208                 }
  209 
  210                 if (c == NULL)
  211                         c = conf = pa;
  212                 else
  213                         c->ipa_sibling = pa;
  214 
  215                 while (c->ipa_sibling)
  216                         c = c->ipa_sibling;
  217         }
  218         return conf;
  219 }
  220 
  221 
  222 /* isapnp_process_tag():
  223  *      Process a resource tag
  224  */
  225 int
  226 isapnp_process_tag(tag, len, buf, card, dev, conf)
  227         u_char tag, len, *buf;
  228         struct isa_attach_args **card, **dev, **conf;
  229 {
  230         char str[64];
  231         struct isapnp_region *r;
  232         struct isapnp_pin *p;
  233         struct isa_attach_args *pa;
  234 
  235 #define COPY(a, b) strncpy((a), (b), sizeof(a)), (a)[sizeof(a) - 1] = '\0'
  236 
  237         switch (tag) {
  238         case ISAPNP_TAG_VERSION_NUM:
  239                 DPRINTF(("PnP version %d.%d, Vendor version %d.%d\n",
  240                     buf[0] >> 4, buf[0] & 0xf, buf[1] >> 4,  buf[1] & 0xf));
  241                 return 0;
  242 
  243         case ISAPNP_TAG_LOGICAL_DEV_ID:
  244                 (void) isapnp_id_to_vendor(str, buf);
  245                 DPRINTF(("Logical device id %s\n", str));
  246 
  247                 *dev = isapnp_newdev(*card);
  248                 COPY((*dev)->ipa_devlogic, str);
  249                 return 0;
  250 
  251         case ISAPNP_TAG_COMPAT_DEV_ID:
  252                 (void) isapnp_id_to_vendor(str, buf);
  253                 DPRINTF(("Compatible device id %s\n", str));
  254 
  255                 if (*dev == NULL)
  256                         return -1;
  257 
  258                 if (*(*dev)->ipa_devcompat == '\0')
  259                         COPY((*dev)->ipa_devcompat, str);
  260                 return 0;
  261 
  262         case ISAPNP_TAG_DEP_START:
  263                 if (len == 0)
  264                         buf[0] = ISAPNP_DEP_ACCEPTABLE;
  265 
  266                 if (*dev == NULL)
  267                         return -1;
  268 
  269                 *conf = isapnp_newconf(*dev);
  270                 (*conf)->ipa_pref = buf[0];
  271 #ifdef DEBUG_ISAPNP
  272                 isapnp_print_dep_start(">>> Start dependent function ",
  273                     (*conf)->ipa_pref);
  274 #endif
  275                 return 0;
  276                 
  277         case ISAPNP_TAG_DEP_END:
  278                 DPRINTF(("<<<End dependent functions\n"));
  279                 *conf = NULL;
  280                 return 0;
  281 
  282         case ISAPNP_TAG_ANSI_IDENT_STRING:
  283                 buf[len] = '\0';
  284                 DPRINTF(("ANSI Ident: %s\n", buf));
  285                 if (*dev == NULL)
  286                         COPY((*card)->ipa_devident, buf);
  287                 else
  288                         COPY((*dev)->ipa_devclass, buf);
  289                 return 0;
  290 
  291         case ISAPNP_TAG_END:
  292                 *dev = NULL;
  293                 return 0;
  294 
  295         default:
  296                 /* Handled below */
  297                 break;
  298         }
  299 
  300 
  301         /*
  302          * Decide which configuration we add the tag to
  303          */
  304         if (*conf)
  305                 pa = *conf;
  306         else if (*dev)
  307                 pa = *dev;
  308         else
  309                 /* error */
  310                 return -1;
  311 
  312         switch (tag) {
  313         case ISAPNP_TAG_IRQ_FORMAT:
  314                 if (len < 2)
  315                         break;
  316 
  317                 if (len != 3)
  318                         buf[2] = ISAPNP_IRQTYPE_EDGE_PLUS;
  319 
  320                 p = &pa->ipa_irq[pa->ipa_nirq++];
  321                 p->bits = buf[0] | (buf[1] << 8);
  322                 p->flags = buf[2];
  323 #ifdef DEBUG_ISAPNP
  324                 isapnp_print_irq("", p);
  325 #endif
  326                 break;
  327 
  328         case ISAPNP_TAG_DMA_FORMAT:
  329                 if (buf[0] == 0)
  330                         break;
  331 
  332                 p = &pa->ipa_drq[pa->ipa_ndrq++];
  333                 p->bits = buf[0];
  334                 p->flags = buf[1];
  335 #ifdef DEBUG_ISAPNP
  336                 isapnp_print_drq("", p);
  337 #endif
  338                 break;
  339 
  340 
  341         case ISAPNP_TAG_IO_PORT_DESC:
  342                 r = &pa->ipa_io[pa->ipa_nio++];
  343                 r->flags = buf[0];
  344                 r->minbase = (buf[2] << 8) | buf[1];
  345                 r->maxbase = (buf[4] << 8) | buf[3];
  346                 r->align = buf[5];
  347                 r->length = buf[6];
  348 #ifdef DEBUG_ISAPNP
  349                 isapnp_print_io("", r);
  350 #endif
  351                 break;
  352 
  353         case ISAPNP_TAG_FIXED_IO_PORT_DESC:
  354                 r = &pa->ipa_io[pa->ipa_nio++];
  355                 r->flags = 0;
  356                 r->minbase = (buf[1] << 8) | buf[0];
  357                 r->maxbase = r->minbase;
  358                 r->align = 1;
  359                 r->length = buf[2];
  360 #ifdef DEBUG_ISAPNP
  361                 isapnp_print_io("FIXED ", r);
  362 #endif
  363                 break;
  364 
  365         case ISAPNP_TAG_VENDOR_DEF:
  366                 DPRINTF(("Vendor defined (short)\n"));
  367                 break;
  368 
  369         case ISAPNP_TAG_MEM_RANGE_DESC:
  370                 r = &pa->ipa_mem[pa->ipa_nmem++];
  371                 r->flags = buf[0];
  372                 r->minbase = (buf[2] << 16) | (buf[1] << 8);
  373                 r->maxbase = (buf[4] << 16) | (buf[3] << 8);
  374                 r->align = (buf[6] << 8) | buf[5];
  375                 r->length = (buf[8] << 16) | (buf[7] << 8);
  376 #ifdef DEBUG_ISAPNP
  377                 isapnp_print_mem("", r);
  378 #endif
  379                 break;
  380 
  381 
  382         case ISAPNP_TAG_UNICODE_IDENT_STRING:
  383                 DPRINTF(("Unicode Ident\n"));
  384                 break;
  385 
  386         case ISAPNP_TAG_VENDOR_DEFINED:
  387                 DPRINTF(("Vendor defined (long)\n"));
  388                 break;
  389 
  390         case ISAPNP_TAG_MEM32_RANGE_DESC:
  391                 r = &pa->ipa_mem32[pa->ipa_nmem32++];
  392                 r->flags = buf[0];
  393                 r->minbase = (buf[4] << 24) | (buf[3] << 16) |
  394                     (buf[2] << 8) | buf[1];
  395                 r->maxbase = (buf[8] << 24) | (buf[7] << 16) |
  396                     (buf[6] << 8) | buf[5];
  397                 r->align = (buf[12] << 24) | (buf[11] << 16) | 
  398                     (buf[10] << 8) | buf[9];
  399                 r->length = (buf[16] << 24) | (buf[15] << 16) |
  400                     (buf[14] << 8) | buf[13];
  401 #ifdef DEBUG_ISAPNP
  402                 isapnp_print_mem("32-bit ", r);
  403 #endif
  404                 break;
  405 
  406         case ISAPNP_TAG_FIXED_MEM32_RANGE_DESC:
  407                 r = &pa->ipa_mem32[pa->ipa_nmem32++];
  408                 r->flags = buf[0];
  409                 r->minbase = (buf[4] << 24) | (buf[3] << 16) |
  410                     (buf[2] << 8) | buf[1];
  411                 r->maxbase = r->minbase;
  412                 r->align = 1;
  413                 r->length = (buf[8] << 24) | (buf[7] << 16) |
  414                     (buf[6] << 8) | buf[5];
  415 #ifdef DEBUG_ISAPNP
  416                 isapnp_print_mem("FIXED 32-bit ", r);
  417 #endif
  418                 break;
  419 
  420         default:
  421 #ifdef DEBUG_ISAPNP
  422                 {
  423                         int i;
  424                         printf("tag %.2x, len %d: ", tag, len);
  425                         for (i = 0; i < len; i++)
  426                                 printf("%.2x ", buf[i]);
  427                         printf("\n");
  428                 }
  429 #endif
  430                 break;
  431         }
  432         return 0;
  433 }
  434 
  435 
  436 /* isapnp_get_resource():
  437  *      Read the resources for card c
  438  */
  439 struct isa_attach_args *
  440 isapnp_get_resource(sc, c, template)
  441         struct isapnp_softc *sc;
  442         int c;
  443         struct isa_attach_args *template;
  444 {
  445         u_char d, tag;
  446         u_short len;
  447         int i;
  448         int warned = 0;
  449         struct isa_attach_args *card, *dev = NULL, *conf = NULL;
  450         u_char buf[ISAPNP_MAX_TAGSIZE], *p;
  451 
  452         bzero(buf, sizeof(buf));
  453 
  454         card = ISAPNP_MALLOC(sizeof(*card));
  455         ISAPNP_CLONE_SETUP(card, template);
  456 
  457 #define NEXT_BYTE \
  458                 if (isapnp_wait_status(sc)) \
  459                         goto bad; \
  460                 d = isapnp_read_reg(sc, ISAPNP_RESOURCE_DATA)
  461 
  462         for (i = 0; i < ISAPNP_SERIAL_SIZE; i++) {
  463                 NEXT_BYTE;
  464 
  465                 if (d != sc->sc_id[c][i] && i != ISAPNP_SERIAL_SIZE - 1) {
  466                         if (!warned) {
  467                                 printf("%s: card %d violates PnP spec; byte %d\n",
  468                                     sc->sc_dev.dv_xname, c + 1, i);
  469                                 warned++;
  470                         }
  471                         if (i == 0) {
  472                                 /*
  473                                  * Magic! If this is the first byte, we
  474                                  * assume that the tag data begins here.
  475                                  */
  476                                 goto parse;
  477                         }
  478                 }
  479         }
  480 
  481         do {
  482                 NEXT_BYTE;
  483 parse:
  484 
  485                 if (d & ISAPNP_LARGE_TAG) {
  486                         tag = d;
  487                         NEXT_BYTE;
  488                         buf[0] = d;
  489                         NEXT_BYTE;
  490                         buf[1] = d;
  491                         len = (buf[1] << 8) | buf[0];
  492                 }
  493                 else {
  494                         tag = (d >> 3) & 0xf;
  495                         len = d & 0x7;
  496                 }
  497 
  498                 for (p = buf, i = 0; i < len; i++) {
  499                         NEXT_BYTE;
  500                         if (i < ISAPNP_MAX_TAGSIZE)
  501                                 *p++ = d;
  502                 }
  503 
  504                 if (len >= ISAPNP_MAX_TAGSIZE) {
  505                         printf("%s: Maximum tag size exceeded, card %d\n",
  506                             sc->sc_dev.dv_xname, c + 1);
  507                         len = ISAPNP_MAX_TAGSIZE;
  508                         if (++warned == 10)
  509                                 goto bad;
  510                 }
  511 
  512                 if (isapnp_process_tag(tag, len, buf, &card, &dev, &conf) == -1) {
  513                         printf("%s: No current device for tag, card %d\n",
  514                             sc->sc_dev.dv_xname, c + 1);
  515                         if (++warned == 10)
  516                                 goto bad;
  517                 }
  518         }
  519         while (tag != ISAPNP_TAG_END);
  520         return isapnp_flatten(card);
  521 
  522 bad:
  523         for (card = isapnp_flatten(card); card; ) {
  524                 dev = card->ipa_sibling;
  525                 ISAPNP_FREE(card);
  526                 card = dev;
  527         }
  528         printf("%s: %s, card %d\n", sc->sc_dev.dv_xname,
  529             warned >= 10 ? "Too many tag errors" : "Resource timeout", c + 1);
  530         return NULL;
  531 }

/* [<][>][^][v][top][bottom][index][help] */