1*7729Sroot /* lpa.c 4.4 82/08/13 */ 26968Ssam #include "lpa.h" 36968Ssam #if NLPA > 0 46968Ssam 56968Ssam #include "../h/param.h" 66968Ssam #include "../h/dir.h" 76968Ssam #include "../h/user.h" 86968Ssam #include "../h/buf.h" 96968Ssam #include "../h/ubavar.h" 106968Ssam #include "../h/proc.h" 116968Ssam #include "../h/ioctl.h" 12*7729Sroot #include "../h/uio.h" 136968Ssam 146968Ssam /* 156968Ssam * LPA driver for 4.1BSD 166968Ssam * Asa Romberger 176968Ssam * method of usage: 186968Ssam * open 196968Ssam * write microcode 206968Ssam * write dedicated mode dispatch table 216968Ssam * ioctl TIOCSETP to set parameters 226968Ssam * struct iocb { 236968Ssam * short *baddr; buffer address 246968Ssam * short rate; - 1,000,000 / frequency in Hz 256968Ssam * short wc; 15-13 = number of buffers - 1 266968Ssam * 12-0 = buffer size in words 276968Ssam * } iocb; 286968Ssam * read - 1 character indicating buffer index 296968Ssam * fill or empty buffer 306968Ssam * minor device number = DDCCCCCC where: 316968Ssam * DD = 00 for analog input 326968Ssam * = 01 for analog output 336968Ssam * CCCCCC = channel number 346968Ssam */ 356968Ssam /* 366968Ssam * define TRACELPA to get trace printouts on the console 376968Ssam * define NOMCODE to eliminate the microcode download check 386968Ssam */ 396968Ssam /* #define NOMCODE */ 406968Ssam 416968Ssam #ifdef TRACELPA 426968Ssam # define TRACER(x) printf(x) 436968Ssam # define TRACERN(x, d) printf(x, d) 446968Ssam #else 456968Ssam # define TRACER(x) 466968Ssam # define TRACERN(x, d) 476968Ssam #endif 486968Ssam 496968Ssam /* PRIORITY AT WHICH PROGRAM SHOULD RUN */ 506968Ssam /* THIS SHOULD EVENTUALLY TELL UNIX THIS IS A REAL-TIME DEVICE */ 516968Ssam 526968Ssam #define NICE 0 536968Ssam 546968Ssam /* WAKEUP PRIORITY */ 556968Ssam 566968Ssam #define LPAPRI (PZERO + 0) 576968Ssam 586968Ssam /* MACRO DEFINITIONS */ 596968Ssam #define inc(v) (sc->v = ((sc->v + 1) % sc->sc_nbuf)) 606968Ssam #define LPAUNIT(dev) 0 616968Ssam #define LPADEVICE(dev) (((dev) >> 6) & 03) 626968Ssam #define LPACHANNEL(dev) ((dev) & 077) 636968Ssam 646968Ssam /* DEFINITIONS FOR INTERACTION WITH UNIX I/O */ 656968Ssam 666968Ssam int lpaprobe(), /*lpaslave(),*/ lpaattach() /*,lpadgo()*/; 676968Ssam int lpaiintr(), lpaointr(); 686968Ssam u_short lpastd[] = {0170460, 0}; 696968Ssam struct uba_device *lpadinfo[NLPA]; 706968Ssam /*struct uba_ctlr *lpaminfo[Ndevice name];*/ 716968Ssam struct uba_driver lpadriver = 726968Ssam {lpaprobe, 0/*lpaslave*/, lpaattach, 0/*lpadgo*/, lpastd, 736968Ssam "lpa", lpadinfo, 0/*"device name"*/, 0/*lpaminfo*/, 0/*exclusive use*/}; 746968Ssam 756968Ssam 766968Ssam /* LPA SOFTWARE OPERATION FLAGS */ 776968Ssam 786968Ssam struct lpa_softc { 796968Ssam int sc_flag; /* flags, as defined below */ 806968Ssam int sc_device; /* device: 0 = analog in, 1 = analog out */ 816968Ssam int sc_channel; /* device channel number */ 826968Ssam struct buf sc_ubuffer; /* user buffer header */ 836968Ssam int sc_ubabuf; /* uba allocation pointer for buffer */ 846968Ssam int sc_ubufn; /* present buffer that user is accessing */ 856968Ssam int sc_lbufn; /* present buffer that lpa is accessing */ 866968Ssam int sc_lbufnx; /* next buffer for lpa (value in ustat) */ 876968Ssam int sc_nbuf; /* number of buffers */ 886968Ssam int sc_count; /* buffer size in words */ 896968Ssam short sc_ustat; /* user status word */ 906968Ssam struct buf sc_ustatbuf; /* dummy user status word buffer for ubasetup */ 916968Ssam int sc_ubaustat; /* uba allocation pointer for ustat */ 926968Ssam struct buf *sc_buffer; /* scratch buffer header */ 936968Ssam int sc_start; /* 0 if lpa operation has been started */ 946968Ssam } lpa_softc[NLPA]; 956968Ssam /* flag bits */ 966968Ssam #define OPEN 01 /* device is open */ 976968Ssam #define MCODE 02 /* microcode has been loaded */ 986968Ssam #define DMDT 04 /* dedicated mode dispatch table loaded */ 996968Ssam #define STTY 010 /* stty call and device initialized */ 1006968Ssam #define SLEEP 020 /* sleeping */ 1016968Ssam /* ustat bits */ 1026968Ssam #define DONE 0100000 /* done */ 1036968Ssam #define STOP 0040000 /* stop data transfer */ 1046968Ssam #define NBI 0003400 /* next buffer index */ 1056968Ssam #define LBI 0000003 /* last buffer index */ 1066968Ssam 1076968Ssam /* DEVICE REGISTER DESCRIPTION AREA */ 1086968Ssam 1096968Ssam struct lpadevice { 1106968Ssam short lcim; /* control in and maintenance */ 1116968Ssam short lcos; /* control and status out */ 1126968Ssam short lrda; /* request description array address word */ 1136968Ssam short lms; /* maintenance status */ 1146968Ssam }; 1156968Ssam /* control in and maintenance register bits */ 1166968Ssam #define READYI 0000200 /* ready in */ 1176968Ssam #define IIE 0000100 /* in interrupt enable */ 1186968Ssam #define RDAEXT 0000014 /* rda address extension */ 1196968Ssam #define RDAEXTOFFSET 2 /* offset of RDAEXT from right side */ 1206968Ssam #define GO 0000001 /* go */ 1216968Ssam #define RUN 0100000 /* run */ 1226968Ssam #define RESET 0040000 /* reset */ 1236968Ssam #define CWRITE 0020000 /* cram write */ 1246968Ssam #define EA 0004000 /* enable arbitration */ 1256968Ssam #define ROMO 0002000 /* rom O */ 1266968Ssam #define ROMI 0001000 /* rom I */ 1276968Ssam #define SMICRO 0000400 /* step microprocessor */ 1286968Ssam /* control and status out register bits */ 1296968Ssam #define READYO 0200 /* ready out */ 1306968Ssam #define OIE 0100 /* out interrupt enable */ 1316968Ssam #define UINDEX 0007 /* user index */ 1326968Ssam #define ERROR 0100000 /* error */ 1336968Ssam #define ESTAT 0060000 /* error status */ 1346968Ssam #define ESCODE 0017400 /* error sub code */ 1356968Ssam #define ECODE 0077400 /* error status + error sub code */ 1366968Ssam #define OVERRUN 0243 /* overrun error */ 1376968Ssam 1386968Ssam /* LPA COMMAND DESCRIPTION AREA */ 1396968Ssam 1406968Ssam /* INIT COMMAND */ 1416968Ssam #define INIT 0 /* mode */ 1426968Ssam #define MCVERS 4 /* microcode version */ 1436968Ssam #define ACLOCKA 0170404 /* LPA bus addresses */ 1446968Ssam #define ACLOCKB 0170432 1456968Ssam #define AAD1 0170400 1466968Ssam #define AAD2 1 /* 0170440 - DOES NOT EXIST */ 1476968Ssam #define ADA 0170420 1486968Ssam #define ADIO1 1 /* 0167770 - DOES NOT EXIST */ 1496968Ssam #define ADIO2 1 /* 0167760 - DOES NOT EXIST */ 1506968Ssam #define ADIO3 1 /* 0167750 - DOES NOT EXIST */ 1516968Ssam #define ADIO4 1 /* 0167740 - DOES NOT EXIST */ 1526968Ssam #define ADIO5 1 /* 0167730 - DOES NOT EXIST */ 1536968Ssam /* CLOCK START COMMAND */ 1546968Ssam #define CLOCK 1 /* mode */ 1556968Ssam #define CLOCKA 0<<4 /* clock A */ 1566968Ssam /* clock status word */ 1576968Ssam #define ENACTR 1 /* enable counter */ 1586968Ssam #define R1M 1<<1 /* 1 MHz rate */ 1596968Ssam #define R100K 2<<1 /* 100 KHz rate */ 1606968Ssam #define R10K 3<<1 /* 10 KHz rate */ 1616968Ssam #define R1K 4<<1 /* 1 KHz rate */ 1626968Ssam #define R100 5<<1 /* 100 Hz rate */ 1636968Ssam #define REXT 6<<1 /* external rate (from st1 input) */ 1646968Ssam #define R60 7<<1 /* line frequency rate */ 1656968Ssam #define MFIE 0100 /* mode flag interrupt enable */ 1666968Ssam #define MSI 0<<8 /* single interval mode */ 1676968Ssam #define MRI 1<<8 /* repeat interval mode */ 1686968Ssam #define MEET 2<<8 /* external event time mode */ 1696968Ssam #define MEETZ 3<<8 /* external event time mode from zero base */ 1706968Ssam #define ST1EC 020000 /* st1 enable counter */ 1716968Ssam #define ST1IE 040000 /* st1 interrupt enable */ 1726968Ssam /* DATA TRANSFER START COMMAND */ 1736968Ssam #define DTS 2 /* mode */ 1746968Ssam #define SCHAN 1<<8 /* single channel */ 1756968Ssam 1766968Ssam /* THE ROUTINES THEMSELVES */ 1776968Ssam 1786968Ssam /* 1796968Ssam * probe lpa to get br level and interrupt vector 1806968Ssam */ 1816968Ssam lpaprobe(reg) 1826968Ssam caddr_t reg; 1836968Ssam { 1846968Ssam register int br, cvec; /* value result (required for UNIX) */ 1856968Ssam register struct lpadevice *lpaaddr = (struct lpadevice *) reg; 1866968Ssam 1876968Ssam #ifdef lint 1886968Ssam br = 0; cvec = br; br = cvec; 1896968Ssam #endif 1906968Ssam /* this should force an interrupt, stall, clear the lpa */ 1916968Ssam br = 0x15; 1926968Ssam cvec = 0330; 1936968Ssam TRACER("PROBE\n"); 1947413Skre return (sizeof (struct lpadevice)); 1956968Ssam } 1966968Ssam 1976968Ssam /* 1986968Ssam * attach the specified controller 1996968Ssam */ 2006968Ssam lpaattach(ui) 2016968Ssam register struct upa_device *ui; 2026968Ssam { 2036968Ssam /* any stuff necessary for initialization can go here */ 2046968Ssam } 2056968Ssam 2066968Ssam /* 2076968Ssam * open the device 2086968Ssam */ 2096968Ssam lpaopen(dev, flag) 2106968Ssam dev_t dev; 2116968Ssam int flag; 2126968Ssam { 2136968Ssam register int unit = LPAUNIT(dev); 2146968Ssam register struct lpa_softc *sc = &lpa_softc[unit]; 2156968Ssam register struct uba_device *ui = lpadinfo[unit]; 2166968Ssam register struct lpadevice *lpaaddr = (struct lpadevice *) ui->ui_addr; 2176968Ssam 2186968Ssam TRACER("OPEN\n"); 2196968Ssam if (unit >= NLPA || sc->sc_flag & OPEN || ui == 0 || 2206968Ssam ui->ui_alive == 0) { 2216968Ssam u.u_error = ENXIO; 2226968Ssam return; 2236968Ssam } 2246968Ssam (void) spl7(); 2256968Ssam lpaaddr->lcim = RESET; 2266968Ssam lpaaddr->lcim = 0; 2276968Ssam (void) spl0(); 2286968Ssam lpaaddr->lcos = 0; /* clear the registers as a precaution */ 2296968Ssam lpaaddr->lrda = 0; 2306968Ssam lpaaddr->lms = 0; 2316968Ssam sc->sc_flag = OPEN; 2326968Ssam sc->sc_device = LPADEVICE(dev); 2336968Ssam sc->sc_channel = LPACHANNEL(dev); 2346968Ssam sc->sc_buffer = geteblk(); 2356968Ssam sc->sc_buffer->b_error = 0; 2366968Ssam sc->sc_buffer->b_proc = u.u_procp; 2376968Ssam sc->sc_ubufn = -1; 2386968Ssam /* THIS SHOULD EVENTUALLY SPECIFY "REAL-TIME" */ 2396968Ssam u.u_procp->p_nice = NICE; 2406968Ssam } 2416968Ssam 2426968Ssam /* 2436968Ssam * close the device 2446968Ssam */ 2456968Ssam lpaclose(dev, flag) 2466968Ssam dev_t dev; 2476968Ssam int flag; 2486968Ssam { 2496968Ssam register int unit = LPAUNIT(dev); 2506968Ssam register struct lpa_softc *sc = &lpa_softc[unit]; 2516968Ssam register struct uba_device *ui = lpadinfo[unit]; 2526968Ssam register struct lpadevice *lpaaddr = (struct lpadevice *) ui->ui_addr; 2536968Ssam 2546968Ssam if (sc->sc_device && sc->sc_ubufn >= 0 && (sc->sc_flag & ERROR) == 0) { 2556968Ssam if (sc->sc_start) 2566968Ssam lpacmd(sc->sc_buffer, lpaaddr, sc, ui->ui_ubanum); 2576968Ssam sc->sc_flag |= STOP; 2586968Ssam (void) spl5(); 2596968Ssam while (sc->sc_flag & STOP) { 2606968Ssam TRACER("SLEEP\n"); 2616968Ssam sc->sc_flag |= SLEEP; 2626968Ssam sleep((caddr_t)sc, LPAPRI); 2636968Ssam } 2646968Ssam } 2656968Ssam (void) spl7(); 2666968Ssam lpaaddr->lcim = RESET; 2676968Ssam lpaaddr->lcim = 0; 2686968Ssam (void) spl0(); 2696968Ssam if (sc->sc_ubabuf) { 2706968Ssam ubarelse(ui->ui_ubanum, &sc->sc_ubabuf); 2716968Ssam sc->sc_ubabuf = 0; 2726968Ssam (void) spl6(); 2736968Ssam vsunlock(sc->sc_ubuffer.b_un.b_addr, sc->sc_ubuffer.b_bcount, 2746968Ssam (sc->sc_device)? B_READ : B_WRITE); 2756968Ssam u.u_procp->p_flag &= ~SPHYSIO; 2766968Ssam (void) spl0(); 2776968Ssam } 2786968Ssam if (sc->sc_ubaustat) { 2796968Ssam ubarelse(ui->ui_ubanum, &sc->sc_ubaustat); 2806968Ssam sc->sc_ubaustat = 0; 2816968Ssam } 2826968Ssam if (sc->sc_buffer) { 2836968Ssam brelse(sc->sc_buffer); 2846968Ssam sc->sc_buffer = 0; 2856968Ssam } 2866968Ssam sc->sc_flag = 0; 2876968Ssam TRACER("CLOSE\n"); 2886968Ssam } 2896968Ssam 2906968Ssam /* 2916968Ssam * write 2926968Ssam * first write is the microcode 2936968Ssam * second write is the dispatch table 2946968Ssam */ 2956968Ssam lpawrite(dev) 2966968Ssam dev_t dev; 2976968Ssam { 2986968Ssam register int unit = LPAUNIT(dev); 2996968Ssam register struct lpa_softc *sc = &lpa_softc[unit]; 3006968Ssam register struct uba_device *ui = lpadinfo[unit]; 3016968Ssam register struct lpadevice *lpaaddr = (struct lpadevice *) ui->ui_addr; 3026968Ssam register int f; 3036968Ssam 3046968Ssam TRACER("WRITE\n"); 3056968Ssam f = sc->sc_flag; 3066968Ssam if ((f & OPEN) == 0) { 3076968Ssam u.u_error = ENXIO; 3086968Ssam return; 3096968Ssam } 3106968Ssam if ((f & MCODE) == 0) { 3116968Ssam lpamcode(lpaaddr, sc); 3126968Ssam return; 3136968Ssam } 3146968Ssam if ((f & DMDT) == 0) { 3156968Ssam lpadmdt(lpaaddr, sc, ui->ui_ubanum); 3166968Ssam return; 3176968Ssam } 3186968Ssam /* writes are only for microcode and dedicated mode dispatch table */ 3196968Ssam u.u_error = ENXIO; 3206968Ssam } 3216968Ssam 3226968Ssam lpamcode(lpaaddr, sc) 3236968Ssam register struct lpadevice *lpaaddr; 3246968Ssam register struct lpa_softc *sc; 3256968Ssam { 3266968Ssam short v, r; 3276968Ssam register int mcaddr; 3286968Ssam 3296968Ssam mcaddr = 0; 3306968Ssam while (u.u_count) { 3316968Ssam iomove(&v, 2, B_WRITE); /* get next microcode word */ 3326968Ssam lpaaddr->lcim = 0; /* load microcode word */ 3336968Ssam lpaaddr->lrda = mcaddr; 3346968Ssam lpaaddr->lms = v; 3356968Ssam lpaaddr->lcim = ROMO; 3366968Ssam lpaaddr->lcim |= CWRITE; 3376968Ssam lpaaddr->lcim = 0; /* verify microcode word */ 3386968Ssam lpaaddr->lrda = mcaddr; 3396968Ssam lpaaddr->lcim = ROMO; 3406968Ssam if ((r = lpaaddr->lms) != v) { 3416968Ssam /* download failure */ 3426968Ssam printf("LPA MICROCODE FAIL: exp:%o got:%o\n", v, r); 3436968Ssam u.u_error = ENXIO; 3446968Ssam return; 3456968Ssam } 3466968Ssam mcaddr++; 3476968Ssam } 3486968Ssam lpaaddr->lcim = RUN | EA; /* turn it on */ 3496968Ssam sc->sc_flag |= MCODE; 3506968Ssam lpaaddr->lcim |= IIE; 3516968Ssam lpaaddr->lcos |= OIE; 3526968Ssam TRACER("MCODE\n"); 3536968Ssam } 3546968Ssam 3556968Ssam lpadmdt(lpaaddr, sc, ubanum) 3566968Ssam register struct lpadevice *lpaaddr; 3576968Ssam register struct lpa_softc *sc; 3586968Ssam register short ubanum; 3596968Ssam { 3606968Ssam register short *p; 3616968Ssam register int n; 3626968Ssam 3636968Ssam p = (short *) sc->sc_buffer->b_un.b_addr; /* INIT */ 3646968Ssam *p++ = (MCVERS << 8) | INIT; /* mode */ 3656968Ssam *p++ = ACLOCKA; /* LPA bus device addresses */ 3666968Ssam *p++ = ACLOCKB; 3676968Ssam *p++ = AAD1; 3686968Ssam *p++ = AAD2; 3696968Ssam *p++ = ADA; 3706968Ssam *p++ = ADIO1; 3716968Ssam *p++ = ADIO2; 3726968Ssam *p++ = ADIO3; 3736968Ssam *p++ = ADIO4; 3746968Ssam *p++ = ADIO5; 3756968Ssam n = min(u.u_count, 256); /* dedicated mode dispatch table */ 3766968Ssam iomove((char *) p, n, B_WRITE); 3776968Ssam n >>= 1; 3786968Ssam p += n; 3796968Ssam while (n++ < 128) 3806968Ssam *p++ = 0; 3816968Ssam lpacmd(sc->sc_buffer, lpaaddr, sc, ubanum); 3826968Ssam sc->sc_flag |= DMDT; 3836968Ssam TRACER("DMDT\n"); 3846968Ssam } 3856968Ssam 3867632Ssam lpaioctl(dev, cmd, data, flag) 3877632Ssam dev_t dev; 3887632Ssam caddr_t data; 3896968Ssam { 3906968Ssam register int unit = LPAUNIT(dev); 3916968Ssam register struct lpa_softc *sc = &lpa_softc[unit]; 3926968Ssam register struct uba_device *ui = lpadinfo[unit]; 3936968Ssam register struct lpadevice *lpaaddr = (struct lpadevice *) ui->ui_addr; 3946968Ssam register short *p; 3956968Ssam register int i; 3966968Ssam register int v; 3976968Ssam struct iocb { 3986968Ssam short *baddr; 3996968Ssam short rate; 4006968Ssam short wc; 4017632Ssam } *iocb; 4026968Ssam 4036968Ssam TRACER("IOCTL IN\n"); 4046968Ssam if (cmd != TIOCSETP) { 4056968Ssam TRACER("NOT TIOCSETP\n"); 4066968Ssam /* not valid */ 4076968Ssam u.u_error = ENXIO; 4086968Ssam return; 4096968Ssam } 4106968Ssam #ifndef NOMCODE 4116968Ssam if ((sc->sc_flag & DMDT) == 0) { 4126968Ssam TRACER("NO DMDT\n"); 4136968Ssam u.u_error = ENXIO; 4146968Ssam return; 4156968Ssam } 4166968Ssam #endif 4177632Ssam iocb = (struct iocb *)data; 4186968Ssam p = (short *) sc->sc_buffer->b_un.b_addr; /* CLOCK START */ 4196968Ssam *p++ = CLOCK | CLOCKA; /* mode */ 4206968Ssam *p++ = ENACTR | R1M | MFIE | MRI; /* clock status */ 4217632Ssam *p = iocb->rate; /* clock preset */ 4226968Ssam lpacmd(sc->sc_buffer, lpaaddr, sc, ui->ui_ubanum); 4236968Ssam TRACER("CLOCK STARTED\n"); 4246968Ssam p = (short *) sc->sc_buffer->b_un.b_addr; /* DATA TRANSFER START*/ 4256968Ssam *p++ = (sc->sc_device << 7) | DTS | SCHAN; /* mode */ 4267632Ssam sc->sc_count = iocb->wc & 017777; /* word count per buffer */ 4276968Ssam *p++ = sc->sc_count; 4286968Ssam /* user status word */ 4296968Ssam sc->sc_ustatbuf.b_un.b_addr = (caddr_t) &sc->sc_ustat; 4306968Ssam sc->sc_ustatbuf.b_flags = 0; 4316968Ssam sc->sc_ustatbuf.b_bcount = 2; 4326968Ssam sc->sc_ustatbuf.b_proc = u.u_procp; 4336968Ssam sc->sc_ubaustat = ubasetup(ui->ui_ubanum, &sc->sc_ustatbuf, 0); 4346968Ssam v = sc->sc_ubaustat; 4356968Ssam *p++ = v; 4366968Ssam *p = (v >> 16) & 03; /* into low portion of word */ 4377632Ssam sc->sc_nbuf = (iocb->wc >> 13) & 07; /* number of buffers */ 4386968Ssam *p++ |= sc->sc_nbuf++ << 8; /* into high portion of word */ 4396968Ssam /* buffer addresses */ 4407632Ssam if (useracc(sc->sc_ubuffer.b_un.b_addr = (caddr_t) iocb->baddr, 4416968Ssam sc->sc_ubuffer.b_bcount = sc->sc_count * sc->sc_nbuf * 2, 4426968Ssam (i = (sc->sc_device)? B_READ : B_WRITE) ) == NULL) { 4436968Ssam TRACER("USER BUFFER FAULT\n"); 4446968Ssam u.u_error = EFAULT; 4456968Ssam return; 4466968Ssam } 4476968Ssam sc->sc_ubuffer.b_flags = B_PHYS | B_BUSY | i; 4486968Ssam sc->sc_ubuffer.b_proc = u.u_procp; 4496968Ssam u.u_procp->p_flag |= SPHYSIO; 4506968Ssam vslock(sc->sc_ubuffer.b_un.b_addr, sc->sc_ubuffer.b_bcount); 4516968Ssam /* sc->sc_ubabuf = ubasetup(ui->ui_ubanum, &sc->sc_ubuffer, UBA_NEEDBDP);*/ 4526968Ssam sc->sc_ubabuf = ubasetup(ui->ui_ubanum, &sc->sc_ubuffer, 0); 4536968Ssam v = sc->sc_ubabuf; 4546968Ssam for (i = 0; i < sc->sc_nbuf; i++) { 4556968Ssam *p++ = v; 4566968Ssam *p++ = (v >> 16) & 03; 4576968Ssam v += sc->sc_count * 2; 4586968Ssam } 4596968Ssam for ( ; i <= 7; i++) { 4606968Ssam *p++ = 0; 4616968Ssam *p++ = 0; 4626968Ssam } 4636968Ssam *p++ = 0; *p++ = 0; /* random channel list address */ 4646968Ssam *p++ = 0; /* delay */ 4656968Ssam *p++ = sc->sc_channel; /* start channel, channel inc */ 4666968Ssam *p++ = 1; /* number of samples in a sequence */ 4676968Ssam *p++ = 0; /* dwell */ 4686968Ssam *p++ = 0; /* start word no., event mark word */ 4696968Ssam *p++ = 0; /* start word mask */ 4706968Ssam *p = 0; /* event mark mask */ 4716968Ssam sc->sc_ustat = 0; 4726968Ssam sc->sc_start = (sc->sc_device)? sc->sc_nbuf+1 : 1; 4736968Ssam sc->sc_lbufn = 0; 4746968Ssam sc->sc_lbufnx = 0; 4756968Ssam sc->sc_flag |= STTY; 4766968Ssam TRACER("IOCTL OUT\n"); 4776968Ssam } 4786968Ssam 4796968Ssam /* 4806968Ssam * read 4816968Ssam * read 1 character only - the next available buffer number 4826968Ssam */ 483*7729Sroot lparead(dev, uio) 4846968Ssam dev_t dev; 485*7729Sroot struct uio *uio; 4866968Ssam { 4876968Ssam register int unit = LPAUNIT(dev); 4886968Ssam register struct lpa_softc *sc = &lpa_softc[unit]; 4896968Ssam register struct uba_device *ui = lpadinfo[unit]; 4906968Ssam register struct lpadevice *lpaaddr = (struct lpadevice *) ui->ui_addr; 4916968Ssam 4926968Ssam TRACER("READ\n"); 4936968Ssam if ((sc->sc_flag & STTY) == 0) { 4946968Ssam u.u_error = ENXIO; 4956968Ssam return; 4966968Ssam } 4976968Ssam if (sc->sc_flag & ERROR) { 4986968Ssam u.u_error = ENXIO; 4996968Ssam return; 5006968Ssam } 5016968Ssam if (sc->sc_start) 5026968Ssam if (--sc->sc_start == 0) { 5036968Ssam lpacmd(sc->sc_buffer, lpaaddr, sc, ui->ui_ubanum); 5046968Ssam TRACER("START\n"); 5056968Ssam } 5066968Ssam inc(sc_ubufn); 5076968Ssam if (sc->sc_start == 0) { 5086968Ssam (void) spl5(); 5096968Ssam while (sc->sc_ubufn == sc->sc_lbufn) { 5106968Ssam if (sc->sc_flag & ERROR) { 5116968Ssam u.u_error = ENXIO; 5126968Ssam return; 5136968Ssam } 5146968Ssam TRACER("SLEEP\n"); 5156968Ssam sc->sc_flag |= SLEEP; 5166968Ssam sleep(sc, LPAPRI); 5176968Ssam } 5186968Ssam (void) spl0(); 5196968Ssam } 5206968Ssam TRACERN("READ %d\n", sc->sc_ubufn); 521*7729Sroot uiomove(&sc->sc_ubufn, 1, B_READ, uio); 5226968Ssam } 5236968Ssam 5246968Ssam /* 5256968Ssam * execute a command and wait for completion 5266968Ssam */ 5276968Ssam lpacmd(bp, lpaaddr, sc, ubanum) 5286968Ssam register struct buf *bp; 5296968Ssam register struct lpadevice *lpaaddr; 5306968Ssam register struct lpa_softc *sc; 5316968Ssam register short ubanum; 5326968Ssam { 5336968Ssam int ubareg; 5346968Ssam 5356968Ssam TRACER("CMD\n"); 5366968Ssam /* bp->b_flags |= B_BUSY|B_WRITE; */ 5376968Ssam ubareg = ubasetup(ubanum, bp, UBA_NEEDBDP); 5386968Ssam lpawait(lpaaddr, sc); 5396968Ssam lpaaddr->lrda = ubareg; 5406968Ssam lpaaddr->lcim &= ~RDAEXT; 5416968Ssam lpaaddr->lcim |= ((ubareg >> (16-RDAEXTOFFSET)) & RDAEXT) | GO; 5426968Ssam lpawait(lpaaddr, sc); 5436968Ssam ubarelse(ubanum, &ubareg); 5446968Ssam /* bp->b_flags &= ~(B_BUSY|B_WRITE); */ 5456968Ssam } 5466968Ssam 5476968Ssam /* 5486968Ssam * wait for completion (ready input) 5496968Ssam */ 5506968Ssam lpawait(lpaaddr, sc) 5516968Ssam register struct lpadevice *lpaaddr; 5526968Ssam register struct lpa_softc *sc; 5536968Ssam { 5546968Ssam (void) spl5(); 5556968Ssam while ((lpaaddr->lcim & READYI) == 0) { 5566968Ssam TRACER("SLEEP\n"); 5576968Ssam sc->sc_flag |= SLEEP; 5586968Ssam sleep((caddr_t)sc, LPAPRI); 5596968Ssam } 5606968Ssam (void) spl0(); 5616968Ssam } 5626968Ssam 5636968Ssam /* 5646968Ssam * lpaiintr 5656968Ssam * in interrupt 5666968Ssam * LPA is now ready to accept a user request 5676968Ssam */ 5686968Ssam lpaiintr(unit) 5696968Ssam int unit; 5706968Ssam { 5716968Ssam register struct lpa_softc *sc = &lpa_softc[unit]; 5726968Ssam 5736968Ssam TRACER("{I"); 5746968Ssam if (sc->sc_flag & SLEEP) { 5756968Ssam TRACER("<WAKEUP>"); 5766968Ssam wakeup((caddr_t)sc); 5776968Ssam sc->sc_flag &= ~SLEEP; 5786968Ssam } 5796968Ssam TRACER("}"); 5806968Ssam } 5816968Ssam 5826968Ssam /* 5836968Ssam * lpaointr 5846968Ssam * out interrupt 5856968Ssam * LPA has status information 5866968Ssam */ 5876968Ssam lpaointr(unit) 5886968Ssam int unit; 5896968Ssam { 5906968Ssam register int c, m; 5916968Ssam register struct lpa_softc *sc = &lpa_softc[unit]; 5926968Ssam register struct uba_device *ui = lpadinfo[unit]; 5936968Ssam register struct lpadevice *lpaaddr = (struct lpadevice *) ui->ui_addr; 5946968Ssam int spx; 5956968Ssam 5966968Ssam TRACER("{O"); 5976968Ssam if (sc->sc_flag & SLEEP) { 5986968Ssam TRACER("<WAKEUP>"); 5996968Ssam wakeup(sc); 6006968Ssam sc->sc_flag &= ~SLEEP; 6016968Ssam } 6026968Ssam c = lpaaddr->lcos; 6036968Ssam m = lpaaddr->lms; 6046968Ssam lpaaddr->lcos &= ~READYO; 6056968Ssam if (c & ERROR) { 6066968Ssam TRACER("<ERROR>"); 6076968Ssam c = (c >> 8) & 0377; 6086968Ssam if ((sc->sc_flag & STOP) == 0 || (c != OVERRUN)) { 6096968Ssam printf("LPA ERROR %o %o\n", c, m&0177777); 6106968Ssam sc->sc_flag |= ERROR; 6116968Ssam } 6126968Ssam sc->sc_flag &= ~STOP; 6136968Ssam TRACER("}\n"); 6146968Ssam return; 6156968Ssam } 6166968Ssam TRACERN("<LPA %d>", sc->sc_lbufnx); 6176968Ssam sc->sc_lbufn = sc->sc_lbufnx; 6186968Ssam if (sc->sc_ubufn == sc->sc_lbufnx && c & ECODE) { 6196968Ssam TRACER("<STOP?>"); 6206968Ssam if (sc->sc_flag & STOP) 6216968Ssam return; 6226968Ssam printf("LPA OVERRUN\n"); 6236968Ssam sc->sc_flag |= ERROR; 6246968Ssam } 6256968Ssam inc(sc_lbufnx); 6266968Ssam TRACERN("<USTAT %o>", sc->sc_ustat); 6276968Ssam spx = spl7(); 6286968Ssam sc->sc_ustat &= ~NBI; 6296968Ssam sc->sc_ustat |= sc->sc_lbufnx << 8; 6306968Ssam sc->sc_ustat &= ~DONE; 6316968Ssam (void) splx(spx); 6326968Ssam TRACERN("<LPAN %d>}", sc->sc_lbufnx); 6336968Ssam } 6346968Ssam 6356968Ssam /* 6366968Ssam * reset called for a unibus reset 6376968Ssam */ 6386968Ssam lpareset(uban) 6396968Ssam int uban; 6406968Ssam { 6416968Ssam register struct uba_device *ui; 6426968Ssam register struct lpadevice *lpaaddr; 6436968Ssam register struct lpa_softc *sc; 6446968Ssam register int unit; 6456968Ssam 6466968Ssam TRACER("LPA RESET\n"); 6476968Ssam for (unit = 0; unit < NLPA; unit++) { 6486968Ssam if ( (ui = lpadinfo[unit]) == 0 || 6496968Ssam ui->ui_ubanum != uban || 6506968Ssam ui->ui_alive == 0) 6516968Ssam continue; 6526968Ssam printf(" lpa%d", unit); 6536968Ssam lpaaddr = (struct lpadevice *)ui->ui_addr; 6546968Ssam sc = &lpa_softc[unit]; 6556968Ssam sc->sc_flag |= ERROR; 6566968Ssam (void) spl7(); 6576968Ssam lpaaddr->lcim = RESET; 6586968Ssam lpaaddr->lcim = 0; 6596968Ssam (void) spl0(); 6606968Ssam if (sc->sc_flag & SLEEP) { 6616968Ssam wakeup((caddr_t)sc); 6626968Ssam sc->sc_flag &= ~SLEEP; 6636968Ssam } 6646968Ssam } 6656968Ssam } 6666968Ssam #endif NLPA 667