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

Cache object: b1b2d7df51d12bd93e9cb463f412afbb


[ 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.