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