1ac9fa1f2Smckusick /*
20e670328Smckusick * Copyright (c) 1982, 1986 Regents of the University of California.
3ac9fa1f2Smckusick * All rights reserved. The Berkeley software License Agreement
4ac9fa1f2Smckusick * specifies the terms and conditions for redistribution.
5ac9fa1f2Smckusick *
6*afb2e50aSbostic * @(#)lpa.c 7.6 (Berkeley) 09/23/93
7ac9fa1f2Smckusick */
842b8bd9bSroot
987f7a842Ssam #include "lpa.h"
1087f7a842Ssam #if NLPA > 0
1187f7a842Ssam
1239bdaf89Sbostic #include "sys/param.h"
1339bdaf89Sbostic #include "sys/user.h"
1439bdaf89Sbostic #include "sys/buf.h"
1539bdaf89Sbostic #include "sys/proc.h"
1639bdaf89Sbostic #include "sys/ioctl.h"
1739bdaf89Sbostic #include "sys/uio.h"
1887f7a842Ssam
1971445730Sbloom #include "ubavar.h"
2042b8bd9bSroot
2187f7a842Ssam /*
22d672d181Sroot * LPA driver for -- Asa Romberger
23d672d181Sroot *
2487f7a842Ssam * open
2587f7a842Ssam * write microcode
2687f7a842Ssam * write dedicated mode dispatch table
2787f7a842Ssam * ioctl TIOCSETP to set parameters
2887f7a842Ssam * struct iocb {
2987f7a842Ssam * short *baddr; buffer address
3087f7a842Ssam * short rate; - 1,000,000 / frequency in Hz
3187f7a842Ssam * short wc; 15-13 = number of buffers - 1
3287f7a842Ssam * 12-0 = buffer size in words
3387f7a842Ssam * } iocb;
3487f7a842Ssam * read - 1 character indicating buffer index
3587f7a842Ssam * fill or empty buffer
3687f7a842Ssam * minor device number = DDCCCCCC where:
3787f7a842Ssam * DD = 00 for analog input
3887f7a842Ssam * = 01 for analog output
3987f7a842Ssam * CCCCCC = channel number
4087f7a842Ssam */
4187f7a842Ssam * define NOMCODE to eliminate the microcode download check
4287f7a842Ssam */
43d672d181Sroot /* #define TRACELPA */
4487f7a842Ssam /* #define NOMCODE */
4587f7a842Ssam
4687f7a842Ssam #ifdef TRACELPA
4787f7a842Ssam # define TRACER(x) printf(x)
4887f7a842Ssam # define TRACERN(x, d) printf(x, d)
4987f7a842Ssam #else
5087f7a842Ssam # define TRACER(x)
5187f7a842Ssam # define TRACERN(x, d)
5287f7a842Ssam #endif
5387f7a842Ssam
5487f7a842Ssam /* PRIORITY AT WHICH PROGRAM SHOULD RUN */
5587f7a842Ssam /* THIS SHOULD EVENTUALLY TELL UNIX THIS IS A REAL-TIME DEVICE */
5687f7a842Ssam
5787f7a842Ssam #define NICE 0
5887f7a842Ssam
59d672d181Sroot #define inc(v) (sc->v = ((sc->v + 1) % sc->sc_nbuf))
6087f7a842Ssam
6187f7a842Ssam #define LPAPRI (PZERO + 0)
6287f7a842Ssam #define LPAUNIT(dev) 0
6387f7a842Ssam #define LPADEVICE(dev) (((dev) >> 6) & 03)
6487f7a842Ssam #define LPACHANNEL(dev) ((dev) & 077)
6587f7a842Ssam
66d672d181Sroot int lpaprobe(), lpaattach(), lpaiintr(), lpaointr();
6787f7a842Ssam u_short lpastd[] = {0170460, 0};
6887f7a842Ssam struct uba_device *lpadinfo[NLPA];
6987f7a842Ssam struct uba_driver lpadriver =
70d672d181Sroot {lpaprobe, 0, lpaattach, 0, lpastd, "lpa", lpadinfo, 0, 0, 0 };
7187f7a842Ssam
7287f7a842Ssam struct lpa_softc {
7387f7a842Ssam int sc_flag; /* flags, as defined below */
7487f7a842Ssam int sc_device; /* device: 0 = analog in, 1 = analog out */
7587f7a842Ssam int sc_channel; /* device channel number */
7687f7a842Ssam struct buf sc_ubuffer; /* user buffer header */
7787f7a842Ssam int sc_ubabuf; /* uba allocation pointer for buffer */
7887f7a842Ssam int sc_ubufn; /* present buffer that user is accessing */
7987f7a842Ssam int sc_lbufn; /* present buffer that lpa is accessing */
8087f7a842Ssam int sc_lbufnx; /* next buffer for lpa (value in ustat) */
8187f7a842Ssam int sc_nbuf; /* number of buffers */
8287f7a842Ssam int sc_count; /* buffer size in words */
8387f7a842Ssam short sc_ustat; /* user status word */
8487f7a842Ssam struct buf sc_ustatbuf; /* dummy user status word buffer for ubasetup */
8587f7a842Ssam int sc_ubaustat; /* uba allocation pointer for ustat */
8687f7a842Ssam struct buf *sc_buffer; /* scratch buffer header */
8787f7a842Ssam int sc_start; /* 0 if lpa operation has been started */
8887f7a842Ssam } lpa_softc[NLPA];
89d672d181Sroot
90d672d181Sroot /* flags for sc_flag */
9187f7a842Ssam #define OPEN 01 /* device is open */
9287f7a842Ssam #define MCODE 02 /* microcode has been loaded */
9387f7a842Ssam #define DMDT 04 /* dedicated mode dispatch table loaded */
9487f7a842Ssam #define STTY 010 /* stty call and device initialized */
9587f7a842Ssam #define SLEEP 020 /* sleeping */
96d672d181Sroot
97d672d181Sroot /* bits for ustat */
9887f7a842Ssam #define DONE 0100000 /* done */
9987f7a842Ssam #define STOP 0040000 /* stop data transfer */
10087f7a842Ssam #define NBI 0003400 /* next buffer index */
10187f7a842Ssam #define LBI 0000003 /* last buffer index */
10287f7a842Ssam
10387f7a842Ssam struct lpadevice {
10487f7a842Ssam short lcim; /* control in and maintenance */
10587f7a842Ssam short lcos; /* control and status out */
10687f7a842Ssam short lrda; /* request description array address word */
10787f7a842Ssam short lms; /* maintenance status */
10887f7a842Ssam };
109d672d181Sroot
11087f7a842Ssam /* control in and maintenance register bits */
11187f7a842Ssam #define READYI 0000200 /* ready in */
11287f7a842Ssam #define IIE 0000100 /* in interrupt enable */
11387f7a842Ssam #define RDAEXT 0000014 /* rda address extension */
11487f7a842Ssam #define RDAEXTOFFSET 2 /* offset of RDAEXT from right side */
11587f7a842Ssam #define GO 0000001 /* go */
11687f7a842Ssam #define RUN 0100000 /* run */
11787f7a842Ssam #define RESET 0040000 /* reset */
11887f7a842Ssam #define CWRITE 0020000 /* cram write */
11987f7a842Ssam #define EA 0004000 /* enable arbitration */
12087f7a842Ssam #define ROMO 0002000 /* rom O */
12187f7a842Ssam #define ROMI 0001000 /* rom I */
12287f7a842Ssam #define SMICRO 0000400 /* step microprocessor */
123d672d181Sroot
12487f7a842Ssam /* control and status out register bits */
12587f7a842Ssam #define READYO 0200 /* ready out */
12687f7a842Ssam #define OIE 0100 /* out interrupt enable */
12787f7a842Ssam #define UINDEX 0007 /* user index */
12887f7a842Ssam #define ERROR 0100000 /* error */
12987f7a842Ssam #define ESTAT 0060000 /* error status */
13087f7a842Ssam #define ESCODE 0017400 /* error sub code */
13187f7a842Ssam #define ECODE 0077400 /* error status + error sub code */
13287f7a842Ssam #define OVERRUN 0243 /* overrun error */
13387f7a842Ssam
13487f7a842Ssam /* LPA COMMAND DESCRIPTION AREA */
13587f7a842Ssam
13687f7a842Ssam /* INIT COMMAND */
13787f7a842Ssam #define INIT 0 /* mode */
13887f7a842Ssam #define MCVERS 4 /* microcode version */
13987f7a842Ssam #define ACLOCKA 0170404 /* LPA bus addresses */
14087f7a842Ssam #define ACLOCKB 0170432
14187f7a842Ssam #define AAD1 0170400
14287f7a842Ssam #define AAD2 1 /* 0170440 - DOES NOT EXIST */
14387f7a842Ssam #define ADA 0170420
14487f7a842Ssam #define ADIO1 1 /* 0167770 - DOES NOT EXIST */
14587f7a842Ssam #define ADIO2 1 /* 0167760 - DOES NOT EXIST */
14687f7a842Ssam #define ADIO3 1 /* 0167750 - DOES NOT EXIST */
14787f7a842Ssam #define ADIO4 1 /* 0167740 - DOES NOT EXIST */
14887f7a842Ssam #define ADIO5 1 /* 0167730 - DOES NOT EXIST */
149d672d181Sroot
15087f7a842Ssam /* CLOCK START COMMAND */
15187f7a842Ssam #define CLOCK 1 /* mode */
15287f7a842Ssam #define CLOCKA 0<<4 /* clock A */
15387f7a842Ssam /* clock status word */
15487f7a842Ssam #define ENACTR 1 /* enable counter */
15587f7a842Ssam #define R1M 1<<1 /* 1 MHz rate */
15687f7a842Ssam #define R100K 2<<1 /* 100 KHz rate */
15787f7a842Ssam #define R10K 3<<1 /* 10 KHz rate */
15887f7a842Ssam #define R1K 4<<1 /* 1 KHz rate */
15987f7a842Ssam #define R100 5<<1 /* 100 Hz rate */
16087f7a842Ssam #define REXT 6<<1 /* external rate (from st1 input) */
16187f7a842Ssam #define R60 7<<1 /* line frequency rate */
16287f7a842Ssam #define MFIE 0100 /* mode flag interrupt enable */
16387f7a842Ssam #define MSI 0<<8 /* single interval mode */
16487f7a842Ssam #define MRI 1<<8 /* repeat interval mode */
16587f7a842Ssam #define MEET 2<<8 /* external event time mode */
16687f7a842Ssam #define MEETZ 3<<8 /* external event time mode from zero base */
16787f7a842Ssam #define ST1EC 020000 /* st1 enable counter */
16887f7a842Ssam #define ST1IE 040000 /* st1 interrupt enable */
169d672d181Sroot
17087f7a842Ssam /* DATA TRANSFER START COMMAND */
17187f7a842Ssam #define DTS 2 /* mode */
17287f7a842Ssam #define SCHAN 1<<8 /* single channel */
17387f7a842Ssam
lpaprobe(reg)17487f7a842Ssam lpaprobe(reg)
17587f7a842Ssam caddr_t reg;
17687f7a842Ssam {
177d672d181Sroot register int br, cvec; /* value result */
17887f7a842Ssam register struct lpadevice *lpaaddr = (struct lpadevice *)reg;
17987f7a842Ssam
18087f7a842Ssam #ifdef lint
18187f7a842Ssam br = 0; cvec = br; br = cvec;
18287f7a842Ssam #endif
18387f7a842Ssam /* this should force an interrupt, stall, clear the lpa */
18487f7a842Ssam br = 0x15;
18587f7a842Ssam cvec = 0330;
18687f7a842Ssam TRACER("PROBE\n");
187d6764b59Skre return (sizeof (struct lpadevice));
18887f7a842Ssam }
18987f7a842Ssam
lpaattach(ui)19087f7a842Ssam lpaattach(ui)
19187f7a842Ssam register struct upa_device *ui;
19287f7a842Ssam {
193d672d181Sroot
19487f7a842Ssam }
19587f7a842Ssam
lpaopen(dev,flag)19687f7a842Ssam lpaopen(dev, flag)
19787f7a842Ssam dev_t dev;
19887f7a842Ssam int flag;
19987f7a842Ssam {
20087f7a842Ssam register int unit = LPAUNIT(dev);
20187f7a842Ssam register struct lpa_softc *sc = &lpa_softc[unit];
20287f7a842Ssam register struct uba_device *ui = lpadinfo[unit];
20387f7a842Ssam register struct lpadevice *lpaaddr = (struct lpadevice *) ui->ui_addr;
20487f7a842Ssam
20587f7a842Ssam TRACER("OPEN\n");
20687f7a842Ssam if (unit >= NLPA || sc->sc_flag & OPEN || ui == 0 ||
207220098f8Sroot ui->ui_alive == 0)
208220098f8Sroot return (ENXIO);
209395e3743Skarels (void) splhigh();
21087f7a842Ssam lpaaddr->lcim = RESET;
21187f7a842Ssam lpaaddr->lcim = 0;
21287f7a842Ssam (void) spl0();
21387f7a842Ssam lpaaddr->lcos = 0; /* clear the registers as a precaution */
21487f7a842Ssam lpaaddr->lrda = 0;
21587f7a842Ssam lpaaddr->lms = 0;
21687f7a842Ssam sc->sc_flag = OPEN;
21787f7a842Ssam sc->sc_device = LPADEVICE(dev);
21887f7a842Ssam sc->sc_channel = LPACHANNEL(dev);
21987f7a842Ssam sc->sc_buffer = geteblk();
22087f7a842Ssam sc->sc_buffer->b_error = 0;
22187f7a842Ssam sc->sc_buffer->b_proc = u.u_procp;
22287f7a842Ssam sc->sc_ubufn = -1;
22387f7a842Ssam /* THIS SHOULD EVENTUALLY SPECIFY "REAL-TIME" */
22487f7a842Ssam u.u_procp->p_nice = NICE;
225220098f8Sroot return (0);
22687f7a842Ssam }
22787f7a842Ssam
lpaclose(dev,flag)22887f7a842Ssam lpaclose(dev, flag)
22987f7a842Ssam dev_t dev;
23087f7a842Ssam int flag;
23187f7a842Ssam {
23287f7a842Ssam register int unit = LPAUNIT(dev);
23387f7a842Ssam register struct lpa_softc *sc = &lpa_softc[unit];
23487f7a842Ssam register struct uba_device *ui = lpadinfo[unit];
23587f7a842Ssam register struct lpadevice *lpaaddr = (struct lpadevice *) ui->ui_addr;
23687f7a842Ssam
23787f7a842Ssam if (sc->sc_device && sc->sc_ubufn >= 0 && (sc->sc_flag & ERROR) == 0) {
23887f7a842Ssam if (sc->sc_start)
23987f7a842Ssam lpacmd(sc->sc_buffer, lpaaddr, sc, ui->ui_ubanum);
24087f7a842Ssam sc->sc_flag |= STOP;
24187f7a842Ssam (void) spl5();
24287f7a842Ssam while (sc->sc_flag & STOP) {
24387f7a842Ssam TRACER("SLEEP\n");
24487f7a842Ssam sc->sc_flag |= SLEEP;
24587f7a842Ssam sleep((caddr_t)sc, LPAPRI);
24687f7a842Ssam }
24787f7a842Ssam }
248395e3743Skarels (void) splhigh();
24987f7a842Ssam lpaaddr->lcim = RESET;
25087f7a842Ssam lpaaddr->lcim = 0;
25187f7a842Ssam (void) spl0();
25287f7a842Ssam if (sc->sc_ubabuf) {
25387f7a842Ssam ubarelse(ui->ui_ubanum, &sc->sc_ubabuf);
25487f7a842Ssam sc->sc_ubabuf = 0;
255395e3743Skarels (void) splclock();
25687f7a842Ssam vsunlock(sc->sc_ubuffer.b_un.b_addr, sc->sc_ubuffer.b_bcount,
25787f7a842Ssam (sc->sc_device)? B_READ : B_WRITE);
258*afb2e50aSbostic u.u_procp->p_flag &= ~P_PHYSIO;
25987f7a842Ssam (void) spl0();
26087f7a842Ssam }
26187f7a842Ssam if (sc->sc_ubaustat) {
26287f7a842Ssam ubarelse(ui->ui_ubanum, &sc->sc_ubaustat);
26387f7a842Ssam sc->sc_ubaustat = 0;
26487f7a842Ssam }
26587f7a842Ssam if (sc->sc_buffer) {
26687f7a842Ssam brelse(sc->sc_buffer);
26787f7a842Ssam sc->sc_buffer = 0;
26887f7a842Ssam }
26987f7a842Ssam sc->sc_flag = 0;
27087f7a842Ssam TRACER("CLOSE\n");
2711db00297Skarels return (0);
27287f7a842Ssam }
27387f7a842Ssam
lpawrite(dev,uio)27425aace65Sroot lpawrite(dev, uio)
27587f7a842Ssam dev_t dev;
27625aace65Sroot struct uio *uio;
27787f7a842Ssam {
27887f7a842Ssam register int unit = LPAUNIT(dev);
27987f7a842Ssam register struct lpa_softc *sc = &lpa_softc[unit];
28087f7a842Ssam register struct uba_device *ui = lpadinfo[unit];
28187f7a842Ssam register struct lpadevice *lpaaddr = (struct lpadevice *) ui->ui_addr;
28287f7a842Ssam register int f;
28387f7a842Ssam
28487f7a842Ssam TRACER("WRITE\n");
28587f7a842Ssam f = sc->sc_flag;
286d672d181Sroot if ((f & OPEN) == 0)
287d672d181Sroot return (ENXIO);
288d672d181Sroot if ((f & MCODE) == 0) /* first write is the microcode */
289d672d181Sroot return (lpamcode(lpaaddr, sc, uio));
290d672d181Sroot if ((f & DMDT) == 0) /* second write is the dispatch table */
291d672d181Sroot return (lpadmdt(lpaaddr, sc, ui->ui_ubanum, uio));
292d672d181Sroot return (ENXIO);
29387f7a842Ssam }
29487f7a842Ssam
lpamcode(lpaaddr,sc,uio)29525aace65Sroot lpamcode(lpaaddr, sc, uio)
29687f7a842Ssam register struct lpadevice *lpaaddr;
29787f7a842Ssam register struct lpa_softc *sc;
29825aace65Sroot struct uio *uio;
29987f7a842Ssam {
30087f7a842Ssam short v, r;
30187f7a842Ssam register int mcaddr;
302af9f716dSroot int error;
30387f7a842Ssam
30487f7a842Ssam mcaddr = 0;
30525aace65Sroot while (uio->uio_resid) {
30645f373caSmckusick error = uiomove(&v, 2, uio);
307af9f716dSroot if (error)
308af9f716dSroot break;
30987f7a842Ssam lpaaddr->lcim = 0; /* load microcode word */
31087f7a842Ssam lpaaddr->lrda = mcaddr;
31187f7a842Ssam lpaaddr->lms = v;
31287f7a842Ssam lpaaddr->lcim = ROMO;
31387f7a842Ssam lpaaddr->lcim |= CWRITE;
31487f7a842Ssam lpaaddr->lcim = 0; /* verify microcode word */
31587f7a842Ssam lpaaddr->lrda = mcaddr;
31687f7a842Ssam lpaaddr->lcim = ROMO;
31787f7a842Ssam if ((r = lpaaddr->lms) != v) {
31887f7a842Ssam /* download failure */
31987f7a842Ssam printf("LPA MICROCODE FAIL: exp:%o got:%o\n", v, r);
320d672d181Sroot return (ENXIO);
32187f7a842Ssam }
32287f7a842Ssam mcaddr++;
32387f7a842Ssam }
32487f7a842Ssam lpaaddr->lcim = RUN | EA; /* turn it on */
32587f7a842Ssam sc->sc_flag |= MCODE;
32687f7a842Ssam lpaaddr->lcim |= IIE;
32787f7a842Ssam lpaaddr->lcos |= OIE;
328af9f716dSroot return (error);
32987f7a842Ssam TRACER("MCODE\n");
33087f7a842Ssam }
33187f7a842Ssam
lpadmdt(lpaaddr,sc,ubanum,uio)33225aace65Sroot lpadmdt(lpaaddr, sc, ubanum, uio)
33387f7a842Ssam register struct lpadevice *lpaaddr;
33487f7a842Ssam register struct lpa_softc *sc;
33587f7a842Ssam register short ubanum;
33625aace65Sroot struct uio *uio;
33787f7a842Ssam {
33887f7a842Ssam register short *p;
33987f7a842Ssam register int n;
340d672d181Sroot int error;
34187f7a842Ssam
34287f7a842Ssam p = (short *) sc->sc_buffer->b_un.b_addr; /* INIT */
34387f7a842Ssam *p++ = (MCVERS << 8) | INIT; /* mode */
34487f7a842Ssam *p++ = ACLOCKA; /* LPA bus device addresses */
34587f7a842Ssam *p++ = ACLOCKB;
34687f7a842Ssam *p++ = AAD1;
34787f7a842Ssam *p++ = AAD2;
34887f7a842Ssam *p++ = ADA;
34987f7a842Ssam *p++ = ADIO1;
35087f7a842Ssam *p++ = ADIO2;
35187f7a842Ssam *p++ = ADIO3;
35287f7a842Ssam *p++ = ADIO4;
35387f7a842Ssam *p++ = ADIO5;
354395e3743Skarels n = MIN(uio->uio_resid, 256); /* dedicated mode dispatch table */
35545f373caSmckusick error = uiomove((char *)p, n, uio);
356d672d181Sroot if (error)
357d672d181Sroot return (error);
35887f7a842Ssam n >>= 1;
35987f7a842Ssam p += n;
36087f7a842Ssam while (n++ < 128)
36187f7a842Ssam *p++ = 0;
36287f7a842Ssam lpacmd(sc->sc_buffer, lpaaddr, sc, ubanum);
36387f7a842Ssam sc->sc_flag |= DMDT;
364d672d181Sroot return (0);
36587f7a842Ssam TRACER("DMDT\n");
36687f7a842Ssam }
36787f7a842Ssam
lpaioctl(dev,cmd,data,flag)368b5e757a2Ssam lpaioctl(dev, cmd, data, flag)
36987f7a842Ssam dev_t dev;
370b5e757a2Ssam caddr_t data;
37187f7a842Ssam {
37287f7a842Ssam register int unit = LPAUNIT(dev);
37387f7a842Ssam register struct lpa_softc *sc = &lpa_softc[unit];
37487f7a842Ssam register struct uba_device *ui = lpadinfo[unit];
37587f7a842Ssam register struct lpadevice *lpaaddr = (struct lpadevice *) ui->ui_addr;
37687f7a842Ssam register short *p;
37787f7a842Ssam register int i;
37887f7a842Ssam register int v;
37987f7a842Ssam struct iocb {
38087f7a842Ssam short *baddr;
38187f7a842Ssam short rate;
38287f7a842Ssam short wc;
383b5e757a2Ssam } *iocb;
38487f7a842Ssam
38587f7a842Ssam TRACER("IOCTL IN\n");
386220098f8Sroot if (cmd != TIOCSETP || (sc->sc_flag & DMDT) == 0)
387220098f8Sroot return (ENXIO);
388b5e757a2Ssam iocb = (struct iocb *)data;
38987f7a842Ssam p = (short *) sc->sc_buffer->b_un.b_addr; /* CLOCK START */
39087f7a842Ssam *p++ = CLOCK | CLOCKA; /* mode */
39187f7a842Ssam *p++ = ENACTR | R1M | MFIE | MRI; /* clock status */
392b5e757a2Ssam *p = iocb->rate; /* clock preset */
39387f7a842Ssam lpacmd(sc->sc_buffer, lpaaddr, sc, ui->ui_ubanum);
39487f7a842Ssam TRACER("CLOCK STARTED\n");
39587f7a842Ssam p = (short *) sc->sc_buffer->b_un.b_addr; /* DATA TRANSFER START*/
39687f7a842Ssam *p++ = (sc->sc_device << 7) | DTS | SCHAN; /* mode */
397b5e757a2Ssam sc->sc_count = iocb->wc & 017777; /* word count per buffer */
39887f7a842Ssam *p++ = sc->sc_count;
39987f7a842Ssam /* user status word */
40087f7a842Ssam sc->sc_ustatbuf.b_un.b_addr = (caddr_t) &sc->sc_ustat;
40187f7a842Ssam sc->sc_ustatbuf.b_flags = 0;
40287f7a842Ssam sc->sc_ustatbuf.b_bcount = 2;
40387f7a842Ssam sc->sc_ustatbuf.b_proc = u.u_procp;
40487f7a842Ssam sc->sc_ubaustat = ubasetup(ui->ui_ubanum, &sc->sc_ustatbuf, 0);
40587f7a842Ssam v = sc->sc_ubaustat;
40687f7a842Ssam *p++ = v;
40787f7a842Ssam *p = (v >> 16) & 03; /* into low portion of word */
408b5e757a2Ssam sc->sc_nbuf = (iocb->wc >> 13) & 07; /* number of buffers */
40987f7a842Ssam *p++ |= sc->sc_nbuf++ << 8; /* into high portion of word */
41087f7a842Ssam /* buffer addresses */
411b5e757a2Ssam if (useracc(sc->sc_ubuffer.b_un.b_addr = (caddr_t) iocb->baddr,
41287f7a842Ssam sc->sc_ubuffer.b_bcount = sc->sc_count * sc->sc_nbuf * 2,
41387f7a842Ssam (i = (sc->sc_device)? B_READ : B_WRITE) ) == NULL) {
41487f7a842Ssam TRACER("USER BUFFER FAULT\n");
415220098f8Sroot return (EFAULT);
41687f7a842Ssam }
41787f7a842Ssam sc->sc_ubuffer.b_flags = B_PHYS | B_BUSY | i;
41887f7a842Ssam sc->sc_ubuffer.b_proc = u.u_procp;
419*afb2e50aSbostic u.u_procp->p_flag |= P_PHYSIO;
42087f7a842Ssam vslock(sc->sc_ubuffer.b_un.b_addr, sc->sc_ubuffer.b_bcount);
42187f7a842Ssam sc->sc_ubabuf = ubasetup(ui->ui_ubanum, &sc->sc_ubuffer, 0);
42287f7a842Ssam v = sc->sc_ubabuf;
42387f7a842Ssam for (i = 0; i < sc->sc_nbuf; i++) {
42487f7a842Ssam *p++ = v;
42587f7a842Ssam *p++ = (v >> 16) & 03;
42687f7a842Ssam v += sc->sc_count * 2;
42787f7a842Ssam }
42887f7a842Ssam for ( ; i <= 7; i++) {
42987f7a842Ssam *p++ = 0;
43087f7a842Ssam *p++ = 0;
43187f7a842Ssam }
43287f7a842Ssam *p++ = 0; *p++ = 0; /* random channel list address */
43387f7a842Ssam *p++ = 0; /* delay */
43487f7a842Ssam *p++ = sc->sc_channel; /* start channel, channel inc */
43587f7a842Ssam *p++ = 1; /* number of samples in a sequence */
43687f7a842Ssam *p++ = 0; /* dwell */
43787f7a842Ssam *p++ = 0; /* start word no., event mark word */
43887f7a842Ssam *p++ = 0; /* start word mask */
43987f7a842Ssam *p = 0; /* event mark mask */
44087f7a842Ssam sc->sc_ustat = 0;
44187f7a842Ssam sc->sc_start = (sc->sc_device)? sc->sc_nbuf+1 : 1;
44287f7a842Ssam sc->sc_lbufn = 0;
44387f7a842Ssam sc->sc_lbufnx = 0;
44487f7a842Ssam sc->sc_flag |= STTY;
44587f7a842Ssam TRACER("IOCTL OUT\n");
446220098f8Sroot return (0);
44787f7a842Ssam }
44887f7a842Ssam
lparead(dev,uio)4496e6bbc9cSroot lparead(dev, uio)
45087f7a842Ssam dev_t dev;
4516e6bbc9cSroot struct uio *uio;
45287f7a842Ssam {
45387f7a842Ssam register int unit = LPAUNIT(dev);
45487f7a842Ssam register struct lpa_softc *sc = &lpa_softc[unit];
45587f7a842Ssam register struct uba_device *ui = lpadinfo[unit];
45687f7a842Ssam register struct lpadevice *lpaaddr = (struct lpadevice *) ui->ui_addr;
45787f7a842Ssam
45887f7a842Ssam TRACER("READ\n");
459d672d181Sroot if ((sc->sc_flag & STTY) == 0)
460d672d181Sroot return (ENXIO);
461d672d181Sroot if (sc->sc_flag & ERROR)
462d672d181Sroot return (ENXIO);
46387f7a842Ssam if (sc->sc_start)
46487f7a842Ssam if (--sc->sc_start == 0) {
46587f7a842Ssam lpacmd(sc->sc_buffer, lpaaddr, sc, ui->ui_ubanum);
46687f7a842Ssam TRACER("START\n");
46787f7a842Ssam }
46887f7a842Ssam inc(sc_ubufn);
46987f7a842Ssam if (sc->sc_start == 0) {
47087f7a842Ssam (void) spl5();
47187f7a842Ssam while (sc->sc_ubufn == sc->sc_lbufn) {
472d672d181Sroot if (sc->sc_flag & ERROR)
473d672d181Sroot return (ENXIO);
47487f7a842Ssam TRACER("SLEEP\n");
47587f7a842Ssam sc->sc_flag |= SLEEP;
47687f7a842Ssam sleep(sc, LPAPRI);
47787f7a842Ssam }
47887f7a842Ssam (void) spl0();
47987f7a842Ssam }
48087f7a842Ssam TRACERN("READ %d\n", sc->sc_ubufn);
48145f373caSmckusick return (uiomove(&sc->sc_ubufn, 1, uio));
48287f7a842Ssam }
48387f7a842Ssam
lpacmd(bp,lpaaddr,sc,ubanum)48487f7a842Ssam lpacmd(bp, lpaaddr, sc, ubanum)
48587f7a842Ssam register struct buf *bp;
48687f7a842Ssam register struct lpadevice *lpaaddr;
48787f7a842Ssam register struct lpa_softc *sc;
48887f7a842Ssam register short ubanum;
48987f7a842Ssam {
49087f7a842Ssam int ubareg;
49187f7a842Ssam
49287f7a842Ssam TRACER("CMD\n");
49387f7a842Ssam ubareg = ubasetup(ubanum, bp, UBA_NEEDBDP);
49487f7a842Ssam lpawait(lpaaddr, sc);
49587f7a842Ssam lpaaddr->lrda = ubareg;
49687f7a842Ssam lpaaddr->lcim &= ~RDAEXT;
49787f7a842Ssam lpaaddr->lcim |= ((ubareg >> (16-RDAEXTOFFSET)) & RDAEXT) | GO;
49887f7a842Ssam lpawait(lpaaddr, sc);
49987f7a842Ssam ubarelse(ubanum, &ubareg);
50087f7a842Ssam }
50187f7a842Ssam
lpawait(lpaaddr,sc)50287f7a842Ssam lpawait(lpaaddr, sc)
50387f7a842Ssam register struct lpadevice *lpaaddr;
50487f7a842Ssam register struct lpa_softc *sc;
50587f7a842Ssam {
506d672d181Sroot
50787f7a842Ssam (void) spl5();
50887f7a842Ssam while ((lpaaddr->lcim & READYI) == 0) {
50987f7a842Ssam TRACER("SLEEP\n");
51087f7a842Ssam sc->sc_flag |= SLEEP;
51187f7a842Ssam sleep((caddr_t)sc, LPAPRI);
51287f7a842Ssam }
51387f7a842Ssam (void) spl0();
51487f7a842Ssam }
51587f7a842Ssam
lpaiintr(unit)51687f7a842Ssam lpaiintr(unit)
51787f7a842Ssam int unit;
51887f7a842Ssam {
51987f7a842Ssam register struct lpa_softc *sc = &lpa_softc[unit];
52087f7a842Ssam
52187f7a842Ssam TRACER("{I");
52287f7a842Ssam if (sc->sc_flag & SLEEP) {
52387f7a842Ssam TRACER("<WAKEUP>");
52487f7a842Ssam wakeup((caddr_t)sc);
52587f7a842Ssam sc->sc_flag &= ~SLEEP;
52687f7a842Ssam }
52787f7a842Ssam TRACER("}");
52887f7a842Ssam }
52987f7a842Ssam
lpaointr(unit)53087f7a842Ssam lpaointr(unit)
53187f7a842Ssam int unit;
53287f7a842Ssam {
53387f7a842Ssam register int c, m;
53487f7a842Ssam register struct lpa_softc *sc = &lpa_softc[unit];
53587f7a842Ssam register struct uba_device *ui = lpadinfo[unit];
53687f7a842Ssam register struct lpadevice *lpaaddr = (struct lpadevice *) ui->ui_addr;
53787f7a842Ssam int spx;
53887f7a842Ssam
53987f7a842Ssam TRACER("{O");
54087f7a842Ssam if (sc->sc_flag & SLEEP) {
54187f7a842Ssam TRACER("<WAKEUP>");
54287f7a842Ssam wakeup(sc);
54387f7a842Ssam sc->sc_flag &= ~SLEEP;
54487f7a842Ssam }
54587f7a842Ssam c = lpaaddr->lcos;
54687f7a842Ssam m = lpaaddr->lms;
54787f7a842Ssam lpaaddr->lcos &= ~READYO;
54887f7a842Ssam if (c & ERROR) {
54987f7a842Ssam TRACER("<ERROR>");
55087f7a842Ssam c = (c >> 8) & 0377;
55187f7a842Ssam if ((sc->sc_flag & STOP) == 0 || (c != OVERRUN)) {
55287f7a842Ssam printf("LPA ERROR %o %o\n", c, m&0177777);
55387f7a842Ssam sc->sc_flag |= ERROR;
55487f7a842Ssam }
55587f7a842Ssam sc->sc_flag &= ~STOP;
55687f7a842Ssam TRACER("}\n");
55787f7a842Ssam return;
55887f7a842Ssam }
55987f7a842Ssam TRACERN("<LPA %d>", sc->sc_lbufnx);
56087f7a842Ssam sc->sc_lbufn = sc->sc_lbufnx;
56187f7a842Ssam if (sc->sc_ubufn == sc->sc_lbufnx && c & ECODE) {
56287f7a842Ssam TRACER("<STOP?>");
56387f7a842Ssam if (sc->sc_flag & STOP)
56487f7a842Ssam return;
56587f7a842Ssam printf("LPA OVERRUN\n");
56687f7a842Ssam sc->sc_flag |= ERROR;
56787f7a842Ssam }
56887f7a842Ssam inc(sc_lbufnx);
56987f7a842Ssam TRACERN("<USTAT %o>", sc->sc_ustat);
570395e3743Skarels spx = splhigh();
57187f7a842Ssam sc->sc_ustat &= ~NBI;
57287f7a842Ssam sc->sc_ustat |= sc->sc_lbufnx << 8;
57387f7a842Ssam sc->sc_ustat &= ~DONE;
574395e3743Skarels splx(spx);
57587f7a842Ssam TRACERN("<LPAN %d>}", sc->sc_lbufnx);
57687f7a842Ssam }
57787f7a842Ssam
lpareset(uban)57887f7a842Ssam lpareset(uban)
57987f7a842Ssam int uban;
58087f7a842Ssam {
58187f7a842Ssam register struct uba_device *ui;
58287f7a842Ssam register struct lpadevice *lpaaddr;
58387f7a842Ssam register struct lpa_softc *sc;
58487f7a842Ssam register int unit;
58587f7a842Ssam
58687f7a842Ssam TRACER("LPA RESET\n");
58787f7a842Ssam for (unit = 0; unit < NLPA; unit++) {
58887f7a842Ssam if ((ui = lpadinfo[unit]) == 0 ||
589d672d181Sroot ui->ui_ubanum != uban || ui->ui_alive == 0)
59087f7a842Ssam continue;
59187f7a842Ssam printf(" lpa%d", unit);
59287f7a842Ssam lpaaddr = (struct lpadevice *)ui->ui_addr;
59387f7a842Ssam sc = &lpa_softc[unit];
59487f7a842Ssam sc->sc_flag |= ERROR;
595395e3743Skarels (void) splhigh();
59687f7a842Ssam lpaaddr->lcim = RESET;
59787f7a842Ssam lpaaddr->lcim = 0;
59887f7a842Ssam (void) spl0();
59987f7a842Ssam if (sc->sc_flag & SLEEP) {
60087f7a842Ssam wakeup((caddr_t)sc);
60187f7a842Ssam sc->sc_flag &= ~SLEEP;
60287f7a842Ssam }
60387f7a842Ssam }
60487f7a842Ssam }
60587f7a842Ssam #endif NLPA
606