123332Smckusick /*
229227Smckusick * Copyright (c) 1982, 1986 Regents of the University of California.
323332Smckusick * All rights reserved. The Berkeley software License Agreement
423332Smckusick * specifies the terms and conditions for redistribution.
523332Smckusick *
6*64624Sbostic * @(#)lpa.c 7.6 (Berkeley) 09/23/93
723332Smckusick */
88476Sroot
96968Ssam #include "lpa.h"
106968Ssam #if NLPA > 0
116968Ssam
1245804Sbostic #include "sys/param.h"
1345804Sbostic #include "sys/user.h"
1445804Sbostic #include "sys/buf.h"
1545804Sbostic #include "sys/proc.h"
1645804Sbostic #include "sys/ioctl.h"
1745804Sbostic #include "sys/uio.h"
186968Ssam
1917074Sbloom #include "ubavar.h"
208476Sroot
216968Ssam /*
228492Sroot * LPA driver for -- Asa Romberger
238492Sroot *
246968Ssam * open
256968Ssam * write microcode
266968Ssam * write dedicated mode dispatch table
276968Ssam * ioctl TIOCSETP to set parameters
286968Ssam * struct iocb {
296968Ssam * short *baddr; buffer address
306968Ssam * short rate; - 1,000,000 / frequency in Hz
316968Ssam * short wc; 15-13 = number of buffers - 1
326968Ssam * 12-0 = buffer size in words
336968Ssam * } iocb;
346968Ssam * read - 1 character indicating buffer index
356968Ssam * fill or empty buffer
366968Ssam * minor device number = DDCCCCCC where:
376968Ssam * DD = 00 for analog input
386968Ssam * = 01 for analog output
396968Ssam * CCCCCC = channel number
406968Ssam */
416968Ssam * define NOMCODE to eliminate the microcode download check
426968Ssam */
438492Sroot /* #define TRACELPA */
448492Sroot /* #define NOMCODE */
456968Ssam
466968Ssam #ifdef TRACELPA
476968Ssam # define TRACER(x) printf(x)
486968Ssam # define TRACERN(x, d) printf(x, d)
496968Ssam #else
506968Ssam # define TRACER(x)
516968Ssam # define TRACERN(x, d)
526968Ssam #endif
536968Ssam
546968Ssam /* PRIORITY AT WHICH PROGRAM SHOULD RUN */
556968Ssam /* THIS SHOULD EVENTUALLY TELL UNIX THIS IS A REAL-TIME DEVICE */
566968Ssam
576968Ssam #define NICE 0
586968Ssam
598492Sroot #define inc(v) (sc->v = ((sc->v + 1) % sc->sc_nbuf))
606968Ssam
618492Sroot #define LPAPRI (PZERO + 0)
626968Ssam #define LPAUNIT(dev) 0
636968Ssam #define LPADEVICE(dev) (((dev) >> 6) & 03)
646968Ssam #define LPACHANNEL(dev) ((dev) & 077)
656968Ssam
668492Sroot int lpaprobe(), lpaattach(), lpaiintr(), lpaointr();
678492Sroot u_short lpastd[] = {0170460, 0};
688492Sroot struct uba_device *lpadinfo[NLPA];
696968Ssam struct uba_driver lpadriver =
708492Sroot {lpaprobe, 0, lpaattach, 0, lpastd, "lpa", lpadinfo, 0, 0, 0 };
716968Ssam
726968Ssam struct lpa_softc {
736968Ssam int sc_flag; /* flags, as defined below */
746968Ssam int sc_device; /* device: 0 = analog in, 1 = analog out */
756968Ssam int sc_channel; /* device channel number */
766968Ssam struct buf sc_ubuffer; /* user buffer header */
776968Ssam int sc_ubabuf; /* uba allocation pointer for buffer */
786968Ssam int sc_ubufn; /* present buffer that user is accessing */
796968Ssam int sc_lbufn; /* present buffer that lpa is accessing */
806968Ssam int sc_lbufnx; /* next buffer for lpa (value in ustat) */
816968Ssam int sc_nbuf; /* number of buffers */
826968Ssam int sc_count; /* buffer size in words */
836968Ssam short sc_ustat; /* user status word */
846968Ssam struct buf sc_ustatbuf; /* dummy user status word buffer for ubasetup */
856968Ssam int sc_ubaustat; /* uba allocation pointer for ustat */
866968Ssam struct buf *sc_buffer; /* scratch buffer header */
876968Ssam int sc_start; /* 0 if lpa operation has been started */
886968Ssam } lpa_softc[NLPA];
898492Sroot
908492Sroot /* flags for sc_flag */
916968Ssam #define OPEN 01 /* device is open */
926968Ssam #define MCODE 02 /* microcode has been loaded */
936968Ssam #define DMDT 04 /* dedicated mode dispatch table loaded */
946968Ssam #define STTY 010 /* stty call and device initialized */
956968Ssam #define SLEEP 020 /* sleeping */
968492Sroot
978492Sroot /* bits for ustat */
986968Ssam #define DONE 0100000 /* done */
996968Ssam #define STOP 0040000 /* stop data transfer */
1006968Ssam #define NBI 0003400 /* next buffer index */
1016968Ssam #define LBI 0000003 /* last buffer index */
1026968Ssam
1036968Ssam struct lpadevice {
1046968Ssam short lcim; /* control in and maintenance */
1056968Ssam short lcos; /* control and status out */
1066968Ssam short lrda; /* request description array address word */
1076968Ssam short lms; /* maintenance status */
1086968Ssam };
1098492Sroot
1108492Sroot /* control in and maintenance register bits */
1116968Ssam #define READYI 0000200 /* ready in */
1126968Ssam #define IIE 0000100 /* in interrupt enable */
1136968Ssam #define RDAEXT 0000014 /* rda address extension */
1146968Ssam #define RDAEXTOFFSET 2 /* offset of RDAEXT from right side */
1156968Ssam #define GO 0000001 /* go */
1166968Ssam #define RUN 0100000 /* run */
1176968Ssam #define RESET 0040000 /* reset */
1186968Ssam #define CWRITE 0020000 /* cram write */
1196968Ssam #define EA 0004000 /* enable arbitration */
1206968Ssam #define ROMO 0002000 /* rom O */
1216968Ssam #define ROMI 0001000 /* rom I */
1226968Ssam #define SMICRO 0000400 /* step microprocessor */
1238492Sroot
1248492Sroot /* control and status out register bits */
1256968Ssam #define READYO 0200 /* ready out */
1266968Ssam #define OIE 0100 /* out interrupt enable */
1276968Ssam #define UINDEX 0007 /* user index */
1286968Ssam #define ERROR 0100000 /* error */
1296968Ssam #define ESTAT 0060000 /* error status */
1306968Ssam #define ESCODE 0017400 /* error sub code */
1316968Ssam #define ECODE 0077400 /* error status + error sub code */
1326968Ssam #define OVERRUN 0243 /* overrun error */
1336968Ssam
1348492Sroot /* LPA COMMAND DESCRIPTION AREA */
1356968Ssam
1368492Sroot /* INIT COMMAND */
1376968Ssam #define INIT 0 /* mode */
1386968Ssam #define MCVERS 4 /* microcode version */
1396968Ssam #define ACLOCKA 0170404 /* LPA bus addresses */
1406968Ssam #define ACLOCKB 0170432
1416968Ssam #define AAD1 0170400
1426968Ssam #define AAD2 1 /* 0170440 - DOES NOT EXIST */
1436968Ssam #define ADA 0170420
1446968Ssam #define ADIO1 1 /* 0167770 - DOES NOT EXIST */
1456968Ssam #define ADIO2 1 /* 0167760 - DOES NOT EXIST */
1466968Ssam #define ADIO3 1 /* 0167750 - DOES NOT EXIST */
1476968Ssam #define ADIO4 1 /* 0167740 - DOES NOT EXIST */
1486968Ssam #define ADIO5 1 /* 0167730 - DOES NOT EXIST */
1498492Sroot
1508492Sroot /* CLOCK START COMMAND */
1516968Ssam #define CLOCK 1 /* mode */
1526968Ssam #define CLOCKA 0<<4 /* clock A */
1538492Sroot /* clock status word */
1546968Ssam #define ENACTR 1 /* enable counter */
1556968Ssam #define R1M 1<<1 /* 1 MHz rate */
1566968Ssam #define R100K 2<<1 /* 100 KHz rate */
1576968Ssam #define R10K 3<<1 /* 10 KHz rate */
1586968Ssam #define R1K 4<<1 /* 1 KHz rate */
1596968Ssam #define R100 5<<1 /* 100 Hz rate */
1606968Ssam #define REXT 6<<1 /* external rate (from st1 input) */
1616968Ssam #define R60 7<<1 /* line frequency rate */
1626968Ssam #define MFIE 0100 /* mode flag interrupt enable */
1636968Ssam #define MSI 0<<8 /* single interval mode */
1646968Ssam #define MRI 1<<8 /* repeat interval mode */
1656968Ssam #define MEET 2<<8 /* external event time mode */
1666968Ssam #define MEETZ 3<<8 /* external event time mode from zero base */
1676968Ssam #define ST1EC 020000 /* st1 enable counter */
1686968Ssam #define ST1IE 040000 /* st1 interrupt enable */
1698492Sroot
1708492Sroot /* DATA TRANSFER START COMMAND */
1716968Ssam #define DTS 2 /* mode */
1726968Ssam #define SCHAN 1<<8 /* single channel */
1736968Ssam
lpaprobe(reg)1746968Ssam lpaprobe(reg)
1758492Sroot caddr_t reg;
1766968Ssam {
1778492Sroot register int br, cvec; /* value result */
1788492Sroot register struct lpadevice *lpaaddr = (struct lpadevice *)reg;
1796968Ssam
1806968Ssam #ifdef lint
1816968Ssam br = 0; cvec = br; br = cvec;
1826968Ssam #endif
1836968Ssam /* this should force an interrupt, stall, clear the lpa */
1846968Ssam br = 0x15;
1856968Ssam cvec = 0330;
1866968Ssam TRACER("PROBE\n");
1877413Skre return (sizeof (struct lpadevice));
1886968Ssam }
1896968Ssam
lpaattach(ui)1906968Ssam lpaattach(ui)
1918492Sroot register struct upa_device *ui;
1926968Ssam {
1938492Sroot
1946968Ssam }
1956968Ssam
lpaopen(dev,flag)1966968Ssam lpaopen(dev, flag)
1978492Sroot dev_t dev;
1988492Sroot int flag;
1996968Ssam {
2006968Ssam register int unit = LPAUNIT(dev);
2016968Ssam register struct lpa_softc *sc = &lpa_softc[unit];
2026968Ssam register struct uba_device *ui = lpadinfo[unit];
2036968Ssam register struct lpadevice *lpaaddr = (struct lpadevice *) ui->ui_addr;
2046968Ssam
2056968Ssam TRACER("OPEN\n");
2066968Ssam if (unit >= NLPA || sc->sc_flag & OPEN || ui == 0 ||
2078571Sroot ui->ui_alive == 0)
2088571Sroot return (ENXIO);
20926367Skarels (void) splhigh();
2106968Ssam lpaaddr->lcim = RESET;
2116968Ssam lpaaddr->lcim = 0;
2126968Ssam (void) spl0();
2136968Ssam lpaaddr->lcos = 0; /* clear the registers as a precaution */
2146968Ssam lpaaddr->lrda = 0;
2156968Ssam lpaaddr->lms = 0;
2166968Ssam sc->sc_flag = OPEN;
2176968Ssam sc->sc_device = LPADEVICE(dev);
2186968Ssam sc->sc_channel = LPACHANNEL(dev);
2196968Ssam sc->sc_buffer = geteblk();
2206968Ssam sc->sc_buffer->b_error = 0;
2216968Ssam sc->sc_buffer->b_proc = u.u_procp;
2226968Ssam sc->sc_ubufn = -1;
2236968Ssam /* THIS SHOULD EVENTUALLY SPECIFY "REAL-TIME" */
2246968Ssam u.u_procp->p_nice = NICE;
2258571Sroot return (0);
2266968Ssam }
2276968Ssam
lpaclose(dev,flag)2286968Ssam lpaclose(dev, flag)
2298492Sroot dev_t dev;
2308492Sroot int flag;
2316968Ssam {
2326968Ssam register int unit = LPAUNIT(dev);
2336968Ssam register struct lpa_softc *sc = &lpa_softc[unit];
2346968Ssam register struct uba_device *ui = lpadinfo[unit];
2356968Ssam register struct lpadevice *lpaaddr = (struct lpadevice *) ui->ui_addr;
2366968Ssam
2376968Ssam if (sc->sc_device && sc->sc_ubufn >= 0 && (sc->sc_flag & ERROR) == 0) {
2386968Ssam if (sc->sc_start)
2396968Ssam lpacmd(sc->sc_buffer, lpaaddr, sc, ui->ui_ubanum);
2406968Ssam sc->sc_flag |= STOP;
2416968Ssam (void) spl5();
2426968Ssam while (sc->sc_flag & STOP) {
2436968Ssam TRACER("SLEEP\n");
2446968Ssam sc->sc_flag |= SLEEP;
2456968Ssam sleep((caddr_t)sc, LPAPRI);
2466968Ssam }
2476968Ssam }
24826367Skarels (void) splhigh();
2496968Ssam lpaaddr->lcim = RESET;
2506968Ssam lpaaddr->lcim = 0;
2516968Ssam (void) spl0();
2526968Ssam if (sc->sc_ubabuf) {
2536968Ssam ubarelse(ui->ui_ubanum, &sc->sc_ubabuf);
2546968Ssam sc->sc_ubabuf = 0;
25526367Skarels (void) splclock();
2566968Ssam vsunlock(sc->sc_ubuffer.b_un.b_addr, sc->sc_ubuffer.b_bcount,
2576968Ssam (sc->sc_device)? B_READ : B_WRITE);
258*64624Sbostic u.u_procp->p_flag &= ~P_PHYSIO;
2596968Ssam (void) spl0();
2606968Ssam }
2616968Ssam if (sc->sc_ubaustat) {
2626968Ssam ubarelse(ui->ui_ubanum, &sc->sc_ubaustat);
2636968Ssam sc->sc_ubaustat = 0;
2646968Ssam }
2656968Ssam if (sc->sc_buffer) {
2666968Ssam brelse(sc->sc_buffer);
2676968Ssam sc->sc_buffer = 0;
2686968Ssam }
2696968Ssam sc->sc_flag = 0;
2706968Ssam TRACER("CLOSE\n");
27140728Skarels return (0);
2726968Ssam }
2736968Ssam
lpawrite(dev,uio)2747835Sroot lpawrite(dev, uio)
2757835Sroot dev_t dev;
2767835Sroot struct uio *uio;
2776968Ssam {
2786968Ssam register int unit = LPAUNIT(dev);
2796968Ssam register struct lpa_softc *sc = &lpa_softc[unit];
2806968Ssam register struct uba_device *ui = lpadinfo[unit];
2816968Ssam register struct lpadevice *lpaaddr = (struct lpadevice *) ui->ui_addr;
2826968Ssam register int f;
2836968Ssam
2846968Ssam TRACER("WRITE\n");
2856968Ssam f = sc->sc_flag;
2868492Sroot if ((f & OPEN) == 0)
2878492Sroot return (ENXIO);
2888492Sroot if ((f & MCODE) == 0) /* first write is the microcode */
2898492Sroot return (lpamcode(lpaaddr, sc, uio));
2908492Sroot if ((f & DMDT) == 0) /* second write is the dispatch table */
2918492Sroot return (lpadmdt(lpaaddr, sc, ui->ui_ubanum, uio));
2928492Sroot return (ENXIO);
2936968Ssam }
2946968Ssam
lpamcode(lpaaddr,sc,uio)2957835Sroot lpamcode(lpaaddr, sc, uio)
2967835Sroot register struct lpadevice *lpaaddr;
2977835Sroot register struct lpa_softc *sc;
2987835Sroot struct uio *uio;
2996968Ssam {
3006968Ssam short v, r;
3016968Ssam register int mcaddr;
3028709Sroot int error;
3036968Ssam
3046968Ssam mcaddr = 0;
3057835Sroot while (uio->uio_resid) {
30637764Smckusick error = uiomove(&v, 2, uio);
3078709Sroot if (error)
3088709Sroot break;
3096968Ssam lpaaddr->lcim = 0; /* load microcode word */
3106968Ssam lpaaddr->lrda = mcaddr;
3116968Ssam lpaaddr->lms = v;
3126968Ssam lpaaddr->lcim = ROMO;
3136968Ssam lpaaddr->lcim |= CWRITE;
3146968Ssam lpaaddr->lcim = 0; /* verify microcode word */
3156968Ssam lpaaddr->lrda = mcaddr;
3166968Ssam lpaaddr->lcim = ROMO;
3176968Ssam if ((r = lpaaddr->lms) != v) {
3186968Ssam /* download failure */
3196968Ssam printf("LPA MICROCODE FAIL: exp:%o got:%o\n", v, r);
3208492Sroot return (ENXIO);
3216968Ssam }
3226968Ssam mcaddr++;
3236968Ssam }
3246968Ssam lpaaddr->lcim = RUN | EA; /* turn it on */
3256968Ssam sc->sc_flag |= MCODE;
3266968Ssam lpaaddr->lcim |= IIE;
3276968Ssam lpaaddr->lcos |= OIE;
3288709Sroot return (error);
3296968Ssam TRACER("MCODE\n");
3306968Ssam }
3316968Ssam
lpadmdt(lpaaddr,sc,ubanum,uio)3327835Sroot lpadmdt(lpaaddr, sc, ubanum, uio)
3337835Sroot register struct lpadevice *lpaaddr;
3347835Sroot register struct lpa_softc *sc;
3357835Sroot register short ubanum;
3367835Sroot struct uio *uio;
3376968Ssam {
3386968Ssam register short *p;
3396968Ssam register int n;
3408492Sroot int error;
3416968Ssam
3426968Ssam p = (short *) sc->sc_buffer->b_un.b_addr; /* INIT */
3436968Ssam *p++ = (MCVERS << 8) | INIT; /* mode */
3446968Ssam *p++ = ACLOCKA; /* LPA bus device addresses */
3456968Ssam *p++ = ACLOCKB;
3466968Ssam *p++ = AAD1;
3476968Ssam *p++ = AAD2;
3486968Ssam *p++ = ADA;
3496968Ssam *p++ = ADIO1;
3506968Ssam *p++ = ADIO2;
3516968Ssam *p++ = ADIO3;
3526968Ssam *p++ = ADIO4;
3536968Ssam *p++ = ADIO5;
35426367Skarels n = MIN(uio->uio_resid, 256); /* dedicated mode dispatch table */
35537764Smckusick error = uiomove((char *)p, n, uio);
3568492Sroot if (error)
3578492Sroot return (error);
3586968Ssam n >>= 1;
3596968Ssam p += n;
3606968Ssam while (n++ < 128)
3616968Ssam *p++ = 0;
3626968Ssam lpacmd(sc->sc_buffer, lpaaddr, sc, ubanum);
3636968Ssam sc->sc_flag |= DMDT;
3648492Sroot return (0);
3656968Ssam TRACER("DMDT\n");
3666968Ssam }
3676968Ssam
lpaioctl(dev,cmd,data,flag)3687632Ssam lpaioctl(dev, cmd, data, flag)
3697632Ssam dev_t dev;
3707632Ssam caddr_t data;
3716968Ssam {
3726968Ssam register int unit = LPAUNIT(dev);
3736968Ssam register struct lpa_softc *sc = &lpa_softc[unit];
3746968Ssam register struct uba_device *ui = lpadinfo[unit];
3756968Ssam register struct lpadevice *lpaaddr = (struct lpadevice *) ui->ui_addr;
3766968Ssam register short *p;
3776968Ssam register int i;
3786968Ssam register int v;
3796968Ssam struct iocb {
3806968Ssam short *baddr;
3816968Ssam short rate;
3826968Ssam short wc;
3837632Ssam } *iocb;
3846968Ssam
3856968Ssam TRACER("IOCTL IN\n");
3868571Sroot if (cmd != TIOCSETP || (sc->sc_flag & DMDT) == 0)
3878571Sroot return (ENXIO);
3887632Ssam iocb = (struct iocb *)data;
3896968Ssam p = (short *) sc->sc_buffer->b_un.b_addr; /* CLOCK START */
3906968Ssam *p++ = CLOCK | CLOCKA; /* mode */
3916968Ssam *p++ = ENACTR | R1M | MFIE | MRI; /* clock status */
3927632Ssam *p = iocb->rate; /* clock preset */
3936968Ssam lpacmd(sc->sc_buffer, lpaaddr, sc, ui->ui_ubanum);
3946968Ssam TRACER("CLOCK STARTED\n");
3956968Ssam p = (short *) sc->sc_buffer->b_un.b_addr; /* DATA TRANSFER START*/
3966968Ssam *p++ = (sc->sc_device << 7) | DTS | SCHAN; /* mode */
3977632Ssam sc->sc_count = iocb->wc & 017777; /* word count per buffer */
3986968Ssam *p++ = sc->sc_count;
3996968Ssam /* user status word */
4006968Ssam sc->sc_ustatbuf.b_un.b_addr = (caddr_t) &sc->sc_ustat;
4016968Ssam sc->sc_ustatbuf.b_flags = 0;
4026968Ssam sc->sc_ustatbuf.b_bcount = 2;
4036968Ssam sc->sc_ustatbuf.b_proc = u.u_procp;
4046968Ssam sc->sc_ubaustat = ubasetup(ui->ui_ubanum, &sc->sc_ustatbuf, 0);
4056968Ssam v = sc->sc_ubaustat;
4066968Ssam *p++ = v;
4076968Ssam *p = (v >> 16) & 03; /* into low portion of word */
4087632Ssam sc->sc_nbuf = (iocb->wc >> 13) & 07; /* number of buffers */
4096968Ssam *p++ |= sc->sc_nbuf++ << 8; /* into high portion of word */
4106968Ssam /* buffer addresses */
4117632Ssam if (useracc(sc->sc_ubuffer.b_un.b_addr = (caddr_t) iocb->baddr,
4128571Sroot sc->sc_ubuffer.b_bcount = sc->sc_count * sc->sc_nbuf * 2,
4138571Sroot (i = (sc->sc_device)? B_READ : B_WRITE) ) == NULL) {
4146968Ssam TRACER("USER BUFFER FAULT\n");
4158571Sroot return (EFAULT);
4166968Ssam }
4176968Ssam sc->sc_ubuffer.b_flags = B_PHYS | B_BUSY | i;
4186968Ssam sc->sc_ubuffer.b_proc = u.u_procp;
419*64624Sbostic u.u_procp->p_flag |= P_PHYSIO;
4206968Ssam vslock(sc->sc_ubuffer.b_un.b_addr, sc->sc_ubuffer.b_bcount);
4216968Ssam sc->sc_ubabuf = ubasetup(ui->ui_ubanum, &sc->sc_ubuffer, 0);
4226968Ssam v = sc->sc_ubabuf;
4236968Ssam for (i = 0; i < sc->sc_nbuf; i++) {
4246968Ssam *p++ = v;
4256968Ssam *p++ = (v >> 16) & 03;
4266968Ssam v += sc->sc_count * 2;
4276968Ssam }
4286968Ssam for ( ; i <= 7; i++) {
4296968Ssam *p++ = 0;
4306968Ssam *p++ = 0;
4316968Ssam }
4326968Ssam *p++ = 0; *p++ = 0; /* random channel list address */
4336968Ssam *p++ = 0; /* delay */
4346968Ssam *p++ = sc->sc_channel; /* start channel, channel inc */
4356968Ssam *p++ = 1; /* number of samples in a sequence */
4366968Ssam *p++ = 0; /* dwell */
4376968Ssam *p++ = 0; /* start word no., event mark word */
4386968Ssam *p++ = 0; /* start word mask */
4396968Ssam *p = 0; /* event mark mask */
4406968Ssam sc->sc_ustat = 0;
4416968Ssam sc->sc_start = (sc->sc_device)? sc->sc_nbuf+1 : 1;
4426968Ssam sc->sc_lbufn = 0;
4436968Ssam sc->sc_lbufnx = 0;
4446968Ssam sc->sc_flag |= STTY;
4456968Ssam TRACER("IOCTL OUT\n");
4468571Sroot return (0);
4476968Ssam }
4486968Ssam
lparead(dev,uio)4497729Sroot lparead(dev, uio)
4507835Sroot dev_t dev;
4517835Sroot struct uio *uio;
4526968Ssam {
4536968Ssam register int unit = LPAUNIT(dev);
4546968Ssam register struct lpa_softc *sc = &lpa_softc[unit];
4556968Ssam register struct uba_device *ui = lpadinfo[unit];
4566968Ssam register struct lpadevice *lpaaddr = (struct lpadevice *) ui->ui_addr;
4576968Ssam
4586968Ssam TRACER("READ\n");
4598492Sroot if ((sc->sc_flag & STTY) == 0)
4608492Sroot return (ENXIO);
4618492Sroot if (sc->sc_flag & ERROR)
4628492Sroot return (ENXIO);
4636968Ssam if (sc->sc_start)
4646968Ssam if (--sc->sc_start == 0) {
4656968Ssam lpacmd(sc->sc_buffer, lpaaddr, sc, ui->ui_ubanum);
4666968Ssam TRACER("START\n");
4676968Ssam }
4686968Ssam inc(sc_ubufn);
4696968Ssam if (sc->sc_start == 0) {
4706968Ssam (void) spl5();
4716968Ssam while (sc->sc_ubufn == sc->sc_lbufn) {
4728492Sroot if (sc->sc_flag & ERROR)
4738492Sroot return (ENXIO);
4746968Ssam TRACER("SLEEP\n");
4756968Ssam sc->sc_flag |= SLEEP;
4766968Ssam sleep(sc, LPAPRI);
4776968Ssam }
4786968Ssam (void) spl0();
4796968Ssam }
4806968Ssam TRACERN("READ %d\n", sc->sc_ubufn);
48137764Smckusick return (uiomove(&sc->sc_ubufn, 1, uio));
4826968Ssam }
4836968Ssam
lpacmd(bp,lpaaddr,sc,ubanum)4846968Ssam lpacmd(bp, lpaaddr, sc, ubanum)
4857835Sroot register struct buf *bp;
4867835Sroot register struct lpadevice *lpaaddr;
4877835Sroot register struct lpa_softc *sc;
4887835Sroot register short ubanum;
4896968Ssam {
4906968Ssam int ubareg;
4916968Ssam
4926968Ssam TRACER("CMD\n");
4936968Ssam ubareg = ubasetup(ubanum, bp, UBA_NEEDBDP);
4946968Ssam lpawait(lpaaddr, sc);
4956968Ssam lpaaddr->lrda = ubareg;
4966968Ssam lpaaddr->lcim &= ~RDAEXT;
4976968Ssam lpaaddr->lcim |= ((ubareg >> (16-RDAEXTOFFSET)) & RDAEXT) | GO;
4986968Ssam lpawait(lpaaddr, sc);
4996968Ssam ubarelse(ubanum, &ubareg);
5006968Ssam }
5016968Ssam
lpawait(lpaaddr,sc)5026968Ssam lpawait(lpaaddr, sc)
5038492Sroot register struct lpadevice *lpaaddr;
5048492Sroot register struct lpa_softc *sc;
5056968Ssam {
5068492Sroot
5076968Ssam (void) spl5();
5086968Ssam while ((lpaaddr->lcim & READYI) == 0) {
5096968Ssam TRACER("SLEEP\n");
5106968Ssam sc->sc_flag |= SLEEP;
5116968Ssam sleep((caddr_t)sc, LPAPRI);
5126968Ssam }
5136968Ssam (void) spl0();
5146968Ssam }
5156968Ssam
lpaiintr(unit)5166968Ssam lpaiintr(unit)
5178492Sroot int unit;
5186968Ssam {
5196968Ssam register struct lpa_softc *sc = &lpa_softc[unit];
5206968Ssam
5216968Ssam TRACER("{I");
5226968Ssam if (sc->sc_flag & SLEEP) {
5236968Ssam TRACER("<WAKEUP>");
5246968Ssam wakeup((caddr_t)sc);
5256968Ssam sc->sc_flag &= ~SLEEP;
5266968Ssam }
5276968Ssam TRACER("}");
5286968Ssam }
5296968Ssam
lpaointr(unit)5306968Ssam lpaointr(unit)
5318492Sroot int unit;
5326968Ssam {
5336968Ssam register int c, m;
5346968Ssam register struct lpa_softc *sc = &lpa_softc[unit];
5356968Ssam register struct uba_device *ui = lpadinfo[unit];
5366968Ssam register struct lpadevice *lpaaddr = (struct lpadevice *) ui->ui_addr;
5376968Ssam int spx;
5386968Ssam
5396968Ssam TRACER("{O");
5406968Ssam if (sc->sc_flag & SLEEP) {
5416968Ssam TRACER("<WAKEUP>");
5426968Ssam wakeup(sc);
5436968Ssam sc->sc_flag &= ~SLEEP;
5446968Ssam }
5456968Ssam c = lpaaddr->lcos;
5466968Ssam m = lpaaddr->lms;
5476968Ssam lpaaddr->lcos &= ~READYO;
5486968Ssam if (c & ERROR) {
5496968Ssam TRACER("<ERROR>");
5506968Ssam c = (c >> 8) & 0377;
5516968Ssam if ((sc->sc_flag & STOP) == 0 || (c != OVERRUN)) {
5526968Ssam printf("LPA ERROR %o %o\n", c, m&0177777);
5536968Ssam sc->sc_flag |= ERROR;
5546968Ssam }
5556968Ssam sc->sc_flag &= ~STOP;
5566968Ssam TRACER("}\n");
5576968Ssam return;
5586968Ssam }
5596968Ssam TRACERN("<LPA %d>", sc->sc_lbufnx);
5606968Ssam sc->sc_lbufn = sc->sc_lbufnx;
5616968Ssam if (sc->sc_ubufn == sc->sc_lbufnx && c & ECODE) {
5626968Ssam TRACER("<STOP?>");
5636968Ssam if (sc->sc_flag & STOP)
5646968Ssam return;
5656968Ssam printf("LPA OVERRUN\n");
5666968Ssam sc->sc_flag |= ERROR;
5676968Ssam }
5686968Ssam inc(sc_lbufnx);
5696968Ssam TRACERN("<USTAT %o>", sc->sc_ustat);
57026367Skarels spx = splhigh();
5716968Ssam sc->sc_ustat &= ~NBI;
5726968Ssam sc->sc_ustat |= sc->sc_lbufnx << 8;
5736968Ssam sc->sc_ustat &= ~DONE;
57426367Skarels splx(spx);
5756968Ssam TRACERN("<LPAN %d>}", sc->sc_lbufnx);
5766968Ssam }
5776968Ssam
lpareset(uban)5786968Ssam lpareset(uban)
5798492Sroot int uban;
5806968Ssam {
5816968Ssam register struct uba_device *ui;
5826968Ssam register struct lpadevice *lpaaddr;
5836968Ssam register struct lpa_softc *sc;
5846968Ssam register int unit;
5856968Ssam
5866968Ssam TRACER("LPA RESET\n");
5876968Ssam for (unit = 0; unit < NLPA; unit++) {
5888492Sroot if ((ui = lpadinfo[unit]) == 0 ||
5898492Sroot ui->ui_ubanum != uban || ui->ui_alive == 0)
5908492Sroot continue;
5916968Ssam printf(" lpa%d", unit);
5926968Ssam lpaaddr = (struct lpadevice *)ui->ui_addr;
5936968Ssam sc = &lpa_softc[unit];
5946968Ssam sc->sc_flag |= ERROR;
59526367Skarels (void) splhigh();
5966968Ssam lpaaddr->lcim = RESET;
5976968Ssam lpaaddr->lcim = 0;
5986968Ssam (void) spl0();
5996968Ssam if (sc->sc_flag & SLEEP) {
6006968Ssam wakeup((caddr_t)sc);
6016968Ssam sc->sc_flag &= ~SLEEP;
6026968Ssam }
6036968Ssam }
6046968Ssam }
6056968Ssam #endif NLPA
606