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