xref: /original-bsd/sys/vax/uba/dmf.c (revision de3f5c4e)
1 /*
2  * Copyright (c) 1982, 1986 Regents of the University of California.
3  * All rights reserved.  The Berkeley software License Agreement
4  * specifies the terms and conditions for redistribution.
5  *
6  *	@(#)dmf.c	7.14 (Berkeley) 05/09/91
7  */
8 
9 /*
10  * DMF32 driver
11  *
12  *
13  * TODO:
14  *	test with modem
15  *	load as much as possible into silo
16  *	use auto XON/XOFF
17  *	test reset code
18  */
19 #include "dmf.h"
20 #if NDMF > 0
21 
22 #ifndef NDMF_LP
23 #define	NDMF_LP	NDMF
24 #endif	NDMF_LP
25 #include "../include/pte.h"
26 
27 #include "sys/param.h"
28 #include "uba.h"
29 #include "sys/conf.h"
30 #include "sys/user.h"
31 #include "sys/proc.h"
32 #include "sys/ioctl.h"
33 #include "sys/tty.h"
34 #include "sys/map.h"
35 #include "sys/buf.h"
36 #include "sys/vm.h"
37 #include "sys/clist.h"
38 #include "sys/file.h"
39 #include "sys/uio.h"
40 #include "sys/kernel.h"
41 #include "sys/syslog.h"
42 
43 #include "dmx.h"
44 #include "ubareg.h"
45 #include "ubavar.h"
46 #include "dmxreg.h"
47 #include "dmfreg.h"
48 #include "dmreg.h"
49 
50 extern	int dmx_timeout;		/* silo timeout, in ms */
51 int	dmfstart();
52 
53 /*
54  * The clist space is mapped by one terminal driver onto each UNIBUS.
55  * The identity of the board which allocated resources is recorded,
56  * so the process may be repeated after UNIBUS resets.
57  * The UBACVT macro converts a clist space address for unibus uban
58  * into an i/o space address for the DMA routine.
59  */
60 int	dmf_uballoc[NUBA];	/* which dmf (if any) allocated unibus map */
61 int	cbase[NUBA];		/* base address of clists in unibus map */
62 
63 /*
64  * Autoconfiguration and variables for DMF32
65  */
66 int	dmfprobe(), dmfattach(), dmfrint(), dmfxint();
67 int	dmflint();
68 struct	uba_device *dmfinfo[NDMF];
69 u_short	dmfstd[] = { 0 };
70 struct	uba_driver dmfdriver =
71 	{ dmfprobe, 0, dmfattach, 0, dmfstd, "dmf", dmfinfo };
72 
73 struct	tty dmf_tty[NDMF*8];
74 struct	dmx_softc dmf_softc[NDMF];
75 #ifndef lint
76 int	ndmf = NDMF*8;			/* used by iostat */
77 #endif
78 
79 /*
80  * Routine for configuration to set dmf interrupt.
81  */
82 /*ARGSUSED*/
83 dmfprobe(reg, ctlr)
84 	caddr_t reg;
85 	struct uba_device *ctlr;
86 {
87 	register int br, cvec;		/* these are ``value-result'' */
88 	register struct dmfdevice *dmfaddr = (struct dmfdevice *)reg;
89 	register int i;
90 	register unsigned int a;
91 	static char *dmfdevs[]=
92 		{"parallel","printer","synch","asynch"};
93 	unsigned int dmfoptions;
94 	static int (*intrv[3])() = { (int (*)())0, (int (*)())0, (int (*)())0 };
95 
96 #ifdef lint
97 	br = 0; cvec = br; br = cvec;
98 	dmfxint(0); dmfrint(0);
99 	dmfsrint(); dmfsxint(); dmfdaint(); dmfdbint(); dmflint(0);
100 #endif
101 	/*
102 	 * Pick the usual size DMF vector here (don't decrement it here).
103 	 * grab configuration; note that the DMF32
104 	 * doesn't seem to put the right bits in this
105 	 * register until AFTER the interrupt vector is set.
106 	 */
107 	br = 0x15;
108 	cvec = (uba_hd[numuba].uh_lastiv - 4*8);
109 	dmfaddr->dmfccsr0 = (cvec >> 2);
110 	dmfoptions = dmfaddr->dmfccsr0 & DMFC_CONFMASK;
111 
112 	/* catch a couple of special cases:  Able vmz/32n and vmz/lp	*/
113 	if (dmfoptions == DMFC_ASYNC) {
114 		/* Async portion only */
115 
116 		cvec = (uba_hd[numuba].uh_lastiv -= 8);
117 		dmfaddr->dmfccsr0 = (cvec - 2*8) >> 2;
118 		intrv[0] = ctlr->ui_intr[4];
119 		intrv[1] = ctlr->ui_intr[5];
120 		ctlr->ui_intr = intrv;
121 	} else if (dmfoptions == DMFC_LP) {
122 		/* LP portion only */
123 
124 		cvec = (uba_hd[numuba].uh_lastiv -= 8);
125 		ctlr->ui_intr = &ctlr->ui_intr[6];
126 	} else if (dmfoptions == (DMFC_LP|DMFC_ASYNC)) {
127 		/* LP and Async portions only */
128 
129 		cvec = (uba_hd[numuba].uh_lastiv -= 2*8);
130 		ctlr->ui_intr = &ctlr->ui_intr[4];
131 	} else {
132 		/* All other configurations get everything */
133 
134 		cvec = (uba_hd[numuba].uh_lastiv -= 4*8);
135 	}
136 	a = (dmfoptions >> 12) & 0xf;
137 	printf("dmf%d:", ctlr->ui_unit);
138 	for (i = 0; a != 0; ++i, a >>= 1) {
139 		if (a & 1)
140 			printf(" %s",dmfdevs[i]);
141 	}
142 	printf(".\n");
143 
144 	if (dmfoptions & DMFC_LP)
145 		dmfaddr->dmfl_ctrl = DMFL_RESET;
146 	return (sizeof (struct dmfdevice));
147 }
148 
149 /*
150  * Routine called to attach a dmf.
151  */
152 dmfattach(ui)
153 	register struct uba_device *ui;
154 {
155 	register struct dmx_softc *sc;
156 
157 	sc = &dmf_softc[ui->ui_unit];
158 	sc->dmx_type = 'f';
159 	sc->dmx_unit = ui->ui_unit;
160 	sc->dmx_unit0 = 0;
161 	sc->dmx_ubanum = ui->ui_ubanum;
162 	sc->dmx_softCAR = ui->ui_flags & 0xff;
163 	sc->dmx_tty = &dmf_tty[ui->ui_unit * 8];
164 	sc->dmx_octet =
165 	    (struct dmx_octet *)&((struct dmfdevice *)ui->ui_addr)->dmfa;
166 
167 	cbase[ui->ui_ubanum] = -1;
168 	dmf_uballoc[ui->ui_ubanum] = -1;
169 #if NDMF_LP > 0
170 	dmflattach(ui);
171 #endif NDMF_LP
172 }
173 
174 /*
175  * Open a DMF32 line, mapping the clist onto the uba if this
176  * is the first dmf on this uba.  Turn on this dmf if this is
177  * the first use of it.
178  */
179 /*ARGSUSED*/
180 dmfopen(dev, flag)
181 	dev_t dev;
182 {
183 	register struct tty *tp;
184 	register struct dmx_softc *sc;
185 	int unit, dmf;
186 	register struct dmfdevice *addr;
187 	register struct uba_device *ui;
188 	int s;
189 	int dmxparam();
190 
191 	unit = minor(dev);
192 	if (unit & 0200)
193 		return (dmflopen(dev,flag));
194 	dmf = unit >> 3;
195 	if (unit >= NDMF*8 || (ui = dmfinfo[dmf])== 0 || ui->ui_alive == 0)
196 		return (ENXIO);
197 
198 	tp = &dmf_tty[unit];
199 	sc = &dmf_softc[dmf];
200 	addr = (struct dmfdevice *)ui->ui_addr;
201 	tp->t_addr = (caddr_t)(&addr->dmfa);
202 	tp->t_oproc = dmfstart;
203 	tp->t_dev = dev;			/* needed before dmxopen */
204 	tp->t_param = dmxparam;
205 
206 	/*
207 	 * While setting up state for this uba,
208 	 * block uba resets which can clear the state.
209 	 */
210 	s = spl6();
211 	if (cbase[ui->ui_ubanum] == -1) {
212 		dmf_uballoc[ui->ui_ubanum] = dmf;
213 		cbase[ui->ui_ubanum] = UBAI_ADDR(uballoc(ui->ui_ubanum,
214 		    (caddr_t)cfree, nclist*sizeof(struct cblock), 0));
215 	}
216 	splx(s);
217 
218 	return (dmxopen(tp, sc, flag));
219 }
220 
221 /*
222  * Close a DMF32 line.
223  */
224 /*ARGSUSED*/
225 dmfclose(dev, flag)
226 	dev_t dev;
227 	int flag;
228 {
229 	register unit;
230 
231 	unit = minor(dev);
232 	if (unit & 0200) {
233 		dmflclose(dev, flag);
234 		return;
235 	}
236 	return (dmxclose(&dmf_tty[unit]));
237 }
238 
239 dmfread(dev, uio, flag)
240 	dev_t dev;
241 	struct uio *uio;
242 {
243 	register struct tty *tp;
244 
245 	if (minor(dev) & 0200)
246 		return(ENXIO);
247 	tp = &dmf_tty[minor(dev)];
248 	return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
249 }
250 
251 dmfwrite(dev, uio)
252 	dev_t dev;
253 	struct uio *uio;
254 {
255 	register struct tty *tp;
256 
257 	if (minor(dev) & 0200)
258 		return (dmflwrite(dev,uio));
259 	tp = &dmf_tty[minor(dev)];
260 	return ((*linesw[tp->t_line].l_write)(tp, uio));
261 }
262 
263 /*
264  * DMF32 receiver interrupt.
265  */
266 dmfrint(dmf)
267 	int dmf;
268 {
269 	struct uba_device *ui;
270 
271 	ui = dmfinfo[dmf];
272 	if (ui == 0 || ui->ui_alive == 0)
273 		return;
274 	dmxrint(&dmf_softc[dmf]);
275 }
276 
277 /*
278  * Ioctl for DMF32.
279  */
280 dmfioctl(dev, cmd, data, flag)
281 	dev_t dev;
282 	caddr_t data;
283 {
284 	int unit = minor(dev);
285 
286 	if (unit & 0200)
287 		return (ENOTTY);
288 	return (dmxioctl(&dmf_tty[unit], cmd, data, flag));
289 }
290 
291 /*
292  * DMF32 transmitter interrupt.
293  * Restart the idle line.
294  */
295 dmfxint(dmf)
296 	int dmf;
297 {
298 
299 	dmxxint(&dmf_softc[dmf]);
300 }
301 
302 /*
303  * Start (restart) transmission on the given line.
304  */
305 dmfstart(tp)
306 	struct tty *tp;
307 {
308 
309 	dmxstart(tp, &dmf_softc[minor(tp->t_dev) >> 3]);
310 }
311 
312 /*
313  * Stop output on a line, e.g. for ^S/^Q or output flush.
314  */
315 dmfstop(tp, flag)
316 	struct tty *tp;
317 {
318 
319 	dmxstop(tp, &dmf_softc[minor(tp->t_dev) >> 3], flag);
320 }
321 
322 /*
323  * Reset state of driver if UBA reset was necessary.
324  * Reset the csr, lpr, and lcr registers on open lines, and
325  * restart transmitters.
326  */
327 dmfreset(uban)
328 	int uban;
329 {
330 	register int dmf;
331 	register struct tty *tp;
332 	register struct uba_device *ui;
333 	register struct dmfdevice *addr;
334 	int i;
335 
336 	for (dmf = 0; dmf < NDMF; dmf++) {
337 		ui = dmfinfo[dmf];
338 		if (ui == 0 || ui->ui_alive == 0 || ui->ui_ubanum != uban)
339 			continue;
340 		printf(" dmf%d", dmf);
341 		if (dmf_uballoc[uban] == dmf) {
342 			int info;
343 
344 			info = uballoc(uban, (caddr_t)cfree,
345 			    nclist * sizeof(struct cblock), UBA_CANTWAIT);
346 			if (info)
347 				cbase[uban] = UBAI_ADDR(info);
348 			else {
349 				printf(" [can't get uba map]");
350 				cbase[uban] = -1;
351 			}
352 		}
353 		addr = (struct dmfdevice *)ui->ui_addr;
354 		addr->dmfa.csr = DMF_IE;
355 		addr->dmfa.rsp = dmx_timeout;
356 		tp = &dmf_tty[dmf * 8];
357 		for (i = 0; i < 8; i++, tp++) {
358 			if (tp->t_state & (TS_ISOPEN|TS_WOPEN)) {
359 				dmxparam(tp, &tp->t_termios);
360 				(void) dmxmctl(tp, DMF_ON, DMSET);
361 				tp->t_state &= ~TS_BUSY;
362 				dmfstart(tp);
363 			}
364 		}
365 #if NDMF_LP > 0
366 		dmflint(dmf);
367 #endif
368 	}
369 }
370 
371 #if NDMF_LP > 0
372 /*
373  * DMF32 line printer driver
374  *
375  * the line printer on dmfx is indicated by a minor device code of 128+x
376  *
377  * the flags field of the config file is interpreted like so:
378  * bits		meaning
379  * ----		-------
380  * 0-7		soft carrier bits for ttys part of dmf32
381  * 8-15		number of cols/line on the line printer
382  *			if 0, 132 will be used.
383  * 16-23	number of lines/page on the line printer
384  *			if 0, 66 will be used.
385  * 24		if 1 DO NOT use the auto format mode of the
386  *			line printer parallel port
387  */
388 
389 struct dmfl_softc {
390 	u_int	dmfl_state; 		/* soft state bits */
391 	int	dmfl_info;		/* uba info */
392 	u_short	dmfl_lines;		/* lines per page (66 def.) */
393 	u_short	dmfl_cols; 		/* cols per line (132 def.) */
394 	u_short	dmfl_format;		/* fflag for auto form feed */
395 	char	dmfl_buf[DMFL_BUFSIZ];
396 } dmfl_softc[NDMF];
397 
398 /*
399  * convert device number into DMF line printer unit number
400  */
401 #define	DMFL_UNIT(d)	(minor(d) & 0xf)	/* up to 16 DMFs */
402 
403 #define ASLP 1		/* waiting for interrupt from dmf */
404 #define OPEN 2		/* line printer is open */
405 #define ERROR 4		/* error while printing, driver
406 			 refuses to do anything till closed */
407 #define MOREIO 8	/* more data for printer */
408 
409 /*
410  * Attach printer portion of dmf.
411  */
412 dmflattach(ui)
413 	register struct uba_device *ui;
414 {
415 	register int unit = ui->ui_unit;
416 	register int cols = (ui->ui_flags>>8) & 0xff;
417 	register int lines = (ui->ui_flags>>16) & 0xff;
418 	register struct dmfl_softc *sc;
419 
420 	sc = &dmfl_softc[unit];
421 	sc->dmfl_cols = cols == 0 ? DMFL_DEFCOLS : cols;
422 	sc->dmfl_lines = lines == 0 ? DMFL_DEFLINES : lines;
423  	if ((ui->ui_flags >> 24) & 0x1)
424  		sc->dmfl_format = (2 << 8);
425  	else
426  		sc->dmfl_format = (2 << 8) | DMFL_FORMAT;
427 }
428 
429 /*
430  * dmflopen -- open the line printer port on a dmf32
431  */
432 /* ARGSUSED */
433 dmflopen(dev, flag)
434 	dev_t dev;
435 	int flag;
436 {
437 	register int dmf;
438 	register struct dmfl_softc *sc;
439 	register struct uba_device *ui;
440 	register struct dmfdevice *addr;
441 
442 	dmf = DMFL_UNIT(dev);
443 	if (dmf >= NDMF || (ui = dmfinfo[dmf]) == 0 || ui->ui_alive == 0)
444 		return (ENXIO);
445 	sc = &dmfl_softc[dmf];
446 	if (sc->dmfl_state & OPEN)
447 		return (EBUSY);
448 	addr = (struct dmfdevice *)ui->ui_addr;
449 	if (addr->dmfl_ctrl & DMFL_OFFLINE) {
450 #ifdef notdef
451 		log(LOG_WARNING, "dmf%d: line printer offline/jammed\n",
452 			dmf);
453 #endif
454 		return (EIO);
455 	}
456 	if ((addr->dmfl_ctrl & DMFL_CONV)) {
457 		log(LOG_WARNING, "dmf%d: line printer disconnected\n", dmf);
458 		return (EIO);
459 	}
460 
461 	addr->dmfl_ctrl = 0;
462 	sc->dmfl_state |= OPEN;
463 	return (0);
464 }
465 
466 /* ARGSUSED */
467 dmflclose(dev, flag)
468 	dev_t dev;
469 	int flag;
470 {
471 	register int dmf = DMFL_UNIT(dev);
472 	register struct dmfl_softc *sc = &dmfl_softc[dmf];
473 	register struct uba_device *ui = dmfinfo[dmf];
474 
475 	sc->dmfl_state = 0;
476 	if (sc->dmfl_info != 0)
477 		ubarelse((int)ui->ui_ubanum, &sc->dmfl_info);
478 
479 	((struct dmfdevice *)ui->ui_addr)->dmfl_ctrl = 0;
480 }
481 
482 dmflwrite(dev, uio)
483 	dev_t dev;
484 	struct uio *uio;
485 {
486 	register int n;
487 	register int error;
488 	register struct dmfl_softc *sc;
489 
490 	sc = &dmfl_softc[DMFL_UNIT(dev)];
491 	if (sc->dmfl_state & ERROR)
492 		return (EIO);
493 	while (n = (unsigned)uio->uio_resid) {
494 		if (n > DMFL_BUFSIZ) {
495 			n = DMFL_BUFSIZ;
496 			sc->dmfl_state |= MOREIO;
497 		} else
498 			sc->dmfl_state &= ~MOREIO;
499 		if (error = uiomove(sc->dmfl_buf, (int)n, uio))
500 			return (error);
501 		if (error = dmflout(dev, sc->dmfl_buf, n))
502 			return (error);
503 	}
504 	return (0);
505 }
506 
507 
508 /*
509  * dmflout -- start io operation to dmf line printer
510  *		cp is addr of buf of n chars to be sent.
511  *
512  *	-- dmf will be put in formatted output mode, this will
513  *		be selectable from an ioctl if the
514  *		need ever arises.
515  */
516 dmflout(dev, cp, n)
517 	dev_t dev;
518 	char *cp;
519 	int n;
520 {
521 	register struct dmfl_softc *sc;
522 	register int dmf;
523 	register struct uba_device *ui;
524 	register struct dmfdevice *d;
525 	int s, error;
526 
527 	dmf = DMFL_UNIT(dev);
528 	sc = &dmfl_softc[dmf];
529 	if (sc->dmfl_state & ERROR)
530 		return (EIO);
531 	ui = dmfinfo[dmf];
532 	/*
533 	 * allocate unibus resources, will be released when io
534 	 * operation is done.
535 	 */
536 	if (sc->dmfl_info == 0)
537 		sc->dmfl_info = uballoc(ui->ui_ubanum, cp, n, 0);
538 	d = (struct dmfdevice *)ui->ui_addr;
539 	d->dmfl_ctrl = sc->dmfl_format;		/* indir reg 2 */
540 	/* indir reg auto increments on r/w */
541 	/* SO DON'T CHANGE THE ORDER OF THIS CODE */
542 	d->dmfl_indrct = 0;			/* prefix chars & num */
543 	d->dmfl_indrct = 0;			/* suffix chars & num */
544 	d->dmfl_indrct = sc->dmfl_info; 	/* dma lo 16 bits addr */
545 	d->dmfl_indrct = -n;			/* number of chars */
546 
547 	d->dmfl_indrct = ((sc->dmfl_info>>16)&3) | DMFL_OPTIONS;
548 						/* dma hi 2 bits addr */
549 	d->dmfl_indrct = sc->dmfl_lines 	/* lines per page */
550 		| (sc->dmfl_cols<<8);		/* carriage width */
551 	sc->dmfl_state |= ASLP;
552 	error = 0;
553 	s = spltty();
554 	d->dmfl_ctrl |= DMFL_PEN | DMFL_IE;
555 	while (sc->dmfl_state & ASLP) {
556 		if (error = tsleep(sc->dmfl_buf, (PZERO + 8) | PCATCH,
557 		    ttyout, 0))
558 			break;
559 		while (sc->dmfl_state & ERROR) {
560 			timeout(dmflint, (caddr_t)dmf, 10 * hz);
561 			if (error = tsleep((caddr_t)&sc->dmfl_state,
562 			    (PZERO + 8) | PCATCH, ttyout, 0))
563 				goto out;
564 		}
565 	}
566 out:
567 	splx(s);
568 	return (0);
569 }
570 
571 /*
572  * dmflint -- handle an interrupt from the line printer part of the dmf32
573  */
574 dmflint(dmf)
575 	int dmf;
576 {
577 	register struct uba_device *ui;
578 	register struct dmfl_softc *sc;
579 	register struct dmfdevice *d;
580 	short dmfl_stats;
581 
582 	ui = dmfinfo[dmf];
583 	sc = &dmfl_softc[dmf];
584 	d = (struct dmfdevice *)ui->ui_addr;
585 
586 	d->dmfl_ctrl &= ~DMFL_IE;
587 	dmfl_stats = d->dmfl_ctrl;
588 	if (sc->dmfl_state & ERROR) {
589 		if ((dmfl_stats & DMFL_OFFLINE) == 0)
590 			sc->dmfl_state &= ~ERROR;
591 		wakeup((caddr_t)&sc->dmfl_state);
592 		return;
593 	}
594 	if (dmfl_stats & DMFL_DMAERR)
595 		log(LOG_WARNING, "dmf%d: NXM\n", dmf);
596 	if (dmfl_stats & DMFL_OFFLINE) {
597 		log(LOG_WARNING, "dmf%d: printer error\n", dmf);
598 		sc->dmfl_state |= ERROR;
599 	}
600 #ifdef notdef
601 	if (dmfl_stats & DMFL_PDONE) {
602 		printf("bytes= %d\n", d->dmfl_indrct);
603 		printf("lines= %d\n", d->dmfl_indrct);
604 	}
605 #endif
606 	sc->dmfl_state &= ~ASLP;
607 	wakeup((caddr_t)sc->dmfl_buf);
608 	if (sc->dmfl_info && (sc->dmfl_state & MOREIO) == 0)
609 		ubarelse(ui->ui_ubanum, &sc->dmfl_info);
610 }
611 #endif NDMF_LP
612 
613 /* stubs for interrupt routines for devices not yet supported */
614 
615 dmfsrint()
616 {
617 	printf("dmfsrint\n");
618 }
619 
620 dmfsxint()
621 {
622 	printf("dmfsxint\n");
623 }
624 
625 dmfdaint()
626 {
627 	printf("dmfdaint\n");
628 }
629 
630 dmfdbint()
631 {
632 	printf("dmfdbint\n");
633 }
634 #endif NDMF
635