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 | * | |
f5369e9c | 6 | * @(#)dh.c 7.4 (Berkeley) %G% |
da7c5cc6 | 7 | */ |
a18f326f | 8 | |
66b4fb09 | 9 | #include "dh.h" |
0916e0d1 | 10 | #if NDH > 0 |
a18f326f | 11 | /* |
d4638843 | 12 | * DH-11/DM-11 driver |
a18f326f | 13 | */ |
961945a8 SL |
14 | #include "../machine/pte.h" |
15 | ||
e2c4935e | 16 | #include "bk.h" |
66e92dcf | 17 | #include "uba.h" |
52163dab JB |
18 | #include "param.h" |
19 | #include "conf.h" | |
20 | #include "dir.h" | |
21 | #include "user.h" | |
22 | #include "proc.h" | |
23 | #include "ioctl.h" | |
24 | #include "tty.h" | |
25 | #include "map.h" | |
26 | #include "buf.h" | |
27 | #include "vm.h" | |
28 | #include "kernel.h" | |
b50ce881 | 29 | #include "syslog.h" |
896962b1 | 30 | |
52163dab JB |
31 | #include "ubareg.h" |
32 | #include "ubavar.h" | |
33 | #include "dhreg.h" | |
34 | #include "dmreg.h" | |
896962b1 | 35 | |
52163dab JB |
36 | #include "bkmac.h" |
37 | #include "clist.h" | |
38 | #include "file.h" | |
39 | #include "uio.h" | |
a18f326f | 40 | |
7e00c42b | 41 | /* |
d4638843 BJ |
42 | * Definition of the driver for the auto-configuration program. |
43 | * There is one definition for the dh and one for the dm. | |
7e00c42b | 44 | */ |
acd2f01b | 45 | int dhprobe(), dhattach(), dhrint(), dhxint(), dhtimer(); |
b09915c5 | 46 | struct uba_device *dhinfo[NDH]; |
3f3a34c3 | 47 | u_short dhstd[] = { 0 }; |
3f3a34c3 | 48 | struct uba_driver dhdriver = |
71236e46 | 49 | { dhprobe, 0, dhattach, 0, dhstd, "dh", dhinfo }; |
3f3a34c3 | 50 | |
71236e46 | 51 | int dmprobe(), dmattach(), dmintr(); |
b09915c5 | 52 | struct uba_device *dminfo[NDH]; |
d4638843 BJ |
53 | u_short dmstd[] = { 0 }; |
54 | struct uba_driver dmdriver = | |
71236e46 | 55 | { dmprobe, 0, dmattach, 0, dmstd, "dm", dminfo }; |
a18f326f | 56 | |
df07bd9e | 57 | #ifndef PORTSELECTOR |
74bfa0d5 | 58 | #define ISPEED B9600 |
df07bd9e SL |
59 | #define IFLAGS (EVENP|ODDP|ECHO) |
60 | #else | |
61 | #define ISPEED B4800 | |
62 | #define IFLAGS (EVENP|ODDP) | |
63 | #endif | |
64 | ||
acd2f01b MK |
65 | #define FASTTIMER (hz/30) /* scan rate with silos on */ |
66 | ||
a18f326f | 67 | /* |
d4638843 | 68 | * Local variables for the driver |
a18f326f | 69 | */ |
0916e0d1 BJ |
70 | short dhsar[NDH]; /* software copy of last bar */ |
71 | short dhsoftCAR[NDH]; | |
a18f326f | 72 | |
0916e0d1 BJ |
73 | struct tty dh11[NDH*16]; |
74 | int ndh11 = NDH*16; | |
d4638843 | 75 | int dhact; /* mask of active dh's */ |
acd2f01b MK |
76 | int dhsilos; /* mask of dh's with silo in use */ |
77 | int dhchars[NDH]; /* recent input count */ | |
78 | int dhrate[NDH]; /* smoothed input count */ | |
79 | int dhhighrate = 100; /* silo on if dhchars > dhhighrate */ | |
80 | int dhlowrate = 75; /* silo off if dhrate < dhlowrate */ | |
81 | static short timerstarted; | |
d4638843 | 82 | int dhstart(), ttrstrt(); |
a18f326f | 83 | |
d4638843 | 84 | /* |
e965c38b MK |
85 | * The clist space is mapped by one terminal driver onto each UNIBUS. |
86 | * The identity of the board which allocated resources is recorded, | |
87 | * so the process may be repeated after UNIBUS resets. | |
d4638843 BJ |
88 | * The UBACVT macro converts a clist space address for unibus uban |
89 | * into an i/o space address for the DMA routine. | |
90 | */ | |
e965c38b MK |
91 | int dh_uballoc[NUBA]; /* which dh (if any) allocated unibus map */ |
92 | int cbase[NUBA]; /* base address of clists in unibus map */ | |
d4638843 | 93 | #define UBACVT(x, uban) (cbase[uban] + ((x)-(char *)cfree)) |
a18f326f | 94 | |
88d5b764 BJ |
95 | /* |
96 | * Routine for configuration to force a dh to interrupt. | |
97 | * Set to transmit at 9600 baud, and cause a transmitter interrupt. | |
98 | */ | |
7e00c42b | 99 | /*ARGSUSED*/ |
71236e46 | 100 | dhprobe(reg) |
f5369e9c | 101 | p |
3f3a34c3 BJ |
102 | caddr_t reg; |
103 | { | |
7e00c42b | 104 | register int br, cvec; /* these are ``value-result'' */ |
d4638843 | 105 | register struct dhdevice *dhaddr = (struct dhdevice *)reg; |
5aa9d5ea | 106 | |
71236e46 BJ |
107 | #ifdef lint |
108 | br = 0; cvec = br; br = cvec; | |
fde2e6c9 | 109 | if (ndh11 == 0) ndh11 = 1; |
89b8a44c | 110 | dhrint(0); dhxint(0); |
71236e46 | 111 | #endif |
52ab9b2b | 112 | #ifndef notdef |
7e286c72 | 113 | dhaddr->un.dhcsr = DH_RIE|DH_MM|DH_RI; |
5e7ab705 | 114 | DELAY(1000); |
fde2e6c9 | 115 | dhaddr->un.dhcsr &= ~DH_RI; |
7e286c72 BJ |
116 | dhaddr->un.dhcsr = 0; |
117 | #else | |
88d5b764 BJ |
118 | dhaddr->un.dhcsr = DH_TIE; |
119 | DELAY(5); | |
120 | dhaddr->dhlpr = (B9600 << 10) | (B9600 << 6) | BITS7|PENABLE; | |
5aa9d5ea | 121 | dhaddr->dhbcr = -1; |
5aa9d5ea | 122 | dhaddr->dhcar = 0; |
88d5b764 BJ |
123 | dhaddr->dhbar = 1; |
124 | DELAY(100000); /* wait 1/10'th of a sec for interrupt */ | |
5aa9d5ea | 125 | dhaddr->un.dhcsr = 0; |
88d5b764 BJ |
126 | if (cvec && cvec != 0x200) |
127 | cvec -= 4; /* transmit -> receive */ | |
4afc81c0 | 128 | #endif |
9c0adba0 | 129 | return (sizeof (struct dhdevice)); |
3f3a34c3 BJ |
130 | } |
131 | ||
88d5b764 | 132 | /* |
71236e46 | 133 | * Routine called to attach a dh. |
88d5b764 | 134 | */ |
71236e46 | 135 | dhattach(ui) |
b09915c5 | 136 | struct uba_device *ui; |
3f3a34c3 BJ |
137 | { |
138 | ||
7e286c72 | 139 | dhsoftCAR[ui->ui_unit] = ui->ui_flags; |
27f8c1d5 | 140 | cbase[ui->ui_ubanum] = -1; |
e965c38b | 141 | dh_uballoc[ui->ui_unit] = -1; |
3f3a34c3 BJ |
142 | } |
143 | ||
d4638843 BJ |
144 | /* |
145 | * Configuration routine to cause a dm to interrupt. | |
146 | */ | |
71236e46 BJ |
147 | dmprobe(reg) |
148 | caddr_t reg; | |
d4638843 BJ |
149 | { |
150 | register int br, vec; /* value-result */ | |
71236e46 | 151 | register struct dmdevice *dmaddr = (struct dmdevice *)reg; |
d4638843 | 152 | |
71236e46 | 153 | #ifdef lint |
a0eab615 | 154 | br = 0; vec = br; br = vec; |
155d9ff0 | 155 | dmintr(0); |
71236e46 | 156 | #endif |
d4638843 BJ |
157 | dmaddr->dmcsr = DM_DONE|DM_IE; |
158 | DELAY(20); | |
159 | dmaddr->dmcsr = 0; | |
71236e46 | 160 | return (1); |
d4638843 BJ |
161 | } |
162 | ||
71236e46 BJ |
163 | /*ARGSUSED*/ |
164 | dmattach(ui) | |
b09915c5 | 165 | struct uba_device *ui; |
d4638843 BJ |
166 | { |
167 | ||
168 | /* no local state to set up */ | |
169 | } | |
170 | ||
a18f326f | 171 | /* |
7e00c42b BJ |
172 | * Open a DH11 line, mapping the clist onto the uba if this |
173 | * is the first dh on this uba. Turn on this dh if this is | |
174 | * the first use of it. Also do a dmopen to wait for carrier. | |
a18f326f BJ |
175 | */ |
176 | /*ARGSUSED*/ | |
177 | dhopen(dev, flag) | |
3f3a34c3 | 178 | dev_t dev; |
a18f326f BJ |
179 | { |
180 | register struct tty *tp; | |
3f3a34c3 | 181 | register int unit, dh; |
d4638843 | 182 | register struct dhdevice *addr; |
b09915c5 | 183 | register struct uba_device *ui; |
a18f326f BJ |
184 | int s; |
185 | ||
3f3a34c3 BJ |
186 | unit = minor(dev); |
187 | dh = unit >> 4; | |
7da157da BJ |
188 | if (unit >= NDH*16 || (ui = dhinfo[dh])== 0 || ui->ui_alive == 0) |
189 | return (ENXIO); | |
3f3a34c3 | 190 | tp = &dh11[unit]; |
7da157da BJ |
191 | if (tp->t_state&TS_XCLUDE && u.u_uid!=0) |
192 | return (EBUSY); | |
d4638843 | 193 | addr = (struct dhdevice *)ui->ui_addr; |
a18f326f BJ |
194 | tp->t_addr = (caddr_t)addr; |
195 | tp->t_oproc = dhstart; | |
941944c9 | 196 | tp->t_state |= TS_WOPEN; |
7e00c42b BJ |
197 | /* |
198 | * While setting up state for this uba and this dh, | |
199 | * block uba resets which can clear the state. | |
200 | */ | |
201 | s = spl5(); | |
27f8c1d5 | 202 | if (cbase[ui->ui_ubanum] == -1) { |
e965c38b MK |
203 | dh_uballoc[ui->ui_ubanum] = dh; |
204 | cbase[ui->ui_ubanum] = UBAI_ADDR(uballoc(ui->ui_ubanum, | |
205 | (caddr_t)cfree, nclist*sizeof(struct cblock), 0)); | |
88d5b764 | 206 | } |
acd2f01b MK |
207 | if (timerstarted == 0) { |
208 | timerstarted++; | |
209 | timeout(dhtimer, (caddr_t) 0, hz); | |
210 | } | |
88d5b764 BJ |
211 | if ((dhact&(1<<dh)) == 0) { |
212 | addr->un.dhcsr |= DH_IE; | |
88d5b764 | 213 | dhact |= (1<<dh); |
acd2f01b | 214 | addr->dhsilo = 0; |
a18f326f BJ |
215 | } |
216 | splx(s); | |
7e00c42b | 217 | /* |
74cd2624 | 218 | * If this is first open, initialize tty state to default. |
7e00c42b | 219 | */ |
941944c9 | 220 | if ((tp->t_state&TS_ISOPEN) == 0) { |
a18f326f | 221 | ttychars(tp); |
74cd2624 MK |
222 | #ifndef PORTSELECTOR |
223 | if (tp->t_ispeed == 0) { | |
224 | #else | |
225 | tp->t_state |= TS_HUPCLS; | |
226 | #endif PORTSELECTOR | |
227 | tp->t_ispeed = ISPEED; | |
228 | tp->t_ospeed = ISPEED; | |
229 | tp->t_flags = IFLAGS; | |
230 | #ifndef PORTSELECTOR | |
231 | } | |
232 | #endif PORTSELECTOR | |
3f3a34c3 | 233 | dhparam(unit); |
a18f326f | 234 | } |
7e00c42b BJ |
235 | /* |
236 | * Wait for carrier, then process line discipline specific open. | |
237 | */ | |
a18f326f | 238 | dmopen(dev); |
7da157da | 239 | return ((*linesw[tp->t_line].l_open)(dev, tp)); |
a18f326f BJ |
240 | } |
241 | ||
242 | /* | |
7e00c42b | 243 | * Close a DH11 line, turning off the DM11. |
a18f326f BJ |
244 | */ |
245 | /*ARGSUSED*/ | |
246 | dhclose(dev, flag) | |
3f3a34c3 BJ |
247 | dev_t dev; |
248 | int flag; | |
a18f326f BJ |
249 | { |
250 | register struct tty *tp; | |
3f3a34c3 | 251 | register unit; |
a18f326f | 252 | |
3f3a34c3 BJ |
253 | unit = minor(dev); |
254 | tp = &dh11[unit]; | |
a18f326f | 255 | (*linesw[tp->t_line].l_close)(tp); |
d4638843 | 256 | ((struct dhdevice *)(tp->t_addr))->dhbreak &= ~(1<<(unit&017)); |
941944c9 | 257 | if (tp->t_state&TS_HUPCLS || (tp->t_state&TS_ISOPEN)==0) |
d4638843 | 258 | dmctl(unit, DML_OFF, DMSET); |
a18f326f BJ |
259 | ttyclose(tp); |
260 | } | |
261 | ||
740e4029 | 262 | dhread(dev, uio) |
3f3a34c3 | 263 | dev_t dev; |
740e4029 | 264 | struct uio *uio; |
a18f326f | 265 | { |
b91c756d | 266 | register struct tty *tp = &dh11[minor(dev)]; |
a18f326f | 267 | |
740e4029 | 268 | return ((*linesw[tp->t_line].l_read)(tp, uio)); |
a18f326f BJ |
269 | } |
270 | ||
406ddcbe | 271 | dhwrite(dev, uio) |
3f3a34c3 | 272 | dev_t dev; |
406ddcbe | 273 | struct uio *uio; |
a18f326f | 274 | { |
b91c756d | 275 | register struct tty *tp = &dh11[minor(dev)]; |
a18f326f | 276 | |
b91c756d | 277 | return ((*linesw[tp->t_line].l_write)(tp, uio)); |
a18f326f BJ |
278 | } |
279 | ||
280 | /* | |
281 | * DH11 receiver interrupt. | |
282 | */ | |
3f3a34c3 BJ |
283 | dhrint(dh) |
284 | int dh; | |
a18f326f BJ |
285 | { |
286 | register struct tty *tp; | |
3f3a34c3 | 287 | register c; |
d4638843 | 288 | register struct dhdevice *addr; |
0e239190 | 289 | register struct tty *tp0; |
b09915c5 | 290 | register struct uba_device *ui; |
b19fe459 | 291 | int overrun = 0; |
a18f326f | 292 | |
3f3a34c3 | 293 | ui = dhinfo[dh]; |
d4638843 BJ |
294 | if (ui == 0 || ui->ui_alive == 0) |
295 | return; | |
296 | addr = (struct dhdevice *)ui->ui_addr; | |
7e00c42b BJ |
297 | tp0 = &dh11[dh<<4]; |
298 | /* | |
299 | * Loop fetching characters from the silo for this | |
300 | * dh until there are no more in the silo. | |
301 | */ | |
302 | while ((c = addr->dhrcr) < 0) { | |
303 | tp = tp0 + ((c>>8)&0xf); | |
acd2f01b | 304 | dhchars[dh]++; |
941944c9 | 305 | if ((tp->t_state&TS_ISOPEN)==0) { |
74bfa0d5 MK |
306 | wakeup((caddr_t)&tp->t_rawq); |
307 | #ifdef PORTSELECTOR | |
308 | if ((tp->t_state&TS_WOPEN) == 0) | |
df07bd9e | 309 | #endif |
74bfa0d5 | 310 | continue; |
a18f326f | 311 | } |
7e00c42b | 312 | if (c & DH_PE) |
a18f326f BJ |
313 | if ((tp->t_flags&(EVENP|ODDP))==EVENP |
314 | || (tp->t_flags&(EVENP|ODDP))==ODDP ) | |
315 | continue; | |
b19fe459 | 316 | if ((c & DH_DO) && overrun == 0) { |
283ffc90 | 317 | log(LOG_WARNING, "dh%d: silo overflow\n", dh); |
b19fe459 BJ |
318 | overrun = 1; |
319 | } | |
7e00c42b BJ |
320 | if (c & DH_FE) |
321 | /* | |
322 | * At framing error (break) generate | |
323 | * a null (in raw mode, for getty), or a | |
324 | * interrupt (in cooked/cbreak mode). | |
325 | */ | |
a18f326f | 326 | if (tp->t_flags&RAW) |
7e00c42b | 327 | c = 0; |
a18f326f | 328 | else |
21a85e60 | 329 | c = tp->t_intrc; |
e2c4935e | 330 | #if NBK > 0 |
5c6adb3e | 331 | if (tp->t_line == NETLDISC) { |
0e239190 | 332 | c &= 0177; |
87f51a66 | 333 | BKINPUT(c, tp); |
0e239190 | 334 | } else |
e2c4935e | 335 | #endif |
7e00c42b | 336 | (*linesw[tp->t_line].l_rint)(c, tp); |
a18f326f BJ |
337 | } |
338 | } | |
339 | ||
340 | /* | |
7e00c42b | 341 | * Ioctl for DH11. |
a18f326f BJ |
342 | */ |
343 | /*ARGSUSED*/ | |
942f05a9 SL |
344 | dhioctl(dev, cmd, data, flag) |
345 | caddr_t data; | |
a18f326f BJ |
346 | { |
347 | register struct tty *tp; | |
7da157da BJ |
348 | register int unit = minor(dev); |
349 | int error; | |
a18f326f | 350 | |
3f3a34c3 | 351 | tp = &dh11[unit]; |
7da157da BJ |
352 | error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag); |
353 | if (error >= 0) | |
354 | return (error); | |
355 | error = ttioctl(tp, cmd, data, flag); | |
356 | if (error >= 0) { | |
21220e35 JB |
357 | if (cmd == TIOCSETP || cmd == TIOCSETN || cmd == TIOCLBIS || |
358 | cmd == TIOCLBIC || cmd == TIOCLSET) | |
3f3a34c3 | 359 | dhparam(unit); |
7da157da BJ |
360 | return (error); |
361 | } | |
362 | switch (cmd) { | |
942f05a9 | 363 | |
87f51a66 | 364 | case TIOCSBRK: |
d4638843 | 365 | ((struct dhdevice *)(tp->t_addr))->dhbreak |= 1<<(unit&017); |
87f51a66 | 366 | break; |
942f05a9 | 367 | |
87f51a66 | 368 | case TIOCCBRK: |
d4638843 | 369 | ((struct dhdevice *)(tp->t_addr))->dhbreak &= ~(1<<(unit&017)); |
87f51a66 | 370 | break; |
942f05a9 | 371 | |
87f51a66 | 372 | case TIOCSDTR: |
d4638843 | 373 | dmctl(unit, DML_DTR|DML_RTS, DMBIS); |
87f51a66 | 374 | break; |
942f05a9 | 375 | |
87f51a66 | 376 | case TIOCCDTR: |
d4638843 | 377 | dmctl(unit, DML_DTR|DML_RTS, DMBIC); |
87f51a66 | 378 | break; |
942f05a9 | 379 | |
87f51a66 | 380 | default: |
7da157da | 381 | return (ENOTTY); |
87f51a66 | 382 | } |
7da157da | 383 | return (0); |
a18f326f BJ |
384 | } |
385 | ||
386 | /* | |
387 | * Set parameters from open or stty into the DH hardware | |
388 | * registers. | |
389 | */ | |
3f3a34c3 BJ |
390 | dhparam(unit) |
391 | register int unit; | |
a18f326f BJ |
392 | { |
393 | register struct tty *tp; | |
d4638843 | 394 | register struct dhdevice *addr; |
3f3a34c3 | 395 | register int lpar; |
0072a3c2 | 396 | int s; |
a18f326f | 397 | |
3f3a34c3 | 398 | tp = &dh11[unit]; |
d4638843 | 399 | addr = (struct dhdevice *)tp->t_addr; |
7e00c42b BJ |
400 | /* |
401 | * Block interrupts so parameters will be set | |
402 | * before the line interrupts. | |
403 | */ | |
0072a3c2 | 404 | s = spl5(); |
7e00c42b | 405 | addr->un.dhcsrl = (unit&0xf) | DH_IE; |
a18f326f | 406 | if ((tp->t_ispeed)==0) { |
941944c9 | 407 | tp->t_state |= TS_HUPCLS; |
d4638843 | 408 | dmctl(unit, DML_OFF, DMSET); |
3371117b | 409 | splx(s); |
a18f326f BJ |
410 | return; |
411 | } | |
3f3a34c3 | 412 | lpar = ((tp->t_ospeed)<<10) | ((tp->t_ispeed)<<6); |
7e00c42b | 413 | if ((tp->t_ispeed) == B134) |
3f3a34c3 | 414 | lpar |= BITS6|PENABLE|HDUPLX; |
fb01874e | 415 | else if (tp->t_flags & (RAW|LITOUT|PASS8)) |
3f3a34c3 | 416 | lpar |= BITS8; |
a18f326f | 417 | else |
3f3a34c3 | 418 | lpar |= BITS7|PENABLE; |
a18f326f | 419 | if ((tp->t_flags&EVENP) == 0) |
3f3a34c3 | 420 | lpar |= OPAR; |
7e00c42b | 421 | if ((tp->t_ospeed) == B110) |
3f3a34c3 BJ |
422 | lpar |= TWOSB; |
423 | addr->dhlpr = lpar; | |
0072a3c2 | 424 | splx(s); |
a18f326f BJ |
425 | } |
426 | ||
427 | /* | |
428 | * DH11 transmitter interrupt. | |
429 | * Restart each line which used to be active but has | |
430 | * terminated transmission since the last interrupt. | |
431 | */ | |
3f3a34c3 BJ |
432 | dhxint(dh) |
433 | int dh; | |
a18f326f BJ |
434 | { |
435 | register struct tty *tp; | |
d4638843 | 436 | register struct dhdevice *addr; |
a18f326f | 437 | short ttybit, bar, *sbar; |
b09915c5 | 438 | register struct uba_device *ui; |
7e00c42b | 439 | register int unit; |
71236e46 | 440 | u_short cntr; |
a18f326f | 441 | |
3f3a34c3 | 442 | ui = dhinfo[dh]; |
d4638843 | 443 | addr = (struct dhdevice *)ui->ui_addr; |
88d5b764 BJ |
444 | if (addr->un.dhcsr & DH_NXM) { |
445 | addr->un.dhcsr |= DH_CNI; | |
b19fe459 | 446 | printf("dh%d: NXM\n", dh); |
b4ec79ea | 447 | } |
3f3a34c3 | 448 | sbar = &dhsar[dh]; |
a18f326f | 449 | bar = *sbar & ~addr->dhbar; |
3f3a34c3 | 450 | unit = dh * 16; ttybit = 1; |
7e00c42b BJ |
451 | addr->un.dhcsr &= (short)~DH_TI; |
452 | for (; bar; unit++, ttybit <<= 1) { | |
453 | if (bar & ttybit) { | |
a18f326f BJ |
454 | *sbar &= ~ttybit; |
455 | bar &= ~ttybit; | |
3f3a34c3 | 456 | tp = &dh11[unit]; |
941944c9 BJ |
457 | tp->t_state &= ~TS_BUSY; |
458 | if (tp->t_state&TS_FLUSH) | |
459 | tp->t_state &= ~TS_FLUSH; | |
038bbe6b | 460 | else { |
88d5b764 | 461 | addr->un.dhcsrl = (unit&017)|DH_IE; |
7e00c42b BJ |
462 | /* |
463 | * Do arithmetic in a short to make up | |
464 | * for lost 16&17 bits. | |
465 | */ | |
71236e46 | 466 | cntr = addr->dhcar - |
7e00c42b | 467 | UBACVT(tp->t_outq.c_cf, ui->ui_ubanum); |
a0eab615 | 468 | ndflush(&tp->t_outq, (int)cntr); |
a18f326f | 469 | } |
038bbe6b BJ |
470 | if (tp->t_line) |
471 | (*linesw[tp->t_line].l_start)(tp); | |
472 | else | |
473 | dhstart(tp); | |
a18f326f BJ |
474 | } |
475 | } | |
476 | } | |
477 | ||
478 | /* | |
479 | * Start (restart) transmission on the given DH11 line. | |
480 | */ | |
481 | dhstart(tp) | |
3f3a34c3 | 482 | register struct tty *tp; |
a18f326f | 483 | { |
d4638843 | 484 | register struct dhdevice *addr; |
7e00c42b | 485 | register int car, dh, unit, nch; |
3f3a34c3 | 486 | int s; |
a18f326f | 487 | |
3f3a34c3 BJ |
488 | unit = minor(tp->t_dev); |
489 | dh = unit >> 4; | |
7e00c42b | 490 | unit &= 0xf; |
d4638843 | 491 | addr = (struct dhdevice *)tp->t_addr; |
7e00c42b BJ |
492 | |
493 | /* | |
494 | * Must hold interrupts in following code to prevent | |
495 | * state of the tp from changing. | |
496 | */ | |
497 | s = spl5(); | |
498 | /* | |
499 | * If it's currently active, or delaying, no need to do anything. | |
500 | */ | |
941944c9 | 501 | if (tp->t_state&(TS_TIMEOUT|TS_BUSY|TS_TTSTOP)) |
a18f326f | 502 | goto out; |
7e00c42b BJ |
503 | /* |
504 | * If there are sleepers, and output has drained below low | |
505 | * water mark, wake up the sleepers. | |
506 | */ | |
941944c9 BJ |
507 | if (tp->t_outq.c_cc<=TTLOWAT(tp)) { |
508 | if (tp->t_state&TS_ASLEEP) { | |
509 | tp->t_state &= ~TS_ASLEEP; | |
510 | wakeup((caddr_t)&tp->t_outq); | |
511 | } | |
512 | if (tp->t_wsel) { | |
513 | selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL); | |
514 | tp->t_wsel = 0; | |
515 | tp->t_state &= ~TS_WCOLL; | |
516 | } | |
a18f326f | 517 | } |
7e00c42b BJ |
518 | /* |
519 | * Now restart transmission unless the output queue is | |
520 | * empty. | |
521 | */ | |
a18f326f BJ |
522 | if (tp->t_outq.c_cc == 0) |
523 | goto out; | |
21a85e60 | 524 | if (tp->t_flags & (RAW|LITOUT)) |
a18f326f | 525 | nch = ndqb(&tp->t_outq, 0); |
3f3a34c3 | 526 | else { |
a18f326f | 527 | nch = ndqb(&tp->t_outq, 0200); |
7e00c42b BJ |
528 | /* |
529 | * If first thing on queue is a delay process it. | |
530 | */ | |
a18f326f BJ |
531 | if (nch == 0) { |
532 | nch = getc(&tp->t_outq); | |
7e00c42b | 533 | timeout(ttrstrt, (caddr_t)tp, (nch&0x7f)+6); |
941944c9 | 534 | tp->t_state |= TS_TIMEOUT; |
a18f326f BJ |
535 | goto out; |
536 | } | |
537 | } | |
7e00c42b BJ |
538 | /* |
539 | * If characters to transmit, restart transmission. | |
540 | */ | |
a18f326f | 541 | if (nch) { |
7e00c42b BJ |
542 | car = UBACVT(tp->t_outq.c_cf, dhinfo[dh]->ui_ubanum); |
543 | addr->un.dhcsrl = unit|((car>>12)&0x30)|DH_IE; | |
a1b41f3d BJ |
544 | /* |
545 | * The following nonsense with short word | |
546 | * is to make sure the dhbar |= word below | |
547 | * is done with an interlocking bisw2 instruction. | |
548 | */ | |
549 | { short word = 1 << unit; | |
550 | dhsar[dh] |= word; | |
7e00c42b | 551 | addr->dhcar = car; |
a18f326f | 552 | addr->dhbcr = -nch; |
a1b41f3d BJ |
553 | addr->dhbar |= word; |
554 | } | |
941944c9 | 555 | tp->t_state |= TS_BUSY; |
a18f326f | 556 | } |
3f3a34c3 | 557 | out: |
a18f326f BJ |
558 | splx(s); |
559 | } | |
560 | ||
a18f326f | 561 | /* |
7e00c42b | 562 | * Stop output on a line, e.g. for ^S/^Q or output flush. |
a18f326f BJ |
563 | */ |
564 | /*ARGSUSED*/ | |
565 | dhstop(tp, flag) | |
7e00c42b | 566 | register struct tty *tp; |
a18f326f | 567 | { |
d4638843 | 568 | register struct dhdevice *addr; |
3f3a34c3 | 569 | register int unit, s; |
a18f326f | 570 | |
d4638843 | 571 | addr = (struct dhdevice *)tp->t_addr; |
7e00c42b BJ |
572 | /* |
573 | * Block input/output interrupts while messing with state. | |
574 | */ | |
575 | s = spl5(); | |
941944c9 | 576 | if (tp->t_state & TS_BUSY) { |
7e00c42b BJ |
577 | /* |
578 | * Device is transmitting; stop output | |
579 | * by selecting the line and setting the byte | |
580 | * count to -1. We will clean up later | |
581 | * by examining the address where the dh stopped. | |
582 | */ | |
3f3a34c3 | 583 | unit = minor(tp->t_dev); |
88d5b764 | 584 | addr->un.dhcsrl = (unit&017) | DH_IE; |
941944c9 BJ |
585 | if ((tp->t_state&TS_TTSTOP)==0) |
586 | tp->t_state |= TS_FLUSH; | |
038bbe6b BJ |
587 | addr->dhbcr = -1; |
588 | } | |
a18f326f BJ |
589 | splx(s); |
590 | } | |
591 | ||
5c30d566 BJ |
592 | /* |
593 | * Reset state of driver if UBA reset was necessary. | |
594 | * Reset the csrl and lpr registers on open lines, and | |
595 | * restart transmitters. | |
596 | */ | |
3f3a34c3 | 597 | dhreset(uban) |
7e00c42b | 598 | int uban; |
5c30d566 | 599 | { |
3f3a34c3 | 600 | register int dh, unit; |
5c30d566 | 601 | register struct tty *tp; |
b09915c5 | 602 | register struct uba_device *ui; |
5aa9d5ea | 603 | int i; |
5c30d566 | 604 | |
3f3a34c3 | 605 | dh = 0; |
0916e0d1 | 606 | for (dh = 0; dh < NDH; dh++) { |
5aa9d5ea RE |
607 | ui = dhinfo[dh]; |
608 | if (ui == 0 || ui->ui_alive == 0 || ui->ui_ubanum != uban) | |
609 | continue; | |
b19fe459 | 610 | printf(" dh%d", dh); |
e965c38b MK |
611 | if (dh_uballoc[uban] == dh) { |
612 | int info; | |
613 | ||
614 | info = uballoc(uban, (caddr_t)cfree, | |
615 | nclist * sizeof(struct cblock), UBA_CANTWAIT); | |
616 | if (info) | |
617 | cbase[uban] = UBAI_ADDR(info); | |
618 | else { | |
619 | printf(" [can't get uba map]"); | |
620 | cbase[uban] = -1; | |
621 | } | |
c18c7ccc | 622 | } |
d4638843 | 623 | ((struct dhdevice *)ui->ui_addr)->un.dhcsr |= DH_IE; |
acd2f01b | 624 | ((struct dhdevice *)ui->ui_addr)->dhsilo = 0; |
5aa9d5ea RE |
625 | unit = dh * 16; |
626 | for (i = 0; i < 16; i++) { | |
627 | tp = &dh11[unit]; | |
941944c9 | 628 | if (tp->t_state & (TS_ISOPEN|TS_WOPEN)) { |
5aa9d5ea | 629 | dhparam(unit); |
d4638843 | 630 | dmctl(unit, DML_ON, DMSET); |
941944c9 | 631 | tp->t_state &= ~TS_BUSY; |
5aa9d5ea RE |
632 | dhstart(tp); |
633 | } | |
634 | unit++; | |
0072a3c2 BJ |
635 | } |
636 | } | |
acd2f01b | 637 | dhsilos = 0; |
5c30d566 | 638 | } |
3f3a34c3 | 639 | |
acd2f01b | 640 | int dhtransitions, dhslowtimers, dhfasttimers; /*DEBUG*/ |
7e00c42b | 641 | /* |
acd2f01b MK |
642 | * At software clock interrupt time, check status. |
643 | * Empty all the dh silos that are in use, and decide whether | |
644 | * to turn any silos off or on. | |
7e00c42b | 645 | */ |
88d5b764 BJ |
646 | dhtimer() |
647 | { | |
acd2f01b MK |
648 | register int dh, s; |
649 | static int timercalls; | |
650 | ||
651 | if (dhsilos) { | |
652 | dhfasttimers++; /*DEBUG*/ | |
653 | timercalls++; | |
654 | s = spl5(); | |
655 | for (dh = 0; dh < NDH; dh++) | |
656 | if (dhsilos & (1 << dh)) | |
657 | dhrint(dh); | |
658 | splx(s); | |
659 | } | |
660 | if ((dhsilos == 0) || ((timercalls += FASTTIMER) >= hz)) { | |
661 | dhslowtimers++; /*DEBUG*/ | |
662 | timercalls = 0; | |
663 | for (dh = 0; dh < NDH; dh++) { | |
664 | ave(dhrate[dh], dhchars[dh], 8); | |
665 | if ((dhchars[dh] > dhhighrate) && | |
666 | ((dhsilos & (1 << dh)) == 0)) { | |
667 | ((struct dhdevice *)(dhinfo[dh]->ui_addr))->dhsilo = | |
668 | (dhchars[dh] > 500? 32 : 16); | |
669 | dhsilos |= (1 << dh); | |
670 | dhtransitions++; /*DEBUG*/ | |
671 | } else if ((dhsilos & (1 << dh)) && | |
672 | (dhrate[dh] < dhlowrate)) { | |
673 | ((struct dhdevice *)(dhinfo[dh]->ui_addr))->dhsilo = 0; | |
674 | dhsilos &= ~(1 << dh); | |
675 | } | |
676 | dhchars[dh] = 0; | |
677 | } | |
678 | } | |
679 | timeout(dhtimer, (caddr_t) 0, dhsilos? FASTTIMER: hz); | |
88d5b764 BJ |
680 | } |
681 | ||
7e00c42b | 682 | /* |
d4638843 | 683 | * Turn on the line associated with dh dev. |
7e00c42b BJ |
684 | */ |
685 | dmopen(dev) | |
686 | dev_t dev; | |
687 | { | |
688 | register struct tty *tp; | |
689 | register struct dmdevice *addr; | |
b09915c5 | 690 | register struct uba_device *ui; |
7e00c42b BJ |
691 | register int unit; |
692 | register int dm; | |
1d6c2d43 | 693 | int s; |
7e00c42b BJ |
694 | |
695 | unit = minor(dev); | |
d4638843 | 696 | dm = unit >> 4; |
7e00c42b | 697 | tp = &dh11[unit]; |
7e286c72 | 698 | unit &= 0xf; |
efbbc69a | 699 | if (dm >= NDH || (ui = dminfo[dm]) == 0 || ui->ui_alive == 0) { |
941944c9 | 700 | tp->t_state |= TS_CARR_ON; |
7e00c42b BJ |
701 | return; |
702 | } | |
703 | addr = (struct dmdevice *)ui->ui_addr; | |
1d6c2d43 | 704 | s = spl5(); |
6e095954 MK |
705 | for (;;) { |
706 | addr->dmcsr &= ~DM_SE; | |
707 | while (addr->dmcsr & DM_BUSY) | |
708 | ; | |
709 | addr->dmcsr = unit; | |
710 | addr->dmlstat = DML_ON; | |
f5369e9c | 711 | if ((addr->dmlstat & DML_CAR) || (dhsoftCAR[dm] & (1 << unit))) |
6e095954 MK |
712 | tp->t_state |= TS_CARR_ON; |
713 | addr->dmcsr = DM_IE|DM_SE; | |
714 | if (tp->t_state & TS_CARR_ON) | |
715 | break; | |
7e00c42b | 716 | sleep((caddr_t)&tp->t_rawq, TTIPRI); |
6e095954 | 717 | } |
1d6c2d43 | 718 | splx(s); |
7e00c42b BJ |
719 | } |
720 | ||
721 | /* | |
722 | * Dump control bits into the DM registers. | |
723 | */ | |
724 | dmctl(dev, bits, how) | |
725 | dev_t dev; | |
726 | int bits, how; | |
727 | { | |
b09915c5 | 728 | register struct uba_device *ui; |
7e00c42b BJ |
729 | register struct dmdevice *addr; |
730 | register int unit, s; | |
731 | int dm; | |
732 | ||
733 | unit = minor(dev); | |
734 | dm = unit >> 4; | |
735 | if ((ui = dminfo[dm]) == 0 || ui->ui_alive == 0) | |
736 | return; | |
737 | addr = (struct dmdevice *)ui->ui_addr; | |
738 | s = spl5(); | |
d4638843 BJ |
739 | addr->dmcsr &= ~DM_SE; |
740 | while (addr->dmcsr & DM_BUSY) | |
7e00c42b BJ |
741 | ; |
742 | addr->dmcsr = unit & 0xf; | |
743 | switch(how) { | |
744 | case DMSET: | |
745 | addr->dmlstat = bits; | |
746 | break; | |
747 | case DMBIS: | |
748 | addr->dmlstat |= bits; | |
749 | break; | |
750 | case DMBIC: | |
751 | addr->dmlstat &= ~bits; | |
752 | break; | |
753 | } | |
1d6c2d43 | 754 | addr->dmcsr = DM_IE|DM_SE; |
7e00c42b BJ |
755 | splx(s); |
756 | } | |
757 | ||
758 | /* | |
759 | * DM11 interrupt; deal with carrier transitions. | |
760 | */ | |
761 | dmintr(dm) | |
762 | register int dm; | |
763 | { | |
b09915c5 | 764 | register struct uba_device *ui; |
7e00c42b BJ |
765 | register struct tty *tp; |
766 | register struct dmdevice *addr; | |
efbbc69a | 767 | int unit; |
7e00c42b BJ |
768 | |
769 | ui = dminfo[dm]; | |
d4638843 BJ |
770 | if (ui == 0) |
771 | return; | |
7e00c42b | 772 | addr = (struct dmdevice *)ui->ui_addr; |
658d2f56 BJ |
773 | if (addr->dmcsr&DM_DONE) { |
774 | if (addr->dmcsr&DM_CF) { | |
efbbc69a MK |
775 | unit = addr->dmcsr & 0xf; |
776 | tp = &dh11[(dm << 4) + unit]; | |
74bfa0d5 MK |
777 | if (addr->dmlstat & DML_CAR) |
778 | (void)(*linesw[tp->t_line].l_modem)(tp, 1); | |
779 | else if ((dhsoftCAR[dm] & (1<<unit)) == 0 && | |
780 | (*linesw[tp->t_line].l_modem)(tp, 0) == 0) | |
781 | addr->dmlstat = 0; | |
658d2f56 BJ |
782 | } |
783 | addr->dmcsr = DM_IE|DM_SE; | |
7e00c42b BJ |
784 | } |
785 | } | |
4569bb70 | 786 | #endif |