Annotation of sys/arch/hp300/dev/nhpib.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: nhpib.c,v 1.16 2005/11/13 18:52:15 miod Exp $ */
! 2: /* $NetBSD: nhpib.c,v 1.17 1997/05/05 21:06:41 thorpej Exp $ */
! 3:
! 4: /*
! 5: * Copyright (c) 1996, 1997 Jason R. Thorpe. All rights reserved.
! 6: * Copyright (c) 1982, 1990, 1993
! 7: * The Regents of the University of California. All rights reserved.
! 8: *
! 9: * Redistribution and use in source and binary forms, with or without
! 10: * modification, are permitted provided that the following conditions
! 11: * are met:
! 12: * 1. Redistributions of source code must retain the above copyright
! 13: * notice, this list of conditions and the following disclaimer.
! 14: * 2. Redistributions in binary form must reproduce the above copyright
! 15: * notice, this list of conditions and the following disclaimer in the
! 16: * documentation and/or other materials provided with the distribution.
! 17: * 3. Neither the name of the University nor the names of its contributors
! 18: * may be used to endorse or promote products derived from this software
! 19: * without specific prior written permission.
! 20: *
! 21: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
! 22: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 23: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 24: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
! 25: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! 26: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
! 27: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 28: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! 29: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 30: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 31: * SUCH DAMAGE.
! 32: *
! 33: * @(#)nhpib.c 8.2 (Berkeley) 1/12/94
! 34: */
! 35:
! 36: /*
! 37: * Internal/98624 HPIB driver
! 38: */
! 39:
! 40: #include <sys/param.h>
! 41: #include <sys/systm.h>
! 42: #include <sys/kernel.h>
! 43: #include <sys/buf.h>
! 44: #include <sys/device.h>
! 45: #include <sys/timeout.h>
! 46:
! 47: #include <machine/autoconf.h>
! 48: #include <machine/intr.h>
! 49:
! 50: #include <hp300/dev/dioreg.h>
! 51: #include <hp300/dev/diovar.h>
! 52: #include <hp300/dev/diodevs.h>
! 53:
! 54: #include <hp300/dev/dmavar.h>
! 55:
! 56: #include <hp300/dev/nhpibreg.h>
! 57: #include <hp300/dev/hpibvar.h>
! 58:
! 59: /*
! 60: * ODD parity table for listen and talk addresses and secondary commands.
! 61: * The TI9914A doesn't produce the parity bit.
! 62: */
! 63: static const u_char listnr_par[] = {
! 64: 0040,0241,0242,0043,0244,0045,0046,0247,
! 65: 0250,0051,0052,0253,0054,0255,0256,0057,
! 66: 0260,0061,0062,0263,0064,0265,0266,0067,
! 67: 0070,0271,0272,0073,0274,0075,0076,0277,
! 68: };
! 69: static const u_char talker_par[] = {
! 70: 0100,0301,0302,0103,0304,0105,0106,0307,
! 71: 0310,0111,0112,0313,0114,0315,0316,0117,
! 72: 0320,0121,0122,0323,0124,0325,0326,0127,
! 73: 0130,0331,0332,0133,0334,0135,0136,0337,
! 74: };
! 75: static const u_char sec_par[] = {
! 76: 0340,0141,0142,0343,0144,0345,0346,0147,
! 77: 0150,0351,0352,0153,0354,0155,0156,0357,
! 78: 0160,0361,0362,0163,0364,0165,0166,0367,
! 79: 0370,0171,0172,0373,0174,0375,0376,0177
! 80: };
! 81:
! 82: void nhpibifc(struct nhpibdevice *);
! 83: void nhpibreadtimo(void *);
! 84: int nhpibwait(struct nhpibdevice *, int);
! 85:
! 86: void nhpibreset(struct hpibbus_softc *);
! 87: int nhpibsend(struct hpibbus_softc *, int, int, void *, int);
! 88: int nhpibrecv(struct hpibbus_softc *, int, int, void *, int);
! 89: int nhpibppoll(struct hpibbus_softc *);
! 90: void nhpibppwatch(void *);
! 91: void nhpibgo(struct hpibbus_softc *, int, int, void *, int, int, int);
! 92: void nhpibdone(struct hpibbus_softc *);
! 93: int nhpibintr(void *);
! 94:
! 95: /*
! 96: * Our controller ops structure.
! 97: */
! 98: struct hpib_controller nhpib_controller = {
! 99: nhpibreset,
! 100: nhpibsend,
! 101: nhpibrecv,
! 102: nhpibppoll,
! 103: nhpibppwatch,
! 104: nhpibgo,
! 105: nhpibdone,
! 106: nhpibintr
! 107: };
! 108:
! 109: struct nhpib_softc {
! 110: struct device sc_dev; /* generic device glue */
! 111: struct isr sc_isr;
! 112: struct nhpibdevice *sc_regs; /* device registers */
! 113: struct hpibbus_softc *sc_hpibbus; /* XXX */
! 114: struct timeout sc_read_to; /* nhpibreadtimo timeout */
! 115: struct timeout sc_watch_to; /* nhpibppwatch timeout */
! 116: };
! 117:
! 118: int nhpibmatch(struct device *, void *, void *);
! 119: void nhpibattach(struct device *, struct device *, void *);
! 120:
! 121: struct cfattach nhpib_ca = {
! 122: sizeof(struct nhpib_softc), nhpibmatch, nhpibattach
! 123: };
! 124:
! 125: struct cfdriver nhpib_cd = {
! 126: NULL, "nhpib", DV_DULL
! 127: };
! 128:
! 129: int
! 130: nhpibmatch(parent, match, aux)
! 131: struct device *parent;
! 132: void *match, *aux;
! 133: {
! 134: struct dio_attach_args *da = aux;
! 135:
! 136: /*
! 137: * Internal HP-IB doesn't always return a device ID,
! 138: * so we rely on the sysflags.
! 139: */
! 140: if (da->da_scode == 7 && internalhpib)
! 141: return (1);
! 142:
! 143: if (da->da_id == DIO_DEVICE_ID_NHPIB)
! 144: return (1);
! 145:
! 146: return (0);
! 147: }
! 148:
! 149: void
! 150: nhpibattach(parent, self, aux)
! 151: struct device *parent, *self;
! 152: void *aux;
! 153: {
! 154: struct nhpib_softc *sc = (struct nhpib_softc *)self;
! 155: struct dio_attach_args *da = aux;
! 156: struct hpibdev_attach_args ha;
! 157: const char *desc;
! 158: int ipl, type = HPIBA;
! 159:
! 160: sc->sc_regs = (struct nhpibdevice *)iomap(dio_scodetopa(da->da_scode),
! 161: da->da_size);
! 162: if (sc->sc_regs == NULL) {
! 163: printf("\n%s: can't map registers\n", self->dv_xname);
! 164: return;
! 165: }
! 166:
! 167: ipl = DIO_IPL(sc->sc_regs);
! 168:
! 169: if (da->da_scode == 7 && internalhpib)
! 170: desc = DIO_DEVICE_DESC_IHPIB;
! 171: else if (da->da_id == DIO_DEVICE_ID_NHPIB) {
! 172: type = HPIBB;
! 173: desc = DIO_DEVICE_DESC_NHPIB;
! 174: } else
! 175: desc = "unknown HP-IB!";
! 176:
! 177: printf(" ipl %d: %s\n", ipl, desc);
! 178:
! 179: /* Establish the interrupt handler. */
! 180: sc->sc_isr.isr_func = nhpibintr;
! 181: sc->sc_isr.isr_arg = sc;
! 182: sc->sc_isr.isr_ipl = ipl;
! 183: sc->sc_isr.isr_priority = IPL_BIO;
! 184: dio_intr_establish(&sc->sc_isr, self->dv_xname);
! 185:
! 186: /* Initialize timeout structures */
! 187: timeout_set(&sc->sc_read_to, nhpibreadtimo, sc);
! 188:
! 189: ha.ha_ops = &nhpib_controller;
! 190: ha.ha_type = type; /* XXX */
! 191: ha.ha_ba = (type == HPIBA) ? HPIBA_BA :
! 192: (sc->sc_regs->hpib_csa & CSA_BA);
! 193: ha.ha_softcpp = &sc->sc_hpibbus; /* XXX */
! 194: (void)config_found(self, &ha, hpibdevprint);
! 195: }
! 196:
! 197: void
! 198: nhpibreset(hs)
! 199: struct hpibbus_softc *hs;
! 200: {
! 201: struct nhpib_softc *sc = (struct nhpib_softc *)hs->sc_dev.dv_parent;
! 202: struct nhpibdevice *hd = sc->sc_regs;
! 203:
! 204: hd->hpib_acr = AUX_SSWRST;
! 205: hd->hpib_ar = hs->sc_ba;
! 206: hd->hpib_lim = LIS_ERR;
! 207: hd->hpib_mim = 0;
! 208: hd->hpib_acr = AUX_CDAI;
! 209: hd->hpib_acr = AUX_CSHDW;
! 210: hd->hpib_acr = AUX_SSTD1;
! 211: hd->hpib_acr = AUX_SVSTD1;
! 212: hd->hpib_acr = AUX_CPP;
! 213: hd->hpib_acr = AUX_CHDFA;
! 214: hd->hpib_acr = AUX_CHDFE;
! 215: hd->hpib_acr = AUX_RHDF;
! 216: hd->hpib_acr = AUX_CSWRST;
! 217: nhpibifc(hd);
! 218: hd->hpib_ie = IDS_IE;
! 219: hd->hpib_data = C_DCL_P;
! 220: DELAY(100000);
! 221: }
! 222:
! 223: void
! 224: nhpibifc(hd)
! 225: struct nhpibdevice *hd;
! 226: {
! 227: hd->hpib_acr = AUX_TCA;
! 228: hd->hpib_acr = AUX_CSRE;
! 229: hd->hpib_acr = AUX_SSIC;
! 230: DELAY(100);
! 231: hd->hpib_acr = AUX_CSIC;
! 232: hd->hpib_acr = AUX_SSRE;
! 233: }
! 234:
! 235: int
! 236: nhpibsend(hs, slave, sec, ptr, origcnt)
! 237: struct hpibbus_softc *hs;
! 238: int slave, sec, origcnt;
! 239: void *ptr;
! 240: {
! 241: struct nhpib_softc *sc = (struct nhpib_softc *)hs->sc_dev.dv_parent;
! 242: struct nhpibdevice *hd = sc->sc_regs;
! 243: int cnt = origcnt;
! 244: char *addr = ptr;
! 245:
! 246: hd->hpib_acr = AUX_TCA;
! 247: hd->hpib_data = C_UNL_P;
! 248: if (nhpibwait(hd, MIS_BO))
! 249: goto senderror;
! 250: hd->hpib_data = talker_par[hs->sc_ba];
! 251: hd->hpib_acr = AUX_STON;
! 252: if (nhpibwait(hd, MIS_BO))
! 253: goto senderror;
! 254: hd->hpib_data = listnr_par[slave];
! 255: if (nhpibwait(hd, MIS_BO))
! 256: goto senderror;
! 257: if (sec >= 0 || sec == -2) {
! 258: if (sec == -2) /* selected device clear KLUDGE */
! 259: hd->hpib_data = C_SDC_P;
! 260: else
! 261: hd->hpib_data = sec_par[sec];
! 262: if (nhpibwait(hd, MIS_BO))
! 263: goto senderror;
! 264: }
! 265: hd->hpib_acr = AUX_GTS;
! 266: if (cnt) {
! 267: while (--cnt > 0) {
! 268: hd->hpib_data = *addr++;
! 269: if (nhpibwait(hd, MIS_BO))
! 270: goto senderror;
! 271: }
! 272: hd->hpib_acr = AUX_EOI;
! 273: hd->hpib_data = *addr;
! 274: if (nhpibwait(hd, MIS_BO))
! 275: goto senderror;
! 276: hd->hpib_acr = AUX_TCA;
! 277: #if 0
! 278: /*
! 279: * May be causing 345 disks to hang due to interference
! 280: * with PPOLL mechanism.
! 281: */
! 282: hd->hpib_data = C_UNL_P;
! 283: (void) nhpibwait(hd, MIS_BO);
! 284: #endif
! 285: }
! 286: return(origcnt);
! 287:
! 288: senderror:
! 289: nhpibifc(hd);
! 290: return(origcnt - cnt - 1);
! 291: }
! 292:
! 293: int
! 294: nhpibrecv(hs, slave, sec, ptr, origcnt)
! 295: struct hpibbus_softc *hs;
! 296: int slave, sec, origcnt;
! 297: void *ptr;
! 298: {
! 299: struct nhpib_softc *sc = (struct nhpib_softc *)hs->sc_dev.dv_parent;
! 300: struct nhpibdevice *hd = sc->sc_regs;
! 301: int cnt = origcnt;
! 302: char *addr = ptr;
! 303:
! 304: /*
! 305: * Slave < 0 implies continuation of a previous receive
! 306: * that probably timed out.
! 307: */
! 308: if (slave >= 0) {
! 309: hd->hpib_acr = AUX_TCA;
! 310: hd->hpib_data = C_UNL_P;
! 311: if (nhpibwait(hd, MIS_BO))
! 312: goto recverror;
! 313: hd->hpib_data = listnr_par[hs->sc_ba];
! 314: hd->hpib_acr = AUX_SLON;
! 315: if (nhpibwait(hd, MIS_BO))
! 316: goto recverror;
! 317: hd->hpib_data = talker_par[slave];
! 318: if (nhpibwait(hd, MIS_BO))
! 319: goto recverror;
! 320: if (sec >= 0) {
! 321: hd->hpib_data = sec_par[sec];
! 322: if (nhpibwait(hd, MIS_BO))
! 323: goto recverror;
! 324: }
! 325: hd->hpib_acr = AUX_RHDF;
! 326: hd->hpib_acr = AUX_GTS;
! 327: }
! 328: if (cnt) {
! 329: while (--cnt >= 0) {
! 330: if (nhpibwait(hd, MIS_BI))
! 331: goto recvbyteserror;
! 332: *addr++ = hd->hpib_data;
! 333: }
! 334: hd->hpib_acr = AUX_TCA;
! 335: hd->hpib_data = (slave == 31) ? C_UNA_P : C_UNT_P;
! 336: (void) nhpibwait(hd, MIS_BO);
! 337: }
! 338: return(origcnt);
! 339:
! 340: recverror:
! 341: nhpibifc(hd);
! 342: recvbyteserror:
! 343: return(origcnt - cnt - 1);
! 344: }
! 345:
! 346: void
! 347: nhpibgo(hs, slave, sec, ptr, count, rw, timo)
! 348: struct hpibbus_softc *hs;
! 349: int slave, sec, count, rw, timo;
! 350: void *ptr;
! 351: {
! 352: struct nhpib_softc *sc = (struct nhpib_softc *)hs->sc_dev.dv_parent;
! 353: struct nhpibdevice *hd = sc->sc_regs;
! 354: char *addr = ptr;
! 355:
! 356: hs->sc_flags |= HPIBF_IO;
! 357: if (timo)
! 358: hs->sc_flags |= HPIBF_TIMO;
! 359: if (rw == B_READ)
! 360: hs->sc_flags |= HPIBF_READ;
! 361: #ifdef DEBUG
! 362: else if (hs->sc_flags & HPIBF_READ) {
! 363: printf("nhpibgo: HPIBF_READ still set\n");
! 364: hs->sc_flags &= ~HPIBF_READ;
! 365: }
! 366: #endif
! 367: hs->sc_count = count;
! 368: hs->sc_addr = addr;
! 369: if (hs->sc_flags & HPIBF_READ) {
! 370: hs->sc_curcnt = count;
! 371: dmago(hs->sc_dq->dq_chan, addr, count, DMAGO_BYTE|DMAGO_READ);
! 372: nhpibrecv(hs, slave, sec, 0, 0);
! 373: hd->hpib_mim = MIS_END;
! 374: } else {
! 375: hd->hpib_mim = 0;
! 376: if (count < hpibdmathresh) {
! 377: hs->sc_curcnt = count;
! 378: nhpibsend(hs, slave, sec, addr, count);
! 379: nhpibdone(hs);
! 380: return;
! 381: }
! 382: hs->sc_curcnt = --count;
! 383: dmago(hs->sc_dq->dq_chan, addr, count, DMAGO_BYTE);
! 384: nhpibsend(hs, slave, sec, 0, 0);
! 385: }
! 386: hd->hpib_ie = IDS_IE | IDS_DMA(hs->sc_dq->dq_chan);
! 387: }
! 388:
! 389: /*
! 390: * This timeout can only happen if a DMA read finishes DMAing with the read
! 391: * still pending (more data in read transaction than the driver was prepared
! 392: * to accept). At the moment, variable-record tape drives are the only things
! 393: * capabale of doing this. We repeat the necessary code from nhpibintr() -
! 394: * easier and quicker than calling nhpibintr() for this special case.
! 395: */
! 396: void
! 397: nhpibreadtimo(arg)
! 398: void *arg;
! 399: {
! 400: struct nhpib_softc *sc = arg;
! 401: struct hpibbus_softc *hs = sc->sc_hpibbus;
! 402: int s;
! 403:
! 404: s = splbio();
! 405: if (hs->sc_flags & HPIBF_IO) {
! 406: struct nhpibdevice *hd = sc->sc_regs;
! 407: struct hpibqueue *hq;
! 408:
! 409: hd->hpib_mim = 0;
! 410: hd->hpib_acr = AUX_TCA;
! 411: hs->sc_flags &= ~(HPIBF_DONE|HPIBF_IO|HPIBF_READ|HPIBF_TIMO);
! 412: dmafree(hs->sc_dq);
! 413:
! 414: hq = TAILQ_FIRST(&hs->sc_queue);
! 415: (hq->hq_intr)(hq->hq_softc);
! 416: }
! 417: splx(s);
! 418: }
! 419:
! 420: void
! 421: nhpibdone(hs)
! 422: struct hpibbus_softc *hs;
! 423: {
! 424: struct nhpib_softc *sc = (struct nhpib_softc *)hs->sc_dev.dv_parent;
! 425: struct nhpibdevice *hd = sc->sc_regs;
! 426: int cnt;
! 427:
! 428: cnt = hs->sc_curcnt;
! 429: hs->sc_addr += cnt;
! 430: hs->sc_count -= cnt;
! 431: hs->sc_flags |= HPIBF_DONE;
! 432: hd->hpib_ie = IDS_IE;
! 433: if (hs->sc_flags & HPIBF_READ) {
! 434: if ((hs->sc_flags & HPIBF_TIMO) &&
! 435: (hd->hpib_ids & IDS_IR) == 0)
! 436: timeout_add(&sc->sc_read_to, hz >> 2);
! 437: } else {
! 438: if (hs->sc_count == 1) {
! 439: (void) nhpibwait(hd, MIS_BO);
! 440: hd->hpib_acr = AUX_EOI;
! 441: hd->hpib_data = *hs->sc_addr;
! 442: hd->hpib_mim = MIS_BO;
! 443: }
! 444: #ifdef DEBUG
! 445: else if (hs->sc_count)
! 446: panic("nhpibdone");
! 447: #endif
! 448: }
! 449: }
! 450:
! 451: int
! 452: nhpibintr(arg)
! 453: void *arg;
! 454: {
! 455: struct nhpib_softc *sc = arg;
! 456: struct hpibbus_softc *hs = sc->sc_hpibbus;
! 457: struct nhpibdevice *hd = sc->sc_regs;
! 458: struct hpibqueue *hq;
! 459: int stat0;
! 460: int stat1;
! 461:
! 462: #ifdef lint
! 463: if (stat1 = unit) return(1);
! 464: #endif
! 465: if ((hd->hpib_ids & IDS_IR) == 0)
! 466: return(0);
! 467: stat0 = hd->hpib_mis;
! 468: stat1 = hd->hpib_lis;
! 469:
! 470: hq = TAILQ_FIRST(&hs->sc_queue);
! 471:
! 472: if (hs->sc_flags & HPIBF_IO) {
! 473: hd->hpib_mim = 0;
! 474: if ((hs->sc_flags & HPIBF_DONE) == 0) {
! 475: hs->sc_flags &= ~HPIBF_TIMO;
! 476: dmastop(hs->sc_dq->dq_chan);
! 477: } else if (hs->sc_flags & HPIBF_TIMO)
! 478: timeout_del(&sc->sc_read_to);
! 479: hd->hpib_acr = AUX_TCA;
! 480: hs->sc_flags &= ~(HPIBF_DONE|HPIBF_IO|HPIBF_READ|HPIBF_TIMO);
! 481:
! 482: dmafree(hs->sc_dq);
! 483: (hq->hq_intr)(hq->hq_softc);
! 484: } else if (hs->sc_flags & HPIBF_PPOLL) {
! 485: hd->hpib_mim = 0;
! 486: stat0 = nhpibppoll(hs);
! 487: if (stat0 & (0x80 >> hq->hq_slave)) {
! 488: hs->sc_flags &= ~HPIBF_PPOLL;
! 489: (hq->hq_intr)(hq->hq_softc);
! 490: }
! 491: #ifdef DEBUG
! 492: else
! 493: printf("%s: PPOLL intr bad status %x\n",
! 494: hs->sc_dev.dv_xname, stat0);
! 495: #endif
! 496: }
! 497: return(1);
! 498: }
! 499:
! 500: int
! 501: nhpibppoll(hs)
! 502: struct hpibbus_softc *hs;
! 503: {
! 504: struct nhpib_softc *sc = (struct nhpib_softc *)hs->sc_dev.dv_parent;
! 505: struct nhpibdevice *hd = sc->sc_regs;
! 506: int ppoll;
! 507:
! 508: hd->hpib_acr = AUX_SPP;
! 509: DELAY(25);
! 510: ppoll = hd->hpib_cpt;
! 511: hd->hpib_acr = AUX_CPP;
! 512: return(ppoll);
! 513: }
! 514:
! 515: #ifdef DEBUG
! 516: int nhpibreporttimo = 0;
! 517: #endif
! 518:
! 519: int
! 520: nhpibwait(hd, x)
! 521: struct nhpibdevice *hd;
! 522: int x;
! 523: {
! 524: int timo = hpibtimeout;
! 525:
! 526: while ((hd->hpib_mis & x) == 0 && --timo)
! 527: DELAY(1);
! 528: if (timo == 0) {
! 529: #ifdef DEBUG
! 530: if (nhpibreporttimo)
! 531: printf("hpib0: %s timo\n", x==MIS_BO?"OUT":"IN");
! 532: #endif
! 533: return(-1);
! 534: }
! 535: return(0);
! 536: }
! 537:
! 538: void
! 539: nhpibppwatch(arg)
! 540: void *arg;
! 541: {
! 542: struct hpibbus_softc *hs = arg;
! 543: struct nhpib_softc *sc = (struct nhpib_softc *)hs->sc_dev.dv_parent;
! 544:
! 545: if ((hs->sc_flags & HPIBF_PPOLL) == 0)
! 546: return;
! 547:
! 548: again:
! 549: if (nhpibppoll(hs) & (0x80 >> TAILQ_FIRST(&hs->sc_queue)->hq_slave))
! 550: sc->sc_regs->hpib_mim = MIS_BO;
! 551: else if (cold)
! 552: /* timeouts not working yet */
! 553: goto again;
! 554: else {
! 555: timeout_set(&sc->sc_watch_to, nhpibppwatch, hs);
! 556: timeout_add(&sc->sc_watch_to, 1);
! 557: }
! 558: }
CVSweb