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