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