The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/pccard/pccard.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 /*      $NetBSD: pcmcia.c,v 1.23 2000/07/28 19:17:02 drochner Exp $     */
    2 /* $FreeBSD: releng/5.0/sys/dev/pccard/pccard.c 106914 2002-11-14 14:02:32Z mux $ */
    3 
    4 /*
    5  * Copyright (c) 1997 Marc Horowitz.  All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions and the following disclaimer.
   12  * 2. Redistributions in binary form must reproduce the above copyright
   13  *    notice, this list of conditions and the following disclaimer in the
   14  *    documentation and/or other materials provided with the distribution.
   15  * 3. All advertising materials mentioning features or use of this software
   16  *    must display the following acknowledgement:
   17  *      This product includes software developed by Marc Horowitz.
   18  * 4. The name of the author may not be used to endorse or promote products
   19  *    derived from this software without specific prior written permission.
   20  *
   21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   22  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   23  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   24  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   26  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   30  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   31  */
   32 
   33 #include <sys/param.h>
   34 #include <sys/systm.h>
   35 #include <sys/malloc.h>
   36 #include <sys/module.h>
   37 #include <sys/kernel.h>
   38 #include <sys/queue.h>
   39 #include <sys/sysctl.h>
   40 #include <sys/types.h>
   41 
   42 #include <sys/bus.h>
   43 #include <machine/bus.h>
   44 #include <sys/rman.h>
   45 #include <machine/resource.h>
   46 
   47 #include <net/ethernet.h>
   48 
   49 #include <dev/pccard/pccardreg.h>
   50 #include <dev/pccard/pccardvar.h>
   51 
   52 #include "power_if.h"
   53 #include "card_if.h"
   54 
   55 #define PCCARDDEBUG
   56 
   57 /* sysctl vars */
   58 SYSCTL_NODE(_hw, OID_AUTO, pccard, CTLFLAG_RD, 0, "PCCARD parameters");
   59 
   60 int     pccard_debug = 0;
   61 TUNABLE_INT("hw.pccard.debug", &pccard_debug);
   62 SYSCTL_INT(_hw_pccard, OID_AUTO, debug, CTLFLAG_RW,
   63     &pccard_debug, 0,
   64   "pccard debug");
   65 
   66 int     pccard_cis_debug = 0;
   67 TUNABLE_INT("hw.pccard.cis_debug", &pccard_cis_debug);
   68 SYSCTL_INT(_hw_pccard, OID_AUTO, cis_debug, CTLFLAG_RW,
   69     &pccard_cis_debug, 0, "pccard CIS debug");
   70 
   71 #ifdef PCCARDDEBUG
   72 #define DPRINTF(arg) if (pccard_debug) printf arg
   73 #define DEVPRINTF(arg) if (pccard_debug) device_printf arg
   74 #define PRVERBOSE(arg) printf arg
   75 #define DEVPRVERBOSE(arg) device_printf arg
   76 #else
   77 #define DPRINTF(arg)
   78 #define DEVPRINTF(arg)
   79 #define PRVERBOSE(arg) if (bootverbose) printf arg
   80 #define DEVPRVERBOSE(arg) if (bootverbose) device_printf arg
   81 #endif
   82 
   83 static int      pccard_ccr_read(struct pccard_function *pf, int ccr);
   84 static void     pccard_ccr_write(struct pccard_function *pf, int ccr, int val);
   85 static int      pccard_attach_card(device_t dev);
   86 static int      pccard_detach_card(device_t dev);
   87 static int      pccard_card_gettype(device_t dev, int *type);
   88 static void     pccard_function_init(struct pccard_function *pf);
   89 static void     pccard_function_free(struct pccard_function *pf);
   90 static int      pccard_function_enable(struct pccard_function *pf);
   91 static void     pccard_function_disable(struct pccard_function *pf);
   92 static int      pccard_compat_do_probe(device_t bus, device_t dev);
   93 static int      pccard_compat_do_attach(device_t bus, device_t dev);
   94 static int      pccard_add_children(device_t dev, int busno);
   95 static int      pccard_probe(device_t dev);
   96 static int      pccard_attach(device_t dev);
   97 static int      pccard_detach(device_t dev);
   98 static void     pccard_print_resources(struct resource_list *rl,
   99                     const char *name, int type, int count, const char *format);
  100 static int      pccard_print_child(device_t dev, device_t child);
  101 static int      pccard_set_resource(device_t dev, device_t child, int type,
  102                     int rid, u_long start, u_long count);
  103 static int      pccard_get_resource(device_t dev, device_t child, int type,
  104                     int rid, u_long *startp, u_long *countp);
  105 static void     pccard_delete_resource(device_t dev, device_t child, int type,
  106                     int rid);
  107 static int      pccard_set_res_flags(device_t dev, device_t child, int type,
  108                     int rid, u_int32_t flags);
  109 static int      pccard_set_memory_offset(device_t dev, device_t child, int rid,
  110                     u_int32_t offset, u_int32_t *deltap);
  111 static void     pccard_probe_nomatch(device_t cbdev, device_t child);
  112 static int      pccard_read_ivar(device_t bus, device_t child, int which,
  113                     u_char *result);
  114 static void     pccard_driver_added(device_t dev, driver_t *driver);
  115 static struct resource *pccard_alloc_resource(device_t dev,
  116                     device_t child, int type, int *rid, u_long start,
  117                     u_long end, u_long count, u_int flags);
  118 static int      pccard_release_resource(device_t dev, device_t child, int type,
  119                     int rid, struct resource *r);
  120 static void     pccard_child_detached(device_t parent, device_t dev);
  121 static void     pccard_intr(void *arg);
  122 static int      pccard_setup_intr(device_t dev, device_t child,
  123                     struct resource *irq, int flags, driver_intr_t *intr,
  124                     void *arg, void **cookiep);
  125 static int      pccard_teardown_intr(device_t dev, device_t child,
  126                     struct resource *r, void *cookie);
  127 
  128 static const struct pccard_product *
  129 pccard_do_product_lookup(device_t bus, device_t dev,
  130                          const struct pccard_product *tab, size_t ent_size,
  131                          pccard_product_match_fn matchfn);
  132 
  133 
  134 static int
  135 pccard_ccr_read(struct pccard_function *pf, int ccr)
  136 {
  137         return (bus_space_read_1(pf->pf_ccrt, pf->pf_ccrh,
  138             pf->pf_ccr_offset + ccr));
  139 }
  140 
  141 static void
  142 pccard_ccr_write(struct pccard_function *pf, int ccr, int val)
  143 {
  144         if ((pf->ccr_mask) & (1 << (ccr / 2))) {
  145                 bus_space_write_1(pf->pf_ccrt, pf->pf_ccrh,
  146                     pf->pf_ccr_offset + ccr, val);
  147         }
  148 }
  149 
  150 static int
  151 pccard_attach_card(device_t dev)
  152 {
  153         struct pccard_softc *sc = PCCARD_SOFTC(dev);
  154         struct pccard_function *pf;
  155         struct pccard_ivar *ivar;
  156         device_t child;
  157         int i;
  158 
  159         /*
  160          * this is here so that when socket_enable calls gettype, trt happens
  161          */
  162         STAILQ_INIT(&sc->card.pf_head);
  163 
  164         DEVPRINTF((dev, "chip_socket_enable\n"));
  165         POWER_ENABLE_SOCKET(device_get_parent(dev), dev);
  166 
  167         DEVPRINTF((dev, "read_cis\n"));
  168         pccard_read_cis(sc);
  169 
  170         DEVPRINTF((dev, "check_cis_quirks\n"));
  171         pccard_check_cis_quirks(dev);
  172 
  173         /*
  174          * bail now if the card has no functions, or if there was an error in
  175          * the cis.
  176          */
  177 
  178         if (sc->card.error) {
  179                 device_printf(dev, "CARD ERROR!\n");
  180                 return (1);
  181         }
  182         if (STAILQ_EMPTY(&sc->card.pf_head)) {
  183                 device_printf(dev, "Card has no functions!\n");
  184                 return (1);
  185         }
  186 
  187         if (bootverbose || pccard_debug)
  188                 pccard_print_cis(dev);
  189 
  190         DEVPRINTF((dev, "functions scanning\n"));
  191         i = -1;
  192         STAILQ_FOREACH(pf, &sc->card.pf_head, pf_list) {
  193                 i++;
  194                 if (STAILQ_EMPTY(&pf->cfe_head)) {
  195                         device_printf(dev,
  196                             "Function %d has no config entries.!\n", i);
  197                         continue;
  198                 }
  199                 pf->sc = sc;
  200                 pf->cfe = NULL;
  201                 pf->dev = NULL;
  202         }
  203         DEVPRINTF((dev, "Card has %d functions. pccard_mfc is %d\n", i + 1,
  204             pccard_mfc(sc)));
  205 
  206         STAILQ_FOREACH(pf, &sc->card.pf_head, pf_list) {
  207                 if (STAILQ_EMPTY(&pf->cfe_head))
  208                         continue;
  209                 /*
  210                  * In NetBSD, the drivers are responsible for activating
  211                  * each function of a card.  I think that in FreeBSD we
  212                  * want to activate them enough for the usual bus_*_resource
  213                  * routines will do the right thing.  This many mean a
  214                  * departure from the current NetBSD model.
  215                  *
  216                  * This seems to work well in practice for most cards.
  217                  * However, there are two cases that are problematic.
  218                  * If a driver wishes to pick and chose which config
  219                  * entry to use, then this method falls down.  These
  220                  * are usually older cards.  In addition, there are
  221                  * some cards that have multiple hardware units on the
  222                  * cards, but presents only one CIS chain.  These cards
  223                  * are combination cards, but only one of these units
  224                  * can be on at a time.
  225                  */
  226                 ivar = malloc(sizeof(struct pccard_ivar), M_DEVBUF,
  227                     M_WAITOK | M_ZERO);
  228                 child = device_add_child(dev, NULL, -1);
  229                 device_set_ivars(child, ivar);
  230                 ivar->fcn = pf;
  231                 pf->dev = child;
  232                 /*
  233                  * XXX We might want to move the next two lines into
  234                  * XXX the pccard interface layer.  For the moment, this
  235                  * XXX is OK, but some drivers want to pick the config
  236                  * XXX entry to use as well as some address tweaks (mostly
  237                  * XXX due to bugs in decode logic that makes some
  238                  * XXX addresses illegal or broken).
  239                  */
  240                 pccard_function_init(pf);
  241                 if (sc->sc_enabled_count == 0)
  242                         POWER_ENABLE_SOCKET(device_get_parent(dev), dev);
  243                 if (pccard_function_enable(pf) == 0 &&
  244                     device_probe_and_attach(child) == 0) {
  245                         DEVPRINTF((sc->dev, "function %d CCR at %d "
  246                             "offset %x: %x %x %x %x, %x %x %x %x, %x\n",
  247                             pf->number, pf->pf_ccr_window, pf->pf_ccr_offset,
  248                             pccard_ccr_read(pf, 0x00),
  249                         pccard_ccr_read(pf, 0x02), pccard_ccr_read(pf, 0x04),
  250                         pccard_ccr_read(pf, 0x06), pccard_ccr_read(pf, 0x0A),
  251                         pccard_ccr_read(pf, 0x0C), pccard_ccr_read(pf, 0x0E),
  252                         pccard_ccr_read(pf, 0x10), pccard_ccr_read(pf, 0x12)));
  253                 } else {
  254                         if (pf->cfe != NULL)
  255                                 pccard_function_disable(pf);
  256                 }
  257         }
  258         return (0);
  259 }
  260 
  261 static int
  262 pccard_detach_card(device_t dev)
  263 {
  264         struct pccard_softc *sc = PCCARD_SOFTC(dev);
  265         struct pccard_function *pf;
  266         struct pccard_config_entry *cfe;
  267 
  268         /*
  269          * We are running on either the PCCARD socket's event thread
  270          * or in user context detaching a device by user request.
  271          */
  272         STAILQ_FOREACH(pf, &sc->card.pf_head, pf_list) {
  273                 int state = device_get_state(pf->dev);
  274 
  275                 if (state == DS_ATTACHED || state == DS_BUSY)
  276                         device_detach(pf->dev);
  277                 if (pf->cfe != NULL)
  278                         pccard_function_disable(pf);
  279                 pccard_function_free(pf);
  280                 device_delete_child(dev, pf->dev);
  281         }
  282         if (sc->sc_enabled_count == 0)
  283                 POWER_DISABLE_SOCKET(device_get_parent(dev), dev);
  284 
  285         while (NULL != (pf = STAILQ_FIRST(&sc->card.pf_head))) {
  286                 while (NULL != (cfe = STAILQ_FIRST(&pf->cfe_head))) {
  287                         STAILQ_REMOVE_HEAD(&pf->cfe_head, cfe_list);
  288                         free(cfe, M_DEVBUF);
  289                 }
  290                 STAILQ_REMOVE_HEAD(&sc->card.pf_head, pf_list);
  291                 free(pf, M_DEVBUF);
  292         }
  293         return (0);
  294 }
  295 
  296 static const struct pccard_product *
  297 pccard_do_product_lookup(device_t bus, device_t dev,
  298                          const struct pccard_product *tab, size_t ent_size,
  299                          pccard_product_match_fn matchfn)
  300 {
  301         const struct pccard_product *ent;
  302         int matches;
  303         u_int32_t fcn;
  304         u_int32_t vendor;
  305         u_int32_t prod;
  306         char *vendorstr;
  307         char *prodstr;
  308 
  309 #ifdef DIAGNOSTIC
  310         if (sizeof *ent > ent_size)
  311                 panic("pccard_product_lookup: bogus ent_size %ld",
  312                     (long) ent_size);
  313 #endif
  314         if (pccard_get_vendor(dev, &vendor))
  315                 return (NULL);
  316         if (pccard_get_product(dev, &prod))
  317                 return (NULL);
  318         if (pccard_get_function_number(dev, &fcn))
  319                 return (NULL);
  320         if (pccard_get_vendor_str(dev, &vendorstr))
  321                 return (NULL);
  322         if (pccard_get_product_str(dev, &prodstr))
  323                 return (NULL);
  324         for (ent = tab; ent->pp_name != NULL; ent =
  325             (const struct pccard_product *) ((const char *) ent + ent_size)) {
  326                 matches = 1;
  327                 if (ent->pp_vendor == PCCARD_VENDOR_ANY &&
  328                     ent->pp_product == PCCARD_VENDOR_ANY &&
  329                     ent->pp_cis[0] == NULL &&
  330                     ent->pp_cis[1] == NULL) {
  331                         device_printf(dev,
  332                             "Total wildcard entry ignored for %s\n",
  333                             ent->pp_name);
  334                         continue;
  335                 }
  336                 if (matches && ent->pp_vendor != PCCARD_VENDOR_ANY &&
  337                     vendor != ent->pp_vendor)
  338                         matches = 0;
  339                 if (matches && ent->pp_product != PCCARD_PRODUCT_ANY &&
  340                     prod != ent->pp_product)
  341                         matches = 0;
  342                 if (matches && fcn != ent->pp_expfunc)
  343                         matches = 0;
  344                 if (matches && ent->pp_cis[0] &&
  345                     strcmp(ent->pp_cis[0], vendorstr) != 0)
  346                         matches = 0;
  347                 if (matches && ent->pp_cis[1] &&
  348                     strcmp(ent->pp_cis[1], prodstr) != 0)
  349                         matches = 0;
  350                 /* XXX need to match cis[2] and cis[3] also XXX */
  351                 if (matchfn != NULL)
  352                         matches = (*matchfn)(dev, ent, matches);
  353                 if (matches)
  354                         return (ent);
  355         }
  356         return (NULL);
  357 }
  358 
  359 static int
  360 pccard_card_gettype(device_t dev, int *type)
  361 {
  362         struct pccard_softc *sc = PCCARD_SOFTC(dev);
  363         struct pccard_function *pf;
  364 
  365         /*
  366          * set the iftype to memory if this card has no functions (not yet
  367          * probed), or only one function, and that is not initialized yet or
  368          * that is memory.
  369          */
  370         pf = STAILQ_FIRST(&sc->card.pf_head);
  371         if (pf == NULL ||
  372             (STAILQ_NEXT(pf, pf_list) == NULL &&
  373             (pf->cfe == NULL || pf->cfe->iftype == PCCARD_IFTYPE_MEMORY)))
  374                 *type = PCCARD_IFTYPE_MEMORY;
  375         else
  376                 *type = PCCARD_IFTYPE_IO;
  377         return (0);
  378 }
  379 
  380 /*
  381  * Initialize a PCCARD function.  May be called as long as the function is
  382  * disabled.
  383  *
  384  * Note: pccard_function_init should not keep resources allocated.  It should
  385  * only set them up ala isa pnp, set the values in the rl lists, and return.
  386  * Any resource held after pccard_function_init is called is a bug.  However,
  387  * the bus routines to get the resources also assume that pccard_function_init
  388  * does this, so they need to be fixed too.
  389  */
  390 static void
  391 pccard_function_init(struct pccard_function *pf)
  392 {
  393         struct pccard_config_entry *cfe;
  394         int i;
  395         struct pccard_ivar *devi = PCCARD_IVAR(pf->dev);
  396         struct resource_list *rl = &devi->resources;
  397         struct resource_list_entry *rle;
  398         struct resource *r = 0;
  399         device_t bus;
  400         int start;
  401         int end;
  402         int spaces;
  403 
  404         if (pf->pf_flags & PFF_ENABLED) {
  405                 printf("pccard_function_init: function is enabled");
  406                 return;
  407         }
  408         bus = device_get_parent(pf->dev);
  409         /* Remember which configuration entry we are using. */
  410         STAILQ_FOREACH(cfe, &pf->cfe_head, cfe_list) {
  411                 for (i = 0; i < cfe->num_iospace; i++)
  412                         cfe->iores[i] = NULL;
  413                 cfe->irqres = NULL;
  414                 spaces = 0;
  415                 for (i = 0; i < cfe->num_iospace; i++) {
  416                         start = cfe->iospace[i].start;
  417                         if (start)
  418                                 end = start + cfe->iospace[i].length - 1;
  419                         else
  420                                 end = ~0;
  421                         cfe->iorid[i] = i;
  422                         DEVPRINTF((bus, "I/O rid %d start %x end %x\n",
  423                             i, start, end));
  424                         r = cfe->iores[i] = bus_alloc_resource(bus,
  425                             SYS_RES_IOPORT, &cfe->iorid[i], start, end,
  426                             cfe->iospace[i].length,
  427                             rman_make_alignment_flags(cfe->iospace[i].length));
  428                         if (cfe->iores[i] == NULL)
  429                                 goto not_this_one;
  430                         resource_list_add(rl, SYS_RES_IOPORT, cfe->iorid[i],
  431                             rman_get_start(r), rman_get_end(r),
  432                             cfe->iospace[i].length);
  433                         rle = resource_list_find(rl, SYS_RES_IOPORT,
  434                             cfe->iorid[i]);
  435                         rle->res = r;
  436                         spaces++;
  437                 }
  438                 if (cfe->num_memspace > 0) {
  439                         /*
  440                          * Not implement yet, Fix me.
  441                          */
  442                         DEVPRINTF((bus, "Memory space not yet implemented.\n"));
  443                 }
  444                 if (spaces == 0) {
  445                         DEVPRINTF((bus, "Neither memory nor I/O mampped\n"));
  446                         goto not_this_one;
  447                 }
  448                 if (cfe->irqmask) {
  449                         cfe->irqrid = 0;
  450                         r = cfe->irqres = bus_alloc_resource(bus, SYS_RES_IRQ,
  451                             &cfe->irqrid, 0, ~0, 1, 0);
  452                         if (cfe->irqres == NULL)
  453                                 goto not_this_one;
  454                         resource_list_add(rl, SYS_RES_IRQ, cfe->irqrid,
  455                             rman_get_start(r), rman_get_end(r), 1);
  456                         rle = resource_list_find(rl, SYS_RES_IRQ,
  457                             cfe->irqrid);
  458                         rle->res = r;
  459                 }
  460                 /* If we get to here, we've allocated all we need */
  461                 pf->cfe = cfe;
  462                 break;
  463             not_this_one:;
  464                 DEVPRVERBOSE((bus, "Allocation failed for cfe %d\n",
  465                     cfe->number));
  466                 /*
  467                  * Release resources that we partially allocated
  468                  * from this config entry.
  469                  */
  470                 for (i = 0; i < cfe->num_iospace; i++) {
  471                         if (cfe->iores[i] != NULL) {
  472                                 bus_release_resource(bus, SYS_RES_IOPORT,
  473                                     cfe->iorid[i], cfe->iores[i]);
  474                                 rle = resource_list_find(rl, SYS_RES_IOPORT,
  475                                     cfe->iorid[i]);
  476                                 rle->res = NULL;
  477                                 resource_list_delete(rl, SYS_RES_IOPORT,
  478                                     cfe->iorid[i]);
  479                         }
  480                         cfe->iores[i] = NULL;
  481                 }
  482                 if (cfe->irqmask && cfe->irqres != NULL) {
  483                         bus_release_resource(bus, SYS_RES_IRQ,
  484                             cfe->irqrid, cfe->irqres);
  485                         rle = resource_list_find(rl, SYS_RES_IRQ,
  486                             cfe->irqrid);
  487                         rle->res = NULL;
  488                         resource_list_delete(rl, SYS_RES_IRQ, cfe->irqrid);
  489                         cfe->irqres = NULL;
  490                 }
  491         }
  492 }
  493 
  494 /*
  495  * Free resources allocated by pccard_function_init(), May be called as long
  496  * as the function is disabled.
  497  *
  498  * NOTE: This function should be unnecessary.  pccard_function_init should
  499  * never keep resources initialized.
  500  */
  501 static void
  502 pccard_function_free(struct pccard_function *pf)
  503 {
  504         struct pccard_ivar *devi = PCCARD_IVAR(pf->dev);
  505         struct resource_list_entry *rle;
  506 
  507         if (pf->pf_flags & PFF_ENABLED) {
  508                 printf("pccard_function_init: function is enabled");
  509                 return;
  510         }
  511 
  512         SLIST_FOREACH(rle, &devi->resources, link) {
  513                 if (rle->res) {
  514                         if (rle->res->r_dev != pf->sc->dev)
  515                                 device_printf(pf->sc->dev,
  516                                     "function_free: Resource still owned by "
  517                                     "child, oops. "
  518                                     "(type=%d, rid=%d, addr=%lx)\n",
  519                                     rle->type, rle->rid,
  520                                     rman_get_start(rle->res));
  521                         BUS_RELEASE_RESOURCE(device_get_parent(pf->sc->dev),
  522                             rle->res->r_dev, rle->type, rle->rid, rle->res);
  523                         rle->res = NULL;
  524                 }
  525         }
  526         resource_list_free(&devi->resources);
  527 }
  528 
  529 /* Enable a PCCARD function */
  530 static int
  531 pccard_function_enable(struct pccard_function *pf)
  532 {
  533         struct pccard_function *tmp;
  534         int reg;
  535         device_t dev = pf->sc->dev;
  536 
  537         if (pf->cfe == NULL) {
  538                 DEVPRVERBOSE((dev, "No config entry could be allocated.\n"));
  539                 return (ENOMEM);
  540         }
  541 
  542         /*
  543          * Increase the reference count on the socket, enabling power, if
  544          * necessary.
  545          */
  546         pf->sc->sc_enabled_count++;
  547 
  548         if (pf->pf_flags & PFF_ENABLED) {
  549                 /*
  550                  * Don't do anything if we're already enabled.
  551                  */
  552                 return (0);
  553         }
  554 
  555         /*
  556          * it's possible for different functions' CCRs to be in the same
  557          * underlying page.  Check for that.
  558          */
  559         STAILQ_FOREACH(tmp, &pf->sc->card.pf_head, pf_list) {
  560                 if ((tmp->pf_flags & PFF_ENABLED) &&
  561                     (pf->ccr_base >= (tmp->ccr_base - tmp->pf_ccr_offset)) &&
  562                     ((pf->ccr_base + PCCARD_CCR_SIZE) <=
  563                     (tmp->ccr_base - tmp->pf_ccr_offset +
  564                     tmp->pf_ccr_realsize))) {
  565                         pf->pf_ccrt = tmp->pf_ccrt;
  566                         pf->pf_ccrh = tmp->pf_ccrh;
  567                         pf->pf_ccr_realsize = tmp->pf_ccr_realsize;
  568 
  569                         /*
  570                          * pf->pf_ccr_offset = (tmp->pf_ccr_offset -
  571                          * tmp->ccr_base) + pf->ccr_base;
  572                          */
  573                         /* pf->pf_ccr_offset =
  574                             (tmp->pf_ccr_offset + pf->ccr_base) -
  575                             tmp->ccr_base; */
  576                         pf->pf_ccr_window = tmp->pf_ccr_window;
  577                         break;
  578                 }
  579         }
  580         if (tmp == NULL) {
  581                 pf->ccr_rid = 0;
  582                 pf->ccr_res = bus_alloc_resource(dev, SYS_RES_MEMORY,
  583                     &pf->ccr_rid, 0, ~0, 1 << 10, RF_ACTIVE);
  584                 if (!pf->ccr_res)
  585                         goto bad;
  586                 DEVPRINTF((dev, "ccr_res == %lx-%lx, base=%x\n",
  587                     rman_get_start(pf->ccr_res), rman_get_end(pf->ccr_res),
  588                     pf->ccr_base));
  589                 CARD_SET_RES_FLAGS(device_get_parent(dev), dev, SYS_RES_MEMORY,
  590                     pf->ccr_rid, PCCARD_A_MEM_ATTR);
  591                 CARD_SET_MEMORY_OFFSET(device_get_parent(dev), dev,
  592                     pf->ccr_rid, pf->ccr_base, &pf->pf_ccr_offset);
  593                 pf->pf_ccrt = rman_get_bustag(pf->ccr_res);
  594                 pf->pf_ccrh = rman_get_bushandle(pf->ccr_res);
  595                 pf->pf_ccr_realsize = 1;
  596         }
  597 
  598         reg = (pf->cfe->number & PCCARD_CCR_OPTION_CFINDEX);
  599         reg |= PCCARD_CCR_OPTION_LEVIREQ;
  600         if (pccard_mfc(pf->sc)) {
  601                 reg |= (PCCARD_CCR_OPTION_FUNC_ENABLE |
  602                         PCCARD_CCR_OPTION_ADDR_DECODE);
  603                 /* PCCARD_CCR_OPTION_IRQ_ENABLE set elsewhere as needed */
  604         }
  605         pccard_ccr_write(pf, PCCARD_CCR_OPTION, reg);
  606 
  607         reg = 0;
  608         if ((pf->cfe->flags & PCCARD_CFE_IO16) == 0)
  609                 reg |= PCCARD_CCR_STATUS_IOIS8;
  610         if (pf->cfe->flags & PCCARD_CFE_AUDIO)
  611                 reg |= PCCARD_CCR_STATUS_AUDIO;
  612         pccard_ccr_write(pf, PCCARD_CCR_STATUS, reg);
  613 
  614         pccard_ccr_write(pf, PCCARD_CCR_SOCKETCOPY, 0);
  615 
  616         if (pccard_mfc(pf->sc)) {
  617                 long tmp, iosize;
  618 
  619                 tmp = pf->pf_mfc_iomax - pf->pf_mfc_iobase;
  620                 /* round up to nearest (2^n)-1 */
  621                 for (iosize = 1; iosize < tmp; iosize <<= 1)
  622                         ;
  623                 iosize--;
  624 
  625                 pccard_ccr_write(pf, PCCARD_CCR_IOBASE0,
  626                                  pf->pf_mfc_iobase & 0xff);
  627                 pccard_ccr_write(pf, PCCARD_CCR_IOBASE1,
  628                                  (pf->pf_mfc_iobase >> 8) & 0xff);
  629                 pccard_ccr_write(pf, PCCARD_CCR_IOBASE2, 0);
  630                 pccard_ccr_write(pf, PCCARD_CCR_IOBASE3, 0);
  631 
  632                 pccard_ccr_write(pf, PCCARD_CCR_IOSIZE, iosize);
  633         }
  634 
  635 #ifdef PCCARDDEBUG
  636         if (pccard_debug) {
  637                 STAILQ_FOREACH(tmp, &pf->sc->card.pf_head, pf_list) {
  638                         device_printf(tmp->sc->dev,
  639                             "function %d CCR at %d offset %x: "
  640                             "%x %x %x %x, %x %x %x %x, %x\n",
  641                             tmp->number, tmp->pf_ccr_window,
  642                             tmp->pf_ccr_offset,
  643                             pccard_ccr_read(tmp, 0x00),
  644                             pccard_ccr_read(tmp, 0x02),
  645                             pccard_ccr_read(tmp, 0x04),
  646                             pccard_ccr_read(tmp, 0x06),
  647                             pccard_ccr_read(tmp, 0x0A),
  648                             pccard_ccr_read(tmp, 0x0C),
  649                             pccard_ccr_read(tmp, 0x0E),
  650                             pccard_ccr_read(tmp, 0x10),
  651                             pccard_ccr_read(tmp, 0x12));
  652                 }
  653         }
  654 #endif
  655         pf->pf_flags |= PFF_ENABLED;
  656         return (0);
  657 
  658  bad:
  659         /*
  660          * Decrement the reference count, and power down the socket, if
  661          * necessary.
  662          */
  663         pf->sc->sc_enabled_count--;
  664         DEVPRINTF((dev, "bad --enabled_count = %d\n", pf->sc->sc_enabled_count));
  665 
  666         return (1);
  667 }
  668 
  669 /* Disable PCCARD function. */
  670 static void
  671 pccard_function_disable(struct pccard_function *pf)
  672 {
  673         struct pccard_function *tmp;
  674         device_t dev = pf->sc->dev;
  675 
  676         if (pf->cfe == NULL)
  677                 panic("pccard_function_disable: function not initialized");
  678 
  679         if ((pf->pf_flags & PFF_ENABLED) == 0) {
  680                 /*
  681                  * Don't do anything if we're already disabled.
  682                  */
  683                 return;
  684         }
  685 
  686         if (pf->intr_handler != NULL) {
  687                 struct pccard_ivar *devi = PCCARD_IVAR(pf->dev);
  688                 struct resource_list_entry *rle =
  689                     resource_list_find(&devi->resources, SYS_RES_IRQ, 0);
  690                 BUS_TEARDOWN_INTR(dev, pf->dev, rle->res,
  691                     pf->intr_handler_cookie);
  692         }
  693 
  694         /*
  695          * it's possible for different functions' CCRs to be in the same
  696          * underlying page.  Check for that.  Note we mark us as disabled
  697          * first to avoid matching ourself.
  698          */
  699 
  700         pf->pf_flags &= ~PFF_ENABLED;
  701         STAILQ_FOREACH(tmp, &pf->sc->card.pf_head, pf_list) {
  702                 if ((tmp->pf_flags & PFF_ENABLED) &&
  703                     (pf->ccr_base >= (tmp->ccr_base - tmp->pf_ccr_offset)) &&
  704                     ((pf->ccr_base + PCCARD_CCR_SIZE) <=
  705                     (tmp->ccr_base - tmp->pf_ccr_offset +
  706                     tmp->pf_ccr_realsize)))
  707                         break;
  708         }
  709 
  710         /* Not used by anyone else; unmap the CCR. */
  711         if (tmp == NULL) {
  712                 bus_release_resource(dev, SYS_RES_MEMORY, pf->ccr_rid,
  713                     pf->ccr_res);
  714                 pf->ccr_res = NULL;
  715         }
  716 
  717         /*
  718          * Decrement the reference count, and power down the socket, if
  719          * necessary.
  720          */
  721         pf->sc->sc_enabled_count--;
  722 }
  723 
  724 /*
  725  * simulate the old "probe" routine.  In the new world order, the driver
  726  * needs to grab devices while in the old they were assigned to the device by
  727  * the pccardd process.  These symbols are exported to the upper layers.
  728  */
  729 static int
  730 pccard_compat_do_probe(device_t bus, device_t dev)
  731 {
  732         return (CARD_COMPAT_MATCH(dev));
  733 }
  734 
  735 static int
  736 pccard_compat_do_attach(device_t bus, device_t dev)
  737 {
  738         int err;
  739 
  740         err = CARD_COMPAT_PROBE(dev);
  741         if (err == 0)
  742                 err = CARD_COMPAT_ATTACH(dev);
  743         return (err);
  744 }
  745 
  746 #define PCCARD_NPORT    2
  747 #define PCCARD_NMEM     5
  748 #define PCCARD_NIRQ     1
  749 #define PCCARD_NDRQ     0
  750 
  751 static int
  752 pccard_add_children(device_t dev, int busno)
  753 {
  754         /* Call parent to scan for any current children */
  755         return (0);
  756 }
  757 
  758 static int
  759 pccard_probe(device_t dev)
  760 {
  761         device_set_desc(dev, "16-bit PCCard bus");
  762         return (pccard_add_children(dev, device_get_unit(dev)));
  763 }
  764 
  765 static int
  766 pccard_attach(device_t dev)
  767 {
  768         struct pccard_softc *sc = PCCARD_SOFTC(dev);
  769 
  770         sc->dev = dev;
  771         sc->sc_enabled_count = 0;
  772         return (bus_generic_attach(dev));
  773 }
  774 
  775 static int
  776 pccard_detach(device_t dev)
  777 {
  778         pccard_detach_card(dev);
  779         return 0;
  780 }
  781 
  782 static int
  783 pccard_suspend(device_t self)
  784 {
  785         pccard_detach_card(self);
  786         return (0);
  787 }
  788 
  789 static
  790 int
  791 pccard_resume(device_t self)
  792 {
  793         return (0);
  794 }
  795 
  796 static void
  797 pccard_print_resources(struct resource_list *rl, const char *name, int type,
  798     int count, const char *format)
  799 {
  800         struct resource_list_entry *rle;
  801         int printed;
  802         int i;
  803 
  804         printed = 0;
  805         for (i = 0; i < count; i++) {
  806                 rle = resource_list_find(rl, type, i);
  807                 if (rle != NULL) {
  808                         if (printed == 0)
  809                                 printf(" %s ", name);
  810                         else if (printed > 0)
  811                                 printf(",");
  812                         printed++;
  813                         printf(format, rle->start);
  814                         if (rle->count > 1) {
  815                                 printf("-");
  816                                 printf(format, rle->start + rle->count - 1);
  817                         }
  818                 } else if (i > 3) {
  819                         /* check the first few regardless */
  820                         break;
  821                 }
  822         }
  823 }
  824 
  825 static int
  826 pccard_print_child(device_t dev, device_t child)
  827 {
  828         struct pccard_ivar *devi = PCCARD_IVAR(child);
  829         struct resource_list *rl = &devi->resources;
  830         int retval = 0;
  831 
  832         retval += bus_print_child_header(dev, child);
  833         retval += printf(" at");
  834 
  835         if (devi != NULL) {
  836                 pccard_print_resources(rl, "port", SYS_RES_IOPORT,
  837                     PCCARD_NPORT, "%#lx");
  838                 pccard_print_resources(rl, "iomem", SYS_RES_MEMORY,
  839                     PCCARD_NMEM, "%#lx");
  840                 pccard_print_resources(rl, "irq", SYS_RES_IRQ, PCCARD_NIRQ,
  841                     "%ld");
  842                 pccard_print_resources(rl, "drq", SYS_RES_DRQ, PCCARD_NDRQ,
  843                     "%ld");
  844                 retval += printf(" function %d config %d", devi->fcn->number,
  845                     devi->fcn->cfe->number);
  846         }
  847 
  848         retval += bus_print_child_footer(dev, child);
  849 
  850         return (retval);
  851 }
  852 
  853 static int
  854 pccard_set_resource(device_t dev, device_t child, int type, int rid,
  855                  u_long start, u_long count)
  856 {
  857         struct pccard_ivar *devi = PCCARD_IVAR(child);
  858         struct resource_list *rl = &devi->resources;
  859 
  860         if (type != SYS_RES_IOPORT && type != SYS_RES_MEMORY
  861             && type != SYS_RES_IRQ && type != SYS_RES_DRQ)
  862                 return (EINVAL);
  863         if (rid < 0)
  864                 return (EINVAL);
  865         if (type == SYS_RES_IOPORT && rid >= PCCARD_NPORT)
  866                 return (EINVAL);
  867         if (type == SYS_RES_MEMORY && rid >= PCCARD_NMEM)
  868                 return (EINVAL);
  869         if (type == SYS_RES_IRQ && rid >= PCCARD_NIRQ)
  870                 return (EINVAL);
  871         if (type == SYS_RES_DRQ && rid >= PCCARD_NDRQ)
  872                 return (EINVAL);
  873 
  874         resource_list_add(rl, type, rid, start, start + count - 1, count);
  875         if (NULL != resource_list_alloc(rl, device_get_parent(dev), dev,
  876             type, &rid, start, start + count - 1, count, 0))
  877                 return 0;
  878         else
  879                 return ENOMEM;
  880 }
  881 
  882 static int
  883 pccard_get_resource(device_t dev, device_t child, int type, int rid,
  884     u_long *startp, u_long *countp)
  885 {
  886         struct pccard_ivar *devi = PCCARD_IVAR(child);
  887         struct resource_list *rl = &devi->resources;
  888         struct resource_list_entry *rle;
  889 
  890         rle = resource_list_find(rl, type, rid);
  891         if (rle == NULL)
  892                 return (ENOENT);
  893 
  894         if (startp != NULL)
  895                 *startp = rle->start;
  896         if (countp != NULL)
  897                 *countp = rle->count;
  898 
  899         return (0);
  900 }
  901 
  902 static void
  903 pccard_delete_resource(device_t dev, device_t child, int type, int rid)
  904 {
  905         struct pccard_ivar *devi = PCCARD_IVAR(child);
  906         struct resource_list *rl = &devi->resources;
  907         resource_list_delete(rl, type, rid);
  908 }
  909 
  910 static int
  911 pccard_set_res_flags(device_t dev, device_t child, int type, int rid,
  912     u_int32_t flags)
  913 {
  914         return (CARD_SET_RES_FLAGS(device_get_parent(dev), child, type,
  915             rid, flags));
  916 }
  917 
  918 static int
  919 pccard_set_memory_offset(device_t dev, device_t child, int rid,
  920     u_int32_t offset, u_int32_t *deltap)
  921 
  922 {
  923         return (CARD_SET_MEMORY_OFFSET(device_get_parent(dev), child, rid,
  924             offset, deltap));
  925 }
  926 
  927 static void
  928 pccard_probe_nomatch(device_t bus, device_t child)
  929 {
  930         struct pccard_ivar *devi = PCCARD_IVAR(child);
  931         struct pccard_function *func = devi->fcn;
  932         struct pccard_softc *sc = PCCARD_SOFTC(bus);
  933 
  934         device_printf(bus, "<unknown card>");
  935         printf(" (manufacturer=0x%04x, product=0x%04x) at function %d\n",
  936           sc->card.manufacturer, sc->card.product, func->number);
  937         device_printf(bus, "   CIS info: %s, %s, %s\n", sc->card.cis1_info[0],
  938           sc->card.cis1_info[1], sc->card.cis1_info[2]);
  939         return;
  940 }
  941 
  942 static int
  943 pccard_child_location_str(device_t bus, device_t child, char *buf,
  944     size_t buflen)
  945 {
  946         struct pccard_ivar *devi = PCCARD_IVAR(child);
  947         struct pccard_function *func = devi->fcn;
  948 
  949         snprintf(buf, buflen, "function=%d", func->number);
  950         return (0);
  951 }
  952 
  953 static int
  954 pccard_child_pnpinfo_str(device_t bus, device_t child, char *buf,
  955     size_t buflen)
  956 {
  957         struct pccard_ivar *devi = PCCARD_IVAR(child);
  958         struct pccard_function *func = devi->fcn;
  959         struct pccard_softc *sc = PCCARD_SOFTC(bus);
  960 
  961         snprintf(buf, buflen, "manufacturer=0x%04x product=0x%04x "
  962             "cisvendor=\"%s\" cisproduct=\"%s\" function_type=%d",
  963             sc->card.manufacturer, sc->card.product, sc->card.cis1_info[0],
  964             sc->card.cis1_info[1], func->function);
  965         return (0);
  966 }
  967 
  968 static int
  969 pccard_read_ivar(device_t bus, device_t child, int which, u_char *result)
  970 {
  971         struct pccard_ivar *devi = PCCARD_IVAR(child);
  972         struct pccard_function *func = devi->fcn;
  973         struct pccard_softc *sc = PCCARD_SOFTC(bus);
  974 
  975         switch (which) {
  976         default:
  977         case PCCARD_IVAR_ETHADDR:
  978                 bcopy(func->pf_funce_lan_nid, result, ETHER_ADDR_LEN);
  979                 break;
  980         case PCCARD_IVAR_VENDOR:
  981                 *(u_int32_t *) result = sc->card.manufacturer;
  982                 break;
  983         case PCCARD_IVAR_PRODUCT:
  984                 *(u_int32_t *) result = sc->card.product;
  985                 break;
  986         case PCCARD_IVAR_PRODEXT:
  987                 *(u_int16_t *) result = sc->card.prodext;
  988                 break;
  989         case PCCARD_IVAR_FUNCTION:
  990                 *(u_int32_t *) result = func->function;
  991                 break;
  992         case PCCARD_IVAR_FUNCTION_NUMBER:
  993                 if (!func) {
  994                         device_printf(bus, "No function number, bug!\n");
  995                         return (ENOENT);
  996                 }
  997                 *(u_int32_t *) result = func->number;
  998                 break;
  999         case PCCARD_IVAR_VENDOR_STR:
 1000                 *(char **) result = sc->card.cis1_info[0];
 1001                 break;
 1002         case PCCARD_IVAR_PRODUCT_STR:
 1003                 *(char **) result = sc->card.cis1_info[1];
 1004                 break;
 1005         case PCCARD_IVAR_CIS3_STR:
 1006                 *(char **) result = sc->card.cis1_info[2];
 1007                 break;
 1008         case PCCARD_IVAR_CIS4_STR:
 1009                 *(char **) result = sc->card.cis1_info[3];
 1010                 break;
 1011         }
 1012         return (0);
 1013 }
 1014 
 1015 static void
 1016 pccard_driver_added(device_t dev, driver_t *driver)
 1017 {
 1018         struct pccard_softc *sc = PCCARD_SOFTC(dev);
 1019         struct pccard_function *pf;
 1020         device_t child;
 1021 
 1022         STAILQ_FOREACH(pf, &sc->card.pf_head, pf_list) {
 1023                 if (STAILQ_EMPTY(&pf->cfe_head))
 1024                         continue;
 1025                 child = pf->dev;
 1026                 if (device_get_state(child) != DS_NOTPRESENT)
 1027                         continue;
 1028                 if (pccard_function_enable(pf) == 0 &&
 1029                     device_probe_and_attach(child) == 0) {
 1030                         DEVPRINTF((sc->dev, "function %d CCR at %d "
 1031                             "offset %x: %x %x %x %x, %x %x %x %x, %x\n",
 1032                             pf->number, pf->pf_ccr_window, pf->pf_ccr_offset,
 1033                             pccard_ccr_read(pf, 0x00),
 1034                         pccard_ccr_read(pf, 0x02), pccard_ccr_read(pf, 0x04),
 1035                         pccard_ccr_read(pf, 0x06), pccard_ccr_read(pf, 0x0A),
 1036                         pccard_ccr_read(pf, 0x0C), pccard_ccr_read(pf, 0x0E),
 1037                         pccard_ccr_read(pf, 0x10), pccard_ccr_read(pf, 0x12)));
 1038                 } else {
 1039                         if (pf->cfe != NULL)
 1040                                 pccard_function_disable(pf);
 1041                 }
 1042         }
 1043         return;
 1044 }
 1045 
 1046 static struct resource *
 1047 pccard_alloc_resource(device_t dev, device_t child, int type, int *rid,
 1048     u_long start, u_long end, u_long count, u_int flags)
 1049 {
 1050         struct pccard_ivar *dinfo;
 1051         struct resource_list_entry *rle = 0;
 1052         int passthrough = (device_get_parent(child) != dev);
 1053         struct resource *r = NULL;
 1054 
 1055         if (passthrough) {
 1056                 return (BUS_ALLOC_RESOURCE(device_get_parent(dev), child,
 1057                     type, rid, start, end, count, flags));
 1058         }
 1059 
 1060         dinfo = device_get_ivars(child);
 1061         rle = resource_list_find(&dinfo->resources, type, *rid);
 1062 
 1063         if (rle == NULL)
 1064                 return (NULL);          /* no resource of that type/rid */
 1065 
 1066         if (rle->res == NULL) {
 1067                 switch(type) {
 1068                 case SYS_RES_IOPORT:
 1069                         r = bus_alloc_resource(dev, type, rid, start, end,
 1070                             count, rman_make_alignment_flags(count));
 1071                         if (r == NULL)
 1072                                 goto bad;
 1073                         resource_list_add(&dinfo->resources, type, *rid,
 1074                             rman_get_start(r), rman_get_end(r), count);
 1075                         rle = resource_list_find(&dinfo->resources, type, *rid);
 1076                         if (!rle)
 1077                                 goto bad;
 1078                         rle->res = r;
 1079                         break;
 1080                 case SYS_RES_MEMORY:
 1081                         break;
 1082                 case SYS_RES_IRQ:
 1083                         break;
 1084                 }
 1085                 return (rle->res);
 1086         }
 1087         if (rle->res->r_dev != dev)
 1088                 return (NULL);
 1089         bus_release_resource(dev, type, *rid, rle->res);
 1090         rle->res = NULL;
 1091         switch(type) {
 1092         case SYS_RES_IOPORT:
 1093         case SYS_RES_MEMORY:
 1094                 if (!(flags & RF_ALIGNMENT_MASK))
 1095                         flags |= rman_make_alignment_flags(rle->count);
 1096                 break;
 1097         case SYS_RES_IRQ:
 1098                 flags |= RF_SHAREABLE;
 1099                 break;
 1100         }
 1101         rle->res = resource_list_alloc(&dinfo->resources, dev, child,
 1102             type, rid, rle->start, rle->end, rle->count, flags);
 1103         return (rle->res);
 1104 bad:;
 1105         device_printf(dev, "WARNING: Resource not reserved by pccard\n");
 1106         return (NULL);
 1107 }
 1108 
 1109 static int
 1110 pccard_release_resource(device_t dev, device_t child, int type, int rid,
 1111     struct resource *r)
 1112 {
 1113         struct pccard_ivar *dinfo;
 1114         int passthrough = (device_get_parent(child) != dev);
 1115         struct resource_list_entry *rle = 0;
 1116         int ret;
 1117         int flags;
 1118 
 1119         if (passthrough)
 1120                 return BUS_RELEASE_RESOURCE(device_get_parent(dev), child,
 1121                     type, rid, r);
 1122 
 1123         dinfo = device_get_ivars(child);
 1124 
 1125         rle = resource_list_find(&dinfo->resources, type, rid);
 1126 
 1127         if (!rle) {
 1128                 device_printf(dev, "Allocated resource not found, "
 1129                     "%d %x %lx %lx\n",
 1130                     type, rid, rman_get_start(r), rman_get_size(r));
 1131                 return ENOENT;
 1132         }
 1133         if (!rle->res) {
 1134                 device_printf(dev, "Allocated resource not recorded\n");
 1135                 return ENOENT;
 1136         }
 1137 
 1138         ret = BUS_RELEASE_RESOURCE(device_get_parent(dev), child,
 1139             type, rid, r);
 1140         switch(type) {
 1141         case SYS_RES_IOPORT:
 1142         case SYS_RES_MEMORY:
 1143                 flags = rman_make_alignment_flags(rle->count);
 1144                 break;
 1145         case SYS_RES_IRQ:
 1146                 flags = RF_SHAREABLE;
 1147                 break;
 1148         default:
 1149                 flags = 0;
 1150         }
 1151         rle->res = bus_alloc_resource(dev, type, &rid,
 1152             rle->start, rle->end, rle->count, flags);
 1153         if (rle->res == NULL)
 1154                 device_printf(dev, "release_resource: "
 1155                     "unable to reaquire resource\n");
 1156         return ret;
 1157 }
 1158 
 1159 static void
 1160 pccard_child_detached(device_t parent, device_t dev)
 1161 {
 1162         struct pccard_ivar *ivar = PCCARD_IVAR(dev);
 1163         struct pccard_function *pf = ivar->fcn;
 1164 
 1165         pccard_function_disable(pf);
 1166 }
 1167 
 1168 static void
 1169 pccard_intr(void *arg)
 1170 {
 1171         struct pccard_function *pf = (struct pccard_function*) arg;
 1172         int reg;
 1173         int doisr = 1;
 1174 
 1175         /*
 1176          * MFC cards know if they interrupted, so we have to ack the
 1177          * interrupt and call the ISR.  Non-MFC cards don't have these
 1178          * bits, so they always get called.  Many non-MFC cards have
 1179          * this bit set always upon read, but some do not.
 1180          *
 1181          * We always ack the interrupt, even if there's no ISR
 1182          * for the card.  This is done on the theory that acking
 1183          * the interrupt will pacify the card enough to keep an
 1184          * interrupt storm from happening.  Of course this won't
 1185          * help in the non-MFC case.
 1186          */
 1187         if (pccard_mfc(pf->sc)) {
 1188                 reg = pccard_ccr_read(pf, PCCARD_CCR_STATUS);
 1189                 if (reg & PCCARD_CCR_STATUS_INTR)
 1190                         pccard_ccr_write(pf, PCCARD_CCR_STATUS,
 1191                             reg & ~PCCARD_CCR_STATUS_INTR);
 1192                 else
 1193                         doisr = 0;
 1194         }
 1195         if (pf->intr_handler != NULL && doisr)
 1196                 pf->intr_handler(pf->intr_handler_arg);
 1197 }
 1198 
 1199 static int
 1200 pccard_setup_intr(device_t dev, device_t child, struct resource *irq,
 1201     int flags, driver_intr_t *intr, void *arg, void **cookiep)
 1202 {
 1203         struct pccard_softc *sc = PCCARD_SOFTC(dev);
 1204         struct pccard_ivar *ivar = PCCARD_IVAR(child);
 1205         struct pccard_function *func = ivar->fcn;
 1206         int err;
 1207 
 1208         if (func->intr_handler != NULL)
 1209                 panic("Only one interrupt handler per function allowed");
 1210         err = bus_generic_setup_intr(dev, child, irq, flags, pccard_intr,
 1211             func, cookiep);
 1212         if (err != 0)
 1213                 return (err);
 1214         func->intr_handler = intr;
 1215         func->intr_handler_arg = arg;
 1216         func->intr_handler_cookie = *cookiep;
 1217         if (pccard_mfc(sc)) {
 1218                 pccard_ccr_write(func, PCCARD_CCR_OPTION,
 1219                     pccard_ccr_read(func, PCCARD_CCR_OPTION) |
 1220                     PCCARD_CCR_OPTION_IREQ_ENABLE);
 1221         }
 1222         return (0);
 1223 }
 1224 
 1225 static int
 1226 pccard_teardown_intr(device_t dev, device_t child, struct resource *r,
 1227     void *cookie)
 1228 {
 1229         struct pccard_softc *sc = PCCARD_SOFTC(dev);
 1230         struct pccard_ivar *ivar = PCCARD_IVAR(child);
 1231         struct pccard_function *func = ivar->fcn;
 1232         int ret;
 1233 
 1234         if (pccard_mfc(sc)) {
 1235                 pccard_ccr_write(func, PCCARD_CCR_OPTION,
 1236                     pccard_ccr_read(func, PCCARD_CCR_OPTION) &
 1237                     ~PCCARD_CCR_OPTION_IREQ_ENABLE);
 1238         }
 1239         ret = bus_generic_teardown_intr(dev, child, r, cookie);
 1240         if (ret == 0) {
 1241                 func->intr_handler = NULL;
 1242                 func->intr_handler_arg = NULL;
 1243                 func->intr_handler_cookie = NULL;
 1244         }
 1245 
 1246         return (ret);
 1247 }
 1248 
 1249 static device_method_t pccard_methods[] = {
 1250         /* Device interface */
 1251         DEVMETHOD(device_probe,         pccard_probe),
 1252         DEVMETHOD(device_attach,        pccard_attach),
 1253         DEVMETHOD(device_detach,        pccard_detach),
 1254         DEVMETHOD(device_shutdown,      bus_generic_shutdown),
 1255         DEVMETHOD(device_suspend,       pccard_suspend),
 1256         DEVMETHOD(device_resume,        pccard_resume),
 1257 
 1258         /* Bus interface */
 1259         DEVMETHOD(bus_print_child,      pccard_print_child),
 1260         DEVMETHOD(bus_driver_added,     pccard_driver_added),
 1261         DEVMETHOD(bus_child_detached,   pccard_child_detached),
 1262         DEVMETHOD(bus_alloc_resource,   pccard_alloc_resource),
 1263         DEVMETHOD(bus_release_resource, pccard_release_resource),
 1264         DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
 1265         DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
 1266         DEVMETHOD(bus_setup_intr,       pccard_setup_intr),
 1267         DEVMETHOD(bus_teardown_intr,    pccard_teardown_intr),
 1268         DEVMETHOD(bus_set_resource,     pccard_set_resource),
 1269         DEVMETHOD(bus_get_resource,     pccard_get_resource),
 1270         DEVMETHOD(bus_delete_resource,  pccard_delete_resource),
 1271         DEVMETHOD(bus_probe_nomatch,    pccard_probe_nomatch),
 1272         DEVMETHOD(bus_read_ivar,        pccard_read_ivar),
 1273         DEVMETHOD(bus_child_pnpinfo_str, pccard_child_pnpinfo_str),
 1274         DEVMETHOD(bus_child_location_str, pccard_child_location_str),
 1275 
 1276         /* Card Interface */
 1277         DEVMETHOD(card_set_res_flags,   pccard_set_res_flags),
 1278         DEVMETHOD(card_set_memory_offset, pccard_set_memory_offset),
 1279         DEVMETHOD(card_get_type,        pccard_card_gettype),
 1280         DEVMETHOD(card_attach_card,     pccard_attach_card),
 1281         DEVMETHOD(card_detach_card,     pccard_detach_card),
 1282         DEVMETHOD(card_compat_do_probe, pccard_compat_do_probe),
 1283         DEVMETHOD(card_compat_do_attach, pccard_compat_do_attach),
 1284         DEVMETHOD(card_do_product_lookup, pccard_do_product_lookup),
 1285 
 1286         { 0, 0 }
 1287 };
 1288 
 1289 static driver_t pccard_driver = {
 1290         "pccard",
 1291         pccard_methods,
 1292         sizeof(struct pccard_softc)
 1293 };
 1294 
 1295 devclass_t      pccard_devclass;
 1296 
 1297 /* Maybe we need to have a slot device? */
 1298 DRIVER_MODULE(pccard, pcic, pccard_driver, pccard_devclass, 0, 0);
 1299 DRIVER_MODULE(pccard, pc98pcic, pccard_driver, pccard_devclass, 0, 0);
 1300 DRIVER_MODULE(pccard, cbb, pccard_driver, pccard_devclass, 0, 0);
 1301 DRIVER_MODULE(pccard, tcic, pccard_driver, pccard_devclass, 0, 0);
 1302 MODULE_VERSION(pccard, 1);
 1303 /*MODULE_DEPEND(pccard, pcic, 1, 1, 1);*/

Cache object: 1799d6069a0966816aa4f9d50884bd7b


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