Annotation of sys/dev/pcmcia/pcmcia.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: pcmcia.c,v 1.37 2006/04/16 20:43:12 miod 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
! 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
! 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
! 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
! 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
! 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
! 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: /*
! 184: * Bail now if there was an error in the CIS.
! 185: */
! 186:
! 187: if (sc->card.error)
! 188: return (1);
! 189:
! 190: #if 0
! 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
! 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
! 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
! 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
! 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: if (i != 0)
! 340: printf("\"");
! 341:
! 342: if (card->manufacturer != PCMCIA_VENDOR_INVALID &&
! 343: card->product != PCMCIA_PRODUCT_INVALID) {
! 344: if (i != 0)
! 345: printf(" ");
! 346: printf("(");
! 347: if (card->manufacturer != PCMCIA_VENDOR_INVALID)
! 348: printf("manufacturer 0x%x%s",
! 349: card->manufacturer,
! 350: card->product == PCMCIA_PRODUCT_INVALID ?
! 351: "" : ", ");
! 352: if (card->product != PCMCIA_PRODUCT_INVALID)
! 353: printf("product 0x%x",
! 354: card->product);
! 355: printf(")");
! 356: }
! 357: if (i != 0)
! 358: printf(" ");
! 359: printf("at %s", pnp);
! 360: }
! 361: printf(" function %d", pa->pf->number);
! 362:
! 363: if (!pnp) {
! 364: for (i = 0; i < 3 && card->cis1_info[i]; i++)
! 365: printf("%s%s", i ? ", " : " \"", card->cis1_info[i]);
! 366: if (i != 0)
! 367: printf("\"");
! 368: }
! 369:
! 370: return (UNCONF);
! 371: }
! 372:
! 373: int
! 374: pcmcia_card_gettype(dev)
! 375: struct device *dev;
! 376: {
! 377: struct pcmcia_softc *sc = (struct pcmcia_softc *)dev;
! 378: struct pcmcia_function *pf;
! 379:
! 380: /*
! 381: * Set the iftype to memory if this card has no functions (not yet
! 382: * probed), or only one function, and that is not initialized yet or
! 383: * that is memory.
! 384: */
! 385: pf = SIMPLEQ_FIRST(&sc->card.pf_head);
! 386: if (pf == NULL || (SIMPLEQ_NEXT(pf, pf_list) == NULL &&
! 387: ((pf->pf_flags & PFF_FAKE) ||
! 388: pf->cfe == NULL || pf->cfe->iftype == PCMCIA_IFTYPE_MEMORY)))
! 389: return (PCMCIA_IFTYPE_MEMORY);
! 390: else
! 391: return (PCMCIA_IFTYPE_IO);
! 392: }
! 393:
! 394: /*
! 395: * Initialize a PCMCIA function. May be called as long as the function is
! 396: * disabled.
! 397: */
! 398: void
! 399: pcmcia_function_init(pf, cfe)
! 400: struct pcmcia_function *pf;
! 401: struct pcmcia_config_entry *cfe;
! 402: {
! 403: if (pf->pf_flags & PFF_ENABLED)
! 404: panic("pcmcia_function_init: function is enabled");
! 405:
! 406: /* Remember which configuration entry we are using. */
! 407: pf->cfe = cfe;
! 408: }
! 409:
! 410: static inline void pcmcia_socket_enable(pct, pch)
! 411: pcmcia_chipset_tag_t pct;
! 412: pcmcia_chipset_handle_t *pch;
! 413: {
! 414: pcmcia_chip_socket_enable(pct, pch);
! 415: }
! 416:
! 417: static inline void pcmcia_socket_disable(pct, pch)
! 418: pcmcia_chipset_tag_t pct;
! 419: pcmcia_chipset_handle_t *pch;
! 420: {
! 421: pcmcia_chip_socket_disable(pct, pch);
! 422: }
! 423:
! 424: /* Enable a PCMCIA function */
! 425: int
! 426: pcmcia_function_enable(pf)
! 427: struct pcmcia_function *pf;
! 428: {
! 429: struct pcmcia_function *tmp;
! 430: int reg;
! 431:
! 432: if (pf->cfe == NULL)
! 433: panic("pcmcia_function_enable: function not initialized");
! 434:
! 435: /*
! 436: * Increase the reference count on the socket, enabling power, if
! 437: * necessary.
! 438: */
! 439: if (pf->sc->sc_enabled_count++ == 0)
! 440: pcmcia_chip_socket_enable(pf->sc->pct, pf->sc->pch);
! 441: DPRINTF(("%s: ++enabled_count = %d\n", pf->sc->dev.dv_xname,
! 442: pf->sc->sc_enabled_count));
! 443:
! 444: if (pf->pf_flags & PFF_ENABLED) {
! 445: /*
! 446: * Don't do anything if we're already enabled.
! 447: */
! 448: DPRINTF(("%s: pcmcia_function_enable on enabled func\n"));
! 449: return (0);
! 450: }
! 451:
! 452: /* If there was no CIS don't mess with CCR */
! 453: if (pf->pf_flags & PFF_FAKE)
! 454: goto done;
! 455:
! 456: /*
! 457: * It's possible for different functions' CCRs to be in the same
! 458: * underlying page. Check for that.
! 459: */
! 460: SIMPLEQ_FOREACH(tmp, &pf->sc->card.pf_head, pf_list) {
! 461: if ((tmp->pf_flags & PFF_ENABLED) &&
! 462: (pf->ccr_base >= (tmp->ccr_base - tmp->pf_ccr_offset)) &&
! 463: ((pf->ccr_base + PCMCIA_CCR_SIZE) <=
! 464: (tmp->ccr_base - tmp->pf_ccr_offset +
! 465: tmp->pf_ccr_realsize))) {
! 466: pf->pf_ccrt = tmp->pf_ccrt;
! 467: pf->pf_ccrh = tmp->pf_ccrh;
! 468: pf->pf_ccr_realsize = tmp->pf_ccr_realsize;
! 469:
! 470: /*
! 471: * pf->pf_ccr_offset = (tmp->pf_ccr_offset -
! 472: * tmp->ccr_base) + pf->ccr_base;
! 473: */
! 474: pf->pf_ccr_offset =
! 475: (tmp->pf_ccr_offset + pf->ccr_base) -
! 476: tmp->ccr_base;
! 477: pf->pf_ccr_window = tmp->pf_ccr_window;
! 478: break;
! 479: }
! 480: }
! 481:
! 482: if (tmp == NULL) {
! 483: if (pcmcia_mem_alloc(pf, PCMCIA_CCR_SIZE, &pf->pf_pcmh))
! 484: goto bad;
! 485:
! 486: if (pcmcia_mem_map(pf, PCMCIA_MEM_ATTR, pf->ccr_base,
! 487: PCMCIA_CCR_SIZE, &pf->pf_pcmh, &pf->pf_ccr_offset,
! 488: &pf->pf_ccr_window)) {
! 489: pcmcia_mem_free(pf, &pf->pf_pcmh);
! 490: goto bad;
! 491: }
! 492: }
! 493:
! 494: reg = (pf->cfe->number & PCMCIA_CCR_OPTION_CFINDEX);
! 495: reg |= PCMCIA_CCR_OPTION_LEVIREQ;
! 496: if (pcmcia_mfc(pf->sc)) {
! 497: reg |= PCMCIA_CCR_OPTION_FUNC_ENABLE;
! 498: if (pf->ccr_mask & (1 << (PCMCIA_CCR_IOBASE0 / 2)))
! 499: reg |= PCMCIA_CCR_OPTION_ADDR_DECODE;
! 500: if (pf->ih_fct)
! 501: reg |= PCMCIA_CCR_OPTION_IREQ_ENABLE;
! 502:
! 503: }
! 504:
! 505: pcmcia_ccr_write(pf, PCMCIA_CCR_OPTION, reg);
! 506:
! 507: reg = 0;
! 508:
! 509: if ((pf->cfe->flags & PCMCIA_CFE_IO16) == 0)
! 510: reg |= PCMCIA_CCR_STATUS_IOIS8;
! 511: if (pf->cfe->flags & PCMCIA_CFE_AUDIO)
! 512: reg |= PCMCIA_CCR_STATUS_AUDIO;
! 513: pcmcia_ccr_write(pf, PCMCIA_CCR_STATUS, reg);
! 514:
! 515: pcmcia_ccr_write(pf, PCMCIA_CCR_SOCKETCOPY, 0);
! 516:
! 517: if (pcmcia_mfc(pf->sc)) {
! 518: pcmcia_ccr_write(pf, PCMCIA_CCR_IOBASE0,
! 519: (pf->pf_mfc_iobase >> 0) & 0xff);
! 520: pcmcia_ccr_write(pf, PCMCIA_CCR_IOBASE1,
! 521: (pf->pf_mfc_iobase >> 8) & 0xff);
! 522: pcmcia_ccr_write(pf, PCMCIA_CCR_IOBASE2,
! 523: (pf->pf_mfc_iobase >> 16) & 0xff);
! 524: pcmcia_ccr_write(pf, PCMCIA_CCR_IOBASE3,
! 525: (pf->pf_mfc_iobase >> 24) & 0xff);
! 526: pcmcia_ccr_write(pf, PCMCIA_CCR_IOSIZE,
! 527: pf->pf_mfc_iomax - pf->pf_mfc_iobase);
! 528: }
! 529:
! 530: #ifdef PCMCIADEBUG
! 531: SIMPLEQ_FOREACH(tmp, &pf->sc->card.pf_head, pf_list) {
! 532: printf("%s: function %d CCR at %d offset %lx: "
! 533: "%x %x %x %x, %x %x %x %x, %x\n",
! 534: tmp->sc->dev.dv_xname, tmp->number,
! 535: tmp->pf_ccr_window, tmp->pf_ccr_offset,
! 536: pcmcia_ccr_read(tmp, 0x00),
! 537: pcmcia_ccr_read(tmp, 0x02),
! 538: pcmcia_ccr_read(tmp, 0x04),
! 539: pcmcia_ccr_read(tmp, 0x06),
! 540:
! 541: pcmcia_ccr_read(tmp, 0x0A),
! 542: pcmcia_ccr_read(tmp, 0x0C),
! 543: pcmcia_ccr_read(tmp, 0x0E),
! 544: pcmcia_ccr_read(tmp, 0x10),
! 545:
! 546: pcmcia_ccr_read(tmp, 0x12));
! 547: }
! 548: #endif
! 549:
! 550: done:
! 551: pf->pf_flags |= PFF_ENABLED;
! 552: delay(1000);
! 553: return (0);
! 554:
! 555: bad:
! 556: /*
! 557: * Decrement the reference count, and power down the socket, if
! 558: * necessary.
! 559: */
! 560: if (--pf->sc->sc_enabled_count == 0)
! 561: pcmcia_chip_socket_disable(pf->sc->pct, pf->sc->pch);
! 562: DPRINTF(("%s: --enabled_count = %d\n", pf->sc->dev.dv_xname,
! 563: pf->sc->sc_enabled_count));
! 564:
! 565: return (1);
! 566: }
! 567:
! 568: /* Disable PCMCIA function. */
! 569: void
! 570: pcmcia_function_disable(pf)
! 571: struct pcmcia_function *pf;
! 572: {
! 573: struct pcmcia_function *tmp;
! 574:
! 575: if (pf->cfe == NULL)
! 576: panic("pcmcia_function_enable: function not initialized");
! 577:
! 578: if ((pf->pf_flags & PFF_ENABLED) == 0) {
! 579: /*
! 580: * Don't do anything if we're already disabled.
! 581: */
! 582: return;
! 583: }
! 584:
! 585: /* If there was no CIS don't mess with CCR */
! 586: if (pf->pf_flags & PFF_FAKE) {
! 587: pf->pf_flags &= ~PFF_ENABLED;
! 588: goto done;
! 589: }
! 590:
! 591: /*
! 592: * it's possible for different functions' CCRs to be in the same
! 593: * underlying page. Check for that. Note we mark us as disabled
! 594: * first to avoid matching ourself.
! 595: */
! 596: pf->pf_flags &= ~PFF_ENABLED;
! 597: SIMPLEQ_FOREACH(tmp, &pf->sc->card.pf_head, pf_list) {
! 598: if ((tmp->pf_flags & PFF_ENABLED) &&
! 599: (pf->ccr_base >= (tmp->ccr_base - tmp->pf_ccr_offset)) &&
! 600: ((pf->ccr_base + PCMCIA_CCR_SIZE) <=
! 601: (tmp->ccr_base - tmp->pf_ccr_offset + tmp->pf_ccr_realsize)))
! 602: break;
! 603: }
! 604:
! 605: /* Not used by anyone else; unmap the CCR. */
! 606: if (tmp == NULL) {
! 607: pcmcia_mem_unmap(pf, pf->pf_ccr_window);
! 608: pcmcia_mem_free(pf, &pf->pf_pcmh);
! 609: }
! 610:
! 611: done:
! 612: /*
! 613: * Decrement the reference count, and power down the socket, if
! 614: * necessary.
! 615: */
! 616: if (--pf->sc->sc_enabled_count == 0)
! 617: pcmcia_chip_socket_disable(pf->sc->pct, pf->sc->pch);
! 618: DPRINTF(("%s: --enabled_count = %d\n", pf->sc->dev.dv_xname,
! 619: pf->sc->sc_enabled_count));
! 620: }
! 621:
! 622: int
! 623: pcmcia_io_map(pf, width, offset, size, pcihp, windowp)
! 624: struct pcmcia_function *pf;
! 625: int width;
! 626: bus_addr_t offset;
! 627: bus_size_t size;
! 628: struct pcmcia_io_handle *pcihp;
! 629: int *windowp;
! 630: {
! 631: int reg;
! 632:
! 633: if (pcmcia_chip_io_map(pf->sc->pct, pf->sc->pch,
! 634: width, offset, size, pcihp, windowp))
! 635: return (1);
! 636:
! 637: /*
! 638: * XXX In the multifunction multi-iospace-per-function case, this
! 639: * needs to cooperate with io_alloc to make sure that the spaces
! 640: * don't overlap, and that the ccr's are set correctly.
! 641: */
! 642:
! 643: if (pcmcia_mfc(pf->sc) &&
! 644: (pf->ccr_mask & (1 << (PCMCIA_CCR_IOBASE0 / 2)))) {
! 645: bus_addr_t iobase = pcihp->addr;
! 646: bus_addr_t iomax = pcihp->addr + pcihp->size - 1;
! 647:
! 648: if (pf->pf_mfc_iomax == 0) {
! 649: pf->pf_mfc_iobase = iobase;
! 650: pf->pf_mfc_iomax = iomax;
! 651: } else {
! 652: if (iobase < pf->pf_mfc_iobase)
! 653: pf->pf_mfc_iobase = iobase;
! 654: if (iomax > pf->pf_mfc_iomax)
! 655: pf->pf_mfc_iomax = iomax;
! 656: }
! 657:
! 658: pcmcia_ccr_write(pf, PCMCIA_CCR_IOBASE0,
! 659: (pf->pf_mfc_iobase >> 0) & 0xff);
! 660: pcmcia_ccr_write(pf, PCMCIA_CCR_IOBASE1,
! 661: (pf->pf_mfc_iobase >> 8) & 0xff);
! 662: pcmcia_ccr_write(pf, PCMCIA_CCR_IOBASE2,
! 663: (pf->pf_mfc_iobase >> 16) & 0xff);
! 664: pcmcia_ccr_write(pf, PCMCIA_CCR_IOBASE3,
! 665: (pf->pf_mfc_iobase >> 24) & 0xff);
! 666: pcmcia_ccr_write(pf, PCMCIA_CCR_IOSIZE,
! 667: pf->pf_mfc_iomax - pf->pf_mfc_iobase);
! 668:
! 669: reg = pcmcia_ccr_read(pf, PCMCIA_CCR_OPTION);
! 670: reg |= PCMCIA_CCR_OPTION_ADDR_DECODE;
! 671: pcmcia_ccr_write(pf, PCMCIA_CCR_OPTION, reg);
! 672: }
! 673: return (0);
! 674: }
! 675:
! 676: void *
! 677: pcmcia_intr_establish(pf, ipl, ih_fct, ih_arg, xname)
! 678: struct pcmcia_function *pf;
! 679: int ipl;
! 680: int (*ih_fct)(void *);
! 681: void *ih_arg;
! 682: char *xname;
! 683: {
! 684: void *ret;
! 685: int s, ihcnt, hiipl, reg;
! 686: struct pcmcia_function *pf2;
! 687:
! 688: /* Behave differently if this is a multifunction card. */
! 689: if (pcmcia_mfc(pf->sc)) {
! 690: /*
! 691: * Mask all the ipl's which are already used by this card,
! 692: * and find the highest ipl number (lowest priority).
! 693: */
! 694: ihcnt = 0;
! 695: SIMPLEQ_FOREACH(pf2, &pf->sc->card.pf_head, pf_list) {
! 696: if (pf2->ih_fct) {
! 697: DPRINTF(("%s: function %d has ih_fct %p\n",
! 698: pf->sc->dev.dv_xname, pf2->number,
! 699: pf2->ih_fct));
! 700:
! 701: if (ihcnt == 0)
! 702: hiipl = pf2->ih_ipl;
! 703: else if (pf2->ih_ipl > hiipl)
! 704: hiipl = pf2->ih_ipl;
! 705:
! 706: ihcnt++;
! 707: }
! 708: }
! 709:
! 710: /*
! 711: * Establish the real interrupt, changing the ipl if
! 712: * necessary.
! 713: */
! 714: if (ihcnt == 0) {
! 715: #ifdef DIAGNOSTIC
! 716: if (pf->sc->ih != NULL)
! 717: panic("card has intr handler, "
! 718: "but no function does");
! 719: #endif
! 720: s = spltty();
! 721:
! 722: /* Set up the handler for the new function. */
! 723: pf->ih_fct = ih_fct;
! 724: pf->ih_arg = ih_arg;
! 725: pf->ih_ipl = ipl;
! 726:
! 727: pf->sc->ih = pcmcia_chip_intr_establish(pf->sc->pct,
! 728: pf->sc->pch, pf, ipl, pcmcia_card_intr, pf->sc,
! 729: xname);
! 730: splx(s);
! 731: } else if (ipl > hiipl) {
! 732: #ifdef DIAGNOSTIC
! 733: if (pf->sc->ih == NULL)
! 734: panic("functions have ih, "
! 735: "but the card does not");
! 736: #endif
! 737:
! 738: s = spltty();
! 739:
! 740: pcmcia_chip_intr_disestablish(pf->sc->pct, pf->sc->pch,
! 741: pf->sc->ih);
! 742:
! 743: /* set up the handler for the new function */
! 744: pf->ih_fct = ih_fct;
! 745: pf->ih_arg = ih_arg;
! 746: pf->ih_ipl = ipl;
! 747:
! 748: pf->sc->ih = pcmcia_chip_intr_establish(pf->sc->pct,
! 749: pf->sc->pch, pf, ipl, pcmcia_card_intr, pf->sc,
! 750: xname);
! 751:
! 752: splx(s);
! 753: } else {
! 754: s = spltty();
! 755:
! 756: /* Set up the handler for the new function. */
! 757: pf->ih_fct = ih_fct;
! 758: pf->ih_arg = ih_arg;
! 759: pf->ih_ipl = ipl;
! 760:
! 761: splx(s);
! 762: }
! 763:
! 764: ret = pf->sc->ih;
! 765:
! 766: if (ret != NULL) {
! 767: reg = pcmcia_ccr_read(pf, PCMCIA_CCR_OPTION);
! 768: reg |= PCMCIA_CCR_OPTION_IREQ_ENABLE;
! 769: pcmcia_ccr_write(pf, PCMCIA_CCR_OPTION, reg);
! 770:
! 771: reg = pcmcia_ccr_read(pf, PCMCIA_CCR_STATUS);
! 772: reg |= PCMCIA_CCR_STATUS_INTRACK;
! 773: pcmcia_ccr_write(pf, PCMCIA_CCR_STATUS, reg);
! 774: }
! 775: } else
! 776: ret = pcmcia_chip_intr_establish(pf->sc->pct, pf->sc->pch,
! 777: pf, ipl, ih_fct, ih_arg, xname);
! 778:
! 779: return (ret);
! 780: }
! 781:
! 782: void
! 783: pcmcia_intr_disestablish(pf, ih)
! 784: struct pcmcia_function *pf;
! 785: void *ih;
! 786: {
! 787: int s, reg, ihcnt, hiipl;
! 788: struct pcmcia_function *pf2;
! 789:
! 790: /* Behave differently if this is a multifunction card. */
! 791: if (pcmcia_mfc(pf->sc)) {
! 792: /*
! 793: * Mask all the ipl's which are already used by this card,
! 794: * and find the highest ipl number (lowest priority). Skip
! 795: * the current function.
! 796: */
! 797: ihcnt = 0;
! 798: SIMPLEQ_FOREACH(pf2, &pf->sc->card.pf_head, pf_list) {
! 799: if (pf2 == pf)
! 800: continue;
! 801:
! 802: if (pf2->ih_fct) {
! 803: if (ihcnt == 0)
! 804: hiipl = pf2->ih_ipl;
! 805: else if (pf2->ih_ipl > hiipl)
! 806: hiipl = pf2->ih_ipl;
! 807: ihcnt++;
! 808: }
! 809: }
! 810:
! 811: /*
! 812: * If the ih being removed is lower priority than the lowest
! 813: * priority remaining interrupt, up the priority.
! 814: */
! 815:
! 816: /*
! 817: * ihcnt is the number of interrupt handlers *not* including
! 818: * the one about to be removed.
! 819: */
! 820: if (ihcnt == 0) {
! 821: #ifdef DIAGNOSTIC
! 822: if (pf->sc->ih == NULL)
! 823: panic("disestablishing last function, but card has no ih");
! 824: #endif
! 825: pcmcia_chip_intr_disestablish(pf->sc->pct, pf->sc->pch,
! 826: pf->sc->ih);
! 827:
! 828: reg = pcmcia_ccr_read(pf, PCMCIA_CCR_OPTION);
! 829: reg &= ~PCMCIA_CCR_OPTION_IREQ_ENABLE;
! 830: pcmcia_ccr_write(pf, PCMCIA_CCR_OPTION, reg);
! 831:
! 832: pf->ih_fct = NULL;
! 833: pf->ih_arg = NULL;
! 834:
! 835: pf->sc->ih = NULL;
! 836: } else if (pf->ih_ipl > hiipl) {
! 837: #ifdef DIAGNOSTIC
! 838: if (pf->sc->ih == NULL)
! 839: panic("changing ih ipl, but card has no ih");
! 840: #endif
! 841: s = spltty();
! 842:
! 843: pcmcia_chip_intr_disestablish(pf->sc->pct, pf->sc->pch,
! 844: pf->sc->ih);
! 845: pf->sc->ih = pcmcia_chip_intr_establish(pf->sc->pct,
! 846: pf->sc->pch, pf, hiipl, pcmcia_card_intr, pf->sc,
! 847: NULL);
! 848:
! 849: /* Null out the handler for this function. */
! 850: pf->ih_fct = NULL;
! 851: pf->ih_arg = NULL;
! 852:
! 853: splx(s);
! 854: } else {
! 855: s = spltty();
! 856:
! 857: pf->ih_fct = NULL;
! 858: pf->ih_arg = NULL;
! 859:
! 860: splx(s);
! 861: }
! 862: } else
! 863: pcmcia_chip_intr_disestablish(pf->sc->pct, pf->sc->pch, ih);
! 864: }
! 865:
! 866: const char *
! 867: pcmcia_intr_string(pf, ih)
! 868: struct pcmcia_function *pf;
! 869: void *ih;
! 870: {
! 871: return pcmcia_chip_intr_string(pf->sc->pct, pf->sc->pch, ih);
! 872: }
! 873:
! 874: int
! 875: pcmcia_card_intr(arg)
! 876: void *arg;
! 877: {
! 878: struct pcmcia_softc *sc = arg;
! 879: struct pcmcia_function *pf;
! 880: int reg, ret, ret2;
! 881:
! 882: ret = 0;
! 883:
! 884: for (pf = SIMPLEQ_FIRST(&sc->card.pf_head); pf != NULL;
! 885: pf = SIMPLEQ_NEXT(pf, pf_list)) {
! 886: #ifdef PCMCIADEBUG
! 887: printf("%s: intr flags=%x fct=%d cor=%02x csr=%02x pin=%02x",
! 888: sc->dev.dv_xname, pf->pf_flags, pf->number,
! 889: pcmcia_ccr_read(pf, PCMCIA_CCR_OPTION),
! 890: pcmcia_ccr_read(pf, PCMCIA_CCR_STATUS),
! 891: pcmcia_ccr_read(pf, PCMCIA_CCR_PIN));
! 892: #endif
! 893: if (pf->ih_fct != NULL &&
! 894: (pf->ccr_mask & (1 << (PCMCIA_CCR_STATUS / 2)))) {
! 895: reg = pcmcia_ccr_read(pf, PCMCIA_CCR_STATUS);
! 896: if (reg & PCMCIA_CCR_STATUS_INTR) {
! 897: ret2 = (*pf->ih_fct)(pf->ih_arg);
! 898: if (ret2 != 0 && ret == 0)
! 899: ret = ret2;
! 900: reg = pcmcia_ccr_read(pf, PCMCIA_CCR_STATUS);
! 901: #ifdef PCMCIADEBUG
! 902: printf("; csr %02x->%02x",
! 903: reg, reg & ~PCMCIA_CCR_STATUS_INTR);
! 904: #endif
! 905: pcmcia_ccr_write(pf, PCMCIA_CCR_STATUS,
! 906: reg & ~PCMCIA_CCR_STATUS_INTR);
! 907: }
! 908: }
! 909: #ifdef PCMCIADEBUG
! 910: printf("\n");
! 911: #endif
! 912: }
! 913:
! 914: return (ret);
! 915: }
CVSweb