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