pcmcia.c revision 1.9 1 /* $NetBSD: pcmcia.c,v 1.9 1998/08/13 02:10:55 eeh 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 #include "locators.h"
49
50 #ifdef PCMCIADEBUG
51 int pcmcia_debug = 0;
52 #define DPRINTF(arg) if (pcmcia_debug) printf arg
53 #else
54 #define DPRINTF(arg)
55 #endif
56
57 #ifdef PCMCIAVERBOSE
58 int pcmcia_verbose = 1;
59 #else
60 int pcmcia_verbose = 0;
61 #endif
62
63 int pcmcia_match __P((struct device *, struct cfdata *, void *));
64 int pcmcia_submatch __P((struct device *, struct cfdata *, void *));
65 void pcmcia_attach __P((struct device *, struct device *, void *));
66 int pcmcia_print __P((void *, const char *));
67
68 static inline void pcmcia_socket_enable __P((pcmcia_chipset_tag_t,
69 pcmcia_chipset_handle_t *));
70 static inline void pcmcia_socket_disable __P((pcmcia_chipset_tag_t,
71 pcmcia_chipset_handle_t *));
72
73 int pcmcia_card_intr __P((void *));
74
75 struct cfattach pcmcia_ca = {
76 sizeof(struct pcmcia_softc), pcmcia_match, pcmcia_attach
77 };
78
79 int
80 pcmcia_ccr_read(pf, ccr)
81 struct pcmcia_function *pf;
82 int ccr;
83 {
84
85 return (bus_space_read_1(pf->pf_ccrt, pf->pf_ccrh,
86 pf->pf_ccr_offset + ccr));
87 }
88
89 void
90 pcmcia_ccr_write(pf, ccr, val)
91 struct pcmcia_function *pf;
92 int ccr;
93 int val;
94 {
95
96 if ((pf->ccr_mask) & (1 << (ccr / 2))) {
97 bus_space_write_1(pf->pf_ccrt, pf->pf_ccrh,
98 pf->pf_ccr_offset + ccr, val);
99 }
100 }
101
102 int
103 pcmcia_match(parent, match, aux)
104 struct device *parent;
105 struct cfdata *match;
106 void *aux;
107 {
108 /* if the autoconfiguration got this far, there's a socket here */
109 return (1);
110 }
111
112 void
113 pcmcia_attach(parent, self, aux)
114 struct device *parent, *self;
115 void *aux;
116 {
117 struct pcmciabus_attach_args *paa = aux;
118 struct pcmcia_softc *sc = (struct pcmcia_softc *) self;
119
120 printf("\n");
121
122 sc->pct = paa->pct;
123 sc->pch = paa->pch;
124 sc->iobase = paa->iobase;
125 sc->iosize = paa->iosize;
126
127 sc->ih = NULL;
128 }
129
130 int
131 pcmcia_card_attach(dev)
132 struct device *dev;
133 {
134 struct pcmcia_softc *sc = (struct pcmcia_softc *) dev;
135 struct pcmcia_function *pf;
136 struct pcmcia_attach_args paa;
137 int attached;
138
139 /*
140 * this is here so that when socket_enable calls gettype, trt happens
141 */
142 sc->card.pf_head.sqh_first = NULL;
143
144 pcmcia_chip_socket_enable(sc->pct, sc->pch);
145
146 pcmcia_read_cis(sc);
147
148 pcmcia_chip_socket_disable(sc->pct, sc->pch);
149
150 /*
151 * bail now if the card has no functions, or if there was an error in
152 * the cis.
153 */
154
155 if (sc->card.error)
156 return (1);
157 if (sc->card.pf_head.sqh_first == NULL)
158 return (1);
159
160 if (pcmcia_verbose)
161 pcmcia_print_cis(sc);
162
163 attached = 0;
164
165 for (pf = sc->card.pf_head.sqh_first; pf != NULL;
166 pf = pf->pf_list.sqe_next) {
167 if (pf->cfe_head.sqh_first == NULL)
168 continue;
169
170 pf->sc = sc;
171 pf->cfe = NULL;
172 pf->ih_fct = NULL;
173 pf->ih_arg = NULL;
174 }
175
176 for (pf = sc->card.pf_head.sqh_first; pf != NULL;
177 pf = pf->pf_list.sqe_next) {
178 if (pf->cfe_head.sqh_first == NULL)
179 continue;
180
181 paa.manufacturer = sc->card.manufacturer;
182 paa.product = sc->card.product;
183 paa.card = &sc->card;
184 paa.pf = pf;
185
186 if (config_found_sm(&sc->dev, &paa, pcmcia_print,
187 pcmcia_submatch)) {
188 attached++;
189
190 DPRINTF(("%s: function %d CCR at %d "
191 "offset %lx: %x %x %x %x, %x %x %x %x, %x\n",
192 sc->dev.dv_xname, pf->number,
193 pf->pf_ccr_window, pf->pf_ccr_offset,
194 pcmcia_ccr_read(pf, 0x00),
195 pcmcia_ccr_read(pf, 0x02), pcmcia_ccr_read(pf, 0x04),
196 pcmcia_ccr_read(pf, 0x06), pcmcia_ccr_read(pf, 0x0A),
197 pcmcia_ccr_read(pf, 0x0C), pcmcia_ccr_read(pf, 0x0E),
198 pcmcia_ccr_read(pf, 0x10), pcmcia_ccr_read(pf, 0x12)));
199 }
200 }
201
202 return (attached ? 0 : 1);
203 }
204
205 void
206 pcmcia_card_detach(dev)
207 struct device *dev;
208 {
209 /* struct pcmcia_softc *sc = (struct pcmcia_softc *) dev; */
210 /* don't do anything yet */
211 }
212
213 int
214 pcmcia_submatch(parent, cf, aux)
215 struct device *parent;
216 struct cfdata *cf;
217 void *aux;
218 {
219 struct pcmcia_attach_args *paa = aux;
220
221 if (cf->cf_loc[PCMCIACF_FUNCTION] != PCMCIACF_FUNCTION_DEFAULT &&
222 cf->cf_loc[PCMCIACF_FUNCTION] != paa->pf->number)
223 return (0);
224
225 return ((*cf->cf_attach->ca_match)(parent, cf, aux));
226 }
227
228 int
229 pcmcia_print(arg, pnp)
230 void *arg;
231 const char *pnp;
232 {
233 struct pcmcia_attach_args *pa = arg;
234 struct pcmcia_softc *sc = pa->pf->sc;
235 struct pcmcia_card *card = &sc->card;
236 int i;
237
238 if (pnp) {
239 for (i = 0; i < 4; i++) {
240 if (card->cis1_info[i] == NULL)
241 break;
242 if (i)
243 printf(", ");
244 printf("%s", card->cis1_info[i]);
245 }
246 if (i)
247 printf(" ");
248 printf("(manufacturer 0x%x, product 0x%x)", card->manufacturer,
249 card->product);
250 }
251 printf(" function %d", pa->pf->number);
252
253 return (UNCONF);
254 }
255
256 int
257 pcmcia_card_gettype(dev)
258 struct device *dev;
259 {
260 struct pcmcia_softc *sc = (struct pcmcia_softc *)dev;
261 struct pcmcia_function *pf;
262
263 /*
264 * set the iftype to memory if this card has no functions (not yet
265 * probed), or only one function, and that is not initialized yet or
266 * that is memory.
267 */
268 pf = SIMPLEQ_FIRST(&sc->card.pf_head);
269 if (pf == NULL ||
270 (SIMPLEQ_NEXT(pf, pf_list) == NULL &&
271 (pf->cfe == NULL || pf->cfe->iftype == PCMCIA_IFTYPE_MEMORY)))
272 return (PCMCIA_IFTYPE_MEMORY);
273 else
274 return (PCMCIA_IFTYPE_IO);
275 }
276
277 /*
278 * Initialize a PCMCIA function. May be called as long as the function is
279 * disabled.
280 */
281 void
282 pcmcia_function_init(pf, cfe)
283 struct pcmcia_function *pf;
284 struct pcmcia_config_entry *cfe;
285 {
286 if (pf->pf_flags & PFF_ENABLED)
287 panic("pcmcia_function_init: function is enabled");
288
289 /* Remember which configuration entry we are using. */
290 pf->cfe = cfe;
291 }
292
293 static inline void pcmcia_socket_enable(pct, pch)
294 pcmcia_chipset_tag_t pct;
295 pcmcia_chipset_handle_t *pch;
296 {
297 pcmcia_chip_socket_enable(pct, pch);
298 }
299
300 static inline void pcmcia_socket_disable(pct, pch)
301 pcmcia_chipset_tag_t pct;
302 pcmcia_chipset_handle_t *pch;
303 {
304 pcmcia_chip_socket_disable(pct, pch);
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 /*
319 * Increase the reference count on the socket, enabling power, if
320 * necessary.
321 */
322 if (pf->sc->sc_enabled_count++ == 0)
323 pcmcia_chip_socket_enable(pf->sc->pct, pf->sc->pch);
324 DPRINTF(("%s: ++enabled_count = %d\n", pf->sc->dev.dv_xname,
325 pf->sc->sc_enabled_count));
326
327 if (pf->pf_flags & PFF_ENABLED) {
328 /*
329 * Don't do anything if we're already enabled.
330 */
331 return (0);
332 }
333
334 /*
335 * it's possible for different functions' CCRs to be in the same
336 * underlying page. Check for that.
337 */
338
339 for (tmp = pf->sc->card.pf_head.sqh_first; tmp != NULL;
340 tmp = tmp->pf_list.sqe_next) {
341 if ((tmp->pf_flags & PFF_ENABLED) &&
342 (pf->ccr_base >= (tmp->ccr_base - tmp->pf_ccr_offset)) &&
343 ((pf->ccr_base + PCMCIA_CCR_SIZE) <=
344 (tmp->ccr_base - tmp->pf_ccr_offset +
345 tmp->pf_ccr_realsize))) {
346 pf->pf_ccrt = tmp->pf_ccrt;
347 pf->pf_ccrh = tmp->pf_ccrh;
348 pf->pf_ccr_realsize = tmp->pf_ccr_realsize;
349
350 /*
351 * pf->pf_ccr_offset = (tmp->pf_ccr_offset -
352 * tmp->ccr_base) + pf->ccr_base;
353 */
354 pf->pf_ccr_offset =
355 (tmp->pf_ccr_offset + pf->ccr_base) -
356 tmp->ccr_base;
357 pf->pf_ccr_window = tmp->pf_ccr_window;
358 break;
359 }
360 }
361
362 if (tmp == NULL) {
363 if (pcmcia_mem_alloc(pf, PCMCIA_CCR_SIZE, &pf->pf_pcmh))
364 goto bad;
365
366 if (pcmcia_mem_map(pf, PCMCIA_MEM_ATTR, pf->ccr_base,
367 PCMCIA_CCR_SIZE, &pf->pf_pcmh, &pf->pf_ccr_offset,
368 &pf->pf_ccr_window)) {
369 pcmcia_mem_free(pf, &pf->pf_pcmh);
370 goto bad;
371 }
372 }
373
374 reg = (pf->cfe->number & PCMCIA_CCR_OPTION_CFINDEX);
375 reg |= PCMCIA_CCR_OPTION_LEVIREQ;
376 if (pcmcia_mfc(pf->sc)) {
377 reg |= (PCMCIA_CCR_OPTION_FUNC_ENABLE |
378 PCMCIA_CCR_OPTION_ADDR_DECODE);
379 if (pf->ih_fct)
380 reg |= PCMCIA_CCR_OPTION_IREQ_ENABLE;
381
382 }
383 pcmcia_ccr_write(pf, PCMCIA_CCR_OPTION, reg);
384
385 reg = 0;
386
387 if ((pf->cfe->flags & PCMCIA_CFE_IO16) == 0)
388 reg |= PCMCIA_CCR_STATUS_IOIS8;
389 if (pf->cfe->flags & PCMCIA_CFE_AUDIO)
390 reg |= PCMCIA_CCR_STATUS_AUDIO;
391 pcmcia_ccr_write(pf, PCMCIA_CCR_STATUS, reg);
392
393 pcmcia_ccr_write(pf, PCMCIA_CCR_SOCKETCOPY, 0);
394
395 if (pcmcia_mfc(pf->sc)) {
396 long tmp, iosize;
397
398 tmp = pf->pf_mfc_iomax - pf->pf_mfc_iobase;
399 /* round up to nearest (2^n)-1 */
400 for (iosize = 1; iosize < tmp; iosize <<= 1)
401 ;
402 iosize--;
403
404 pcmcia_ccr_write(pf, PCMCIA_CCR_IOBASE0,
405 pf->pf_mfc_iobase & 0xff);
406 pcmcia_ccr_write(pf, PCMCIA_CCR_IOBASE1,
407 (pf->pf_mfc_iobase >> 8) & 0xff);
408 pcmcia_ccr_write(pf, PCMCIA_CCR_IOBASE2, 0);
409 pcmcia_ccr_write(pf, PCMCIA_CCR_IOBASE3, 0);
410
411 pcmcia_ccr_write(pf, PCMCIA_CCR_IOSIZE, iosize);
412 }
413
414 DPRINTF(("%s: function %d CCR at %d offset %lx: "
415 "%x %x %x %x, %x %x %x %x, %x\n",
416 pf->sc->dev.dv_xname, pf->number,
417 pf->pf_ccr_window, pf->pf_ccr_offset,
418 pcmcia_ccr_read(pf, 0x00), pcmcia_ccr_read(pf, 0x02),
419 pcmcia_ccr_read(pf, 0x04), pcmcia_ccr_read(pf, 0x06),
420
421 pcmcia_ccr_read(pf, 0x0A), pcmcia_ccr_read(pf, 0x0C),
422 pcmcia_ccr_read(pf, 0x0E), pcmcia_ccr_read(pf, 0x10),
423
424 pcmcia_ccr_read(pf, 0x12)));
425
426 pf->pf_flags |= PFF_ENABLED;
427 return (0);
428
429 bad:
430 /*
431 * Decrement the reference count, and power down the socket, if
432 * necessary.
433 */
434 if (--pf->sc->sc_enabled_count == 0)
435 pcmcia_chip_socket_disable(pf->sc->pct, pf->sc->pch);
436 DPRINTF(("%s: --enabled_count = %d\n", pf->sc->dev.dv_xname,
437 pf->sc->sc_enabled_count));
438
439 return (1);
440 }
441
442 /* Disable PCMCIA function. */
443 void
444 pcmcia_function_disable(pf)
445 struct pcmcia_function *pf;
446 {
447 struct pcmcia_function *tmp;
448
449 if (pf->cfe == NULL)
450 panic("pcmcia_function_enable: function not initialized");
451
452 if ((pf->pf_flags & PFF_ENABLED) == 0) {
453 /*
454 * Don't do anything if we're already disabled.
455 */
456 return;
457 }
458
459 /*
460 * it's possible for different functions' CCRs to be in the same
461 * underlying page. Check for that. Note we mark us as disabled
462 * first to avoid matching ourself.
463 */
464
465 pf->pf_flags &= ~PFF_ENABLED;
466 for (tmp = pf->sc->card.pf_head.sqh_first; tmp != NULL;
467 tmp = tmp->pf_list.sqe_next) {
468 if ((tmp->pf_flags & PFF_ENABLED) &&
469 (pf->ccr_base >= (tmp->ccr_base - tmp->pf_ccr_offset)) &&
470 ((pf->ccr_base + PCMCIA_CCR_SIZE) <=
471 (tmp->ccr_base - tmp->pf_ccr_offset + tmp->pf_ccr_realsize)))
472 break;
473 }
474
475 /* Not used by anyone else; unmap the CCR. */
476 if (tmp == NULL) {
477 pcmcia_mem_unmap(pf, pf->pf_ccr_window);
478 pcmcia_mem_free(pf, &pf->pf_pcmh);
479 }
480
481 /*
482 * Decrement the reference count, and power down the socket, if
483 * necessary.
484 */
485 if (--pf->sc->sc_enabled_count == 0)
486 pcmcia_chip_socket_disable(pf->sc->pct, pf->sc->pch);
487 DPRINTF(("%s: --enabled_count = %d\n", pf->sc->dev.dv_xname,
488 pf->sc->sc_enabled_count));
489 }
490
491 int
492 pcmcia_io_map(pf, width, offset, size, pcihp, windowp)
493 struct pcmcia_function *pf;
494 int width;
495 bus_addr_t offset;
496 bus_size_t size;
497 struct pcmcia_io_handle *pcihp;
498 int *windowp;
499 {
500 int reg;
501
502 if (pcmcia_chip_io_map(pf->sc->pct, pf->sc->pch,
503 width, offset, size, pcihp, windowp))
504 return (1);
505
506 /*
507 * XXX in the multifunction multi-iospace-per-function case, this
508 * needs to cooperate with io_alloc to make sure that the spaces
509 * don't overlap, and that the ccr's are set correctly
510 */
511
512 if (pcmcia_mfc(pf->sc)) {
513 long tmp, iosize;
514
515 if (pf->pf_mfc_iomax == 0) {
516 pf->pf_mfc_iobase = pcihp->addr + offset;
517 pf->pf_mfc_iomax = pf->pf_mfc_iobase + size;
518 } else {
519 /* this makes the assumption that nothing overlaps */
520 if (pf->pf_mfc_iobase > pcihp->addr + offset)
521 pf->pf_mfc_iobase = pcihp->addr + offset;
522 if (pf->pf_mfc_iomax < pcihp->addr + offset + size)
523 pf->pf_mfc_iomax = pcihp->addr + offset + size;
524 }
525
526 tmp = pf->pf_mfc_iomax - pf->pf_mfc_iobase;
527 /* round up to nearest (2^n)-1 */
528 for (iosize = 1; iosize >= tmp; iosize <<= 1)
529 ;
530 iosize--;
531
532 pcmcia_ccr_write(pf, PCMCIA_CCR_IOBASE0,
533 pf->pf_mfc_iobase & 0xff);
534 pcmcia_ccr_write(pf, PCMCIA_CCR_IOBASE1,
535 (pf->pf_mfc_iobase >> 8) & 0xff);
536 pcmcia_ccr_write(pf, PCMCIA_CCR_IOBASE2, 0);
537 pcmcia_ccr_write(pf, PCMCIA_CCR_IOBASE3, 0);
538
539 pcmcia_ccr_write(pf, PCMCIA_CCR_IOSIZE, iosize);
540
541 reg = pcmcia_ccr_read(pf, PCMCIA_CCR_OPTION);
542 reg |= PCMCIA_CCR_OPTION_ADDR_DECODE;
543 pcmcia_ccr_write(pf, PCMCIA_CCR_OPTION, reg);
544 }
545 return (0);
546 }
547
548 void *
549 pcmcia_intr_establish(pf, ipl, ih_fct, ih_arg)
550 struct pcmcia_function *pf;
551 int ipl;
552 int (*ih_fct) __P((void *));
553 void *ih_arg;
554 {
555 void *ret;
556
557 /* behave differently if this is a multifunction card */
558
559 if (pcmcia_mfc(pf->sc)) {
560 int s, ihcnt, hiipl, reg;
561 struct pcmcia_function *pf2;
562
563 /*
564 * mask all the ipl's which are already used by this card,
565 * and find the highest ipl number (lowest priority)
566 */
567
568 ihcnt = 0;
569 s = 0; /* this is only here to keep the compiler
570 happy */
571 hiipl = 0; /* this is only here to keep the compiler
572 happy */
573
574 for (pf2 = pf->sc->card.pf_head.sqh_first; pf2 != NULL;
575 pf2 = pf2->pf_list.sqe_next) {
576 if (pf2->ih_fct) {
577 DPRINTF(("%s: function %d has ih_fct %p\n",
578 pf->sc->dev.dv_xname, pf2->number,
579 pf2->ih_fct));
580
581 if (ihcnt == 0) {
582 hiipl = pf2->ih_ipl;
583 } else {
584 if (pf2->ih_ipl > hiipl)
585 hiipl = pf2->ih_ipl;
586 }
587
588 ihcnt++;
589 }
590 }
591
592 /*
593 * establish the real interrupt, changing the ipl if
594 * necessary
595 */
596
597 if (ihcnt == 0) {
598 #ifdef DIAGNOSTIC
599 if (pf->sc->ih != NULL)
600 panic("card has intr handler, but no function does");
601 #endif
602 s = splhigh();
603
604 /* set up the handler for the new function */
605
606 pf->ih_fct = ih_fct;
607 pf->ih_arg = ih_arg;
608 pf->ih_ipl = ipl;
609
610 pf->sc->ih = pcmcia_chip_intr_establish(pf->sc->pct,
611 pf->sc->pch, pf, ipl, pcmcia_card_intr, pf->sc);
612 splx(s);
613 } else if (ipl > hiipl) {
614 #ifdef DIAGNOSTIC
615 if (pf->sc->ih == NULL)
616 panic("functions have ih, but the card does not");
617 #endif
618
619 /* XXX need #ifdef for splserial on x86 */
620 s = splhigh();
621
622 pcmcia_chip_intr_disestablish(pf->sc->pct, pf->sc->pch,
623 pf->sc->ih);
624
625 /* set up the handler for the new function */
626 pf->ih_fct = ih_fct;
627 pf->ih_arg = ih_arg;
628 pf->ih_ipl = ipl;
629
630 pf->sc->ih = pcmcia_chip_intr_establish(pf->sc->pct,
631 pf->sc->pch, pf, ipl, pcmcia_card_intr, pf->sc);
632
633 splx(s);
634 } else {
635 s = splhigh();
636
637 /* set up the handler for the new function */
638
639 pf->ih_fct = ih_fct;
640 pf->ih_arg = ih_arg;
641 pf->ih_ipl = ipl;
642
643 splx(s);
644 }
645
646 ret = pf->sc->ih;
647
648 if (ret != NULL) {
649 reg = pcmcia_ccr_read(pf, PCMCIA_CCR_OPTION);
650 reg |= PCMCIA_CCR_OPTION_IREQ_ENABLE;
651 pcmcia_ccr_write(pf, PCMCIA_CCR_OPTION, reg);
652
653 reg = pcmcia_ccr_read(pf, PCMCIA_CCR_STATUS);
654 reg |= PCMCIA_CCR_STATUS_INTRACK;
655 pcmcia_ccr_write(pf, PCMCIA_CCR_STATUS, reg);
656 }
657 } else {
658 ret = pcmcia_chip_intr_establish(pf->sc->pct, pf->sc->pch,
659 pf, ipl, ih_fct, ih_arg);
660 }
661
662 return (ret);
663 }
664
665 void
666 pcmcia_intr_disestablish(pf, ih)
667 struct pcmcia_function *pf;
668 void *ih;
669 {
670 /* behave differently if this is a multifunction card */
671
672 if (pcmcia_mfc(pf->sc)) {
673 int s, ihcnt, hiipl;
674 struct pcmcia_function *pf2;
675
676 /*
677 * mask all the ipl's which are already used by this card,
678 * and find the highest ipl number (lowest priority). Skip
679 * the current function.
680 */
681
682 ihcnt = 0;
683 s = 0; /* this is only here to keep the compipler
684 happy */
685 hiipl = 0; /* this is only here to keep the compipler
686 happy */
687
688 for (pf2 = pf->sc->card.pf_head.sqh_first; pf2 != NULL;
689 pf2 = pf2->pf_list.sqe_next) {
690 if (pf2 == pf)
691 continue;
692
693 if (pf2->ih_fct) {
694 if (ihcnt == 0) {
695 hiipl = pf2->ih_ipl;
696 } else {
697 if (pf2->ih_ipl > hiipl)
698 hiipl = pf2->ih_ipl;
699 }
700 ihcnt++;
701 }
702 }
703
704 /*
705 * if the ih being removed is lower priority than the lowest
706 * priority remaining interrupt, up the priority.
707 */
708
709 /* ihcnt is the number of interrupt handlers *not* including
710 the one about to be removed. */
711
712 if (ihcnt == 0) {
713 int reg;
714
715 #ifdef DIAGNOSTIC
716 if (pf->sc->ih == NULL)
717 panic("disestablishing last function, but card has no ih");
718 #endif
719 pcmcia_chip_intr_disestablish(pf->sc->pct, pf->sc->pch,
720 pf->sc->ih);
721
722 reg = pcmcia_ccr_read(pf, PCMCIA_CCR_OPTION);
723 reg &= ~PCMCIA_CCR_OPTION_IREQ_ENABLE;
724 pcmcia_ccr_write(pf, PCMCIA_CCR_OPTION, reg);
725
726 pf->ih_fct = NULL;
727 pf->ih_arg = NULL;
728
729 pf->sc->ih = NULL;
730 } else if (pf->ih_ipl > hiipl) {
731 #ifdef DIAGNOSTIC
732 if (pf->sc->ih == NULL)
733 panic("changing ih ipl, but card has no ih");
734 #endif
735 /* XXX need #ifdef for splserial on x86 */
736 s = splhigh();
737
738 pcmcia_chip_intr_disestablish(pf->sc->pct, pf->sc->pch,
739 pf->sc->ih);
740 pf->sc->ih = pcmcia_chip_intr_establish(pf->sc->pct,
741 pf->sc->pch, pf, hiipl, pcmcia_card_intr, pf->sc);
742
743 /* null out the handler for this function */
744
745 pf->ih_fct = NULL;
746 pf->ih_arg = NULL;
747
748 splx(s);
749 } else {
750 s = splhigh();
751
752 pf->ih_fct = NULL;
753 pf->ih_arg = NULL;
754
755 splx(s);
756 }
757 } else {
758 pcmcia_chip_intr_disestablish(pf->sc->pct, pf->sc->pch, ih);
759 }
760 }
761
762 int
763 pcmcia_card_intr(arg)
764 void *arg;
765 {
766 struct pcmcia_softc *sc = arg;
767 struct pcmcia_function *pf;
768 int reg, ret, ret2;
769
770 ret = 0;
771
772 for (pf = sc->card.pf_head.sqh_first; pf != NULL;
773 pf = pf->pf_list.sqe_next) {
774 #if 0
775 printf("%s: intr flags=%x fct=%d physaddr=%lx cor=%02x csr=%02x pin=%02x",
776 sc->dev.dv_xname, pf->pf_flags, pf->number,
777 pmap_extract(pmap_kernel(),
778 (vaddr_t) pf->pf_ccrh) + pf->pf_ccr_offset,
779 pcmcia_ccr_read(pf, PCMCIA_CCR_OPTION),
780 pcmcia_ccr_read(pf, PCMCIA_CCR_STATUS),
781 pcmcia_ccr_read(pf, PCMCIA_CCR_PIN));
782 #endif
783 if (pf->ih_fct != NULL &&
784 (pf->ccr_mask & (1 << (PCMCIA_CCR_STATUS / 2)))) {
785 reg = pcmcia_ccr_read(pf, PCMCIA_CCR_STATUS);
786 if (reg & PCMCIA_CCR_STATUS_INTR) {
787 ret2 = (*pf->ih_fct)(pf->ih_arg);
788 if (ret2 != 0 && ret == 0)
789 ret = ret2;
790 reg = pcmcia_ccr_read(pf, PCMCIA_CCR_STATUS);
791 #if 0
792 printf("; csr %02x->%02x",
793 reg, reg & ~PCMCIA_CCR_STATUS_INTR);
794 #endif
795 pcmcia_ccr_write(pf, PCMCIA_CCR_STATUS,
796 reg & ~PCMCIA_CCR_STATUS_INTR);
797 }
798 }
799 #if 0
800 printf("\n");
801 #endif
802 }
803
804 return (ret);
805 }
806