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

Cache object: 85ecbb0412a1e2c64dea23aa2eb78600


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