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