Commit | Line | Data |
---|---|---|
7e00c42b | 1 | /* dh.c 4.16 81/02/17 */ |
a18f326f | 2 | |
66b4fb09 | 3 | #include "dh.h" |
a5cc519e | 4 | #if NDH11 > 0 |
88d5b764 | 5 | #define DELAY(i) { register int j = i; while (--j > 0); } |
a18f326f | 6 | /* |
a5cc519e | 7 | * DH-11 driver |
a18f326f | 8 | */ |
a18f326f BJ |
9 | #include "../h/param.h" |
10 | #include "../h/conf.h" | |
11 | #include "../h/dir.h" | |
12 | #include "../h/user.h" | |
13 | #include "../h/tty.h" | |
14 | #include "../h/map.h" | |
15 | #include "../h/pte.h" | |
3f3a34c3 | 16 | #include "../h/buf.h" |
a18f326f | 17 | #include "../h/uba.h" |
038bbe6b | 18 | #include "../h/bk.h" |
a5cc519e | 19 | #include "../h/clist.h" |
1b05b375 | 20 | #include "../h/mx.h" |
7e00c42b | 21 | #include "../h/file.h" |
a18f326f | 22 | |
7e00c42b | 23 | #define UBACVT(x, uban) (cbase[uban] + ((x)-(char *)cfree)) |
a18f326f | 24 | |
7e00c42b BJ |
25 | /* |
26 | * Definition of the controller for the auto-configuration program. | |
27 | */ | |
3f3a34c3 BJ |
28 | int dhcntrlr(), dhslave(), dhrint(), dhxint(); |
29 | struct uba_dinfo *dhinfo[NDH11]; | |
30 | u_short dhstd[] = { 0 }; | |
3f3a34c3 | 31 | struct uba_driver dhdriver = |
88d5b764 | 32 | { dhcntrlr, dhslave, 0, 0, dhstd, "dh", dhinfo }; |
3f3a34c3 BJ |
33 | |
34 | struct tty dh11[NDH11*16]; | |
0e239190 | 35 | int dhact; |
3f3a34c3 | 36 | int ndh11 = NDH11*16; |
a18f326f BJ |
37 | int dhstart(); |
38 | int ttrstrt(); | |
5aa9d5ea RE |
39 | int dh_ubinfo[MAXNUBA]; |
40 | int cbase[MAXNUBA]; | |
a18f326f | 41 | |
7e00c42b | 42 | /* Bits in dhlpr */ |
a18f326f BJ |
43 | #define BITS6 01 |
44 | #define BITS7 02 | |
45 | #define BITS8 03 | |
46 | #define TWOSB 04 | |
47 | #define PENABLE 020 | |
48 | /* DEC manuals incorrectly say this bit causes generation of even parity. */ | |
49 | #define OPAR 040 | |
50 | #define HDUPLX 040000 | |
51 | ||
88d5b764 BJ |
52 | /* Bits in dhcsr */ |
53 | #define DH_TI 0100000 /* transmit interrupt */ | |
54 | #define DH_SI 0040000 /* storage interrupt */ | |
55 | #define DH_TIE 0020000 /* transmit interrupt enable */ | |
56 | #define DH_SIE 0010000 /* storage interrupt enable */ | |
57 | #define DH_MC 0004000 /* master clear */ | |
58 | #define DH_NXM 0002000 /* non-existant memory */ | |
59 | #define DH_MM 0001000 /* maintenance mode */ | |
60 | #define DH_CNI 0000400 /* clear non-existant memory interrupt */ | |
61 | #define DH_RI 0000200 /* receiver interrupt */ | |
62 | #define DH_RIE 0000100 /* receiver interrupt enable */ | |
63 | ||
64 | #define DH_IE (DH_TIE|DH_SIE|DH_RIE) | |
65 | ||
66 | /* Bits in dhrcr */ | |
67 | #define DH_PE 010000 /* parity error */ | |
68 | #define DH_FE 020000 /* framing error */ | |
69 | #define DH_DO 040000 /* data overrun */ | |
a18f326f | 70 | |
a18f326f BJ |
71 | /* |
72 | * DM control bits | |
73 | */ | |
88d5b764 BJ |
74 | #define DM_ON 03 /* CD lead + line enable */ |
75 | #define DM_OFF 01 /* line enable */ | |
76 | #define DM_DTR 02 /* data terminal ready */ | |
77 | #define DM_RQS 04 /* request to send */ | |
a18f326f | 78 | |
7e00c42b | 79 | /* Software copy of last dhbar */ |
3f3a34c3 | 80 | short dhsar[NDH11]; |
a18f326f BJ |
81 | |
82 | struct device | |
83 | { | |
84 | union { | |
88d5b764 BJ |
85 | short dhcsr; /* control-status register */ |
86 | char dhcsrl; /* low byte for line select */ | |
a18f326f | 87 | } un; |
88d5b764 BJ |
88 | short dhrcr; /* receive character register */ |
89 | short dhlpr; /* line parameter register */ | |
90 | u_short dhcar; /* current address register */ | |
91 | short dhbcr; /* byte count register */ | |
92 | u_short dhbar; /* buffer active register */ | |
93 | short dhbreak; /* break control register */ | |
94 | short dhsilo; /* silo status register */ | |
a18f326f BJ |
95 | }; |
96 | ||
88d5b764 BJ |
97 | /* |
98 | * Routine for configuration to force a dh to interrupt. | |
99 | * Set to transmit at 9600 baud, and cause a transmitter interrupt. | |
100 | */ | |
7e00c42b | 101 | /*ARGSUSED*/ |
3f3a34c3 BJ |
102 | dhcntrlr(ui, reg) |
103 | struct uba_dinfo *ui; | |
104 | caddr_t reg; | |
105 | { | |
7e00c42b | 106 | register int br, cvec; /* these are ``value-result'' */ |
88d5b764 | 107 | register struct device *dhaddr = (struct device *)reg; |
5aa9d5ea RE |
108 | int i; |
109 | ||
88d5b764 BJ |
110 | dhaddr->un.dhcsr = DH_TIE; |
111 | DELAY(5); | |
112 | dhaddr->dhlpr = (B9600 << 10) | (B9600 << 6) | BITS7|PENABLE; | |
5aa9d5ea | 113 | dhaddr->dhbcr = -1; |
5aa9d5ea | 114 | dhaddr->dhcar = 0; |
88d5b764 BJ |
115 | dhaddr->dhbar = 1; |
116 | DELAY(100000); /* wait 1/10'th of a sec for interrupt */ | |
5aa9d5ea | 117 | dhaddr->un.dhcsr = 0; |
88d5b764 BJ |
118 | if (cvec && cvec != 0x200) |
119 | cvec -= 4; /* transmit -> receive */ | |
120 | return (1); | |
3f3a34c3 BJ |
121 | } |
122 | ||
88d5b764 BJ |
123 | /* |
124 | * Routine called to init slave tables. | |
125 | */ | |
3f3a34c3 BJ |
126 | dhslave(ui, reg, slaveno) |
127 | struct uba_dinfo *ui; | |
128 | caddr_t reg; | |
129 | { | |
130 | ||
88d5b764 | 131 | /* no tables to set up */ |
3f3a34c3 BJ |
132 | } |
133 | ||
a18f326f | 134 | /* |
7e00c42b BJ |
135 | * Open a DH11 line, mapping the clist onto the uba if this |
136 | * is the first dh on this uba. Turn on this dh if this is | |
137 | * the first use of it. Also do a dmopen to wait for carrier. | |
a18f326f BJ |
138 | */ |
139 | /*ARGSUSED*/ | |
140 | dhopen(dev, flag) | |
3f3a34c3 | 141 | dev_t dev; |
a18f326f BJ |
142 | { |
143 | register struct tty *tp; | |
3f3a34c3 | 144 | register int unit, dh; |
a18f326f | 145 | register struct device *addr; |
3f3a34c3 | 146 | register struct uba_dinfo *ui; |
a18f326f BJ |
147 | int s; |
148 | ||
3f3a34c3 BJ |
149 | unit = minor(dev); |
150 | dh = unit >> 4; | |
7e00c42b | 151 | if (unit >= NDH11*16 || (ui = dhinfo[dh])== 0 || ui->ui_alive == 0) { |
a18f326f BJ |
152 | u.u_error = ENXIO; |
153 | return; | |
154 | } | |
3f3a34c3 | 155 | tp = &dh11[unit]; |
7e00c42b BJ |
156 | if (tp->t_state&XCLUDE && u.u_uid!=0) { |
157 | u.u_error = EBUSY; | |
158 | return; | |
159 | } | |
3f3a34c3 | 160 | addr = (struct device *)ui->ui_addr; |
a18f326f BJ |
161 | tp->t_addr = (caddr_t)addr; |
162 | tp->t_oproc = dhstart; | |
163 | tp->t_iproc = NULL; | |
164 | tp->t_state |= WOPEN; | |
7e00c42b BJ |
165 | /* |
166 | * While setting up state for this uba and this dh, | |
167 | * block uba resets which can clear the state. | |
168 | */ | |
169 | s = spl5(); | |
5aa9d5ea | 170 | if (dh_ubinfo[ui->ui_ubanum] == 0) { |
d319892b | 171 | /* 512+ is a kludge to try to get around a hardware problem */ |
3f3a34c3 | 172 | dh_ubinfo[ui->ui_ubanum] = |
5aa9d5ea | 173 | uballoc(ui->ui_ubanum, (caddr_t)cfree, |
3f3a34c3 | 174 | 512+NCLIST*sizeof(struct cblock), 0); |
88d5b764 BJ |
175 | cbase[ui->ui_ubanum] = dh_ubinfo[ui->ui_ubanum]&0x3ffff; |
176 | } | |
177 | if ((dhact&(1<<dh)) == 0) { | |
178 | addr->un.dhcsr |= DH_IE; | |
7e00c42b | 179 | DELAY(5); |
88d5b764 | 180 | dhact |= (1<<dh); |
7e00c42b | 181 | addr->dhsilo = 16; |
a18f326f BJ |
182 | } |
183 | splx(s); | |
7e00c42b BJ |
184 | /* |
185 | * If this is first open, initialze tty state to default. | |
186 | */ | |
a18f326f BJ |
187 | if ((tp->t_state&ISOPEN) == 0) { |
188 | ttychars(tp); | |
87f51a66 | 189 | if (tp->t_ispeed == 0) { |
88d5b764 BJ |
190 | tp->t_ispeed = B300; |
191 | tp->t_ospeed = B300; | |
87f51a66 BJ |
192 | tp->t_flags = ODDP|EVENP|ECHO; |
193 | } | |
3f3a34c3 | 194 | dhparam(unit); |
a18f326f | 195 | } |
7e00c42b BJ |
196 | /* |
197 | * Wait for carrier, then process line discipline specific open. | |
198 | */ | |
a18f326f | 199 | dmopen(dev); |
3f3a34c3 | 200 | (*linesw[tp->t_line].l_open)(dev, tp); |
a18f326f BJ |
201 | } |
202 | ||
203 | /* | |
7e00c42b | 204 | * Close a DH11 line, turning off the DM11. |
a18f326f BJ |
205 | */ |
206 | /*ARGSUSED*/ | |
207 | dhclose(dev, flag) | |
3f3a34c3 BJ |
208 | dev_t dev; |
209 | int flag; | |
a18f326f BJ |
210 | { |
211 | register struct tty *tp; | |
3f3a34c3 | 212 | register unit; |
a18f326f | 213 | |
3f3a34c3 BJ |
214 | unit = minor(dev); |
215 | tp = &dh11[unit]; | |
a18f326f | 216 | (*linesw[tp->t_line].l_close)(tp); |
3f3a34c3 | 217 | ((struct device *)(tp->t_addr))->dhbreak &= ~(1<<(unit&017)); |
a18f326f | 218 | if (tp->t_state&HUPCLS || (tp->t_state&ISOPEN)==0) |
88d5b764 | 219 | dmctl(unit, DM_OFF, DMSET); |
a18f326f BJ |
220 | ttyclose(tp); |
221 | } | |
222 | ||
a18f326f | 223 | dhread(dev) |
3f3a34c3 | 224 | dev_t dev; |
a18f326f | 225 | { |
3f3a34c3 | 226 | register struct tty *tp; |
a18f326f | 227 | |
3f3a34c3 | 228 | tp = &dh11[minor(dev)]; |
a18f326f BJ |
229 | (*linesw[tp->t_line].l_read)(tp); |
230 | } | |
231 | ||
a18f326f | 232 | dhwrite(dev) |
3f3a34c3 | 233 | dev_t dev; |
a18f326f | 234 | { |
3f3a34c3 | 235 | register struct tty *tp; |
a18f326f | 236 | |
3f3a34c3 | 237 | tp = &dh11[minor(dev)]; |
a18f326f BJ |
238 | (*linesw[tp->t_line].l_write)(tp); |
239 | } | |
240 | ||
241 | /* | |
242 | * DH11 receiver interrupt. | |
243 | */ | |
3f3a34c3 BJ |
244 | dhrint(dh) |
245 | int dh; | |
a18f326f BJ |
246 | { |
247 | register struct tty *tp; | |
3f3a34c3 | 248 | register c; |
a18f326f | 249 | register struct device *addr; |
0e239190 | 250 | register struct tty *tp0; |
3f3a34c3 | 251 | register struct uba_dinfo *ui; |
5c6adb3e | 252 | int s; |
a18f326f | 253 | |
3f3a34c3 BJ |
254 | ui = dhinfo[dh]; |
255 | addr = (struct device *)ui->ui_addr; | |
7e00c42b BJ |
256 | tp0 = &dh11[dh<<4]; |
257 | /* | |
258 | * Loop fetching characters from the silo for this | |
259 | * dh until there are no more in the silo. | |
260 | */ | |
261 | while ((c = addr->dhrcr) < 0) { | |
262 | tp = tp0 + ((c>>8)&0xf); | |
263 | if ((tp->t_state&ISOPEN)==0) { | |
a18f326f BJ |
264 | wakeup((caddr_t)tp); |
265 | continue; | |
266 | } | |
7e00c42b | 267 | if (c & DH_PE) |
a18f326f BJ |
268 | if ((tp->t_flags&(EVENP|ODDP))==EVENP |
269 | || (tp->t_flags&(EVENP|ODDP))==ODDP ) | |
270 | continue; | |
7e00c42b | 271 | if (c & DH_DO) |
a18f326f | 272 | printf("O"); |
7e00c42b BJ |
273 | if (c & DH_FE) |
274 | /* | |
275 | * At framing error (break) generate | |
276 | * a null (in raw mode, for getty), or a | |
277 | * interrupt (in cooked/cbreak mode). | |
278 | */ | |
a18f326f | 279 | if (tp->t_flags&RAW) |
7e00c42b | 280 | c = 0; |
a18f326f | 281 | else |
1c17c385 | 282 | c = tun.t_intrc; |
5c6adb3e | 283 | if (tp->t_line == NETLDISC) { |
0e239190 | 284 | c &= 0177; |
87f51a66 | 285 | BKINPUT(c, tp); |
0e239190 | 286 | } else |
7e00c42b | 287 | (*linesw[tp->t_line].l_rint)(c, tp); |
a18f326f BJ |
288 | } |
289 | } | |
290 | ||
291 | /* | |
7e00c42b | 292 | * Ioctl for DH11. |
a18f326f BJ |
293 | */ |
294 | /*ARGSUSED*/ | |
295 | dhioctl(dev, cmd, addr, flag) | |
3f3a34c3 | 296 | caddr_t addr; |
a18f326f BJ |
297 | { |
298 | register struct tty *tp; | |
3f3a34c3 | 299 | register unit = minor(dev); |
a18f326f | 300 | |
3f3a34c3 | 301 | tp = &dh11[unit]; |
038bbe6b | 302 | cmd = (*linesw[tp->t_line].l_ioctl)(tp, cmd, addr); |
7e00c42b | 303 | if (cmd == 0) |
038bbe6b | 304 | return; |
f4e18828 | 305 | if (ttioctl(tp, cmd, addr, flag)) { |
7e00c42b | 306 | if (cmd==TIOCSETP || cmd==TIOCSETN) |
3f3a34c3 | 307 | dhparam(unit); |
87f51a66 BJ |
308 | } else switch(cmd) { |
309 | case TIOCSBRK: | |
3f3a34c3 | 310 | ((struct device *)(tp->t_addr))->dhbreak |= 1<<(unit&017); |
87f51a66 BJ |
311 | break; |
312 | case TIOCCBRK: | |
3f3a34c3 | 313 | ((struct device *)(tp->t_addr))->dhbreak &= ~(1<<(unit&017)); |
87f51a66 BJ |
314 | break; |
315 | case TIOCSDTR: | |
88d5b764 | 316 | dmctl(unit, DM_DTR|DM_RQS, DMBIS); |
87f51a66 BJ |
317 | break; |
318 | case TIOCCDTR: | |
88d5b764 | 319 | dmctl(unit, DM_DTR|DM_RQS, DMBIC); |
87f51a66 BJ |
320 | break; |
321 | default: | |
a18f326f | 322 | u.u_error = ENOTTY; |
87f51a66 | 323 | } |
a18f326f BJ |
324 | } |
325 | ||
326 | /* | |
327 | * Set parameters from open or stty into the DH hardware | |
328 | * registers. | |
329 | */ | |
3f3a34c3 BJ |
330 | dhparam(unit) |
331 | register int unit; | |
a18f326f BJ |
332 | { |
333 | register struct tty *tp; | |
334 | register struct device *addr; | |
3f3a34c3 | 335 | register int lpar; |
0072a3c2 | 336 | int s; |
a18f326f | 337 | |
3f3a34c3 | 338 | tp = &dh11[unit]; |
a18f326f | 339 | addr = (struct device *)tp->t_addr; |
7e00c42b BJ |
340 | /* |
341 | * Block interrupts so parameters will be set | |
342 | * before the line interrupts. | |
343 | */ | |
0072a3c2 | 344 | s = spl5(); |
7e00c42b | 345 | addr->un.dhcsrl = (unit&0xf) | DH_IE; |
a18f326f BJ |
346 | if ((tp->t_ispeed)==0) { |
347 | tp->t_state |= HUPCLS; | |
88d5b764 | 348 | dmctl(unit, DM_OFF, DMSET); |
a18f326f BJ |
349 | return; |
350 | } | |
3f3a34c3 | 351 | lpar = ((tp->t_ospeed)<<10) | ((tp->t_ispeed)<<6); |
7e00c42b | 352 | if ((tp->t_ispeed) == B134) |
3f3a34c3 | 353 | lpar |= BITS6|PENABLE|HDUPLX; |
131b2e17 | 354 | else if ((tp->t_flags&RAW) || (tp->t_local&LLITOUT)) |
3f3a34c3 | 355 | lpar |= BITS8; |
a18f326f | 356 | else |
3f3a34c3 | 357 | lpar |= BITS7|PENABLE; |
a18f326f | 358 | if ((tp->t_flags&EVENP) == 0) |
3f3a34c3 | 359 | lpar |= OPAR; |
7e00c42b | 360 | if ((tp->t_ospeed) == B110) |
3f3a34c3 BJ |
361 | lpar |= TWOSB; |
362 | addr->dhlpr = lpar; | |
0072a3c2 | 363 | splx(s); |
a18f326f BJ |
364 | } |
365 | ||
366 | /* | |
367 | * DH11 transmitter interrupt. | |
368 | * Restart each line which used to be active but has | |
369 | * terminated transmission since the last interrupt. | |
370 | */ | |
3f3a34c3 BJ |
371 | dhxint(dh) |
372 | int dh; | |
a18f326f BJ |
373 | { |
374 | register struct tty *tp; | |
375 | register struct device *addr; | |
a18f326f | 376 | short ttybit, bar, *sbar; |
3f3a34c3 | 377 | register struct uba_dinfo *ui; |
7e00c42b | 378 | register int unit; |
d3ebf5ee | 379 | int s; |
7e00c42b | 380 | u_short cnt; |
a18f326f | 381 | |
3f3a34c3 BJ |
382 | ui = dhinfo[dh]; |
383 | addr = (struct device *)ui->ui_addr; | |
88d5b764 | 384 | if (addr->un.dhcsr & DH_NXM) { |
7e00c42b | 385 | DELAY(5); |
88d5b764 | 386 | addr->un.dhcsr |= DH_CNI; |
7e00c42b | 387 | printf("dh%d NXM\n", dh); |
b4ec79ea | 388 | } |
3f3a34c3 | 389 | sbar = &dhsar[dh]; |
a18f326f | 390 | bar = *sbar & ~addr->dhbar; |
3f3a34c3 | 391 | unit = dh * 16; ttybit = 1; |
7e00c42b BJ |
392 | addr->un.dhcsr &= (short)~DH_TI; |
393 | for (; bar; unit++, ttybit <<= 1) { | |
394 | if (bar & ttybit) { | |
a18f326f BJ |
395 | *sbar &= ~ttybit; |
396 | bar &= ~ttybit; | |
3f3a34c3 | 397 | tp = &dh11[unit]; |
038bbe6b BJ |
398 | tp->t_state &= ~BUSY; |
399 | if (tp->t_state&FLUSH) | |
400 | tp->t_state &= ~FLUSH; | |
401 | else { | |
88d5b764 | 402 | addr->un.dhcsrl = (unit&017)|DH_IE; |
7e00c42b BJ |
403 | DELAY(5); |
404 | /* | |
405 | * Do arithmetic in a short to make up | |
406 | * for lost 16&17 bits. | |
407 | */ | |
408 | cnt = addr->dhcar - | |
409 | UBACVT(tp->t_outq.c_cf, ui->ui_ubanum); | |
410 | ndflush(&tp->t_outq, cnt); | |
a18f326f | 411 | } |
038bbe6b BJ |
412 | if (tp->t_line) |
413 | (*linesw[tp->t_line].l_start)(tp); | |
414 | else | |
415 | dhstart(tp); | |
a18f326f BJ |
416 | } |
417 | } | |
418 | } | |
419 | ||
420 | /* | |
421 | * Start (restart) transmission on the given DH11 line. | |
422 | */ | |
423 | dhstart(tp) | |
3f3a34c3 | 424 | register struct tty *tp; |
a18f326f BJ |
425 | { |
426 | register struct device *addr; | |
7e00c42b | 427 | register int car, dh, unit, nch; |
3f3a34c3 | 428 | int s; |
a18f326f | 429 | |
3f3a34c3 BJ |
430 | unit = minor(tp->t_dev); |
431 | dh = unit >> 4; | |
7e00c42b | 432 | unit &= 0xf; |
a18f326f | 433 | addr = (struct device *)tp->t_addr; |
7e00c42b BJ |
434 | |
435 | /* | |
436 | * Must hold interrupts in following code to prevent | |
437 | * state of the tp from changing. | |
438 | */ | |
439 | s = spl5(); | |
440 | /* | |
441 | * If it's currently active, or delaying, no need to do anything. | |
442 | */ | |
a18f326f BJ |
443 | if (tp->t_state&(TIMEOUT|BUSY|TTSTOP)) |
444 | goto out; | |
7e00c42b BJ |
445 | /* |
446 | * If there are sleepers, and output has drained below low | |
447 | * water mark, wake up the sleepers. | |
448 | */ | |
3f3a34c3 | 449 | if ((tp->t_state&ASLEEP) && tp->t_outq.c_cc<=TTLOWAT(tp)) { |
a18f326f BJ |
450 | tp->t_state &= ~ASLEEP; |
451 | if (tp->t_chan) | |
87f51a66 BJ |
452 | mcstart(tp->t_chan, (caddr_t)&tp->t_outq); |
453 | else | |
a18f326f BJ |
454 | wakeup((caddr_t)&tp->t_outq); |
455 | } | |
7e00c42b BJ |
456 | /* |
457 | * Now restart transmission unless the output queue is | |
458 | * empty. | |
459 | */ | |
a18f326f BJ |
460 | if (tp->t_outq.c_cc == 0) |
461 | goto out; | |
3f3a34c3 | 462 | if (tp->t_flags & RAW) |
a18f326f | 463 | nch = ndqb(&tp->t_outq, 0); |
3f3a34c3 | 464 | else { |
a18f326f | 465 | nch = ndqb(&tp->t_outq, 0200); |
7e00c42b BJ |
466 | /* |
467 | * If first thing on queue is a delay process it. | |
468 | */ | |
a18f326f BJ |
469 | if (nch == 0) { |
470 | nch = getc(&tp->t_outq); | |
7e00c42b | 471 | timeout(ttrstrt, (caddr_t)tp, (nch&0x7f)+6); |
a18f326f BJ |
472 | tp->t_state |= TIMEOUT; |
473 | goto out; | |
474 | } | |
475 | } | |
7e00c42b BJ |
476 | /* |
477 | * If characters to transmit, restart transmission. | |
478 | */ | |
a18f326f | 479 | if (nch) { |
7e00c42b BJ |
480 | car = UBACVT(tp->t_outq.c_cf, dhinfo[dh]->ui_ubanum); |
481 | addr->un.dhcsrl = unit|((car>>12)&0x30)|DH_IE; | |
482 | DELAY(5); | |
483 | unit = 1 << unit; | |
484 | dhsar[dh] |= unit; | |
485 | addr->dhcar = car; | |
a18f326f | 486 | addr->dhbcr = -nch; |
7e00c42b | 487 | addr->dhbar |= unit; |
a18f326f BJ |
488 | tp->t_state |= BUSY; |
489 | } | |
3f3a34c3 | 490 | out: |
a18f326f BJ |
491 | splx(s); |
492 | } | |
493 | ||
a18f326f | 494 | /* |
7e00c42b | 495 | * Stop output on a line, e.g. for ^S/^Q or output flush. |
a18f326f BJ |
496 | */ |
497 | /*ARGSUSED*/ | |
498 | dhstop(tp, flag) | |
7e00c42b | 499 | register struct tty *tp; |
a18f326f | 500 | { |
038bbe6b | 501 | register struct device *addr; |
3f3a34c3 | 502 | register int unit, s; |
a18f326f | 503 | |
038bbe6b | 504 | addr = (struct device *)tp->t_addr; |
7e00c42b BJ |
505 | /* |
506 | * Block input/output interrupts while messing with state. | |
507 | */ | |
508 | s = spl5(); | |
038bbe6b | 509 | if (tp->t_state & BUSY) { |
7e00c42b BJ |
510 | /* |
511 | * Device is transmitting; stop output | |
512 | * by selecting the line and setting the byte | |
513 | * count to -1. We will clean up later | |
514 | * by examining the address where the dh stopped. | |
515 | */ | |
3f3a34c3 | 516 | unit = minor(tp->t_dev); |
88d5b764 | 517 | addr->un.dhcsrl = (unit&017) | DH_IE; |
7e00c42b | 518 | DELAY(5); |
a18f326f BJ |
519 | if ((tp->t_state&TTSTOP)==0) |
520 | tp->t_state |= FLUSH; | |
038bbe6b BJ |
521 | addr->dhbcr = -1; |
522 | } | |
a18f326f BJ |
523 | splx(s); |
524 | } | |
525 | ||
5c30d566 BJ |
526 | /* |
527 | * Reset state of driver if UBA reset was necessary. | |
528 | * Reset the csrl and lpr registers on open lines, and | |
529 | * restart transmitters. | |
530 | */ | |
3f3a34c3 | 531 | dhreset(uban) |
7e00c42b | 532 | int uban; |
5c30d566 | 533 | { |
3f3a34c3 | 534 | register int dh, unit; |
5c30d566 | 535 | register struct tty *tp; |
3f3a34c3 | 536 | register struct uba_dinfo *ui; |
5aa9d5ea | 537 | int i; |
5c30d566 | 538 | |
5aa9d5ea RE |
539 | if (dh_ubinfo[uban] == 0) |
540 | return; | |
5c30d566 | 541 | printf(" dh"); |
5aa9d5ea RE |
542 | ubarelse(uban, &dh_ubinfo[uban]); |
543 | dh_ubinfo[uban] = uballoc(uban, (caddr_t)cfree, | |
544 | 512+NCLIST*sizeof (struct cblock), 0); | |
545 | cbase[uban] = dh_ubinfo[uban]&0x3ffff; | |
3f3a34c3 | 546 | dh = 0; |
5aa9d5ea RE |
547 | for (dh = 0; dh < NDH11; dh++) { |
548 | ui = dhinfo[dh]; | |
549 | if (ui == 0 || ui->ui_alive == 0 || ui->ui_ubanum != uban) | |
550 | continue; | |
88d5b764 | 551 | ((struct device *)ui->ui_addr)->un.dhcsr |= DH_IE; |
7e00c42b | 552 | DELAY(5); |
88d5b764 | 553 | ((struct device *)ui->ui_addr)->dhsilo = 16; |
5aa9d5ea RE |
554 | unit = dh * 16; |
555 | for (i = 0; i < 16; i++) { | |
556 | tp = &dh11[unit]; | |
557 | if (tp->t_state & (ISOPEN|WOPEN)) { | |
558 | dhparam(unit); | |
88d5b764 | 559 | dmctl(unit, DM_ON, DMSET); |
5aa9d5ea RE |
560 | tp->t_state &= ~BUSY; |
561 | dhstart(tp); | |
562 | } | |
563 | unit++; | |
0072a3c2 BJ |
564 | } |
565 | } | |
566 | dhtimer(); | |
5c30d566 | 567 | } |
3f3a34c3 | 568 | |
7e00c42b BJ |
569 | /* |
570 | * At software clock interrupt time or after a UNIBUS reset | |
571 | * empty all the dh silos. | |
572 | */ | |
88d5b764 BJ |
573 | dhtimer() |
574 | { | |
575 | register int dh; | |
576 | ||
577 | for (dh = 0; dh < NDH11; dh++) | |
578 | dhrint(dh); | |
579 | } | |
580 | ||
7e00c42b BJ |
581 | /* |
582 | * DM-11 driver. | |
583 | */ | |
584 | ||
585 | /* | |
586 | * Definition of the controller for the auto-configuration program. | |
587 | */ | |
588 | int dmcntrlr(), dmslave(), dmintr(); | |
589 | struct uba_dinfo *dminfo[NDH11]; | |
590 | u_short dmstd[] = { 0 }; | |
591 | struct uba_driver dmdriver = | |
592 | { dmcntrlr, dmslave, 0, 0, dmstd, "dm", dminfo }; | |
593 | ||
594 | /* hardware bits */ | |
595 | #define DM_CARRTRANS 040000 /* carrier transition */ | |
596 | #define DM_CLSCAN 004000 /* clear scan */ | |
597 | #define DM_DONE 000200 | |
598 | #define DM_CARRON 000100 /* carrier on */ | |
599 | #define DM_SCENABLE 000040 /* scan enable */ | |
600 | #define DM_SCBUSY 000020 /* scan busy */ | |
601 | ||
602 | struct dmdevice | |
603 | { | |
604 | short dmcsr; | |
605 | short dmlstat; | |
606 | short dmpad1[2]; | |
607 | }; | |
608 | ||
609 | dmcntrlr(um, addr) | |
610 | struct uba_minfo *um; | |
611 | caddr_t addr; | |
612 | { | |
613 | ||
614 | } | |
615 | ||
616 | dmslave() | |
617 | { | |
618 | ||
619 | } | |
620 | ||
621 | /* | |
622 | * Turn on the line associated with the dh device dev. | |
623 | */ | |
624 | dmopen(dev) | |
625 | dev_t dev; | |
626 | { | |
627 | register struct tty *tp; | |
628 | register struct dmdevice *addr; | |
629 | register struct uba_dinfo *ui; | |
630 | register int unit; | |
631 | register int dm; | |
632 | ||
633 | unit = minor(dev); | |
634 | dm = unit >> 8; | |
635 | tp = &dh11[unit]; | |
636 | if (dm >= NDH11 || (ui = dminfo[dm]) == 0 || ui->ui_alive == 0) { | |
637 | tp->t_state |= CARR_ON; | |
638 | return; | |
639 | } | |
640 | addr = (struct dmdevice *)ui->ui_addr; | |
641 | spl5(); | |
642 | addr->dmcsr &= ~DM_SCENABLE; | |
643 | while (addr->dmcsr & DM_SCBUSY) | |
644 | ; | |
645 | addr->dmcsr = unit & 0xf; | |
646 | addr->dmlstat = DM_ON; | |
647 | if (addr->dmlstat&DM_CARRON) | |
648 | tp->t_state |= CARR_ON; | |
649 | addr->dmcsr = DH_IE|DM_SCENABLE; | |
650 | while ((tp->t_state&CARR_ON)==0) | |
651 | sleep((caddr_t)&tp->t_rawq, TTIPRI); | |
652 | spl0(); | |
653 | } | |
654 | ||
655 | /* | |
656 | * Dump control bits into the DM registers. | |
657 | */ | |
658 | dmctl(dev, bits, how) | |
659 | dev_t dev; | |
660 | int bits, how; | |
661 | { | |
662 | register struct uba_dinfo *ui; | |
663 | register struct dmdevice *addr; | |
664 | register int unit, s; | |
665 | int dm; | |
666 | ||
667 | unit = minor(dev); | |
668 | dm = unit >> 4; | |
669 | if ((ui = dminfo[dm]) == 0 || ui->ui_alive == 0) | |
670 | return; | |
671 | addr = (struct dmdevice *)ui->ui_addr; | |
672 | s = spl5(); | |
673 | addr->dmcsr &= ~DM_SCENABLE; | |
674 | while (addr->dmcsr & DM_SCBUSY) | |
675 | ; | |
676 | addr->dmcsr = unit & 0xf; | |
677 | switch(how) { | |
678 | case DMSET: | |
679 | addr->dmlstat = bits; | |
680 | break; | |
681 | case DMBIS: | |
682 | addr->dmlstat |= bits; | |
683 | break; | |
684 | case DMBIC: | |
685 | addr->dmlstat &= ~bits; | |
686 | break; | |
687 | } | |
688 | addr->dmcsr = DH_IE|DM_SCENABLE; | |
689 | splx(s); | |
690 | } | |
691 | ||
692 | /* | |
693 | * DM11 interrupt; deal with carrier transitions. | |
694 | */ | |
695 | dmintr(dm) | |
696 | register int dm; | |
697 | { | |
698 | register struct uba_dinfo *ui; | |
699 | register struct tty *tp; | |
700 | register struct dmdevice *addr; | |
701 | ||
702 | ui = dminfo[dm]; | |
703 | addr = (struct dmdevice *)ui->ui_addr; | |
704 | if (addr->dmcsr&DM_DONE && addr->dmcsr&DM_CARRTRANS) { | |
705 | tp = &dh11[(dm<<4)+(addr->dmcsr&0xf)]; | |
706 | wakeup((caddr_t)&tp->t_rawq); | |
707 | if ((tp->t_state&WOPEN)==0 && | |
708 | (tp->t_local&LMDMBUF)) { | |
709 | if (addr->dmlstat & DM_CARRON) { | |
710 | tp->t_state &= ~TTSTOP; | |
711 | ttstart(tp); | |
712 | } else if ((tp->t_state&TTSTOP) == 0) { | |
713 | tp->t_state |= TTSTOP; | |
714 | dhstop(tp, 0); | |
715 | } | |
716 | } else if ((addr->dmlstat&DM_CARRON)==0) { | |
717 | if ((tp->t_state&WOPEN)==0 && | |
718 | (tp->t_local&LNOHANG)==0) { | |
719 | gsignal(tp->t_pgrp, SIGHUP); | |
720 | gsignal(tp->t_pgrp, SIGCONT); | |
721 | addr->dmlstat = 0; | |
722 | flushtty(tp, FREAD|FWRITE); | |
723 | } | |
724 | tp->t_state &= ~CARR_ON; | |
725 | } else | |
726 | tp->t_state |= CARR_ON; | |
727 | addr->dmcsr = DH_IE|DM_SCENABLE; | |
728 | } | |
729 | } |