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: releng/5.3/sys/dev/pccard/pccard.c 133865 2004-08-16 15:57:18Z imp $");
   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, u_int32_t flags);
  110 static int      pccard_set_memory_offset(device_t dev, device_t child, int rid,
  111                     u_int32_t offset, u_int32_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         u_int32_t fcn;
  339         u_int32_t vendor;
  340         u_int32_t prod;
  341         const char *vendorstr;
  342         const char *prodstr;
  343 
  344 #ifdef DIAGNOSTIC
  345         if (sizeof *ent > ent_size)
  346                 panic("pccard_product_lookup: bogus ent_size %jd",
  347                     (intmax_t) ent_size);
  348 #endif
  349         if (pccard_get_vendor(dev, &vendor))
  350                 return (NULL);
  351         if (pccard_get_product(dev, &prod))
  352                 return (NULL);
  353         if (pccard_get_function_number(dev, &fcn))
  354                 return (NULL);
  355         if (pccard_get_vendor_str(dev, &vendorstr))
  356                 return (NULL);
  357         if (pccard_get_product_str(dev, &prodstr))
  358                 return (NULL);
  359         for (ent = tab; ent->pp_vendor != 0; ent =
  360             (const struct pccard_product *) ((const char *) ent + ent_size)) {
  361                 matches = 1;
  362                 if (ent->pp_vendor == PCCARD_VENDOR_ANY &&
  363                     ent->pp_product == PCCARD_PRODUCT_ANY &&
  364                     ent->pp_cis[0] == NULL &&
  365                     ent->pp_cis[1] == NULL) {
  366                         if (ent->pp_name)
  367                                 device_printf(dev,
  368                                     "Total wildcard entry ignored for %s\n",
  369                                     ent->pp_name);
  370                         continue;
  371                 }
  372                 if (matches && ent->pp_vendor != PCCARD_VENDOR_ANY &&
  373                     vendor != ent->pp_vendor)
  374                         matches = 0;
  375                 if (matches && ent->pp_product != PCCARD_PRODUCT_ANY &&
  376                     prod != ent->pp_product)
  377                         matches = 0;
  378                 if (matches && fcn != ent->pp_expfunc)
  379                         matches = 0;
  380                 if (matches && ent->pp_cis[0] &&
  381                     (vendorstr == NULL ||
  382                     strcmp(ent->pp_cis[0], vendorstr) != 0))
  383                         matches = 0;
  384                 if (matches && ent->pp_cis[1] &&
  385                     (prodstr == NULL ||
  386                     strcmp(ent->pp_cis[1], prodstr) != 0))
  387                         matches = 0;
  388                 /* XXX need to match cis[2] and cis[3] also XXX */
  389                 if (matchfn != NULL)
  390                         matches = (*matchfn)(dev, ent, matches);
  391                 if (matches)
  392                         return (ent);
  393         }
  394         return (NULL);
  395 }
  396 
  397 /*
  398  * Initialize a PCCARD function.  May be called as long as the function is
  399  * disabled.
  400  *
  401  * Note: pccard_function_init should not keep resources allocated.  It should
  402  * only set them up ala isa pnp, set the values in the rl lists, and return.
  403  * Any resource held after pccard_function_init is called is a bug.  However,
  404  * the bus routines to get the resources also assume that pccard_function_init
  405  * does this, so they need to be fixed too.
  406  */
  407 static void
  408 pccard_function_init(struct pccard_function *pf)
  409 {
  410         struct pccard_config_entry *cfe;
  411         int i;
  412         struct pccard_ivar *devi = PCCARD_IVAR(pf->dev);
  413         struct resource_list *rl = &devi->resources;
  414         struct resource_list_entry *rle;
  415         struct resource *r = 0;
  416         device_t bus;
  417         int start;
  418         int end;
  419         int spaces;
  420 
  421         if (pf->pf_flags & PFF_ENABLED) {
  422                 printf("pccard_function_init: function is enabled");
  423                 return;
  424         }
  425         bus = device_get_parent(pf->dev);
  426         /* Remember which configuration entry we are using. */
  427         STAILQ_FOREACH(cfe, &pf->cfe_head, cfe_list) {
  428                 for (i = 0; i < cfe->num_iospace; i++)
  429                         cfe->iores[i] = NULL;
  430                 cfe->irqres = NULL;
  431                 spaces = 0;
  432                 for (i = 0; i < cfe->num_iospace; i++) {
  433                         start = cfe->iospace[i].start;
  434                         if (start)
  435                                 end = start + cfe->iospace[i].length - 1;
  436                         else
  437                                 end = ~0;
  438                         cfe->iorid[i] = i;
  439                         DEVPRINTF((bus, "I/O rid %d start %x end %x\n",
  440                             i, start, end));
  441                         r = cfe->iores[i] = bus_alloc_resource(bus,
  442                             SYS_RES_IOPORT, &cfe->iorid[i], start, end,
  443                             cfe->iospace[i].length,
  444                             rman_make_alignment_flags(cfe->iospace[i].length));
  445                         if (cfe->iores[i] == NULL)
  446                                 goto not_this_one;
  447                         resource_list_add(rl, SYS_RES_IOPORT, cfe->iorid[i],
  448                             rman_get_start(r), rman_get_end(r),
  449                             cfe->iospace[i].length);
  450                         rle = resource_list_find(rl, SYS_RES_IOPORT,
  451                             cfe->iorid[i]);
  452                         rle->res = r;
  453                         spaces++;
  454                 }
  455                 if (cfe->num_memspace > 0) {
  456                         /*
  457                          * Not implement yet, Fix me.
  458                          */
  459                         DEVPRINTF((bus, "Memory space not yet implemented.\n"));
  460                 }
  461                 if (spaces == 0) {
  462                         DEVPRINTF((bus, "Neither memory nor I/O mampped\n"));
  463                         goto not_this_one;
  464                 }
  465                 if (cfe->irqmask) {
  466                         cfe->irqrid = 0;
  467                         r = cfe->irqres = bus_alloc_resource_any(bus,
  468                                 SYS_RES_IRQ, &cfe->irqrid, 0);
  469                         if (cfe->irqres == NULL)
  470                                 goto not_this_one;
  471                         resource_list_add(rl, SYS_RES_IRQ, cfe->irqrid,
  472                             rman_get_start(r), rman_get_end(r), 1);
  473                         rle = resource_list_find(rl, SYS_RES_IRQ,
  474                             cfe->irqrid);
  475                         rle->res = r;
  476                 }
  477                 /* If we get to here, we've allocated all we need */
  478                 pf->cfe = cfe;
  479                 break;
  480             not_this_one:;
  481                 DEVPRVERBOSE((bus, "Allocation failed for cfe %d\n",
  482                     cfe->number));
  483                 /*
  484                  * Release resources that we partially allocated
  485                  * from this config entry.
  486                  */
  487                 for (i = 0; i < cfe->num_iospace; i++) {
  488                         if (cfe->iores[i] != NULL) {
  489                                 bus_release_resource(bus, SYS_RES_IOPORT,
  490                                     cfe->iorid[i], cfe->iores[i]);
  491                                 rle = resource_list_find(rl, SYS_RES_IOPORT,
  492                                     cfe->iorid[i]);
  493                                 rle->res = NULL;
  494                                 resource_list_delete(rl, SYS_RES_IOPORT,
  495                                     cfe->iorid[i]);
  496                         }
  497                         cfe->iores[i] = NULL;
  498                 }
  499                 if (cfe->irqmask && cfe->irqres != NULL) {
  500                         bus_release_resource(bus, SYS_RES_IRQ,
  501                             cfe->irqrid, cfe->irqres);
  502                         rle = resource_list_find(rl, SYS_RES_IRQ,
  503                             cfe->irqrid);
  504                         rle->res = NULL;
  505                         resource_list_delete(rl, SYS_RES_IRQ, cfe->irqrid);
  506                         cfe->irqres = NULL;
  507                 }
  508         }
  509 }
  510 
  511 /*
  512  * Free resources allocated by pccard_function_init(), May be called as long
  513  * as the function is disabled.
  514  *
  515  * NOTE: This function should be unnecessary.  pccard_function_init should
  516  * never keep resources initialized.
  517  */
  518 static void
  519 pccard_function_free(struct pccard_function *pf)
  520 {
  521         struct pccard_ivar *devi = PCCARD_IVAR(pf->dev);
  522         struct resource_list_entry *rle;
  523 
  524         if (pf->pf_flags & PFF_ENABLED) {
  525                 printf("pccard_function_init: function is enabled");
  526                 return;
  527         }
  528 
  529         SLIST_FOREACH(rle, &devi->resources, link) {
  530                 if (rle->res) {
  531                         if (rman_get_device(rle->res) != pf->sc->dev)
  532                                 device_printf(pf->sc->dev,
  533                                     "function_free: Resource still owned by "
  534                                     "child, oops. "
  535                                     "(type=%d, rid=%d, addr=%lx)\n",
  536                                     rle->type, rle->rid,
  537                                     rman_get_start(rle->res));
  538                         BUS_RELEASE_RESOURCE(device_get_parent(pf->sc->dev),
  539                             pf->sc->dev, rle->type, rle->rid, rle->res);
  540                         rle->res = NULL;
  541                 }
  542         }
  543         resource_list_free(&devi->resources);
  544 }
  545 
  546 static void
  547 pccard_mfc_adjust_iobase(struct pccard_function *pf, bus_addr_t addr,
  548     bus_addr_t offset, bus_size_t size)
  549 {
  550         bus_size_t iosize, tmp;
  551 
  552         if (addr != 0) {
  553                 if (pf->pf_mfc_iomax == 0) {
  554                         pf->pf_mfc_iobase = addr + offset;
  555                         pf->pf_mfc_iomax = pf->pf_mfc_iobase + size;
  556                 } else {
  557                         /* this makes the assumption that nothing overlaps */
  558                         if (pf->pf_mfc_iobase > addr + offset)
  559                                 pf->pf_mfc_iobase = addr + offset;
  560                         if (pf->pf_mfc_iomax < addr + offset + size)
  561                                 pf->pf_mfc_iomax = addr + offset + size;
  562                 }
  563         }
  564 
  565         tmp = pf->pf_mfc_iomax - pf->pf_mfc_iobase;
  566         /* round up to nearest (2^n)-1 */
  567         for (iosize = 1; iosize < tmp; iosize <<= 1)
  568                 ;
  569         iosize--;
  570 
  571         DEVPRINTF((pf->dev, "MFC: I/O base %#jx IOSIZE %#jx\n",
  572             (uintmax_t)pf->pf_mfc_iobase, (uintmax_t)(iosize + 1)));
  573         pccard_ccr_write(pf, PCCARD_CCR_IOBASE0,
  574             pf->pf_mfc_iobase & 0xff);
  575         pccard_ccr_write(pf, PCCARD_CCR_IOBASE1,
  576             (pf->pf_mfc_iobase >> 8) & 0xff);
  577         pccard_ccr_write(pf, PCCARD_CCR_IOBASE2, 0);
  578         pccard_ccr_write(pf, PCCARD_CCR_IOBASE3, 0);
  579         pccard_ccr_write(pf, PCCARD_CCR_IOSIZE, iosize);
  580 }
  581 
  582 /* Enable a PCCARD function */
  583 static int
  584 pccard_function_enable(struct pccard_function *pf)
  585 {
  586         struct pccard_function *tmp;
  587         int reg;
  588         device_t dev = pf->sc->dev;
  589 
  590         if (pf->cfe == NULL) {
  591                 DEVPRVERBOSE((dev, "No config entry could be allocated.\n"));
  592                 return (ENOMEM);
  593         }
  594 
  595         /*
  596          * Increase the reference count on the socket, enabling power, if
  597          * necessary.
  598          */
  599         pf->sc->sc_enabled_count++;
  600 
  601         if (pf->pf_flags & PFF_ENABLED) {
  602                 /*
  603                  * Don't do anything if we're already enabled.
  604                  */
  605                 return (0);
  606         }
  607 
  608         /*
  609          * it's possible for different functions' CCRs to be in the same
  610          * underlying page.  Check for that.
  611          */
  612         STAILQ_FOREACH(tmp, &pf->sc->card.pf_head, pf_list) {
  613                 if ((tmp->pf_flags & PFF_ENABLED) &&
  614                     (pf->ccr_base >= (tmp->ccr_base - tmp->pf_ccr_offset)) &&
  615                     ((pf->ccr_base + PCCARD_CCR_SIZE) <=
  616                     (tmp->ccr_base - tmp->pf_ccr_offset +
  617                     tmp->pf_ccr_realsize))) {
  618                         pf->pf_ccrt = tmp->pf_ccrt;
  619                         pf->pf_ccrh = tmp->pf_ccrh;
  620                         pf->pf_ccr_realsize = tmp->pf_ccr_realsize;
  621 
  622                         /*
  623                          * pf->pf_ccr_offset = (tmp->pf_ccr_offset -
  624                          * tmp->ccr_base) + pf->ccr_base;
  625                          */
  626                         /* pf->pf_ccr_offset =
  627                             (tmp->pf_ccr_offset + pf->ccr_base) -
  628                             tmp->ccr_base; */
  629                         pf->pf_ccr_window = tmp->pf_ccr_window;
  630                         break;
  631                 }
  632         }
  633         if (tmp == NULL) {
  634                 pf->ccr_rid = 0;
  635                 pf->ccr_res = bus_alloc_resource(dev, SYS_RES_MEMORY,
  636                     &pf->ccr_rid, 0, ~0, 1 << 10, RF_ACTIVE);
  637                 if (!pf->ccr_res)
  638                         goto bad;
  639                 DEVPRINTF((dev, "ccr_res == %lx-%lx, base=%x\n",
  640                     rman_get_start(pf->ccr_res), rman_get_end(pf->ccr_res),
  641                     pf->ccr_base));
  642                 CARD_SET_RES_FLAGS(device_get_parent(dev), dev, SYS_RES_MEMORY,
  643                     pf->ccr_rid, PCCARD_A_MEM_ATTR);
  644                 CARD_SET_MEMORY_OFFSET(device_get_parent(dev), dev,
  645                     pf->ccr_rid, pf->ccr_base, &pf->pf_ccr_offset);
  646                 pf->pf_ccrt = rman_get_bustag(pf->ccr_res);
  647                 pf->pf_ccrh = rman_get_bushandle(pf->ccr_res);
  648                 pf->pf_ccr_realsize = 1;
  649         }
  650 
  651         reg = (pf->cfe->number & PCCARD_CCR_OPTION_CFINDEX);
  652         reg |= PCCARD_CCR_OPTION_LEVIREQ;
  653         if (pccard_mfc(pf->sc)) {
  654                 reg |= (PCCARD_CCR_OPTION_FUNC_ENABLE |
  655                         PCCARD_CCR_OPTION_ADDR_DECODE);
  656                 /* PCCARD_CCR_OPTION_IRQ_ENABLE set elsewhere as needed */
  657         }
  658         pccard_ccr_write(pf, PCCARD_CCR_OPTION, reg);
  659 
  660         reg = 0;
  661         if ((pf->cfe->flags & PCCARD_CFE_IO16) == 0)
  662                 reg |= PCCARD_CCR_STATUS_IOIS8;
  663         if (pf->cfe->flags & PCCARD_CFE_AUDIO)
  664                 reg |= PCCARD_CCR_STATUS_AUDIO;
  665         pccard_ccr_write(pf, PCCARD_CCR_STATUS, reg);
  666 
  667         pccard_ccr_write(pf, PCCARD_CCR_SOCKETCOPY, 0);
  668 
  669         if (pccard_mfc(pf->sc))
  670                 pccard_mfc_adjust_iobase(pf, 0, 0, 0);
  671 
  672 #ifdef PCCARDDEBUG
  673         if (pccard_debug) {
  674                 STAILQ_FOREACH(tmp, &pf->sc->card.pf_head, pf_list) {
  675                         device_printf(tmp->sc->dev,
  676                             "function %d CCR at %d offset %x: "
  677                             "%x %x %x %x, %x %x %x %x, %x\n",
  678                             tmp->number, tmp->pf_ccr_window,
  679                             tmp->pf_ccr_offset,
  680                             pccard_ccr_read(tmp, 0x00),
  681                             pccard_ccr_read(tmp, 0x02),
  682                             pccard_ccr_read(tmp, 0x04),
  683                             pccard_ccr_read(tmp, 0x06),
  684                             pccard_ccr_read(tmp, 0x0A),
  685                             pccard_ccr_read(tmp, 0x0C),
  686                             pccard_ccr_read(tmp, 0x0E),
  687                             pccard_ccr_read(tmp, 0x10),
  688                             pccard_ccr_read(tmp, 0x12));
  689                 }
  690         }
  691 #endif
  692         pf->pf_flags |= PFF_ENABLED;
  693         return (0);
  694 
  695  bad:
  696         /*
  697          * Decrement the reference count, and power down the socket, if
  698          * necessary.
  699          */
  700         pf->sc->sc_enabled_count--;
  701         DEVPRINTF((dev, "bad --enabled_count = %d\n", pf->sc->sc_enabled_count));
  702 
  703         return (1);
  704 }
  705 
  706 /* Disable PCCARD function. */
  707 static void
  708 pccard_function_disable(struct pccard_function *pf)
  709 {
  710         struct pccard_function *tmp;
  711         device_t dev = pf->sc->dev;
  712 
  713         if (pf->cfe == NULL)
  714                 panic("pccard_function_disable: function not initialized");
  715 
  716         if ((pf->pf_flags & PFF_ENABLED) == 0) {
  717                 /*
  718                  * Don't do anything if we're already disabled.
  719                  */
  720                 return;
  721         }
  722 
  723         if (pf->intr_handler != NULL) {
  724                 struct pccard_ivar *devi = PCCARD_IVAR(pf->dev);
  725                 struct resource_list_entry *rle =
  726                     resource_list_find(&devi->resources, SYS_RES_IRQ, 0);
  727                 BUS_TEARDOWN_INTR(dev, pf->dev, rle->res,
  728                     pf->intr_handler_cookie);
  729         }
  730 
  731         /*
  732          * it's possible for different functions' CCRs to be in the same
  733          * underlying page.  Check for that.  Note we mark us as disabled
  734          * first to avoid matching ourself.
  735          */
  736 
  737         pf->pf_flags &= ~PFF_ENABLED;
  738         STAILQ_FOREACH(tmp, &pf->sc->card.pf_head, pf_list) {
  739                 if ((tmp->pf_flags & PFF_ENABLED) &&
  740                     (pf->ccr_base >= (tmp->ccr_base - tmp->pf_ccr_offset)) &&
  741                     ((pf->ccr_base + PCCARD_CCR_SIZE) <=
  742                     (tmp->ccr_base - tmp->pf_ccr_offset +
  743                     tmp->pf_ccr_realsize)))
  744                         break;
  745         }
  746 
  747         /* Not used by anyone else; unmap the CCR. */
  748         if (tmp == NULL) {
  749                 bus_release_resource(dev, SYS_RES_MEMORY, pf->ccr_rid,
  750                     pf->ccr_res);
  751                 pf->ccr_res = NULL;
  752         }
  753 
  754         /*
  755          * Decrement the reference count, and power down the socket, if
  756          * necessary.
  757          */
  758         pf->sc->sc_enabled_count--;
  759 }
  760 
  761 /*
  762  * simulate the old "probe" routine.  In the new world order, the driver
  763  * needs to grab devices while in the old they were assigned to the device by
  764  * the pccardd process.  These symbols are exported to the upper layers.
  765  */
  766 static int
  767 pccard_compat_do_probe(device_t bus, device_t dev)
  768 {
  769         return (CARD_COMPAT_MATCH(dev));
  770 }
  771 
  772 static int
  773 pccard_compat_do_attach(device_t bus, device_t dev)
  774 {
  775         int err;
  776 
  777         err = CARD_COMPAT_PROBE(dev);
  778         if (err <= 0)
  779                 err = CARD_COMPAT_ATTACH(dev);
  780         return (err);
  781 }
  782 
  783 #define PCCARD_NPORT    2
  784 #define PCCARD_NMEM     5
  785 #define PCCARD_NIRQ     1
  786 #define PCCARD_NDRQ     0
  787 
  788 static int
  789 pccard_add_children(device_t dev, int busno)
  790 {
  791         /* Call parent to scan for any current children */
  792         return (0);
  793 }
  794 
  795 static int
  796 pccard_probe(device_t dev)
  797 {
  798         device_set_desc(dev, "16-bit PCCard bus");
  799         return (pccard_add_children(dev, device_get_unit(dev)));
  800 }
  801 
  802 static int
  803 pccard_attach(device_t dev)
  804 {
  805         struct pccard_softc *sc = PCCARD_SOFTC(dev);
  806 
  807         sc->dev = dev;
  808         sc->sc_enabled_count = 0;
  809         return (bus_generic_attach(dev));
  810 }
  811 
  812 static int
  813 pccard_detach(device_t dev)
  814 {
  815         pccard_detach_card(dev);
  816         return 0;
  817 }
  818 
  819 static int
  820 pccard_suspend(device_t self)
  821 {
  822         pccard_detach_card(self);
  823         return (0);
  824 }
  825 
  826 static
  827 int
  828 pccard_resume(device_t self)
  829 {
  830         return (0);
  831 }
  832 
  833 static void
  834 pccard_print_resources(struct resource_list *rl, const char *name, int type,
  835     int count, const char *format)
  836 {
  837         struct resource_list_entry *rle;
  838         int printed;
  839         int i;
  840 
  841         printed = 0;
  842         for (i = 0; i < count; i++) {
  843                 rle = resource_list_find(rl, type, i);
  844                 if (rle != NULL) {
  845                         if (printed == 0)
  846                                 printf(" %s ", name);
  847                         else if (printed > 0)
  848                                 printf(",");
  849                         printed++;
  850                         printf(format, rle->start);
  851                         if (rle->count > 1) {
  852                                 printf("-");
  853                                 printf(format, rle->start + rle->count - 1);
  854                         }
  855                 } else if (i > 3) {
  856                         /* check the first few regardless */
  857                         break;
  858                 }
  859         }
  860 }
  861 
  862 static int
  863 pccard_print_child(device_t dev, device_t child)
  864 {
  865         struct pccard_ivar *devi = PCCARD_IVAR(child);
  866         struct resource_list *rl = &devi->resources;
  867         int retval = 0;
  868 
  869         retval += bus_print_child_header(dev, child);
  870         retval += printf(" at");
  871 
  872         if (devi != NULL) {
  873                 pccard_print_resources(rl, "port", SYS_RES_IOPORT,
  874                     PCCARD_NPORT, "%#lx");
  875                 pccard_print_resources(rl, "iomem", SYS_RES_MEMORY,
  876                     PCCARD_NMEM, "%#lx");
  877                 pccard_print_resources(rl, "irq", SYS_RES_IRQ, PCCARD_NIRQ,
  878                     "%ld");
  879                 pccard_print_resources(rl, "drq", SYS_RES_DRQ, PCCARD_NDRQ,
  880                     "%ld");
  881                 retval += printf(" function %d config %d", devi->fcn->number,
  882                     devi->fcn->cfe->number);
  883         }
  884 
  885         retval += bus_print_child_footer(dev, child);
  886 
  887         return (retval);
  888 }
  889 
  890 static int
  891 pccard_set_resource(device_t dev, device_t child, int type, int rid,
  892                  u_long start, u_long count)
  893 {
  894         struct pccard_ivar *devi = PCCARD_IVAR(child);
  895         struct resource_list *rl = &devi->resources;
  896 
  897         if (type != SYS_RES_IOPORT && type != SYS_RES_MEMORY
  898             && type != SYS_RES_IRQ && type != SYS_RES_DRQ)
  899                 return (EINVAL);
  900         if (rid < 0)
  901                 return (EINVAL);
  902         if (type == SYS_RES_IOPORT && rid >= PCCARD_NPORT)
  903                 return (EINVAL);
  904         if (type == SYS_RES_MEMORY && rid >= PCCARD_NMEM)
  905                 return (EINVAL);
  906         if (type == SYS_RES_IRQ && rid >= PCCARD_NIRQ)
  907                 return (EINVAL);
  908         if (type == SYS_RES_DRQ && rid >= PCCARD_NDRQ)
  909                 return (EINVAL);
  910 
  911         resource_list_add(rl, type, rid, start, start + count - 1, count);
  912         if (NULL != resource_list_alloc(rl, device_get_parent(dev), dev,
  913             type, &rid, start, start + count - 1, count, 0))
  914                 return 0;
  915         else
  916                 return ENOMEM;
  917 }
  918 
  919 static int
  920 pccard_get_resource(device_t dev, device_t child, int type, int rid,
  921     u_long *startp, u_long *countp)
  922 {
  923         struct pccard_ivar *devi = PCCARD_IVAR(child);
  924         struct resource_list *rl = &devi->resources;
  925         struct resource_list_entry *rle;
  926 
  927         rle = resource_list_find(rl, type, rid);
  928         if (rle == NULL)
  929                 return (ENOENT);
  930 
  931         if (startp != NULL)
  932                 *startp = rle->start;
  933         if (countp != NULL)
  934                 *countp = rle->count;
  935 
  936         return (0);
  937 }
  938 
  939 static void
  940 pccard_delete_resource(device_t dev, device_t child, int type, int rid)
  941 {
  942         struct pccard_ivar *devi = PCCARD_IVAR(child);
  943         struct resource_list *rl = &devi->resources;
  944         resource_list_delete(rl, type, rid);
  945 }
  946 
  947 static int
  948 pccard_set_res_flags(device_t dev, device_t child, int type, int rid,
  949     u_int32_t flags)
  950 {
  951         return (CARD_SET_RES_FLAGS(device_get_parent(dev), child, type,
  952             rid, flags));
  953 }
  954 
  955 static int
  956 pccard_set_memory_offset(device_t dev, device_t child, int rid,
  957     u_int32_t offset, u_int32_t *deltap)
  958 
  959 {
  960         return (CARD_SET_MEMORY_OFFSET(device_get_parent(dev), child, rid,
  961             offset, deltap));
  962 }
  963 
  964 static void
  965 pccard_probe_nomatch(device_t bus, device_t child)
  966 {
  967         struct pccard_ivar *devi = PCCARD_IVAR(child);
  968         struct pccard_function *func = devi->fcn;
  969         struct pccard_softc *sc = PCCARD_SOFTC(bus);
  970 
  971         device_printf(bus, "<unknown card>");
  972         printf(" (manufacturer=0x%04x, product=0x%04x) at function %d\n",
  973           sc->card.manufacturer, sc->card.product, func->number);
  974         device_printf(bus, "   CIS info: %s, %s, %s\n", sc->card.cis1_info[0],
  975           sc->card.cis1_info[1], sc->card.cis1_info[2]);
  976         return;
  977 }
  978 
  979 static int
  980 pccard_child_location_str(device_t bus, device_t child, char *buf,
  981     size_t buflen)
  982 {
  983         struct pccard_ivar *devi = PCCARD_IVAR(child);
  984         struct pccard_function *func = devi->fcn;
  985 
  986         snprintf(buf, buflen, "function=%d", func->number);
  987         return (0);
  988 }
  989 
  990 static int
  991 pccard_child_pnpinfo_str(device_t bus, device_t child, char *buf,
  992     size_t buflen)
  993 {
  994         struct pccard_ivar *devi = PCCARD_IVAR(child);
  995         struct pccard_function *func = devi->fcn;
  996         struct pccard_softc *sc = PCCARD_SOFTC(bus);
  997 
  998         snprintf(buf, buflen, "manufacturer=0x%04x product=0x%04x "
  999             "cisvendor=\"%s\" cisproduct=\"%s\" function_type=%d",
 1000             sc->card.manufacturer, sc->card.product, sc->card.cis1_info[0],
 1001             sc->card.cis1_info[1], func->function);
 1002         return (0);
 1003 }
 1004 
 1005 static int
 1006 pccard_read_ivar(device_t bus, device_t child, int which, u_char *result)
 1007 {
 1008         struct pccard_ivar *devi = PCCARD_IVAR(child);
 1009         struct pccard_function *func = devi->fcn;
 1010         struct pccard_softc *sc = PCCARD_SOFTC(bus);
 1011 
 1012         switch (which) {
 1013         default:
 1014         case PCCARD_IVAR_ETHADDR:
 1015                 bcopy(func->pf_funce_lan_nid, result, ETHER_ADDR_LEN);
 1016                 break;
 1017         case PCCARD_IVAR_VENDOR:
 1018                 *(u_int32_t *) result = sc->card.manufacturer;
 1019                 break;
 1020         case PCCARD_IVAR_PRODUCT:
 1021                 *(u_int32_t *) result = sc->card.product;
 1022                 break;
 1023         case PCCARD_IVAR_PRODEXT:
 1024                 *(u_int16_t *) result = sc->card.prodext;
 1025                 break;
 1026         case PCCARD_IVAR_FUNCTION:
 1027                 *(u_int32_t *) result = func->function;
 1028                 break;
 1029         case PCCARD_IVAR_FUNCTION_NUMBER:
 1030                 if (!func) {
 1031                         device_printf(bus, "No function number, bug!\n");
 1032                         return (ENOENT);
 1033                 }
 1034                 *(u_int32_t *) result = func->number;
 1035                 break;
 1036         case PCCARD_IVAR_VENDOR_STR:
 1037                 *(char **) result = sc->card.cis1_info[0];
 1038                 break;
 1039         case PCCARD_IVAR_PRODUCT_STR:
 1040                 *(char **) result = sc->card.cis1_info[1];
 1041                 break;
 1042         case PCCARD_IVAR_CIS3_STR:
 1043                 *(char **) result = sc->card.cis1_info[2];
 1044                 break;
 1045         case PCCARD_IVAR_CIS4_STR:
 1046                 *(char **) result = sc->card.cis1_info[3];
 1047                 break;
 1048         }
 1049         return (0);
 1050 }
 1051 
 1052 static void
 1053 pccard_driver_added(device_t dev, driver_t *driver)
 1054 {
 1055         struct pccard_softc *sc = PCCARD_SOFTC(dev);
 1056         struct pccard_function *pf;
 1057         device_t child;
 1058 
 1059         STAILQ_FOREACH(pf, &sc->card.pf_head, pf_list) {
 1060                 if (STAILQ_EMPTY(&pf->cfe_head))
 1061                         continue;
 1062                 child = pf->dev;
 1063                 if (device_get_state(child) != DS_NOTPRESENT)
 1064                         continue;
 1065                 if (pccard_function_enable(pf) == 0 &&
 1066                     device_probe_and_attach(child) == 0) {
 1067                         DEVPRINTF((sc->dev, "function %d CCR at %d "
 1068                             "offset %x: %x %x %x %x, %x %x %x %x, %x\n",
 1069                             pf->number, pf->pf_ccr_window, pf->pf_ccr_offset,
 1070                             pccard_ccr_read(pf, 0x00),
 1071                         pccard_ccr_read(pf, 0x02), pccard_ccr_read(pf, 0x04),
 1072                         pccard_ccr_read(pf, 0x06), pccard_ccr_read(pf, 0x0A),
 1073                         pccard_ccr_read(pf, 0x0C), pccard_ccr_read(pf, 0x0E),
 1074                         pccard_ccr_read(pf, 0x10), pccard_ccr_read(pf, 0x12)));
 1075                 } else {
 1076                         if (pf->cfe != NULL)
 1077                                 pccard_function_disable(pf);
 1078                 }
 1079         }
 1080         return;
 1081 }
 1082 
 1083 static struct resource *
 1084 pccard_alloc_resource(device_t dev, device_t child, int type, int *rid,
 1085     u_long start, u_long end, u_long count, u_int flags)
 1086 {
 1087         struct pccard_ivar *dinfo;
 1088         struct resource_list_entry *rle = 0;
 1089         int passthrough = (device_get_parent(child) != dev);
 1090         int isdefault = (start == 0 && end == ~0UL && count == 1);
 1091         struct resource *r = NULL;
 1092 
 1093         /* XXX I'm no longer sure this is right */
 1094         if (passthrough) {
 1095                 return (BUS_ALLOC_RESOURCE(device_get_parent(dev), child,
 1096                     type, rid, start, end, count, flags));
 1097         }
 1098 
 1099         dinfo = device_get_ivars(child);
 1100         rle = resource_list_find(&dinfo->resources, type, *rid);
 1101 
 1102         if (rle == NULL && isdefault)
 1103                 return (NULL);  /* no resource of that type/rid */
 1104         if (rle == NULL || rle->res == NULL) {
 1105                 /* Do we want this device to own it? */
 1106                 /* XXX I think so, but that might be lame XXX */
 1107                 r = bus_alloc_resource(dev, type, rid, start, end,
 1108                   count, flags /* XXX aligment? */);
 1109                 if (r == NULL)
 1110                     goto bad;
 1111                 resource_list_add(&dinfo->resources, type, *rid,
 1112                   rman_get_start(r), rman_get_end(r), count);
 1113                 rle = resource_list_find(&dinfo->resources, type, *rid);
 1114                 if (!rle)
 1115                     goto bad;
 1116                 rle->res = r;
 1117         }
 1118         /*
 1119          * XXX the following looks wrong, in theory, but likely it is
 1120          * XXX needed because of how the CIS code allocates resources
 1121          * XXX for this device.
 1122          */
 1123         if (rman_get_device(rle->res) != dev)
 1124                 return (NULL);
 1125         bus_release_resource(dev, type, *rid, rle->res);
 1126         rle->res = NULL;
 1127         switch(type) {
 1128         case SYS_RES_IOPORT:
 1129         case SYS_RES_MEMORY:
 1130                 if (!(flags & RF_ALIGNMENT_MASK))
 1131                         flags |= rman_make_alignment_flags(rle->count);
 1132                 break;
 1133         case SYS_RES_IRQ:
 1134                 flags |= RF_SHAREABLE;
 1135                 break;
 1136         }
 1137         rle->res = resource_list_alloc(&dinfo->resources, dev, child,
 1138             type, rid, rle->start, rle->end, rle->count, flags);
 1139         return (rle->res);
 1140 bad:;
 1141         device_printf(dev, "WARNING: Resource not reserved by pccard\n");
 1142         return (NULL);
 1143 }
 1144 
 1145 static int
 1146 pccard_release_resource(device_t dev, device_t child, int type, int rid,
 1147     struct resource *r)
 1148 {
 1149         struct pccard_ivar *dinfo;
 1150         int passthrough = (device_get_parent(child) != dev);
 1151         struct resource_list_entry *rle = 0;
 1152         int ret;
 1153         int flags;
 1154 
 1155         if (passthrough)
 1156                 return BUS_RELEASE_RESOURCE(device_get_parent(dev), child,
 1157                     type, rid, r);
 1158 
 1159         dinfo = device_get_ivars(child);
 1160 
 1161         rle = resource_list_find(&dinfo->resources, type, rid);
 1162 
 1163         if (!rle) {
 1164                 device_printf(dev, "Allocated resource not found, "
 1165                     "%d %x %lx %lx\n",
 1166                     type, rid, rman_get_start(r), rman_get_size(r));
 1167                 return ENOENT;
 1168         }
 1169         if (!rle->res) {
 1170                 device_printf(dev, "Allocated resource not recorded\n");
 1171                 return ENOENT;
 1172         }
 1173 
 1174         ret = BUS_RELEASE_RESOURCE(device_get_parent(dev), child,
 1175             type, rid, r);
 1176         switch(type) {
 1177         case SYS_RES_IOPORT:
 1178         case SYS_RES_MEMORY:
 1179                 flags = rman_make_alignment_flags(rle->count);
 1180                 break;
 1181         case SYS_RES_IRQ:
 1182                 flags = RF_SHAREABLE;
 1183                 break;
 1184         default:
 1185                 flags = 0;
 1186         }
 1187         rle->res = bus_alloc_resource(dev, type, &rid,
 1188             rle->start, rle->end, rle->count, flags);
 1189         if (rle->res == NULL)
 1190                 device_printf(dev, "release_resource: "
 1191                     "unable to reaquire resource\n");
 1192         return ret;
 1193 }
 1194 
 1195 static void
 1196 pccard_child_detached(device_t parent, device_t dev)
 1197 {
 1198         struct pccard_ivar *ivar = PCCARD_IVAR(dev);
 1199         struct pccard_function *pf = ivar->fcn;
 1200 
 1201         pccard_function_disable(pf);
 1202 }
 1203 
 1204 static void
 1205 pccard_intr(void *arg)
 1206 {
 1207         struct pccard_function *pf = (struct pccard_function*) arg;
 1208         int reg;
 1209         int doisr = 1;
 1210 
 1211         /*
 1212          * MFC cards know if they interrupted, so we have to ack the
 1213          * interrupt and call the ISR.  Non-MFC cards don't have these
 1214          * bits, so they always get called.  Many non-MFC cards have
 1215          * this bit set always upon read, but some do not.
 1216          *
 1217          * We always ack the interrupt, even if there's no ISR
 1218          * for the card.  This is done on the theory that acking
 1219          * the interrupt will pacify the card enough to keep an
 1220          * interrupt storm from happening.  Of course this won't
 1221          * help in the non-MFC case.
 1222          *
 1223          * This has no impact for MPSAFEness of the client drivers.
 1224          * We register this with whatever flags the intr_handler
 1225          * was registered with.  All these functions are MPSAFE.
 1226          */
 1227         if (pccard_mfc(pf->sc)) {
 1228                 reg = pccard_ccr_read(pf, PCCARD_CCR_STATUS);
 1229                 if (reg & PCCARD_CCR_STATUS_INTR)
 1230                         pccard_ccr_write(pf, PCCARD_CCR_STATUS,
 1231                             reg & ~PCCARD_CCR_STATUS_INTR);
 1232                 else
 1233                         doisr = 0;
 1234         }
 1235         if (pf->intr_handler != NULL && doisr)
 1236                 pf->intr_handler(pf->intr_handler_arg);
 1237 }
 1238 
 1239 static int
 1240 pccard_setup_intr(device_t dev, device_t child, struct resource *irq,
 1241     int flags, driver_intr_t *intr, void *arg, void **cookiep)
 1242 {
 1243         struct pccard_softc *sc = PCCARD_SOFTC(dev);
 1244         struct pccard_ivar *ivar = PCCARD_IVAR(child);
 1245         struct pccard_function *func = ivar->fcn;
 1246         int err;
 1247 
 1248         if (func->intr_handler != NULL)
 1249                 panic("Only one interrupt handler per function allowed");
 1250         err = bus_generic_setup_intr(dev, child, irq, flags, pccard_intr,
 1251             func, cookiep);
 1252         if (err != 0)
 1253                 return (err);
 1254         func->intr_handler = intr;
 1255         func->intr_handler_arg = arg;
 1256         func->intr_handler_cookie = *cookiep;
 1257         if (pccard_mfc(sc)) {
 1258                 pccard_ccr_write(func, PCCARD_CCR_OPTION,
 1259                     pccard_ccr_read(func, PCCARD_CCR_OPTION) |
 1260                     PCCARD_CCR_OPTION_IREQ_ENABLE);
 1261         }
 1262         return (0);
 1263 }
 1264 
 1265 static int
 1266 pccard_teardown_intr(device_t dev, device_t child, struct resource *r,
 1267     void *cookie)
 1268 {
 1269         struct pccard_softc *sc = PCCARD_SOFTC(dev);
 1270         struct pccard_ivar *ivar = PCCARD_IVAR(child);
 1271         struct pccard_function *func = ivar->fcn;
 1272         int ret;
 1273 
 1274         if (pccard_mfc(sc)) {
 1275                 pccard_ccr_write(func, PCCARD_CCR_OPTION,
 1276                     pccard_ccr_read(func, PCCARD_CCR_OPTION) &
 1277                     ~PCCARD_CCR_OPTION_IREQ_ENABLE);
 1278         }
 1279         ret = bus_generic_teardown_intr(dev, child, r, cookie);
 1280         if (ret == 0) {
 1281                 func->intr_handler = NULL;
 1282                 func->intr_handler_arg = NULL;
 1283                 func->intr_handler_cookie = NULL;
 1284         }
 1285 
 1286         return (ret);
 1287 }
 1288 
 1289 static int
 1290 pccard_activate_resource(device_t brdev, device_t child, int type, int rid,
 1291     struct resource *r)
 1292 {
 1293         struct pccard_ivar *ivar = PCCARD_IVAR(child);
 1294         struct pccard_function *pf = ivar->fcn;
 1295 
 1296         switch(type) {
 1297         case SYS_RES_IOPORT:
 1298                 /*
 1299                  * We need to adjust IOBASE[01] and IOSIZE if we're an MFC
 1300                  * card.
 1301                  */
 1302                 if (pccard_mfc(pf->sc))
 1303                         pccard_mfc_adjust_iobase(pf, rman_get_start(r), 0,
 1304                             rman_get_size(r));
 1305                 break;
 1306         default:
 1307                 break;
 1308         }
 1309         return (bus_generic_activate_resource(brdev, child, type, rid, r));
 1310 }
 1311 
 1312 static int
 1313 pccard_deactivate_resource(device_t brdev, device_t child, int type,
 1314     int rid, struct resource *r)
 1315 {
 1316         /* XXX undo pccard_activate_resource? XXX */
 1317         return (bus_generic_deactivate_resource(brdev, child, type, rid, r));
 1318 }
 1319 
 1320 static device_method_t pccard_methods[] = {
 1321         /* Device interface */
 1322         DEVMETHOD(device_probe,         pccard_probe),
 1323         DEVMETHOD(device_attach,        pccard_attach),
 1324         DEVMETHOD(device_detach,        pccard_detach),
 1325         DEVMETHOD(device_shutdown,      bus_generic_shutdown),
 1326         DEVMETHOD(device_suspend,       pccard_suspend),
 1327         DEVMETHOD(device_resume,        pccard_resume),
 1328 
 1329         /* Bus interface */
 1330         DEVMETHOD(bus_print_child,      pccard_print_child),
 1331         DEVMETHOD(bus_driver_added,     pccard_driver_added),
 1332         DEVMETHOD(bus_child_detached,   pccard_child_detached),
 1333         DEVMETHOD(bus_alloc_resource,   pccard_alloc_resource),
 1334         DEVMETHOD(bus_release_resource, pccard_release_resource),
 1335         DEVMETHOD(bus_activate_resource, pccard_activate_resource),
 1336         DEVMETHOD(bus_deactivate_resource, pccard_deactivate_resource),
 1337         DEVMETHOD(bus_setup_intr,       pccard_setup_intr),
 1338         DEVMETHOD(bus_teardown_intr,    pccard_teardown_intr),
 1339         DEVMETHOD(bus_set_resource,     pccard_set_resource),
 1340         DEVMETHOD(bus_get_resource,     pccard_get_resource),
 1341         DEVMETHOD(bus_delete_resource,  pccard_delete_resource),
 1342         DEVMETHOD(bus_probe_nomatch,    pccard_probe_nomatch),
 1343         DEVMETHOD(bus_read_ivar,        pccard_read_ivar),
 1344         DEVMETHOD(bus_child_pnpinfo_str, pccard_child_pnpinfo_str),
 1345         DEVMETHOD(bus_child_location_str, pccard_child_location_str),
 1346 
 1347         /* Card Interface */
 1348         DEVMETHOD(card_set_res_flags,   pccard_set_res_flags),
 1349         DEVMETHOD(card_set_memory_offset, pccard_set_memory_offset),
 1350         DEVMETHOD(card_attach_card,     pccard_attach_card),
 1351         DEVMETHOD(card_detach_card,     pccard_detach_card),
 1352         DEVMETHOD(card_compat_do_probe, pccard_compat_do_probe),
 1353         DEVMETHOD(card_compat_do_attach, pccard_compat_do_attach),
 1354         DEVMETHOD(card_do_product_lookup, pccard_do_product_lookup),
 1355 
 1356         { 0, 0 }
 1357 };
 1358 
 1359 static driver_t pccard_driver = {
 1360         "pccard",
 1361         pccard_methods,
 1362         sizeof(struct pccard_softc)
 1363 };
 1364 
 1365 devclass_t      pccard_devclass;
 1366 
 1367 /* Maybe we need to have a slot device? */
 1368 DRIVER_MODULE(pccard, pcic, pccard_driver, pccard_devclass, 0, 0);
 1369 DRIVER_MODULE(pccard, cbb, pccard_driver, pccard_devclass, 0, 0);
 1370 MODULE_VERSION(pccard, 1);

Cache object: 3af1b078f82404e174c56c6dcc2008c2


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