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