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.16.2.1 2000/09/16 15:49:52 roger 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         __P((device_t, device_t));
   80 
   81 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();             /* 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                 for (start = config->ic_mem[i].ir_start,
  137                              end = config->ic_mem[i].ir_end,
  138                              size = config->ic_mem[i].ir_size,
  139                              align = config->ic_mem[i].ir_align;
  140                      start + size - 1 <= end;
  141                      start += align) {
  142                         bus_set_resource(child, SYS_RES_MEMORY, i,
  143                                          start, size);
  144                         res[i] = bus_alloc_resource(child,
  145                                                     SYS_RES_MEMORY, &i,
  146                                                     0, ~0, 1, 0 /* !RF_ACTIVE */);
  147                         if (res[i]) {
  148                                 result->ic_mem[i].ir_start = start;
  149                                 result->ic_mem[i].ir_end = start + size - 1;
  150                                 result->ic_mem[i].ir_size = size;
  151                                 result->ic_mem[i].ir_align = align;
  152                                 break;
  153                         }
  154                 }
  155 
  156                 /*
  157                  * If we didn't find a place for memory range i, then 
  158                  * give up now.
  159                  */
  160                 if (!res[i]) {
  161                         success = 0;
  162                         break;
  163                 }
  164         }
  165 
  166         for (i = 0; i < ISA_NMEM; i++) {
  167                 if (res[i])
  168                         bus_release_resource(child, SYS_RES_MEMORY,
  169                                              i, res[i]);
  170         }
  171 
  172         return success;
  173 }
  174 
  175 /*
  176  * Find a working set of port regions for a child using the ranges
  177  * in *config  and return the regions in *result. Returns non-zero if
  178  * a set of ranges was found.
  179  */
  180 static int
  181 isa_find_port(device_t child,
  182               struct isa_config *config,
  183               struct isa_config *result)
  184 {
  185         int success, i;
  186         struct resource *res[ISA_NPORT];
  187 
  188         /*
  189          * First clear out any existing resource definitions.
  190          */
  191         for (i = 0; i < ISA_NPORT; i++) {
  192                 bus_delete_resource(child, SYS_RES_IOPORT, i);
  193                 res[i] = NULL;
  194         }
  195 
  196         success = 1;
  197         result->ic_nport = config->ic_nport;
  198         for (i = 0; i < config->ic_nport; i++) {
  199                 u_int32_t start, end, size, align;
  200                 for (start = config->ic_port[i].ir_start,
  201                              end = config->ic_port[i].ir_end,
  202                              size = config->ic_port[i].ir_size,
  203                              align = config->ic_port[i].ir_align;
  204                      start + size - 1 <= end;
  205                      start += align) {
  206                         bus_set_resource(child, SYS_RES_IOPORT, i,
  207                                          start, size);
  208                         res[i] = bus_alloc_resource(child,
  209                                                     SYS_RES_IOPORT, &i,
  210                                                     0, ~0, 1, 0 /* !RF_ACTIVE */);
  211                         if (res[i]) {
  212                                 result->ic_port[i].ir_start = start;
  213                                 result->ic_port[i].ir_end = start + size - 1;
  214                                 result->ic_port[i].ir_size = size;
  215                                 result->ic_port[i].ir_align = align;
  216                                 break;
  217                         }
  218                 }
  219 
  220                 /*
  221                  * If we didn't find a place for port range i, then 
  222                  * give up now.
  223                  */
  224                 if (!res[i]) {
  225                         success = 0;
  226                         break;
  227                 }
  228         }
  229 
  230         for (i = 0; i < ISA_NPORT; i++) {
  231                 if (res[i])
  232                         bus_release_resource(child, SYS_RES_IOPORT,
  233                                              i, res[i]);
  234         }
  235 
  236         return success;
  237 }
  238 
  239 /*
  240  * Return the index of the first bit in the mask (or -1 if mask is empty.
  241  */
  242 static int
  243 find_first_bit(u_int32_t mask)
  244 {
  245         return ffs(mask) - 1;
  246 }
  247 
  248 /*
  249  * Return the index of the next bit in the mask, or -1 if there are no more.
  250  */
  251 static int
  252 find_next_bit(u_int32_t mask, int bit)
  253 {
  254         bit++;
  255         while (bit < 32 && !(mask & (1 << bit)))
  256                 bit++;
  257         if (bit != 32)
  258                 return bit;
  259         return -1;
  260 }
  261 
  262 /*
  263  * Find a working set of irqs for a child using the masks in *config
  264  * and return the regions in *result. Returns non-zero if a set of
  265  * irqs was found.
  266  */
  267 static int
  268 isa_find_irq(device_t child,
  269              struct isa_config *config,
  270              struct isa_config *result)
  271 {
  272         int success, i;
  273         struct resource *res[ISA_NIRQ];
  274 
  275         /*
  276          * First clear out any existing resource definitions.
  277          */
  278         for (i = 0; i < ISA_NIRQ; i++) {
  279                 bus_delete_resource(child, SYS_RES_IRQ, i);
  280                 res[i] = NULL;
  281         }
  282 
  283         success = 1;
  284         result->ic_nirq = config->ic_nirq;
  285         for (i = 0; i < config->ic_nirq; i++) {
  286                 u_int32_t mask = config->ic_irqmask[i];
  287                 int irq;
  288                 for (irq = find_first_bit(mask);
  289                      irq != -1;
  290                      irq = find_next_bit(mask, irq)) {
  291                         bus_set_resource(child, SYS_RES_IRQ, i,
  292                                          irq, 1);
  293                         res[i] = bus_alloc_resource(child,
  294                                                     SYS_RES_IRQ, &i,
  295                                                     0, ~0, 1, 0 /* !RF_ACTIVE */ );
  296                         if (res[i]) {
  297                                 result->ic_irqmask[i] = (1 << irq);
  298                                 break;
  299                         }
  300                 }
  301 
  302                 /*
  303                  * If we didn't find a place for irq range i, then 
  304                  * give up now.
  305                  */
  306                 if (!res[i]) {
  307                         success = 0;
  308                         break;
  309                 }
  310         }
  311 
  312         for (i = 0; i < ISA_NIRQ; i++) {
  313                 if (res[i])
  314                         bus_release_resource(child, SYS_RES_IRQ,
  315                                              i, res[i]);
  316         }
  317 
  318         return success;
  319 }
  320 
  321 /*
  322  * Find a working set of drqs for a child using the masks in *config
  323  * and return the regions in *result. Returns non-zero if a set of
  324  * drqs was found.
  325  */
  326 static int
  327 isa_find_drq(device_t child,
  328              struct isa_config *config,
  329              struct isa_config *result)
  330 {
  331         int success, i;
  332         struct resource *res[ISA_NDRQ];
  333 
  334         /*
  335          * First clear out any existing resource definitions.
  336          */
  337         for (i = 0; i < ISA_NDRQ; i++) {
  338                 bus_delete_resource(child, SYS_RES_DRQ, i);
  339                 res[i] = NULL;
  340         }
  341 
  342         success = 1;
  343         result->ic_ndrq = config->ic_ndrq;
  344         for (i = 0; i < config->ic_ndrq; i++) {
  345                 u_int32_t mask = config->ic_drqmask[i];
  346                 int drq;
  347                 for (drq = find_first_bit(mask);
  348                      drq != -1;
  349                      drq = find_next_bit(mask, drq)) {
  350                         bus_set_resource(child, SYS_RES_DRQ, i,
  351                                          drq, 1);
  352                         res[i] = bus_alloc_resource(child,
  353                                                     SYS_RES_DRQ, &i,
  354                                                     0, ~0, 1, 0 /* !RF_ACTIVE */);
  355                         if (res[i]) {
  356                                 result->ic_drqmask[i] = (1 << drq);
  357                                 break;
  358                         }
  359                 }
  360 
  361                 /*
  362                  * If we didn't find a place for drq range i, then 
  363                  * give up now.
  364                  */
  365                 if (!res[i]) {
  366                         success = 0;
  367                         break;
  368                 }
  369         }
  370 
  371         for (i = 0; i < ISA_NDRQ; i++) {
  372                 if (res[i])
  373                         bus_release_resource(child, SYS_RES_DRQ,
  374                                              i, res[i]);
  375         }
  376 
  377         return success;
  378 }
  379 
  380 /*
  381  * Attempt to find a working set of resources for a device. Return
  382  * non-zero if a working configuration is found.
  383  */
  384 static int
  385 isa_assign_resources(device_t child)
  386 {
  387         struct isa_device *idev = DEVTOISA(child);
  388         struct isa_config_entry *ice;
  389         struct isa_config config;
  390 
  391         bzero(&config, sizeof config);
  392         TAILQ_FOREACH(ice, &idev->id_configs, ice_link) {
  393                 if (!isa_find_memory(child, &ice->ice_config, &config))
  394                         continue;
  395                 if (!isa_find_port(child, &ice->ice_config, &config))
  396                         continue;
  397                 if (!isa_find_irq(child, &ice->ice_config, &config))
  398                         continue;
  399                 if (!isa_find_drq(child, &ice->ice_config, &config))
  400                         continue;
  401 
  402                 /*
  403                  * A working configuration was found enable the device 
  404                  * with this configuration.
  405                  */
  406                 if (idev->id_config_cb) {
  407                         idev->id_config_cb(idev->id_config_arg,
  408                                            &config, 1);
  409                         return 1;
  410                 }
  411         }
  412 
  413         /*
  414          * Disable the device.
  415          */
  416         bus_print_child_header(device_get_parent(child), child);
  417         printf(" can't assign resources\n");
  418         if (bootverbose)
  419             isa_print_child(device_get_parent(child), child);
  420         bzero(&config, sizeof config);
  421         if (idev->id_config_cb)
  422                 idev->id_config_cb(idev->id_config_arg, &config, 0);
  423         device_disable(child);
  424 
  425         return 0;
  426 }
  427 
  428 /*
  429  * Called after other devices have initialised to probe for isa devices.
  430  */
  431 void
  432 isa_probe_children(device_t dev)
  433 {
  434         device_t *children;
  435         int nchildren, i;
  436 
  437         /*
  438          * Create all the children by calling driver's identify methods.
  439          */
  440         bus_generic_probe(dev);
  441 
  442         if (device_get_children(dev, &children, &nchildren))
  443                 return;
  444 
  445         /*
  446          * First disable all pnp devices so that they don't get
  447          * matched by legacy probes.
  448          */
  449         if (bootverbose)
  450                 printf("isa_probe_children: disabling PnP devices\n");
  451         for (i = 0; i < nchildren; i++) {
  452                 device_t child = children[i];
  453                 struct isa_device *idev = DEVTOISA(child);
  454                 struct isa_config config;
  455 
  456                 bzero(&config, sizeof config);
  457                 if (idev->id_config_cb)
  458                         idev->id_config_cb(idev->id_config_arg, &config, 0);
  459         }
  460 
  461         /*
  462          * Next probe all non-pnp devices so that they claim their
  463          * resources first.
  464          */
  465         if (bootverbose)
  466                 printf("isa_probe_children: probing non-PnP devices\n");
  467         for (i = 0; i < nchildren; i++) {
  468                 device_t child = children[i];
  469                 struct isa_device *idev = DEVTOISA(child);
  470 
  471                 if (TAILQ_FIRST(&idev->id_configs))
  472                         continue;
  473 
  474                 device_probe_and_attach(child);
  475         }
  476 
  477         /*
  478          * Finally assign resource to pnp devices and probe them.
  479          */
  480         if (bootverbose)
  481                 printf("isa_probe_children: probing PnP devices\n");
  482         for (i = 0; i < nchildren; i++) {
  483                 device_t child = children[i];
  484                 struct isa_device* idev = DEVTOISA(child);
  485 
  486                 if (!TAILQ_FIRST(&idev->id_configs))
  487                         continue;
  488 
  489                 if (isa_assign_resources(child)) {
  490                         struct resource_list *rl = &idev->id_resources;
  491                         struct resource_list_entry *rle;
  492 
  493                         device_probe_and_attach(child);
  494 
  495                         /*
  496                          * Claim any unallocated resources to keep other
  497                          * devices from using them.
  498                          */
  499                         SLIST_FOREACH(rle, rl, link) {
  500                                 if (!rle->res) {
  501                                         int rid = rle->rid;
  502                                         resource_list_alloc(rl, dev, child,
  503                                                             rle->type,
  504                                                             &rid,
  505                                                             0, ~0, 1,
  506                                                             0 /* !RF_ACTIVE */);
  507                                 }
  508                         }
  509                 }
  510         }
  511 
  512         free(children, M_TEMP);
  513 
  514         isa_running = 1;
  515 }
  516 
  517 /*
  518  * Add a new child with default ivars.
  519  */
  520 static device_t
  521 isa_add_child(device_t dev, int order, const char *name, int unit)
  522 {
  523         device_t child;
  524         struct  isa_device *idev;
  525 
  526         idev = malloc(sizeof(struct isa_device), M_ISADEV, M_NOWAIT);
  527         if (!idev)
  528                 return 0;
  529         bzero(idev, sizeof *idev);
  530 
  531         resource_list_init(&idev->id_resources);
  532         TAILQ_INIT(&idev->id_configs);
  533 
  534         child = device_add_child_ordered(dev, order, name, unit);
  535         device_set_ivars(child, idev);
  536 
  537         return child;
  538 }
  539 
  540 static int
  541 isa_print_resources(struct resource_list *rl, const char *name, int type,
  542                     int count, const char *format)
  543 {
  544         struct resource_list_entry *rle;
  545         int printed;
  546         int i, retval = 0;;
  547 
  548         printed = 0;
  549         for (i = 0; i < count; i++) {
  550                 rle = resource_list_find(rl, type, i);
  551                 if (rle) {
  552                         if (printed == 0)
  553                                 retval += printf(" %s ", name);
  554                         else if (printed > 0)
  555                                 retval += printf(",");
  556                         printed++;
  557                         retval += printf(format, rle->start);
  558                         if (rle->count > 1) {
  559                                 retval += printf("-");
  560                                 retval += printf(format,
  561                                                  rle->start + rle->count - 1);
  562                         }
  563                 } else if (i > 3) {
  564                         /* check the first few regardless */
  565                         break;
  566                 }
  567         }
  568         return retval;
  569 }
  570 
  571 static int
  572 isa_print_all_resources(device_t dev)
  573 {
  574         struct  isa_device *idev = DEVTOISA(dev);
  575         struct resource_list *rl = &idev->id_resources;
  576         int retval = 0;
  577 
  578         if (SLIST_FIRST(rl) || device_get_flags(dev))
  579                 retval += printf(" at");
  580         
  581         retval += isa_print_resources(rl, "port", SYS_RES_IOPORT,
  582                                       ISA_NPORT, "%#lx");
  583         retval += isa_print_resources(rl, "iomem", SYS_RES_MEMORY,
  584                                       ISA_NMEM, "%#lx");
  585         retval += isa_print_resources(rl, "irq", SYS_RES_IRQ,
  586                                       ISA_NIRQ, "%ld");
  587         retval += isa_print_resources(rl, "drq", SYS_RES_DRQ,
  588                                       ISA_NDRQ, "%ld");
  589         if (device_get_flags(dev))
  590                 retval += printf(" flags %#x", device_get_flags(dev));
  591 
  592         return retval;
  593 }
  594 
  595 static int
  596 isa_print_child(device_t bus, device_t dev)
  597 {
  598         int retval = 0;
  599 
  600         retval += bus_print_child_header(bus, dev);
  601         retval += isa_print_all_resources(dev);
  602         retval += bus_print_child_footer(bus, dev);
  603 
  604         return (retval);
  605 }
  606 
  607 static void
  608 isa_probe_nomatch(device_t dev, device_t child)
  609 {
  610         if (bootverbose) {
  611                 bus_print_child_header(dev, child);
  612                 printf(" failed to probe");
  613                 isa_print_all_resources(child);
  614                 bus_print_child_footer(dev, child);
  615         }
  616                                       
  617         return;
  618 }
  619 
  620 static int
  621 isa_read_ivar(device_t bus, device_t dev, int index, uintptr_t * result)
  622 {
  623         struct isa_device* idev = DEVTOISA(dev);
  624         struct resource_list *rl = &idev->id_resources;
  625         struct resource_list_entry *rle;
  626 
  627         switch (index) {
  628         case ISA_IVAR_PORT_0:
  629                 rle = resource_list_find(rl, SYS_RES_IOPORT, 0);
  630                 if (rle)
  631                         *result = rle->start;
  632                 else
  633                         *result = -1;
  634                 break;
  635 
  636         case ISA_IVAR_PORT_1:
  637                 rle = resource_list_find(rl, SYS_RES_IOPORT, 1);
  638                 if (rle)
  639                         *result = rle->start;
  640                 else
  641                         *result = -1;
  642                 break;
  643 
  644         case ISA_IVAR_PORTSIZE_0:
  645                 rle = resource_list_find(rl, SYS_RES_IOPORT, 0);
  646                 if (rle)
  647                         *result = rle->count;
  648                 else
  649                         *result = 0;
  650                 break;
  651 
  652         case ISA_IVAR_PORTSIZE_1:
  653                 rle = resource_list_find(rl, SYS_RES_IOPORT, 1);
  654                 if (rle)
  655                         *result = rle->count;
  656                 else
  657                         *result = 0;
  658                 break;
  659 
  660         case ISA_IVAR_MADDR_0:
  661                 rle = resource_list_find(rl, SYS_RES_MEMORY, 0);
  662                 if (rle)
  663                         *result = rle->start;
  664                 else
  665                         *result = -1;
  666                 break;
  667 
  668         case ISA_IVAR_MADDR_1:
  669                 rle = resource_list_find(rl, SYS_RES_MEMORY, 1);
  670                 if (rle)
  671                         *result = rle->start;
  672                 else
  673                         *result = -1;
  674                 break;
  675 
  676         case ISA_IVAR_MSIZE_0:
  677                 rle = resource_list_find(rl, SYS_RES_MEMORY, 0);
  678                 if (rle)
  679                         *result = rle->count;
  680                 else
  681                         *result = 0;
  682                 break;
  683 
  684         case ISA_IVAR_MSIZE_1:
  685                 rle = resource_list_find(rl, SYS_RES_MEMORY, 1);
  686                 if (rle)
  687                         *result = rle->count;
  688                 else
  689                         *result = 0;
  690                 break;
  691 
  692         case ISA_IVAR_IRQ_0:
  693                 rle = resource_list_find(rl, SYS_RES_IRQ, 0);
  694                 if (rle)
  695                         *result = rle->start;
  696                 else
  697                         *result = -1;
  698                 break;
  699 
  700         case ISA_IVAR_IRQ_1:
  701                 rle = resource_list_find(rl, SYS_RES_IRQ, 1);
  702                 if (rle)
  703                         *result = rle->start;
  704                 else
  705                         *result = -1;
  706                 break;
  707 
  708         case ISA_IVAR_DRQ_0:
  709                 rle = resource_list_find(rl, SYS_RES_DRQ, 0);
  710                 if (rle)
  711                         *result = rle->start;
  712                 else
  713                         *result = -1;
  714                 break;
  715 
  716         case ISA_IVAR_DRQ_1:
  717                 rle = resource_list_find(rl, SYS_RES_DRQ, 1);
  718                 if (rle)
  719                         *result = rle->start;
  720                 else
  721                         *result = -1;
  722                 break;
  723 
  724         case ISA_IVAR_VENDORID:
  725                 *result = idev->id_vendorid;
  726                 break;
  727 
  728         case ISA_IVAR_SERIAL:
  729                 *result = idev->id_serial;
  730                 break;
  731 
  732         case ISA_IVAR_LOGICALID:
  733                 *result = idev->id_logicalid;
  734                 break;
  735 
  736         case ISA_IVAR_COMPATID:
  737                 *result = idev->id_compatid;
  738                 break;
  739 
  740         default:
  741                 return ENOENT;
  742         }
  743 
  744         return 0;
  745 }
  746 
  747 static int
  748 isa_write_ivar(device_t bus, device_t dev,
  749                int index, uintptr_t value)
  750 {
  751         struct isa_device* idev = DEVTOISA(dev);
  752 
  753         switch (index) {
  754         case ISA_IVAR_PORT_0:
  755         case ISA_IVAR_PORT_1:
  756         case ISA_IVAR_PORTSIZE_0:
  757         case ISA_IVAR_PORTSIZE_1:
  758         case ISA_IVAR_MADDR_0:
  759         case ISA_IVAR_MADDR_1:
  760         case ISA_IVAR_MSIZE_0:
  761         case ISA_IVAR_MSIZE_1:
  762         case ISA_IVAR_IRQ_0:
  763         case ISA_IVAR_IRQ_1:
  764         case ISA_IVAR_DRQ_0:
  765         case ISA_IVAR_DRQ_1:
  766                 return EINVAL;
  767 
  768         case ISA_IVAR_VENDORID:
  769                 idev->id_vendorid = value;
  770                 break;
  771 
  772         case ISA_IVAR_SERIAL:
  773                 idev->id_serial = value;
  774                 break;
  775 
  776         case ISA_IVAR_LOGICALID:
  777                 idev->id_logicalid = value;
  778                 break;
  779 
  780         case ISA_IVAR_COMPATID:
  781                 idev->id_compatid = value;
  782                 break;
  783 
  784         default:
  785                 return (ENOENT);
  786         }
  787 
  788         return (0);
  789 }
  790 
  791 /*
  792  * Free any resources which the driver missed or which we were holding for
  793  * it (see isa_probe_children).
  794  */
  795 static void
  796 isa_child_detached(device_t dev, device_t child)
  797 {
  798         struct isa_device* idev = DEVTOISA(child);
  799         struct resource_list *rl = &idev->id_resources;
  800         struct resource_list_entry *rle;
  801 
  802         if (TAILQ_FIRST(&idev->id_configs)) {
  803                 /*
  804                  * Claim any unallocated resources to keep other
  805                  * devices from using them.
  806                  */
  807                 SLIST_FOREACH(rle, rl, link) {
  808                         if (!rle->res) {
  809                                 int rid = rle->rid;
  810                                 resource_list_alloc(rl, dev, child,
  811                                                     rle->type,
  812                                                     &rid, 0, ~0, 1, 0);
  813                         }
  814                 }
  815         }
  816 }
  817 
  818 static void
  819 isa_driver_added(device_t dev, driver_t *driver)
  820 {
  821         device_t *children;
  822         int nchildren, i;
  823 
  824         /*
  825          * Don't do anything if drivers are dynamically
  826          * added during autoconfiguration (cf. ymf724).
  827          * since that would end up calling identify
  828          * twice.
  829          */
  830         if (!isa_running)
  831                 return;
  832 
  833         DEVICE_IDENTIFY(driver, dev);
  834         if (device_get_children(dev, &children, &nchildren))
  835                 return;
  836 
  837         for (i = 0; i < nchildren; i++) {
  838                 device_t child = children[i];
  839                 struct isa_device *idev = DEVTOISA(child);
  840                 struct resource_list *rl = &idev->id_resources;
  841                 struct resource_list_entry *rle;
  842 
  843                 if (device_get_state(child) != DS_NOTPRESENT)
  844                         continue;
  845                 if (!device_is_enabled(child))
  846                         continue;
  847 
  848                 /*
  849                  * Free resources which we were holding on behalf of
  850                  * the device.
  851                  */
  852                 SLIST_FOREACH(rle, &idev->id_resources, link) {
  853                         if (rle->res)
  854                                 resource_list_release(rl, dev, child,
  855                                                       rle->type,
  856                                                       rle->rid,
  857                                                       rle->res);
  858                 }
  859 
  860                 if (TAILQ_FIRST(&idev->id_configs))
  861                         if (!isa_assign_resources(child))
  862                                 continue;
  863 
  864                 device_probe_and_attach(child);
  865 
  866                 if (TAILQ_FIRST(&idev->id_configs)) {
  867                         /*
  868                          * Claim any unallocated resources to keep other
  869                          * devices from using them.
  870                          */
  871                         SLIST_FOREACH(rle, rl, link) {
  872                                 if (!rle->res) {
  873                                         int rid = rle->rid;
  874                                         resource_list_alloc(rl, dev, child,
  875                                                             rle->type,
  876                                                             &rid,
  877                                                             0, ~0, 1,
  878                                                             0 /* !RF_ACTIVE */);
  879                                 }
  880                         }
  881                 }
  882         }
  883 
  884         free(children, M_TEMP);
  885 }
  886 
  887 static int
  888 isa_set_resource(device_t dev, device_t child, int type, int rid,
  889                  u_long start, u_long count)
  890 {
  891         struct isa_device* idev = DEVTOISA(child);
  892         struct resource_list *rl = &idev->id_resources;
  893 
  894         if (type != SYS_RES_IOPORT && type != SYS_RES_MEMORY
  895             && type != SYS_RES_IRQ && type != SYS_RES_DRQ)
  896                 return EINVAL;
  897         if (rid < 0)
  898                 return EINVAL;
  899         if (type == SYS_RES_IOPORT && rid >= ISA_NPORT)
  900                 return EINVAL;
  901         if (type == SYS_RES_MEMORY && rid >= ISA_NMEM)
  902                 return EINVAL;
  903         if (type == SYS_RES_IRQ && rid >= ISA_NIRQ)
  904                 return EINVAL;
  905         if (type == SYS_RES_DRQ && rid >= ISA_NDRQ)
  906                 return EINVAL;
  907 
  908         resource_list_add(rl, type, rid, start, start + count - 1, count);
  909 
  910         return 0;
  911 }
  912 
  913 static int
  914 isa_get_resource(device_t dev, device_t child, int type, int rid,
  915                  u_long *startp, u_long *countp)
  916 {
  917         struct isa_device* idev = DEVTOISA(child);
  918         struct resource_list *rl = &idev->id_resources;
  919         struct resource_list_entry *rle;
  920 
  921         rle = resource_list_find(rl, type, rid);
  922         if (!rle)
  923                 return ENOENT;
  924         
  925         if (startp)
  926                 *startp = rle->start;
  927         if (countp)
  928                 *countp = rle->count;
  929 
  930         return 0;
  931 }
  932 
  933 static void
  934 isa_delete_resource(device_t dev, device_t child, int type, int rid)
  935 {
  936         struct isa_device* idev = DEVTOISA(child);
  937         struct resource_list *rl = &idev->id_resources;
  938         resource_list_delete(rl, type, rid);
  939 }
  940 
  941 static int
  942 isa_add_config(device_t dev, device_t child,
  943                int priority, struct isa_config *config)
  944 {
  945         struct isa_device* idev = DEVTOISA(child);
  946         struct isa_config_entry *newice, *ice;
  947 
  948         newice = malloc(sizeof *ice, M_DEVBUF, M_NOWAIT);
  949         if (!newice)
  950                 return ENOMEM;
  951 
  952         newice->ice_priority = priority;
  953         newice->ice_config = *config;
  954         
  955         TAILQ_FOREACH(ice, &idev->id_configs, ice_link) {
  956                 if (ice->ice_priority > priority)
  957                         break;
  958         }
  959         if (ice)
  960                 TAILQ_INSERT_BEFORE(ice, newice, ice_link);
  961         else
  962                 TAILQ_INSERT_TAIL(&idev->id_configs, newice, ice_link);
  963 
  964         return 0;
  965 }
  966 
  967 static void
  968 isa_set_config_callback(device_t dev, device_t child,
  969                         isa_config_cb *fn, void *arg)
  970 {
  971         struct isa_device* idev = DEVTOISA(child);
  972 
  973         idev->id_config_cb = fn;
  974         idev->id_config_arg = arg;
  975 }
  976 
  977 static int
  978 isa_pnp_probe(device_t dev, device_t child, struct isa_pnp_id *ids)
  979 {
  980         struct isa_device* idev = DEVTOISA(child);
  981 
  982         if (!idev->id_vendorid)
  983                 return ENOENT;
  984 
  985         while (ids->ip_id) {
  986                 /*
  987                  * Really ought to support >1 compat id per device.
  988                  */
  989                 if (idev->id_logicalid == ids->ip_id
  990                     || idev->id_compatid == ids->ip_id) {
  991                         if (ids->ip_desc)
  992                                 device_set_desc(child, ids->ip_desc);
  993                         return 0;
  994                 }
  995                 ids++;
  996         }
  997 
  998         return ENXIO;
  999 }
 1000 
 1001 static device_method_t isa_methods[] = {
 1002         /* Device interface */
 1003         DEVMETHOD(device_probe,         isa_probe),
 1004         DEVMETHOD(device_attach,        isa_attach),
 1005         DEVMETHOD(device_detach,        bus_generic_detach),
 1006         DEVMETHOD(device_shutdown,      bus_generic_shutdown),
 1007         DEVMETHOD(device_suspend,       bus_generic_suspend),
 1008         DEVMETHOD(device_resume,        bus_generic_resume),
 1009 
 1010         /* Bus interface */
 1011         DEVMETHOD(bus_add_child,        isa_add_child),
 1012         DEVMETHOD(bus_print_child,      isa_print_child),
 1013         DEVMETHOD(bus_probe_nomatch,    isa_probe_nomatch),     
 1014         DEVMETHOD(bus_read_ivar,        isa_read_ivar),
 1015         DEVMETHOD(bus_write_ivar,       isa_write_ivar),
 1016         DEVMETHOD(bus_child_detached,   isa_child_detached),
 1017         DEVMETHOD(bus_driver_added,     isa_driver_added),
 1018         DEVMETHOD(bus_alloc_resource,   isa_alloc_resource),
 1019         DEVMETHOD(bus_release_resource, isa_release_resource),
 1020         DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
 1021         DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
 1022         DEVMETHOD(bus_setup_intr,       isa_setup_intr),
 1023         DEVMETHOD(bus_teardown_intr,    isa_teardown_intr),
 1024         DEVMETHOD(bus_set_resource,     isa_set_resource),
 1025         DEVMETHOD(bus_get_resource,     isa_get_resource),
 1026         DEVMETHOD(bus_delete_resource,  isa_delete_resource),
 1027 
 1028         /* ISA interface */
 1029         DEVMETHOD(isa_add_config,       isa_add_config),
 1030         DEVMETHOD(isa_set_config_callback, isa_set_config_callback),
 1031         DEVMETHOD(isa_pnp_probe,        isa_pnp_probe),
 1032 
 1033         { 0, 0 }
 1034 };
 1035 
 1036 static driver_t isa_driver = {
 1037         "isa",
 1038         isa_methods,
 1039         1,                      /* no softc */
 1040 };
 1041 
 1042 /*
 1043  * ISA can be attached to a PCI-ISA bridge or directly to the nexus.
 1044  */
 1045 DRIVER_MODULE(isa, isab, isa_driver, isa_devclass, 0, 0);
 1046 #ifdef __i386__
 1047 DRIVER_MODULE(isa, nexus, isa_driver, isa_devclass, 0, 0);
 1048 #endif
 1049 

Cache object: bde64a76aecc5f5113893033c3b0b429


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