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  -  FREEBSD11  -  FREEBSD10  -  FREEBSD9  -  FREEBSD92  -  FREEBSD91  -  FREEBSD90  -  FREEBSD8  -  FREEBSD82  -  FREEBSD81  -  FREEBSD80  -  FREEBSD7  -  FREEBSD74  -  FREEBSD73  -  FREEBSD72  -  FREEBSD71  -  FREEBSD70  -  FREEBSD6  -  FREEBSD64  -  FREEBSD63  -  FREEBSD62  -  FREEBSD61  -  FREEBSD60  -  FREEBSD5  -  FREEBSD55  -  FREEBSD54  -  FREEBSD53  -  FREEBSD52  -  FREEBSD51  -  FREEBSD50  -  FREEBSD4  -  FREEBSD3  -  FREEBSD22  -  linux-2.6  -  linux-2.4.22  -  MK83  -  MK84  -  PLAN9  -  DFBSD  -  NETBSD  -  NETBSD5  -  NETBSD4  -  NETBSD3  -  NETBSD20  -  OPENBSD  -  xnu-517  -  xnu-792  -  xnu-792.6.70  -  xnu-1228  -  xnu-1456.1.26  -  xnu-1699.24.8  -  xnu-2050.18.24  -  OPENSOLARIS  -  minix-3-1-1 
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: src/sys/isa/isa_common.c,v 1.32 2002/10/15 00:02:51 jhb Exp $
   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/param.h>
   63 #include <sys/systm.h>
   64 #include <sys/kernel.h>
   65 #include <sys/bus.h>
   66 #include <sys/malloc.h>
   67 #include <sys/module.h>
   68 #include <machine/bus.h>
   69 #include <sys/rman.h>
   70 
   71 #include <machine/resource.h>
   72 
   73 #include <isa/isavar.h>
   74 #include <isa/isa_common.h>
   75 #ifdef __alpha__                /* XXX workaround a stupid warning */
   76 #include <alpha/isa/isavar.h>
   77 #endif
   78 
   79 static int      isa_print_child(device_t bus, device_t dev);
   80 
   81 static MALLOC_DEFINE(M_ISADEV, "isadev", "ISA device");
   82 
   83 static devclass_t isa_devclass;
   84 static int isa_running;
   85 
   86 /*
   87  * At 'probe' time, we add all the devices which we know about to the
   88  * bus.  The generic attach routine will probe and attach them if they
   89  * are alive.
   90  */
   91 static int
   92 isa_probe(device_t dev)
   93 {
   94         device_set_desc(dev, "ISA bus");
   95         isa_init(dev);          /* Allow machdep code to initialise */
   96         return 0;
   97 }
   98 
   99 extern device_t isa_bus_device;
  100 
  101 static int
  102 isa_attach(device_t dev)
  103 {
  104         /*
  105          * Arrange for isa_probe_children(dev) to be called later. XXX
  106          */
  107         isa_bus_device = dev;
  108         return 0;
  109 }
  110 
  111 /*
  112  * Find a working set of memory regions for a child using the ranges
  113  * in *config  and return the regions in *result. Returns non-zero if
  114  * a set of ranges was found.
  115  */
  116 static int
  117 isa_find_memory(device_t child,
  118                 struct isa_config *config,
  119                 struct isa_config *result)
  120 {
  121         int success, i;
  122         struct resource *res[ISA_NMEM];
  123 
  124         /*
  125          * First clear out any existing resource definitions.
  126          */
  127         for (i = 0; i < ISA_NMEM; i++) {
  128                 bus_delete_resource(child, SYS_RES_MEMORY, i);
  129                 res[i] = NULL;
  130         }
  131 
  132         success = 1;
  133         result->ic_nmem = config->ic_nmem;
  134         for (i = 0; i < config->ic_nmem; i++) {
  135                 u_int32_t start, end, size, align;
  136 
  137                 size = config->ic_mem[i].ir_size;
  138 
  139                 /* the PnP device may have a null resource as filler */
  140                 if (size == 0) {
  141                         result->ic_mem[i].ir_start = 0;
  142                         result->ic_mem[i].ir_end = 0;
  143                         result->ic_mem[i].ir_size = 0;
  144                         result->ic_mem[i].ir_align = 0;
  145                         continue;
  146                 }
  147 
  148                 for (start = config->ic_mem[i].ir_start,
  149                              end = config->ic_mem[i].ir_end,
  150                              align = config->ic_mem[i].ir_align;
  151                      start + size - 1 <= end;
  152                      start += align) {
  153                         bus_set_resource(child, SYS_RES_MEMORY, i,
  154                                          start, size);
  155                         res[i] = bus_alloc_resource(child,
  156                                                     SYS_RES_MEMORY, &i,
  157                                                     0, ~0, 1, 0 /* !RF_ACTIVE */);
  158                         if (res[i]) {
  159                                 result->ic_mem[i].ir_start = start;
  160                                 result->ic_mem[i].ir_end = start + size - 1;
  161                                 result->ic_mem[i].ir_size = size;
  162                                 result->ic_mem[i].ir_align = align;
  163                                 break;
  164                         }
  165                 }
  166 
  167                 /*
  168                  * If we didn't find a place for memory range i, then 
  169                  * give up now.
  170                  */
  171                 if (!res[i]) {
  172                         success = 0;
  173                         break;
  174                 }
  175         }
  176 
  177         for (i = 0; i < ISA_NMEM; i++) {
  178                 if (res[i])
  179                         bus_release_resource(child, SYS_RES_MEMORY,
  180                                              i, res[i]);
  181         }
  182 
  183         return success;
  184 }
  185 
  186 /*
  187  * Find a working set of port regions for a child using the ranges
  188  * in *config  and return the regions in *result. Returns non-zero if
  189  * a set of ranges was found.
  190  */
  191 static int
  192 isa_find_port(device_t child,
  193               struct isa_config *config,
  194               struct isa_config *result)
  195 {
  196         int success, i;
  197         struct resource *res[ISA_NPORT];
  198 
  199         /*
  200          * First clear out any existing resource definitions.
  201          */
  202         for (i = 0; i < ISA_NPORT; i++) {
  203                 bus_delete_resource(child, SYS_RES_IOPORT, i);
  204                 res[i] = NULL;
  205         }
  206 
  207         success = 1;
  208         result->ic_nport = config->ic_nport;
  209         for (i = 0; i < config->ic_nport; i++) {
  210                 u_int32_t start, end, size, align;
  211 
  212                 size = config->ic_port[i].ir_size;
  213 
  214                 /* the PnP device may have a null resource as filler */
  215                 if (size == 0) {
  216                         result->ic_port[i].ir_start = 0;
  217                         result->ic_port[i].ir_end = 0;
  218                         result->ic_port[i].ir_size = 0;
  219                         result->ic_port[i].ir_align = 0;
  220                         continue;
  221                 }
  222 
  223                 for (start = config->ic_port[i].ir_start,
  224                              end = config->ic_port[i].ir_end,
  225                              align = config->ic_port[i].ir_align;
  226                      start + size - 1 <= end;
  227                      start += align) {
  228                         bus_set_resource(child, SYS_RES_IOPORT, i,
  229                                          start, size);
  230                         res[i] = bus_alloc_resource(child,
  231                                                     SYS_RES_IOPORT, &i,
  232                                                     0, ~0, 1, 0 /* !RF_ACTIVE */);
  233                         if (res[i]) {
  234                                 result->ic_port[i].ir_start = start;
  235                                 result->ic_port[i].ir_end = start + size - 1;
  236                                 result->ic_port[i].ir_size = size;
  237                                 result->ic_port[i].ir_align = align;
  238                                 break;
  239                         }
  240                 }
  241 
  242                 /*
  243                  * If we didn't find a place for port range i, then 
  244                  * give up now.
  245                  */
  246                 if (!res[i]) {
  247                         success = 0;
  248                         break;
  249                 }
  250         }
  251 
  252         for (i = 0; i < ISA_NPORT; i++) {
  253                 if (res[i])
  254                         bus_release_resource(child, SYS_RES_IOPORT,
  255                                              i, res[i]);
  256         }
  257 
  258         return success;
  259 }
  260 
  261 /*
  262  * Return the index of the first bit in the mask (or -1 if mask is empty.
  263  */
  264 static int
  265 find_first_bit(u_int32_t mask)
  266 {
  267         return ffs(mask) - 1;
  268 }
  269 
  270 /*
  271  * Return the index of the next bit in the mask, or -1 if there are no more.
  272  */
  273 static int
  274 find_next_bit(u_int32_t mask, int bit)
  275 {
  276         bit++;
  277         while (bit < 32 && !(mask & (1 << bit)))
  278                 bit++;
  279         if (bit != 32)
  280                 return bit;
  281         return -1;
  282 }
  283 
  284 /*
  285  * Find a working set of irqs for a child using the masks in *config
  286  * and return the regions in *result. Returns non-zero if a set of
  287  * irqs was found.
  288  */
  289 static int
  290 isa_find_irq(device_t child,
  291              struct isa_config *config,
  292              struct isa_config *result)
  293 {
  294         int success, i;
  295         struct resource *res[ISA_NIRQ];
  296 
  297         /*
  298          * First clear out any existing resource definitions.
  299          */
  300         for (i = 0; i < ISA_NIRQ; i++) {
  301                 bus_delete_resource(child, SYS_RES_IRQ, i);
  302                 res[i] = NULL;
  303         }
  304 
  305         success = 1;
  306         result->ic_nirq = config->ic_nirq;
  307         for (i = 0; i < config->ic_nirq; i++) {
  308                 u_int32_t mask = config->ic_irqmask[i];
  309                 int irq;
  310 
  311                 /* the PnP device may have a null resource as filler */
  312                 if (mask == 0) {
  313                         result->ic_irqmask[i] = 0;
  314                         continue;
  315                 }
  316 
  317                 for (irq = find_first_bit(mask);
  318                      irq != -1;
  319                      irq = find_next_bit(mask, irq)) {
  320                         bus_set_resource(child, SYS_RES_IRQ, i,
  321                                          irq, 1);
  322                         res[i] = bus_alloc_resource(child,
  323                                                     SYS_RES_IRQ, &i,
  324                                                     0, ~0, 1, 0 /* !RF_ACTIVE */ );
  325                         if (res[i]) {
  326                                 result->ic_irqmask[i] = (1 << irq);
  327                                 break;
  328                         }
  329                 }
  330 
  331                 /*
  332                  * If we didn't find a place for irq range i, then 
  333                  * give up now.
  334                  */
  335                 if (!res[i]) {
  336                         success = 0;
  337                         break;
  338                 }
  339         }
  340 
  341         for (i = 0; i < ISA_NIRQ; i++) {
  342                 if (res[i])
  343                         bus_release_resource(child, SYS_RES_IRQ,
  344                                              i, res[i]);
  345         }
  346 
  347         return success;
  348 }
  349 
  350 /*
  351  * Find a working set of drqs for a child using the masks in *config
  352  * and return the regions in *result. Returns non-zero if a set of
  353  * drqs was found.
  354  */
  355 static int
  356 isa_find_drq(device_t child,
  357              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                 u_int32_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(child,
  389                                                     SYS_RES_DRQ, &i,
  390                                                     0, ~0, 1, 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  * Return non-zero if the device has a single configuration, that is,
  477  * a fixed set of resoruces.
  478  */
  479 static int
  480 isa_has_single_config(device_t dev)
  481 {
  482         struct isa_device *idev = DEVTOISA(dev);
  483         struct isa_config_entry *ice;
  484         u_int32_t mask;
  485         int i;
  486 
  487         ice = TAILQ_FIRST(&idev->id_configs);
  488         if (TAILQ_NEXT(ice, ice_link))
  489                 return 0;
  490 
  491         for (i = 0; i < ice->ice_config.ic_nmem; ++i) {
  492                 if (ice->ice_config.ic_mem[i].ir_size == 0)
  493                         continue;
  494                 if (ice->ice_config.ic_mem[i].ir_end !=
  495                     ice->ice_config.ic_mem[i].ir_start + 
  496                     ice->ice_config.ic_mem[i].ir_size - 1)
  497                         return 0;
  498         }
  499         for (i = 0; i < ice->ice_config.ic_nport; ++i) {
  500                 if (ice->ice_config.ic_port[i].ir_size == 0)
  501                         continue;
  502                 if (ice->ice_config.ic_port[i].ir_end !=
  503                     ice->ice_config.ic_port[i].ir_start + 
  504                     ice->ice_config.ic_port[i].ir_size - 1)
  505                         return 0;
  506         }
  507         for (i = 0; i < ice->ice_config.ic_nirq; ++i) {
  508                 mask = ice->ice_config.ic_irqmask[i];
  509                 if (mask == 0)
  510                         continue;
  511                 if (find_next_bit(mask, find_first_bit(mask)) != -1)
  512                         return 0;
  513         }
  514         for (i = 0; i < ice->ice_config.ic_ndrq; ++i) {
  515                 mask = ice->ice_config.ic_drqmask[i];
  516                 if (mask == 0)
  517                         continue;
  518                 if (find_next_bit(mask, find_first_bit(mask)) != -1)
  519                         return 0;
  520         }
  521         return 1;
  522 }
  523 
  524 /*
  525  * Called after other devices have initialised to probe for isa devices.
  526  */
  527 void
  528 isa_probe_children(device_t dev)
  529 {
  530         device_t *children;
  531         struct isa_config *cfg;
  532         int nchildren, i;
  533 
  534         /*
  535          * Create all the children by calling driver's identify methods.
  536          */
  537         bus_generic_probe(dev);
  538 
  539         if (device_get_children(dev, &children, &nchildren))
  540                 return;
  541 
  542         /*
  543          * First disable all pnp devices so that they don't get
  544          * matched by legacy probes.
  545          */
  546         if (bootverbose)
  547                 printf("isa_probe_children: disabling PnP devices\n");
  548 
  549         cfg = malloc(sizeof(*cfg), M_TEMP, M_NOWAIT|M_ZERO);
  550         if (cfg == NULL) {
  551                 free(children, M_TEMP);
  552                 return;
  553         }
  554 
  555         for (i = 0; i < nchildren; i++) {
  556                 device_t child = children[i];
  557                 struct isa_device *idev = DEVTOISA(child);
  558 
  559                 bzero(cfg, sizeof(*cfg));
  560                 if (idev->id_config_cb)
  561                         idev->id_config_cb(idev->id_config_arg, cfg, 0);
  562         }
  563 
  564         free(cfg, M_TEMP);
  565 
  566         /*
  567          * Next probe all non-pnp devices so that they claim their
  568          * resources first.
  569          */
  570         if (bootverbose)
  571                 printf("isa_probe_children: probing non-PnP devices\n");
  572         for (i = 0; i < nchildren; i++) {
  573                 device_t child = children[i];
  574                 struct isa_device *idev = DEVTOISA(child);
  575 
  576                 if (TAILQ_FIRST(&idev->id_configs))
  577                         continue;
  578 
  579                 device_probe_and_attach(child);
  580         }
  581 
  582         /*
  583          * Finally assign resource to pnp devices and probe them.
  584          */
  585         if (bootverbose)
  586                 printf("isa_probe_children: probing PnP devices\n");
  587         for (i = 0; i < nchildren; i++) {
  588                 device_t child = children[i];
  589                 struct isa_device* idev = DEVTOISA(child);
  590 
  591                 if (!TAILQ_FIRST(&idev->id_configs))
  592                         continue;
  593 
  594                 if (isa_assign_resources(child)) {
  595                         struct resource_list *rl = &idev->id_resources;
  596                         struct resource_list_entry *rle;
  597 
  598                         device_probe_and_attach(child);
  599 
  600                         /*
  601                          * Claim any unallocated resources to keep other
  602                          * devices from using them.
  603                          */
  604                         SLIST_FOREACH(rle, rl, link) {
  605                                 if (!rle->res) {
  606                                         int rid = rle->rid;
  607                                         resource_list_alloc(rl, dev, child,
  608                                                             rle->type,
  609                                                             &rid,
  610                                                             0, ~0, 1, 0);
  611                                 }
  612                         }
  613                 }
  614         }
  615 
  616         free(children, M_TEMP);
  617 
  618         isa_running = 1;
  619 }
  620 
  621 /*
  622  * Add a new child with default ivars.
  623  */
  624 static device_t
  625 isa_add_child(device_t dev, int order, const char *name, int unit)
  626 {
  627         device_t child;
  628         struct  isa_device *idev;
  629 
  630         child = device_add_child_ordered(dev, order, name, unit);
  631         if (child == NULL) 
  632                 return (child);
  633         
  634         idev = malloc(sizeof(struct isa_device), M_ISADEV, M_NOWAIT | M_ZERO);
  635         if (!idev)
  636                 return 0;
  637 
  638         resource_list_init(&idev->id_resources);
  639         TAILQ_INIT(&idev->id_configs);
  640 
  641         device_set_ivars(child, idev);
  642 
  643         return (child);
  644 }
  645 
  646 static int
  647 isa_print_all_resources(device_t dev)
  648 {
  649         struct  isa_device *idev = DEVTOISA(dev);
  650         struct resource_list *rl = &idev->id_resources;
  651         int retval = 0;
  652 
  653         if (SLIST_FIRST(rl) || device_get_flags(dev))
  654                 retval += printf(" at");
  655         
  656         retval += resource_list_print_type(rl, "port", SYS_RES_IOPORT, "%#lx");
  657         retval += resource_list_print_type(rl, "iomem", SYS_RES_MEMORY, "%#lx");
  658         retval += resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%ld");
  659         retval += resource_list_print_type(rl, "drq", SYS_RES_DRQ, "%ld");
  660         if (device_get_flags(dev))
  661                 retval += printf(" flags %#x", device_get_flags(dev));
  662 
  663         return retval;
  664 }
  665 
  666 static int
  667 isa_print_child(device_t bus, device_t dev)
  668 {
  669         int retval = 0;
  670 
  671         retval += bus_print_child_header(bus, dev);
  672         retval += isa_print_all_resources(dev);
  673         retval += bus_print_child_footer(bus, dev);
  674 
  675         return (retval);
  676 }
  677 
  678 static void
  679 isa_probe_nomatch(device_t dev, device_t child)
  680 {
  681         if (bootverbose) {
  682                 bus_print_child_header(dev, child);
  683                 printf(" failed to probe");
  684                 isa_print_all_resources(child);
  685                 bus_print_child_footer(dev, child);
  686         }
  687                                       
  688         return;
  689 }
  690 
  691 static int
  692 isa_read_ivar(device_t bus, device_t dev, int index, uintptr_t * result)
  693 {
  694         struct isa_device* idev = DEVTOISA(dev);
  695         struct resource_list *rl = &idev->id_resources;
  696         struct resource_list_entry *rle;
  697 
  698         switch (index) {
  699         case ISA_IVAR_PORT_0:
  700                 rle = resource_list_find(rl, SYS_RES_IOPORT, 0);
  701                 if (rle)
  702                         *result = rle->start;
  703                 else
  704                         *result = -1;
  705                 break;
  706 
  707         case ISA_IVAR_PORT_1:
  708                 rle = resource_list_find(rl, SYS_RES_IOPORT, 1);
  709                 if (rle)
  710                         *result = rle->start;
  711                 else
  712                         *result = -1;
  713                 break;
  714 
  715         case ISA_IVAR_PORTSIZE_0:
  716                 rle = resource_list_find(rl, SYS_RES_IOPORT, 0);
  717                 if (rle)
  718                         *result = rle->count;
  719                 else
  720                         *result = 0;
  721                 break;
  722 
  723         case ISA_IVAR_PORTSIZE_1:
  724                 rle = resource_list_find(rl, SYS_RES_IOPORT, 1);
  725                 if (rle)
  726                         *result = rle->count;
  727                 else
  728                         *result = 0;
  729                 break;
  730 
  731         case ISA_IVAR_MADDR_0:
  732                 rle = resource_list_find(rl, SYS_RES_MEMORY, 0);
  733                 if (rle)
  734                         *result = rle->start;
  735                 else
  736                         *result = -1;
  737                 break;
  738 
  739         case ISA_IVAR_MADDR_1:
  740                 rle = resource_list_find(rl, SYS_RES_MEMORY, 1);
  741                 if (rle)
  742                         *result = rle->start;
  743                 else
  744                         *result = -1;
  745                 break;
  746 
  747         case ISA_IVAR_MEMSIZE_0:
  748                 rle = resource_list_find(rl, SYS_RES_MEMORY, 0);
  749                 if (rle)
  750                         *result = rle->count;
  751                 else
  752                         *result = 0;
  753                 break;
  754 
  755         case ISA_IVAR_MEMSIZE_1:
  756                 rle = resource_list_find(rl, SYS_RES_MEMORY, 1);
  757                 if (rle)
  758                         *result = rle->count;
  759                 else
  760                         *result = 0;
  761                 break;
  762 
  763         case ISA_IVAR_IRQ_0:
  764                 rle = resource_list_find(rl, SYS_RES_IRQ, 0);
  765                 if (rle)
  766                         *result = rle->start;
  767                 else
  768                         *result = -1;
  769                 break;
  770 
  771         case ISA_IVAR_IRQ_1:
  772                 rle = resource_list_find(rl, SYS_RES_IRQ, 1);
  773                 if (rle)
  774                         *result = rle->start;
  775                 else
  776                         *result = -1;
  777                 break;
  778 
  779         case ISA_IVAR_DRQ_0:
  780                 rle = resource_list_find(rl, SYS_RES_DRQ, 0);
  781                 if (rle)
  782                         *result = rle->start;
  783                 else
  784                         *result = -1;
  785                 break;
  786 
  787         case ISA_IVAR_DRQ_1:
  788                 rle = resource_list_find(rl, SYS_RES_DRQ, 1);
  789                 if (rle)
  790                         *result = rle->start;
  791                 else
  792                         *result = -1;
  793                 break;
  794 
  795         case ISA_IVAR_VENDORID:
  796                 *result = idev->id_vendorid;
  797                 break;
  798 
  799         case ISA_IVAR_SERIAL:
  800                 *result = idev->id_serial;
  801                 break;
  802 
  803         case ISA_IVAR_LOGICALID:
  804                 *result = idev->id_logicalid;
  805                 break;
  806 
  807         case ISA_IVAR_COMPATID:
  808                 *result = idev->id_compatid;
  809                 break;
  810 
  811         case ISA_IVAR_CONFIGATTR:
  812                 *result = idev->id_config_attr;
  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,
  824                int index, uintptr_t value)
  825 {
  826         struct isa_device* idev = DEVTOISA(dev);
  827 
  828         switch (index) {
  829         case ISA_IVAR_PORT_0:
  830         case ISA_IVAR_PORT_1:
  831         case ISA_IVAR_PORTSIZE_0:
  832         case ISA_IVAR_PORTSIZE_1:
  833         case ISA_IVAR_MADDR_0:
  834         case ISA_IVAR_MADDR_1:
  835         case ISA_IVAR_MEMSIZE_0:
  836         case ISA_IVAR_MEMSIZE_1:
  837         case ISA_IVAR_IRQ_0:
  838         case ISA_IVAR_IRQ_1:
  839         case ISA_IVAR_DRQ_0:
  840         case ISA_IVAR_DRQ_1:
  841                 return EINVAL;
  842 
  843         case ISA_IVAR_VENDORID:
  844                 idev->id_vendorid = value;
  845                 break;
  846 
  847         case ISA_IVAR_SERIAL:
  848                 idev->id_serial = value;
  849                 break;
  850 
  851         case ISA_IVAR_LOGICALID:
  852                 idev->id_logicalid = value;
  853                 break;
  854 
  855         case ISA_IVAR_COMPATID:
  856                 idev->id_compatid = value;
  857                 break;
  858 
  859         case ISA_IVAR_CONFIGATTR:
  860                 idev->id_config_attr = value;
  861                 break;
  862 
  863         default:
  864                 return (ENOENT);
  865         }
  866 
  867         return (0);
  868 }
  869 
  870 /*
  871  * Free any resources which the driver missed or which we were holding for
  872  * it (see isa_probe_children).
  873  */
  874 static void
  875 isa_child_detached(device_t dev, device_t child)
  876 {
  877         struct isa_device* idev = DEVTOISA(child);
  878         struct resource_list *rl = &idev->id_resources;
  879         struct resource_list_entry *rle;
  880 
  881         if (TAILQ_FIRST(&idev->id_configs)) {
  882                 /*
  883                  * Claim any unallocated resources to keep other
  884                  * devices from using them.
  885                  */
  886                 SLIST_FOREACH(rle, rl, link) {
  887                         if (!rle->res) {
  888                                 int rid = rle->rid;
  889                                 resource_list_alloc(rl, dev, child,
  890                                                     rle->type,
  891                                                     &rid, 0, ~0, 1, 0);
  892                         }
  893                 }
  894         }
  895 }
  896 
  897 static void
  898 isa_driver_added(device_t dev, driver_t *driver)
  899 {
  900         device_t *children;
  901         int nchildren, i;
  902 
  903         /*
  904          * Don't do anything if drivers are dynamically
  905          * added during autoconfiguration (cf. ymf724).
  906          * since that would end up calling identify
  907          * twice.
  908          */
  909         if (!isa_running)
  910                 return;
  911 
  912         DEVICE_IDENTIFY(driver, dev);
  913         if (device_get_children(dev, &children, &nchildren))
  914                 return;
  915 
  916         for (i = 0; i < nchildren; i++) {
  917                 device_t child = children[i];
  918                 struct isa_device *idev = DEVTOISA(child);
  919                 struct resource_list *rl = &idev->id_resources;
  920                 struct resource_list_entry *rle;
  921 
  922                 if (device_get_state(child) != DS_NOTPRESENT)
  923                         continue;
  924                 if (!device_is_enabled(child))
  925                         continue;
  926 
  927                 /*
  928                  * Free resources which we were holding on behalf of
  929                  * the device.
  930                  */
  931                 SLIST_FOREACH(rle, &idev->id_resources, link) {
  932                         if (rle->res)
  933                                 resource_list_release(rl, dev, child,
  934                                                       rle->type,
  935                                                       rle->rid,
  936                                                       rle->res);
  937                 }
  938 
  939                 if (TAILQ_FIRST(&idev->id_configs))
  940                         if (!isa_assign_resources(child))
  941                                 continue;
  942 
  943                 device_probe_and_attach(child);
  944 
  945                 if (TAILQ_FIRST(&idev->id_configs)) {
  946                         /*
  947                          * Claim any unallocated resources to keep other
  948                          * devices from using them.
  949                          */
  950                         SLIST_FOREACH(rle, rl, link) {
  951                                 if (!rle->res) {
  952                                         int rid = rle->rid;
  953                                         resource_list_alloc(rl, dev, child,
  954                                                             rle->type,
  955                                                             &rid, 0, ~0, 1, 0);
  956                                 }
  957                         }
  958                 }
  959         }
  960 
  961         free(children, M_TEMP);
  962 }
  963 
  964 static int
  965 isa_set_resource(device_t dev, device_t child, int type, int rid,
  966                  u_long start, u_long count)
  967 {
  968         struct isa_device* idev = DEVTOISA(child);
  969         struct resource_list *rl = &idev->id_resources;
  970 
  971         if (type != SYS_RES_IOPORT && type != SYS_RES_MEMORY
  972             && type != SYS_RES_IRQ && type != SYS_RES_DRQ)
  973                 return EINVAL;
  974         if (rid < 0)
  975                 return EINVAL;
  976         if (type == SYS_RES_IOPORT && rid >= ISA_NPORT)
  977                 return EINVAL;
  978         if (type == SYS_RES_MEMORY && rid >= ISA_NMEM)
  979                 return EINVAL;
  980         if (type == SYS_RES_IRQ && rid >= ISA_NIRQ)
  981                 return EINVAL;
  982         if (type == SYS_RES_DRQ && rid >= ISA_NDRQ)
  983                 return EINVAL;
  984 
  985         resource_list_add(rl, type, rid, start, start + count - 1, count);
  986 
  987         return 0;
  988 }
  989 
  990 static struct resource_list *
  991 isa_get_resource_list (device_t dev, device_t child)
  992 {
  993         struct isa_device* idev = DEVTOISA(child);
  994         struct resource_list *rl = &idev->id_resources;
  995 
  996         if (!rl)
  997                 return (NULL);
  998 
  999         return (rl);
 1000 }
 1001 
 1002 static int
 1003 isa_add_config(device_t dev, device_t child,
 1004                int priority, struct isa_config *config)
 1005 {
 1006         struct isa_device* idev = DEVTOISA(child);
 1007         struct isa_config_entry *newice, *ice;
 1008 
 1009         newice = malloc(sizeof *ice, M_DEVBUF, M_NOWAIT);
 1010         if (!newice)
 1011                 return ENOMEM;
 1012 
 1013         newice->ice_priority = priority;
 1014         newice->ice_config = *config;
 1015         
 1016         TAILQ_FOREACH(ice, &idev->id_configs, ice_link) {
 1017                 if (ice->ice_priority > priority)
 1018                         break;
 1019         }
 1020         if (ice)
 1021                 TAILQ_INSERT_BEFORE(ice, newice, ice_link);
 1022         else
 1023                 TAILQ_INSERT_TAIL(&idev->id_configs, newice, ice_link);
 1024 
 1025         if (isa_has_single_config(child))
 1026                 idev->id_config_attr &= ~ISACFGATTR_MULTI;
 1027         else
 1028                 idev->id_config_attr |= ISACFGATTR_MULTI;
 1029 
 1030         return 0;
 1031 }
 1032 
 1033 static void
 1034 isa_set_config_callback(device_t dev, device_t child,
 1035                         isa_config_cb *fn, void *arg)
 1036 {
 1037         struct isa_device* idev = DEVTOISA(child);
 1038 
 1039         idev->id_config_cb = fn;
 1040         idev->id_config_arg = arg;
 1041 }
 1042 
 1043 static int
 1044 isa_pnp_probe(device_t dev, device_t child, struct isa_pnp_id *ids)
 1045 {
 1046         struct isa_device* idev = DEVTOISA(child);
 1047 
 1048         if (!idev->id_vendorid)
 1049                 return ENOENT;
 1050 
 1051         while (ids && ids->ip_id) {
 1052                 /*
 1053                  * Really ought to support >1 compat id per device.
 1054                  */
 1055                 if (idev->id_logicalid == ids->ip_id
 1056                     || idev->id_compatid == ids->ip_id) {
 1057                         if (ids->ip_desc)
 1058                                 device_set_desc(child, ids->ip_desc);
 1059                         return 0;
 1060                 }
 1061                 ids++;
 1062         }
 1063 
 1064         return ENXIO;
 1065 }
 1066 
 1067 static device_method_t isa_methods[] = {
 1068         /* Device interface */
 1069         DEVMETHOD(device_probe,         isa_probe),
 1070         DEVMETHOD(device_attach,        isa_attach),
 1071         DEVMETHOD(device_detach,        bus_generic_detach),
 1072         DEVMETHOD(device_shutdown,      bus_generic_shutdown),
 1073         DEVMETHOD(device_suspend,       bus_generic_suspend),
 1074         DEVMETHOD(device_resume,        bus_generic_resume),
 1075 
 1076         /* Bus interface */
 1077         DEVMETHOD(bus_add_child,        isa_add_child),
 1078         DEVMETHOD(bus_print_child,      isa_print_child),
 1079         DEVMETHOD(bus_probe_nomatch,    isa_probe_nomatch),
 1080         DEVMETHOD(bus_read_ivar,        isa_read_ivar),
 1081         DEVMETHOD(bus_write_ivar,       isa_write_ivar),
 1082         DEVMETHOD(bus_child_detached,   isa_child_detached),
 1083         DEVMETHOD(bus_driver_added,     isa_driver_added),
 1084         DEVMETHOD(bus_setup_intr,       isa_setup_intr),
 1085         DEVMETHOD(bus_teardown_intr,    isa_teardown_intr),
 1086 
 1087         DEVMETHOD(bus_get_resource_list,isa_get_resource_list),
 1088         DEVMETHOD(bus_alloc_resource,   isa_alloc_resource),
 1089         DEVMETHOD(bus_release_resource, isa_release_resource),
 1090         DEVMETHOD(bus_set_resource,     isa_set_resource),
 1091         DEVMETHOD(bus_get_resource,     bus_generic_rl_get_resource),
 1092         DEVMETHOD(bus_delete_resource,  bus_generic_rl_delete_resource),
 1093         DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
 1094         DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
 1095 
 1096         /* ISA interface */
 1097         DEVMETHOD(isa_add_config,       isa_add_config),
 1098         DEVMETHOD(isa_set_config_callback, isa_set_config_callback),
 1099         DEVMETHOD(isa_pnp_probe,        isa_pnp_probe),
 1100 
 1101         { 0, 0 }
 1102 };
 1103 
 1104 static driver_t isa_driver = {
 1105         "isa",
 1106         isa_methods,
 1107         1,                      /* no softc */
 1108 };
 1109 
 1110 /*
 1111  * ISA can be attached to a PCI-ISA bridge or directly to the legacy device.
 1112  */
 1113 DRIVER_MODULE(isa, isab, isa_driver, isa_devclass, 0, 0);
 1114 DRIVER_MODULE(isa, eisab, isa_driver, isa_devclass, 0, 0);
 1115 #ifdef __i386__
 1116 DRIVER_MODULE(isa, legacy, isa_driver, isa_devclass, 0, 0);
 1117 #endif

Cache object: 5ea3436c52092d33c314b3ffce22fcf6


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