pcmcia.c revision 1.26 1 /* $NetBSD: pcmcia.c,v 1.26 2001/11/13 07:26:34 lukem Exp $ */
2
3 /*
4 * Copyright (c) 1997 Marc Horowitz. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. All advertising materials mentioning features or use of this software
15 * must display the following acknowledgement:
16 * This product includes software developed by Marc Horowitz.
17 * 4. The name of the author may not be used to endorse or promote products
18 * derived from this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
24 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: pcmcia.c,v 1.26 2001/11/13 07:26:34 lukem Exp $");
34
35 #include "opt_pcmciaverbose.h"
36
37 #include <sys/types.h>
38 #include <sys/param.h>
39 #include <sys/systm.h>
40 #include <sys/device.h>
41
42
43 #include <dev/pcmcia/pcmciareg.h>
44 #include <dev/pcmcia/pcmciachip.h>
45 #include <dev/pcmcia/pcmciavar.h>
46 #ifdef IT8368E_LEGACY_MODE /* XXX -uch */
47 #include <arch/hpcmips/dev/it8368var.h>
48 #endif
49
50 #include "locators.h"
51
52 #ifdef PCMCIADEBUG
53 int pcmcia_debug = 0;
54 #define DPRINTF(arg) if (pcmcia_debug) printf arg
55 int pcmciaintr_debug = 0;
56 /* this is done this way to avoid doing lots of conditionals
57 at interrupt level. */
58 #define PCMCIA_CARD_INTR (pcmciaintr_debug?pcmcia_card_intrdebug:pcmcia_card_intr)
59 #else
60 #define DPRINTF(arg)
61 #define PCMCIA_CARD_INTR (pcmcia_card_intr)
62 #endif
63
64 #ifdef PCMCIAVERBOSE
65 int pcmcia_verbose = 1;
66 #else
67 int pcmcia_verbose = 0;
68 #endif
69
70 int pcmcia_match __P((struct device *, struct cfdata *, void *));
71 int pcmcia_submatch __P((struct device *, struct cfdata *, void *));
72 void pcmcia_attach __P((struct device *, struct device *, void *));
73 int pcmcia_print __P((void *, const char *));
74
75 static inline void pcmcia_socket_enable __P((pcmcia_chipset_tag_t,
76 pcmcia_chipset_handle_t *));
77 static inline void pcmcia_socket_disable __P((pcmcia_chipset_tag_t,
78 pcmcia_chipset_handle_t *));
79
80 int pcmcia_card_intr __P((void *));
81 #ifdef PCMCIADEBUG
82 int pcmcia_card_intrdebug __P((void *));
83 #endif
84
85 struct cfattach pcmcia_ca = {
86 sizeof(struct pcmcia_softc), pcmcia_match, pcmcia_attach
87 };
88
89 int
90 pcmcia_ccr_read(pf, ccr)
91 struct pcmcia_function *pf;
92 int ccr;
93 {
94
95 return (bus_space_read_1(pf->pf_ccrt, pf->pf_ccrh,
96 pf->pf_ccr_offset + ccr));
97 }
98
99 void
100 pcmcia_ccr_write(pf, ccr, val)
101 struct pcmcia_function *pf;
102 int ccr;
103 int val;
104 {
105
106 if ((pf->ccr_mask) & (1 << (ccr / 2))) {
107 bus_space_write_1(pf->pf_ccrt, pf->pf_ccrh,
108 pf->pf_ccr_offset + ccr, val);
109 }
110 }
111
112 int
113 pcmcia_match(parent, match, aux)
114 struct device *parent;
115 struct cfdata *match;
116 void *aux;
117 {
118 struct pcmciabus_attach_args *paa = aux;
119
120 if (strcmp(paa->paa_busname, match->cf_driver->cd_name)) {
121 return 0;
122 }
123 /* if the autoconfiguration got this far, there's a socket here */
124 return (1);
125 }
126
127 void
128 pcmcia_attach(parent, self, aux)
129 struct device *parent, *self;
130 void *aux;
131 {
132 struct pcmciabus_attach_args *paa = aux;
133 struct pcmcia_softc *sc = (struct pcmcia_softc *) self;
134
135 printf("\n");
136
137 sc->pct = paa->pct;
138 sc->pch = paa->pch;
139 sc->iobase = paa->iobase;
140 sc->iosize = paa->iosize;
141
142 sc->ih = NULL;
143 }
144
145 int
146 pcmcia_card_attach(dev)
147 struct device *dev;
148 {
149 struct pcmcia_softc *sc = (struct pcmcia_softc *) dev;
150 struct pcmcia_function *pf;
151 struct pcmcia_attach_args paa;
152 int attached;
153
154 /*
155 * this is here so that when socket_enable calls gettype, trt happens
156 */
157 sc->card.pf_head.sqh_first = NULL;
158
159 pcmcia_chip_socket_enable(sc->pct, sc->pch);
160
161 pcmcia_read_cis(sc);
162
163 pcmcia_chip_socket_disable(sc->pct, sc->pch);
164
165 pcmcia_check_cis_quirks(sc);
166
167 /*
168 * bail now if the card has no functions, or if there was an error in
169 * the cis.
170 */
171
172 if (sc->card.error)
173 return (1);
174 if (sc->card.pf_head.sqh_first == NULL)
175 return (1);
176
177 if (pcmcia_verbose)
178 pcmcia_print_cis(sc);
179
180 attached = 0;
181
182 for (pf = sc->card.pf_head.sqh_first; pf != NULL;
183 pf = pf->pf_list.sqe_next) {
184 if (pf->cfe_head.sqh_first == NULL)
185 continue;
186
187 #ifdef DIAGNOSTIC
188 if (pf->child != NULL) {
189 printf("%s: %s still attached to function %d!\n",
190 sc->dev.dv_xname, pf->child->dv_xname,
191 pf->number);
192 panic("pcmcia_card_attach");
193 }
194 #endif
195 pf->sc = sc;
196 pf->child = NULL;
197 pf->cfe = NULL;
198 pf->ih_fct = NULL;
199 pf->ih_arg = NULL;
200 }
201
202 for (pf = sc->card.pf_head.sqh_first; pf != NULL;
203 pf = pf->pf_list.sqe_next) {
204 if (pf->cfe_head.sqh_first == NULL)
205 continue;
206
207 paa.manufacturer = sc->card.manufacturer;
208 paa.product = sc->card.product;
209 paa.card = &sc->card;
210 paa.pf = pf;
211
212 if ((pf->child = config_found_sm(&sc->dev, &paa, pcmcia_print,
213 pcmcia_submatch)) != NULL)
214 attached++;
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 char devinfo[256];
298
299 if (pnp) {
300 pcmcia_devinfo(card, 1, devinfo, sizeof devinfo);
301 printf("%s at %s, ", devinfo, pnp);
302 }
303 printf(" function %d", pa->pf->number);
304
305 return (UNCONF);
306 }
307
308 void
309 pcmcia_devinfo(card, showhex, cp, cplen)
310 struct pcmcia_card *card;
311 int showhex;
312 char *cp;
313 int cplen;
314 {
315 int i, n;
316
317 for (i = 0; i < 4 && card->cis1_info[i] != NULL && cplen > 0; i++) {
318 n = snprintf(cp, cplen, "%s%s", (i && i != 3) ? ", " : "",
319 card->cis1_info[i]);
320 cp += n;
321 cplen -= n;
322 }
323 if (showhex && cplen > 0)
324 snprintf(cp, cplen, "%s(manufacturer 0x%04x, product 0x%04x)",
325 i ? " " : "", card->manufacturer, card->product);
326 }
327
328 const struct pcmcia_product *
329 pcmcia_product_lookup(pa, tab, ent_size, matchfn)
330 struct pcmcia_attach_args *pa;
331 const struct pcmcia_product *tab;
332 size_t ent_size;
333 pcmcia_product_match_fn matchfn;
334 {
335 const struct pcmcia_product *ent;
336 int matches;
337
338 #ifdef DIAGNOSTIC
339 if (sizeof *ent > ent_size)
340 panic("pcmcia_product_lookup: bogus ent_size %ld",
341 (long) ent_size);
342 #endif
343
344 for (ent = tab;
345 ent->pp_name != NULL;
346 ent = (const struct pcmcia_product *)
347 ((const char *)ent + ent_size)) {
348
349 /* see if it matches vendor/product/function */
350 matches = (pa->manufacturer == ent->pp_vendor) &&
351 (pa->product == ent->pp_product) &&
352 (pa->pf->number == ent->pp_expfunc);
353
354 /* if a separate match function is given, let it override */
355 if (matchfn != NULL)
356 matches = (*matchfn)(pa, ent, matches);
357
358 if (matches)
359 return (ent);
360 }
361 return (NULL);
362 }
363
364 int
365 pcmcia_card_gettype(dev)
366 struct device *dev;
367 {
368 struct pcmcia_softc *sc = (struct pcmcia_softc *)dev;
369 struct pcmcia_function *pf;
370
371 /*
372 * set the iftype to memory if this card has no functions (not yet
373 * probed), or only one function, and that is not initialized yet or
374 * that is memory.
375 */
376 pf = SIMPLEQ_FIRST(&sc->card.pf_head);
377 if (pf == NULL ||
378 (SIMPLEQ_NEXT(pf, pf_list) == NULL &&
379 (pf->cfe == NULL || pf->cfe->iftype == PCMCIA_IFTYPE_MEMORY)))
380 return (PCMCIA_IFTYPE_MEMORY);
381 else
382 return (PCMCIA_IFTYPE_IO);
383 }
384
385 /*
386 * Initialize a PCMCIA function. May be called as long as the function is
387 * disabled.
388 */
389 void
390 pcmcia_function_init(pf, cfe)
391 struct pcmcia_function *pf;
392 struct pcmcia_config_entry *cfe;
393 {
394 if (pf->pf_flags & PFF_ENABLED)
395 panic("pcmcia_function_init: function is enabled");
396
397 /* Remember which configuration entry we are using. */
398 pf->cfe = cfe;
399 }
400
401 static inline void pcmcia_socket_enable(pct, pch)
402 pcmcia_chipset_tag_t pct;
403 pcmcia_chipset_handle_t *pch;
404 {
405 pcmcia_chip_socket_enable(pct, pch);
406 }
407
408 static inline void pcmcia_socket_disable(pct, pch)
409 pcmcia_chipset_tag_t pct;
410 pcmcia_chipset_handle_t *pch;
411 {
412 pcmcia_chip_socket_disable(pct, pch);
413 }
414
415 /* Enable a PCMCIA function */
416 int
417 pcmcia_function_enable(pf)
418 struct pcmcia_function *pf;
419 {
420 struct pcmcia_function *tmp;
421 int reg;
422
423 if (pf->cfe == NULL)
424 panic("pcmcia_function_enable: function not initialized");
425
426 /*
427 * Increase the reference count on the socket, enabling power, if
428 * necessary.
429 */
430 if (pf->sc->sc_enabled_count++ == 0)
431 pcmcia_chip_socket_enable(pf->sc->pct, pf->sc->pch);
432 DPRINTF(("%s: ++enabled_count = %d\n", pf->sc->dev.dv_xname,
433 pf->sc->sc_enabled_count));
434
435 if (pf->pf_flags & PFF_ENABLED) {
436 /*
437 * Don't do anything if we're already enabled.
438 */
439 return (0);
440 }
441
442 /*
443 * it's possible for different functions' CCRs to be in the same
444 * underlying page. Check for that.
445 */
446
447 for (tmp = pf->sc->card.pf_head.sqh_first; tmp != NULL;
448 tmp = tmp->pf_list.sqe_next) {
449 if ((tmp->pf_flags & PFF_ENABLED) &&
450 (pf->ccr_base >= (tmp->ccr_base - tmp->pf_ccr_offset)) &&
451 ((pf->ccr_base + PCMCIA_CCR_SIZE) <=
452 (tmp->ccr_base - tmp->pf_ccr_offset +
453 tmp->pf_ccr_realsize))) {
454 pf->pf_ccrt = tmp->pf_ccrt;
455 pf->pf_ccrh = tmp->pf_ccrh;
456 pf->pf_ccr_realsize = tmp->pf_ccr_realsize;
457
458 /*
459 * pf->pf_ccr_offset = (tmp->pf_ccr_offset -
460 * tmp->ccr_base) + pf->ccr_base;
461 */
462 pf->pf_ccr_offset =
463 (tmp->pf_ccr_offset + pf->ccr_base) -
464 tmp->ccr_base;
465 pf->pf_ccr_window = tmp->pf_ccr_window;
466 break;
467 }
468 }
469
470 if (tmp == NULL) {
471 if (pcmcia_mem_alloc(pf, PCMCIA_CCR_SIZE, &pf->pf_pcmh))
472 goto bad;
473
474 if (pcmcia_mem_map(pf, PCMCIA_MEM_ATTR, pf->ccr_base,
475 PCMCIA_CCR_SIZE, &pf->pf_pcmh, &pf->pf_ccr_offset,
476 &pf->pf_ccr_window)) {
477 pcmcia_mem_free(pf, &pf->pf_pcmh);
478 goto bad;
479 }
480 }
481
482 reg = (pf->cfe->number & PCMCIA_CCR_OPTION_CFINDEX);
483 reg |= PCMCIA_CCR_OPTION_LEVIREQ;
484 if (pcmcia_mfc(pf->sc)) {
485 reg |= (PCMCIA_CCR_OPTION_FUNC_ENABLE |
486 PCMCIA_CCR_OPTION_ADDR_DECODE);
487 if (pf->ih_fct)
488 reg |= PCMCIA_CCR_OPTION_IREQ_ENABLE;
489
490 }
491 pcmcia_ccr_write(pf, PCMCIA_CCR_OPTION, reg);
492
493 reg = 0;
494
495 if ((pf->cfe->flags & PCMCIA_CFE_IO16) == 0)
496 reg |= PCMCIA_CCR_STATUS_IOIS8;
497 if (pf->cfe->flags & PCMCIA_CFE_AUDIO)
498 reg |= PCMCIA_CCR_STATUS_AUDIO;
499 pcmcia_ccr_write(pf, PCMCIA_CCR_STATUS, reg);
500
501 pcmcia_ccr_write(pf, PCMCIA_CCR_SOCKETCOPY, 0);
502
503 if (pcmcia_mfc(pf->sc)) {
504 long tmp, iosize;
505
506 tmp = pf->pf_mfc_iomax - pf->pf_mfc_iobase;
507 /* round up to nearest (2^n)-1 */
508 for (iosize = 1; iosize < tmp; iosize <<= 1)
509 ;
510 iosize--;
511
512 pcmcia_ccr_write(pf, PCMCIA_CCR_IOBASE0,
513 pf->pf_mfc_iobase & 0xff);
514 pcmcia_ccr_write(pf, PCMCIA_CCR_IOBASE1,
515 (pf->pf_mfc_iobase >> 8) & 0xff);
516 pcmcia_ccr_write(pf, PCMCIA_CCR_IOBASE2, 0);
517 pcmcia_ccr_write(pf, PCMCIA_CCR_IOBASE3, 0);
518
519 pcmcia_ccr_write(pf, PCMCIA_CCR_IOSIZE, iosize);
520 }
521
522 #ifdef PCMCIADEBUG
523 if (pcmcia_debug) {
524 for (tmp = pf->sc->card.pf_head.sqh_first; tmp != NULL;
525 tmp = tmp->pf_list.sqe_next) {
526 printf("%s: function %d CCR at %d offset %lx: "
527 "%x %x %x %x, %x %x %x %x, %x\n",
528 tmp->sc->dev.dv_xname, tmp->number,
529 tmp->pf_ccr_window,
530 (unsigned long) tmp->pf_ccr_offset,
531 pcmcia_ccr_read(tmp, 0x00),
532 pcmcia_ccr_read(tmp, 0x02),
533 pcmcia_ccr_read(tmp, 0x04),
534 pcmcia_ccr_read(tmp, 0x06),
535
536 pcmcia_ccr_read(tmp, 0x0A),
537 pcmcia_ccr_read(tmp, 0x0C),
538 pcmcia_ccr_read(tmp, 0x0E),
539 pcmcia_ccr_read(tmp, 0x10),
540
541 pcmcia_ccr_read(tmp, 0x12));
542 }
543 }
544 #endif
545
546 pf->pf_flags |= PFF_ENABLED;
547
548 #ifdef IT8368E_LEGACY_MODE
549 /* return to I/O mode */
550 it8368_mode(pf, IT8368_IO_MODE, IT8368_WIDTH_16);
551 #endif
552 return (0);
553
554 bad:
555 /*
556 * Decrement the reference count, and power down the socket, if
557 * necessary.
558 */
559 if (--pf->sc->sc_enabled_count == 0)
560 pcmcia_chip_socket_disable(pf->sc->pct, pf->sc->pch);
561 DPRINTF(("%s: --enabled_count = %d\n", pf->sc->dev.dv_xname,
562 pf->sc->sc_enabled_count));
563
564 return (1);
565 }
566
567 /* Disable PCMCIA function. */
568 void
569 pcmcia_function_disable(pf)
570 struct pcmcia_function *pf;
571 {
572 struct pcmcia_function *tmp;
573
574 if (pf->cfe == NULL)
575 panic("pcmcia_function_enable: function not initialized");
576
577 if ((pf->pf_flags & PFF_ENABLED) == 0) {
578 /*
579 * Don't do anything if we're already disabled.
580 */
581 return;
582 }
583
584 /*
585 * it's possible for different functions' CCRs to be in the same
586 * underlying page. Check for that. Note we mark us as disabled
587 * first to avoid matching ourself.
588 */
589
590 pf->pf_flags &= ~PFF_ENABLED;
591 for (tmp = pf->sc->card.pf_head.sqh_first; tmp != NULL;
592 tmp = tmp->pf_list.sqe_next) {
593 if ((tmp->pf_flags & PFF_ENABLED) &&
594 (pf->ccr_base >= (tmp->ccr_base - tmp->pf_ccr_offset)) &&
595 ((pf->ccr_base + PCMCIA_CCR_SIZE) <=
596 (tmp->ccr_base - tmp->pf_ccr_offset + tmp->pf_ccr_realsize)))
597 break;
598 }
599
600 /* Not used by anyone else; unmap the CCR. */
601 if (tmp == NULL) {
602 pcmcia_mem_unmap(pf, pf->pf_ccr_window);
603 pcmcia_mem_free(pf, &pf->pf_pcmh);
604 }
605
606 /*
607 * Decrement the reference count, and power down the socket, if
608 * necessary.
609 */
610 if (--pf->sc->sc_enabled_count == 0)
611 pcmcia_chip_socket_disable(pf->sc->pct, pf->sc->pch);
612 DPRINTF(("%s: --enabled_count = %d\n", pf->sc->dev.dv_xname,
613 pf->sc->sc_enabled_count));
614 }
615
616 int
617 pcmcia_io_map(pf, width, offset, size, pcihp, windowp)
618 struct pcmcia_function *pf;
619 int width;
620 bus_addr_t offset;
621 bus_size_t size;
622 struct pcmcia_io_handle *pcihp;
623 int *windowp;
624 {
625 int reg;
626
627 if (pcmcia_chip_io_map(pf->sc->pct, pf->sc->pch,
628 width, offset, size, pcihp, windowp))
629 return (1);
630
631 /*
632 * XXX in the multifunction multi-iospace-per-function case, this
633 * needs to cooperate with io_alloc to make sure that the spaces
634 * don't overlap, and that the ccr's are set correctly
635 */
636
637 if (pcmcia_mfc(pf->sc)) {
638 long tmp, iosize;
639
640 if (pf->pf_mfc_iomax == 0) {
641 pf->pf_mfc_iobase = pcihp->addr + offset;
642 pf->pf_mfc_iomax = pf->pf_mfc_iobase + size;
643 } else {
644 /* this makes the assumption that nothing overlaps */
645 if (pf->pf_mfc_iobase > pcihp->addr + offset)
646 pf->pf_mfc_iobase = pcihp->addr + offset;
647 if (pf->pf_mfc_iomax < pcihp->addr + offset + size)
648 pf->pf_mfc_iomax = pcihp->addr + offset + size;
649 }
650
651 tmp = pf->pf_mfc_iomax - pf->pf_mfc_iobase;
652 /* round up to nearest (2^n)-1 */
653 for (iosize = 1; iosize >= tmp; iosize <<= 1)
654 ;
655 iosize--;
656
657 pcmcia_ccr_write(pf, PCMCIA_CCR_IOBASE0,
658 pf->pf_mfc_iobase & 0xff);
659 pcmcia_ccr_write(pf, PCMCIA_CCR_IOBASE1,
660 (pf->pf_mfc_iobase >> 8) & 0xff);
661 pcmcia_ccr_write(pf, PCMCIA_CCR_IOBASE2, 0);
662 pcmcia_ccr_write(pf, PCMCIA_CCR_IOBASE3, 0);
663
664 pcmcia_ccr_write(pf, PCMCIA_CCR_IOSIZE, iosize);
665
666 reg = pcmcia_ccr_read(pf, PCMCIA_CCR_OPTION);
667 reg |= PCMCIA_CCR_OPTION_ADDR_DECODE;
668 pcmcia_ccr_write(pf, PCMCIA_CCR_OPTION, reg);
669 }
670 return (0);
671 }
672
673 void
674 pcmcia_io_unmap(pf, window)
675 struct pcmcia_function *pf;
676 int window;
677 {
678
679 pcmcia_chip_io_unmap(pf->sc->pct, pf->sc->pch, window);
680
681 /* XXX Anything for multi-function cards? */
682 }
683
684 void *
685 pcmcia_intr_establish(pf, ipl, ih_fct, ih_arg)
686 struct pcmcia_function *pf;
687 int ipl;
688 int (*ih_fct) __P((void *));
689 void *ih_arg;
690 {
691 void *ret;
692
693 /* behave differently if this is a multifunction card */
694
695 if (pcmcia_mfc(pf->sc)) {
696 int s, ihcnt, hiipl, reg;
697 struct pcmcia_function *pf2;
698
699 /*
700 * mask all the ipl's which are already used by this card,
701 * and find the highest ipl number (lowest priority)
702 */
703
704 ihcnt = 0;
705 s = 0; /* this is only here to keep the compiler
706 happy */
707 hiipl = 0; /* this is only here to keep the compiler
708 happy */
709
710 for (pf2 = pf->sc->card.pf_head.sqh_first; pf2 != NULL;
711 pf2 = pf2->pf_list.sqe_next) {
712 if (pf2->ih_fct) {
713 DPRINTF(("%s: function %d has ih_fct %p\n",
714 pf->sc->dev.dv_xname, pf2->number,
715 pf2->ih_fct));
716
717 if (ihcnt == 0) {
718 hiipl = pf2->ih_ipl;
719 } else {
720 if (pf2->ih_ipl > hiipl)
721 hiipl = pf2->ih_ipl;
722 }
723
724 ihcnt++;
725 }
726 }
727
728 /*
729 * establish the real interrupt, changing the ipl if
730 * necessary
731 */
732
733 if (ihcnt == 0) {
734 #ifdef DIAGNOSTIC
735 if (pf->sc->ih != NULL)
736 panic("card has intr handler, but no function does");
737 #endif
738 s = splhigh();
739
740 /* set up the handler for the new function */
741
742 pf->ih_fct = ih_fct;
743 pf->ih_arg = ih_arg;
744 pf->ih_ipl = ipl;
745
746 pf->sc->ih = pcmcia_chip_intr_establish(pf->sc->pct,
747 pf->sc->pch, pf, ipl, PCMCIA_CARD_INTR, pf->sc);
748 splx(s);
749 } else if (ipl > hiipl) {
750 #ifdef DIAGNOSTIC
751 if (pf->sc->ih == NULL)
752 panic("functions have ih, but the card does not");
753 #endif
754
755 /* XXX need #ifdef for splserial on x86 */
756 s = splhigh();
757
758 pcmcia_chip_intr_disestablish(pf->sc->pct, pf->sc->pch,
759 pf->sc->ih);
760
761 /* set up the handler for the new function */
762 pf->ih_fct = ih_fct;
763 pf->ih_arg = ih_arg;
764 pf->ih_ipl = ipl;
765
766 pf->sc->ih = pcmcia_chip_intr_establish(pf->sc->pct,
767 pf->sc->pch, pf, ipl, PCMCIA_CARD_INTR, pf->sc);
768
769 splx(s);
770 } else {
771 s = splhigh();
772
773 /* set up the handler for the new function */
774
775 pf->ih_fct = ih_fct;
776 pf->ih_arg = ih_arg;
777 pf->ih_ipl = ipl;
778
779 splx(s);
780 }
781
782 ret = pf->sc->ih;
783
784 if (ret != NULL) {
785 reg = pcmcia_ccr_read(pf, PCMCIA_CCR_OPTION);
786 reg |= PCMCIA_CCR_OPTION_IREQ_ENABLE;
787 pcmcia_ccr_write(pf, PCMCIA_CCR_OPTION, reg);
788
789 reg = pcmcia_ccr_read(pf, PCMCIA_CCR_STATUS);
790 reg |= PCMCIA_CCR_STATUS_INTRACK;
791 pcmcia_ccr_write(pf, PCMCIA_CCR_STATUS, reg);
792 }
793 } else {
794 ret = pcmcia_chip_intr_establish(pf->sc->pct, pf->sc->pch,
795 pf, ipl, ih_fct, ih_arg);
796 }
797
798 return (ret);
799 }
800
801 void
802 pcmcia_intr_disestablish(pf, ih)
803 struct pcmcia_function *pf;
804 void *ih;
805 {
806 /* behave differently if this is a multifunction card */
807
808 if (pcmcia_mfc(pf->sc)) {
809 int s, ihcnt, hiipl;
810 struct pcmcia_function *pf2;
811
812 /*
813 * mask all the ipl's which are already used by this card,
814 * and find the highest ipl number (lowest priority). Skip
815 * the current function.
816 */
817
818 ihcnt = 0;
819 s = 0; /* avoid compiler warning */
820 hiipl = 0; /* avoid compiler warning */
821
822 for (pf2 = pf->sc->card.pf_head.sqh_first; pf2 != NULL;
823 pf2 = pf2->pf_list.sqe_next) {
824 if (pf2 == pf)
825 continue;
826
827 if (pf2->ih_fct) {
828 if (ihcnt == 0) {
829 hiipl = pf2->ih_ipl;
830 } else {
831 if (pf2->ih_ipl > hiipl)
832 hiipl = pf2->ih_ipl;
833 }
834 ihcnt++;
835 }
836 }
837
838 /*
839 * If the ih being removed is lower priority than the lowest
840 * priority remaining interrupt, up the priority.
841 */
842
843 /*
844 * ihcnt is the number of interrupt handlers *not* including
845 * the one about to be removed.
846 */
847
848 if (ihcnt == 0) {
849 int reg;
850
851 #ifdef DIAGNOSTIC
852 if (pf->sc->ih == NULL)
853 panic("disestablishing last function, but card has no ih");
854 #endif
855 pcmcia_chip_intr_disestablish(pf->sc->pct, pf->sc->pch,
856 pf->sc->ih);
857
858 reg = pcmcia_ccr_read(pf, PCMCIA_CCR_OPTION);
859 reg &= ~PCMCIA_CCR_OPTION_IREQ_ENABLE;
860 pcmcia_ccr_write(pf, PCMCIA_CCR_OPTION, reg);
861
862 pf->ih_fct = NULL;
863 pf->ih_arg = NULL;
864
865 pf->sc->ih = NULL;
866 } else if (pf->ih_ipl > hiipl) {
867 #ifdef DIAGNOSTIC
868 if (pf->sc->ih == NULL)
869 panic("changing ih ipl, but card has no ih");
870 #endif
871 /* XXX need #ifdef for splserial on x86 */
872 s = splhigh();
873
874 pcmcia_chip_intr_disestablish(pf->sc->pct, pf->sc->pch,
875 pf->sc->ih);
876 pf->sc->ih = pcmcia_chip_intr_establish(pf->sc->pct,
877 pf->sc->pch, pf, hiipl, PCMCIA_CARD_INTR, pf->sc);
878
879 /* null out the handler for this function */
880
881 pf->ih_fct = NULL;
882 pf->ih_arg = NULL;
883
884 splx(s);
885 } else {
886 s = splhigh();
887
888 pf->ih_fct = NULL;
889 pf->ih_arg = NULL;
890
891 splx(s);
892 }
893 } else {
894 pcmcia_chip_intr_disestablish(pf->sc->pct, pf->sc->pch, ih);
895 }
896 }
897
898 int
899 pcmcia_card_intr(arg)
900 void *arg;
901 {
902 struct pcmcia_softc *sc = arg;
903 struct pcmcia_function *pf;
904 int reg, ret, ret2;
905
906 ret = 0;
907
908 for (pf = sc->card.pf_head.sqh_first; pf != NULL;
909 pf = pf->pf_list.sqe_next) {
910 if (pf->ih_fct != NULL &&
911 (pf->ccr_mask & (1 << (PCMCIA_CCR_STATUS / 2)))) {
912 reg = pcmcia_ccr_read(pf, PCMCIA_CCR_STATUS);
913 if (reg & PCMCIA_CCR_STATUS_INTR) {
914 ret2 = (*pf->ih_fct)(pf->ih_arg);
915 if (ret2 != 0 && ret == 0)
916 ret = ret2;
917 reg = pcmcia_ccr_read(pf, PCMCIA_CCR_STATUS);
918 pcmcia_ccr_write(pf, PCMCIA_CCR_STATUS,
919 reg & ~PCMCIA_CCR_STATUS_INTR);
920 }
921 }
922 }
923
924 return (ret);
925 }
926
927 #ifdef PCMCIADEBUG
928 int
929 pcmcia_card_intrdebug(arg)
930 void *arg;
931 {
932 struct pcmcia_softc *sc = arg;
933 struct pcmcia_function *pf;
934 int reg, ret, ret2;
935
936 ret = 0;
937
938 for (pf = sc->card.pf_head.sqh_first; pf != NULL;
939 pf = pf->pf_list.sqe_next) {
940 printf("%s: intr flags=%x fct=%d cor=%02x csr=%02x pin=%02x",
941 sc->dev.dv_xname, pf->pf_flags, pf->number,
942 pcmcia_ccr_read(pf, PCMCIA_CCR_OPTION),
943 pcmcia_ccr_read(pf, PCMCIA_CCR_STATUS),
944 pcmcia_ccr_read(pf, PCMCIA_CCR_PIN));
945 if (pf->ih_fct != NULL &&
946 (pf->ccr_mask & (1 << (PCMCIA_CCR_STATUS / 2)))) {
947 reg = pcmcia_ccr_read(pf, PCMCIA_CCR_STATUS);
948 if (reg & PCMCIA_CCR_STATUS_INTR) {
949 ret2 = (*pf->ih_fct)(pf->ih_arg);
950 if (ret2 != 0 && ret == 0)
951 ret = ret2;
952 reg = pcmcia_ccr_read(pf, PCMCIA_CCR_STATUS);
953 printf("; csr %02x->%02x",
954 reg, reg & ~PCMCIA_CCR_STATUS_INTR);
955 pcmcia_ccr_write(pf, PCMCIA_CCR_STATUS,
956 reg & ~PCMCIA_CCR_STATUS_INTR);
957 }
958 }
959 printf("\n");
960 }
961
962 return (ret);
963 }
964 #endif
965