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