Commit | Line | Data |
---|---|---|
6e7edb25 | 1 | /* dmf.c 4.12 82/10/20 */ |
7a17d042 SL |
2 | |
3 | #include "dmf.h" | |
4 | #if NDMF > 0 | |
5 | /* | |
6 | * DMF32 driver | |
7 | * | |
8 | * TODO: | |
9 | * test with modem | |
10 | * load as much as possible into silo | |
11 | * get correct numbers for receive silo parameter timeout | |
12 | * use auto XON/XOFF | |
13 | * test reset code | |
14 | * test with more than one unit | |
15 | * optimize for efficient DMA and dynamically | |
16 | * decide between silo and DMA mode | |
17 | */ | |
18 | #include "bk.h" | |
19 | #include "../h/param.h" | |
20 | #include "../h/conf.h" | |
21 | #include "../h/dir.h" | |
22 | #include "../h/user.h" | |
23 | #include "../h/tty.h" | |
24 | #include "../h/map.h" | |
25 | #include "../h/pte.h" | |
26 | #include "../h/buf.h" | |
27 | #include "../h/vm.h" | |
7a17d042 SL |
28 | #include "../h/bk.h" |
29 | #include "../h/clist.h" | |
7a17d042 | 30 | #include "../h/file.h" |
740e4029 | 31 | #include "../h/uio.h" |
7a17d042 | 32 | |
896962b1 BJ |
33 | #include "../vaxuba/ubareg.h" |
34 | #include "../vaxuba/ubavar.h" | |
35 | ||
7a17d042 SL |
36 | /* |
37 | * Definition of the driver for the auto-configuration program. | |
38 | */ | |
39 | int dmfprobe(), dmfattach(), dmfrint(), dmfxint(); | |
40 | struct uba_device *dmfinfo[NDMF]; | |
41 | u_short dmfstd[] = { 0 }; | |
42 | struct uba_driver dmfdriver = | |
43 | { dmfprobe, 0, dmfattach, 0, dmfstd, "dmf", dmfinfo }; | |
44 | ||
45 | /* | |
46 | * In this driver, "dmf" (unqualified) refers to the async portion | |
47 | * of the dmf32, "dmfc" to the combo portion, "dmfs" to the sync | |
48 | * portion, "dmfl" to the lp portion, and "dmfd" to the dr portion. | |
49 | */ | |
50 | struct dmfdevice | |
51 | { | |
52 | short dmfccsr0; /* combo csr 0 */ | |
53 | short dmfccsr1; /* combo csr 1 */ | |
54 | short dmfs[4]; | |
55 | short dmfcsr; /* control-status register */ | |
56 | short dmflpr; /* line parameter register */ | |
57 | short dmfrbuf; /* receiver buffer (ro) */ | |
58 | union { | |
59 | u_short dmfirw; /* indirect register word */ | |
60 | u_char dmfirc[2]; /* " " bytes */ | |
61 | } dmfun; | |
62 | short dmfl[2]; | |
63 | short dmfd[4]; | |
64 | }; | |
65 | ||
66 | #define dmfrsp dmfrbuf /* receive silo parameter register (wo) */ | |
67 | #define dmftbuf dmfun.dmfirc[0] /* transmit buffer */ | |
68 | #define dmftsc dmfun.dmfirc[0] /* transmit silo count */ | |
69 | #define dmfrms dmfun.dmfirc[1] /* receive modem status */ | |
70 | #define dmflcr dmfun.dmfirc[0] /* line control register */ | |
71 | #define dmftms dmfun.dmfirc[1] /* transmit modem status */ | |
72 | #define dmftba dmfun.dmfirw /* transmit buffer address */ | |
73 | #define dmftcc dmfun.dmfirw /* transmit character count */ | |
74 | ||
75 | /* bits in dmfcsr */ | |
76 | #define DMF_TI 0100000 /* transmit interrupt */ | |
77 | #define DMF_TIE 0040000 /* transmit interrupt enable */ | |
78 | #define DMF_NXM 0020000 /* non-existant memory */ | |
79 | #define DMF_LIN 0003400 /* transmit line number */ | |
80 | #define DMF_RI 0000200 /* receiver interrupt */ | |
81 | #define DMF_RIE 0000100 /* receiver interrupt enable */ | |
82 | #define DMF_CLR 0000040 /* master reset */ | |
83 | #define DMF_IAD 0000037 /* indirect address register */ | |
84 | ||
85 | #define DMFIR_TBUF 000 /* select tbuf indirect register */ | |
86 | #define DMFIR_LCR 010 /* select lcr indirect register */ | |
87 | #define DMFIR_TBA 020 /* select tba indirect register */ | |
88 | #define DMFIR_TCC 030 /* select tcc indirect register */ | |
89 | ||
90 | /* bits in dmflpr */ | |
91 | #define BITS6 (01<<3) | |
92 | #define BITS7 (02<<3) | |
93 | #define BITS8 (03<<3) | |
94 | #define TWOSB 0200 | |
95 | #define PENABLE 040 | |
96 | /* DEC manuals incorrectly say this bit causes generation of even parity. */ | |
97 | #define OPAR 0100 | |
98 | ||
99 | #define DMF_IE (DMF_TIE|DMF_RIE) | |
100 | ||
101 | #define DMF_SILOCNT 32 /* size of DMF output silo (per line) */ | |
102 | ||
103 | /* bits in dmfrbuf */ | |
104 | #define DMF_DSC 0004000 /* data set change */ | |
105 | #define DMF_PE 0010000 /* parity error */ | |
106 | #define DMF_FE 0020000 /* framing error */ | |
107 | #define DMF_DO 0040000 /* data overrun */ | |
108 | ||
109 | /* bits in dmfrms */ | |
110 | #define DMF_USRR 0004 /* user modem signal (pin 25) */ | |
111 | #define DMF_SR 0010 /* secondary receive */ | |
112 | #define DMF_CTS 0020 /* clear to send */ | |
113 | #define DMF_CAR 0040 /* carrier detect */ | |
114 | #define DMF_RNG 0100 /* ring */ | |
115 | #define DMF_DSR 0200 /* data set ready */ | |
116 | ||
117 | /* bits in dmftms */ | |
118 | #define DMF_USRW 0001 /* user modem signal (pin 18) */ | |
119 | #define DMF_DTR 0002 /* data terminal ready */ | |
120 | #define DMF_RATE 0004 /* data signal rate select */ | |
121 | #define DMF_ST 0010 /* secondary transmit */ | |
122 | #define DMF_RTS 0020 /* request to send */ | |
123 | #define DMF_BRK 0040 /* pseudo break bit */ | |
124 | #define DMF_PREEMPT 0200 /* preempt output */ | |
125 | ||
126 | /* flags for modem control */ | |
127 | #define DMF_ON (DMF_DTR|DMF_RTS) | |
128 | #define DMF_OFF 0 | |
129 | ||
130 | /* bits in dmflcr */ | |
131 | #define DMF_MIE 0040 /* modem interrupt enable */ | |
132 | #define DMF_FLUSH 0020 /* flush transmit silo */ | |
133 | #define DMF_RBRK 0010 /* real break bit */ | |
134 | #define DMF_RE 0004 /* receive enable */ | |
135 | #define DMF_AUTOX 0002 /* auto XON/XOFF */ | |
136 | #define DMF_TE 0001 /* transmit enable */ | |
137 | ||
138 | #define DMFLCR_ENA (DMF_MIE|DMF_RE|DMF_TE) | |
139 | ||
140 | /* bits in dm lsr, copied from dh.c */ | |
141 | #define DML_USR 0001000 /* usr modem sig, not a real DM bit */ | |
142 | #define DML_DSR 0000400 /* data set ready, not a real DM bit */ | |
143 | #define DML_RNG 0000200 /* ring */ | |
144 | #define DML_CAR 0000100 /* carrier detect */ | |
145 | #define DML_CTS 0000040 /* clear to send */ | |
146 | #define DML_SR 0000020 /* secondary receive */ | |
147 | #define DML_ST 0000010 /* secondary transmit */ | |
148 | #define DML_RTS 0000004 /* request to send */ | |
149 | #define DML_DTR 0000002 /* data terminal ready */ | |
150 | #define DML_LE 0000001 /* line enable */ | |
151 | ||
152 | /* | |
153 | * Local variables for the driver | |
154 | */ | |
155 | char dmf_speeds[] = | |
156 | { 0, 0, 1, 2, 3, 4, 0, 5, 6, 7, 010, 012, 014, 016, 017, 0 }; | |
157 | ||
158 | struct tty dmf_tty[NDMF*8]; | |
159 | char dmfsoftCAR[NDMF]; | |
160 | int ndmf = NDMF*8; | |
161 | int dmfact; /* mask of active dmf's */ | |
162 | int dmfstart(), ttrstrt(); | |
163 | ||
164 | #ifdef DMFDMA | |
165 | /* | |
166 | * The clist space is mapped by the driver onto each UNIBUS. | |
167 | * The UBACVT macro converts a clist space address for unibus uban | |
168 | * into an i/o space address for the DMA routine. | |
169 | */ | |
170 | int dmf_ubinfo[MAXNUBA]; /* info about allocated unibus map */ | |
171 | static int cbase[MAXNUBA]; /* base address in unibus map */ | |
172 | #define UBACVT(x, uban) (cbase[uban] + ((x)-(char *)cfree)) | |
173 | #endif | |
174 | ||
175 | /* | |
176 | * Routine for configuration to set dmf interrupt. | |
177 | */ | |
178 | /*ARGSUSED*/ | |
179 | dmfprobe(reg, ctlr) | |
180 | caddr_t reg; | |
181 | int ctlr; | |
182 | { | |
183 | register int br, cvec; /* these are ``value-result'' */ | |
184 | register struct dmfdevice *dmfaddr = (struct dmfdevice *)reg; | |
185 | ||
186 | #ifdef lint | |
187 | br = 0; cvec = br; br = cvec; | |
188 | #endif | |
189 | br = 0x15; | |
190 | cvec = (uba_hd[numuba].uh_lastiv -= 4*8); | |
191 | dmfaddr->dmfccsr0 = cvec >> 2; | |
192 | /* NEED TO SAVE IT SOMEWHERE FOR OTHER DEVICES */ | |
9c0adba0 | 193 | return (sizeof (struct dmfdevice)); |
7a17d042 SL |
194 | } |
195 | ||
196 | /* | |
197 | * Routine called to attach a dmf. | |
198 | */ | |
199 | dmfattach(ui) | |
200 | struct uba_device *ui; | |
201 | { | |
202 | ||
203 | dmfsoftCAR[ui->ui_unit] = ui->ui_flags; | |
204 | } | |
205 | ||
206 | ||
207 | /* | |
208 | * Open a DMF32 line, mapping the clist onto the uba if this | |
209 | * is the first dmf on this uba. Turn on this dmf if this is | |
210 | * the first use of it. | |
211 | */ | |
212 | /*ARGSUSED*/ | |
213 | dmfopen(dev, flag) | |
214 | dev_t dev; | |
215 | { | |
216 | register struct tty *tp; | |
217 | register int unit, dmf; | |
218 | register struct dmfdevice *addr; | |
219 | register struct uba_device *ui; | |
220 | int s; | |
221 | ||
222 | unit = minor(dev); | |
223 | dmf = unit >> 3; | |
7da157da BJ |
224 | if (unit >= NDMF*8 || (ui = dmfinfo[dmf])== 0 || ui->ui_alive == 0) |
225 | return (ENXIO); | |
7a17d042 | 226 | tp = &dmf_tty[unit]; |
7da157da BJ |
227 | if (tp->t_state&TS_XCLUDE && u.u_uid!=0) |
228 | return (EBUSY); | |
7a17d042 SL |
229 | addr = (struct dmfdevice *)ui->ui_addr; |
230 | tp->t_addr = (caddr_t)addr; | |
231 | tp->t_oproc = dmfstart; | |
c38b985f | 232 | tp->t_state |= TS_WOPEN; |
7a17d042 SL |
233 | /* |
234 | * While setting up state for this uba and this dmf, | |
235 | * block uba resets which can clear the state. | |
236 | */ | |
237 | s = spl5(); | |
238 | #ifdef DMFDMA | |
239 | if (dmf_ubinfo[ui->ui_ubanum] == 0) { | |
240 | dmf_ubinfo[ui->ui_ubanum] = | |
241 | uballoc(ui->ui_ubanum, (caddr_t)cfree, | |
242 | nclist*sizeof(struct cblock), 0); | |
243 | cbase[ui->ui_ubanum] = dmf_ubinfo[ui->ui_ubanum]&0x3ffff; | |
244 | } | |
245 | #endif | |
246 | if ((dmfact&(1<<dmf)) == 0) { | |
247 | addr->dmfcsr |= DMF_IE; | |
248 | dmfact |= (1<<dmf); | |
249 | addr->dmfrsp = 1; /* DON'T KNOW WHAT TO SET IT TO YET */ | |
250 | } | |
251 | splx(s); | |
252 | /* | |
253 | * If this is first open, initialze tty state to default. | |
254 | */ | |
c38b985f | 255 | if ((tp->t_state&TS_ISOPEN) == 0) { |
7a17d042 SL |
256 | ttychars(tp); |
257 | if (tp->t_ispeed == 0) { | |
258 | tp->t_ispeed = B300; | |
259 | tp->t_ospeed = B300; | |
260 | tp->t_flags = ODDP|EVENP|ECHO; | |
261 | } | |
262 | dmfparam(unit); | |
263 | } | |
264 | /* | |
265 | * Wait for carrier, then process line discipline specific open. | |
266 | */ | |
267 | if ((dmfmctl(dev, DMF_ON, DMSET) & (DMF_CAR<<8)) || | |
268 | (dmfsoftCAR[dmf] & (1<<(unit&07)))) | |
c38b985f | 269 | tp->t_state |= TS_CARR_ON; |
7a17d042 | 270 | s = spl5(); |
c38b985f SL |
271 | while ((tp->t_state & TS_CARR_ON) == 0) { |
272 | tp->t_state |= TS_WOPEN; | |
7a17d042 SL |
273 | sleep((caddr_t)&tp->t_rawq, TTIPRI); |
274 | } | |
275 | splx(s); | |
7da157da | 276 | return ((*linesw[tp->t_line].l_open)(dev, tp)); |
7a17d042 SL |
277 | } |
278 | ||
279 | /* | |
280 | * Close a DMF32 line. | |
281 | */ | |
282 | /*ARGSUSED*/ | |
283 | dmfclose(dev, flag) | |
284 | dev_t dev; | |
285 | int flag; | |
286 | { | |
287 | register struct tty *tp; | |
288 | register unit; | |
289 | ||
290 | unit = minor(dev); | |
291 | tp = &dmf_tty[unit]; | |
292 | (*linesw[tp->t_line].l_close)(tp); | |
6e7edb25 | 293 | (void) dmfmctl(unit, DMF_BRK, DMBIC); |
c38b985f | 294 | if (tp->t_state&TS_HUPCLS || (tp->t_state&TS_ISOPEN)==0) |
6e7edb25 | 295 | (void) dmfmctl(unit, DMF_OFF, DMSET); |
7a17d042 SL |
296 | ttyclose(tp); |
297 | } | |
298 | ||
740e4029 | 299 | dmfread(dev, uio) |
7a17d042 | 300 | dev_t dev; |
740e4029 | 301 | struct uio *uio; |
7a17d042 SL |
302 | { |
303 | register struct tty *tp; | |
304 | ||
305 | tp = &dmf_tty[minor(dev)]; | |
740e4029 | 306 | return ((*linesw[tp->t_line].l_read)(tp, uio)); |
7a17d042 SL |
307 | } |
308 | ||
406ddcbe | 309 | dmfwrite(dev, uio) |
7a17d042 | 310 | dev_t dev; |
406ddcbe | 311 | struct uio *uio; |
7a17d042 SL |
312 | { |
313 | register struct tty *tp; | |
314 | ||
315 | tp = &dmf_tty[minor(dev)]; | |
078d920f | 316 | return ((*linesw[tp->t_line].l_write)(tp, uio)); |
7a17d042 SL |
317 | } |
318 | ||
319 | /* | |
320 | * DMF32 receiver interrupt. | |
321 | */ | |
322 | dmfrint(dmf) | |
323 | int dmf; | |
324 | { | |
325 | register struct tty *tp; | |
326 | register c; | |
327 | register struct dmfdevice *addr; | |
328 | register struct tty *tp0; | |
329 | register struct uba_device *ui; | |
330 | int overrun = 0; | |
331 | ||
332 | ui = dmfinfo[dmf]; | |
333 | if (ui == 0 || ui->ui_alive == 0) | |
334 | return; | |
335 | addr = (struct dmfdevice *)ui->ui_addr; | |
336 | tp0 = &dmf_tty[dmf<<3]; | |
337 | /* | |
338 | * Loop fetching characters from the silo for this | |
339 | * dmf until there are no more in the silo. | |
340 | */ | |
341 | while ((c = addr->dmfrbuf) < 0) { | |
342 | tp = tp0 + ((c>>8)&07); | |
343 | if (c & DMF_DSC) { | |
344 | addr->dmfcsr = DMF_IE | DMFIR_TBUF | ((c>>8)&07); | |
345 | if (addr->dmfrms & DMF_CAR) { | |
c38b985f | 346 | if ((tp->t_state & TS_CARR_ON) == 0) { |
7a17d042 | 347 | wakeup((caddr_t)&tp->t_rawq); |
c38b985f | 348 | tp->t_state |= TS_CARR_ON; |
7a17d042 SL |
349 | } |
350 | } else { | |
c38b985f | 351 | if (tp->t_state & TS_CARR_ON) { |
7a17d042 SL |
352 | gsignal(tp->t_pgrp, SIGHUP); |
353 | gsignal(tp->t_pgrp, SIGCONT); | |
354 | addr->dmfcsr = DMF_IE | DMFIR_LCR | | |
355 | ((c>>8)&07); | |
356 | addr->dmftms = 0; | |
357 | flushtty(tp, FREAD|FWRITE); | |
358 | } | |
c38b985f | 359 | tp->t_state &= ~TS_CARR_ON; |
7a17d042 SL |
360 | } |
361 | continue; | |
362 | } | |
c38b985f | 363 | if ((tp->t_state&TS_ISOPEN)==0) { |
7a17d042 SL |
364 | wakeup((caddr_t)tp); |
365 | continue; | |
366 | } | |
367 | if (c & DMF_PE) | |
368 | if ((tp->t_flags&(EVENP|ODDP))==EVENP | |
369 | || (tp->t_flags&(EVENP|ODDP))==ODDP ) | |
370 | continue; | |
371 | if ((c & DMF_DO) && overrun == 0) { | |
372 | printf("dmf%d: silo overflow\n", dmf); | |
373 | overrun = 1; | |
374 | } | |
375 | if (c & DMF_FE) | |
376 | /* | |
377 | * At framing error (break) generate | |
378 | * a null (in raw mode, for getty), or a | |
379 | * interrupt (in cooked/cbreak mode). | |
380 | */ | |
381 | if (tp->t_flags&RAW) | |
382 | c = 0; | |
383 | else | |
384 | c = tun.t_intrc; | |
385 | #if NBK > 0 | |
386 | if (tp->t_line == NETLDISC) { | |
387 | c &= 0177; | |
388 | BKINPUT(c, tp); | |
389 | } else | |
390 | #endif | |
391 | (*linesw[tp->t_line].l_rint)(c, tp); | |
392 | } | |
393 | } | |
394 | ||
395 | /* | |
396 | * Ioctl for DMF32. | |
397 | */ | |
398 | /*ARGSUSED*/ | |
942f05a9 | 399 | dmfioctl(dev, cmd, data, flag) |
7a17d042 | 400 | dev_t dev; |
942f05a9 | 401 | caddr_t data; |
7a17d042 SL |
402 | { |
403 | register struct tty *tp; | |
404 | register int unit = minor(dev); | |
7da157da | 405 | int error; |
7a17d042 SL |
406 | |
407 | tp = &dmf_tty[unit]; | |
7da157da BJ |
408 | error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag); |
409 | if (error >= 0) | |
410 | return (error); | |
411 | error = ttioctl(tp, cmd, data, flag); | |
412 | if (error >= 0) { | |
942f05a9 | 413 | if (cmd == TIOCSETP || cmd == TIOCSETN) |
7a17d042 | 414 | dmfparam(unit); |
7da157da BJ |
415 | return (error); |
416 | } | |
417 | switch (cmd) { | |
7a17d042 SL |
418 | |
419 | case TIOCSBRK: | |
6e7edb25 | 420 | (void) dmfmctl(dev, DMF_BRK, DMBIS); |
7a17d042 | 421 | break; |
942f05a9 | 422 | |
7a17d042 | 423 | case TIOCCBRK: |
6e7edb25 | 424 | (void) dmfmctl(dev, DMF_BRK, DMBIC); |
7a17d042 | 425 | break; |
942f05a9 | 426 | |
7a17d042 | 427 | case TIOCSDTR: |
6e7edb25 | 428 | (void) dmfmctl(dev, DMF_DTR|DMF_RTS, DMBIS); |
7a17d042 | 429 | break; |
942f05a9 | 430 | |
7a17d042 | 431 | case TIOCCDTR: |
6e7edb25 | 432 | (void) dmfmctl(dev, DMF_DTR|DMF_RTS, DMBIC); |
7a17d042 | 433 | break; |
942f05a9 | 434 | |
7a17d042 | 435 | case TIOCMSET: |
6e7edb25 | 436 | (void) dmfmctl(dev, dmtodmf(*(int *)data), DMSET); |
7a17d042 | 437 | break; |
942f05a9 | 438 | |
7a17d042 | 439 | case TIOCMBIS: |
6e7edb25 | 440 | (void) dmfmctl(dev, dmtodmf(*(int *)data), DMBIS); |
7a17d042 | 441 | break; |
942f05a9 | 442 | |
7a17d042 | 443 | case TIOCMBIC: |
6e7edb25 | 444 | (void) dmfmctl(dev, dmtodmf(*(int *)data), DMBIC); |
7a17d042 | 445 | break; |
942f05a9 | 446 | |
7a17d042 | 447 | case TIOCMGET: |
942f05a9 | 448 | *(int *)data = dmftodm(dmfmctl(dev, 0, DMGET)); |
7a17d042 | 449 | break; |
942f05a9 | 450 | |
7a17d042 | 451 | default: |
7da157da | 452 | return (ENOTTY); |
7a17d042 | 453 | } |
7da157da | 454 | return (0); |
7a17d042 SL |
455 | } |
456 | ||
457 | dmtodmf(bits) | |
458 | register int bits; | |
459 | { | |
460 | register int b; | |
461 | ||
462 | b = bits & 012; | |
463 | if (bits & DML_ST) b |= DMF_RATE; | |
464 | if (bits & DML_RTS) b |= DMF_RTS; | |
465 | if (bits & DML_USR) b |= DMF_USRW; | |
466 | return(b); | |
467 | } | |
468 | ||
469 | dmftodm(bits) | |
470 | register int bits; | |
471 | { | |
472 | register int b; | |
473 | ||
474 | b = (bits & 012) | ((bits >> 7) & 0760) | DML_LE; | |
475 | if (bits & DMF_USRR) b |= DML_USR; | |
476 | if (bits & DMF_RTS) b |= DML_RTS; | |
477 | return(b); | |
478 | } | |
479 | ||
480 | ||
481 | /* | |
482 | * Set parameters from open or stty into the DMF hardware | |
483 | * registers. | |
484 | */ | |
485 | dmfparam(unit) | |
486 | register int unit; | |
487 | { | |
488 | register struct tty *tp; | |
489 | register struct dmfdevice *addr; | |
490 | register int lpar, lcr; | |
491 | int s; | |
492 | ||
493 | tp = &dmf_tty[unit]; | |
494 | addr = (struct dmfdevice *)tp->t_addr; | |
495 | /* | |
496 | * Block interrupts so parameters will be set | |
497 | * before the line interrupts. | |
498 | */ | |
499 | s = spl5(); | |
500 | addr->dmfcsr = (unit&07) | DMFIR_LCR | DMF_IE; | |
501 | if ((tp->t_ispeed)==0) { | |
c38b985f | 502 | tp->t_state |= TS_HUPCLS; |
6e7edb25 | 503 | (void) dmfmctl(unit, DMF_OFF, DMSET); |
7a17d042 SL |
504 | return; |
505 | } | |
506 | lpar = (dmf_speeds[tp->t_ospeed]<<12) | (dmf_speeds[tp->t_ispeed]<<8); | |
507 | lcr = DMFLCR_ENA; | |
508 | if ((tp->t_ispeed) == B134) | |
509 | lpar |= BITS6|PENABLE; | |
510 | else if ((tp->t_flags&RAW) || (tp->t_local&LLITOUT)) | |
511 | lpar |= BITS8; | |
512 | else { | |
513 | lpar |= BITS7|PENABLE; | |
514 | /* CHECK FOR XON/XOFF AND SET lcr |= DMF_AUTOX; */ | |
515 | } | |
516 | if ((tp->t_flags&EVENP) == 0) | |
517 | lpar |= OPAR; | |
518 | if ((tp->t_ospeed) == B110) | |
519 | lpar |= TWOSB; | |
520 | lpar |= (unit&07); | |
521 | addr->dmflpr = lpar; | |
522 | addr->dmflcr = lcr; | |
523 | splx(s); | |
524 | } | |
525 | ||
526 | /* | |
527 | * DMF32 transmitter interrupt. | |
528 | * Restart the idle line. | |
529 | */ | |
530 | dmfxint(dmf) | |
531 | int dmf; | |
532 | { | |
533 | register struct tty *tp; | |
534 | register struct dmfdevice *addr; | |
535 | register struct uba_device *ui; | |
536 | register int unit, t; | |
537 | #ifdef DMFDMA | |
538 | short cntr; | |
539 | #endif | |
540 | ||
541 | ui = dmfinfo[dmf]; | |
542 | addr = (struct dmfdevice *)ui->ui_addr; | |
543 | while ((t = addr->dmfcsr) & DMF_TI) { | |
544 | unit = dmf*8 + ((t>>8)&07); | |
545 | tp = &dmf_tty[unit]; | |
c38b985f | 546 | tp->t_state &= ~TS_BUSY; |
7a17d042 SL |
547 | if (t & DMF_NXM) { |
548 | printf("dmf%d: NXM line %d\n", dmf, unit&7); | |
549 | /* SHOULD RESTART OR SOMETHING... */ | |
550 | } | |
c38b985f SL |
551 | if (tp->t_state&TS_FLUSH) |
552 | tp->t_state &= ~TS_FLUSH; | |
7a17d042 SL |
553 | #ifdef DMFDMA |
554 | else { | |
555 | addr->dmfcsr = DMFIR_TBUF | DMF_IE | (unit&07); | |
556 | if (addr->dmftsc == 0) { | |
557 | /* | |
558 | * Do arithmetic in a short to make up | |
559 | * for lost 16&17 bits. | |
560 | */ | |
561 | addr->dmfcsr = DMFIR_TBA | DMF_IE | (unit&07); | |
562 | cntr = addr->dmftba - | |
563 | UBACVT(tp->t_outq.c_cf, ui->ui_ubanum); | |
564 | ndflush(&tp->t_outq, (int)cntr); | |
565 | } | |
566 | } | |
567 | #endif | |
568 | if (tp->t_line) | |
569 | (*linesw[tp->t_line].l_start)(tp); | |
570 | else | |
571 | dmfstart(tp); | |
572 | } | |
573 | } | |
574 | ||
575 | /* | |
576 | * Start (restart) transmission on the given DMF32 line. | |
577 | */ | |
578 | dmfstart(tp) | |
579 | register struct tty *tp; | |
580 | { | |
581 | register struct dmfdevice *addr; | |
bc3a8383 | 582 | register int unit, nch; |
7a17d042 SL |
583 | int s; |
584 | ||
585 | unit = minor(tp->t_dev); | |
7a17d042 SL |
586 | unit &= 07; |
587 | addr = (struct dmfdevice *)tp->t_addr; | |
588 | ||
589 | /* | |
590 | * Must hold interrupts in following code to prevent | |
591 | * state of the tp from changing. | |
592 | */ | |
593 | s = spl5(); | |
594 | /* | |
595 | * If it's currently active, or delaying, no need to do anything. | |
596 | */ | |
c38b985f | 597 | if (tp->t_state&(TS_TIMEOUT|TS_BUSY|TS_TTSTOP)) |
7a17d042 SL |
598 | goto out; |
599 | /* | |
600 | * If there are still characters in the silo, | |
601 | * just reenable the transmitter. | |
602 | */ | |
603 | addr->dmfcsr = DMF_IE | DMFIR_TBUF | unit; | |
604 | if (addr->dmftsc) { | |
605 | addr->dmfcsr = DMF_IE | DMFIR_LCR | unit; | |
606 | addr->dmflcr |= DMF_TE; | |
c38b985f | 607 | tp->t_state |= TS_BUSY; |
7a17d042 SL |
608 | goto out; |
609 | } | |
610 | /* | |
611 | * If there are sleepers, and output has drained below low | |
612 | * water mark, wake up the sleepers. | |
613 | */ | |
c38b985f SL |
614 | if ((tp->t_state&TS_ASLEEP) && tp->t_outq.c_cc<=TTLOWAT(tp)) { |
615 | tp->t_state &= ~TS_ASLEEP; | |
e9c71764 | 616 | wakeup((caddr_t)&tp->t_outq); |
7a17d042 SL |
617 | } |
618 | /* | |
619 | * Now restart transmission unless the output queue is | |
620 | * empty. | |
621 | */ | |
622 | if (tp->t_outq.c_cc == 0) | |
623 | goto out; | |
624 | if (tp->t_flags&RAW || tp->t_local&LLITOUT) | |
625 | nch = ndqb(&tp->t_outq, 0); | |
626 | else { | |
627 | nch = ndqb(&tp->t_outq, 0200); | |
628 | /* | |
629 | * If first thing on queue is a delay process it. | |
630 | */ | |
631 | if (nch == 0) { | |
632 | nch = getc(&tp->t_outq); | |
633 | timeout(ttrstrt, (caddr_t)tp, (nch&0x7f)+6); | |
c38b985f | 634 | tp->t_state |= TS_TIMEOUT; |
7a17d042 SL |
635 | goto out; |
636 | } | |
637 | } | |
638 | /* | |
639 | * If characters to transmit, restart transmission. | |
640 | */ | |
641 | if (nch) { | |
642 | #ifdef DMFDMA | |
643 | addr->dmfcsr = DMF_IE | DMFIR_LCR | unit; | |
644 | addr->dmflcr |= DMF_TE; | |
645 | car = UBACVT(tp->t_outq.c_cf, dmfinfo[dmf]->ui_ubanum); | |
646 | addr->dmfcsr = DMF_IE | DMFIR_TBA | unit; | |
647 | addr->dmftba = car; | |
648 | addr->dmftcc = ((car>>2)&0xc000) | nch; | |
649 | #else | |
650 | register char *cp = tp->t_outq.c_cf; | |
651 | register int i; | |
652 | ||
653 | nch = MIN(nch, DMF_SILOCNT); | |
654 | addr->dmfcsr = DMF_IE | DMFIR_LCR | unit; | |
655 | addr->dmflcr |= DMF_TE; | |
656 | addr->dmfcsr = DMF_IE | DMFIR_TBUF | unit; | |
657 | for (i = 0; i < nch; i++) | |
658 | addr->dmftbuf = *cp++; | |
659 | ndflush(&tp->t_outq, nch); | |
660 | #endif | |
c38b985f | 661 | tp->t_state |= TS_BUSY; |
7a17d042 SL |
662 | } |
663 | out: | |
664 | splx(s); | |
665 | } | |
666 | ||
667 | /* | |
668 | * Stop output on a line, e.g. for ^S/^Q or output flush. | |
669 | */ | |
670 | /*ARGSUSED*/ | |
671 | dmfstop(tp, flag) | |
672 | register struct tty *tp; | |
673 | { | |
674 | register struct dmfdevice *addr; | |
675 | register int unit, s; | |
676 | ||
677 | addr = (struct dmfdevice *)tp->t_addr; | |
678 | /* | |
679 | * Block input/output interrupts while messing with state. | |
680 | */ | |
681 | s = spl5(); | |
c38b985f | 682 | if (tp->t_state & TS_BUSY) { |
7a17d042 SL |
683 | /* |
684 | * Device is transmitting; stop output | |
685 | * by selecting the line and disabling | |
686 | * the transmitter. If this is a flush | |
687 | * request then flush the output silo, | |
688 | * otherwise we will pick up where we | |
689 | * left off by enabling the transmitter. | |
690 | */ | |
691 | unit = minor(tp->t_dev); | |
692 | addr->dmfcsr = DMFIR_LCR | (unit&07) | DMF_IE; | |
693 | addr->dmflcr &= ~DMF_TE; | |
c38b985f SL |
694 | if ((tp->t_state&TS_TTSTOP)==0) { |
695 | tp->t_state |= TS_FLUSH; | |
7a17d042 SL |
696 | addr->dmflcr |= DMF_FLUSH; |
697 | } else | |
c38b985f | 698 | tp->t_state &= ~TS_BUSY; |
7a17d042 SL |
699 | } |
700 | splx(s); | |
701 | } | |
702 | ||
703 | /* | |
704 | * DMF32 modem control | |
705 | */ | |
706 | dmfmctl(dev, bits, how) | |
707 | dev_t dev; | |
708 | int bits, how; | |
709 | { | |
710 | register struct dmfdevice *dmfaddr; | |
711 | register int unit, mbits, lcr; | |
712 | int s; | |
713 | ||
714 | unit = minor(dev); | |
715 | dmfaddr = (struct dmfdevice *)(dmf_tty[unit].t_addr); | |
716 | unit &= 07; | |
717 | s = spl5(); | |
718 | dmfaddr->dmfcsr = DMF_IE | DMFIR_TBUF | unit; | |
719 | mbits = dmfaddr->dmfrms << 8; | |
720 | dmfaddr->dmfcsr = DMF_IE | DMFIR_LCR | unit; | |
721 | mbits |= dmfaddr->dmftms; | |
722 | lcr = dmfaddr->dmflcr; | |
723 | switch (how) { | |
724 | case DMSET: | |
725 | mbits = bits; | |
726 | break; | |
727 | ||
728 | case DMBIS: | |
729 | mbits |= bits; | |
730 | break; | |
731 | ||
732 | case DMBIC: | |
733 | mbits &= ~bits; | |
734 | break; | |
735 | ||
736 | case DMGET: | |
737 | (void) splx(s); | |
738 | return(mbits); | |
739 | } | |
740 | dmfaddr->dmftms = mbits&037; | |
741 | if (mbits & DMF_BRK) | |
742 | lcr |= DMF_RBRK; | |
743 | else | |
744 | lcr &= ~DMF_RBRK; | |
745 | dmfaddr->dmflcr = lcr; | |
746 | (void) splx(s); | |
747 | return(mbits); | |
748 | } | |
749 | ||
750 | /* | |
751 | * Reset state of driver if UBA reset was necessary. | |
752 | * Reset the csr, lpr, and lcr registers on open lines, and | |
753 | * restart transmitters. | |
754 | */ | |
755 | dmfreset(uban) | |
756 | int uban; | |
757 | { | |
758 | register int dmf, unit; | |
759 | register struct tty *tp; | |
760 | register struct uba_device *ui; | |
761 | register struct dmfdevice *addr; | |
762 | int i; | |
763 | ||
764 | #ifdef DMFDMA | |
765 | if (dmf_ubinfo[uban] == 0) | |
766 | return; | |
7a17d042 SL |
767 | dmf_ubinfo[uban] = uballoc(uban, (caddr_t)cfree, |
768 | nclist*sizeof (struct cblock), 0); | |
769 | cbase[uban] = dmf_ubinfo[uban]&0x3ffff; | |
770 | #endif | |
771 | for (dmf = 0; dmf < NDMF; dmf++) { | |
772 | ui = dmfinfo[dmf]; | |
773 | if (ui == 0 || ui->ui_alive == 0 || ui->ui_ubanum != uban) | |
774 | continue; | |
775 | printf(" dmf%d", dmf); | |
776 | addr = (struct dmfdevice *)ui->ui_addr; | |
777 | addr->dmfcsr = DMF_IE; | |
778 | addr->dmfrsp = 1; | |
779 | unit = dmf * 8; | |
780 | for (i = 0; i < 8; i++) { | |
781 | tp = &dmf_tty[unit]; | |
c38b985f | 782 | if (tp->t_state & (TS_ISOPEN|TS_WOPEN)) { |
7a17d042 | 783 | dmfparam(unit); |
6e7edb25 | 784 | (void) dmfmctl(unit, DMF_ON, DMSET); |
c38b985f | 785 | tp->t_state &= ~TS_BUSY; |
7a17d042 SL |
786 | dmfstart(tp); |
787 | } | |
788 | unit++; | |
789 | } | |
790 | } | |
791 | } | |
792 | ||
793 | /* stubs for interrupt routines for devices not yet supported */ | |
794 | ||
795 | dmfsrint() { printf("dmfsrint\n"); } | |
796 | ||
797 | dmfsxint() { printf("dmfsxint\n"); } | |
798 | ||
799 | dmfdaint() { printf("dmfdaint\n"); } | |
800 | ||
801 | dmfdbint() { printf("dmfdbint\n"); } | |
802 | ||
803 | dmflint() { printf("dmflint\n"); } | |
804 | #endif |