Commit | Line | Data |
---|---|---|
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 |
67 | int lpaprobe(), lpaattach(), lpaiintr(), lpaointr(); |
68 | u_short lpastd[] = {0170460, 0}; | |
69 | struct uba_device *lpadinfo[NLPA]; | |
de1d86d8 | 70 | struct uba_driver lpadriver = |
b91c756d | 71 | {lpaprobe, 0, lpaattach, 0, lpastd, "lpa", lpadinfo, 0, 0, 0 }; |
de1d86d8 SL |
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]; | |
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 |
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 | }; | |
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 | 175 | lpaprobe(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; | |
187 | TRACER("PROBE\n"); | |
9c0adba0 | 188 | return (sizeof (struct lpadevice)); |
de1d86d8 SL |
189 | } |
190 | ||
de1d86d8 | 191 | lpaattach(ui) |
b91c756d | 192 | register struct upa_device *ui; |
de1d86d8 | 193 | { |
b91c756d | 194 | |
de1d86d8 SL |
195 | } |
196 | ||
de1d86d8 | 197 | lpaopen(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 | ||
206 | TRACER("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 | 229 | lpaclose(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) { | |
244 | TRACER("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; | |
271 | TRACER("CLOSE\n"); | |
272 | } | |
273 | ||
406ddcbe BJ |
274 | lpawrite(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 | ||
284 | TRACER("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 |
295 | lpamcode(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 |
329 | TRACER("MCODE\n"); |
330 | } | |
331 | ||
406ddcbe BJ |
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; | |
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 |
365 | TRACER("DMDT\n"); |
366 | } | |
367 | ||
942f05a9 SL |
368 | lpaioctl(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 | |
385 | TRACER("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); |
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 */ | |
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 | 414 | TRACER("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; | |
445 | TRACER("IOCTL OUT\n"); | |
7da157da | 446 | return (0); |
de1d86d8 SL |
447 | } |
448 | ||
740e4029 | 449 | lparead(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 | ||
458 | TRACER("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); | |
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) { | |
b91c756d BJ |
472 | if (sc->sc_flag & ERROR) |
473 | return (ENXIO); | |
de1d86d8 SL |
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); | |
b91c756d | 481 | return (uiomove(&sc->sc_ubufn, 1, UIO_READ, uio)); |
de1d86d8 SL |
482 | } |
483 | ||
de1d86d8 | 484 | lpacmd(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 | ||
492 | TRACER("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 | 502 | lpawait(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) { | |
509 | TRACER("SLEEP\n"); | |
510 | sc->sc_flag |= SLEEP; | |
511 | sleep((caddr_t)sc, LPAPRI); | |
512 | } | |
513 | (void) spl0(); | |
514 | } | |
515 | ||
de1d86d8 | 516 | lpaiintr(unit) |
b91c756d | 517 | int unit; |
de1d86d8 SL |
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 | ||
de1d86d8 | 530 | lpaointr(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 | ||
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); | |
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 |
575 | TRACERN("<LPAN %d>}", sc->sc_lbufnx); |
576 | } | |
577 | ||
de1d86d8 | 578 | lpareset(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 | ||
586 | TRACER("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 |