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