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