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