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