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

Cache object: 0139a9e6b13baf9ce12a1f0d6d45a739


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