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