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