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.6 (Berkeley) 09/23/93
7 */
8
9 #include "lpa.h"
10 #if NLPA > 0
11
12 #include "sys/param.h"
13 #include "sys/user.h"
14 #include "sys/buf.h"
15 #include "sys/proc.h"
16 #include "sys/ioctl.h"
17 #include "sys/uio.h"
18
19 #include "ubavar.h"
20
21 /*
22 * LPA driver for -- Asa Romberger
23 *
24 * open
25 * write microcode
26 * write dedicated mode dispatch table
27 * ioctl TIOCSETP to set parameters
28 * struct iocb {
29 * short *baddr; buffer address
30 * short rate; - 1,000,000 / frequency in Hz
31 * short wc; 15-13 = number of buffers - 1
32 * 12-0 = buffer size in words
33 * } iocb;
34 * read - 1 character indicating buffer index
35 * fill or empty buffer
36 * minor device number = DDCCCCCC where:
37 * DD = 00 for analog input
38 * = 01 for analog output
39 * CCCCCC = channel number
40 */
41 * define NOMCODE to eliminate the microcode download check
42 */
43 /* #define TRACELPA */
44 /* #define NOMCODE */
45
46 #ifdef TRACELPA
47 # define TRACER(x) printf(x)
48 # define TRACERN(x, d) printf(x, d)
49 #else
50 # define TRACER(x)
51 # define TRACERN(x, d)
52 #endif
53
54 /* PRIORITY AT WHICH PROGRAM SHOULD RUN */
55 /* THIS SHOULD EVENTUALLY TELL UNIX THIS IS A REAL-TIME DEVICE */
56
57 #define NICE 0
58
59 #define inc(v) (sc->v = ((sc->v + 1) % sc->sc_nbuf))
60
61 #define LPAPRI (PZERO + 0)
62 #define LPAUNIT(dev) 0
63 #define LPADEVICE(dev) (((dev) >> 6) & 03)
64 #define LPACHANNEL(dev) ((dev) & 077)
65
66 int lpaprobe(), lpaattach(), lpaiintr(), lpaointr();
67 u_short lpastd[] = {0170460, 0};
68 struct uba_device *lpadinfo[NLPA];
69 struct uba_driver lpadriver =
70 {lpaprobe, 0, lpaattach, 0, lpastd, "lpa", lpadinfo, 0, 0, 0 };
71
72 struct lpa_softc {
73 int sc_flag; /* flags, as defined below */
74 int sc_device; /* device: 0 = analog in, 1 = analog out */
75 int sc_channel; /* device channel number */
76 struct buf sc_ubuffer; /* user buffer header */
77 int sc_ubabuf; /* uba allocation pointer for buffer */
78 int sc_ubufn; /* present buffer that user is accessing */
79 int sc_lbufn; /* present buffer that lpa is accessing */
80 int sc_lbufnx; /* next buffer for lpa (value in ustat) */
81 int sc_nbuf; /* number of buffers */
82 int sc_count; /* buffer size in words */
83 short sc_ustat; /* user status word */
84 struct buf sc_ustatbuf; /* dummy user status word buffer for ubasetup */
85 int sc_ubaustat; /* uba allocation pointer for ustat */
86 struct buf *sc_buffer; /* scratch buffer header */
87 int sc_start; /* 0 if lpa operation has been started */
88 } lpa_softc[NLPA];
89
90 /* flags for sc_flag */
91 #define OPEN 01 /* device is open */
92 #define MCODE 02 /* microcode has been loaded */
93 #define DMDT 04 /* dedicated mode dispatch table loaded */
94 #define STTY 010 /* stty call and device initialized */
95 #define SLEEP 020 /* sleeping */
96
97 /* bits for ustat */
98 #define DONE 0100000 /* done */
99 #define STOP 0040000 /* stop data transfer */
100 #define NBI 0003400 /* next buffer index */
101 #define LBI 0000003 /* last buffer index */
102
103 struct lpadevice {
104 short lcim; /* control in and maintenance */
105 short lcos; /* control and status out */
106 short lrda; /* request description array address word */
107 short lms; /* maintenance status */
108 };
109
110 /* control in and maintenance register bits */
111 #define READYI 0000200 /* ready in */
112 #define IIE 0000100 /* in interrupt enable */
113 #define RDAEXT 0000014 /* rda address extension */
114 #define RDAEXTOFFSET 2 /* offset of RDAEXT from right side */
115 #define GO 0000001 /* go */
116 #define RUN 0100000 /* run */
117 #define RESET 0040000 /* reset */
118 #define CWRITE 0020000 /* cram write */
119 #define EA 0004000 /* enable arbitration */
120 #define ROMO 0002000 /* rom O */
121 #define ROMI 0001000 /* rom I */
122 #define SMICRO 0000400 /* step microprocessor */
123
124 /* control and status out register bits */
125 #define READYO 0200 /* ready out */
126 #define OIE 0100 /* out interrupt enable */
127 #define UINDEX 0007 /* user index */
128 #define ERROR 0100000 /* error */
129 #define ESTAT 0060000 /* error status */
130 #define ESCODE 0017400 /* error sub code */
131 #define ECODE 0077400 /* error status + error sub code */
132 #define OVERRUN 0243 /* overrun error */
133
134 /* LPA COMMAND DESCRIPTION AREA */
135
136 /* INIT COMMAND */
137 #define INIT 0 /* mode */
138 #define MCVERS 4 /* microcode version */
139 #define ACLOCKA 0170404 /* LPA bus addresses */
140 #define ACLOCKB 0170432
141 #define AAD1 0170400
142 #define AAD2 1 /* 0170440 - DOES NOT EXIST */
143 #define ADA 0170420
144 #define ADIO1 1 /* 0167770 - DOES NOT EXIST */
145 #define ADIO2 1 /* 0167760 - DOES NOT EXIST */
146 #define ADIO3 1 /* 0167750 - DOES NOT EXIST */
147 #define ADIO4 1 /* 0167740 - DOES NOT EXIST */
148 #define ADIO5 1 /* 0167730 - DOES NOT EXIST */
149
150 /* CLOCK START COMMAND */
151 #define CLOCK 1 /* mode */
152 #define CLOCKA 0<<4 /* clock A */
153 /* clock status word */
154 #define ENACTR 1 /* enable counter */
155 #define R1M 1<<1 /* 1 MHz rate */
156 #define R100K 2<<1 /* 100 KHz rate */
157 #define R10K 3<<1 /* 10 KHz rate */
158 #define R1K 4<<1 /* 1 KHz rate */
159 #define R100 5<<1 /* 100 Hz rate */
160 #define REXT 6<<1 /* external rate (from st1 input) */
161 #define R60 7<<1 /* line frequency rate */
162 #define MFIE 0100 /* mode flag interrupt enable */
163 #define MSI 0<<8 /* single interval mode */
164 #define MRI 1<<8 /* repeat interval mode */
165 #define MEET 2<<8 /* external event time mode */
166 #define MEETZ 3<<8 /* external event time mode from zero base */
167 #define ST1EC 020000 /* st1 enable counter */
168 #define ST1IE 040000 /* st1 interrupt enable */
169
170 /* DATA TRANSFER START COMMAND */
171 #define DTS 2 /* mode */
172 #define SCHAN 1<<8 /* single channel */
173
lpaprobe(reg)174 lpaprobe(reg)
175 caddr_t reg;
176 {
177 register int br, cvec; /* value result */
178 register struct lpadevice *lpaaddr = (struct lpadevice *)reg;
179
180 #ifdef lint
181 br = 0; cvec = br; br = cvec;
182 #endif
183 /* this should force an interrupt, stall, clear the lpa */
184 br = 0x15;
185 cvec = 0330;
186 TRACER("PROBE\n");
187 return (sizeof (struct lpadevice));
188 }
189
lpaattach(ui)190 lpaattach(ui)
191 register struct upa_device *ui;
192 {
193
194 }
195
lpaopen(dev,flag)196 lpaopen(dev, flag)
197 dev_t dev;
198 int flag;
199 {
200 register int unit = LPAUNIT(dev);
201 register struct lpa_softc *sc = &lpa_softc[unit];
202 register struct uba_device *ui = lpadinfo[unit];
203 register struct lpadevice *lpaaddr = (struct lpadevice *) ui->ui_addr;
204
205 TRACER("OPEN\n");
206 if (unit >= NLPA || sc->sc_flag & OPEN || ui == 0 ||
207 ui->ui_alive == 0)
208 return (ENXIO);
209 (void) splhigh();
210 lpaaddr->lcim = RESET;
211 lpaaddr->lcim = 0;
212 (void) spl0();
213 lpaaddr->lcos = 0; /* clear the registers as a precaution */
214 lpaaddr->lrda = 0;
215 lpaaddr->lms = 0;
216 sc->sc_flag = OPEN;
217 sc->sc_device = LPADEVICE(dev);
218 sc->sc_channel = LPACHANNEL(dev);
219 sc->sc_buffer = geteblk();
220 sc->sc_buffer->b_error = 0;
221 sc->sc_buffer->b_proc = u.u_procp;
222 sc->sc_ubufn = -1;
223 /* THIS SHOULD EVENTUALLY SPECIFY "REAL-TIME" */
224 u.u_procp->p_nice = NICE;
225 return (0);
226 }
227
lpaclose(dev,flag)228 lpaclose(dev, flag)
229 dev_t dev;
230 int flag;
231 {
232 register int unit = LPAUNIT(dev);
233 register struct lpa_softc *sc = &lpa_softc[unit];
234 register struct uba_device *ui = lpadinfo[unit];
235 register struct lpadevice *lpaaddr = (struct lpadevice *) ui->ui_addr;
236
237 if (sc->sc_device && sc->sc_ubufn >= 0 && (sc->sc_flag & ERROR) == 0) {
238 if (sc->sc_start)
239 lpacmd(sc->sc_buffer, lpaaddr, sc, ui->ui_ubanum);
240 sc->sc_flag |= STOP;
241 (void) spl5();
242 while (sc->sc_flag & STOP) {
243 TRACER("SLEEP\n");
244 sc->sc_flag |= SLEEP;
245 sleep((caddr_t)sc, LPAPRI);
246 }
247 }
248 (void) splhigh();
249 lpaaddr->lcim = RESET;
250 lpaaddr->lcim = 0;
251 (void) spl0();
252 if (sc->sc_ubabuf) {
253 ubarelse(ui->ui_ubanum, &sc->sc_ubabuf);
254 sc->sc_ubabuf = 0;
255 (void) splclock();
256 vsunlock(sc->sc_ubuffer.b_un.b_addr, sc->sc_ubuffer.b_bcount,
257 (sc->sc_device)? B_READ : B_WRITE);
258 u.u_procp->p_flag &= ~P_PHYSIO;
259 (void) spl0();
260 }
261 if (sc->sc_ubaustat) {
262 ubarelse(ui->ui_ubanum, &sc->sc_ubaustat);
263 sc->sc_ubaustat = 0;
264 }
265 if (sc->sc_buffer) {
266 brelse(sc->sc_buffer);
267 sc->sc_buffer = 0;
268 }
269 sc->sc_flag = 0;
270 TRACER("CLOSE\n");
271 return (0);
272 }
273
lpawrite(dev,uio)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
lpamcode(lpaaddr,sc,uio)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);
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
lpadmdt(lpaaddr,sc,ubanum,uio)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);
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
lpaioctl(dev,cmd,data,flag)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 |= P_PHYSIO;
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
lparead(dev,uio)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));
482 }
483
lpacmd(bp,lpaaddr,sc,ubanum)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
lpawait(lpaaddr,sc)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
lpaiintr(unit)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
lpaointr(unit)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
lpareset(uban)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
606