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 | * | |
74cd2624 | 6 | * @(#)dh.c 6.16 (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); |
a18f326f BJ |
406 | return; |
407 | } | |
3f3a34c3 | 408 | lpar = ((tp->t_ospeed)<<10) | ((tp->t_ispeed)<<6); |
7e00c42b | 409 | if ((tp->t_ispeed) == B134) |
3f3a34c3 | 410 | lpar |= BITS6|PENABLE|HDUPLX; |
fb01874e | 411 | else if (tp->t_flags & (RAW|LITOUT|PASS8)) |
3f3a34c3 | 412 | lpar |= BITS8; |
a18f326f | 413 | else |
3f3a34c3 | 414 | lpar |= BITS7|PENABLE; |
a18f326f | 415 | if ((tp->t_flags&EVENP) == 0) |
3f3a34c3 | 416 | lpar |= OPAR; |
7e00c42b | 417 | if ((tp->t_ospeed) == B110) |
3f3a34c3 BJ |
418 | lpar |= TWOSB; |
419 | addr->dhlpr = lpar; | |
0072a3c2 | 420 | splx(s); |
a18f326f BJ |
421 | } |
422 | ||
423 | /* | |
424 | * DH11 transmitter interrupt. | |
425 | * Restart each line which used to be active but has | |
426 | * terminated transmission since the last interrupt. | |
427 | */ | |
3f3a34c3 BJ |
428 | dhxint(dh) |
429 | int dh; | |
a18f326f BJ |
430 | { |
431 | register struct tty *tp; | |
d4638843 | 432 | register struct dhdevice *addr; |
a18f326f | 433 | short ttybit, bar, *sbar; |
b09915c5 | 434 | register struct uba_device *ui; |
7e00c42b | 435 | register int unit; |
71236e46 | 436 | u_short cntr; |
a18f326f | 437 | |
3f3a34c3 | 438 | ui = dhinfo[dh]; |
d4638843 | 439 | addr = (struct dhdevice *)ui->ui_addr; |
88d5b764 BJ |
440 | if (addr->un.dhcsr & DH_NXM) { |
441 | addr->un.dhcsr |= DH_CNI; | |
b19fe459 | 442 | printf("dh%d: NXM\n", dh); |
b4ec79ea | 443 | } |
3f3a34c3 | 444 | sbar = &dhsar[dh]; |
a18f326f | 445 | bar = *sbar & ~addr->dhbar; |
3f3a34c3 | 446 | unit = dh * 16; ttybit = 1; |
7e00c42b BJ |
447 | addr->un.dhcsr &= (short)~DH_TI; |
448 | for (; bar; unit++, ttybit <<= 1) { | |
449 | if (bar & ttybit) { | |
a18f326f BJ |
450 | *sbar &= ~ttybit; |
451 | bar &= ~ttybit; | |
3f3a34c3 | 452 | tp = &dh11[unit]; |
941944c9 BJ |
453 | tp->t_state &= ~TS_BUSY; |
454 | if (tp->t_state&TS_FLUSH) | |
455 | tp->t_state &= ~TS_FLUSH; | |
038bbe6b | 456 | else { |
88d5b764 | 457 | addr->un.dhcsrl = (unit&017)|DH_IE; |
7e00c42b BJ |
458 | /* |
459 | * Do arithmetic in a short to make up | |
460 | * for lost 16&17 bits. | |
461 | */ | |
71236e46 | 462 | cntr = addr->dhcar - |
7e00c42b | 463 | UBACVT(tp->t_outq.c_cf, ui->ui_ubanum); |
a0eab615 | 464 | ndflush(&tp->t_outq, (int)cntr); |
a18f326f | 465 | } |
038bbe6b BJ |
466 | if (tp->t_line) |
467 | (*linesw[tp->t_line].l_start)(tp); | |
468 | else | |
469 | dhstart(tp); | |
a18f326f BJ |
470 | } |
471 | } | |
472 | } | |
473 | ||
474 | /* | |
475 | * Start (restart) transmission on the given DH11 line. | |
476 | */ | |
477 | dhstart(tp) | |
3f3a34c3 | 478 | register struct tty *tp; |
a18f326f | 479 | { |
d4638843 | 480 | register struct dhdevice *addr; |
7e00c42b | 481 | register int car, dh, unit, nch; |
3f3a34c3 | 482 | int s; |
a18f326f | 483 | |
3f3a34c3 BJ |
484 | unit = minor(tp->t_dev); |
485 | dh = unit >> 4; | |
7e00c42b | 486 | unit &= 0xf; |
d4638843 | 487 | addr = (struct dhdevice *)tp->t_addr; |
7e00c42b BJ |
488 | |
489 | /* | |
490 | * Must hold interrupts in following code to prevent | |
491 | * state of the tp from changing. | |
492 | */ | |
493 | s = spl5(); | |
494 | /* | |
495 | * If it's currently active, or delaying, no need to do anything. | |
496 | */ | |
941944c9 | 497 | if (tp->t_state&(TS_TIMEOUT|TS_BUSY|TS_TTSTOP)) |
a18f326f | 498 | goto out; |
7e00c42b BJ |
499 | /* |
500 | * If there are sleepers, and output has drained below low | |
501 | * water mark, wake up the sleepers. | |
502 | */ | |
941944c9 BJ |
503 | if (tp->t_outq.c_cc<=TTLOWAT(tp)) { |
504 | if (tp->t_state&TS_ASLEEP) { | |
505 | tp->t_state &= ~TS_ASLEEP; | |
506 | wakeup((caddr_t)&tp->t_outq); | |
507 | } | |
508 | if (tp->t_wsel) { | |
509 | selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL); | |
510 | tp->t_wsel = 0; | |
511 | tp->t_state &= ~TS_WCOLL; | |
512 | } | |
a18f326f | 513 | } |
7e00c42b BJ |
514 | /* |
515 | * Now restart transmission unless the output queue is | |
516 | * empty. | |
517 | */ | |
a18f326f BJ |
518 | if (tp->t_outq.c_cc == 0) |
519 | goto out; | |
21a85e60 | 520 | if (tp->t_flags & (RAW|LITOUT)) |
a18f326f | 521 | nch = ndqb(&tp->t_outq, 0); |
3f3a34c3 | 522 | else { |
a18f326f | 523 | nch = ndqb(&tp->t_outq, 0200); |
7e00c42b BJ |
524 | /* |
525 | * If first thing on queue is a delay process it. | |
526 | */ | |
a18f326f BJ |
527 | if (nch == 0) { |
528 | nch = getc(&tp->t_outq); | |
7e00c42b | 529 | timeout(ttrstrt, (caddr_t)tp, (nch&0x7f)+6); |
941944c9 | 530 | tp->t_state |= TS_TIMEOUT; |
a18f326f BJ |
531 | goto out; |
532 | } | |
533 | } | |
7e00c42b BJ |
534 | /* |
535 | * If characters to transmit, restart transmission. | |
536 | */ | |
a18f326f | 537 | if (nch) { |
7e00c42b BJ |
538 | car = UBACVT(tp->t_outq.c_cf, dhinfo[dh]->ui_ubanum); |
539 | addr->un.dhcsrl = unit|((car>>12)&0x30)|DH_IE; | |
a1b41f3d BJ |
540 | /* |
541 | * The following nonsense with short word | |
542 | * is to make sure the dhbar |= word below | |
543 | * is done with an interlocking bisw2 instruction. | |
544 | */ | |
545 | { short word = 1 << unit; | |
546 | dhsar[dh] |= word; | |
7e00c42b | 547 | addr->dhcar = car; |
a18f326f | 548 | addr->dhbcr = -nch; |
a1b41f3d BJ |
549 | addr->dhbar |= word; |
550 | } | |
941944c9 | 551 | tp->t_state |= TS_BUSY; |
a18f326f | 552 | } |
3f3a34c3 | 553 | out: |
a18f326f BJ |
554 | splx(s); |
555 | } | |
556 | ||
a18f326f | 557 | /* |
7e00c42b | 558 | * Stop output on a line, e.g. for ^S/^Q or output flush. |
a18f326f BJ |
559 | */ |
560 | /*ARGSUSED*/ | |
561 | dhstop(tp, flag) | |
7e00c42b | 562 | register struct tty *tp; |
a18f326f | 563 | { |
d4638843 | 564 | register struct dhdevice *addr; |
3f3a34c3 | 565 | register int unit, s; |
a18f326f | 566 | |
d4638843 | 567 | addr = (struct dhdevice *)tp->t_addr; |
7e00c42b BJ |
568 | /* |
569 | * Block input/output interrupts while messing with state. | |
570 | */ | |
571 | s = spl5(); | |
941944c9 | 572 | if (tp->t_state & TS_BUSY) { |
7e00c42b BJ |
573 | /* |
574 | * Device is transmitting; stop output | |
575 | * by selecting the line and setting the byte | |
576 | * count to -1. We will clean up later | |
577 | * by examining the address where the dh stopped. | |
578 | */ | |
3f3a34c3 | 579 | unit = minor(tp->t_dev); |
88d5b764 | 580 | addr->un.dhcsrl = (unit&017) | DH_IE; |
941944c9 BJ |
581 | if ((tp->t_state&TS_TTSTOP)==0) |
582 | tp->t_state |= TS_FLUSH; | |
038bbe6b BJ |
583 | addr->dhbcr = -1; |
584 | } | |
a18f326f BJ |
585 | splx(s); |
586 | } | |
587 | ||
5c30d566 BJ |
588 | /* |
589 | * Reset state of driver if UBA reset was necessary. | |
590 | * Reset the csrl and lpr registers on open lines, and | |
591 | * restart transmitters. | |
592 | */ | |
3f3a34c3 | 593 | dhreset(uban) |
7e00c42b | 594 | int uban; |
5c30d566 | 595 | { |
3f3a34c3 | 596 | register int dh, unit; |
5c30d566 | 597 | register struct tty *tp; |
b09915c5 | 598 | register struct uba_device *ui; |
5aa9d5ea | 599 | int i; |
5c30d566 | 600 | |
3f3a34c3 | 601 | dh = 0; |
0916e0d1 | 602 | for (dh = 0; dh < NDH; dh++) { |
5aa9d5ea RE |
603 | ui = dhinfo[dh]; |
604 | if (ui == 0 || ui->ui_alive == 0 || ui->ui_ubanum != uban) | |
605 | continue; | |
b19fe459 | 606 | printf(" dh%d", dh); |
27f8c1d5 | 607 | if (dh_ubinfo[uban]) { |
c18c7ccc MK |
608 | dh_ubinfo[uban] = uballoc(uban, (caddr_t)cfree, |
609 | nclist*sizeof (struct cblock), 0); | |
27f8c1d5 | 610 | cbase[uban] = UBAI_ADDR(dh_ubinfo[uban]); |
c18c7ccc | 611 | } |
d4638843 | 612 | ((struct dhdevice *)ui->ui_addr)->un.dhcsr |= DH_IE; |
acd2f01b | 613 | ((struct dhdevice *)ui->ui_addr)->dhsilo = 0; |
5aa9d5ea RE |
614 | unit = dh * 16; |
615 | for (i = 0; i < 16; i++) { | |
616 | tp = &dh11[unit]; | |
941944c9 | 617 | if (tp->t_state & (TS_ISOPEN|TS_WOPEN)) { |
5aa9d5ea | 618 | dhparam(unit); |
d4638843 | 619 | dmctl(unit, DML_ON, DMSET); |
941944c9 | 620 | tp->t_state &= ~TS_BUSY; |
5aa9d5ea RE |
621 | dhstart(tp); |
622 | } | |
623 | unit++; | |
0072a3c2 BJ |
624 | } |
625 | } | |
acd2f01b | 626 | dhsilos = 0; |
5c30d566 | 627 | } |
3f3a34c3 | 628 | |
acd2f01b | 629 | int dhtransitions, dhslowtimers, dhfasttimers; /*DEBUG*/ |
7e00c42b | 630 | /* |
acd2f01b MK |
631 | * At software clock interrupt time, check status. |
632 | * Empty all the dh silos that are in use, and decide whether | |
633 | * to turn any silos off or on. | |
7e00c42b | 634 | */ |
88d5b764 BJ |
635 | dhtimer() |
636 | { | |
acd2f01b MK |
637 | register int dh, s; |
638 | static int timercalls; | |
639 | ||
640 | if (dhsilos) { | |
641 | dhfasttimers++; /*DEBUG*/ | |
642 | timercalls++; | |
643 | s = spl5(); | |
644 | for (dh = 0; dh < NDH; dh++) | |
645 | if (dhsilos & (1 << dh)) | |
646 | dhrint(dh); | |
647 | splx(s); | |
648 | } | |
649 | if ((dhsilos == 0) || ((timercalls += FASTTIMER) >= hz)) { | |
650 | dhslowtimers++; /*DEBUG*/ | |
651 | timercalls = 0; | |
652 | for (dh = 0; dh < NDH; dh++) { | |
653 | ave(dhrate[dh], dhchars[dh], 8); | |
654 | if ((dhchars[dh] > dhhighrate) && | |
655 | ((dhsilos & (1 << dh)) == 0)) { | |
656 | ((struct dhdevice *)(dhinfo[dh]->ui_addr))->dhsilo = | |
657 | (dhchars[dh] > 500? 32 : 16); | |
658 | dhsilos |= (1 << dh); | |
659 | dhtransitions++; /*DEBUG*/ | |
660 | } else if ((dhsilos & (1 << dh)) && | |
661 | (dhrate[dh] < dhlowrate)) { | |
662 | ((struct dhdevice *)(dhinfo[dh]->ui_addr))->dhsilo = 0; | |
663 | dhsilos &= ~(1 << dh); | |
664 | } | |
665 | dhchars[dh] = 0; | |
666 | } | |
667 | } | |
668 | timeout(dhtimer, (caddr_t) 0, dhsilos? FASTTIMER: hz); | |
88d5b764 BJ |
669 | } |
670 | ||
7e00c42b | 671 | /* |
d4638843 | 672 | * Turn on the line associated with dh dev. |
7e00c42b BJ |
673 | */ |
674 | dmopen(dev) | |
675 | dev_t dev; | |
676 | { | |
677 | register struct tty *tp; | |
678 | register struct dmdevice *addr; | |
b09915c5 | 679 | register struct uba_device *ui; |
7e00c42b BJ |
680 | register int unit; |
681 | register int dm; | |
1d6c2d43 | 682 | int s; |
7e00c42b BJ |
683 | |
684 | unit = minor(dev); | |
d4638843 | 685 | dm = unit >> 4; |
7e00c42b | 686 | tp = &dh11[unit]; |
7e286c72 | 687 | unit &= 0xf; |
efbbc69a | 688 | if (dm >= NDH || (ui = dminfo[dm]) == 0 || ui->ui_alive == 0) { |
941944c9 | 689 | tp->t_state |= TS_CARR_ON; |
7e00c42b BJ |
690 | return; |
691 | } | |
692 | addr = (struct dmdevice *)ui->ui_addr; | |
1d6c2d43 | 693 | s = spl5(); |
d4638843 BJ |
694 | addr->dmcsr &= ~DM_SE; |
695 | while (addr->dmcsr & DM_BUSY) | |
7e00c42b | 696 | ; |
7e286c72 | 697 | addr->dmcsr = unit; |
d4638843 | 698 | addr->dmlstat = DML_ON; |
efbbc69a | 699 | if ((addr->dmlstat&DML_CAR) || (dhsoftCAR[dm]&(1<<unit))) |
941944c9 | 700 | tp->t_state |= TS_CARR_ON; |
1d6c2d43 | 701 | addr->dmcsr = DM_IE|DM_SE; |
941944c9 | 702 | while ((tp->t_state&TS_CARR_ON)==0) |
7e00c42b | 703 | sleep((caddr_t)&tp->t_rawq, TTIPRI); |
1d6c2d43 | 704 | splx(s); |
7e00c42b BJ |
705 | } |
706 | ||
707 | /* | |
708 | * Dump control bits into the DM registers. | |
709 | */ | |
710 | dmctl(dev, bits, how) | |
711 | dev_t dev; | |
712 | int bits, how; | |
713 | { | |
b09915c5 | 714 | register struct uba_device *ui; |
7e00c42b BJ |
715 | register struct dmdevice *addr; |
716 | register int unit, s; | |
717 | int dm; | |
718 | ||
719 | unit = minor(dev); | |
720 | dm = unit >> 4; | |
721 | if ((ui = dminfo[dm]) == 0 || ui->ui_alive == 0) | |
722 | return; | |
723 | addr = (struct dmdevice *)ui->ui_addr; | |
724 | s = spl5(); | |
d4638843 BJ |
725 | addr->dmcsr &= ~DM_SE; |
726 | while (addr->dmcsr & DM_BUSY) | |
7e00c42b BJ |
727 | ; |
728 | addr->dmcsr = unit & 0xf; | |
729 | switch(how) { | |
730 | case DMSET: | |
731 | addr->dmlstat = bits; | |
732 | break; | |
733 | case DMBIS: | |
734 | addr->dmlstat |= bits; | |
735 | break; | |
736 | case DMBIC: | |
737 | addr->dmlstat &= ~bits; | |
738 | break; | |
739 | } | |
1d6c2d43 | 740 | addr->dmcsr = DM_IE|DM_SE; |
7e00c42b BJ |
741 | splx(s); |
742 | } | |
743 | ||
744 | /* | |
745 | * DM11 interrupt; deal with carrier transitions. | |
746 | */ | |
747 | dmintr(dm) | |
748 | register int dm; | |
749 | { | |
b09915c5 | 750 | register struct uba_device *ui; |
7e00c42b BJ |
751 | register struct tty *tp; |
752 | register struct dmdevice *addr; | |
efbbc69a | 753 | int unit; |
7e00c42b BJ |
754 | |
755 | ui = dminfo[dm]; | |
d4638843 BJ |
756 | if (ui == 0) |
757 | return; | |
7e00c42b | 758 | addr = (struct dmdevice *)ui->ui_addr; |
658d2f56 BJ |
759 | if (addr->dmcsr&DM_DONE) { |
760 | if (addr->dmcsr&DM_CF) { | |
efbbc69a MK |
761 | unit = addr->dmcsr & 0xf; |
762 | tp = &dh11[(dm << 4) + unit]; | |
74bfa0d5 MK |
763 | if (addr->dmlstat & DML_CAR) |
764 | (void)(*linesw[tp->t_line].l_modem)(tp, 1); | |
765 | else if ((dhsoftCAR[dm] & (1<<unit)) == 0 && | |
766 | (*linesw[tp->t_line].l_modem)(tp, 0) == 0) | |
767 | addr->dmlstat = 0; | |
658d2f56 BJ |
768 | } |
769 | addr->dmcsr = DM_IE|DM_SE; | |
7e00c42b BJ |
770 | } |
771 | } | |
4569bb70 | 772 | #endif |