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