Annotation of sys/dev/pcmcia/esp_pcmcia.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: esp_pcmcia.c,v 1.6 2006/04/20 20:30:28 miod Exp $ */
! 2: /* $NetBSD: esp_pcmcia.c,v 1.8 2000/06/05 15:36:45 tsutsui Exp $ */
! 3:
! 4: /*-
! 5: * Copyright (c) 2000 The NetBSD Foundation, Inc.
! 6: * All rights reserved.
! 7: *
! 8: * This code is derived from software contributed to The NetBSD Foundation
! 9: * by Charles M. Hannum.
! 10: *
! 11: * Redistribution and use in source and binary forms, with or without
! 12: * modification, are permitted provided that the following conditions
! 13: * are met:
! 14: * 1. Redistributions of source code must retain the above copyright
! 15: * notice, this list of conditions and the following disclaimer.
! 16: * 2. Redistributions in binary form must reproduce the above copyright
! 17: * notice, this list of conditions and the following disclaimer in the
! 18: * documentation and/or other materials provided with the distribution.
! 19: * 3. All advertising materials mentioning features or use of this software
! 20: * must display the following acknowledgement:
! 21: * This product includes software developed by the NetBSD
! 22: * Foundation, Inc. and its contributors.
! 23: * 4. Neither the name of The NetBSD Foundation nor the names of its
! 24: * contributors may be used to endorse or promote products derived
! 25: * from this software without specific prior written permission.
! 26: *
! 27: * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
! 28: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
! 29: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
! 30: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
! 31: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
! 32: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
! 33: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
! 34: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
! 35: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
! 36: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
! 37: * POSSIBILITY OF SUCH DAMAGE.
! 38: */
! 39:
! 40: #include <sys/param.h>
! 41: #include <sys/systm.h>
! 42: #include <sys/device.h>
! 43: #include <sys/buf.h>
! 44:
! 45: #include <machine/bus.h>
! 46: #include <machine/intr.h>
! 47:
! 48: #include <scsi/scsi_all.h>
! 49: #include <scsi/scsiconf.h>
! 50:
! 51: #include <dev/pcmcia/pcmciareg.h>
! 52: #include <dev/pcmcia/pcmciavar.h>
! 53: #include <dev/pcmcia/pcmciadevs.h>
! 54:
! 55: #include <dev/ic/ncr53c9xreg.h>
! 56: #include <dev/ic/ncr53c9xvar.h>
! 57:
! 58: struct esp_pcmcia_softc {
! 59: struct ncr53c9x_softc sc_ncr53c9x; /* glue to MI code */
! 60:
! 61: int sc_active; /* Pseudo-DMA state vars */
! 62: int sc_tc;
! 63: int sc_datain;
! 64: size_t sc_dmasize;
! 65: size_t sc_dmatrans;
! 66: char **sc_dmaaddr;
! 67: size_t *sc_pdmalen;
! 68:
! 69: /* PCMCIA-specific goo. */
! 70: struct pcmcia_io_handle sc_pcioh; /* PCMCIA i/o space info */
! 71: int sc_io_window; /* our i/o window */
! 72: struct pcmcia_function *sc_pf; /* our PCMCIA function */
! 73: void *sc_ih; /* interrupt handler */
! 74: #ifdef ESP_PCMCIA_POLL
! 75: struct callout sc_poll_ch;
! 76: #endif
! 77: int sc_flags;
! 78: #define ESP_PCMCIA_ATTACHED 1 /* attach completed */
! 79: #define ESP_PCMCIA_ATTACHING 2 /* attach in progress */
! 80: };
! 81:
! 82: int esp_pcmcia_match(struct device *, void *, void *);
! 83: void esp_pcmcia_attach(struct device *, struct device *, void *);
! 84: void esp_pcmcia_init(struct esp_pcmcia_softc *);
! 85: int esp_pcmcia_detach(struct device *, int);
! 86: int esp_pcmcia_enable(void *, int);
! 87:
! 88: struct scsi_adapter esp_pcmcia_adapter = {
! 89: ncr53c9x_scsi_cmd, /* cmd */
! 90: minphys, /* minphys */
! 91: 0, /* open */
! 92: 0, /* close */
! 93: };
! 94:
! 95: struct cfattach esp_pcmcia_ca = {
! 96: sizeof(struct esp_pcmcia_softc), esp_pcmcia_match, esp_pcmcia_attach
! 97: };
! 98:
! 99: /*
! 100: * Functions and the switch for the MI code.
! 101: */
! 102: #ifdef ESP_PCMCIA_POLL
! 103: void esp_pcmcia_poll(void *);
! 104: #endif
! 105: u_char esp_pcmcia_read_reg(struct ncr53c9x_softc *, int);
! 106: void esp_pcmcia_write_reg(struct ncr53c9x_softc *, int, u_char);
! 107: int esp_pcmcia_dma_isintr(struct ncr53c9x_softc *);
! 108: void esp_pcmcia_dma_reset(struct ncr53c9x_softc *);
! 109: int esp_pcmcia_dma_intr(struct ncr53c9x_softc *);
! 110: int esp_pcmcia_dma_setup(struct ncr53c9x_softc *, caddr_t *,
! 111: size_t *, int, size_t *);
! 112: void esp_pcmcia_dma_go(struct ncr53c9x_softc *);
! 113: void esp_pcmcia_dma_stop(struct ncr53c9x_softc *);
! 114: int esp_pcmcia_dma_isactive(struct ncr53c9x_softc *);
! 115:
! 116: struct ncr53c9x_glue esp_pcmcia_glue = {
! 117: esp_pcmcia_read_reg,
! 118: esp_pcmcia_write_reg,
! 119: esp_pcmcia_dma_isintr,
! 120: esp_pcmcia_dma_reset,
! 121: esp_pcmcia_dma_intr,
! 122: esp_pcmcia_dma_setup,
! 123: esp_pcmcia_dma_go,
! 124: esp_pcmcia_dma_stop,
! 125: esp_pcmcia_dma_isactive,
! 126: NULL, /* gl_clear_latched_intr */
! 127: };
! 128:
! 129: struct esp_pcmcia_product {
! 130: u_int16_t app_vendor; /* PCMCIA vendor ID */
! 131: u_int16_t app_product; /* PCMCIA product ID */
! 132: int app_expfunc; /* expected function number */
! 133: } esp_pcmcia_prod[] = {
! 134: { PCMCIA_VENDOR_PANASONIC, PCMCIA_PRODUCT_PANASONIC_KXLC002, 0 },
! 135: { PCMCIA_VENDOR_PANASONIC, PCMCIA_PRODUCT_PANASONIC_KME, 0 },
! 136: { PCMCIA_VENDOR_NEWMEDIA2, PCMCIA_PRODUCT_NEWMEDIA2_BUSTOASTER, 0 }
! 137: };
! 138:
! 139: int
! 140: esp_pcmcia_match(parent, match, aux)
! 141: struct device *parent;
! 142: void *match, *aux;
! 143: {
! 144: struct pcmcia_attach_args *pa = aux;
! 145: int i;
! 146:
! 147: for (i = 0; i < sizeof(esp_pcmcia_prod)/sizeof(esp_pcmcia_prod[0]); i++)
! 148: if (pa->manufacturer == esp_pcmcia_prod[i].app_vendor &&
! 149: pa->product == esp_pcmcia_prod[i].app_product &&
! 150: pa->pf->number == esp_pcmcia_prod[i].app_expfunc)
! 151: return (1);
! 152: return (0);
! 153: }
! 154:
! 155: void
! 156: esp_pcmcia_attach(parent, self, aux)
! 157: struct device *parent, *self;
! 158: void *aux;
! 159: {
! 160: struct esp_pcmcia_softc *esc = (void *)self;
! 161: struct ncr53c9x_softc *sc = &esc->sc_ncr53c9x;
! 162: struct pcmcia_attach_args *pa = aux;
! 163: struct pcmcia_config_entry *cfe;
! 164: struct pcmcia_function *pf = pa->pf;
! 165: const char *intrstr;
! 166:
! 167: esc->sc_pf = pf;
! 168:
! 169: for (cfe = SIMPLEQ_FIRST(&pf->cfe_head); cfe != NULL;
! 170: cfe = SIMPLEQ_NEXT(cfe, cfe_list)) {
! 171: if (cfe->num_memspace != 0 ||
! 172: cfe->num_iospace != 1)
! 173: continue;
! 174:
! 175: if (pcmcia_io_alloc(pa->pf, cfe->iospace[0].start,
! 176: cfe->iospace[0].length, 0, &esc->sc_pcioh) == 0)
! 177: break;
! 178: }
! 179:
! 180: if (cfe == 0) {
! 181: printf(": can't alloc i/o space\n");
! 182: goto no_config_entry;
! 183: }
! 184:
! 185: /* Enable the card. */
! 186: pcmcia_function_init(pf, cfe);
! 187: if (pcmcia_function_enable(pf)) {
! 188: printf(": function enable failed\n");
! 189: goto enable_failed;
! 190: }
! 191:
! 192: /* Map in the I/O space */
! 193: if (pcmcia_io_map(pa->pf, PCMCIA_WIDTH_AUTO, 0, esc->sc_pcioh.size,
! 194: &esc->sc_pcioh, &esc->sc_io_window)) {
! 195: printf(": can't map i/o space\n");
! 196: goto iomap_failed;
! 197: }
! 198:
! 199: printf(" port 0x%lx/%lu", esc->sc_pcioh.addr,
! 200: (u_long)esc->sc_pcioh.size);
! 201:
! 202: esp_pcmcia_init(esc);
! 203:
! 204: esc->sc_ih = pcmcia_intr_establish(esc->sc_pf, IPL_BIO,
! 205: ncr53c9x_intr, &esc->sc_ncr53c9x, sc->sc_dev.dv_xname);
! 206: intrstr = pcmcia_intr_string(esc->sc_pf, esc->sc_ih);
! 207: if (esc->sc_ih == NULL) {
! 208: printf(", %s\n", intrstr);
! 209: goto iomap_failed;
! 210: }
! 211: if (*intrstr)
! 212: printf(", %s", intrstr);
! 213:
! 214: /*
! 215: * Initialize nca board itself.
! 216: */
! 217: esc->sc_flags |= ESP_PCMCIA_ATTACHING;
! 218: ncr53c9x_attach(sc, &esp_pcmcia_adapter, NULL);
! 219: esc->sc_flags &= ~ESP_PCMCIA_ATTACHING;
! 220: esc->sc_flags |= ESP_PCMCIA_ATTACHED;
! 221: return;
! 222:
! 223: iomap_failed:
! 224: /* Disable the device. */
! 225: pcmcia_function_disable(esc->sc_pf);
! 226:
! 227: enable_failed:
! 228: /* Unmap our I/O space. */
! 229: pcmcia_io_free(esc->sc_pf, &esc->sc_pcioh);
! 230:
! 231: no_config_entry:
! 232: return;
! 233: }
! 234:
! 235: void
! 236: esp_pcmcia_init(esc)
! 237: struct esp_pcmcia_softc *esc;
! 238: {
! 239: struct ncr53c9x_softc *sc = &esc->sc_ncr53c9x;
! 240: bus_space_tag_t iot = esc->sc_pcioh.iot;
! 241: bus_space_handle_t ioh = esc->sc_pcioh.ioh;
! 242:
! 243: /* id 7, clock 40M, parity ON, sync OFF, fast ON, slow ON */
! 244:
! 245: sc->sc_glue = &esp_pcmcia_glue;
! 246:
! 247: #ifdef ESP_PCMCIA_POLL
! 248: callout_init(&esc->sc_poll_ch);
! 249: #endif
! 250:
! 251: sc->sc_rev = NCR_VARIANT_ESP406;
! 252: sc->sc_id = 7;
! 253: sc->sc_freq = 40;
! 254: /* try -PARENB -SLOW */
! 255: sc->sc_cfg1 = sc->sc_id | NCRCFG1_PARENB | NCRCFG1_SLOW;
! 256: /* try +FE */
! 257: sc->sc_cfg2 = NCRCFG2_SCSI2;
! 258: /* try -IDM -FSCSI -FCLK */
! 259: sc->sc_cfg3 = NCRESPCFG3_CDB | NCRESPCFG3_FCLK | NCRESPCFG3_IDM |
! 260: NCRESPCFG3_FSCSI;
! 261: sc->sc_cfg4 = NCRCFG4_ACTNEG;
! 262: /* try +INTP */
! 263: sc->sc_cfg5 = NCRCFG5_CRS1 | NCRCFG5_AADDR | NCRCFG5_PTRINC;
! 264: sc->sc_minsync = 0;
! 265: sc->sc_maxxfer = 64 * 1024;
! 266:
! 267: bus_space_write_1(iot, ioh, NCR_CFG5, sc->sc_cfg5);
! 268:
! 269: bus_space_write_1(iot, ioh, NCR_PIOI, 0);
! 270: bus_space_write_1(iot, ioh, NCR_PSTAT, 0);
! 271: bus_space_write_1(iot, ioh, 0x09, 0x24);
! 272:
! 273: bus_space_write_1(iot, ioh, NCR_CFG4, sc->sc_cfg4);
! 274: }
! 275:
! 276: #ifdef notyet
! 277: int
! 278: esp_pcmcia_detach(self, flags)
! 279: struct device *self;
! 280: int flags;
! 281: {
! 282: struct esp_pcmcia_softc *esc = (void *)self;
! 283: int error;
! 284:
! 285: if ((esc->sc_flags & ESP_PCMCIA_ATTACHED) == 0) {
! 286: /* Nothing to detach. */
! 287: return (0);
! 288: }
! 289:
! 290: error = ncr53c9x_detach(&esc->sc_ncr53c9x, flags);
! 291: if (error)
! 292: return (error);
! 293:
! 294: /* Unmap our i/o window and i/o space. */
! 295: pcmcia_io_unmap(esc->sc_pf, esc->sc_io_window);
! 296: pcmcia_io_free(esc->sc_pf, &esc->sc_pcioh);
! 297:
! 298: return (0);
! 299: }
! 300: #endif
! 301:
! 302: int
! 303: esp_pcmcia_enable(arg, onoff)
! 304: void *arg;
! 305: int onoff;
! 306: {
! 307: struct esp_pcmcia_softc *esc = arg;
! 308:
! 309: if (onoff) {
! 310: #ifdef ESP_PCMCIA_POLL
! 311: callout_reset(&esc->sc_poll_ch, 1, esp_pcmcia_poll, esc);
! 312: #else
! 313: /* Establish the interrupt handler. */
! 314: esc->sc_ih = pcmcia_intr_establish(esc->sc_pf, IPL_BIO,
! 315: ncr53c9x_intr, &esc->sc_ncr53c9x,
! 316: esc->sc_ncr53c9x.sc_dev.dv_xname);
! 317: if (esc->sc_ih == NULL) {
! 318: printf("%s: couldn't establish interrupt handler\n",
! 319: esc->sc_ncr53c9x.sc_dev.dv_xname);
! 320: return (EIO);
! 321: }
! 322: #endif
! 323:
! 324: /*
! 325: * If attach is in progress, we know that card power is
! 326: * enabled and chip will be initialized later.
! 327: * Otherwise, enable and reset now.
! 328: */
! 329: if ((esc->sc_flags & ESP_PCMCIA_ATTACHING) == 0) {
! 330: if (pcmcia_function_enable(esc->sc_pf)) {
! 331: printf("%s: couldn't enable PCMCIA function\n",
! 332: esc->sc_ncr53c9x.sc_dev.dv_xname);
! 333: pcmcia_intr_disestablish(esc->sc_pf,
! 334: esc->sc_ih);
! 335: return (EIO);
! 336: }
! 337:
! 338: /* Initialize only chip. */
! 339: ncr53c9x_init(&esc->sc_ncr53c9x, 0);
! 340: }
! 341: } else {
! 342: pcmcia_function_disable(esc->sc_pf);
! 343: #ifdef ESP_PCMCIA_POLL
! 344: callout_stop(&esc->sc_poll_ch);
! 345: #else
! 346: pcmcia_intr_disestablish(esc->sc_pf, esc->sc_ih);
! 347: #endif
! 348: }
! 349:
! 350: return (0);
! 351: }
! 352:
! 353: #ifdef ESP_PCMCIA_POLL
! 354: void
! 355: esp_pcmcia_poll(arg)
! 356: void *arg;
! 357: {
! 358: struct esp_pcmcia_softc *esc = arg;
! 359:
! 360: (void) ncr53c9x_intr(&esc->sc_ncr53c9x);
! 361: callout_reset(&esc->sc_poll_ch, 1, esp_pcmcia_poll, esc);
! 362: }
! 363: #endif
! 364:
! 365: /*
! 366: * Glue functions.
! 367: */
! 368: u_char
! 369: esp_pcmcia_read_reg(sc, reg)
! 370: struct ncr53c9x_softc *sc;
! 371: int reg;
! 372: {
! 373: struct esp_pcmcia_softc *esc = (struct esp_pcmcia_softc *)sc;
! 374: u_char v;
! 375:
! 376: v = bus_space_read_1(esc->sc_pcioh.iot, esc->sc_pcioh.ioh, reg);
! 377: return v;
! 378: }
! 379:
! 380: void
! 381: esp_pcmcia_write_reg(sc, reg, val)
! 382: struct ncr53c9x_softc *sc;
! 383: int reg;
! 384: u_char val;
! 385: {
! 386: struct esp_pcmcia_softc *esc = (struct esp_pcmcia_softc *)sc;
! 387: u_char v = val;
! 388:
! 389: if (reg == NCR_CMD && v == (NCRCMD_TRANS|NCRCMD_DMA))
! 390: v = NCRCMD_TRANS;
! 391: bus_space_write_1(esc->sc_pcioh.iot, esc->sc_pcioh.ioh, reg, v);
! 392: }
! 393:
! 394: int
! 395: esp_pcmcia_dma_isintr(sc)
! 396: struct ncr53c9x_softc *sc;
! 397: {
! 398:
! 399: return NCR_READ_REG(sc, NCR_STAT) & NCRSTAT_INT;
! 400: }
! 401:
! 402: void
! 403: esp_pcmcia_dma_reset(sc)
! 404: struct ncr53c9x_softc *sc;
! 405: {
! 406: struct esp_pcmcia_softc *esc = (struct esp_pcmcia_softc *)sc;
! 407:
! 408: esc->sc_active = 0;
! 409: esc->sc_tc = 0;
! 410: }
! 411:
! 412: int
! 413: esp_pcmcia_dma_intr(sc)
! 414: struct ncr53c9x_softc *sc;
! 415: {
! 416: struct esp_pcmcia_softc *esc = (struct esp_pcmcia_softc *)sc;
! 417: u_char *p;
! 418: u_int espphase, espstat, espintr;
! 419: int cnt;
! 420:
! 421: if (esc->sc_active == 0) {
! 422: printf("%s: dma_intr--inactive DMA\n", sc->sc_dev.dv_xname);
! 423: return -1;
! 424: }
! 425:
! 426: if ((sc->sc_espintr & NCRINTR_BS) == 0) {
! 427: esc->sc_active = 0;
! 428: return 0;
! 429: }
! 430:
! 431: cnt = *esc->sc_pdmalen;
! 432: if (*esc->sc_pdmalen == 0) {
! 433: printf("%s: data interrupt, but no count left\n",
! 434: sc->sc_dev.dv_xname);
! 435: }
! 436:
! 437: p = *esc->sc_dmaaddr;
! 438: espphase = sc->sc_phase;
! 439: espstat = (u_int) sc->sc_espstat;
! 440: espintr = (u_int) sc->sc_espintr;
! 441: do {
! 442: if (esc->sc_datain) {
! 443: *p++ = NCR_READ_REG(sc, NCR_FIFO);
! 444: cnt--;
! 445: if (espphase == DATA_IN_PHASE)
! 446: NCR_WRITE_REG(sc, NCR_CMD, NCRCMD_TRANS);
! 447: else
! 448: esc->sc_active = 0;
! 449: } else {
! 450: if (espphase == DATA_OUT_PHASE ||
! 451: espphase == MESSAGE_OUT_PHASE) {
! 452: NCR_WRITE_REG(sc, NCR_FIFO, *p++);
! 453: cnt--;
! 454: NCR_WRITE_REG(sc, NCR_CMD, NCRCMD_TRANS);
! 455: } else
! 456: esc->sc_active = 0;
! 457: }
! 458:
! 459: if (esc->sc_active) {
! 460: while (!(NCR_READ_REG(sc, NCR_STAT) & NCRSTAT_INT));
! 461: espstat = NCR_READ_REG(sc, NCR_STAT);
! 462: espintr = NCR_READ_REG(sc, NCR_INTR);
! 463: espphase = (espintr & NCRINTR_DIS)
! 464: ? /* Disconnected */ BUSFREE_PHASE
! 465: : espstat & PHASE_MASK;
! 466: }
! 467: } while (esc->sc_active && espintr);
! 468: sc->sc_phase = espphase;
! 469: sc->sc_espstat = (u_char) espstat;
! 470: sc->sc_espintr = (u_char) espintr;
! 471: *esc->sc_dmaaddr = p;
! 472: *esc->sc_pdmalen = cnt;
! 473:
! 474: if (*esc->sc_pdmalen == 0)
! 475: esc->sc_tc = NCRSTAT_TC;
! 476: sc->sc_espstat |= esc->sc_tc;
! 477: return 0;
! 478: }
! 479:
! 480: int
! 481: esp_pcmcia_dma_setup(sc, addr, len, datain, dmasize)
! 482: struct ncr53c9x_softc *sc;
! 483: caddr_t *addr;
! 484: size_t *len;
! 485: int datain;
! 486: size_t *dmasize;
! 487: {
! 488: struct esp_pcmcia_softc *esc = (struct esp_pcmcia_softc *)sc;
! 489:
! 490: esc->sc_dmaaddr = addr;
! 491: esc->sc_pdmalen = len;
! 492: esc->sc_datain = datain;
! 493: esc->sc_dmasize = *dmasize;
! 494: esc->sc_tc = 0;
! 495:
! 496: return 0;
! 497: }
! 498:
! 499: void
! 500: esp_pcmcia_dma_go(sc)
! 501: struct ncr53c9x_softc *sc;
! 502: {
! 503: struct esp_pcmcia_softc *esc = (struct esp_pcmcia_softc *)sc;
! 504:
! 505: esc->sc_active = 1;
! 506: }
! 507:
! 508: void
! 509: esp_pcmcia_dma_stop(sc)
! 510: struct ncr53c9x_softc *sc;
! 511: {
! 512: }
! 513:
! 514: int
! 515: esp_pcmcia_dma_isactive(sc)
! 516: struct ncr53c9x_softc *sc;
! 517: {
! 518: struct esp_pcmcia_softc *esc = (struct esp_pcmcia_softc *)sc;
! 519:
! 520: return (esc->sc_active);
! 521: }
CVSweb