Home | History | Annotate | Line # | Download | only in pcmcia
pcmcia.c revision 1.2
      1 /*	$NetBSD: pcmcia.c,v 1.2 1997/10/16 23:27:30 thorpej Exp $	*/
      2 
      3 #define	PCMCIADEBUG
      4 
      5 /*
      6  * Copyright (c) 1997 Marc Horowitz.  All rights reserved.
      7  *
      8  * Redistribution and use in source and binary forms, with or without
      9  * modification, are permitted provided that the following conditions
     10  * are met:
     11  * 1. Redistributions of source code must retain the above copyright
     12  *    notice, this list of conditions and the following disclaimer.
     13  * 2. Redistributions in binary form must reproduce the above copyright
     14  *    notice, this list of conditions and the following disclaimer in the
     15  *    documentation and/or other materials provided with the distribution.
     16  * 3. All advertising materials mentioning features or use of this software
     17  *    must display the following acknowledgement:
     18  *	This product includes software developed by Marc Horowitz.
     19  * 4. The name of the author may not be used to endorse or promote products
     20  *    derived from this software without specific prior written permission.
     21  *
     22  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     23  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     24  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     25  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     27  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     28  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     29  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     30  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     31  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     32  */
     33 
     34 #include "opt_pcmciaverbose.h"
     35 
     36 #include <sys/types.h>
     37 #include <sys/param.h>
     38 #include <sys/systm.h>
     39 #include <sys/device.h>
     40 
     41 /* XXX only needed for intr debugging */
     42 #include <vm/vm.h>
     43 
     44 #include <dev/pcmcia/pcmciareg.h>
     45 #include <dev/pcmcia/pcmciachip.h>
     46 #include <dev/pcmcia/pcmciavar.h>
     47 
     48 #ifdef PCMCIADEBUG
     49 int	pcmcia_debug = 0;
     50 #define	DPRINTF(arg) if (pcmcia_debug) printf arg
     51 #else
     52 #define	DPRINTF(arg)
     53 #endif
     54 
     55 #ifdef PCMCIAVERBOSE
     56 int	pcmcia_verbose = 1;
     57 #else
     58 int	pcmcia_verbose = 0;
     59 #endif
     60 
     61 #ifdef	__BROKEN_INDIRECT_CONFIG
     62 int	pcmcia_match __P((struct device *, void *, void *));
     63 int	pcmcia_submatch __P((struct device *, void *, void *));
     64 #else
     65 int	pcmcia_match __P((struct device *, struct cfdata *, void *));
     66 int	pcmcia_submatch __P((struct device *, struct cfdata *, void *));
     67 #endif
     68 void	pcmcia_attach __P((struct device *, struct device *, void *));
     69 int	pcmcia_print __P((void *, const char *));
     70 
     71 int	pcmcia_card_intr __P((void *));
     72 
     73 struct cfdriver pcmcia_cd = {
     74 	NULL, "pcmcia", DV_DULL
     75 };
     76 
     77 struct cfattach pcmcia_ca = {
     78 	sizeof(struct pcmcia_softc), pcmcia_match, pcmcia_attach
     79 };
     80 
     81 int
     82 pcmcia_ccr_read(pf, ccr)
     83 	struct pcmcia_function *pf;
     84 	int ccr;
     85 {
     86 
     87 	return (bus_space_read_1(pf->pf_ccrt, pf->pf_ccrh,
     88 	    pf->pf_ccr_offset + ccr));
     89 }
     90 
     91 void
     92 pcmcia_ccr_write(pf, ccr, val)
     93 	struct pcmcia_function *pf;
     94 	int ccr;
     95 	int val;
     96 {
     97 
     98 	if ((pf->ccr_mask) & (1 << (ccr / 2))) {
     99 		bus_space_write_1(pf->pf_ccrt, pf->pf_ccrh,
    100 		    pf->pf_ccr_offset + ccr, val);
    101 	}
    102 }
    103 
    104 int
    105 pcmcia_match(parent, match, aux)
    106 	struct device *parent;
    107 #ifdef	__BROKEN_INDIRECT_CONFIG
    108 	void *match;
    109 #else
    110 	struct cfdata *match;
    111 #endif
    112 	void *aux;
    113 {
    114 
    115 	/* if the autoconfiguration got this far, there's a socket here */
    116 	return (1);
    117 }
    118 
    119 void
    120 pcmcia_attach(parent, self, aux)
    121 	struct device *parent, *self;
    122 	void *aux;
    123 {
    124 	struct pcmciabus_attach_args *paa = aux;
    125 	struct pcmcia_softc *sc = (struct pcmcia_softc *) self;
    126 
    127 	printf("\n");
    128 
    129 	sc->pct = paa->pct;
    130 	sc->pch = paa->pch;
    131 	sc->iobase = paa->iobase;
    132 	sc->iosize = paa->iosize;
    133 
    134 	sc->ih = NULL;
    135 }
    136 
    137 int
    138 pcmcia_card_attach(dev)
    139 	struct device *dev;
    140 {
    141 	struct pcmcia_softc *sc = (struct pcmcia_softc *) dev;
    142 	struct pcmcia_function *pf;
    143 	struct pcmcia_attach_args paa;
    144 	int attached;
    145 
    146 	/*
    147 	 * this is here so that when socket_enable calls gettype, trt happens
    148 	 */
    149 	sc->card.pf_head.sqh_first = NULL;
    150 
    151 	pcmcia_chip_socket_enable(sc->pct, sc->pch);
    152 
    153 	pcmcia_read_cis(sc);
    154 
    155 	pcmcia_chip_socket_disable(sc->pct, sc->pch);
    156 
    157 	/*
    158 	 * bail now if the card has no functions, or if there was an error in
    159 	 * the cis.
    160 	 */
    161 
    162 	if (sc->card.error)
    163 		return (1);
    164 	if (sc->card.pf_head.sqh_first == NULL)
    165 		return (1);
    166 
    167 	if (pcmcia_verbose)
    168 		pcmcia_print_cis(sc);
    169 
    170 	attached = 0;
    171 
    172 	for (pf = sc->card.pf_head.sqh_first; pf != NULL;
    173 	    pf = pf->pf_list.sqe_next) {
    174 		if (pf->cfe_head.sqh_first == NULL)
    175 			continue;
    176 
    177 		pf->sc = sc;
    178 		pf->cfe = NULL;
    179 		pf->ih_fct = NULL;
    180 		pf->ih_arg = NULL;
    181 	}
    182 
    183 	for (pf = sc->card.pf_head.sqh_first; pf != NULL;
    184 	    pf = pf->pf_list.sqe_next) {
    185 		if (pf->cfe_head.sqh_first == NULL)
    186 			continue;
    187 
    188 		paa.manufacturer = sc->card.manufacturer;
    189 		paa.product = sc->card.product;
    190 		paa.card = &sc->card;
    191 		paa.pf = pf;
    192 
    193 		if (config_found_sm(&sc->dev, &paa, pcmcia_print,
    194 		    pcmcia_submatch)) {
    195 			attached++;
    196 
    197 			DPRINTF(("%s: function %d CCR at %d "
    198 			     "offset %lx: %x %x %x %x, %x %x %x %x, %x\n",
    199 			     sc->dev.dv_xname, pf->number,
    200 			     pf->pf_ccr_window, pf->pf_ccr_offset,
    201 			     pcmcia_ccr_read(pf, 0x00),
    202 			pcmcia_ccr_read(pf, 0x02), pcmcia_ccr_read(pf, 0x04),
    203 			pcmcia_ccr_read(pf, 0x06), pcmcia_ccr_read(pf, 0x0A),
    204 			pcmcia_ccr_read(pf, 0x0C), pcmcia_ccr_read(pf, 0x0E),
    205 			pcmcia_ccr_read(pf, 0x10), pcmcia_ccr_read(pf, 0x12)));
    206 		}
    207 	}
    208 
    209 	return (attached ? 0 : 1);
    210 }
    211 
    212 void
    213 pcmcia_card_detach(dev)
    214 	struct device *dev;
    215 {
    216 	/* struct pcmcia_softc *sc = (struct pcmcia_softc *) dev; */
    217 	/* don't do anything yet */
    218 }
    219 
    220 int
    221 #ifdef __BROKEN_INDIRECT_CONFIG
    222 pcmcia_submatch(parent, match, aux)
    223 	struct device *parent;
    224 	void *match, *aux;
    225 {
    226 	struct cfdata *cf = match;
    227 #else
    228 pcmcia_submatch(parent, cf, aux)
    229 	struct device *parent;
    230 	struct cfdata *cf;
    231 	void *aux;
    232 {
    233 #endif
    234 	struct pcmcia_attach_args *paa = aux;
    235 
    236 	if (cf->cf_loc[0] != -1 && cf->cf_loc[0] != paa->pf->number)
    237 		return (0);
    238 
    239 	return ((*cf->cf_attach->ca_match)(parent, cf, aux));
    240 }
    241 
    242 int
    243 pcmcia_print(arg, pnp)
    244 	void *arg;
    245 	const char *pnp;
    246 {
    247 	struct pcmcia_attach_args *pa = arg;
    248 	struct pcmcia_softc *sc = pa->pf->sc;
    249 	struct pcmcia_card *card = &sc->card;
    250 	int i;
    251 
    252 	if (pnp) {
    253 		for (i = 0; i < 4; i++) {
    254 			if (card->cis1_info[i] == NULL)
    255 				break;
    256 			if (i)
    257 				printf(", ");
    258 			printf("%s", card->cis1_info[i]);
    259 		}
    260 		if (i)
    261 			printf(" ");
    262 		printf("(manufacturer 0x%x, product 0x%x)", card->manufacturer,
    263 		       card->product);
    264 	}
    265 	printf(" function %d", pa->pf->number);
    266 
    267 	return (UNCONF);
    268 }
    269 
    270 int
    271 pcmcia_card_gettype(dev)
    272 	struct device  *dev;
    273 {
    274 	struct pcmcia_softc *sc = (struct pcmcia_softc *) dev;
    275 
    276 	/*
    277 	 * set the iftype to memory if this card has no functions (not yet
    278 	 * probed), or only one function, and that is memory.
    279 	 */
    280 	if (sc->card.pf_head.sqh_first == NULL ||
    281 	    (sc->card.pf_head.sqh_first != NULL &&
    282 	     sc->card.pf_head.sqh_first->pf_list.sqe_next == NULL &&
    283 	     (sc->card.pf_head.sqh_first->cfe_head.sqh_first->iftype ==
    284 	      PCMCIA_IFTYPE_MEMORY)))
    285 		return (PCMCIA_IFTYPE_MEMORY);
    286 	else
    287 		return (PCMCIA_IFTYPE_IO);
    288 }
    289 
    290 /*
    291  * Initialize a PCMCIA function.  May be called as long as the function is
    292  * disabled.
    293  */
    294 void
    295 pcmcia_function_init(pf, cfe)
    296 	struct pcmcia_function *pf;
    297 	struct pcmcia_config_entry *cfe;
    298 {
    299 
    300 	if (pf->pf_flags & PFF_ENABLED)
    301 		panic("pcmcia_function_init: function is enabled");
    302 
    303 	/* Remember which configuration entry we are using. */
    304 	pf->cfe = cfe;
    305 }
    306 
    307 /* Enable a PCMCIA function */
    308 int
    309 pcmcia_function_enable(pf)
    310 	struct pcmcia_function *pf;
    311 {
    312 	struct pcmcia_function *tmp;
    313 	int reg;
    314 
    315 	if (pf->cfe == NULL)
    316 		panic("pcmcia_function_enable: function not initialized");
    317 
    318 	if (pf->pf_flags & PFF_ENABLED) {
    319 		/*
    320 		 * Don't do anything if we're already enabled.
    321 		 */
    322 		return (0);
    323 	}
    324 
    325 	/*
    326 	 * Increase the reference count on the socket, enabling power, if
    327 	 * necessary.
    328 	 */
    329 	if (pf->sc->sc_enabled_count++ == 0)
    330 		pcmcia_chip_socket_enable(pf->sc->pct, pf->sc->pch);
    331 
    332 	/*
    333 	 * it's possible for different functions' CCRs to be in the same
    334 	 * underlying page.  Check for that.
    335 	 */
    336 
    337 	for (tmp = pf->sc->card.pf_head.sqh_first; tmp != NULL;
    338 	    tmp = tmp->pf_list.sqe_next) {
    339 		if ((tmp->pf_flags & PFF_ENABLED) &&
    340 		    (pf->ccr_base >= (tmp->ccr_base - tmp->pf_ccr_offset)) &&
    341 		    ((pf->ccr_base + PCMCIA_CCR_SIZE) <=
    342 		     (tmp->ccr_base - tmp->pf_ccr_offset +
    343 		      tmp->pf_ccr_realsize))) {
    344 			pf->pf_ccrt = tmp->pf_ccrt;
    345 			pf->pf_ccrh = tmp->pf_ccrh;
    346 			pf->pf_ccr_realsize = tmp->pf_ccr_realsize;
    347 
    348 			/*
    349 			 * pf->pf_ccr_offset = (tmp->pf_ccr_offset -
    350 			 * tmp->ccr_base) + pf->ccr_base;
    351 			 */
    352 			pf->pf_ccr_offset =
    353 			    (tmp->pf_ccr_offset + pf->ccr_base) -
    354 			    tmp->ccr_base;
    355 			pf->pf_ccr_window = tmp->pf_ccr_window;
    356 			break;
    357 		}
    358 	}
    359 
    360 	if (tmp == NULL) {
    361 		if (pcmcia_mem_alloc(pf, PCMCIA_CCR_SIZE, &pf->pf_pcmh))
    362 			goto bad;
    363 
    364 		if (pcmcia_mem_map(pf, PCMCIA_MEM_ATTR, pf->ccr_base,
    365 		    PCMCIA_CCR_SIZE, &pf->pf_pcmh, &pf->pf_ccr_offset,
    366 		    &pf->pf_ccr_window)) {
    367 			pcmcia_mem_free(pf, &pf->pf_pcmh);
    368 			goto bad;
    369 		}
    370 	}
    371 	DPRINTF(("%s: function %d CCR at %d offset %lx: "
    372 	    "%x %x %x %x, %x %x %x %x, %x\n",
    373 	    pf->sc->dev.dv_xname, pf->number,
    374 	    pf->pf_ccr_window, pf->pf_ccr_offset,
    375 	    pcmcia_ccr_read(pf, 0x00),
    376 	    pcmcia_ccr_read(pf, 0x02), pcmcia_ccr_read(pf, 0x04),
    377 	    pcmcia_ccr_read(pf, 0x06), pcmcia_ccr_read(pf, 0x0A),
    378 	    pcmcia_ccr_read(pf, 0x0C), pcmcia_ccr_read(pf, 0x0E),
    379 	    pcmcia_ccr_read(pf, 0x10), pcmcia_ccr_read(pf, 0x12)));
    380 
    381 	reg = (pf->cfe->number & PCMCIA_CCR_OPTION_CFINDEX);
    382 	reg |= PCMCIA_CCR_OPTION_LEVIREQ;
    383 	if (pcmcia_mfc(pf->sc))
    384 		reg |= PCMCIA_CCR_OPTION_FUNC_ENABLE;
    385 	pcmcia_ccr_write(pf, PCMCIA_CCR_OPTION, reg);
    386 
    387 	reg = 0;
    388 
    389 	if ((pf->cfe->flags & PCMCIA_CFE_IO16) == 0)
    390 		reg |= PCMCIA_CCR_STATUS_IOIS8;
    391 	if (pf->cfe->flags & PCMCIA_CFE_AUDIO)
    392 		reg |= PCMCIA_CCR_STATUS_AUDIO;
    393 	/* Not really needed, since we start with 0. */
    394 	if (pf->cfe->flags & PCMCIA_CFE_POWERDOWN)
    395 		reg &= ~PCMCIA_CCR_STATUS_PWRDWN;
    396 	pcmcia_ccr_write(pf, PCMCIA_CCR_STATUS, reg);
    397 
    398 	pcmcia_ccr_write(pf, PCMCIA_CCR_SOCKETCOPY, 0);
    399 
    400 	pf->pf_flags |= PFF_ENABLED;
    401 	return (0);
    402 
    403  bad:
    404 	/*
    405 	 * Decrement the reference count, and power down the socket, if
    406 	 * necessary.
    407 	 */
    408 	if (pf->sc->sc_enabled_count-- == 1)
    409 		pcmcia_chip_socket_disable(pf->sc->pct, pf->sc->pch);
    410 	return (1);
    411 }
    412 
    413 /* Disable PCMCIA function. */
    414 void
    415 pcmcia_function_disable(pf)
    416 	struct pcmcia_function *pf;
    417 {
    418 	struct pcmcia_function *tmp;
    419 	int reg;
    420 
    421 	if (pf->cfe == NULL)
    422 		panic("pcmcia_function_enable: function not initialized");
    423 
    424 	if ((pf->pf_flags & PFF_ENABLED) == 0) {
    425 		/*
    426 		 * Don't do anything if we're already disabled.
    427 		 */
    428 		return;
    429 	}
    430 
    431 	/* Power down the function if the card supports it. */
    432 	if (pf->cfe->flags & PCMCIA_CFE_POWERDOWN) {
    433 		reg = pcmcia_ccr_read(pf, PCMCIA_CCR_STATUS);
    434 		reg |= PCMCIA_CCR_STATUS_PWRDWN;
    435 		pcmcia_ccr_write(pf, PCMCIA_CCR_STATUS, reg);
    436 	}
    437 
    438 	/*
    439 	 * it's possible for different functions' CCRs to be in the same
    440 	 * underlying page.  Check for that.  Note we mark us as disabled
    441 	 * first to avoid matching ourself.
    442 	 */
    443 
    444 	pf->pf_flags &= ~PFF_ENABLED;
    445 	for (tmp = pf->sc->card.pf_head.sqh_first; tmp != NULL;
    446 	    tmp = tmp->pf_list.sqe_next) {
    447 		if ((tmp->pf_flags & PFF_ENABLED) &&
    448 		    (pf->ccr_base >= (tmp->ccr_base - tmp->pf_ccr_offset)) &&
    449 		    ((pf->ccr_base + PCMCIA_CCR_SIZE) <=
    450 		(tmp->ccr_base - tmp->pf_ccr_offset + tmp->pf_ccr_realsize)))
    451 			break;
    452 	}
    453 
    454 	/* Not used by anyone else; unmap the CCR. */
    455 	if (tmp == NULL) {
    456 		pcmcia_mem_unmap(pf, pf->pf_ccr_window);
    457 		pcmcia_mem_free(pf, &pf->pf_pcmh);
    458 	}
    459 
    460 	/*
    461 	 * Decrement the reference count, and power down the socket, if
    462 	 * necessary.
    463 	 */
    464 	if (--pf->sc->sc_enabled_count == 0)
    465 		pcmcia_chip_socket_disable(pf->sc->pct, pf->sc->pch);
    466 }
    467 
    468 int
    469 pcmcia_io_map(pf, width, offset, size, pcihp, windowp)
    470 	struct pcmcia_function *pf;
    471 	int width;
    472 	bus_addr_t offset;
    473 	bus_size_t size;
    474 	struct pcmcia_io_handle *pcihp;
    475 	int *windowp;
    476 {
    477 	bus_addr_t ioaddr;
    478 	int reg;
    479 
    480 	if (pcmcia_chip_io_map(pf->sc->pct, pf->sc->pch,
    481 	    width, offset, size, pcihp, windowp))
    482 		return (1);
    483 
    484 	ioaddr = pcihp->addr + offset;
    485 
    486 	/*
    487 	 * XXX in the multifunction multi-iospace-per-function case, this
    488 	 * needs to cooperate with io_alloc to make sure that the spaces
    489 	 * don't overlap, and that the ccr's are set correctly
    490 	 */
    491 
    492 	if (pcmcia_mfc(pf->sc)) {
    493 		pcmcia_ccr_write(pf, PCMCIA_CCR_IOBASE0, ioaddr & 0xff);
    494 		pcmcia_ccr_write(pf, PCMCIA_CCR_IOBASE1, (ioaddr >> 8) & 0xff);
    495 		pcmcia_ccr_write(pf, PCMCIA_CCR_IOSIZE, size - 1);
    496 
    497 		reg = pcmcia_ccr_read(pf, PCMCIA_CCR_OPTION);
    498 		reg |= PCMCIA_CCR_OPTION_ADDR_DECODE;
    499 		pcmcia_ccr_write(pf, PCMCIA_CCR_OPTION, reg);
    500 	}
    501 	return (0);
    502 }
    503 
    504 void *
    505 pcmcia_intr_establish(pf, ipl, ih_fct, ih_arg)
    506 	struct pcmcia_function *pf;
    507 	int ipl;
    508 	int (*ih_fct) __P((void *));
    509 	void *ih_arg;
    510 {
    511 	void *ret;
    512 
    513 	/* behave differently if this is a multifunction card */
    514 
    515 	if (pcmcia_mfc(pf->sc)) {
    516 		int s, ihcnt, hiipl, reg;
    517 		struct pcmcia_function *pf2;
    518 
    519 		/* XXX splraise() use needs to go away! */
    520 
    521 		/*
    522 		 * mask all the ipl's which are already used by this card,
    523 		 * and find the highest ipl number (lowest priority)
    524 		 */
    525 
    526 		ihcnt = 0;
    527 		s = 0;		/* this is only here to keep the compipler
    528 				   happy */
    529 		hiipl = 0;	/* this is only here to keep the compipler
    530 				   happy */
    531 
    532 		for (pf2 = pf->sc->card.pf_head.sqh_first; pf2 != NULL;
    533 		     pf2 = pf2->pf_list.sqe_next) {
    534 			if (pf2->ih_fct) {
    535 				if (ihcnt == 0) {
    536 					s = splraise(pf2->ih_ipl);
    537 					hiipl = pf2->ih_ipl;
    538 					ihcnt++;
    539 				} else {
    540 					splraise(pf2->ih_ipl);
    541 					if (pf2->ih_ipl > hiipl)
    542 						hiipl = pf2->ih_ipl;
    543 				}
    544 			}
    545 		}
    546 
    547 		/* set up the handler for the new function */
    548 
    549 		pf->ih_fct = ih_fct;
    550 		pf->ih_arg = ih_arg;
    551 		pf->ih_ipl = ipl;
    552 
    553 		/*
    554 		 * establish the real interrupt, changing the ipl if
    555 		 * necessary
    556 		 */
    557 
    558 		if (ihcnt == 0) {
    559 #ifdef DIAGNOSTIC
    560 			if (pf->sc->ih != NULL)
    561 				panic("card has intr handler, but no function does");
    562 #endif
    563 
    564 			pf->sc->ih = pcmcia_chip_intr_establish(pf->sc->pct,
    565 			    pf->sc->pch, pf, ipl, pcmcia_card_intr, pf->sc);
    566 		} else if (ipl > hiipl) {
    567 #ifdef DIAGNOSTIC
    568 			if (pf->sc->ih == NULL)
    569 				panic("functions have ih, but the card does not");
    570 #endif
    571 
    572 			pcmcia_chip_intr_disestablish(pf->sc->pct, pf->sc->pch,
    573 			    pf->sc->ih);
    574 			pf->sc->ih = pcmcia_chip_intr_establish(pf->sc->pct,
    575 			    pf->sc->pch, pf, ipl, pcmcia_card_intr, pf->sc);
    576 		}
    577 		if (ihcnt)
    578 			splx(s);
    579 
    580 		ret = pf->sc->ih;
    581 
    582 		if (ret != NULL) {
    583 			reg = pcmcia_ccr_read(pf, PCMCIA_CCR_OPTION);
    584 			reg |= PCMCIA_CCR_OPTION_IREQ_ENABLE;
    585 			pcmcia_ccr_write(pf, PCMCIA_CCR_OPTION, reg);
    586 
    587 			reg = pcmcia_ccr_read(pf, PCMCIA_CCR_STATUS);
    588 			reg |= PCMCIA_CCR_STATUS_INTRACK;
    589 			pcmcia_ccr_write(pf, PCMCIA_CCR_STATUS, reg);
    590 		}
    591 	} else {
    592 		ret = pcmcia_chip_intr_establish(pf->sc->pct, pf->sc->pch,
    593 		    pf, ipl, ih_fct, ih_arg);
    594 	}
    595 
    596 	return (ret);
    597 }
    598 
    599 void
    600 pcmcia_intr_disestablish(pf, ih)
    601 	struct pcmcia_function *pf;
    602 	void *ih;
    603 {
    604 
    605 	/* behave differently if this is a multifunction card */
    606 
    607 	if (pcmcia_mfc(pf->sc)) {
    608 		int s, ihcnt, hiipl;
    609 		struct pcmcia_function *pf2;
    610 
    611 		/*
    612 		 * mask all the ipl's which are already used by this card,
    613 		 * and find the highest ipl number (lowest priority).  Skip
    614 		 * the current function.
    615 		 */
    616 
    617 		ihcnt = 0;
    618 		s = 0;		/* this is only here to keep the compipler
    619 				   happy */
    620 		hiipl = 0;	/* this is only here to keep the compipler
    621 				   happy */
    622 
    623 		for (pf2 = pf->sc->card.pf_head.sqh_first; pf2 != NULL;
    624 		     pf2 = pf2->pf_list.sqe_next) {
    625 			if (pf2 == pf)
    626 				continue;
    627 
    628 			if (pf2->ih_fct) {
    629 				if (ihcnt == 0) {
    630 					s = splraise(pf2->ih_ipl);
    631 					hiipl = pf2->ih_ipl;
    632 					ihcnt++;
    633 				} else {
    634 					splraise(pf2->ih_ipl);
    635 					if (pf2->ih_ipl > hiipl)
    636 						hiipl = pf2->ih_ipl;
    637 				}
    638 			}
    639 		}
    640 
    641 		/* null out the handler for this function */
    642 
    643 		pf->ih_fct = NULL;
    644 		pf->ih_arg = NULL;
    645 
    646 		/*
    647 		 * if the ih being removed is lower priority than the lowest
    648 		 * priority remaining interrupt, up the priority.
    649 		 */
    650 
    651 #ifdef DIAGNOSTIC
    652 		if (ihcnt == 0) {
    653 			panic("can't remove a handler from a card which has none");
    654 		} else
    655 #endif
    656 		if (ihcnt == 1) {
    657 #ifdef DIAGNOSTIC
    658 			if (pf->sc->ih == NULL)
    659 				panic("disestablishing last function, but card has no ih");
    660 #endif
    661 			pcmcia_chip_intr_disestablish(pf->sc->pct, pf->sc->pch,
    662 			    pf->sc->ih);
    663 			pf->sc->ih = NULL;
    664 		} else if (pf->ih_ipl > hiipl) {
    665 #ifdef DIAGNOSTIC
    666 			if (pf->sc->ih == NULL)
    667 				panic("changing ih ipl, but card has no ih");
    668 #endif
    669 			pcmcia_chip_intr_disestablish(pf->sc->pct, pf->sc->pch,
    670 			    pf->sc->ih);
    671 			pf->sc->ih = pcmcia_chip_intr_establish(pf->sc->pct,
    672 			    pf->sc->pch, pf, hiipl, pcmcia_card_intr, pf->sc);
    673 		}
    674 		if (ihcnt)
    675 			splx(s);
    676 	} else {
    677 		pcmcia_chip_intr_disestablish(pf->sc->pct, pf->sc->pch, ih);
    678 	}
    679 }
    680 
    681 int
    682 pcmcia_card_intr(arg)
    683 	void *arg;
    684 {
    685 	struct pcmcia_softc *sc = arg;
    686 	struct pcmcia_function *pf;
    687 	int reg, ret, ret2;
    688 
    689 	ret = 0;
    690 
    691 	for (pf = sc->card.pf_head.sqh_first; pf != NULL;
    692 	    pf = pf->pf_list.sqe_next) {
    693 #if 0
    694 		printf("%s: intr fct=%d physaddr=%lx cor=%02x csr=%02x pin=%02x",
    695 		       sc->dev.dv_xname, pf->number,
    696 		       pmap_extract(pmap_kernel(),
    697 		           (vm_offset_t) pf->ccrh) + pf->ccr_offset,
    698 		       bus_space_read_1(pf->pf_ccrt, pf->pf_ccrh,
    699 		           pf->pf_ccr_offset + PCMCIA_CCR_OPTION),
    700 		       bus_space_read_1(pf->pf_ccrt, pf->pf_ccrh,
    701 		           pf->pf_ccr_offset + PCMCIA_CCR_STATUS),
    702 		       bus_space_read_1(pf->pf_ccrt, pf->pf_ccrh,
    703 		           pf->pf_ccr_offset + PCMCIA_CCR_PIN));
    704 #endif
    705 		if (pf->ih_fct != NULL &&
    706 		    (pf->ccr_mask & (1 << (PCMCIA_CCR_STATUS / 2)))) {
    707 			reg = pcmcia_ccr_read(pf, PCMCIA_CCR_STATUS);
    708 			if (reg & PCMCIA_CCR_STATUS_INTR) {
    709 				ret2 = (*pf->ih_fct)(pf->ih_arg);
    710 				if (ret2 != 0 && ret == 0)
    711 					ret = ret2;
    712 				reg = pcmcia_ccr_read(pf, PCMCIA_CCR_STATUS);
    713 #if 0
    714 				printf("; csr %02x->%02x",
    715 				    reg, reg & ~PCMCIA_CCR_STATUS_INTR);
    716 #endif
    717 				pcmcia_ccr_write(pf, PCMCIA_CCR_STATUS,
    718 				    reg & ~PCMCIA_CCR_STATUS_INTR);
    719 			}
    720 		}
    721 #if 0
    722 		printf("\n");
    723 #endif
    724 	}
    725 
    726 	return (ret);
    727 }
    728