1 /* lpa.c 4.9 82/10/20 */ 2 3 #include "lpa.h" 4 #if NLPA > 0 5 6 #include "../h/param.h" 7 #include "../h/dir.h" 8 #include "../h/user.h" 9 #include "../h/buf.h" 10 #include "../h/proc.h" 11 #include "../h/ioctl.h" 12 #include "../h/uio.h" 13 14 #include "../vaxuba/ubavar.h" 15 16 /* 17 * LPA driver for -- Asa Romberger 18 * 19 * open 20 * write microcode 21 * write dedicated mode dispatch table 22 * ioctl TIOCSETP to set parameters 23 * struct iocb { 24 * short *baddr; buffer address 25 * short rate; - 1,000,000 / frequency in Hz 26 * short wc; 15-13 = number of buffers - 1 27 * 12-0 = buffer size in words 28 * } iocb; 29 * read - 1 character indicating buffer index 30 * fill or empty buffer 31 * minor device number = DDCCCCCC where: 32 * DD = 00 for analog input 33 * = 01 for analog output 34 * CCCCCC = channel number 35 */ 36 * define NOMCODE to eliminate the microcode download check 37 */ 38 /* #define TRACELPA */ 39 /* #define NOMCODE */ 40 41 #ifdef TRACELPA 42 # define TRACER(x) printf(x) 43 # define TRACERN(x, d) printf(x, d) 44 #else 45 # define TRACER(x) 46 # define TRACERN(x, d) 47 #endif 48 49 /* PRIORITY AT WHICH PROGRAM SHOULD RUN */ 50 /* THIS SHOULD EVENTUALLY TELL UNIX THIS IS A REAL-TIME DEVICE */ 51 52 #define NICE 0 53 54 #define inc(v) (sc->v = ((sc->v + 1) % sc->sc_nbuf)) 55 56 #define LPAPRI (PZERO + 0) 57 #define LPAUNIT(dev) 0 58 #define LPADEVICE(dev) (((dev) >> 6) & 03) 59 #define LPACHANNEL(dev) ((dev) & 077) 60 61 int lpaprobe(), lpaattach(), lpaiintr(), lpaointr(); 62 u_short lpastd[] = {0170460, 0}; 63 struct uba_device *lpadinfo[NLPA]; 64 struct uba_driver lpadriver = 65 {lpaprobe, 0, lpaattach, 0, lpastd, "lpa", lpadinfo, 0, 0, 0 }; 66 67 struct lpa_softc { 68 int sc_flag; /* flags, as defined below */ 69 int sc_device; /* device: 0 = analog in, 1 = analog out */ 70 int sc_channel; /* device channel number */ 71 struct buf sc_ubuffer; /* user buffer header */ 72 int sc_ubabuf; /* uba allocation pointer for buffer */ 73 int sc_ubufn; /* present buffer that user is accessing */ 74 int sc_lbufn; /* present buffer that lpa is accessing */ 75 int sc_lbufnx; /* next buffer for lpa (value in ustat) */ 76 int sc_nbuf; /* number of buffers */ 77 int sc_count; /* buffer size in words */ 78 short sc_ustat; /* user status word */ 79 struct buf sc_ustatbuf; /* dummy user status word buffer for ubasetup */ 80 int sc_ubaustat; /* uba allocation pointer for ustat */ 81 struct buf *sc_buffer; /* scratch buffer header */ 82 int sc_start; /* 0 if lpa operation has been started */ 83 } lpa_softc[NLPA]; 84 85 /* flags for sc_flag */ 86 #define OPEN 01 /* device is open */ 87 #define MCODE 02 /* microcode has been loaded */ 88 #define DMDT 04 /* dedicated mode dispatch table loaded */ 89 #define STTY 010 /* stty call and device initialized */ 90 #define SLEEP 020 /* sleeping */ 91 92 /* bits for ustat */ 93 #define DONE 0100000 /* done */ 94 #define STOP 0040000 /* stop data transfer */ 95 #define NBI 0003400 /* next buffer index */ 96 #define LBI 0000003 /* last buffer index */ 97 98 struct lpadevice { 99 short lcim; /* control in and maintenance */ 100 short lcos; /* control and status out */ 101 short lrda; /* request description array address word */ 102 short lms; /* maintenance status */ 103 }; 104 105 /* control in and maintenance register bits */ 106 #define READYI 0000200 /* ready in */ 107 #define IIE 0000100 /* in interrupt enable */ 108 #define RDAEXT 0000014 /* rda address extension */ 109 #define RDAEXTOFFSET 2 /* offset of RDAEXT from right side */ 110 #define GO 0000001 /* go */ 111 #define RUN 0100000 /* run */ 112 #define RESET 0040000 /* reset */ 113 #define CWRITE 0020000 /* cram write */ 114 #define EA 0004000 /* enable arbitration */ 115 #define ROMO 0002000 /* rom O */ 116 #define ROMI 0001000 /* rom I */ 117 #define SMICRO 0000400 /* step microprocessor */ 118 119 /* control and status out register bits */ 120 #define READYO 0200 /* ready out */ 121 #define OIE 0100 /* out interrupt enable */ 122 #define UINDEX 0007 /* user index */ 123 #define ERROR 0100000 /* error */ 124 #define ESTAT 0060000 /* error status */ 125 #define ESCODE 0017400 /* error sub code */ 126 #define ECODE 0077400 /* error status + error sub code */ 127 #define OVERRUN 0243 /* overrun error */ 128 129 /* LPA COMMAND DESCRIPTION AREA */ 130 131 /* INIT COMMAND */ 132 #define INIT 0 /* mode */ 133 #define MCVERS 4 /* microcode version */ 134 #define ACLOCKA 0170404 /* LPA bus addresses */ 135 #define ACLOCKB 0170432 136 #define AAD1 0170400 137 #define AAD2 1 /* 0170440 - DOES NOT EXIST */ 138 #define ADA 0170420 139 #define ADIO1 1 /* 0167770 - DOES NOT EXIST */ 140 #define ADIO2 1 /* 0167760 - DOES NOT EXIST */ 141 #define ADIO3 1 /* 0167750 - DOES NOT EXIST */ 142 #define ADIO4 1 /* 0167740 - DOES NOT EXIST */ 143 #define ADIO5 1 /* 0167730 - DOES NOT EXIST */ 144 145 /* CLOCK START COMMAND */ 146 #define CLOCK 1 /* mode */ 147 #define CLOCKA 0<<4 /* clock A */ 148 /* clock status word */ 149 #define ENACTR 1 /* enable counter */ 150 #define R1M 1<<1 /* 1 MHz rate */ 151 #define R100K 2<<1 /* 100 KHz rate */ 152 #define R10K 3<<1 /* 10 KHz rate */ 153 #define R1K 4<<1 /* 1 KHz rate */ 154 #define R100 5<<1 /* 100 Hz rate */ 155 #define REXT 6<<1 /* external rate (from st1 input) */ 156 #define R60 7<<1 /* line frequency rate */ 157 #define MFIE 0100 /* mode flag interrupt enable */ 158 #define MSI 0<<8 /* single interval mode */ 159 #define MRI 1<<8 /* repeat interval mode */ 160 #define MEET 2<<8 /* external event time mode */ 161 #define MEETZ 3<<8 /* external event time mode from zero base */ 162 #define ST1EC 020000 /* st1 enable counter */ 163 #define ST1IE 040000 /* st1 interrupt enable */ 164 165 /* DATA TRANSFER START COMMAND */ 166 #define DTS 2 /* mode */ 167 #define SCHAN 1<<8 /* single channel */ 168 169 lpaprobe(reg) 170 caddr_t reg; 171 { 172 register int br, cvec; /* value result */ 173 register struct lpadevice *lpaaddr = (struct lpadevice *)reg; 174 175 #ifdef lint 176 br = 0; cvec = br; br = cvec; 177 #endif 178 /* this should force an interrupt, stall, clear the lpa */ 179 br = 0x15; 180 cvec = 0330; 181 TRACER("PROBE\n"); 182 return (sizeof (struct lpadevice)); 183 } 184 185 lpaattach(ui) 186 register struct upa_device *ui; 187 { 188 189 } 190 191 lpaopen(dev, flag) 192 dev_t dev; 193 int flag; 194 { 195 register int unit = LPAUNIT(dev); 196 register struct lpa_softc *sc = &lpa_softc[unit]; 197 register struct uba_device *ui = lpadinfo[unit]; 198 register struct lpadevice *lpaaddr = (struct lpadevice *) ui->ui_addr; 199 200 TRACER("OPEN\n"); 201 if (unit >= NLPA || sc->sc_flag & OPEN || ui == 0 || 202 ui->ui_alive == 0) 203 return (ENXIO); 204 (void) spl7(); 205 lpaaddr->lcim = RESET; 206 lpaaddr->lcim = 0; 207 (void) spl0(); 208 lpaaddr->lcos = 0; /* clear the registers as a precaution */ 209 lpaaddr->lrda = 0; 210 lpaaddr->lms = 0; 211 sc->sc_flag = OPEN; 212 sc->sc_device = LPADEVICE(dev); 213 sc->sc_channel = LPACHANNEL(dev); 214 sc->sc_buffer = geteblk(); 215 sc->sc_buffer->b_error = 0; 216 sc->sc_buffer->b_proc = u.u_procp; 217 sc->sc_ubufn = -1; 218 /* THIS SHOULD EVENTUALLY SPECIFY "REAL-TIME" */ 219 u.u_procp->p_nice = NICE; 220 return (0); 221 } 222 223 lpaclose(dev, flag) 224 dev_t dev; 225 int flag; 226 { 227 register int unit = LPAUNIT(dev); 228 register struct lpa_softc *sc = &lpa_softc[unit]; 229 register struct uba_device *ui = lpadinfo[unit]; 230 register struct lpadevice *lpaaddr = (struct lpadevice *) ui->ui_addr; 231 232 if (sc->sc_device && sc->sc_ubufn >= 0 && (sc->sc_flag & ERROR) == 0) { 233 if (sc->sc_start) 234 lpacmd(sc->sc_buffer, lpaaddr, sc, ui->ui_ubanum); 235 sc->sc_flag |= STOP; 236 (void) spl5(); 237 while (sc->sc_flag & STOP) { 238 TRACER("SLEEP\n"); 239 sc->sc_flag |= SLEEP; 240 sleep((caddr_t)sc, LPAPRI); 241 } 242 } 243 (void) spl7(); 244 lpaaddr->lcim = RESET; 245 lpaaddr->lcim = 0; 246 (void) spl0(); 247 if (sc->sc_ubabuf) { 248 ubarelse(ui->ui_ubanum, &sc->sc_ubabuf); 249 sc->sc_ubabuf = 0; 250 (void) spl6(); 251 vsunlock(sc->sc_ubuffer.b_un.b_addr, sc->sc_ubuffer.b_bcount, 252 (sc->sc_device)? B_READ : B_WRITE); 253 u.u_procp->p_flag &= ~SPHYSIO; 254 (void) spl0(); 255 } 256 if (sc->sc_ubaustat) { 257 ubarelse(ui->ui_ubanum, &sc->sc_ubaustat); 258 sc->sc_ubaustat = 0; 259 } 260 if (sc->sc_buffer) { 261 brelse(sc->sc_buffer); 262 sc->sc_buffer = 0; 263 } 264 sc->sc_flag = 0; 265 TRACER("CLOSE\n"); 266 } 267 268 lpawrite(dev, uio) 269 dev_t dev; 270 struct uio *uio; 271 { 272 register int unit = LPAUNIT(dev); 273 register struct lpa_softc *sc = &lpa_softc[unit]; 274 register struct uba_device *ui = lpadinfo[unit]; 275 register struct lpadevice *lpaaddr = (struct lpadevice *) ui->ui_addr; 276 register int f; 277 278 TRACER("WRITE\n"); 279 f = sc->sc_flag; 280 if ((f & OPEN) == 0) 281 return (ENXIO); 282 if ((f & MCODE) == 0) /* first write is the microcode */ 283 return (lpamcode(lpaaddr, sc, uio)); 284 if ((f & DMDT) == 0) /* second write is the dispatch table */ 285 return (lpadmdt(lpaaddr, sc, ui->ui_ubanum, uio)); 286 return (ENXIO); 287 } 288 289 lpamcode(lpaaddr, sc, uio) 290 register struct lpadevice *lpaaddr; 291 register struct lpa_softc *sc; 292 struct uio *uio; 293 { 294 short v, r; 295 register int mcaddr; 296 int error; 297 298 mcaddr = 0; 299 while (uio->uio_resid) { 300 error = uiomove(&v, 2, UIO_WRITE, uio); 301 if (error) 302 break; 303 lpaaddr->lcim = 0; /* load microcode word */ 304 lpaaddr->lrda = mcaddr; 305 lpaaddr->lms = v; 306 lpaaddr->lcim = ROMO; 307 lpaaddr->lcim |= CWRITE; 308 lpaaddr->lcim = 0; /* verify microcode word */ 309 lpaaddr->lrda = mcaddr; 310 lpaaddr->lcim = ROMO; 311 if ((r = lpaaddr->lms) != v) { 312 /* download failure */ 313 printf("LPA MICROCODE FAIL: exp:%o got:%o\n", v, r); 314 return (ENXIO); 315 } 316 mcaddr++; 317 } 318 lpaaddr->lcim = RUN | EA; /* turn it on */ 319 sc->sc_flag |= MCODE; 320 lpaaddr->lcim |= IIE; 321 lpaaddr->lcos |= OIE; 322 return (error); 323 TRACER("MCODE\n"); 324 } 325 326 lpadmdt(lpaaddr, sc, ubanum, uio) 327 register struct lpadevice *lpaaddr; 328 register struct lpa_softc *sc; 329 register short ubanum; 330 struct uio *uio; 331 { 332 register short *p; 333 register int n; 334 int error; 335 336 p = (short *) sc->sc_buffer->b_un.b_addr; /* INIT */ 337 *p++ = (MCVERS << 8) | INIT; /* mode */ 338 *p++ = ACLOCKA; /* LPA bus device addresses */ 339 *p++ = ACLOCKB; 340 *p++ = AAD1; 341 *p++ = AAD2; 342 *p++ = ADA; 343 *p++ = ADIO1; 344 *p++ = ADIO2; 345 *p++ = ADIO3; 346 *p++ = ADIO4; 347 *p++ = ADIO5; 348 n = min(uio->uio_resid, 256); /* dedicated mode dispatch table */ 349 error = uiomove((char *)p, n, UIO_WRITE, uio); 350 if (error) 351 return (error); 352 n >>= 1; 353 p += n; 354 while (n++ < 128) 355 *p++ = 0; 356 lpacmd(sc->sc_buffer, lpaaddr, sc, ubanum); 357 sc->sc_flag |= DMDT; 358 return (0); 359 TRACER("DMDT\n"); 360 } 361 362 lpaioctl(dev, cmd, data, flag) 363 dev_t dev; 364 caddr_t data; 365 { 366 register int unit = LPAUNIT(dev); 367 register struct lpa_softc *sc = &lpa_softc[unit]; 368 register struct uba_device *ui = lpadinfo[unit]; 369 register struct lpadevice *lpaaddr = (struct lpadevice *) ui->ui_addr; 370 register short *p; 371 register int i; 372 register int v; 373 struct iocb { 374 short *baddr; 375 short rate; 376 short wc; 377 } *iocb; 378 379 TRACER("IOCTL IN\n"); 380 if (cmd != TIOCSETP || (sc->sc_flag & DMDT) == 0) 381 return (ENXIO); 382 iocb = (struct iocb *)data; 383 p = (short *) sc->sc_buffer->b_un.b_addr; /* CLOCK START */ 384 *p++ = CLOCK | CLOCKA; /* mode */ 385 *p++ = ENACTR | R1M | MFIE | MRI; /* clock status */ 386 *p = iocb->rate; /* clock preset */ 387 lpacmd(sc->sc_buffer, lpaaddr, sc, ui->ui_ubanum); 388 TRACER("CLOCK STARTED\n"); 389 p = (short *) sc->sc_buffer->b_un.b_addr; /* DATA TRANSFER START*/ 390 *p++ = (sc->sc_device << 7) | DTS | SCHAN; /* mode */ 391 sc->sc_count = iocb->wc & 017777; /* word count per buffer */ 392 *p++ = sc->sc_count; 393 /* user status word */ 394 sc->sc_ustatbuf.b_un.b_addr = (caddr_t) &sc->sc_ustat; 395 sc->sc_ustatbuf.b_flags = 0; 396 sc->sc_ustatbuf.b_bcount = 2; 397 sc->sc_ustatbuf.b_proc = u.u_procp; 398 sc->sc_ubaustat = ubasetup(ui->ui_ubanum, &sc->sc_ustatbuf, 0); 399 v = sc->sc_ubaustat; 400 *p++ = v; 401 *p = (v >> 16) & 03; /* into low portion of word */ 402 sc->sc_nbuf = (iocb->wc >> 13) & 07; /* number of buffers */ 403 *p++ |= sc->sc_nbuf++ << 8; /* into high portion of word */ 404 /* buffer addresses */ 405 if (useracc(sc->sc_ubuffer.b_un.b_addr = (caddr_t) iocb->baddr, 406 sc->sc_ubuffer.b_bcount = sc->sc_count * sc->sc_nbuf * 2, 407 (i = (sc->sc_device)? B_READ : B_WRITE) ) == NULL) { 408 TRACER("USER BUFFER FAULT\n"); 409 return (EFAULT); 410 } 411 sc->sc_ubuffer.b_flags = B_PHYS | B_BUSY | i; 412 sc->sc_ubuffer.b_proc = u.u_procp; 413 u.u_procp->p_flag |= SPHYSIO; 414 vslock(sc->sc_ubuffer.b_un.b_addr, sc->sc_ubuffer.b_bcount); 415 sc->sc_ubabuf = ubasetup(ui->ui_ubanum, &sc->sc_ubuffer, 0); 416 v = sc->sc_ubabuf; 417 for (i = 0; i < sc->sc_nbuf; i++) { 418 *p++ = v; 419 *p++ = (v >> 16) & 03; 420 v += sc->sc_count * 2; 421 } 422 for ( ; i <= 7; i++) { 423 *p++ = 0; 424 *p++ = 0; 425 } 426 *p++ = 0; *p++ = 0; /* random channel list address */ 427 *p++ = 0; /* delay */ 428 *p++ = sc->sc_channel; /* start channel, channel inc */ 429 *p++ = 1; /* number of samples in a sequence */ 430 *p++ = 0; /* dwell */ 431 *p++ = 0; /* start word no., event mark word */ 432 *p++ = 0; /* start word mask */ 433 *p = 0; /* event mark mask */ 434 sc->sc_ustat = 0; 435 sc->sc_start = (sc->sc_device)? sc->sc_nbuf+1 : 1; 436 sc->sc_lbufn = 0; 437 sc->sc_lbufnx = 0; 438 sc->sc_flag |= STTY; 439 TRACER("IOCTL OUT\n"); 440 return (0); 441 } 442 443 lparead(dev, uio) 444 dev_t dev; 445 struct uio *uio; 446 { 447 register int unit = LPAUNIT(dev); 448 register struct lpa_softc *sc = &lpa_softc[unit]; 449 register struct uba_device *ui = lpadinfo[unit]; 450 register struct lpadevice *lpaaddr = (struct lpadevice *) ui->ui_addr; 451 452 TRACER("READ\n"); 453 if ((sc->sc_flag & STTY) == 0) 454 return (ENXIO); 455 if (sc->sc_flag & ERROR) 456 return (ENXIO); 457 if (sc->sc_start) 458 if (--sc->sc_start == 0) { 459 lpacmd(sc->sc_buffer, lpaaddr, sc, ui->ui_ubanum); 460 TRACER("START\n"); 461 } 462 inc(sc_ubufn); 463 if (sc->sc_start == 0) { 464 (void) spl5(); 465 while (sc->sc_ubufn == sc->sc_lbufn) { 466 if (sc->sc_flag & ERROR) 467 return (ENXIO); 468 TRACER("SLEEP\n"); 469 sc->sc_flag |= SLEEP; 470 sleep(sc, LPAPRI); 471 } 472 (void) spl0(); 473 } 474 TRACERN("READ %d\n", sc->sc_ubufn); 475 return (uiomove(&sc->sc_ubufn, 1, UIO_READ, uio)); 476 } 477 478 lpacmd(bp, lpaaddr, sc, ubanum) 479 register struct buf *bp; 480 register struct lpadevice *lpaaddr; 481 register struct lpa_softc *sc; 482 register short ubanum; 483 { 484 int ubareg; 485 486 TRACER("CMD\n"); 487 ubareg = ubasetup(ubanum, bp, UBA_NEEDBDP); 488 lpawait(lpaaddr, sc); 489 lpaaddr->lrda = ubareg; 490 lpaaddr->lcim &= ~RDAEXT; 491 lpaaddr->lcim |= ((ubareg >> (16-RDAEXTOFFSET)) & RDAEXT) | GO; 492 lpawait(lpaaddr, sc); 493 ubarelse(ubanum, &ubareg); 494 } 495 496 lpawait(lpaaddr, sc) 497 register struct lpadevice *lpaaddr; 498 register struct lpa_softc *sc; 499 { 500 501 (void) spl5(); 502 while ((lpaaddr->lcim & READYI) == 0) { 503 TRACER("SLEEP\n"); 504 sc->sc_flag |= SLEEP; 505 sleep((caddr_t)sc, LPAPRI); 506 } 507 (void) spl0(); 508 } 509 510 lpaiintr(unit) 511 int unit; 512 { 513 register struct lpa_softc *sc = &lpa_softc[unit]; 514 515 TRACER("{I"); 516 if (sc->sc_flag & SLEEP) { 517 TRACER("<WAKEUP>"); 518 wakeup((caddr_t)sc); 519 sc->sc_flag &= ~SLEEP; 520 } 521 TRACER("}"); 522 } 523 524 lpaointr(unit) 525 int unit; 526 { 527 register int c, m; 528 register struct lpa_softc *sc = &lpa_softc[unit]; 529 register struct uba_device *ui = lpadinfo[unit]; 530 register struct lpadevice *lpaaddr = (struct lpadevice *) ui->ui_addr; 531 int spx; 532 533 TRACER("{O"); 534 if (sc->sc_flag & SLEEP) { 535 TRACER("<WAKEUP>"); 536 wakeup(sc); 537 sc->sc_flag &= ~SLEEP; 538 } 539 c = lpaaddr->lcos; 540 m = lpaaddr->lms; 541 lpaaddr->lcos &= ~READYO; 542 if (c & ERROR) { 543 TRACER("<ERROR>"); 544 c = (c >> 8) & 0377; 545 if ((sc->sc_flag & STOP) == 0 || (c != OVERRUN)) { 546 printf("LPA ERROR %o %o\n", c, m&0177777); 547 sc->sc_flag |= ERROR; 548 } 549 sc->sc_flag &= ~STOP; 550 TRACER("}\n"); 551 return; 552 } 553 TRACERN("<LPA %d>", sc->sc_lbufnx); 554 sc->sc_lbufn = sc->sc_lbufnx; 555 if (sc->sc_ubufn == sc->sc_lbufnx && c & ECODE) { 556 TRACER("<STOP?>"); 557 if (sc->sc_flag & STOP) 558 return; 559 printf("LPA OVERRUN\n"); 560 sc->sc_flag |= ERROR; 561 } 562 inc(sc_lbufnx); 563 TRACERN("<USTAT %o>", sc->sc_ustat); 564 spx = spl7(); 565 sc->sc_ustat &= ~NBI; 566 sc->sc_ustat |= sc->sc_lbufnx << 8; 567 sc->sc_ustat &= ~DONE; 568 (void) splx(spx); 569 TRACERN("<LPAN %d>}", sc->sc_lbufnx); 570 } 571 572 lpareset(uban) 573 int uban; 574 { 575 register struct uba_device *ui; 576 register struct lpadevice *lpaaddr; 577 register struct lpa_softc *sc; 578 register int unit; 579 580 TRACER("LPA RESET\n"); 581 for (unit = 0; unit < NLPA; unit++) { 582 if ((ui = lpadinfo[unit]) == 0 || 583 ui->ui_ubanum != uban || ui->ui_alive == 0) 584 continue; 585 printf(" lpa%d", unit); 586 lpaaddr = (struct lpadevice *)ui->ui_addr; 587 sc = &lpa_softc[unit]; 588 sc->sc_flag |= ERROR; 589 (void) spl7(); 590 lpaaddr->lcim = RESET; 591 lpaaddr->lcim = 0; 592 (void) spl0(); 593 if (sc->sc_flag & SLEEP) { 594 wakeup((caddr_t)sc); 595 sc->sc_flag &= ~SLEEP; 596 } 597 } 598 } 599 #endif NLPA 600