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/pcmcia/pcmcia.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.36 2003/10/22 07:46:48 briggs 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 __KERNEL_RCSID(0, "$NetBSD: pcmcia.c,v 1.36 2003/10/22 07:46:48 briggs Exp $");
   34 
   35 #include "opt_pcmciaverbose.h"
   36 
   37 #include <sys/param.h>
   38 #include <sys/systm.h>
   39 #include <sys/device.h>
   40 
   41 #include <dev/pcmcia/pcmciareg.h>
   42 #include <dev/pcmcia/pcmciachip.h>
   43 #include <dev/pcmcia/pcmciavar.h>
   44 #ifdef IT8368E_LEGACY_MODE /* XXX -uch */
   45 #include <arch/hpcmips/dev/it8368var.h>
   46 #endif
   47 
   48 #include "locators.h"
   49 
   50 #ifdef PCMCIADEBUG
   51 int     pcmcia_debug = 0;
   52 #define DPRINTF(arg) if (pcmcia_debug) printf arg
   53 int     pcmciaintr_debug = 0;
   54 /* this is done this way to avoid doing lots of conditionals
   55    at interrupt level.  */
   56 #define PCMCIA_CARD_INTR (pcmciaintr_debug?pcmcia_card_intrdebug:pcmcia_card_intr)
   57 #else
   58 #define DPRINTF(arg)
   59 #define PCMCIA_CARD_INTR (pcmcia_card_intr)
   60 #endif
   61 
   62 #ifdef PCMCIAVERBOSE
   63 int     pcmcia_verbose = 1;
   64 #else
   65 int     pcmcia_verbose = 0;
   66 #endif
   67 
   68 int     pcmcia_match __P((struct device *, struct cfdata *, void *));
   69 int     pcmcia_submatch __P((struct device *, struct cfdata *, void *));
   70 void    pcmcia_attach __P((struct device *, struct device *, void *));
   71 int     pcmcia_print __P((void *, const char *));
   72 
   73 static inline void pcmcia_socket_enable __P((pcmcia_chipset_tag_t,
   74                                              pcmcia_chipset_handle_t *));
   75 static inline void pcmcia_socket_disable __P((pcmcia_chipset_tag_t,
   76                                               pcmcia_chipset_handle_t *));
   77 
   78 int pcmcia_card_intr __P((void *));
   79 #ifdef PCMCIADEBUG
   80 int pcmcia_card_intrdebug __P((void *));
   81 #endif
   82 
   83 CFATTACH_DECL(pcmcia, sizeof(struct pcmcia_softc),
   84     pcmcia_match, pcmcia_attach, NULL, NULL);
   85 
   86 int
   87 pcmcia_ccr_read(pf, ccr)
   88         struct pcmcia_function *pf;
   89         int ccr;
   90 {
   91 
   92         return (bus_space_read_1(pf->pf_ccrt, pf->pf_ccrh,
   93             pf->pf_ccr_offset + ccr));
   94 }
   95 
   96 void
   97 pcmcia_ccr_write(pf, ccr, val)
   98         struct pcmcia_function *pf;
   99         int ccr;
  100         int val;
  101 {
  102 
  103         if ((pf->ccr_mask) & (1 << (ccr / 2))) {
  104                 bus_space_write_1(pf->pf_ccrt, pf->pf_ccrh,
  105                     pf->pf_ccr_offset + ccr, val);
  106         }
  107 }
  108 
  109 int
  110 pcmcia_match(parent, match, aux)
  111         struct device *parent;
  112         struct cfdata *match;
  113         void *aux;
  114 {
  115         struct pcmciabus_attach_args *paa = aux;
  116 
  117         if (strcmp(paa->paa_busname, match->cf_name)) {
  118             return 0;
  119         }
  120         /* if the autoconfiguration got this far, there's a socket here */
  121         return (1);
  122 }
  123 
  124 void
  125 pcmcia_attach(parent, self, aux)
  126         struct device *parent, *self;
  127         void *aux;
  128 {
  129         struct pcmciabus_attach_args *paa = aux;
  130         struct pcmcia_softc *sc = (struct pcmcia_softc *) self;
  131 
  132         printf("\n");
  133 
  134         sc->pct = paa->pct;
  135         sc->pch = paa->pch;
  136         sc->iobase = paa->iobase;
  137         sc->iosize = paa->iosize;
  138 
  139         sc->ih = NULL;
  140 }
  141 
  142 int
  143 pcmcia_card_attach(dev)
  144         struct device *dev;
  145 {
  146         struct pcmcia_softc *sc = (struct pcmcia_softc *) dev;
  147         struct pcmcia_function *pf;
  148         struct pcmcia_attach_args paa;
  149         int attached;
  150 
  151         /*
  152          * this is here so that when socket_enable calls gettype, trt happens
  153          */
  154         SIMPLEQ_FIRST(&sc->card.pf_head) = NULL;
  155 
  156         pcmcia_chip_socket_enable(sc->pct, sc->pch);
  157 
  158         pcmcia_read_cis(sc);
  159 
  160         pcmcia_chip_socket_disable(sc->pct, sc->pch);
  161 
  162         pcmcia_check_cis_quirks(sc);
  163 
  164         /*
  165          * bail now if the card has no functions, or if there was an error in
  166          * the cis.
  167          */
  168 
  169         if (sc->card.error)
  170                 return (1);
  171         if (SIMPLEQ_EMPTY(&sc->card.pf_head))
  172                 return (1);
  173 
  174         if (pcmcia_verbose)
  175                 pcmcia_print_cis(sc);
  176 
  177         attached = 0;
  178 
  179         SIMPLEQ_FOREACH(pf, &sc->card.pf_head, pf_list) {
  180                 if (SIMPLEQ_EMPTY(&pf->cfe_head))
  181                         continue;
  182 
  183 #ifdef DIAGNOSTIC
  184                 if (pf->child != NULL) {
  185                         printf("%s: %s still attached to function %d!\n",
  186                             sc->dev.dv_xname, pf->child->dv_xname,
  187                             pf->number);
  188                         panic("pcmcia_card_attach");
  189                 }
  190 #endif
  191                 pf->sc = sc;
  192                 pf->child = NULL;
  193                 pf->cfe = NULL;
  194                 pf->ih_fct = NULL;
  195                 pf->ih_arg = NULL;
  196         }
  197 
  198         SIMPLEQ_FOREACH(pf, &sc->card.pf_head, pf_list) {
  199                 if (SIMPLEQ_EMPTY(&pf->cfe_head))
  200                         continue;
  201 
  202                 paa.manufacturer = sc->card.manufacturer;
  203                 paa.product = sc->card.product;
  204                 paa.card = &sc->card;
  205                 paa.pf = pf;
  206 
  207                 if ((pf->child = config_found_sm(&sc->dev, &paa, pcmcia_print,
  208                     pcmcia_submatch)) != NULL)
  209                         attached++;
  210         }
  211 
  212         return (attached ? 0 : 1);
  213 }
  214 
  215 void
  216 pcmcia_card_detach(dev, flags)
  217         struct device *dev;
  218         int flags;              /* DETACH_* flags */
  219 {
  220         struct pcmcia_softc *sc = (struct pcmcia_softc *) dev;
  221         struct pcmcia_function *pf;
  222         int error;
  223 
  224         /*
  225          * We are running on either the PCMCIA socket's event thread
  226          * or in user context detaching a device by user request.
  227          */
  228         SIMPLEQ_FOREACH(pf, &sc->card.pf_head, pf_list) {
  229                 if (SIMPLEQ_EMPTY(&pf->cfe_head))
  230                         continue;
  231                 if (pf->child == NULL)
  232                         continue;
  233                 DPRINTF(("%s: detaching %s (function %d)\n",
  234                     sc->dev.dv_xname, pf->child->dv_xname, pf->number));
  235                 if ((error = config_detach(pf->child, flags)) != 0) {
  236                         printf("%s: error %d detaching %s (function %d)\n",
  237                             sc->dev.dv_xname, error, pf->child->dv_xname,
  238                             pf->number);
  239                 } else
  240                         pf->child = NULL;
  241         }
  242 }
  243 
  244 void
  245 pcmcia_card_deactivate(dev)
  246         struct device *dev;
  247 {
  248         struct pcmcia_softc *sc = (struct pcmcia_softc *) dev;
  249         struct pcmcia_function *pf;
  250 
  251         /*
  252          * We're in the chip's card removal interrupt handler.
  253          * Deactivate the child driver.  The PCMCIA socket's
  254          * event thread will run later to finish the detach.
  255          */
  256         SIMPLEQ_FOREACH(pf, &sc->card.pf_head, pf_list) {
  257                 if (SIMPLEQ_EMPTY(&pf->cfe_head))
  258                         continue;
  259                 if (pf->child == NULL)
  260                         continue;
  261                 DPRINTF(("%s: deactivating %s (function %d)\n",
  262                     sc->dev.dv_xname, pf->child->dv_xname, pf->number));
  263                 config_deactivate(pf->child);
  264         }
  265 }
  266 
  267 int
  268 pcmcia_submatch(parent, cf, aux)
  269         struct device *parent;
  270         struct cfdata *cf;
  271         void *aux;
  272 {
  273         struct pcmcia_attach_args *paa = aux;
  274 
  275         if (cf->cf_loc[PCMCIACF_FUNCTION] != PCMCIACF_FUNCTION_DEFAULT &&
  276             cf->cf_loc[PCMCIACF_FUNCTION] != paa->pf->number)
  277                 return (0);
  278 
  279         return (config_match(parent, cf, aux));
  280 }
  281 
  282 int
  283 pcmcia_print(arg, pnp)
  284         void *arg;
  285         const char *pnp;
  286 {
  287         struct pcmcia_attach_args *pa = arg;
  288         struct pcmcia_softc *sc = pa->pf->sc;
  289         struct pcmcia_card *card = &sc->card;
  290         char devinfo[256];
  291 
  292         if (pnp) {
  293                 pcmcia_devinfo(card, 1, devinfo, sizeof devinfo);
  294                 aprint_normal("%s at %s, ", devinfo, pnp);
  295         }
  296         aprint_normal(" function %d", pa->pf->number);
  297 
  298         return (UNCONF);
  299 }
  300 
  301 void
  302 pcmcia_devinfo(card, showhex, cp, cplen)
  303         struct pcmcia_card *card;
  304         int showhex;
  305         char *cp;
  306         int cplen;
  307 {
  308         int i, n;
  309 
  310         for (i = 0; i < 4 && card->cis1_info[i] != NULL && cplen > 0; i++) {
  311                 n = snprintf(cp, cplen, "%s%s", (i && i != 3) ? ", " : "",
  312                         card->cis1_info[i]);
  313                 cp += n;
  314                 cplen -= n;
  315         }
  316         if (showhex && cplen > 0)
  317                 snprintf(cp, cplen, "%s(manufacturer 0x%04x, product 0x%04x)",
  318                     i ? " " : "", card->manufacturer, card->product);
  319 }
  320 
  321 const struct pcmcia_product *
  322 pcmcia_product_lookup(pa, tab, ent_size, matchfn)
  323         struct pcmcia_attach_args *pa;
  324         const struct pcmcia_product *tab;
  325         size_t ent_size;
  326         pcmcia_product_match_fn matchfn;
  327 {
  328         const struct pcmcia_product *ent;
  329         int matches;
  330 
  331 #ifdef DIAGNOSTIC
  332         if (sizeof *ent > ent_size)
  333                 panic("pcmcia_product_lookup: bogus ent_size %ld", 
  334                       (long) ent_size);
  335 #endif
  336 
  337         for (ent = tab;
  338             ent->pp_name != NULL;
  339             ent = (const struct pcmcia_product *)
  340               ((const char *)ent + ent_size)) {
  341 
  342                 /* see if it matches vendor/product/function */
  343                 matches = (pa->manufacturer == ent->pp_vendor) &&
  344                     (pa->product == ent->pp_product) &&
  345                     (pa->pf->number == ent->pp_expfunc);
  346 
  347                 /* if a separate match function is given, let it override */
  348                 if (matchfn != NULL)
  349                         matches = (*matchfn)(pa, ent, matches);
  350 
  351                 if (matches)
  352                         return (ent);
  353         }
  354         return (NULL);
  355 }
  356 
  357 int 
  358 pcmcia_card_gettype(dev)
  359         struct device  *dev;
  360 {
  361         struct pcmcia_softc *sc = (struct pcmcia_softc *)dev;
  362         struct pcmcia_function *pf;
  363 
  364         /*
  365          * set the iftype to memory if this card has no functions (not yet
  366          * probed), or only one function, and that is not initialized yet or
  367          * that is memory.
  368          */
  369         pf = SIMPLEQ_FIRST(&sc->card.pf_head);
  370         if (pf == NULL ||
  371             (SIMPLEQ_NEXT(pf, pf_list) == NULL &&
  372             (pf->cfe == NULL || pf->cfe->iftype == PCMCIA_IFTYPE_MEMORY)))
  373                 return (PCMCIA_IFTYPE_MEMORY);
  374         else
  375                 return (PCMCIA_IFTYPE_IO);
  376 }
  377 
  378 /*
  379  * Initialize a PCMCIA function.  May be called as long as the function is
  380  * disabled.
  381  */
  382 void
  383 pcmcia_function_init(pf, cfe)
  384         struct pcmcia_function *pf;
  385         struct pcmcia_config_entry *cfe;
  386 {
  387         if (pf->pf_flags & PFF_ENABLED)
  388                 panic("pcmcia_function_init: function is enabled");
  389 
  390         /* Remember which configuration entry we are using. */
  391         pf->cfe = cfe;
  392 }
  393 
  394 static inline void pcmcia_socket_enable(pct, pch)
  395      pcmcia_chipset_tag_t pct;
  396      pcmcia_chipset_handle_t *pch;
  397 {
  398         pcmcia_chip_socket_enable(pct, pch);
  399 }
  400 
  401 static inline void pcmcia_socket_disable(pct, pch)
  402      pcmcia_chipset_tag_t pct;
  403      pcmcia_chipset_handle_t *pch;
  404 {
  405         pcmcia_chip_socket_disable(pct, pch);
  406 }
  407 
  408 /* Enable a PCMCIA function */
  409 int
  410 pcmcia_function_enable(pf)
  411         struct pcmcia_function *pf;
  412 {
  413         struct pcmcia_function *tmp;
  414         int reg;
  415 
  416         if (pf->cfe == NULL)
  417                 panic("pcmcia_function_enable: function not initialized");
  418 
  419         /*
  420          * Increase the reference count on the socket, enabling power, if
  421          * necessary.
  422          */
  423         if (pf->sc->sc_enabled_count++ == 0)
  424                 pcmcia_chip_socket_enable(pf->sc->pct, pf->sc->pch);
  425         DPRINTF(("%s: ++enabled_count = %d\n", pf->sc->dev.dv_xname,
  426                  pf->sc->sc_enabled_count));
  427 
  428         if (pf->pf_flags & PFF_ENABLED) {
  429                 /*
  430                  * Don't do anything if we're already enabled.
  431                  */
  432                 return (0);
  433         }
  434 
  435         /*
  436          * it's possible for different functions' CCRs to be in the same
  437          * underlying page.  Check for that.
  438          */
  439 
  440         SIMPLEQ_FOREACH(tmp, &pf->sc->card.pf_head, pf_list) {
  441                 if ((tmp->pf_flags & PFF_ENABLED) &&
  442                     (pf->ccr_base >= (tmp->ccr_base - tmp->pf_ccr_offset)) &&
  443                     ((pf->ccr_base + PCMCIA_CCR_SIZE) <=
  444                      (tmp->ccr_base - tmp->pf_ccr_offset +
  445                       tmp->pf_ccr_realsize))) {
  446                         pf->pf_ccrt = tmp->pf_ccrt;
  447                         pf->pf_ccrh = tmp->pf_ccrh;
  448                         pf->pf_ccr_realsize = tmp->pf_ccr_realsize;
  449 
  450                         /*
  451                          * pf->pf_ccr_offset = (tmp->pf_ccr_offset -
  452                          * tmp->ccr_base) + pf->ccr_base;
  453                          */
  454                         pf->pf_ccr_offset =
  455                             (tmp->pf_ccr_offset + pf->ccr_base) -
  456                             tmp->ccr_base;
  457                         pf->pf_ccr_window = tmp->pf_ccr_window;
  458                         break;
  459                 }
  460         }
  461 
  462         if (tmp == NULL) {
  463                 if (pcmcia_mem_alloc(pf, PCMCIA_CCR_SIZE, &pf->pf_pcmh))
  464                         goto bad;
  465 
  466                 if (pcmcia_mem_map(pf, PCMCIA_MEM_ATTR, pf->ccr_base,
  467                     PCMCIA_CCR_SIZE, &pf->pf_pcmh, &pf->pf_ccr_offset,
  468                     &pf->pf_ccr_window)) {
  469                         pcmcia_mem_free(pf, &pf->pf_pcmh);
  470                         goto bad;
  471                 }
  472         }
  473 
  474         reg = (pf->cfe->number & PCMCIA_CCR_OPTION_CFINDEX);
  475         reg |= PCMCIA_CCR_OPTION_LEVIREQ;
  476         if (pcmcia_mfc(pf->sc)) {
  477                 reg |= (PCMCIA_CCR_OPTION_FUNC_ENABLE |
  478                         PCMCIA_CCR_OPTION_ADDR_DECODE);
  479                 if (pf->ih_fct)
  480                         reg |= PCMCIA_CCR_OPTION_IREQ_ENABLE;
  481 
  482         }
  483         pcmcia_ccr_write(pf, PCMCIA_CCR_OPTION, reg);
  484 
  485         reg = 0;
  486 
  487         if ((pf->cfe->flags & PCMCIA_CFE_IO16) == 0)
  488                 reg |= PCMCIA_CCR_STATUS_IOIS8;
  489         if (pf->cfe->flags & PCMCIA_CFE_AUDIO)
  490                 reg |= PCMCIA_CCR_STATUS_AUDIO;
  491         pcmcia_ccr_write(pf, PCMCIA_CCR_STATUS, reg);
  492 
  493         pcmcia_ccr_write(pf, PCMCIA_CCR_SOCKETCOPY, 0);
  494 
  495         if (pcmcia_mfc(pf->sc)) {
  496                 long tmp, iosize;
  497 
  498                 tmp = pf->pf_mfc_iomax - pf->pf_mfc_iobase;
  499                 /* round up to nearest (2^n)-1 */
  500                 for (iosize = 1; iosize < tmp; iosize <<= 1)
  501                         ;
  502                 iosize--;
  503 
  504                 pcmcia_ccr_write(pf, PCMCIA_CCR_IOBASE0,
  505                                  pf->pf_mfc_iobase & 0xff);
  506                 pcmcia_ccr_write(pf, PCMCIA_CCR_IOBASE1,
  507                                  (pf->pf_mfc_iobase >> 8) & 0xff);
  508                 pcmcia_ccr_write(pf, PCMCIA_CCR_IOBASE2, 0);
  509                 pcmcia_ccr_write(pf, PCMCIA_CCR_IOBASE3, 0);
  510 
  511                 pcmcia_ccr_write(pf, PCMCIA_CCR_IOSIZE, iosize);
  512         }
  513 
  514 #ifdef PCMCIADEBUG
  515         if (pcmcia_debug) {
  516                 SIMPLEQ_FOREACH(tmp, &pf->sc->card.pf_head, pf_list) {
  517                         printf("%s: function %d CCR at %d offset %lx: "
  518                                "%x %x %x %x, %x %x %x %x, %x\n",
  519                                tmp->sc->dev.dv_xname, tmp->number,
  520                                tmp->pf_ccr_window,
  521                                (unsigned long) tmp->pf_ccr_offset,
  522                                pcmcia_ccr_read(tmp, 0x00),
  523                                pcmcia_ccr_read(tmp, 0x02),
  524                                pcmcia_ccr_read(tmp, 0x04),
  525                                pcmcia_ccr_read(tmp, 0x06),
  526 
  527                                pcmcia_ccr_read(tmp, 0x0A),
  528                                pcmcia_ccr_read(tmp, 0x0C), 
  529                                pcmcia_ccr_read(tmp, 0x0E),
  530                                pcmcia_ccr_read(tmp, 0x10),
  531 
  532                                pcmcia_ccr_read(tmp, 0x12));
  533                 }
  534         }
  535 #endif
  536 
  537         pf->pf_flags |= PFF_ENABLED;
  538 
  539 #ifdef IT8368E_LEGACY_MODE
  540         /* return to I/O mode */
  541         it8368_mode(pf, IT8368_IO_MODE, IT8368_WIDTH_16);
  542 #endif
  543         return (0);
  544 
  545  bad:
  546         /*
  547          * Decrement the reference count, and power down the socket, if
  548          * necessary.
  549          */
  550         if (--pf->sc->sc_enabled_count == 0)
  551                 pcmcia_chip_socket_disable(pf->sc->pct, pf->sc->pch);
  552         DPRINTF(("%s: --enabled_count = %d\n", pf->sc->dev.dv_xname,
  553                  pf->sc->sc_enabled_count));
  554 
  555         return (1);
  556 }
  557 
  558 /* Disable PCMCIA function. */
  559 void
  560 pcmcia_function_disable(pf)
  561         struct pcmcia_function *pf;
  562 {
  563         struct pcmcia_function *tmp;
  564 
  565         if (pf->cfe == NULL)
  566                 panic("pcmcia_function_enable: function not initialized");
  567 
  568         if ((pf->pf_flags & PFF_ENABLED) == 0) {
  569                 /*
  570                  * Don't do anything but decrement if we're already disabled.
  571                  */
  572                 goto out;
  573         }
  574 
  575         /*
  576          * it's possible for different functions' CCRs to be in the same
  577          * underlying page.  Check for that.  Note we mark us as disabled
  578          * first to avoid matching ourself.
  579          */
  580 
  581         pf->pf_flags &= ~PFF_ENABLED;
  582         SIMPLEQ_FOREACH(tmp, &pf->sc->card.pf_head, pf_list) {
  583                 if ((tmp->pf_flags & PFF_ENABLED) &&
  584                     (pf->ccr_base >= (tmp->ccr_base - tmp->pf_ccr_offset)) &&
  585                     ((pf->ccr_base + PCMCIA_CCR_SIZE) <=
  586                 (tmp->ccr_base - tmp->pf_ccr_offset + tmp->pf_ccr_realsize)))
  587                         break;
  588         }
  589 
  590         /* Not used by anyone else; unmap the CCR. */
  591         if (tmp == NULL) {
  592                 pcmcia_mem_unmap(pf, pf->pf_ccr_window);
  593                 pcmcia_mem_free(pf, &pf->pf_pcmh);
  594         }
  595 
  596 out:
  597         /*
  598          * Decrement the reference count, and power down the socket, if
  599          * necessary.
  600          */
  601         if (--pf->sc->sc_enabled_count == 0)
  602                 pcmcia_chip_socket_disable(pf->sc->pct, pf->sc->pch);
  603         DPRINTF(("%s: --enabled_count = %d\n", pf->sc->dev.dv_xname,
  604                  pf->sc->sc_enabled_count));
  605 }
  606 
  607 int
  608 pcmcia_io_map(pf, width, offset, size, pcihp, windowp)
  609         struct pcmcia_function *pf;
  610         int width;
  611         bus_addr_t offset;
  612         bus_size_t size;
  613         struct pcmcia_io_handle *pcihp;
  614         int *windowp;
  615 {
  616         int reg;
  617 
  618         if (pcmcia_chip_io_map(pf->sc->pct, pf->sc->pch,
  619             width, offset, size, pcihp, windowp))
  620                 return (1);
  621 
  622         /*
  623          * XXX in the multifunction multi-iospace-per-function case, this
  624          * needs to cooperate with io_alloc to make sure that the spaces
  625          * don't overlap, and that the ccr's are set correctly
  626          */
  627 
  628         if (pcmcia_mfc(pf->sc)) {
  629                 long tmp, iosize;
  630 
  631                 if (pf->pf_mfc_iomax == 0) {
  632                         pf->pf_mfc_iobase = pcihp->addr + offset;
  633                         pf->pf_mfc_iomax = pf->pf_mfc_iobase + size;
  634                 } else {
  635                         /* this makes the assumption that nothing overlaps */
  636                         if (pf->pf_mfc_iobase > pcihp->addr + offset)
  637                                 pf->pf_mfc_iobase = pcihp->addr + offset;
  638                         if (pf->pf_mfc_iomax < pcihp->addr + offset + size)
  639                                 pf->pf_mfc_iomax = pcihp->addr + offset + size;
  640                 }
  641 
  642                 tmp = pf->pf_mfc_iomax - pf->pf_mfc_iobase;
  643                 /* round up to nearest (2^n)-1 */
  644                 for (iosize = 1; iosize >= tmp; iosize <<= 1)
  645                         ;
  646                 iosize--;
  647 
  648                 pcmcia_ccr_write(pf, PCMCIA_CCR_IOBASE0,
  649                                  pf->pf_mfc_iobase & 0xff);
  650                 pcmcia_ccr_write(pf, PCMCIA_CCR_IOBASE1,
  651                                  (pf->pf_mfc_iobase >> 8) & 0xff);
  652                 pcmcia_ccr_write(pf, PCMCIA_CCR_IOBASE2, 0);
  653                 pcmcia_ccr_write(pf, PCMCIA_CCR_IOBASE3, 0);
  654 
  655                 pcmcia_ccr_write(pf, PCMCIA_CCR_IOSIZE, iosize);
  656 
  657                 reg = pcmcia_ccr_read(pf, PCMCIA_CCR_OPTION);
  658                 reg |= PCMCIA_CCR_OPTION_ADDR_DECODE;
  659                 pcmcia_ccr_write(pf, PCMCIA_CCR_OPTION, reg);
  660         }
  661         return (0);
  662 }
  663 
  664 void
  665 pcmcia_io_unmap(pf, window)
  666         struct pcmcia_function *pf;
  667         int window;
  668 {
  669 
  670         pcmcia_chip_io_unmap(pf->sc->pct, pf->sc->pch, window);
  671 
  672         /* XXX Anything for multi-function cards? */
  673 }
  674 
  675 void *
  676 pcmcia_intr_establish(pf, ipl, ih_fct, ih_arg)
  677         struct pcmcia_function *pf;
  678         int ipl;
  679         int (*ih_fct) __P((void *));
  680         void *ih_arg;
  681 {
  682         void *ret;
  683 
  684         /* behave differently if this is a multifunction card */
  685 
  686         if (pcmcia_mfc(pf->sc)) {
  687                 int s, ihcnt, hiipl, reg;
  688                 struct pcmcia_function *pf2;
  689 
  690                 /*
  691                  * mask all the ipl's which are already used by this card,
  692                  * and find the highest ipl number (lowest priority)
  693                  */
  694 
  695                 ihcnt = 0;
  696                 s = 0;          /* this is only here to keep the compiler
  697                                    happy */
  698                 hiipl = 0;      /* this is only here to keep the compiler
  699                                    happy */
  700 
  701                 SIMPLEQ_FOREACH(pf2, &pf->sc->card.pf_head, pf_list) {
  702                         if (pf2->ih_fct) {
  703                                 DPRINTF(("%s: function %d has ih_fct %p\n",
  704                                          pf->sc->dev.dv_xname, pf2->number,
  705                                          pf2->ih_fct));
  706 
  707                                 if (ihcnt == 0) {
  708                                         hiipl = pf2->ih_ipl;
  709                                 } else {
  710                                         if (pf2->ih_ipl > hiipl)
  711                                                 hiipl = pf2->ih_ipl;
  712                                 }
  713 
  714                                 ihcnt++;
  715                         }
  716                 }
  717 
  718                 /*
  719                  * establish the real interrupt, changing the ipl if
  720                  * necessary
  721                  */
  722 
  723                 if (ihcnt == 0) {
  724 #ifdef DIAGNOSTIC
  725                         if (pf->sc->ih != NULL)
  726                                 panic("card has intr handler, but no function does");
  727 #endif
  728                         s = splhigh();
  729 
  730                         /* set up the handler for the new function */
  731 
  732                         pf->ih_fct = ih_fct;
  733                         pf->ih_arg = ih_arg;
  734                         pf->ih_ipl = ipl;
  735 
  736                         pf->sc->ih = pcmcia_chip_intr_establish(pf->sc->pct,
  737                             pf->sc->pch, pf, ipl, PCMCIA_CARD_INTR, pf->sc);
  738                         splx(s);
  739                 } else if (ipl > hiipl) {
  740 #ifdef DIAGNOSTIC
  741                         if (pf->sc->ih == NULL)
  742                                 panic("functions have ih, but the card does not");
  743 #endif
  744 
  745                         /* XXX need #ifdef for splserial on x86 */
  746                         s = splhigh();
  747 
  748                         pcmcia_chip_intr_disestablish(pf->sc->pct, pf->sc->pch,
  749                                                       pf->sc->ih);
  750 
  751                         /* set up the handler for the new function */
  752                         pf->ih_fct = ih_fct;
  753                         pf->ih_arg = ih_arg;
  754                         pf->ih_ipl = ipl;
  755 
  756                         pf->sc->ih = pcmcia_chip_intr_establish(pf->sc->pct,
  757                             pf->sc->pch, pf, ipl, PCMCIA_CARD_INTR, pf->sc);
  758 
  759                         splx(s);
  760                 } else {
  761                         s = splhigh();
  762 
  763                         /* set up the handler for the new function */
  764 
  765                         pf->ih_fct = ih_fct;
  766                         pf->ih_arg = ih_arg;
  767                         pf->ih_ipl = ipl;
  768 
  769                         splx(s);
  770                 }
  771 
  772                 ret = pf->sc->ih;
  773 
  774                 if (ret != NULL) {
  775                         reg = pcmcia_ccr_read(pf, PCMCIA_CCR_OPTION);
  776                         reg |= PCMCIA_CCR_OPTION_IREQ_ENABLE;
  777                         pcmcia_ccr_write(pf, PCMCIA_CCR_OPTION, reg);
  778 
  779                         reg = pcmcia_ccr_read(pf, PCMCIA_CCR_STATUS);
  780                         reg |= PCMCIA_CCR_STATUS_INTRACK;
  781                         pcmcia_ccr_write(pf, PCMCIA_CCR_STATUS, reg);
  782                 }
  783         } else {
  784                 ret = pcmcia_chip_intr_establish(pf->sc->pct, pf->sc->pch,
  785                     pf, ipl, ih_fct, ih_arg);
  786         }
  787 
  788         return (ret);
  789 }
  790 
  791 void
  792 pcmcia_intr_disestablish(pf, ih)
  793         struct pcmcia_function *pf;
  794         void *ih;
  795 {
  796         /* behave differently if this is a multifunction card */
  797 
  798         if (pcmcia_mfc(pf->sc)) {
  799                 int s, ihcnt, hiipl;
  800                 struct pcmcia_function *pf2;
  801 
  802                 /*
  803                  * mask all the ipl's which are already used by this card,
  804                  * and find the highest ipl number (lowest priority).  Skip
  805                  * the current function.
  806                  */
  807 
  808                 ihcnt = 0;
  809                 s = 0;          /* avoid compiler warning */
  810                 hiipl = 0;      /* avoid compiler warning */
  811 
  812                 SIMPLEQ_FOREACH(pf2, &pf->sc->card.pf_head, pf_list) {
  813                         if (pf2 == pf)
  814                                 continue;
  815 
  816                         if (pf2->ih_fct) {
  817                                 if (ihcnt == 0) {
  818                                         hiipl = pf2->ih_ipl;
  819                                 } else {
  820                                         if (pf2->ih_ipl > hiipl)
  821                                                 hiipl = pf2->ih_ipl;
  822                                 }
  823                                 ihcnt++;
  824                         }
  825                 }
  826 
  827                 /*
  828                  * If the ih being removed is lower priority than the lowest
  829                  * priority remaining interrupt, up the priority.
  830                  */
  831 
  832                 /* 
  833                  * ihcnt is the number of interrupt handlers *not* including
  834                  * the one about to be removed. 
  835                  */
  836 
  837                 if (ihcnt == 0) {
  838                         int reg;
  839 
  840 #ifdef DIAGNOSTIC
  841                         if (pf->sc->ih == NULL)
  842                                 panic("disestablishing last function, but card has no ih");
  843 #endif
  844                         pcmcia_chip_intr_disestablish(pf->sc->pct, pf->sc->pch,
  845                             pf->sc->ih);
  846 
  847                         reg = pcmcia_ccr_read(pf, PCMCIA_CCR_OPTION);
  848                         reg &= ~PCMCIA_CCR_OPTION_IREQ_ENABLE;
  849                         pcmcia_ccr_write(pf, PCMCIA_CCR_OPTION, reg);
  850 
  851                         pf->ih_fct = NULL;
  852                         pf->ih_arg = NULL;
  853 
  854                         pf->sc->ih = NULL;
  855                 } else if (pf->ih_ipl > hiipl) {
  856 #ifdef DIAGNOSTIC
  857                         if (pf->sc->ih == NULL)
  858                                 panic("changing ih ipl, but card has no ih");
  859 #endif
  860                         /* XXX need #ifdef for splserial on x86 */
  861                         s = splhigh();
  862 
  863                         pcmcia_chip_intr_disestablish(pf->sc->pct, pf->sc->pch,
  864                             pf->sc->ih);
  865                         pf->sc->ih = pcmcia_chip_intr_establish(pf->sc->pct,
  866                             pf->sc->pch, pf, hiipl, PCMCIA_CARD_INTR, pf->sc);
  867 
  868                         /* null out the handler for this function */
  869 
  870                         pf->ih_fct = NULL;
  871                         pf->ih_arg = NULL;
  872 
  873                         splx(s);
  874                 } else {
  875                         s = splhigh();
  876 
  877                         pf->ih_fct = NULL;
  878                         pf->ih_arg = NULL;
  879 
  880                         splx(s);
  881                 }
  882         } else {
  883                 pcmcia_chip_intr_disestablish(pf->sc->pct, pf->sc->pch, ih);
  884         }
  885 }
  886 
  887 int 
  888 pcmcia_card_intr(arg)
  889         void *arg;
  890 {
  891         struct pcmcia_softc *sc = arg;
  892         struct pcmcia_function *pf;
  893         int reg, ret, ret2;
  894 
  895         ret = 0;
  896 
  897         SIMPLEQ_FOREACH(pf, &sc->card.pf_head, pf_list) {
  898                 if (pf->ih_fct != NULL &&
  899                     (pf->ccr_mask & (1 << (PCMCIA_CCR_STATUS / 2)))) {
  900                         reg = pcmcia_ccr_read(pf, PCMCIA_CCR_STATUS);
  901                         if (reg & PCMCIA_CCR_STATUS_INTR) {
  902                                 ret2 = (*pf->ih_fct)(pf->ih_arg);
  903                                 if (ret2 != 0 && ret == 0)
  904                                         ret = ret2;
  905                                 reg = pcmcia_ccr_read(pf, PCMCIA_CCR_STATUS);
  906                                 pcmcia_ccr_write(pf, PCMCIA_CCR_STATUS,
  907                                     reg & ~PCMCIA_CCR_STATUS_INTR);
  908                         }
  909                 }
  910         }
  911 
  912         return (ret);
  913 }
  914 
  915 #ifdef PCMCIADEBUG
  916 int 
  917 pcmcia_card_intrdebug(arg)
  918         void *arg;
  919 {
  920         struct pcmcia_softc *sc = arg;
  921         struct pcmcia_function *pf;
  922         int reg, ret, ret2;
  923 
  924         ret = 0;
  925 
  926         SIMPLEQ_FOREACH(pf, &sc->card.pf_head, pf_list) {
  927                 printf("%s: intr flags=%x fct=%d cor=%02x csr=%02x pin=%02x",
  928                        sc->dev.dv_xname, pf->pf_flags, pf->number,
  929                        pcmcia_ccr_read(pf, PCMCIA_CCR_OPTION),
  930                        pcmcia_ccr_read(pf, PCMCIA_CCR_STATUS),
  931                        pcmcia_ccr_read(pf, PCMCIA_CCR_PIN));
  932                 if (pf->ih_fct != NULL &&
  933                     (pf->ccr_mask & (1 << (PCMCIA_CCR_STATUS / 2)))) {
  934                         reg = pcmcia_ccr_read(pf, PCMCIA_CCR_STATUS);
  935                         if (reg & PCMCIA_CCR_STATUS_INTR) {
  936                                 ret2 = (*pf->ih_fct)(pf->ih_arg);
  937                                 if (ret2 != 0 && ret == 0)
  938                                         ret = ret2;
  939                                 reg = pcmcia_ccr_read(pf, PCMCIA_CCR_STATUS);
  940                                 printf("; csr %02x->%02x",
  941                                     reg, reg & ~PCMCIA_CCR_STATUS_INTR);
  942                                 pcmcia_ccr_write(pf, PCMCIA_CCR_STATUS,
  943                                     reg & ~PCMCIA_CCR_STATUS_INTR);
  944                         }
  945                 }
  946                 printf("\n");
  947         }
  948 
  949         return (ret);
  950 }
  951 #endif

Cache object: c54d185dff505ca29a43ad1272d1dbbf


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