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/isa/pnpparse.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 /*-
    2  * Copyright (c) 1999 Doug Rabson
    3  * All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer.
   10  * 2. Redistributions in binary form must reproduce the above copyright
   11  *    notice, this list of conditions and the following disclaimer in the
   12  *    documentation and/or other materials provided with the distribution.
   13  *
   14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   24  * SUCH DAMAGE.
   25  *
   26  *      $FreeBSD$
   27  */
   28 
   29 #include <sys/param.h>
   30 #include <sys/systm.h>
   31 #include <sys/kernel.h>
   32 #include <sys/malloc.h>
   33 #include <sys/module.h>
   34 #include <sys/bus.h>
   35 #include <isa/isavar.h>
   36 #include <isa/pnpreg.h>
   37 #include <isa/pnpvar.h>
   38 
   39 #define MAXDEP  8
   40 
   41 #define I16(p)  ((p)[0] + ((p)[1] << 8))
   42 #define I32(p)  (I16(p) + (I16(p+2) << 16))
   43 
   44 /*
   45  * Parse resource data for Logical Devices.
   46  *
   47  * This function exits as soon as it gets an error reading *ANY*
   48  * Resource Data or it reaches the end of Resource Data.
   49  */
   50 void
   51 pnp_parse_resources(device_t dev, u_char *resources, int len)
   52 {
   53         device_t parent = device_get_parent(dev);
   54         u_char tag, *resp, *resinfo;
   55         int large_len, scanning = len;
   56         u_int32_t id, compat_id;
   57         struct isa_config *config;
   58         int ncfgs = 1;
   59         int priorities[1 + MAXDEP];
   60         struct isa_config *configs;
   61         char buf[100];
   62         int i;
   63 
   64         id = isa_get_logicalid(dev);
   65         configs = (struct isa_config *)malloc(sizeof(*configs) * (1 + MAXDEP),
   66                                                 M_DEVBUF, M_NOWAIT);
   67         if (configs == NULL) {
   68                 device_printf(dev, "No memory to parse PNP data\n");
   69                 return;
   70         }
   71         bzero(configs, sizeof(*configs) * (1 + MAXDEP));
   72         config = &configs[0];
   73         priorities[0] = 0;
   74         resp = resources;
   75         while (scanning > 0) {
   76                 tag = *resp++;
   77                 scanning--;
   78                 if (PNP_RES_TYPE(tag) == 0) {
   79                         /* Small resource */
   80                         if (scanning < PNP_SRES_LEN(tag)) {
   81                                 scanning = 0;
   82                                 continue;
   83                         }
   84                         resinfo = resp;
   85                         resp += PNP_SRES_LEN(tag);
   86                         scanning -= PNP_SRES_LEN(tag);;
   87                         
   88                         switch (PNP_SRES_NUM(tag)) {
   89                         case PNP_TAG_COMPAT_DEVICE:
   90                                 /*
   91                                  * Got a compatible device id
   92                                  * resource. Should keep a list of
   93                                  * compat ids in the device.
   94                                  */
   95                                 bcopy(resinfo, &compat_id, 4);
   96                                 isa_set_compatid(dev, compat_id);
   97                                 break;
   98                     
   99                         case PNP_TAG_IRQ_FORMAT:
  100                                 if (bootverbose) {
  101                                         printf("%s: adding irq mask %#04x\n",
  102                                                pnp_eisaformat(id),
  103                                                I16(resinfo));
  104                                 }
  105                                 if (config->ic_nirq == ISA_NIRQ) {
  106                                         device_printf(parent, "too many irqs\n");
  107                                         scanning = 0;
  108                                         break;
  109                                 }
  110                                 config->ic_irqmask[config->ic_nirq] =
  111                                         I16(resinfo);
  112                                 config->ic_nirq++;
  113                                 break;
  114 
  115                         case PNP_TAG_DMA_FORMAT:
  116                                 if (bootverbose) {
  117                                         printf("%s: adding dma mask %#02x\n",
  118                                                pnp_eisaformat(id),
  119                                                resinfo[0]);
  120                                 }
  121                                 if (config->ic_ndrq == ISA_NDRQ) {
  122                                         device_printf(parent, "too many drqs\n");
  123                                         scanning = 0;
  124                                         break;
  125                                 }
  126                                 config->ic_drqmask[config->ic_ndrq] =
  127                                         resinfo[0];
  128                                 config->ic_ndrq++;
  129                                 break;
  130 
  131                         case PNP_TAG_START_DEPENDANT:
  132                                 if (bootverbose) {
  133                                         printf("%s: start dependant\n",
  134                                                pnp_eisaformat(id));
  135                                 }
  136                                 if (ncfgs > MAXDEP) {
  137                                         device_printf(parent, "too many dependant configs (%d)\n", MAXDEP);
  138                                         scanning = 0;
  139                                         break;
  140                                 }
  141                                 config = &configs[ncfgs];
  142                                 /*
  143                                  * If the priority is not specified,
  144                                  * then use the default of
  145                                  * 'acceptable'
  146                                  */
  147                                 if (PNP_SRES_LEN(tag) > 0)
  148                                         priorities[ncfgs] = resinfo[0];
  149                                 else
  150                                         priorities[ncfgs] = 1;
  151                                 ncfgs++;
  152                                 break;
  153 
  154                         case PNP_TAG_END_DEPENDANT:
  155                                 if (bootverbose) {
  156                                         printf("%s: end dependant\n",
  157                                                pnp_eisaformat(id));
  158                                 }
  159                                 config = &configs[0];   /* back to main config */
  160                                 break;
  161 
  162                         case PNP_TAG_IO_RANGE:
  163                                 if (bootverbose) {
  164                                         printf("%s: adding io range "
  165                                                "%#x-%#x, size=%#x, "
  166                                                "align=%#x\n",
  167                                                pnp_eisaformat(id),
  168                                                I16(resinfo + 1),
  169                                                I16(resinfo + 3) + resinfo[6]-1,
  170                                                resinfo[6],
  171                                                resinfo[5]);
  172                                 }
  173                                 if (config->ic_nport == ISA_NPORT) {
  174                                         device_printf(parent, "too many ports\n");
  175                                         scanning = 0;
  176                                         break;
  177                                 }
  178                                 config->ic_port[config->ic_nport].ir_start =
  179                                         I16(resinfo + 1);
  180                                 config->ic_port[config->ic_nport].ir_end =
  181                                         I16(resinfo + 3) + resinfo[6] - 1;
  182                                 config->ic_port[config->ic_nport].ir_size =
  183                                         resinfo[6];
  184                                 if (resinfo[5] == 0) {
  185                                     /* Make sure align is at least one */
  186                                     resinfo[5] = 1;
  187                                 }
  188                                 config->ic_port[config->ic_nport].ir_align =
  189                                         resinfo[5];
  190                                 config->ic_nport++;
  191                                 break;
  192 
  193                         case PNP_TAG_IO_FIXED:
  194                                 if (bootverbose) {
  195                                         printf("%s: adding fixed io range "
  196                                                "%#x-%#x, size=%#x, "
  197                                                "align=%#x\n",
  198                                                pnp_eisaformat(id),
  199                                                I16(resinfo),
  200                                                I16(resinfo) + resinfo[2] - 1,
  201                                                resinfo[2],
  202                                                1);
  203                                 }
  204                                 if (config->ic_nport == ISA_NPORT) {
  205                                         device_printf(parent, "too many ports\n");
  206                                         scanning = 0;
  207                                         break;
  208                                 }
  209                                 config->ic_port[config->ic_nport].ir_start =
  210                                         I16(resinfo);
  211                                 config->ic_port[config->ic_nport].ir_end =
  212                                         I16(resinfo) + resinfo[2] - 1;
  213                                 config->ic_port[config->ic_nport].ir_size
  214                                         = resinfo[2];
  215                                 config->ic_port[config->ic_nport].ir_align = 1;
  216                                 config->ic_nport++;
  217                                 break;
  218 
  219                         case PNP_TAG_END:
  220                                 if (bootverbose) {
  221                                         printf("%s: end config\n",
  222                                                pnp_eisaformat(id));
  223                                 }
  224                                 scanning = 0;
  225                                 break;
  226 
  227                         default:
  228                                 /* Skip this resource */
  229                                 device_printf(parent, "unexpected small tag %d\n",
  230                                               PNP_SRES_NUM(tag));
  231                                 break;
  232                         }
  233                 } else {
  234                         /* Large resource */
  235                         if (scanning < 2) {
  236                                 scanning = 0;
  237                                 continue;
  238                         }
  239                         large_len = I16(resp);
  240                         resp += 2;
  241                         scanning -= 2;
  242 
  243                         if (scanning < large_len) {
  244                                 scanning = 0;
  245                                 continue;
  246                         }
  247                         resinfo = resp;
  248                         resp += large_len;
  249                         scanning -= large_len;
  250 
  251                         switch (PNP_LRES_NUM(tag)) {
  252                         case PNP_TAG_ID_ANSI:
  253                                 if (large_len > sizeof(buf) - 1)
  254                                         large_len = sizeof(buf) - 1;
  255                                 bcopy(resinfo, buf, large_len);
  256 
  257                                 /*
  258                                  * Trim trailing spaces and garbage.
  259                                  */
  260                                 while (large_len > 0 && buf[large_len - 1] <= ' ')
  261                                         large_len--;
  262                                 buf[large_len] = '\0';
  263                                 device_set_desc_copy(dev, buf);
  264                                 break;
  265                                 
  266                         case PNP_TAG_MEMORY_RANGE:
  267                                 if (bootverbose) {
  268                                         int temp = I16(resinfo + 7) << 8;
  269 
  270                                         printf("%s: adding memory range "
  271                                                "%#x-%#x, size=%#x, "
  272                                                "align=%#x\n",
  273                                                pnp_eisaformat(id),
  274                                                I16(resinfo + 1)<<8,
  275                                                (I16(resinfo + 3)<<8) + temp - 1,
  276                                                temp,
  277                                                I16(resinfo + 5));
  278                                 }
  279 
  280                                 if (config->ic_nmem == ISA_NMEM) {
  281                                         device_printf(parent, "too many memory ranges\n");
  282                                         scanning = 0;
  283                                         break;
  284                                 }
  285 
  286                                 config->ic_mem[config->ic_nmem].ir_start =
  287                                         I16(resinfo + 1)<<8;
  288                                 config->ic_mem[config->ic_nmem].ir_end =
  289                                         (I16(resinfo + 3)<<8)
  290                                         + (I16(resinfo + 7) << 8) - 1;
  291                                 config->ic_mem[config->ic_nmem].ir_size =
  292                                         I16(resinfo + 7) << 8;
  293                                 config->ic_mem[config->ic_nmem].ir_align =
  294                                         I16(resinfo + 5);
  295                                 if (!config->ic_mem[config->ic_nmem].ir_align)
  296                                         config->ic_mem[config->ic_nmem]
  297                                                 .ir_align = 0x10000;
  298                                 config->ic_nmem++;
  299                                 break;
  300 
  301                         case PNP_TAG_MEMORY32_RANGE:
  302                                 if (I32(resinfo + 13) == 0) {
  303                                         if (bootverbose) {
  304                                                 printf("%s: skipping empty range\n",
  305                                                        pnp_eisaformat(id));
  306                                         }
  307                                         continue;
  308                                 }
  309                                 if (bootverbose) {
  310                                         printf("%s: adding memory32 range "
  311                                                "%#x-%#x, size=%#x, "
  312                                                "align=%#x\n",
  313                                                pnp_eisaformat(id),
  314                                                I32(resinfo + 1),
  315                                                I32(resinfo + 5)
  316                                                + I32(resinfo + 13) - 1,
  317                                                I32(resinfo + 13),
  318                                                I32(resinfo + 9));
  319                                 }
  320 
  321                                 if (config->ic_nmem == ISA_NMEM) {
  322                                         device_printf(parent, "too many memory ranges\n");
  323                                         scanning = 0;
  324                                         break;
  325                                 }
  326 
  327                                 config->ic_mem[config->ic_nmem].ir_start =
  328                                         I32(resinfo + 1);
  329                                 config->ic_mem[config->ic_nmem].ir_end =
  330                                         I32(resinfo + 5)
  331                                         + I32(resinfo + 13) - 1;
  332                                 config->ic_mem[config->ic_nmem].ir_size =
  333                                         I32(resinfo + 13);
  334                                 config->ic_mem[config->ic_nmem].ir_align =
  335                                         I32(resinfo + 9);
  336                                 config->ic_nmem++;
  337                                 break;
  338 
  339                         case PNP_TAG_MEMORY32_FIXED:
  340                                 if (I32(resinfo + 5) == 0) {
  341                                         if (bootverbose) {
  342                                                 printf("%s: skipping empty range\n",
  343                                                        pnp_eisaformat(id));
  344                                         }
  345                                         continue;
  346                                 }
  347                                 if (bootverbose) {
  348                                         printf("%s: adding fixed memory32 range "
  349                                                "%#x-%#x, size=%#x\n",
  350                                                pnp_eisaformat(id),
  351                                                I32(resinfo + 1),
  352                                                I32(resinfo + 1)
  353                                                + I32(resinfo + 5) - 1,
  354                                                I32(resinfo + 5));
  355                                 }
  356 
  357                                 if (config->ic_nmem == ISA_NMEM) {
  358                                         device_printf(parent, "too many memory ranges\n");
  359                                         scanning = 0;
  360                                         break;
  361                                 }
  362 
  363                                 config->ic_mem[config->ic_nmem].ir_start =
  364                                         I32(resinfo + 1);
  365                                 config->ic_mem[config->ic_nmem].ir_end =
  366                                         I32(resinfo + 1)
  367                                         + I32(resinfo + 5) - 1;
  368                                 config->ic_mem[config->ic_nmem].ir_size =
  369                                         I32(resinfo + 5);
  370                                 config->ic_mem[config->ic_nmem].ir_align = 1;
  371                                 config->ic_nmem++;
  372                                 break;
  373 
  374                         default:
  375                                 /* Skip this resource */
  376                                 device_printf(parent, "unexpected large tag %d\n",
  377                                               PNP_SRES_NUM(tag));
  378                         }
  379                 }
  380         }
  381         if(ncfgs == 1) {
  382                 /* Single config without dependants */
  383                 (void)ISA_ADD_CONFIG(parent, dev, priorities[0], &configs[0]);
  384                 free(configs, M_DEVBUF);
  385                 return;
  386         }
  387         /* Cycle through dependant configs merging primary details */
  388         for(i = 1; i < ncfgs; i++) {
  389                 int j;
  390                 config = &configs[i];
  391                 for(j = 0; j < configs[0].ic_nmem; j++) {
  392                         if (config->ic_nmem == ISA_NMEM) {
  393                                 device_printf(parent, "too many memory ranges\n");
  394                                 free(configs, M_DEVBUF);
  395                                 return;
  396                         }
  397                         config->ic_mem[config->ic_nmem] = configs[0].ic_mem[j];
  398                         config->ic_nmem++;
  399                 }
  400                 for(j = 0; j < configs[0].ic_nport; j++) {
  401                         if (config->ic_nport == ISA_NPORT) {
  402                                 device_printf(parent, "too many port ranges\n");
  403                                 free(configs, M_DEVBUF);
  404                                 return;
  405                         }
  406                         config->ic_port[config->ic_nport] = configs[0].ic_port[j];
  407                         config->ic_nport++;
  408                 }
  409                 for(j = 0; j < configs[0].ic_nirq; j++) {
  410                         if (config->ic_nirq == ISA_NIRQ) {
  411                                 device_printf(parent, "too many irq ranges\n");
  412                                 free(configs, M_DEVBUF);
  413                                 return;
  414                         }
  415                         config->ic_irqmask[config->ic_nirq] = configs[0].ic_irqmask[j];
  416                         config->ic_nirq++;
  417                 }
  418                 for(j = 0; j < configs[0].ic_ndrq; j++) {
  419                         if (config->ic_ndrq == ISA_NDRQ) {
  420                                 device_printf(parent, "too many drq ranges\n");
  421                                 free(configs, M_DEVBUF);
  422                                 return;
  423                         }
  424                         config->ic_drqmask[config->ic_ndrq] = configs[0].ic_drqmask[j];
  425                         config->ic_ndrq++;
  426                 }
  427                 (void)ISA_ADD_CONFIG(parent, dev, priorities[i], &configs[i]);
  428         }
  429         free(configs, M_DEVBUF);
  430 }

Cache object: 74966080b978495044cc2eff411b982f


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