generalize uba code to handle Q bus more gracefully
[unix-history] / usr / src / sys / vax / uba / dmf.c
CommitLineData
da7c5cc6 1/*
0880b18e 2 * Copyright (c) 1982, 1986 Regents of the University of California.
da7c5cc6
KM
3 * All rights reserved. The Berkeley software License Agreement
4 * specifies the terms and conditions for redistribution.
5 *
15687812 6 * @(#)dmf.c 7.2 (Berkeley) %G%
da7c5cc6 7 */
7a17d042
SL
8
9#include "dmf.h"
10#if NDMF > 0
11/*
12 * DMF32 driver
13 *
b660f54f 14 *
7a17d042
SL
15 * TODO:
16 * test with modem
17 * load as much as possible into silo
7a17d042
SL
18 * use auto XON/XOFF
19 * test reset code
b660f54f
JB
20 ****************************
21 * DMF32 line printer driver
22 *
23 * the line printer on dmfx is indicated by a minor device code of 128+x
24 *
25 * the flags field of the config file is interpreted like so:
26 * bits meaning
27 * ---- -------
28 * 0-7 soft carrier bits for ttys part of dmf32
29 * 8-15 number of cols/line on the line printer
30 * if 0, 132 will be used.
31 * 16-23 number of lines/page on the line printer
32 * if 0, 66 will be used.
3c808bd7
MK
33 * 24 if 1 DO NOT use the auto format mode of the
34 * line printer parallel port
7a17d042 35 */
961945a8
SL
36#include "../machine/pte.h"
37
7a17d042 38#include "bk.h"
66e92dcf 39#include "uba.h"
52163dab
JB
40#include "param.h"
41#include "conf.h"
42#include "dir.h"
43#include "user.h"
0b35cf68 44#include "proc.h"
52163dab
JB
45#include "ioctl.h"
46#include "tty.h"
47#include "map.h"
48#include "buf.h"
49#include "vm.h"
50#include "bkmac.h"
51#include "clist.h"
52#include "file.h"
53#include "uio.h"
b660f54f 54#include "kernel.h"
b50ce881 55#include "syslog.h"
7a17d042 56
52163dab
JB
57#include "ubareg.h"
58#include "ubavar.h"
59#include "dmfreg.h"
896962b1 60
7a17d042
SL
61/*
62 * Definition of the driver for the auto-configuration program.
63 */
64int dmfprobe(), dmfattach(), dmfrint(), dmfxint();
b660f54f 65int dmflint();
7a17d042
SL
66struct uba_device *dmfinfo[NDMF];
67u_short dmfstd[] = { 0 };
68struct uba_driver dmfdriver =
69 { dmfprobe, 0, dmfattach, 0, dmfstd, "dmf", dmfinfo };
70
9c95d9b6 71int dmf_timeout = 10; /* silo timeout, in ms */
b660f54f
JB
72int dmf_mindma = 4; /* don't dma below this point */
73
7a17d042
SL
74/*
75 * Local variables for the driver
76 */
77char dmf_speeds[] =
78 { 0, 0, 1, 2, 3, 4, 0, 5, 6, 7, 010, 012, 014, 016, 017, 0 };
79
9c95d9b6
MK
80#ifndef PORTSELECTOR
81#define ISPEED B9600
82#define IFLAGS (EVENP|ODDP|ECHO)
83#else
84#define ISPEED B4800
85#define IFLAGS (EVENP|ODDP)
86#endif
87
7a17d042
SL
88struct tty dmf_tty[NDMF*8];
89char dmfsoftCAR[NDMF];
b660f54f 90
8011f5df
MK
91struct dmfl_softc {
92 u_int dmfl_state; /* soft state bits */
93 int dmfl_info; /* uba info */
94 u_short dmfl_lines; /* lines per page (66 def.) */
95 u_short dmfl_cols; /* cols per line (132 def.) */
3c808bd7 96 u_short dmfl_format; /* fflag for auto form feed */
8011f5df 97 char dmfl_buf[DMFL_BUFSIZ];
b660f54f
JB
98} dmfl_softc[NDMF];
99
100/*
101 * convert device number into DMF line printer unit number
102 */
103#define DMFL_UNIT(d) (minor(d)&0xF) /* up to 16 DMFs */
104
105#define ASLP 1 /* waiting for interrupt from dmf */
106#define OPEN 2 /* line printer is open */
107#define ERROR 4 /* error while printing, driver
108 refuses to do anything till closed */
3c808bd7 109#define MOREIO 8 /* more data for printer */
b660f54f 110
39d536e6
BJ
111#ifndef lint
112int ndmf = NDMF*8; /* used by iostat */
113#endif
7a17d042
SL
114int dmfact; /* mask of active dmf's */
115int dmfstart(), ttrstrt();
116
7a17d042
SL
117/*
118 * The clist space is mapped by the driver onto each UNIBUS.
119 * The UBACVT macro converts a clist space address for unibus uban
120 * into an i/o space address for the DMA routine.
121 */
66e92dcf 122int dmf_ubinfo[NUBA]; /* info about allocated unibus map */
9c95d9b6 123int cbase[NUBA]; /* base address in unibus map */
7a17d042 124#define UBACVT(x, uban) (cbase[uban] + ((x)-(char *)cfree))
b660f54f 125char dmf_dma[NDMF*8];
7a17d042
SL
126
127/*
128 * Routine for configuration to set dmf interrupt.
129 */
130/*ARGSUSED*/
131dmfprobe(reg, ctlr)
132 caddr_t reg;
b660f54f 133 struct uba_device *ctlr;
7a17d042
SL
134{
135 register int br, cvec; /* these are ``value-result'' */
136 register struct dmfdevice *dmfaddr = (struct dmfdevice *)reg;
b660f54f
JB
137 register int i;
138 register unsigned int a;
139 static char *dmfdevs[]=
140 {"parallel","printer","synch","asynch"};
141 unsigned int dmfoptions;
9c95d9b6 142 static int (*intrv[3])() = { (int (*)())0, (int (*)())0, (int (*)())0 };
7a17d042
SL
143
144#ifdef lint
145 br = 0; cvec = br; br = cvec;
bbee7e10 146 dmfxint(0); dmfrint(0);
8011f5df 147 dmfsrint(); dmfsxint(); dmfdaint(); dmfdbint(); dmflint(0);
7a17d042 148#endif
b660f54f
JB
149 /*
150 * Pick the usual size DMF vector here (don't decrement it here).
151 * grab configuration; note that the DMF32
152 * doesn't seem to put the right bits in this
153 * register until AFTER the interrupt vector is set.
154 */
7a17d042 155 br = 0x15;
b660f54f 156 cvec = (uba_hd[numuba].uh_lastiv - 4*8);
9c95d9b6 157 dmfaddr->dmfccsr0 = (cvec >> 2);
b660f54f
JB
158 dmfoptions = dmfaddr->dmfccsr0 & DMFC_CONFMASK;
159
160 /* catch a couple of special cases: Able vmz/32n and vmz/lp */
161 if (dmfoptions == DMFC_ASYNC) {
9c95d9b6
MK
162 /* Async portion only */
163
164 cvec = (uba_hd[numuba].uh_lastiv -= 8);
165 dmfaddr->dmfccsr0 = (cvec - 2*8) >> 2;
166 intrv[0] = ctlr->ui_intr[4];
167 intrv[1] = ctlr->ui_intr[5];
168 ctlr->ui_intr = intrv;
0840b085 169 } else if (dmfoptions == DMFC_LP) {
9c95d9b6 170 /* LP portion only */
b660f54f 171
9c95d9b6
MK
172 cvec = (uba_hd[numuba].uh_lastiv -= 8);
173 ctlr->ui_intr = &ctlr->ui_intr[6];
0840b085 174 } else if (dmfoptions == (DMFC_LP|DMFC_ASYNC)) {
9c95d9b6
MK
175 /* LP ans Async portions only */
176
177 cvec = (uba_hd[numuba].uh_lastiv -= 2*8);
178 ctlr->ui_intr = &ctlr->ui_intr[4];
0840b085 179 } else {
9c95d9b6 180 /* All other configurations get everything */
b660f54f
JB
181
182 cvec = (uba_hd[numuba].uh_lastiv -= 4*8);
b660f54f 183 }
9c95d9b6
MK
184 a = (dmfoptions >> 12) & 0xf;
185 printf("dmf%d:", ctlr->ui_unit);
0840b085
MK
186 for (i = 0; a != 0; ++i, a >>= 1) {
187 if (a & 1)
9c95d9b6
MK
188 printf(" %s",dmfdevs[i]);
189 }
190 printf(".\n");
b660f54f
JB
191
192 if (dmfoptions & DMFC_LP)
15ad1ce4 193 dmfaddr->dmfl_ctrl = DMFL_RESET;
9c0adba0 194 return (sizeof (struct dmfdevice));
7a17d042
SL
195}
196
197/*
198 * Routine called to attach a dmf.
199 */
200dmfattach(ui)
201 struct uba_device *ui;
202{
b660f54f
JB
203 register int cols = (ui->ui_flags>>8) & 0xff;
204 register int lines = (ui->ui_flags>>16) & 0xff;
7a17d042 205
b660f54f 206 dmfsoftCAR[ui->ui_unit] = ui->ui_flags & 0xff;
26505102
MK
207 dmfl_softc[ui->ui_unit].dmfl_cols = cols == 0 ? DMFL_DEFCOLS : cols;
208 dmfl_softc[ui->ui_unit].dmfl_lines = lines == 0 ? DMFL_DEFLINES : lines;
3c808bd7
MK
209 if ((ui->ui_flags >> 24) & 0x1)
210 dmfl_softc[ui->ui_unit].dmfl_format = (2 << 8);
211 else
212 dmfl_softc[ui->ui_unit].dmfl_format = (2 << 8) | DMFL_FORMAT;
27f8c1d5 213 cbase[ui->ui_ubanum] = -1;
7a17d042
SL
214}
215
216
217/*
218 * Open a DMF32 line, mapping the clist onto the uba if this
219 * is the first dmf on this uba. Turn on this dmf if this is
220 * the first use of it.
221 */
222/*ARGSUSED*/
223dmfopen(dev, flag)
224 dev_t dev;
225{
226 register struct tty *tp;
227 register int unit, dmf;
228 register struct dmfdevice *addr;
229 register struct uba_device *ui;
230 int s;
231
232 unit = minor(dev);
0840b085
MK
233 if (unit & 0200)
234 return (dmflopen(dev,flag));
7a17d042 235 dmf = unit >> 3;
7da157da
BJ
236 if (unit >= NDMF*8 || (ui = dmfinfo[dmf])== 0 || ui->ui_alive == 0)
237 return (ENXIO);
7a17d042 238 tp = &dmf_tty[unit];
7da157da
BJ
239 if (tp->t_state&TS_XCLUDE && u.u_uid!=0)
240 return (EBUSY);
7a17d042
SL
241 addr = (struct dmfdevice *)ui->ui_addr;
242 tp->t_addr = (caddr_t)addr;
243 tp->t_oproc = dmfstart;
c38b985f 244 tp->t_state |= TS_WOPEN;
7a17d042
SL
245 /*
246 * While setting up state for this uba and this dmf,
247 * block uba resets which can clear the state.
248 */
b660f54f 249 s = spltty();
27f8c1d5 250 if (cbase[ui->ui_ubanum] == -1) {
7a17d042
SL
251 dmf_ubinfo[ui->ui_ubanum] =
252 uballoc(ui->ui_ubanum, (caddr_t)cfree,
253 nclist*sizeof(struct cblock), 0);
27f8c1d5 254 cbase[ui->ui_ubanum] = UBAI_ADDR(dmf_ubinfo[ui->ui_ubanum]);
7a17d042 255 }
7a17d042
SL
256 if ((dmfact&(1<<dmf)) == 0) {
257 addr->dmfcsr |= DMF_IE;
258 dmfact |= (1<<dmf);
b660f54f 259 addr->dmfrsp = dmf_timeout;
7a17d042
SL
260 }
261 splx(s);
262 /*
3c808bd7 263 * If this is first open, initialize tty state to default.
7a17d042 264 */
c38b985f 265 if ((tp->t_state&TS_ISOPEN) == 0) {
7a17d042 266 ttychars(tp);
26505102 267#ifndef PORTSELECTOR
3c808bd7 268 if (tp->t_ispeed == 0) {
26505102
MK
269#else
270 tp->t_state |= TS_HUPCLS;
271#endif PORTSELECTOR
3c808bd7
MK
272 tp->t_ispeed = ISPEED;
273 tp->t_ospeed = ISPEED;
274 tp->t_flags = IFLAGS;
26505102 275#ifndef PORTSELECTOR
3c808bd7 276 }
26505102 277#endif PORTSELECTOR
7a17d042
SL
278 dmfparam(unit);
279 }
280 /*
281 * Wait for carrier, then process line discipline specific open.
282 */
b660f54f 283 s = spltty();
3c808bd7
MK
284 for (;;) {
285 if ((dmfmctl(dev, DMF_ON, DMSET) & (DMF_CAR<<8)) ||
286 (dmfsoftCAR[dmf] & (1<<(unit&07))))
287 tp->t_state |= TS_CARR_ON;
288 if (tp->t_state & TS_CARR_ON)
289 break;
c38b985f 290 tp->t_state |= TS_WOPEN;
7a17d042
SL
291 sleep((caddr_t)&tp->t_rawq, TTIPRI);
292 }
293 splx(s);
7da157da 294 return ((*linesw[tp->t_line].l_open)(dev, tp));
7a17d042
SL
295}
296
297/*
298 * Close a DMF32 line.
299 */
300/*ARGSUSED*/
301dmfclose(dev, flag)
302 dev_t dev;
303 int flag;
304{
305 register struct tty *tp;
306 register unit;
307
308 unit = minor(dev);
0840b085
MK
309 if (unit & 0200) {
310 dmflclose(dev,flag);
311 return;
312 }
b660f54f 313
7a17d042
SL
314 tp = &dmf_tty[unit];
315 (*linesw[tp->t_line].l_close)(tp);
6e7edb25 316 (void) dmfmctl(unit, DMF_BRK, DMBIC);
c38b985f 317 if (tp->t_state&TS_HUPCLS || (tp->t_state&TS_ISOPEN)==0)
6e7edb25 318 (void) dmfmctl(unit, DMF_OFF, DMSET);
7a17d042
SL
319 ttyclose(tp);
320}
321
740e4029 322dmfread(dev, uio)
7a17d042 323 dev_t dev;
740e4029 324 struct uio *uio;
7a17d042
SL
325{
326 register struct tty *tp;
327
0840b085 328 if (minor(dev) & 0200)
b660f54f 329 return(ENXIO);
7a17d042 330 tp = &dmf_tty[minor(dev)];
740e4029 331 return ((*linesw[tp->t_line].l_read)(tp, uio));
7a17d042
SL
332}
333
406ddcbe 334dmfwrite(dev, uio)
7a17d042 335 dev_t dev;
406ddcbe 336 struct uio *uio;
7a17d042
SL
337{
338 register struct tty *tp;
339
0840b085
MK
340 if (minor(dev) & 0200)
341 return (dmflwrite(dev,uio));
7a17d042 342 tp = &dmf_tty[minor(dev)];
078d920f 343 return ((*linesw[tp->t_line].l_write)(tp, uio));
7a17d042
SL
344}
345
346/*
347 * DMF32 receiver interrupt.
348 */
349dmfrint(dmf)
350 int dmf;
351{
7a17d042 352 register c;
0840b085 353 register struct tty *tp;
7a17d042
SL
354 register struct dmfdevice *addr;
355 register struct tty *tp0;
b660f54f 356 int unit;
9c95d9b6 357 int overrun = 0;
0840b085 358 register struct uba_device *ui;
7a17d042 359
0840b085
MK
360 ui = dmfinfo[dmf];
361 if (ui == 0 || ui->ui_alive == 0)
362 return;
363 addr = (struct dmfdevice *)ui->ui_addr;
b660f54f 364 tp0 = &dmf_tty[dmf * 8];
7a17d042
SL
365 /*
366 * Loop fetching characters from the silo for this
367 * dmf until there are no more in the silo.
368 */
369 while ((c = addr->dmfrbuf) < 0) {
b660f54f
JB
370
371 unit = (c >> 8) & 07;
372 tp = tp0 + unit;
7a17d042 373 if (c & DMF_DSC) {
b660f54f 374 addr->dmfcsr = DMF_IE | DMFIR_TBUF | unit;
9c95d9b6
MK
375 if (addr->dmfrms & DMF_CAR)
376 (void)(*linesw[tp->t_line].l_modem)(tp, 1);
0840b085 377 else if ((dmfsoftCAR[dmf] & (1 << unit)) == 0 &&
9c95d9b6
MK
378 (*linesw[tp->t_line].l_modem)(tp, 0) == 0) {
379 addr->dmfcsr = DMF_IE | DMFIR_LCR | unit;
380 addr->dmflctms = DMFLCR_ENA;
7a17d042
SL
381 }
382 continue;
383 }
0840b085 384 if ((tp->t_state&TS_ISOPEN) == 0) {
9c95d9b6
MK
385 wakeup((caddr_t)&tp->t_rawq);
386#ifdef PORTSELECTOR
0840b085 387 if ((tp->t_state & TS_WOPEN) == 0)
9c95d9b6
MK
388#endif
389 continue;
7a17d042 390 }
223428e7 391 if (c & (DMF_PE|DMF_DO|DMF_FE)) {
b660f54f 392 if (c & DMF_PE)
0840b085
MK
393 if ((tp->t_flags & (EVENP|ODDP)) == EVENP
394 || (tp->t_flags & (EVENP|ODDP)) == ODDP)
b660f54f
JB
395 continue;
396 if ((c & DMF_DO) && overrun == 0) {
283ffc90 397 log(LOG_WARNING, "dmf%d: silo overflow\n", dmf);
b660f54f
JB
398 overrun = 1;
399 }
400 if (c & DMF_FE)
401 /*
402 * At framing error (break) generate
403 * a null (in raw mode, for getty), or a
404 * interrupt (in cooked/cbreak mode).
405 */
0840b085 406 if (tp->t_flags & RAW)
b660f54f
JB
407 c = 0;
408 else
409 c = tp->t_intrc;
7a17d042 410 }
7a17d042
SL
411#if NBK > 0
412 if (tp->t_line == NETLDISC) {
413 c &= 0177;
414 BKINPUT(c, tp);
415 } else
416#endif
417 (*linesw[tp->t_line].l_rint)(c, tp);
418 }
419}
420
421/*
422 * Ioctl for DMF32.
423 */
424/*ARGSUSED*/
942f05a9 425dmfioctl(dev, cmd, data, flag)
7a17d042 426 dev_t dev;
942f05a9 427 caddr_t data;
7a17d042
SL
428{
429 register struct tty *tp;
430 register int unit = minor(dev);
7da157da 431 int error;
7a17d042 432
0840b085 433 if (unit & 0200)
b660f54f 434 return (ENOTTY);
7a17d042 435 tp = &dmf_tty[unit];
7da157da
BJ
436 error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag);
437 if (error >= 0)
438 return (error);
439 error = ttioctl(tp, cmd, data, flag);
440 if (error >= 0) {
21220e35
JB
441 if (cmd == TIOCSETP || cmd == TIOCSETN || cmd == TIOCLBIS ||
442 cmd == TIOCLBIC || cmd == TIOCLSET)
7a17d042 443 dmfparam(unit);
7da157da
BJ
444 return (error);
445 }
446 switch (cmd) {
7a17d042
SL
447
448 case TIOCSBRK:
6e7edb25 449 (void) dmfmctl(dev, DMF_BRK, DMBIS);
7a17d042 450 break;
942f05a9 451
7a17d042 452 case TIOCCBRK:
6e7edb25 453 (void) dmfmctl(dev, DMF_BRK, DMBIC);
7a17d042 454 break;
942f05a9 455
7a17d042 456 case TIOCSDTR:
6e7edb25 457 (void) dmfmctl(dev, DMF_DTR|DMF_RTS, DMBIS);
7a17d042 458 break;
942f05a9 459
7a17d042 460 case TIOCCDTR:
6e7edb25 461 (void) dmfmctl(dev, DMF_DTR|DMF_RTS, DMBIC);
7a17d042 462 break;
942f05a9 463
7a17d042 464 case TIOCMSET:
6e7edb25 465 (void) dmfmctl(dev, dmtodmf(*(int *)data), DMSET);
7a17d042 466 break;
942f05a9 467
7a17d042 468 case TIOCMBIS:
6e7edb25 469 (void) dmfmctl(dev, dmtodmf(*(int *)data), DMBIS);
7a17d042 470 break;
942f05a9 471
7a17d042 472 case TIOCMBIC:
6e7edb25 473 (void) dmfmctl(dev, dmtodmf(*(int *)data), DMBIC);
7a17d042 474 break;
942f05a9 475
7a17d042 476 case TIOCMGET:
942f05a9 477 *(int *)data = dmftodm(dmfmctl(dev, 0, DMGET));
7a17d042 478 break;
942f05a9 479
7a17d042 480 default:
7da157da 481 return (ENOTTY);
7a17d042 482 }
7da157da 483 return (0);
7a17d042
SL
484}
485
486dmtodmf(bits)
487 register int bits;
488{
489 register int b;
490
491 b = bits & 012;
492 if (bits & DML_ST) b |= DMF_RATE;
493 if (bits & DML_RTS) b |= DMF_RTS;
494 if (bits & DML_USR) b |= DMF_USRW;
495 return(b);
496}
497
498dmftodm(bits)
499 register int bits;
500{
501 register int b;
502
503 b = (bits & 012) | ((bits >> 7) & 0760) | DML_LE;
504 if (bits & DMF_USRR) b |= DML_USR;
505 if (bits & DMF_RTS) b |= DML_RTS;
506 return(b);
507}
508
509
510/*
511 * Set parameters from open or stty into the DMF hardware
512 * registers.
513 */
514dmfparam(unit)
515 register int unit;
516{
517 register struct tty *tp;
518 register struct dmfdevice *addr;
519 register int lpar, lcr;
520 int s;
521
522 tp = &dmf_tty[unit];
523 addr = (struct dmfdevice *)tp->t_addr;
524 /*
525 * Block interrupts so parameters will be set
526 * before the line interrupts.
527 */
b660f54f 528 s = spltty();
7a17d042
SL
529 addr->dmfcsr = (unit&07) | DMFIR_LCR | DMF_IE;
530 if ((tp->t_ispeed)==0) {
c38b985f 531 tp->t_state |= TS_HUPCLS;
6e7edb25 532 (void) dmfmctl(unit, DMF_OFF, DMSET);
9c95d9b6 533 splx(s);
7a17d042
SL
534 return;
535 }
536 lpar = (dmf_speeds[tp->t_ospeed]<<12) | (dmf_speeds[tp->t_ispeed]<<8);
537 lcr = DMFLCR_ENA;
538 if ((tp->t_ispeed) == B134)
539 lpar |= BITS6|PENABLE;
fb01874e 540 else if (tp->t_flags & (RAW|LITOUT|PASS8))
7a17d042
SL
541 lpar |= BITS8;
542 else {
543 lpar |= BITS7|PENABLE;
544 /* CHECK FOR XON/XOFF AND SET lcr |= DMF_AUTOX; */
545 }
46245e68
SL
546 if (tp->t_flags&EVENP)
547 lpar |= EPAR;
7a17d042
SL
548 if ((tp->t_ospeed) == B110)
549 lpar |= TWOSB;
550 lpar |= (unit&07);
551 addr->dmflpr = lpar;
29eca3ca 552 addr->dmflctms = (addr->dmflctms &~ 0xff) | lcr;
7a17d042
SL
553 splx(s);
554}
555
556/*
557 * DMF32 transmitter interrupt.
558 * Restart the idle line.
559 */
560dmfxint(dmf)
561 int dmf;
562{
0840b085
MK
563 int unit0 = dmf * 8;
564 struct tty *tp0 = &dmf_tty[unit0];
7a17d042
SL
565 register struct tty *tp;
566 register struct dmfdevice *addr;
567 register struct uba_device *ui;
b660f54f 568 register int t;
7a17d042 569 short cntr;
7a17d042
SL
570
571 ui = dmfinfo[dmf];
572 addr = (struct dmfdevice *)ui->ui_addr;
573 while ((t = addr->dmfcsr) & DMF_TI) {
b660f54f 574 if (t & DMF_NXM)
7a17d042 575 /* SHOULD RESTART OR SOMETHING... */
b660f54f
JB
576 printf("dmf%d: NXM line %d\n", dmf, t >> 8 & 7);
577 t = t >> 8 & 7;
578 tp = tp0 + t;
579 tp->t_state &= ~TS_BUSY;
c38b985f
SL
580 if (tp->t_state&TS_FLUSH)
581 tp->t_state &= ~TS_FLUSH;
bed079ce
MK
582 else if (dmf_dma[unit0 + t])
583 ndflush(&tp->t_outq, (int)dmf_dma[unit0 + t]);
584 dmf_dma[unit0 + t] = 0;
7a17d042
SL
585 if (tp->t_line)
586 (*linesw[tp->t_line].l_start)(tp);
587 else
588 dmfstart(tp);
589 }
590}
591
592/*
593 * Start (restart) transmission on the given DMF32 line.
594 */
595dmfstart(tp)
596 register struct tty *tp;
597{
598 register struct dmfdevice *addr;
bc3a8383 599 register int unit, nch;
7a17d042 600 int s;
b660f54f 601 register int dmf;
7a17d042
SL
602
603 unit = minor(tp->t_dev);
b660f54f 604 dmf = unit >> 3;
7a17d042
SL
605 unit &= 07;
606 addr = (struct dmfdevice *)tp->t_addr;
607
608 /*
609 * Must hold interrupts in following code to prevent
610 * state of the tp from changing.
611 */
b660f54f 612 s = spltty();
7a17d042
SL
613 /*
614 * If it's currently active, or delaying, no need to do anything.
615 */
c38b985f 616 if (tp->t_state&(TS_TIMEOUT|TS_BUSY|TS_TTSTOP))
7a17d042
SL
617 goto out;
618 /*
619 * If there are still characters in the silo,
620 * just reenable the transmitter.
621 */
622 addr->dmfcsr = DMF_IE | DMFIR_TBUF | unit;
623 if (addr->dmftsc) {
624 addr->dmfcsr = DMF_IE | DMFIR_LCR | unit;
9c95d9b6 625 addr->dmflctms = addr->dmflctms | DMF_TE;
c38b985f 626 tp->t_state |= TS_BUSY;
7a17d042
SL
627 goto out;
628 }
629 /*
630 * If there are sleepers, and output has drained below low
631 * water mark, wake up the sleepers.
632 */
b660f54f
JB
633 if (tp->t_outq.c_cc<=TTLOWAT(tp)) {
634 if (tp->t_state&TS_ASLEEP) {
635 tp->t_state &= ~TS_ASLEEP;
636 wakeup((caddr_t)&tp->t_outq);
637 }
638 if (tp->t_wsel) {
639 selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
640 tp->t_wsel = 0;
641 tp->t_state &= ~TS_WCOLL;
642 }
7a17d042
SL
643 }
644 /*
645 * Now restart transmission unless the output queue is
646 * empty.
647 */
648 if (tp->t_outq.c_cc == 0)
649 goto out;
21a85e60 650 if (tp->t_flags & (RAW|LITOUT))
7a17d042
SL
651 nch = ndqb(&tp->t_outq, 0);
652 else {
b660f54f
JB
653 if ((nch = ndqb(&tp->t_outq, 0200)) == 0) {
654 /*
655 * If first thing on queue is a delay process it.
656 */
7a17d042
SL
657 nch = getc(&tp->t_outq);
658 timeout(ttrstrt, (caddr_t)tp, (nch&0x7f)+6);
c38b985f 659 tp->t_state |= TS_TIMEOUT;
7a17d042
SL
660 goto out;
661 }
662 }
663 /*
664 * If characters to transmit, restart transmission.
665 */
b660f54f
JB
666 if (nch >= dmf_mindma) {
667 register car;
668
bed079ce 669 dmf_dma[minor(tp->t_dev)] = nch;
7a17d042 670 addr->dmfcsr = DMF_IE | DMFIR_LCR | unit;
9c95d9b6 671 addr->dmflctms = addr->dmflctms | DMF_TE;
7a17d042
SL
672 car = UBACVT(tp->t_outq.c_cf, dmfinfo[dmf]->ui_ubanum);
673 addr->dmfcsr = DMF_IE | DMFIR_TBA | unit;
674 addr->dmftba = car;
b660f54f
JB
675 addr->dmftcc = ((car >> 2) & 0xc000) | nch;
676 tp->t_state |= TS_BUSY;
677 } else if (nch) {
7a17d042
SL
678 register char *cp = tp->t_outq.c_cf;
679 register int i;
680
b660f54f 681 dmf_dma[minor(tp->t_dev)] = 0;
7a17d042
SL
682 nch = MIN(nch, DMF_SILOCNT);
683 addr->dmfcsr = DMF_IE | DMFIR_LCR | unit;
9c95d9b6 684 addr->dmflctms = addr->dmflctms | DMF_TE;
7a17d042
SL
685 addr->dmfcsr = DMF_IE | DMFIR_TBUF | unit;
686 for (i = 0; i < nch; i++)
687 addr->dmftbuf = *cp++;
688 ndflush(&tp->t_outq, nch);
c38b985f 689 tp->t_state |= TS_BUSY;
7a17d042
SL
690 }
691out:
692 splx(s);
693}
694
695/*
696 * Stop output on a line, e.g. for ^S/^Q or output flush.
697 */
698/*ARGSUSED*/
699dmfstop(tp, flag)
700 register struct tty *tp;
701{
702 register struct dmfdevice *addr;
b660f54f
JB
703 register unit = minor(tp->t_dev) & 7;
704 int s;
7a17d042
SL
705
706 addr = (struct dmfdevice *)tp->t_addr;
707 /*
708 * Block input/output interrupts while messing with state.
709 */
b660f54f
JB
710 s = spltty();
711 if (flag) {
712 addr->dmfcsr = DMF_IE | DMFIR_TBUF | unit;
713 if (addr->dmftsc) {
714 /*
715 * Flush regardless of whether we're transmitting
716 * (TS_BUSY), if the silo contains untransmitted
717 * characters.
718 */
719 addr->dmfcsr = DMFIR_LCR | unit | DMF_IE;
9c95d9b6 720 addr->dmflctms = addr->dmflctms | DMF_TE | DMF_FLUSH;
b660f54f
JB
721 /* this will interrupt so let dmfxint handle the rest */
722 tp->t_state |= TS_FLUSH|TS_BUSY;
723 }
724 } else {
725 if (tp->t_state & TS_BUSY) {
726 /*
727 * Stop transmission by disabling
728 * the transmitter. We'll pick up where we
729 * left off by reenabling in dmfstart.
730 */
731 addr->dmfcsr = DMFIR_LCR | unit | DMF_IE;
9c95d9b6 732 addr->dmflctms = addr->dmflctms &~ DMF_TE;
b660f54f 733 /* no interrupt here */
c38b985f 734 tp->t_state &= ~TS_BUSY;
b660f54f 735 }
7a17d042
SL
736 }
737 splx(s);
738}
739
740/*
741 * DMF32 modem control
742 */
743dmfmctl(dev, bits, how)
744 dev_t dev;
745 int bits, how;
746{
747 register struct dmfdevice *dmfaddr;
748 register int unit, mbits, lcr;
749 int s;
750
751 unit = minor(dev);
752 dmfaddr = (struct dmfdevice *)(dmf_tty[unit].t_addr);
753 unit &= 07;
b660f54f 754 s = spltty();
7a17d042
SL
755 dmfaddr->dmfcsr = DMF_IE | DMFIR_TBUF | unit;
756 mbits = dmfaddr->dmfrms << 8;
757 dmfaddr->dmfcsr = DMF_IE | DMFIR_LCR | unit;
29eca3ca 758 lcr = dmfaddr->dmflctms;
9c95d9b6 759 mbits |= (lcr & 0xff00) >> 8;
7a17d042
SL
760 switch (how) {
761 case DMSET:
9893b42d 762 mbits = (mbits &0xff00) | bits;
7a17d042
SL
763 break;
764
765 case DMBIS:
766 mbits |= bits;
767 break;
768
769 case DMBIC:
770 mbits &= ~bits;
771 break;
772
773 case DMGET:
774 (void) splx(s);
775 return(mbits);
776 }
7a17d042
SL
777 if (mbits & DMF_BRK)
778 lcr |= DMF_RBRK;
779 else
780 lcr &= ~DMF_RBRK;
9c95d9b6 781 dmfaddr->dmflctms = ((mbits & 037) << 8) | (lcr & 0xff);
7a17d042
SL
782 (void) splx(s);
783 return(mbits);
784}
785
786/*
787 * Reset state of driver if UBA reset was necessary.
788 * Reset the csr, lpr, and lcr registers on open lines, and
789 * restart transmitters.
790 */
791dmfreset(uban)
792 int uban;
793{
794 register int dmf, unit;
795 register struct tty *tp;
796 register struct uba_device *ui;
797 register struct dmfdevice *addr;
798 int i;
799
7a17d042
SL
800 for (dmf = 0; dmf < NDMF; dmf++) {
801 ui = dmfinfo[dmf];
802 if (ui == 0 || ui->ui_alive == 0 || ui->ui_ubanum != uban)
803 continue;
804 printf(" dmf%d", dmf);
27f8c1d5 805 if (dmf_ubinfo[uban]) {
9c95d9b6
MK
806 dmf_ubinfo[uban] = uballoc(uban, (caddr_t)cfree,
807 nclist*sizeof (struct cblock), 0);
27f8c1d5 808 cbase[uban] = UBAI_ADDR(dmf_ubinfo[uban]);
9c95d9b6 809 }
7a17d042
SL
810 addr = (struct dmfdevice *)ui->ui_addr;
811 addr->dmfcsr = DMF_IE;
b660f54f 812 addr->dmfrsp = dmf_timeout;
7a17d042
SL
813 unit = dmf * 8;
814 for (i = 0; i < 8; i++) {
815 tp = &dmf_tty[unit];
c38b985f 816 if (tp->t_state & (TS_ISOPEN|TS_WOPEN)) {
7a17d042 817 dmfparam(unit);
6e7edb25 818 (void) dmfmctl(unit, DMF_ON, DMSET);
c38b985f 819 tp->t_state &= ~TS_BUSY;
7a17d042
SL
820 dmfstart(tp);
821 }
822 unit++;
823 }
824 }
825}
826
0840b085
MK
827/*
828 * dmflopen -- open the line printer port on a dmf32
b660f54f 829 */
0840b085
MK
830/* ARGSUSED */
831dmflopen(dev, flag)
832 dev_t dev;
833 int flag;
b660f54f
JB
834{
835 register int dmf;
836 register struct dmfl_softc *sc;
837 register struct uba_device *ui;
838 register struct dmfdevice *addr;
839
0840b085 840 dmf = DMFL_UNIT(dev);
3c808bd7
MK
841 if (dmf >= NDMF || (ui = dmfinfo[dmf]) == 0 || ui->ui_alive == 0)
842 return (ENXIO);
843 sc = &dmfl_softc[dmf];
844 if (sc->dmfl_state & OPEN)
845 return (EBUSY);
b660f54f 846 addr = (struct dmfdevice *)ui->ui_addr;
3c808bd7
MK
847 if (addr->dmfl_ctrl & DMFL_OFFLINE) {
848#ifdef notdef
849 log(LOG_WARNING, "dmf%d: line printer offline/jammed\n",
850 dmf);
851#endif
0840b085 852 return (EIO);
b660f54f 853 }
3c808bd7
MK
854 if ((addr->dmfl_ctrl & DMFL_CONV)) {
855 log(LOG_WARNING, "dmf%d: line printer disconnected\n", dmf);
0840b085 856 return (EIO);
b660f54f
JB
857 }
858
3c808bd7 859 addr->dmfl_ctrl = 0;
b660f54f 860 sc->dmfl_state |= OPEN;
0840b085 861 return (0);
b660f54f
JB
862}
863
0840b085
MK
864/* ARGSUSED */
865dmflclose(dev, flag)
866 dev_t dev;
867 int flag;
b660f54f 868{
3c808bd7 869 register int dmf = DMFL_UNIT(dev);
b660f54f 870 register struct dmfl_softc *sc = &dmfl_softc[dmf];
3c808bd7 871 register struct uba_device *ui = dmfinfo[dmf];
b660f54f 872
b660f54f 873 sc->dmfl_state = 0;
0840b085 874 if (sc->dmfl_info != 0)
3c808bd7 875 ubarelse((int)ui->ui_ubanum, &sc->dmfl_info);
b660f54f 876
3c808bd7 877 ((struct dmfdevice *)ui->ui_addr)->dmfl_ctrl = 0;
b660f54f
JB
878}
879
0840b085
MK
880dmflwrite(dev, uio)
881 dev_t dev;
882 struct uio *uio;
b660f54f 883{
8011f5df 884 register int n;
b660f54f
JB
885 register int error;
886 register struct dmfl_softc *sc;
887
888 sc = &dmfl_softc[DMFL_UNIT(dev)];
3c808bd7
MK
889 if (sc->dmfl_state & ERROR)
890 return (EIO);
891 while (n = (unsigned)uio->uio_resid) {
892 if (n > DMFL_BUFSIZ) {
893 n = DMFL_BUFSIZ;
894 sc->dmfl_state |= MOREIO;
895 } else
896 sc->dmfl_state &= ~MOREIO;
897 if (error = uiomove(sc->dmfl_buf, (int)n, UIO_WRITE, uio))
0840b085 898 return (error);
3c808bd7 899 if (error = dmflout(dev, sc->dmfl_buf, n))
0840b085 900 return (error);
b660f54f 901 }
0840b085 902 return (0);
b660f54f
JB
903}
904
905
0840b085
MK
906/*
907 * dmflout -- start io operation to dmf line printer
b660f54f
JB
908 * cp is addr of buf of n chars to be sent.
909 *
910 * -- dmf will be put in formatted output mode, this will
911 * be selectable from an ioctl if the
912 * need ever arises.
913 */
0840b085
MK
914dmflout(dev, cp, n)
915 dev_t dev;
916 char *cp;
917 int n;
b660f54f
JB
918{
919 register struct dmfl_softc *sc;
920 register int dmf;
921 register struct uba_device *ui;
922 register struct dmfdevice *d;
3c808bd7 923 int s;
b660f54f 924
0840b085
MK
925 dmf = DMFL_UNIT(dev);
926 sc = &dmfl_softc[dmf];
927 if (sc->dmfl_state & ERROR)
928 return (EIO);
929 ui = dmfinfo[dmf];
930 /*
931 * allocate unibus resources, will be released when io
932 * operation is done.
b660f54f 933 */
3c808bd7
MK
934 if (sc->dmfl_info == 0)
935 sc->dmfl_info = uballoc(ui->ui_ubanum, cp, n, 0);
0840b085 936 d = (struct dmfdevice *)ui->ui_addr;
3c808bd7 937 d->dmfl_ctrl = sc->dmfl_format; /* indir reg 2 */
b660f54f
JB
938 /* indir reg auto increments on r/w */
939 /* SO DON'T CHANGE THE ORDER OF THIS CODE */
3c808bd7
MK
940 d->dmfl_indrct = 0; /* prefix chars & num */
941 d->dmfl_indrct = 0; /* suffix chars & num */
942 d->dmfl_indrct = sc->dmfl_info; /* dma lo 16 bits addr */
943 d->dmfl_indrct = -n; /* number of chars */
944
945 d->dmfl_indrct = ((sc->dmfl_info>>16)&3) | DMFL_OPTIONS;
946 /* dma hi 2 bits addr */
947 d->dmfl_indrct = sc->dmfl_lines /* lines per page */
948 | (sc->dmfl_cols<<8); /* carriage width */
b660f54f 949 sc->dmfl_state |= ASLP;
3c808bd7
MK
950 s = spltty();
951 d->dmfl_ctrl |= DMFL_PEN | DMFL_IE;
0840b085 952 while (sc->dmfl_state & ASLP) {
3c808bd7 953 sleep(sc->dmfl_buf, PZERO + 8);
0840b085 954 while (sc->dmfl_state & ERROR) {
3c808bd7
MK
955 timeout(dmflint, (caddr_t)dmf, 10 * hz);
956 sleep((caddr_t)&sc->dmfl_state, PZERO + 8);
b660f54f 957 }
b660f54f 958 }
3c808bd7 959 splx(s);
0840b085 960 return (0);
b660f54f 961}
b660f54f 962
0840b085
MK
963/*
964 * dmflint -- handle an interrupt from the line printer part of the dmf32
965 */
b660f54f 966dmflint(dmf)
0840b085 967 int dmf;
b660f54f 968{
b660f54f
JB
969 register struct uba_device *ui;
970 register struct dmfl_softc *sc;
971 register struct dmfdevice *d;
3c808bd7 972 short dmfl_stats;
b660f54f 973
0840b085
MK
974 ui = dmfinfo[dmf];
975 sc = &dmfl_softc[dmf];
976 d = (struct dmfdevice *)ui->ui_addr;
b660f54f 977
3c808bd7 978 d->dmfl_ctrl &= ~DMFL_IE;
15ad1ce4 979 dmfl_stats = d->dmfl_ctrl;
0840b085 980 if (sc->dmfl_state & ERROR) {
3c808bd7 981 if ((dmfl_stats & DMFL_OFFLINE) == 0)
b660f54f 982 sc->dmfl_state &= ~ERROR;
8011f5df 983 wakeup((caddr_t)&sc->dmfl_state);
b660f54f
JB
984 return;
985 }
3c808bd7
MK
986 if (dmfl_stats & DMFL_DMAERR)
987 log(LOG_WARNING, "dmf%d: NXM\n", dmf);
988 if (dmfl_stats & DMFL_OFFLINE) {
989 log(LOG_WARNING, "dmf%d: printer error\n", dmf);
b660f54f
JB
990 sc->dmfl_state |= ERROR;
991 }
b660f54f 992#ifdef notdef
3c808bd7
MK
993 if (dmfl_stats & DMFL_PDONE) {
994 printf("bytes= %d\n", d->dmfl_indrct);
995 printf("lines= %d\n", d->dmfl_indrct);
b660f54f 996 }
3c808bd7 997#endif
b660f54f 998 sc->dmfl_state &= ~ASLP;
3c808bd7
MK
999 wakeup((caddr_t)sc->dmfl_buf);
1000 if (sc->dmfl_info && (sc->dmfl_state & MOREIO) == 0)
0840b085 1001 ubarelse(ui->ui_ubanum, &sc->dmfl_info);
b660f54f
JB
1002}
1003
7a17d042
SL
1004/* stubs for interrupt routines for devices not yet supported */
1005
0840b085
MK
1006dmfsrint()
1007{
1008 printf("dmfsrint\n");
1009}
7a17d042 1010
0840b085
MK
1011dmfsxint()
1012{
1013 printf("dmfsxint\n");
1014}
7a17d042 1015
0840b085
MK
1016dmfdaint()
1017{
1018 printf("dmfdaint\n");
1019}
b660f54f 1020
0840b085
MK
1021dmfdbint()
1022{
1023 printf("dmfdbint\n");
1024}
3c808bd7 1025#endif NDMF