Commit | Line | Data |
---|---|---|
dc44829a | 1 | /* dz.c 3.6 %H% */ |
5074fa57 BJ |
2 | |
3 | /* | |
4 | * DZ-11 Driver | |
5 | */ | |
6 | #include "../h/param.h" | |
7 | #include "../h/systm.h" | |
8 | #include "../h/tty.h" | |
9 | #include "../h/dir.h" | |
10 | #include "../h/user.h" | |
11 | #include "../h/map.h" | |
12 | #include "../h/pte.h" | |
13 | #include "../h/uba.h" | |
14 | #include "../h/conf.h" | |
15 | #include "../h/pdma.h" | |
771d8988 | 16 | #include "../h/bk.h" |
d3ebf5ee BJ |
17 | |
18 | /* | |
19 | * When running dz's using only SAE (silo alarm) on input | |
20 | * it is necessary to call dzrint() at clock interrupt time. | |
21 | * This is unsafe unless spl5()s in tty code are changed to | |
22 | * spl6()s to block clock interrupts. Note that the dh driver | |
23 | * currently in use works the same way as the dz, even though | |
24 | * we could try to more intelligently manage its silo. | |
25 | * Thus don't take this out if you have no dz's unless you | |
26 | * change clock.c and dhtimer(). | |
27 | */ | |
28 | #define spl5 spl6 | |
5074fa57 BJ |
29 | |
30 | #define DZADDR (UBA0_DEV + 0160100) | |
31 | #ifdef ERNIE | |
32 | #define NDZ (3*8) | |
33 | #else | |
34 | #define NDZ (8) | |
35 | #endif | |
36 | ||
37 | #define BITS7 020 | |
38 | #define BITS8 030 | |
39 | #define TWOSB 040 | |
40 | #define PENABLE 0100 | |
41 | #define OPAR 0200 | |
42 | #define MSE 040 /* Master Scan Enable */ | |
43 | #define RIE 0100 /* Receiver Interrupt Enable */ | |
9dca4f86 BJ |
44 | #define SAE 010000 /* Silo Alarm Enable */ |
45 | #define TIE 040000 /* Transmit Interrupt Enable */ | |
46 | #define DZ_IEN (MSE+RIE+TIE+SAE) | |
5074fa57 BJ |
47 | #define PERROR 010000 |
48 | #define FRERROR 020000 | |
9dca4f86 | 49 | #define OVERRUN 040000 |
5074fa57 BJ |
50 | #define SSPEED 7 /* std speed = 300 baud */ |
51 | ||
52 | ||
53 | #define dzlpr dzrbuf | |
54 | #define dzmsr dzbrk | |
55 | #define ON 1 | |
56 | #define OFF 0 | |
57 | ||
58 | int dzstart(); | |
59 | int dzxint(); | |
771d8988 | 60 | int ttrstrt(); |
5074fa57 BJ |
61 | struct tty dz_tty[NDZ]; |
62 | int dz_cnt = { NDZ }; | |
9dca4f86 | 63 | int dzact; |
5074fa57 BJ |
64 | |
65 | struct device { | |
66 | short dzcsr; | |
67 | short dzrbuf; | |
68 | char dztcr; | |
69 | char dzdtr; | |
70 | char dztbuf; | |
71 | char dzbrk; | |
72 | }; | |
73 | ||
74 | struct pdma dzpdma[] = { | |
75 | (struct device *)(DZADDR), NULL, NULL, (int)&dz_tty[0], dzxint, | |
76 | (struct device *)(DZADDR), NULL, NULL, (int)&dz_tty[1], dzxint, | |
77 | (struct device *)(DZADDR), NULL, NULL, (int)&dz_tty[2], dzxint, | |
78 | (struct device *)(DZADDR), NULL, NULL, (int)&dz_tty[3], dzxint, | |
79 | (struct device *)(DZADDR), NULL, NULL, (int)&dz_tty[4], dzxint, | |
80 | (struct device *)(DZADDR), NULL, NULL, (int)&dz_tty[5], dzxint, | |
81 | (struct device *)(DZADDR), NULL, NULL, (int)&dz_tty[6], dzxint, | |
82 | (struct device *)(DZADDR), NULL, NULL, (int)&dz_tty[7], dzxint, | |
83 | #ifdef ERNIE | |
84 | (struct device *)(DZADDR+010), NULL, NULL, (int)&dz_tty[8], dzxint, | |
85 | (struct device *)(DZADDR+010), NULL, NULL, (int)&dz_tty[9], dzxint, | |
86 | (struct device *)(DZADDR+010), NULL, NULL, (int)&dz_tty[10], dzxint, | |
87 | (struct device *)(DZADDR+010), NULL, NULL, (int)&dz_tty[11], dzxint, | |
88 | (struct device *)(DZADDR+010), NULL, NULL, (int)&dz_tty[12], dzxint, | |
89 | (struct device *)(DZADDR+010), NULL, NULL, (int)&dz_tty[13], dzxint, | |
90 | (struct device *)(DZADDR+010), NULL, NULL, (int)&dz_tty[14], dzxint, | |
91 | (struct device *)(DZADDR+010), NULL, NULL, (int)&dz_tty[15], dzxint, | |
92 | (struct device *)(DZADDR+020), NULL, NULL, (int)&dz_tty[16], dzxint, | |
93 | (struct device *)(DZADDR+020), NULL, NULL, (int)&dz_tty[17], dzxint, | |
94 | (struct device *)(DZADDR+020), NULL, NULL, (int)&dz_tty[18], dzxint, | |
95 | (struct device *)(DZADDR+020), NULL, NULL, (int)&dz_tty[19], dzxint, | |
96 | (struct device *)(DZADDR+020), NULL, NULL, (int)&dz_tty[20], dzxint, | |
97 | (struct device *)(DZADDR+020), NULL, NULL, (int)&dz_tty[21], dzxint, | |
98 | (struct device *)(DZADDR+020), NULL, NULL, (int)&dz_tty[22], dzxint, | |
99 | (struct device *)(DZADDR+020), NULL, NULL, (int)&dz_tty[23], dzxint, | |
100 | #endif | |
101 | }; | |
102 | char dz_timer; | |
103 | char dz_speeds[] = { | |
104 | 0, 020 , 021 , 022 , 023 , 024 , 0, 025, | |
105 | 026 , 027 , 030 , 032 , 034 , 036 , 0 , 0, | |
106 | }; | |
107 | ||
108 | /*ARGSUSED*/ | |
109 | dzopen(d, flag) | |
110 | { | |
111 | register struct tty *tp; | |
112 | register dev; | |
113 | extern dzscan(); | |
114 | ||
115 | dev = minor(d); | |
116 | if (dev >= dz_cnt) { | |
117 | u.u_error = ENXIO; | |
118 | return; | |
119 | } | |
120 | if (dz_timer == 0) { | |
121 | dz_timer++; | |
122 | timeout(dzscan, (caddr_t)0, 60); | |
123 | } | |
124 | tp = &dz_tty[dev]; | |
125 | tp->t_addr = (caddr_t)&dzpdma[dev]; | |
126 | tp->t_oproc = dzstart; | |
127 | tp->t_iproc = NULL; | |
128 | tp->t_state |= WOPEN; | |
129 | if ((tp->t_state & ISOPEN) == 0) { | |
130 | ttychars(tp); | |
131 | tp->t_ospeed = tp->t_ispeed = SSPEED; | |
132 | tp->t_flags = ODDP|EVENP|ECHO; | |
133 | /*tp->t_state |= HUPCLS;*/ | |
134 | dzparam(dev); | |
135 | } else if (tp->t_state&XCLUDE && u.u_uid != 0) { | |
136 | u.u_error = EBUSY; | |
137 | return; | |
138 | } | |
139 | dzmodem(dev, ON); | |
771d8988 | 140 | (void) spl5(); |
5074fa57 BJ |
141 | while ((tp->t_state & CARR_ON) == 0) { |
142 | tp->t_state |= WOPEN; | |
143 | sleep((caddr_t)&tp->t_rawq, TTIPRI); | |
144 | } | |
771d8988 | 145 | (void) spl0(); |
5074fa57 BJ |
146 | (*linesw[tp->t_line].l_open)(d, tp); |
147 | } | |
148 | ||
149 | dzclose(d) | |
150 | { | |
151 | register struct tty *tp; | |
152 | register dev; | |
153 | ||
154 | dev = minor(d); | |
155 | tp = &dz_tty[dev]; | |
156 | (*linesw[tp->t_line].l_close)(tp); | |
157 | if (tp->t_state & HUPCLS) | |
158 | dzmodem(dev, OFF); | |
159 | ttyclose(tp); | |
160 | } | |
161 | ||
162 | dzread(d) | |
163 | { | |
164 | register struct tty *tp; | |
165 | ||
166 | tp = &dz_tty[minor(d)]; | |
167 | (*linesw[tp->t_line].l_read)(tp); | |
168 | } | |
169 | ||
170 | dzwrite(d) | |
171 | { | |
172 | register struct tty *tp; | |
173 | ||
174 | tp = &dz_tty[minor(d)]; | |
175 | (*linesw[tp->t_line].l_write)(tp); | |
176 | } | |
177 | ||
9dca4f86 | 178 | /*ARGSUSED*/ |
5074fa57 BJ |
179 | dzrint(dev) |
180 | { | |
181 | register struct tty *tp; | |
182 | register int c; | |
183 | register struct device *dzaddr; | |
9dca4f86 | 184 | register struct tty *tp0; |
5c6adb3e | 185 | int s; |
5074fa57 | 186 | |
5c6adb3e | 187 | s = spl6(); /* see comment in clock.c */ |
9dca4f86 BJ |
188 | /* as long as we are here, service them all */ |
189 | for (dev = 0; dev < NDZ; dev += 8) { | |
190 | if ((dzact & (1<<(dev>>3))) == 0) | |
5074fa57 | 191 | continue; |
9dca4f86 BJ |
192 | dzaddr = dzpdma[dev].p_addr; |
193 | tp0 = &dz_tty[dev]; | |
194 | while ((c = dzaddr->dzrbuf) < 0) { /* char present */ | |
195 | tp = tp0 + ((c>>8)&07); | |
196 | if (tp >= &dz_tty[dz_cnt]) | |
5074fa57 | 197 | continue; |
9dca4f86 BJ |
198 | if ((tp->t_state & ISOPEN) == 0) { |
199 | wakeup((caddr_t)&tp->t_rawq); | |
200 | continue; | |
201 | } | |
202 | if (c&FRERROR) | |
203 | /* framing error = break */ | |
204 | if (tp->t_flags & RAW) | |
205 | c = 0; /* null for getty */ | |
206 | else | |
dc44829a BJ |
207 | #ifdef IIASA |
208 | continue; | |
209 | #else | |
210 | c = 0177; /* tun.t_intrc? */ | |
211 | #endif | |
9dca4f86 BJ |
212 | if (c&OVERRUN) |
213 | printf("o"); | |
214 | if (c&PERROR) | |
215 | /* parity error */ | |
216 | if (((tp->t_flags & (EVENP|ODDP)) == EVENP) | |
217 | || ((tp->t_flags & (EVENP|ODDP)) == ODDP)) | |
218 | continue; | |
5c6adb3e | 219 | if (tp->t_line == NETLDISC) { |
771d8988 | 220 | c &= 0177; |
dc44829a | 221 | BKINPUT(c, tp); |
771d8988 | 222 | } else |
771d8988 | 223 | (*linesw[tp->t_line].l_rint)(c, tp); |
9dca4f86 | 224 | } |
5074fa57 | 225 | } |
5c6adb3e | 226 | splx(s); |
5074fa57 BJ |
227 | } |
228 | ||
229 | /*ARGSUSED*/ | |
230 | dzioctl(dev, cmd, addr, flag) | |
231 | caddr_t addr; | |
232 | dev_t dev; | |
233 | { | |
234 | register struct tty *tp; | |
235 | ||
236 | tp = &dz_tty[minor(dev)]; | |
771d8988 BJ |
237 | cmd = (*linesw[tp->t_line].l_ioctl)(tp, cmd, addr); |
238 | if (cmd == 0) | |
239 | return; | |
5074fa57 BJ |
240 | if (ttioccomm(cmd, tp, addr, dev)) { |
241 | if (cmd==TIOCSETP || cmd==TIOCSETN) | |
242 | dzparam(minor(dev)); | |
dc44829a BJ |
243 | } else switch(cmd) { |
244 | case TIOCSBRK: | |
245 | ((struct device *)(tp->t_addr))->dzbrk |= 1 << (dev&07); | |
246 | break; | |
247 | case TIOCCBRK: | |
248 | ((struct device *)(tp->t_addr))->dzbrk &= ~(1 << (dev&07)); | |
249 | break; | |
250 | case TIOCSDTR: | |
251 | dzmodem(dev, ON); | |
252 | break; | |
253 | case TIOCCDTR: | |
254 | dzmodem(dev, OFF); | |
255 | break; | |
256 | default: | |
5074fa57 | 257 | u.u_error = ENOTTY; |
dc44829a | 258 | } |
5074fa57 BJ |
259 | } |
260 | ||
261 | dzparam(dev) | |
262 | { | |
263 | register struct tty *tp; | |
264 | register struct device *dzaddr; | |
265 | register short lpr; | |
266 | ||
267 | tp = &dz_tty[dev]; | |
268 | dzaddr = dzpdma[dev].p_addr; | |
269 | dzaddr->dzcsr = DZ_IEN; | |
9dca4f86 | 270 | dzact |= (1<<(dev>>3)); |
5074fa57 BJ |
271 | if (tp->t_ispeed == 0) { |
272 | dzmodem(dev, OFF); /* hang up line */ | |
273 | return; | |
274 | } | |
275 | lpr = (dz_speeds[tp->t_ispeed]<<8) | (dev & 07); | |
276 | if (tp->t_flags & RAW) | |
277 | lpr |= BITS8; | |
278 | else | |
279 | lpr |= (BITS7|PENABLE); | |
280 | if ((tp->t_flags & EVENP) == 0) | |
281 | lpr |= OPAR; | |
282 | if (tp->t_ispeed == 3) | |
283 | lpr |= TWOSB; /* 110 baud: 2 stop bits */ | |
284 | dzaddr->dzlpr = lpr; | |
285 | } | |
286 | ||
287 | dzxint(tp) | |
288 | register struct tty *tp; | |
289 | { | |
290 | register struct pdma *dp; | |
d3ebf5ee BJ |
291 | register s; |
292 | s = spl6(); /* block the clock */ | |
5074fa57 BJ |
293 | |
294 | dp = &dzpdma[tp-dz_tty]; | |
295 | tp->t_state &= ~BUSY; | |
296 | if (tp->t_state & FLUSH) | |
297 | tp->t_state &= ~FLUSH; | |
298 | else | |
299 | ndflush(&tp->t_outq, dp->p_end-tp->t_outq.c_cf); | |
300 | if (tp->t_line) | |
301 | (*linesw[tp->t_line].l_start)(tp); | |
302 | else | |
303 | dzstart(tp); | |
304 | if (tp->t_outq.c_cc == 0 || (tp->t_state&BUSY)==0) | |
305 | dp->p_addr->dztcr &= ~(1 << ((tp-dz_tty) % 8)); | |
d3ebf5ee | 306 | splx(s); |
5074fa57 BJ |
307 | } |
308 | ||
309 | dzstart(tp) | |
310 | register struct tty *tp; | |
311 | { | |
312 | register struct pdma *dp; | |
313 | register struct device *dzaddr; | |
314 | register cc; | |
315 | int sps; | |
5074fa57 BJ |
316 | |
317 | dp = &dzpdma[tp-dz_tty]; | |
318 | dzaddr = dp->p_addr; | |
319 | sps = spl5(); | |
320 | if (tp->t_state & (TIMEOUT|BUSY|TTSTOP)) | |
321 | goto out; | |
322 | if (tp->t_outq.c_cc <= TTLOWAT && tp->t_state&ASLEEP) { | |
323 | tp->t_state &= ~ASLEEP; | |
324 | if (tp->t_chan) | |
325 | mcstart(tp->t_chan, (caddr_t)&tp->t_outq); | |
326 | else | |
327 | wakeup((caddr_t)&tp->t_outq); | |
328 | } | |
329 | if (tp->t_outq.c_cc == 0) | |
330 | goto out; | |
331 | if (tp->t_flags&RAW) | |
332 | cc = ndqb(&tp->t_outq, 0); | |
333 | else { | |
334 | cc = ndqb(&tp->t_outq, 0200); | |
335 | if (cc == 0) { | |
336 | cc = getc(&tp->t_outq); | |
337 | timeout(ttrstrt, (caddr_t)tp, (cc&0177) + 6); | |
338 | tp->t_state |= TIMEOUT; | |
339 | goto out; | |
340 | } | |
341 | } | |
342 | tp->t_state |= BUSY; | |
343 | dp->p_end = dp->p_mem = tp->t_outq.c_cf; | |
344 | dp->p_end += cc; | |
345 | dzaddr->dztcr |= 1 << ((tp-dz_tty) % 8); | |
346 | out: | |
347 | splx(sps); | |
348 | } | |
349 | ||
350 | /* | |
351 | * Stop output on a line. | |
352 | * Assume call is made at spl6. | |
353 | */ | |
354 | /*ARGSUSED*/ | |
355 | dzstop(tp, flag) | |
356 | register struct tty *tp; | |
357 | { | |
358 | register struct pdma *dp; | |
359 | register int s; | |
360 | ||
361 | dp = &dzpdma[tp-dz_tty]; | |
362 | s = spl6(); | |
363 | if (tp->t_state & BUSY) { | |
364 | dp->p_end = dp->p_mem; | |
365 | if ((tp->t_state&TTSTOP)==0) { | |
366 | tp->t_state |= FLUSH; | |
367 | } | |
368 | } | |
369 | splx(s); | |
370 | } | |
371 | ||
372 | dzmodem(dev, flag) | |
373 | register int dev; | |
374 | { | |
375 | register struct device *dzaddr; | |
376 | register char bit; | |
377 | ||
378 | dzaddr = dzpdma[dev].p_addr; | |
379 | bit = 1<<(dev&07); | |
380 | if (flag == OFF) | |
381 | dzaddr->dzdtr &= ~bit; | |
382 | else | |
383 | dzaddr->dzdtr |= bit; | |
384 | } | |
385 | ||
386 | dzscan() | |
387 | { | |
388 | register i; | |
389 | register struct device *dzaddr; | |
390 | register bit; | |
391 | register struct tty *tp; | |
392 | ||
393 | for (i = 0; i < dz_cnt ; i++) { | |
394 | dzaddr = dzpdma[i].p_addr; | |
395 | tp = &dz_tty[i]; | |
396 | bit = 1<<(i&07); | |
397 | if (dzaddr->dzmsr & bit) { | |
398 | /* carrier present */ | |
399 | if ((tp->t_state & CARR_ON) == 0) { | |
400 | wakeup((caddr_t)&tp->t_rawq); | |
401 | tp->t_state |= CARR_ON; | |
402 | } | |
403 | } else { | |
404 | if ((tp->t_state & CARR_ON)) { | |
405 | /* carrier lost */ | |
dc44829a BJ |
406 | if (tp->t_state&ISOPEN && |
407 | (tp->t_local&LNOHANG) == 0) { | |
408 | gsignal(tp->t_pgrp, SIGHUP); | |
409 | dzaddr->dzdtr &= ~bit; | |
410 | flushtty(tp); | |
411 | } | |
412 | tp->t_state &= ~CARR_ON; | |
5074fa57 | 413 | } |
5074fa57 BJ |
414 | } |
415 | } | |
416 | timeout(dzscan, (caddr_t)0, 2*HZ); | |
417 | } | |
9dca4f86 BJ |
418 | |
419 | dztimer() | |
420 | { | |
421 | ||
422 | dzrint(0); | |
423 | } |