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