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