generalize uba code to handle Q bus more gracefully
[unix-history] / usr / src / sys / vax / uba / lpa.c
CommitLineData
da7c5cc6 1/*
0880b18e 2 * Copyright (c) 1982, 1986 Regents of the University of California.
da7c5cc6
KM
3 * All rights reserved. The Berkeley software License Agreement
4 * specifies the terms and conditions for redistribution.
5 *
0880b18e 6 * @(#)lpa.c 7.1 (Berkeley) %G%
da7c5cc6 7 */
896962b1 8
de1d86d8
SL
9#include "lpa.h"
10#if NLPA > 0
11
ff360633
JB
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"
de1d86d8 19
ff360633 20#include "ubavar.h"
896962b1 21
de1d86d8 22/*
b91c756d
BJ
23 * LPA driver for -- Asa Romberger
24 *
de1d86d8
SL
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 */
de1d86d8
SL
42 * define NOMCODE to eliminate the microcode download check
43 */
b91c756d
BJ
44/* #define TRACELPA */
45/* #define NOMCODE */
de1d86d8
SL
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
b91c756d 60#define inc(v) (sc->v = ((sc->v + 1) % sc->sc_nbuf))
de1d86d8 61
b91c756d 62#define LPAPRI (PZERO + 0)
de1d86d8
SL
63#define LPAUNIT(dev) 0
64#define LPADEVICE(dev) (((dev) >> 6) & 03)
65#define LPACHANNEL(dev) ((dev) & 077)
66
b91c756d
BJ
67int lpaprobe(), lpaattach(), lpaiintr(), lpaointr();
68u_short lpastd[] = {0170460, 0};
69struct uba_device *lpadinfo[NLPA];
de1d86d8 70struct uba_driver lpadriver =
b91c756d 71 {lpaprobe, 0, lpaattach, 0, lpastd, "lpa", lpadinfo, 0, 0, 0 };
de1d86d8
SL
72
73struct 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];
b91c756d
BJ
90
91/* flags for sc_flag */
de1d86d8
SL
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 */
b91c756d
BJ
97
98/* bits for ustat */
de1d86d8
SL
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
de1d86d8
SL
104struct 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};
b91c756d
BJ
110
111/* control in and maintenance register bits */
de1d86d8
SL
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 */
b91c756d
BJ
124
125/* control and status out register bits */
de1d86d8
SL
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
b91c756d 135/* LPA COMMAND DESCRIPTION AREA */
de1d86d8 136
b91c756d 137/* INIT COMMAND */
de1d86d8
SL
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 */
b91c756d
BJ
150
151/* CLOCK START COMMAND */
de1d86d8
SL
152#define CLOCK 1 /* mode */
153#define CLOCKA 0<<4 /* clock A */
b91c756d 154 /* clock status word */
de1d86d8
SL
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 */
b91c756d
BJ
170
171/* DATA TRANSFER START COMMAND */
de1d86d8
SL
172#define DTS 2 /* mode */
173#define SCHAN 1<<8 /* single channel */
174
de1d86d8 175lpaprobe(reg)
b91c756d 176 caddr_t reg;
de1d86d8 177{
b91c756d
BJ
178 register int br, cvec; /* value result */
179 register struct lpadevice *lpaaddr = (struct lpadevice *)reg;
de1d86d8
SL
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;
187TRACER("PROBE\n");
9c0adba0 188 return (sizeof (struct lpadevice));
de1d86d8
SL
189}
190
de1d86d8 191lpaattach(ui)
b91c756d 192 register struct upa_device *ui;
de1d86d8 193{
b91c756d 194
de1d86d8
SL
195}
196
de1d86d8 197lpaopen(dev, flag)
b91c756d
BJ
198 dev_t dev;
199 int flag;
de1d86d8
SL
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
206TRACER("OPEN\n");
207 if (unit >= NLPA || sc->sc_flag & OPEN || ui == 0 ||
7da157da
BJ
208 ui->ui_alive == 0)
209 return (ENXIO);
8011f5df 210 (void) splhigh();
de1d86d8
SL
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;
7da157da 226 return (0);
de1d86d8
SL
227}
228
de1d86d8 229lpaclose(dev, flag)
b91c756d
BJ
230 dev_t dev;
231 int flag;
de1d86d8
SL
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) {
244TRACER("SLEEP\n");
245 sc->sc_flag |= SLEEP;
246 sleep((caddr_t)sc, LPAPRI);
247 }
248 }
8011f5df 249 (void) splhigh();
de1d86d8
SL
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;
8011f5df 256 (void) splclock();
de1d86d8
SL
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;
271TRACER("CLOSE\n");
272}
273
406ddcbe
BJ
274lpawrite(dev, uio)
275 dev_t dev;
276 struct uio *uio;
de1d86d8
SL
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
284TRACER("WRITE\n");
285 f = sc->sc_flag;
b91c756d
BJ
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);
de1d86d8
SL
293}
294
406ddcbe
BJ
295lpamcode(lpaaddr, sc, uio)
296 register struct lpadevice *lpaaddr;
297 register struct lpa_softc *sc;
298 struct uio *uio;
de1d86d8
SL
299{
300 short v, r;
301 register int mcaddr;
5a1f132a 302 int error;
de1d86d8
SL
303
304 mcaddr = 0;
406ddcbe 305 while (uio->uio_resid) {
5a1f132a
BJ
306 error = uiomove(&v, 2, UIO_WRITE, uio);
307 if (error)
308 break;
de1d86d8
SL
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);
b91c756d 320 return (ENXIO);
de1d86d8
SL
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;
5a1f132a 328 return (error);
de1d86d8
SL
329TRACER("MCODE\n");
330}
331
406ddcbe
BJ
332lpadmdt(lpaaddr, sc, ubanum, uio)
333 register struct lpadevice *lpaaddr;
334 register struct lpa_softc *sc;
335 register short ubanum;
336 struct uio *uio;
de1d86d8
SL
337{
338 register short *p;
339 register int n;
b91c756d 340 int error;
de1d86d8
SL
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;
8011f5df 354 n = MIN(uio->uio_resid, 256); /* dedicated mode dispatch table */
b91c756d
BJ
355 error = uiomove((char *)p, n, UIO_WRITE, uio);
356 if (error)
357 return (error);
de1d86d8
SL
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;
b91c756d 364 return (0);
de1d86d8
SL
365TRACER("DMDT\n");
366}
367
942f05a9
SL
368lpaioctl(dev, cmd, data, flag)
369 dev_t dev;
370 caddr_t data;
de1d86d8
SL
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;
942f05a9 383 } *iocb;
de1d86d8
SL
384
385TRACER("IOCTL IN\n");
7da157da
BJ
386 if (cmd != TIOCSETP || (sc->sc_flag & DMDT) == 0)
387 return (ENXIO);
942f05a9 388 iocb = (struct iocb *)data;
de1d86d8
SL
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 */
942f05a9 392 *p = iocb->rate; /* clock preset */
de1d86d8
SL
393 lpacmd(sc->sc_buffer, lpaaddr, sc, ui->ui_ubanum);
394TRACER("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 */
942f05a9 397 sc->sc_count = iocb->wc & 017777; /* word count per buffer */
de1d86d8
SL
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 */
942f05a9 408 sc->sc_nbuf = (iocb->wc >> 13) & 07; /* number of buffers */
de1d86d8
SL
409 *p++ |= sc->sc_nbuf++ << 8; /* into high portion of word */
410 /* buffer addresses */
942f05a9 411 if (useracc(sc->sc_ubuffer.b_un.b_addr = (caddr_t) iocb->baddr,
7da157da
BJ
412 sc->sc_ubuffer.b_bcount = sc->sc_count * sc->sc_nbuf * 2,
413 (i = (sc->sc_device)? B_READ : B_WRITE) ) == NULL) {
de1d86d8 414TRACER("USER BUFFER FAULT\n");
7da157da 415 return (EFAULT);
de1d86d8
SL
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);
de1d86d8
SL
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;
445TRACER("IOCTL OUT\n");
7da157da 446 return (0);
de1d86d8
SL
447}
448
740e4029 449lparead(dev, uio)
406ddcbe
BJ
450 dev_t dev;
451 struct uio *uio;
de1d86d8
SL
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
458TRACER("READ\n");
b91c756d
BJ
459 if ((sc->sc_flag & STTY) == 0)
460 return (ENXIO);
461 if (sc->sc_flag & ERROR)
462 return (ENXIO);
de1d86d8
SL
463 if (sc->sc_start)
464 if (--sc->sc_start == 0) {
465 lpacmd(sc->sc_buffer, lpaaddr, sc, ui->ui_ubanum);
466TRACER("START\n");
467 }
468 inc(sc_ubufn);
469 if (sc->sc_start == 0) {
470 (void) spl5();
471 while (sc->sc_ubufn == sc->sc_lbufn) {
b91c756d
BJ
472 if (sc->sc_flag & ERROR)
473 return (ENXIO);
de1d86d8
SL
474TRACER("SLEEP\n");
475 sc->sc_flag |= SLEEP;
476 sleep(sc, LPAPRI);
477 }
478 (void) spl0();
479 }
480TRACERN("READ %d\n", sc->sc_ubufn);
b91c756d 481 return (uiomove(&sc->sc_ubufn, 1, UIO_READ, uio));
de1d86d8
SL
482}
483
de1d86d8 484lpacmd(bp, lpaaddr, sc, ubanum)
406ddcbe
BJ
485 register struct buf *bp;
486 register struct lpadevice *lpaaddr;
487 register struct lpa_softc *sc;
488 register short ubanum;
de1d86d8
SL
489{
490 int ubareg;
491
492TRACER("CMD\n");
de1d86d8
SL
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);
de1d86d8
SL
500}
501
de1d86d8 502lpawait(lpaaddr, sc)
b91c756d
BJ
503 register struct lpadevice *lpaaddr;
504 register struct lpa_softc *sc;
de1d86d8 505{
b91c756d 506
de1d86d8
SL
507 (void) spl5();
508 while ((lpaaddr->lcim & READYI) == 0) {
509TRACER("SLEEP\n");
510 sc->sc_flag |= SLEEP;
511 sleep((caddr_t)sc, LPAPRI);
512 }
513 (void) spl0();
514}
515
de1d86d8 516lpaiintr(unit)
b91c756d 517 int unit;
de1d86d8
SL
518{
519 register struct lpa_softc *sc = &lpa_softc[unit];
520
521TRACER("{I");
522 if (sc->sc_flag & SLEEP) {
523TRACER("<WAKEUP>");
524 wakeup((caddr_t)sc);
525 sc->sc_flag &= ~SLEEP;
526 }
527TRACER("}");
528}
529
de1d86d8 530lpaointr(unit)
b91c756d 531 int unit;
de1d86d8
SL
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
539TRACER("{O");
540 if (sc->sc_flag & SLEEP) {
541TRACER("<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) {
549TRACER("<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;
556TRACER("}\n");
557 return;
558 }
559TRACERN("<LPA %d>", sc->sc_lbufnx);
560 sc->sc_lbufn = sc->sc_lbufnx;
561 if (sc->sc_ubufn == sc->sc_lbufnx && c & ECODE) {
562TRACER("<STOP?>");
563 if (sc->sc_flag & STOP)
564 return;
565 printf("LPA OVERRUN\n");
566 sc->sc_flag |= ERROR;
567 }
568 inc(sc_lbufnx);
569TRACERN("<USTAT %o>", sc->sc_ustat);
8011f5df 570 spx = splhigh();
de1d86d8
SL
571 sc->sc_ustat &= ~NBI;
572 sc->sc_ustat |= sc->sc_lbufnx << 8;
573 sc->sc_ustat &= ~DONE;
8011f5df 574 splx(spx);
de1d86d8
SL
575TRACERN("<LPAN %d>}", sc->sc_lbufnx);
576}
577
de1d86d8 578lpareset(uban)
b91c756d 579 int uban;
de1d86d8
SL
580{
581 register struct uba_device *ui;
582 register struct lpadevice *lpaaddr;
583 register struct lpa_softc *sc;
584 register int unit;
585
586TRACER("LPA RESET\n");
587 for (unit = 0; unit < NLPA; unit++) {
b91c756d
BJ
588 if ((ui = lpadinfo[unit]) == 0 ||
589 ui->ui_ubanum != uban || ui->ui_alive == 0)
590 continue;
de1d86d8
SL
591 printf(" lpa%d", unit);
592 lpaaddr = (struct lpadevice *)ui->ui_addr;
593 sc = &lpa_softc[unit];
594 sc->sc_flag |= ERROR;
8011f5df 595 (void) splhigh();
de1d86d8
SL
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