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/isa_common.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  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD AND MIT
    3  *
    4  * Copyright (c) 1999 Doug Rabson
    5  * 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  *
   16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   26  * SUCH DAMAGE.
   27  */
   28 /*
   29  * Modifications for Intel architecture by Garrett A. Wollman.
   30  * Copyright 1998 Massachusetts Institute of Technology
   31  *
   32  * Permission to use, copy, modify, and distribute this software and
   33  * its documentation for any purpose and without fee is hereby
   34  * granted, provided that both the above copyright notice and this
   35  * permission notice appear in all copies, that both the above
   36  * copyright notice and this permission notice appear in all
   37  * supporting documentation, and that the name of M.I.T. not be used
   38  * in advertising or publicity pertaining to distribution of the
   39  * software without specific, written prior permission.  M.I.T. makes
   40  * no representations about the suitability of this software for any
   41  * purpose.  It is provided "as is" without express or implied
   42  * warranty.
   43  * 
   44  * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''.  M.I.T. DISCLAIMS
   45  * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE,
   46  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
   47  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT
   48  * SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   49  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   50  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   51  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   52  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   53  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   54  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   55  * SUCH DAMAGE.
   56  */
   57 
   58 /*
   59  * Parts of the ISA bus implementation common to all architectures.
   60  */
   61 
   62 #include <sys/cdefs.h>
   63 __FBSDID("$FreeBSD$");
   64 
   65 #include "opt_isa.h"
   66 
   67 #include <sys/param.h>
   68 #include <sys/systm.h>
   69 #include <sys/kernel.h>
   70 #include <sys/bus.h>
   71 #include <sys/endian.h>
   72 #include <sys/malloc.h>
   73 #include <sys/module.h>
   74 #include <machine/bus.h>
   75 #include <sys/rman.h>
   76 #include <sys/sbuf.h>
   77 #include <sys/sysctl.h>
   78 
   79 #include <machine/resource.h>
   80 
   81 #include <isa/isavar.h>
   82 #include <isa/isa_common.h>
   83 
   84 static int      isa_print_child(device_t bus, device_t dev);
   85 
   86 static MALLOC_DEFINE(M_ISADEV, "isadev", "ISA device");
   87 
   88 static int isa_running;
   89 
   90 /*
   91  * At 'probe' time, we add all the devices which we know about to the
   92  * bus.  The generic attach routine will probe and attach them if they
   93  * are alive.
   94  */
   95 static int
   96 isa_probe(device_t dev)
   97 {
   98         device_set_desc(dev, "ISA bus");
   99         isa_init(dev);          /* Allow machdep code to initialise */
  100         return (0);
  101 }
  102 
  103 extern device_t isa_bus_device;
  104 
  105 static int
  106 isa_attach(device_t dev)
  107 {
  108         /*
  109          * Arrange for isa_probe_children(dev) to be called later. XXX
  110          */
  111         isa_bus_device = dev;
  112         return (0);
  113 }
  114 
  115 /*
  116  * Find a working set of memory regions for a child using the ranges
  117  * in *config  and return the regions in *result. Returns non-zero if
  118  * a set of ranges was found.
  119  */
  120 static int
  121 isa_find_memory(device_t child, struct isa_config *config,
  122     struct isa_config *result)
  123 {
  124         int success, i;
  125         struct resource *res[ISA_NMEM];
  126 
  127         /*
  128          * First clear out any existing resource definitions.
  129          */
  130         for (i = 0; i < ISA_NMEM; i++) {
  131                 bus_delete_resource(child, SYS_RES_MEMORY, i);
  132                 res[i] = NULL;
  133         }
  134 
  135         success = 1;
  136         result->ic_nmem = config->ic_nmem;
  137         for (i = 0; i < config->ic_nmem; i++) {
  138                 uint32_t start, end, size, align;
  139 
  140                 size = config->ic_mem[i].ir_size;
  141 
  142                 /* the PnP device may have a null resource as filler */
  143                 if (size == 0) {
  144                         result->ic_mem[i].ir_start = 0;
  145                         result->ic_mem[i].ir_end = 0;
  146                         result->ic_mem[i].ir_size = 0;
  147                         result->ic_mem[i].ir_align = 0;
  148                         continue;
  149                 }
  150 
  151                 for (start = config->ic_mem[i].ir_start,
  152                              end = config->ic_mem[i].ir_end,
  153                              align = config->ic_mem[i].ir_align;
  154                      start + size - 1 <= end && start + size > start;
  155                      start += MAX(align, 1)) {
  156                         bus_set_resource(child, SYS_RES_MEMORY, i,
  157                                          start, size);
  158                         res[i] = bus_alloc_resource_any(child,
  159                             SYS_RES_MEMORY, &i,
  160                             rman_make_alignment_flags(align) /* !RF_ACTIVE */);
  161                         if (res[i]) {
  162                                 result->ic_mem[i].ir_start = start;
  163                                 result->ic_mem[i].ir_end = start + size - 1;
  164                                 result->ic_mem[i].ir_size = size;
  165                                 result->ic_mem[i].ir_align = align;
  166                                 break;
  167                         }
  168                 }
  169 
  170                 /*
  171                  * If we didn't find a place for memory range i, then 
  172                  * give up now.
  173                  */
  174                 if (!res[i]) {
  175                         success = 0;
  176                         break;
  177                 }
  178         }
  179 
  180         for (i = 0; i < ISA_NMEM; i++) {
  181                 if (res[i])
  182                         bus_release_resource(child, SYS_RES_MEMORY,
  183                                              i, res[i]);
  184         }
  185 
  186         return (success);
  187 }
  188 
  189 /*
  190  * Find a working set of port regions for a child using the ranges
  191  * in *config  and return the regions in *result. Returns non-zero if
  192  * a set of ranges was found.
  193  */
  194 static int
  195 isa_find_port(device_t child, struct isa_config *config,
  196     struct isa_config *result)
  197 {
  198         int success, i;
  199         struct resource *res[ISA_NPORT];
  200 
  201         /*
  202          * First clear out any existing resource definitions.
  203          */
  204         for (i = 0; i < ISA_NPORT; i++) {
  205                 bus_delete_resource(child, SYS_RES_IOPORT, i);
  206                 res[i] = NULL;
  207         }
  208 
  209         success = 1;
  210         result->ic_nport = config->ic_nport;
  211         for (i = 0; i < config->ic_nport; i++) {
  212                 uint32_t start, end, size, align;
  213 
  214                 size = config->ic_port[i].ir_size;
  215 
  216                 /* the PnP device may have a null resource as filler */
  217                 if (size == 0) {
  218                         result->ic_port[i].ir_start = 0;
  219                         result->ic_port[i].ir_end = 0;
  220                         result->ic_port[i].ir_size = 0;
  221                         result->ic_port[i].ir_align = 0;
  222                         continue;
  223                 }
  224 
  225                 for (start = config->ic_port[i].ir_start,
  226                              end = config->ic_port[i].ir_end,
  227                              align = config->ic_port[i].ir_align;
  228                      start + size - 1 <= end;
  229                      start += align) {
  230                         bus_set_resource(child, SYS_RES_IOPORT, i,
  231                                          start, size);
  232                         res[i] = bus_alloc_resource_any(child,
  233                             SYS_RES_IOPORT, &i,
  234                             rman_make_alignment_flags(align) /* !RF_ACTIVE */);
  235                         if (res[i]) {
  236                                 result->ic_port[i].ir_start = start;
  237                                 result->ic_port[i].ir_end = start + size - 1;
  238                                 result->ic_port[i].ir_size = size;
  239                                 result->ic_port[i].ir_align = align;
  240                                 break;
  241                         }
  242                 }
  243 
  244                 /*
  245                  * If we didn't find a place for port range i, then 
  246                  * give up now.
  247                  */
  248                 if (!res[i]) {
  249                         success = 0;
  250                         break;
  251                 }
  252         }
  253 
  254         for (i = 0; i < ISA_NPORT; i++) {
  255                 if (res[i])
  256                         bus_release_resource(child, SYS_RES_IOPORT,
  257                                              i, res[i]);
  258         }
  259 
  260         return success;
  261 }
  262 
  263 /*
  264  * Return the index of the first bit in the mask (or -1 if mask is empty.
  265  */
  266 static int
  267 find_first_bit(uint32_t mask)
  268 {
  269         return (ffs(mask) - 1);
  270 }
  271 
  272 /*
  273  * Return the index of the next bit in the mask, or -1 if there are no more.
  274  */
  275 static int
  276 find_next_bit(uint32_t mask, int bit)
  277 {
  278         bit++;
  279         while (bit < 32 && !(mask & (1 << bit)))
  280                 bit++;
  281         if (bit != 32)
  282                 return (bit);
  283         return (-1);
  284 }
  285 
  286 /*
  287  * Find a working set of irqs for a child using the masks in *config
  288  * and return the regions in *result. Returns non-zero if a set of
  289  * irqs was found.
  290  */
  291 static int
  292 isa_find_irq(device_t child, struct isa_config *config,
  293     struct isa_config *result)
  294 {
  295         int success, i;
  296         struct resource *res[ISA_NIRQ];
  297 
  298         /*
  299          * First clear out any existing resource definitions.
  300          */
  301         for (i = 0; i < ISA_NIRQ; i++) {
  302                 bus_delete_resource(child, SYS_RES_IRQ, i);
  303                 res[i] = NULL;
  304         }
  305 
  306         success = 1;
  307         result->ic_nirq = config->ic_nirq;
  308         for (i = 0; i < config->ic_nirq; i++) {
  309                 uint32_t mask = config->ic_irqmask[i];
  310                 int irq;
  311 
  312                 /* the PnP device may have a null resource as filler */
  313                 if (mask == 0) {
  314                         result->ic_irqmask[i] = 0;
  315                         continue;
  316                 }
  317 
  318                 for (irq = find_first_bit(mask);
  319                      irq != -1;
  320                      irq = find_next_bit(mask, irq)) {
  321                         bus_set_resource(child, SYS_RES_IRQ, i,
  322                                          irq, 1);
  323                         res[i] = bus_alloc_resource_any(child,
  324                                                         SYS_RES_IRQ, &i,
  325                                                         0 /* !RF_ACTIVE */ );
  326                         if (res[i]) {
  327                                 result->ic_irqmask[i] = (1 << irq);
  328                                 break;
  329                         }
  330                 }
  331 
  332                 /*
  333                  * If we didn't find a place for irq range i, then 
  334                  * give up now.
  335                  */
  336                 if (!res[i]) {
  337                         success = 0;
  338                         break;
  339                 }
  340         }
  341 
  342         for (i = 0; i < ISA_NIRQ; i++) {
  343                 if (res[i])
  344                         bus_release_resource(child, SYS_RES_IRQ,
  345                                              i, res[i]);
  346         }
  347 
  348         return (success);
  349 }
  350 
  351 /*
  352  * Find a working set of drqs for a child using the masks in *config
  353  * and return the regions in *result. Returns non-zero if a set of
  354  * drqs was found.
  355  */
  356 static int
  357 isa_find_drq(device_t child, struct isa_config *config,
  358     struct isa_config *result)
  359 {
  360         int success, i;
  361         struct resource *res[ISA_NDRQ];
  362 
  363         /*
  364          * First clear out any existing resource definitions.
  365          */
  366         for (i = 0; i < ISA_NDRQ; i++) {
  367                 bus_delete_resource(child, SYS_RES_DRQ, i);
  368                 res[i] = NULL;
  369         }
  370 
  371         success = 1;
  372         result->ic_ndrq = config->ic_ndrq;
  373         for (i = 0; i < config->ic_ndrq; i++) {
  374                 uint32_t mask = config->ic_drqmask[i];
  375                 int drq;
  376 
  377                 /* the PnP device may have a null resource as filler */
  378                 if (mask == 0) {
  379                         result->ic_drqmask[i] = 0;
  380                         continue;
  381                 }
  382 
  383                 for (drq = find_first_bit(mask);
  384                      drq != -1;
  385                      drq = find_next_bit(mask, drq)) {
  386                         bus_set_resource(child, SYS_RES_DRQ, i,
  387                                          drq, 1);
  388                         res[i] = bus_alloc_resource_any(child,
  389                                                         SYS_RES_DRQ, &i,
  390                                                         0 /* !RF_ACTIVE */);
  391                         if (res[i]) {
  392                                 result->ic_drqmask[i] = (1 << drq);
  393                                 break;
  394                         }
  395                 }
  396 
  397                 /*
  398                  * If we didn't find a place for drq range i, then 
  399                  * give up now.
  400                  */
  401                 if (!res[i]) {
  402                         success = 0;
  403                         break;
  404                 }
  405         }
  406 
  407         for (i = 0; i < ISA_NDRQ; i++) {
  408                 if (res[i])
  409                         bus_release_resource(child, SYS_RES_DRQ,
  410                                              i, res[i]);
  411         }
  412 
  413         return (success);
  414 }
  415 
  416 /*
  417  * Attempt to find a working set of resources for a device. Return
  418  * non-zero if a working configuration is found.
  419  */
  420 static int
  421 isa_assign_resources(device_t child)
  422 {
  423         struct isa_device *idev = DEVTOISA(child);
  424         struct isa_config_entry *ice;
  425         struct isa_config *cfg;
  426         const char *reason;
  427         
  428         reason = "Empty ISA id_configs";
  429         cfg = malloc(sizeof(struct isa_config), M_TEMP, M_NOWAIT|M_ZERO);
  430         if (cfg == NULL)
  431                 return(0);
  432         TAILQ_FOREACH(ice, &idev->id_configs, ice_link) {
  433                 reason = "memory";
  434                 if (!isa_find_memory(child, &ice->ice_config, cfg))
  435                         continue;
  436                 reason = "port";
  437                 if (!isa_find_port(child, &ice->ice_config, cfg))
  438                         continue;
  439                 reason = "irq";
  440                 if (!isa_find_irq(child, &ice->ice_config, cfg))
  441                         continue;
  442                 reason = "drq";
  443                 if (!isa_find_drq(child, &ice->ice_config, cfg))
  444                         continue;
  445 
  446                 /*
  447                  * A working configuration was found enable the device 
  448                  * with this configuration.
  449                  */
  450                 reason = "no callback";
  451                 if (idev->id_config_cb) {
  452                         idev->id_config_cb(idev->id_config_arg,
  453                                            cfg, 1);
  454                         free(cfg, M_TEMP);
  455                         return (1);
  456                 }
  457         }
  458 
  459         /*
  460          * Disable the device.
  461          */
  462         bus_print_child_header(device_get_parent(child), child);
  463         printf(" can't assign resources (%s)\n", reason);
  464         if (bootverbose)
  465                 isa_print_child(device_get_parent(child), child);
  466         bzero(cfg, sizeof (*cfg));
  467         if (idev->id_config_cb)
  468                 idev->id_config_cb(idev->id_config_arg, cfg, 0);
  469         device_disable(child);
  470 
  471         free(cfg, M_TEMP);
  472         return (0);
  473 }
  474 
  475 /*
  476  * Claim any unallocated resources to keep other devices from using
  477  * them.
  478  */
  479 static void
  480 isa_claim_resources(device_t dev, device_t child)
  481 {
  482         struct isa_device *idev = DEVTOISA(child);
  483         struct resource_list *rl = &idev->id_resources;
  484         struct resource_list_entry *rle;
  485         int rid;
  486 
  487         STAILQ_FOREACH(rle, rl, link) {
  488                 if (!rle->res) {
  489                         rid = rle->rid;
  490                         resource_list_alloc(rl, dev, child, rle->type, &rid,
  491                             0, ~0, 1, 0);
  492                 }
  493         }
  494 }
  495 
  496 /*
  497  * Called after other devices have initialised to probe for isa devices.
  498  */
  499 void
  500 isa_probe_children(device_t dev)
  501 {
  502         struct isa_device *idev;
  503         device_t *children, child;
  504         struct isa_config *cfg;
  505         int nchildren, i, err;
  506 
  507         /*
  508          * Create all the non-hinted children by calling drivers'
  509          * identify methods.
  510          */
  511         bus_generic_probe(dev);
  512 
  513         if (device_get_children(dev, &children, &nchildren))
  514                 return;
  515 
  516         /*
  517          * First disable all pnp devices so that they don't get
  518          * matched by legacy probes.
  519          */
  520         if (bootverbose)
  521                 printf("isa_probe_children: disabling PnP devices\n");
  522 
  523         cfg = malloc(sizeof(*cfg), M_TEMP, M_NOWAIT|M_ZERO);
  524         if (cfg == NULL) {
  525                 free(children, M_TEMP);
  526                 return;
  527         }
  528 
  529         for (i = 0; i < nchildren; i++) {
  530                 idev = DEVTOISA(children[i]);
  531 
  532                 bzero(cfg, sizeof(*cfg));
  533                 if (idev->id_config_cb)
  534                         idev->id_config_cb(idev->id_config_arg, cfg, 0);
  535         }
  536 
  537         free(cfg, M_TEMP);
  538 
  539         /*
  540          * Next, probe all the PnP BIOS devices so they can subsume any
  541          * hints.
  542          */
  543         for (i = 0; i < nchildren; i++) {
  544                 child = children[i];
  545                 idev = DEVTOISA(child);
  546 
  547                 if (idev->id_order > ISA_ORDER_PNPBIOS)
  548                         continue;
  549                 if (!TAILQ_EMPTY(&idev->id_configs) &&
  550                     !isa_assign_resources(child))
  551                         continue;
  552 
  553                 if (device_probe_and_attach(child) == 0)
  554                         isa_claim_resources(dev, child);
  555         }
  556         free(children, M_TEMP);
  557 
  558         /*
  559          * Next, enumerate hinted devices and probe all non-pnp devices so
  560          * that they claim their resources first.
  561          */
  562         bus_enumerate_hinted_children(dev);
  563         if (device_get_children(dev, &children, &nchildren))
  564                 return;
  565         if (bootverbose)
  566                 printf("isa_probe_children: probing non-PnP devices\n");
  567         for (i = 0; i < nchildren; i++) {
  568                 child = children[i];
  569                 idev = DEVTOISA(child);
  570 
  571                 if (device_is_attached(child) ||
  572                     !TAILQ_EMPTY(&idev->id_configs))
  573                         continue;
  574 
  575                 err = device_probe_and_attach(child);
  576                 if (err == 0 && idev->id_vendorid == 0 &&
  577                     strcmp(kern_ident, "GENERIC") == 0 &&
  578                     device_is_attached(child))
  579                         device_printf(child,
  580                             "non-PNP ISA device will be removed from GENERIC in FreeBSD 14.\n");
  581         }
  582 
  583         /*
  584          * Finally assign resource to pnp devices and probe them.
  585          */
  586         if (bootverbose)
  587                 printf("isa_probe_children: probing PnP devices\n");
  588         for (i = 0; i < nchildren; i++) {
  589                 child = children[i];
  590                 idev = DEVTOISA(child);
  591 
  592                 if (device_is_attached(child) || TAILQ_EMPTY(&idev->id_configs))
  593                         continue;
  594 
  595                 if (isa_assign_resources(child)) {
  596                         device_probe_and_attach(child);
  597                         isa_claim_resources(dev, child);
  598                 }
  599         }
  600 
  601         free(children, M_TEMP);
  602 
  603         isa_running = 1;
  604 }
  605 
  606 /*
  607  * Add a new child with default ivars.
  608  */
  609 static device_t
  610 isa_add_child(device_t dev, u_int order, const char *name, int unit)
  611 {
  612         device_t child;
  613         struct  isa_device *idev;
  614 
  615         child = device_add_child_ordered(dev, order, name, unit);
  616         if (child == NULL) 
  617                 return (child);
  618         
  619         idev = malloc(sizeof(struct isa_device), M_ISADEV, M_NOWAIT | M_ZERO);
  620         if (!idev)
  621                 return (0);
  622 
  623         resource_list_init(&idev->id_resources);
  624         TAILQ_INIT(&idev->id_configs);
  625         idev->id_order = order;
  626 
  627         device_set_ivars(child, idev);
  628 
  629         return (child);
  630 }
  631 
  632 static int
  633 isa_print_all_resources(device_t dev)
  634 {
  635         struct  isa_device *idev = DEVTOISA(dev);
  636         struct resource_list *rl = &idev->id_resources;
  637         int retval = 0;
  638 
  639         if (STAILQ_FIRST(rl) || device_get_flags(dev))
  640                 retval += printf(" at");
  641         
  642         retval += resource_list_print_type(rl, "port", SYS_RES_IOPORT, "%#jx");
  643         retval += resource_list_print_type(rl, "iomem", SYS_RES_MEMORY, "%#jx");
  644         retval += resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%jd");
  645         retval += resource_list_print_type(rl, "drq", SYS_RES_DRQ, "%jd");
  646         if (device_get_flags(dev))
  647                 retval += printf(" flags %#x", device_get_flags(dev));
  648         if (idev->id_vendorid)
  649                 retval += printf(" pnpid %s", pnp_eisaformat(idev->id_vendorid));
  650 
  651         return (retval);
  652 }
  653 
  654 static int
  655 isa_print_child(device_t bus, device_t dev)
  656 {
  657         int retval = 0;
  658 
  659         retval += bus_print_child_header(bus, dev);
  660         retval += isa_print_all_resources(dev);
  661         retval += bus_print_child_footer(bus, dev);
  662 
  663         return (retval);
  664 }
  665 
  666 static void
  667 isa_probe_nomatch(device_t dev, device_t child)
  668 {
  669         if (bootverbose) {
  670                 bus_print_child_header(dev, child);
  671                 printf(" failed to probe");
  672                 isa_print_all_resources(child);
  673                 bus_print_child_footer(dev, child);
  674         }
  675                                       
  676         return;
  677 }
  678 
  679 static int
  680 isa_read_ivar(device_t bus, device_t dev, int index, uintptr_t * result)
  681 {
  682         struct isa_device* idev = DEVTOISA(dev);
  683         struct resource_list *rl = &idev->id_resources;
  684         struct resource_list_entry *rle;
  685 
  686         switch (index) {
  687         case ISA_IVAR_PORT_0:
  688                 rle = resource_list_find(rl, SYS_RES_IOPORT, 0);
  689                 if (rle)
  690                         *result = rle->start;
  691                 else
  692                         *result = -1;
  693                 break;
  694 
  695         case ISA_IVAR_PORT_1:
  696                 rle = resource_list_find(rl, SYS_RES_IOPORT, 1);
  697                 if (rle)
  698                         *result = rle->start;
  699                 else
  700                         *result = -1;
  701                 break;
  702 
  703         case ISA_IVAR_PORTSIZE_0:
  704                 rle = resource_list_find(rl, SYS_RES_IOPORT, 0);
  705                 if (rle)
  706                         *result = rle->count;
  707                 else
  708                         *result = 0;
  709                 break;
  710 
  711         case ISA_IVAR_PORTSIZE_1:
  712                 rle = resource_list_find(rl, SYS_RES_IOPORT, 1);
  713                 if (rle)
  714                         *result = rle->count;
  715                 else
  716                         *result = 0;
  717                 break;
  718 
  719         case ISA_IVAR_MADDR_0:
  720                 rle = resource_list_find(rl, SYS_RES_MEMORY, 0);
  721                 if (rle)
  722                         *result = rle->start;
  723                 else
  724                         *result = -1;
  725                 break;
  726 
  727         case ISA_IVAR_MADDR_1:
  728                 rle = resource_list_find(rl, SYS_RES_MEMORY, 1);
  729                 if (rle)
  730                         *result = rle->start;
  731                 else
  732                         *result = -1;
  733                 break;
  734 
  735         case ISA_IVAR_MEMSIZE_0:
  736                 rle = resource_list_find(rl, SYS_RES_MEMORY, 0);
  737                 if (rle)
  738                         *result = rle->count;
  739                 else
  740                         *result = 0;
  741                 break;
  742 
  743         case ISA_IVAR_MEMSIZE_1:
  744                 rle = resource_list_find(rl, SYS_RES_MEMORY, 1);
  745                 if (rle)
  746                         *result = rle->count;
  747                 else
  748                         *result = 0;
  749                 break;
  750 
  751         case ISA_IVAR_IRQ_0:
  752                 rle = resource_list_find(rl, SYS_RES_IRQ, 0);
  753                 if (rle)
  754                         *result = rle->start;
  755                 else
  756                         *result = -1;
  757                 break;
  758 
  759         case ISA_IVAR_IRQ_1:
  760                 rle = resource_list_find(rl, SYS_RES_IRQ, 1);
  761                 if (rle)
  762                         *result = rle->start;
  763                 else
  764                         *result = -1;
  765                 break;
  766 
  767         case ISA_IVAR_DRQ_0:
  768                 rle = resource_list_find(rl, SYS_RES_DRQ, 0);
  769                 if (rle)
  770                         *result = rle->start;
  771                 else
  772                         *result = -1;
  773                 break;
  774 
  775         case ISA_IVAR_DRQ_1:
  776                 rle = resource_list_find(rl, SYS_RES_DRQ, 1);
  777                 if (rle)
  778                         *result = rle->start;
  779                 else
  780                         *result = -1;
  781                 break;
  782 
  783         case ISA_IVAR_VENDORID:
  784                 *result = idev->id_vendorid;
  785                 break;
  786 
  787         case ISA_IVAR_SERIAL:
  788                 *result = idev->id_serial;
  789                 break;
  790 
  791         case ISA_IVAR_LOGICALID:
  792                 *result = idev->id_logicalid;
  793                 break;
  794 
  795         case ISA_IVAR_COMPATID:
  796                 *result = idev->id_compatid;
  797                 break;
  798 
  799         case ISA_IVAR_CONFIGATTR:
  800                 *result = idev->id_config_attr;
  801                 break;
  802 
  803         case ISA_IVAR_PNP_CSN:
  804                 *result = idev->id_pnp_csn;
  805                 break;
  806 
  807         case ISA_IVAR_PNP_LDN:
  808                 *result = idev->id_pnp_ldn;
  809                 break;
  810 
  811         case ISA_IVAR_PNPBIOS_HANDLE:
  812                 *result = idev->id_pnpbios_handle;
  813                 break;
  814 
  815         default:
  816                 return (ENOENT);
  817         }
  818 
  819         return (0);
  820 }
  821 
  822 static int
  823 isa_write_ivar(device_t bus, device_t dev, int index, uintptr_t value)
  824 {
  825         struct isa_device* idev = DEVTOISA(dev);
  826 
  827         switch (index) {
  828         case ISA_IVAR_PORT_0:
  829         case ISA_IVAR_PORT_1:
  830         case ISA_IVAR_PORTSIZE_0:
  831         case ISA_IVAR_PORTSIZE_1:
  832         case ISA_IVAR_MADDR_0:
  833         case ISA_IVAR_MADDR_1:
  834         case ISA_IVAR_MEMSIZE_0:
  835         case ISA_IVAR_MEMSIZE_1:
  836         case ISA_IVAR_IRQ_0:
  837         case ISA_IVAR_IRQ_1:
  838         case ISA_IVAR_DRQ_0:
  839         case ISA_IVAR_DRQ_1:
  840                 return (EINVAL);
  841 
  842         case ISA_IVAR_VENDORID:
  843                 idev->id_vendorid = value;
  844                 break;
  845 
  846         case ISA_IVAR_SERIAL:
  847                 idev->id_serial = value;
  848                 break;
  849 
  850         case ISA_IVAR_LOGICALID:
  851                 idev->id_logicalid = value;
  852                 break;
  853 
  854         case ISA_IVAR_COMPATID:
  855                 idev->id_compatid = value;
  856                 break;
  857 
  858         case ISA_IVAR_CONFIGATTR:
  859                 idev->id_config_attr = value;
  860                 break;
  861 
  862         default:
  863                 return (ENOENT);
  864         }
  865 
  866         return (0);
  867 }
  868 
  869 /*
  870  * Free any resources which the driver missed or which we were holding for
  871  * it (see isa_probe_children).
  872  */
  873 static void
  874 isa_child_detached(device_t dev, device_t child)
  875 {
  876         struct isa_device* idev = DEVTOISA(child);
  877 
  878         if (TAILQ_FIRST(&idev->id_configs))
  879                 isa_claim_resources(dev, child);
  880 }
  881 
  882 static void
  883 isa_driver_added(device_t dev, driver_t *driver)
  884 {
  885         device_t *children;
  886         int nchildren, i;
  887 
  888         /*
  889          * Don't do anything if drivers are dynamically
  890          * added during autoconfiguration (cf. ymf724).
  891          * since that would end up calling identify
  892          * twice.
  893          */
  894         if (!isa_running)
  895                 return;
  896 
  897         DEVICE_IDENTIFY(driver, dev);
  898         if (device_get_children(dev, &children, &nchildren))
  899                 return;
  900 
  901         for (i = 0; i < nchildren; i++) {
  902                 device_t child = children[i];
  903                 struct isa_device *idev = DEVTOISA(child);
  904                 struct resource_list *rl = &idev->id_resources;
  905                 struct resource_list_entry *rle;
  906 
  907                 if (device_get_state(child) != DS_NOTPRESENT)
  908                         continue;
  909                 if (!device_is_enabled(child))
  910                         continue;
  911 
  912                 /*
  913                  * Free resources which we were holding on behalf of
  914                  * the device.
  915                  */
  916                 STAILQ_FOREACH(rle, &idev->id_resources, link) {
  917                         if (rle->res)
  918                                 resource_list_release(rl, dev, child,
  919                                                       rle->type,
  920                                                       rle->rid,
  921                                                       rle->res);
  922                 }
  923 
  924                 if (TAILQ_FIRST(&idev->id_configs))
  925                         if (!isa_assign_resources(child))
  926                                 continue;
  927 
  928                 device_probe_and_attach(child);
  929 
  930                 if (TAILQ_FIRST(&idev->id_configs))
  931                         isa_claim_resources(dev, child);
  932         }
  933 
  934         free(children, M_TEMP);
  935 }
  936 
  937 static int
  938 isa_set_resource(device_t dev, device_t child, int type, int rid,
  939     rman_res_t start, rman_res_t count)
  940 {
  941         struct isa_device* idev = DEVTOISA(child);
  942         struct resource_list *rl = &idev->id_resources;
  943 
  944         if (type != SYS_RES_IOPORT && type != SYS_RES_MEMORY
  945             && type != SYS_RES_IRQ && type != SYS_RES_DRQ)
  946                 return (EINVAL);
  947         if (rid < 0)
  948                 return (EINVAL);
  949         if (type == SYS_RES_IOPORT && rid >= ISA_NPORT)
  950                 return (EINVAL);
  951         if (type == SYS_RES_MEMORY && rid >= ISA_NMEM)
  952                 return (EINVAL);
  953         if (type == SYS_RES_IRQ && rid >= ISA_NIRQ)
  954                 return (EINVAL);
  955         if (type == SYS_RES_DRQ && rid >= ISA_NDRQ)
  956                 return (EINVAL);
  957 
  958         resource_list_add(rl, type, rid, start, start + count - 1, count);
  959 
  960         return (0);
  961 }
  962 
  963 static struct resource_list *
  964 isa_get_resource_list (device_t dev, device_t child)
  965 {
  966         struct isa_device* idev = DEVTOISA(child);
  967         struct resource_list *rl = &idev->id_resources;
  968 
  969         if (!rl)
  970                 return (NULL);
  971 
  972         return (rl);
  973 }
  974 
  975 static int
  976 isa_add_config(device_t dev, device_t child, int priority,
  977     struct isa_config *config)
  978 {
  979         struct isa_device* idev = DEVTOISA(child);
  980         struct isa_config_entry *newice, *ice;
  981 
  982         newice = malloc(sizeof *ice, M_DEVBUF, M_NOWAIT);
  983         if (!newice)
  984                 return (ENOMEM);
  985 
  986         newice->ice_priority = priority;
  987         newice->ice_config = *config;
  988         
  989         TAILQ_FOREACH(ice, &idev->id_configs, ice_link) {
  990                 if (ice->ice_priority > priority)
  991                         break;
  992         }
  993         if (ice)
  994                 TAILQ_INSERT_BEFORE(ice, newice, ice_link);
  995         else
  996                 TAILQ_INSERT_TAIL(&idev->id_configs, newice, ice_link);
  997 
  998         return (0);
  999 }
 1000 
 1001 static void
 1002 isa_set_config_callback(device_t dev, device_t child, isa_config_cb *fn,
 1003     void *arg)
 1004 {
 1005         struct isa_device* idev = DEVTOISA(child);
 1006 
 1007         idev->id_config_cb = fn;
 1008         idev->id_config_arg = arg;
 1009 }
 1010 
 1011 static int
 1012 isa_pnp_probe(device_t dev, device_t child, struct isa_pnp_id *ids)
 1013 {
 1014         struct isa_device* idev = DEVTOISA(child);
 1015 
 1016         if (!idev->id_vendorid)
 1017                 return (ENOENT);
 1018 
 1019         while (ids && ids->ip_id) {
 1020                 /*
 1021                  * Really ought to support >1 compat id per device.
 1022                  */
 1023                 if (idev->id_logicalid == ids->ip_id
 1024                     || idev->id_compatid == ids->ip_id) {
 1025                         if (ids->ip_desc)
 1026                                 device_set_desc(child, ids->ip_desc);
 1027                         return (0);
 1028                 }
 1029                 ids++;
 1030         }
 1031 
 1032         return (ENXIO);
 1033 }
 1034 
 1035 static int
 1036 isa_child_pnpinfo(device_t bus, device_t child, struct sbuf *sb)
 1037 {
 1038         struct isa_device *idev = DEVTOISA(child);
 1039 
 1040         if (idev->id_vendorid)
 1041                 sbuf_printf(sb, "pnpid=%s",
 1042                     pnp_eisaformat(idev->id_vendorid));
 1043         return (0);
 1044 }
 1045 
 1046 static int
 1047 isa_child_location(device_t bus, device_t child, struct sbuf *sb)
 1048 {
 1049 #if 0
 1050         /* id_pnphandle isn't there yet */
 1051         struct isa_device *idev = DEVTOISA(child);
 1052 
 1053         if (idev->id_vendorid)
 1054                 sbuf_printf(sbuf, "pnphandle=%d", idev->id_pnphandle);
 1055 #endif
 1056         return (0);
 1057 }
 1058 
 1059 static device_method_t isa_methods[] = {
 1060         /* Device interface */
 1061         DEVMETHOD(device_probe,         isa_probe),
 1062         DEVMETHOD(device_attach,        isa_attach),
 1063         DEVMETHOD(device_detach,        bus_generic_detach),
 1064         DEVMETHOD(device_shutdown,      bus_generic_shutdown),
 1065         DEVMETHOD(device_suspend,       bus_generic_suspend),
 1066         DEVMETHOD(device_resume,        bus_generic_resume),
 1067 
 1068         /* Bus interface */
 1069         DEVMETHOD(bus_add_child,        isa_add_child),
 1070         DEVMETHOD(bus_print_child,      isa_print_child),
 1071         DEVMETHOD(bus_probe_nomatch,    isa_probe_nomatch),
 1072         DEVMETHOD(bus_read_ivar,        isa_read_ivar),
 1073         DEVMETHOD(bus_write_ivar,       isa_write_ivar),
 1074         DEVMETHOD(bus_child_detached,   isa_child_detached),
 1075         DEVMETHOD(bus_driver_added,     isa_driver_added),
 1076         DEVMETHOD(bus_setup_intr,       bus_generic_setup_intr),
 1077         DEVMETHOD(bus_teardown_intr,    bus_generic_teardown_intr),
 1078 
 1079         DEVMETHOD(bus_get_resource_list,isa_get_resource_list),
 1080         DEVMETHOD(bus_alloc_resource,   isa_alloc_resource),
 1081         DEVMETHOD(bus_release_resource, isa_release_resource),
 1082         DEVMETHOD(bus_set_resource,     isa_set_resource),
 1083         DEVMETHOD(bus_get_resource,     bus_generic_rl_get_resource),
 1084         DEVMETHOD(bus_delete_resource,  bus_generic_rl_delete_resource),
 1085         DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
 1086         DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
 1087         DEVMETHOD(bus_child_pnpinfo,    isa_child_pnpinfo),
 1088         DEVMETHOD(bus_child_location,   isa_child_location),
 1089         DEVMETHOD(bus_hinted_child,     isa_hinted_child),
 1090         DEVMETHOD(bus_hint_device_unit, isa_hint_device_unit),
 1091 
 1092         /* ISA interface */
 1093         DEVMETHOD(isa_add_config,       isa_add_config),
 1094         DEVMETHOD(isa_set_config_callback, isa_set_config_callback),
 1095         DEVMETHOD(isa_pnp_probe,        isa_pnp_probe),
 1096 
 1097         { 0, 0 }
 1098 };
 1099 
 1100 DEFINE_CLASS_0(isa, isa_driver, isa_methods, 0);
 1101 
 1102 /*
 1103  * ISA can be attached to a PCI-ISA bridge, or other locations on some
 1104  * platforms.
 1105  */
 1106 DRIVER_MODULE(isa, isab, isa_driver, 0, 0);
 1107 DRIVER_MODULE(isa, eisab, isa_driver, 0, 0);
 1108 MODULE_VERSION(isa, 1);
 1109 
 1110 /*
 1111  * Code common to ISA bridges.
 1112  */
 1113 
 1114 int
 1115 isab_attach(device_t dev)
 1116 {
 1117         device_t child;
 1118 
 1119         child = device_add_child(dev, "isa", 0);
 1120         if (child != NULL)
 1121                 return (bus_generic_attach(dev));
 1122         return (ENXIO);
 1123 }
 1124 
 1125 char *
 1126 pnp_eisaformat(uint32_t id)
 1127 {
 1128         uint8_t *data;
 1129         static char idbuf[8];
 1130         const char  hextoascii[] = "0123456789abcdef";
 1131 
 1132         id = htole32(id);
 1133         data = (uint8_t *)&id;
 1134         idbuf[0] = '@' + ((data[0] & 0x7c) >> 2);
 1135         idbuf[1] = '@' + (((data[0] & 0x3) << 3) + ((data[1] & 0xe0) >> 5));
 1136         idbuf[2] = '@' + (data[1] & 0x1f);
 1137         idbuf[3] = hextoascii[(data[2] >> 4)];
 1138         idbuf[4] = hextoascii[(data[2] & 0xf)];
 1139         idbuf[5] = hextoascii[(data[3] >> 4)];
 1140         idbuf[6] = hextoascii[(data[3] & 0xf)];
 1141         idbuf[7] = 0;
 1142         return(idbuf);
 1143 }

Cache object: ac7e02e6003edce28e369db4db5b8478


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