Commit | Line | Data |
---|---|---|
896962b1 | 1 | /* dmf.c 4.8 82/10/10 */ |
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; | |
224 | if (unit >= NDMF*8 || (ui = dmfinfo[dmf])== 0 || ui->ui_alive == 0) { | |
225 | u.u_error = ENXIO; | |
226 | return; | |
227 | } | |
228 | tp = &dmf_tty[unit]; | |
c38b985f | 229 | if (tp->t_state&TS_XCLUDE && u.u_uid!=0) { |
7a17d042 SL |
230 | u.u_error = EBUSY; |
231 | return; | |
232 | } | |
233 | addr = (struct dmfdevice *)ui->ui_addr; | |
234 | tp->t_addr = (caddr_t)addr; | |
235 | tp->t_oproc = dmfstart; | |
c38b985f | 236 | tp->t_state |= TS_WOPEN; |
7a17d042 SL |
237 | /* |
238 | * While setting up state for this uba and this dmf, | |
239 | * block uba resets which can clear the state. | |
240 | */ | |
241 | s = spl5(); | |
242 | #ifdef DMFDMA | |
243 | if (dmf_ubinfo[ui->ui_ubanum] == 0) { | |
244 | dmf_ubinfo[ui->ui_ubanum] = | |
245 | uballoc(ui->ui_ubanum, (caddr_t)cfree, | |
246 | nclist*sizeof(struct cblock), 0); | |
247 | cbase[ui->ui_ubanum] = dmf_ubinfo[ui->ui_ubanum]&0x3ffff; | |
248 | } | |
249 | #endif | |
250 | if ((dmfact&(1<<dmf)) == 0) { | |
251 | addr->dmfcsr |= DMF_IE; | |
252 | dmfact |= (1<<dmf); | |
253 | addr->dmfrsp = 1; /* DON'T KNOW WHAT TO SET IT TO YET */ | |
254 | } | |
255 | splx(s); | |
256 | /* | |
257 | * If this is first open, initialze tty state to default. | |
258 | */ | |
c38b985f | 259 | if ((tp->t_state&TS_ISOPEN) == 0) { |
7a17d042 SL |
260 | ttychars(tp); |
261 | if (tp->t_ispeed == 0) { | |
262 | tp->t_ispeed = B300; | |
263 | tp->t_ospeed = B300; | |
264 | tp->t_flags = ODDP|EVENP|ECHO; | |
265 | } | |
266 | dmfparam(unit); | |
267 | } | |
268 | /* | |
269 | * Wait for carrier, then process line discipline specific open. | |
270 | */ | |
271 | if ((dmfmctl(dev, DMF_ON, DMSET) & (DMF_CAR<<8)) || | |
272 | (dmfsoftCAR[dmf] & (1<<(unit&07)))) | |
c38b985f | 273 | tp->t_state |= TS_CARR_ON; |
7a17d042 | 274 | s = spl5(); |
c38b985f SL |
275 | while ((tp->t_state & TS_CARR_ON) == 0) { |
276 | tp->t_state |= TS_WOPEN; | |
7a17d042 SL |
277 | sleep((caddr_t)&tp->t_rawq, TTIPRI); |
278 | } | |
279 | splx(s); | |
280 | (*linesw[tp->t_line].l_open)(dev, tp); | |
281 | } | |
282 | ||
283 | /* | |
284 | * Close a DMF32 line. | |
285 | */ | |
286 | /*ARGSUSED*/ | |
287 | dmfclose(dev, flag) | |
288 | dev_t dev; | |
289 | int flag; | |
290 | { | |
291 | register struct tty *tp; | |
292 | register unit; | |
293 | ||
294 | unit = minor(dev); | |
295 | tp = &dmf_tty[unit]; | |
296 | (*linesw[tp->t_line].l_close)(tp); | |
297 | dmfmctl(unit, DMF_BRK, DMBIC); | |
c38b985f | 298 | if (tp->t_state&TS_HUPCLS || (tp->t_state&TS_ISOPEN)==0) |
7a17d042 SL |
299 | dmfmctl(unit, DMF_OFF, DMSET); |
300 | ttyclose(tp); | |
301 | } | |
302 | ||
740e4029 | 303 | dmfread(dev, uio) |
7a17d042 | 304 | dev_t dev; |
740e4029 | 305 | struct uio *uio; |
7a17d042 SL |
306 | { |
307 | register struct tty *tp; | |
308 | ||
309 | tp = &dmf_tty[minor(dev)]; | |
740e4029 | 310 | return ((*linesw[tp->t_line].l_read)(tp, uio)); |
7a17d042 SL |
311 | } |
312 | ||
406ddcbe | 313 | dmfwrite(dev, uio) |
7a17d042 | 314 | dev_t dev; |
406ddcbe | 315 | struct uio *uio; |
7a17d042 SL |
316 | { |
317 | register struct tty *tp; | |
318 | ||
319 | tp = &dmf_tty[minor(dev)]; | |
406ddcbe | 320 | (*linesw[tp->t_line].l_write)(tp, uio); |
7a17d042 SL |
321 | } |
322 | ||
323 | /* | |
324 | * DMF32 receiver interrupt. | |
325 | */ | |
326 | dmfrint(dmf) | |
327 | int dmf; | |
328 | { | |
329 | register struct tty *tp; | |
330 | register c; | |
331 | register struct dmfdevice *addr; | |
332 | register struct tty *tp0; | |
333 | register struct uba_device *ui; | |
334 | int overrun = 0; | |
335 | ||
336 | ui = dmfinfo[dmf]; | |
337 | if (ui == 0 || ui->ui_alive == 0) | |
338 | return; | |
339 | addr = (struct dmfdevice *)ui->ui_addr; | |
340 | tp0 = &dmf_tty[dmf<<3]; | |
341 | /* | |
342 | * Loop fetching characters from the silo for this | |
343 | * dmf until there are no more in the silo. | |
344 | */ | |
345 | while ((c = addr->dmfrbuf) < 0) { | |
346 | tp = tp0 + ((c>>8)&07); | |
347 | if (c & DMF_DSC) { | |
348 | addr->dmfcsr = DMF_IE | DMFIR_TBUF | ((c>>8)&07); | |
349 | if (addr->dmfrms & DMF_CAR) { | |
c38b985f | 350 | if ((tp->t_state & TS_CARR_ON) == 0) { |
7a17d042 | 351 | wakeup((caddr_t)&tp->t_rawq); |
c38b985f | 352 | tp->t_state |= TS_CARR_ON; |
7a17d042 SL |
353 | } |
354 | } else { | |
c38b985f | 355 | if (tp->t_state & TS_CARR_ON) { |
7a17d042 SL |
356 | gsignal(tp->t_pgrp, SIGHUP); |
357 | gsignal(tp->t_pgrp, SIGCONT); | |
358 | addr->dmfcsr = DMF_IE | DMFIR_LCR | | |
359 | ((c>>8)&07); | |
360 | addr->dmftms = 0; | |
361 | flushtty(tp, FREAD|FWRITE); | |
362 | } | |
c38b985f | 363 | tp->t_state &= ~TS_CARR_ON; |
7a17d042 SL |
364 | } |
365 | continue; | |
366 | } | |
c38b985f | 367 | if ((tp->t_state&TS_ISOPEN)==0) { |
7a17d042 SL |
368 | wakeup((caddr_t)tp); |
369 | continue; | |
370 | } | |
371 | if (c & DMF_PE) | |
372 | if ((tp->t_flags&(EVENP|ODDP))==EVENP | |
373 | || (tp->t_flags&(EVENP|ODDP))==ODDP ) | |
374 | continue; | |
375 | if ((c & DMF_DO) && overrun == 0) { | |
376 | printf("dmf%d: silo overflow\n", dmf); | |
377 | overrun = 1; | |
378 | } | |
379 | if (c & DMF_FE) | |
380 | /* | |
381 | * At framing error (break) generate | |
382 | * a null (in raw mode, for getty), or a | |
383 | * interrupt (in cooked/cbreak mode). | |
384 | */ | |
385 | if (tp->t_flags&RAW) | |
386 | c = 0; | |
387 | else | |
388 | c = tun.t_intrc; | |
389 | #if NBK > 0 | |
390 | if (tp->t_line == NETLDISC) { | |
391 | c &= 0177; | |
392 | BKINPUT(c, tp); | |
393 | } else | |
394 | #endif | |
395 | (*linesw[tp->t_line].l_rint)(c, tp); | |
396 | } | |
397 | } | |
398 | ||
399 | /* | |
400 | * Ioctl for DMF32. | |
401 | */ | |
402 | /*ARGSUSED*/ | |
942f05a9 | 403 | dmfioctl(dev, cmd, data, flag) |
7a17d042 | 404 | dev_t dev; |
942f05a9 | 405 | caddr_t data; |
7a17d042 SL |
406 | { |
407 | register struct tty *tp; | |
408 | register int unit = minor(dev); | |
409 | register int dmf = unit >> 3; | |
410 | register struct device *dmfaddr; | |
7a17d042 SL |
411 | |
412 | tp = &dmf_tty[unit]; | |
942f05a9 | 413 | cmd = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag); |
7a17d042 SL |
414 | if (cmd == 0) |
415 | return; | |
942f05a9 SL |
416 | if (ttioctl(tp, cmd, data, flag)) { |
417 | if (cmd == TIOCSETP || cmd == TIOCSETN) | |
7a17d042 SL |
418 | dmfparam(unit); |
419 | } else switch(cmd) { | |
420 | ||
421 | case TIOCSBRK: | |
422 | dmfmctl(dev, DMF_BRK, DMBIS); | |
423 | break; | |
942f05a9 | 424 | |
7a17d042 SL |
425 | case TIOCCBRK: |
426 | dmfmctl(dev, DMF_BRK, DMBIC); | |
427 | break; | |
942f05a9 | 428 | |
7a17d042 SL |
429 | case TIOCSDTR: |
430 | dmfmctl(dev, DMF_DTR|DMF_RTS, DMBIS); | |
431 | break; | |
942f05a9 | 432 | |
7a17d042 SL |
433 | case TIOCCDTR: |
434 | dmfmctl(dev, DMF_DTR|DMF_RTS, DMBIC); | |
435 | break; | |
942f05a9 | 436 | |
7a17d042 | 437 | case TIOCMSET: |
942f05a9 | 438 | dmfmctl(dev, dmtodmf(*(int *)data), DMSET); |
7a17d042 | 439 | break; |
942f05a9 | 440 | |
7a17d042 | 441 | case TIOCMBIS: |
942f05a9 | 442 | dmfmctl(dev, dmtodmf(*(int *)data), DMBIS); |
7a17d042 | 443 | break; |
942f05a9 | 444 | |
7a17d042 | 445 | case TIOCMBIC: |
942f05a9 | 446 | dmfmctl(dev, dmtodmf(*(int *)data), DMBIC); |
7a17d042 | 447 | break; |
942f05a9 | 448 | |
7a17d042 | 449 | case TIOCMGET: |
942f05a9 | 450 | *(int *)data = dmftodm(dmfmctl(dev, 0, DMGET)); |
7a17d042 | 451 | break; |
942f05a9 | 452 | |
7a17d042 SL |
453 | default: |
454 | u.u_error = ENOTTY; | |
455 | } | |
456 | } | |
457 | ||
458 | dmtodmf(bits) | |
459 | register int bits; | |
460 | { | |
461 | register int b; | |
462 | ||
463 | b = bits & 012; | |
464 | if (bits & DML_ST) b |= DMF_RATE; | |
465 | if (bits & DML_RTS) b |= DMF_RTS; | |
466 | if (bits & DML_USR) b |= DMF_USRW; | |
467 | return(b); | |
468 | } | |
469 | ||
470 | dmftodm(bits) | |
471 | register int bits; | |
472 | { | |
473 | register int b; | |
474 | ||
475 | b = (bits & 012) | ((bits >> 7) & 0760) | DML_LE; | |
476 | if (bits & DMF_USRR) b |= DML_USR; | |
477 | if (bits & DMF_RTS) b |= DML_RTS; | |
478 | return(b); | |
479 | } | |
480 | ||
481 | ||
482 | /* | |
483 | * Set parameters from open or stty into the DMF hardware | |
484 | * registers. | |
485 | */ | |
486 | dmfparam(unit) | |
487 | register int unit; | |
488 | { | |
489 | register struct tty *tp; | |
490 | register struct dmfdevice *addr; | |
491 | register int lpar, lcr; | |
492 | int s; | |
493 | ||
494 | tp = &dmf_tty[unit]; | |
495 | addr = (struct dmfdevice *)tp->t_addr; | |
496 | /* | |
497 | * Block interrupts so parameters will be set | |
498 | * before the line interrupts. | |
499 | */ | |
500 | s = spl5(); | |
501 | addr->dmfcsr = (unit&07) | DMFIR_LCR | DMF_IE; | |
502 | if ((tp->t_ispeed)==0) { | |
c38b985f | 503 | tp->t_state |= TS_HUPCLS; |
7a17d042 SL |
504 | dmfmctl(unit, DMF_OFF, DMSET); |
505 | return; | |
506 | } | |
507 | lpar = (dmf_speeds[tp->t_ospeed]<<12) | (dmf_speeds[tp->t_ispeed]<<8); | |
508 | lcr = DMFLCR_ENA; | |
509 | if ((tp->t_ispeed) == B134) | |
510 | lpar |= BITS6|PENABLE; | |
511 | else if ((tp->t_flags&RAW) || (tp->t_local&LLITOUT)) | |
512 | lpar |= BITS8; | |
513 | else { | |
514 | lpar |= BITS7|PENABLE; | |
515 | /* CHECK FOR XON/XOFF AND SET lcr |= DMF_AUTOX; */ | |
516 | } | |
517 | if ((tp->t_flags&EVENP) == 0) | |
518 | lpar |= OPAR; | |
519 | if ((tp->t_ospeed) == B110) | |
520 | lpar |= TWOSB; | |
521 | lpar |= (unit&07); | |
522 | addr->dmflpr = lpar; | |
523 | addr->dmflcr = lcr; | |
524 | splx(s); | |
525 | } | |
526 | ||
527 | /* | |
528 | * DMF32 transmitter interrupt. | |
529 | * Restart the idle line. | |
530 | */ | |
531 | dmfxint(dmf) | |
532 | int dmf; | |
533 | { | |
534 | register struct tty *tp; | |
535 | register struct dmfdevice *addr; | |
536 | register struct uba_device *ui; | |
537 | register int unit, t; | |
538 | #ifdef DMFDMA | |
539 | short cntr; | |
540 | #endif | |
541 | ||
542 | ui = dmfinfo[dmf]; | |
543 | addr = (struct dmfdevice *)ui->ui_addr; | |
544 | while ((t = addr->dmfcsr) & DMF_TI) { | |
545 | unit = dmf*8 + ((t>>8)&07); | |
546 | tp = &dmf_tty[unit]; | |
c38b985f | 547 | tp->t_state &= ~TS_BUSY; |
7a17d042 SL |
548 | if (t & DMF_NXM) { |
549 | printf("dmf%d: NXM line %d\n", dmf, unit&7); | |
550 | /* SHOULD RESTART OR SOMETHING... */ | |
551 | } | |
c38b985f SL |
552 | if (tp->t_state&TS_FLUSH) |
553 | tp->t_state &= ~TS_FLUSH; | |
7a17d042 SL |
554 | #ifdef DMFDMA |
555 | else { | |
556 | addr->dmfcsr = DMFIR_TBUF | DMF_IE | (unit&07); | |
557 | if (addr->dmftsc == 0) { | |
558 | /* | |
559 | * Do arithmetic in a short to make up | |
560 | * for lost 16&17 bits. | |
561 | */ | |
562 | addr->dmfcsr = DMFIR_TBA | DMF_IE | (unit&07); | |
563 | cntr = addr->dmftba - | |
564 | UBACVT(tp->t_outq.c_cf, ui->ui_ubanum); | |
565 | ndflush(&tp->t_outq, (int)cntr); | |
566 | } | |
567 | } | |
568 | #endif | |
569 | if (tp->t_line) | |
570 | (*linesw[tp->t_line].l_start)(tp); | |
571 | else | |
572 | dmfstart(tp); | |
573 | } | |
574 | } | |
575 | ||
576 | /* | |
577 | * Start (restart) transmission on the given DMF32 line. | |
578 | */ | |
579 | dmfstart(tp) | |
580 | register struct tty *tp; | |
581 | { | |
582 | register struct dmfdevice *addr; | |
583 | register int car, dmf, unit, nch; | |
584 | int s; | |
585 | ||
586 | unit = minor(tp->t_dev); | |
587 | dmf = unit >> 3; | |
588 | unit &= 07; | |
589 | addr = (struct dmfdevice *)tp->t_addr; | |
590 | ||
591 | /* | |
592 | * Must hold interrupts in following code to prevent | |
593 | * state of the tp from changing. | |
594 | */ | |
595 | s = spl5(); | |
596 | /* | |
597 | * If it's currently active, or delaying, no need to do anything. | |
598 | */ | |
c38b985f | 599 | if (tp->t_state&(TS_TIMEOUT|TS_BUSY|TS_TTSTOP)) |
7a17d042 SL |
600 | goto out; |
601 | /* | |
602 | * If there are still characters in the silo, | |
603 | * just reenable the transmitter. | |
604 | */ | |
605 | addr->dmfcsr = DMF_IE | DMFIR_TBUF | unit; | |
606 | if (addr->dmftsc) { | |
607 | addr->dmfcsr = DMF_IE | DMFIR_LCR | unit; | |
608 | addr->dmflcr |= DMF_TE; | |
c38b985f | 609 | tp->t_state |= TS_BUSY; |
7a17d042 SL |
610 | goto out; |
611 | } | |
612 | /* | |
613 | * If there are sleepers, and output has drained below low | |
614 | * water mark, wake up the sleepers. | |
615 | */ | |
c38b985f SL |
616 | if ((tp->t_state&TS_ASLEEP) && tp->t_outq.c_cc<=TTLOWAT(tp)) { |
617 | tp->t_state &= ~TS_ASLEEP; | |
e9c71764 | 618 | wakeup((caddr_t)&tp->t_outq); |
7a17d042 SL |
619 | } |
620 | /* | |
621 | * Now restart transmission unless the output queue is | |
622 | * empty. | |
623 | */ | |
624 | if (tp->t_outq.c_cc == 0) | |
625 | goto out; | |
626 | if (tp->t_flags&RAW || tp->t_local&LLITOUT) | |
627 | nch = ndqb(&tp->t_outq, 0); | |
628 | else { | |
629 | nch = ndqb(&tp->t_outq, 0200); | |
630 | /* | |
631 | * If first thing on queue is a delay process it. | |
632 | */ | |
633 | if (nch == 0) { | |
634 | nch = getc(&tp->t_outq); | |
635 | timeout(ttrstrt, (caddr_t)tp, (nch&0x7f)+6); | |
c38b985f | 636 | tp->t_state |= TS_TIMEOUT; |
7a17d042 SL |
637 | goto out; |
638 | } | |
639 | } | |
640 | /* | |
641 | * If characters to transmit, restart transmission. | |
642 | */ | |
643 | if (nch) { | |
644 | #ifdef DMFDMA | |
645 | addr->dmfcsr = DMF_IE | DMFIR_LCR | unit; | |
646 | addr->dmflcr |= DMF_TE; | |
647 | car = UBACVT(tp->t_outq.c_cf, dmfinfo[dmf]->ui_ubanum); | |
648 | addr->dmfcsr = DMF_IE | DMFIR_TBA | unit; | |
649 | addr->dmftba = car; | |
650 | addr->dmftcc = ((car>>2)&0xc000) | nch; | |
651 | #else | |
652 | register char *cp = tp->t_outq.c_cf; | |
653 | register int i; | |
654 | ||
655 | nch = MIN(nch, DMF_SILOCNT); | |
656 | addr->dmfcsr = DMF_IE | DMFIR_LCR | unit; | |
657 | addr->dmflcr |= DMF_TE; | |
658 | addr->dmfcsr = DMF_IE | DMFIR_TBUF | unit; | |
659 | for (i = 0; i < nch; i++) | |
660 | addr->dmftbuf = *cp++; | |
661 | ndflush(&tp->t_outq, nch); | |
662 | #endif | |
c38b985f | 663 | tp->t_state |= TS_BUSY; |
7a17d042 SL |
664 | } |
665 | out: | |
666 | splx(s); | |
667 | } | |
668 | ||
669 | /* | |
670 | * Stop output on a line, e.g. for ^S/^Q or output flush. | |
671 | */ | |
672 | /*ARGSUSED*/ | |
673 | dmfstop(tp, flag) | |
674 | register struct tty *tp; | |
675 | { | |
676 | register struct dmfdevice *addr; | |
677 | register int unit, s; | |
678 | ||
679 | addr = (struct dmfdevice *)tp->t_addr; | |
680 | /* | |
681 | * Block input/output interrupts while messing with state. | |
682 | */ | |
683 | s = spl5(); | |
c38b985f | 684 | if (tp->t_state & TS_BUSY) { |
7a17d042 SL |
685 | /* |
686 | * Device is transmitting; stop output | |
687 | * by selecting the line and disabling | |
688 | * the transmitter. If this is a flush | |
689 | * request then flush the output silo, | |
690 | * otherwise we will pick up where we | |
691 | * left off by enabling the transmitter. | |
692 | */ | |
693 | unit = minor(tp->t_dev); | |
694 | addr->dmfcsr = DMFIR_LCR | (unit&07) | DMF_IE; | |
695 | addr->dmflcr &= ~DMF_TE; | |
c38b985f SL |
696 | if ((tp->t_state&TS_TTSTOP)==0) { |
697 | tp->t_state |= TS_FLUSH; | |
7a17d042 SL |
698 | addr->dmflcr |= DMF_FLUSH; |
699 | } else | |
c38b985f | 700 | tp->t_state &= ~TS_BUSY; |
7a17d042 SL |
701 | } |
702 | splx(s); | |
703 | } | |
704 | ||
705 | /* | |
706 | * DMF32 modem control | |
707 | */ | |
708 | dmfmctl(dev, bits, how) | |
709 | dev_t dev; | |
710 | int bits, how; | |
711 | { | |
712 | register struct dmfdevice *dmfaddr; | |
713 | register int unit, mbits, lcr; | |
714 | int s; | |
715 | ||
716 | unit = minor(dev); | |
717 | dmfaddr = (struct dmfdevice *)(dmf_tty[unit].t_addr); | |
718 | unit &= 07; | |
719 | s = spl5(); | |
720 | dmfaddr->dmfcsr = DMF_IE | DMFIR_TBUF | unit; | |
721 | mbits = dmfaddr->dmfrms << 8; | |
722 | dmfaddr->dmfcsr = DMF_IE | DMFIR_LCR | unit; | |
723 | mbits |= dmfaddr->dmftms; | |
724 | lcr = dmfaddr->dmflcr; | |
725 | switch (how) { | |
726 | case DMSET: | |
727 | mbits = bits; | |
728 | break; | |
729 | ||
730 | case DMBIS: | |
731 | mbits |= bits; | |
732 | break; | |
733 | ||
734 | case DMBIC: | |
735 | mbits &= ~bits; | |
736 | break; | |
737 | ||
738 | case DMGET: | |
739 | (void) splx(s); | |
740 | return(mbits); | |
741 | } | |
742 | dmfaddr->dmftms = mbits&037; | |
743 | if (mbits & DMF_BRK) | |
744 | lcr |= DMF_RBRK; | |
745 | else | |
746 | lcr &= ~DMF_RBRK; | |
747 | dmfaddr->dmflcr = lcr; | |
748 | (void) splx(s); | |
749 | return(mbits); | |
750 | } | |
751 | ||
752 | /* | |
753 | * Reset state of driver if UBA reset was necessary. | |
754 | * Reset the csr, lpr, and lcr registers on open lines, and | |
755 | * restart transmitters. | |
756 | */ | |
757 | dmfreset(uban) | |
758 | int uban; | |
759 | { | |
760 | register int dmf, unit; | |
761 | register struct tty *tp; | |
762 | register struct uba_device *ui; | |
763 | register struct dmfdevice *addr; | |
764 | int i; | |
765 | ||
766 | #ifdef DMFDMA | |
767 | if (dmf_ubinfo[uban] == 0) | |
768 | return; | |
769 | ubarelse(uban, &dmf_ubinfo[uban]); | |
770 | dmf_ubinfo[uban] = uballoc(uban, (caddr_t)cfree, | |
771 | nclist*sizeof (struct cblock), 0); | |
772 | cbase[uban] = dmf_ubinfo[uban]&0x3ffff; | |
773 | #endif | |
774 | for (dmf = 0; dmf < NDMF; dmf++) { | |
775 | ui = dmfinfo[dmf]; | |
776 | if (ui == 0 || ui->ui_alive == 0 || ui->ui_ubanum != uban) | |
777 | continue; | |
778 | printf(" dmf%d", dmf); | |
779 | addr = (struct dmfdevice *)ui->ui_addr; | |
780 | addr->dmfcsr = DMF_IE; | |
781 | addr->dmfrsp = 1; | |
782 | unit = dmf * 8; | |
783 | for (i = 0; i < 8; i++) { | |
784 | tp = &dmf_tty[unit]; | |
c38b985f | 785 | if (tp->t_state & (TS_ISOPEN|TS_WOPEN)) { |
7a17d042 SL |
786 | dmfparam(unit); |
787 | dmfmctl(unit, DMF_ON, DMSET); | |
c38b985f | 788 | tp->t_state &= ~TS_BUSY; |
7a17d042 SL |
789 | dmfstart(tp); |
790 | } | |
791 | unit++; | |
792 | } | |
793 | } | |
794 | } | |
795 | ||
796 | /* stubs for interrupt routines for devices not yet supported */ | |
797 | ||
798 | dmfsrint() { printf("dmfsrint\n"); } | |
799 | ||
800 | dmfsxint() { printf("dmfsxint\n"); } | |
801 | ||
802 | dmfdaint() { printf("dmfdaint\n"); } | |
803 | ||
804 | dmfdbint() { printf("dmfdbint\n"); } | |
805 | ||
806 | dmflint() { printf("dmflint\n"); } | |
807 | #endif |