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