xref: /netbsd-src/sys/arch/amiga/dev/ser.c (revision ae1bfcddc410612bc8c58b807e1830becb69a24c)
1 /*
2  * Copyright (c) 1982, 1986, 1990 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *	This product includes software developed by the University of
16  *	California, Berkeley and its contributors.
17  * 4. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  *
33  *	@(#)ser.c	7.12 (Berkeley) 6/27/91
34  *	$Id: ser.c,v 1.18 1994/05/22 07:22:31 chopps Exp $
35  */
36 /*
37  * XXX This file needs major cleanup it will never ervice more than one
38  * XXX unit.
39  */
40 
41 #include <sys/param.h>
42 #include <sys/systm.h>
43 #include <sys/ioctl.h>
44 #include <sys/device.h>
45 #include <sys/tty.h>
46 #include <sys/proc.h>
47 #include <sys/conf.h>
48 #include <sys/file.h>
49 #include <sys/malloc.h>
50 #include <sys/uio.h>
51 #include <sys/kernel.h>
52 #include <sys/syslog.h>
53 #include <sys/queue.h>
54 #include <machine/cpu.h>
55 #include <amiga/amiga/device.h>
56 #include <amiga/dev/serreg.h>
57 #include <amiga/amiga/custom.h>
58 #include <amiga/amiga/cia.h>
59 #include <amiga/amiga/cc.h>
60 
61 #include <dev/cons.h>
62 
63 #include "ser.h"
64 #if NSER > 0
65 
66 void serattach __P((struct device *, struct device *, void *));
67 int sermatch __P((struct device *, struct cfdata *, void *));
68 
69 struct cfdriver sercd = {
70 	NULL, "ser", sermatch, serattach, DV_TTY,
71 	sizeof(struct device), NULL, 0 };
72 
73 #define SEROBUF_SIZE 32
74 #define SERIBUF_SIZE 512
75 
76 int	serstart(), serparam(), serintr();
77 int	ser_active;
78 int	ser_hasfifo;
79 int	nser = NSER;
80 #ifdef SERCONSOLE
81 int	serconsole = SERCONSOLE;
82 #else
83 int	serconsole = -1;
84 #endif
85 int	serconsinit;
86 int	serdefaultrate = TTYDEF_SPEED;
87 int	sermajor;
88 int	serswflags;
89 #define SWFLAGS(dev) (serswflags | (DIALOUT(dev) ? TIOCFLAG_SOFTCAR : 0))
90 
91 struct	vbl_node ser_vbl_node[NSER];
92 struct	tty ser_cons;
93 struct	tty *ser_tty[NSER];
94 
95 struct speedtab serspeedtab[] = {
96 	0,	0,
97 	50,	SERBRD(50),
98 	75,	SERBRD(75),
99 	110,	SERBRD(110),
100 	134,	SERBRD(134),
101 	150,	SERBRD(150),
102 	200,	SERBRD(200),
103 	300,	SERBRD(300),
104 	600,	SERBRD(600),
105 	1200,	SERBRD(1200),
106 	1800,	SERBRD(1800),
107 	2400,	SERBRD(2400),
108 	4800,	SERBRD(4800),
109 	9600,	SERBRD(9600),
110 	19200,	SERBRD(19200),
111 	38400,	SERBRD(38400),
112 	57600,	SERBRD(57600),
113 	76800,	SERBRD(76800),
114 	-1,	-1
115 };
116 
117 
118 /*
119  * Since this UART is not particularly bright (to put it nicely), we'll
120  * have to do parity stuff on our own.	This table contains the 8th bit
121  * in 7bit character mode, for even parity.  If you want odd parity,
122  * flip the bit.  (for generation of the table, see genpar.c)
123  */
124 
125 u_char	even_parity[] = {
126 	0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
127 	1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
128 	1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
129 	0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
130 	1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
131 	0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
132 	0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
133 	1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
134 };
135 
136 /*
137  * Since we don't get interrupts for changes on the modem control line,
138  * we'll have to fake them by comparing current settings to the settings
139  * we remembered on last invocation.
140  */
141 
142 u_char	last_ciab_pra;
143 
144 extern struct tty *constty;
145 
146 #ifdef KGDB
147 #include <machine/remote-sl.h>
148 
149 extern dev_t kgdb_dev;
150 extern int kgdb_rate;
151 extern int kgdb_debug_init;
152 #endif
153 
154 #ifdef DEBUG
155 long	fifoin[17];
156 long	fifoout[17];
157 long	serintrcount[16];
158 long	sermintcount[16];
159 #endif
160 
161 void	sermint __P((register int unit));
162 
163 int
164 sermatch(pdp, cfp, auxp)
165 	struct device *pdp;
166 	struct cfdata *cfp;
167 	void *auxp;
168 {
169 	if (matchname("ser", (char *)auxp) == 0 || cfp->cf_unit != 0)
170 		return(0);
171 	if (serconsole != 0 && amiga_realconfig == 0)
172 		return(0);
173 	return(1);
174 }
175 
176 
177 void
178 serattach(pdp, dp, auxp)
179 	struct device *pdp, *dp;
180 	void *auxp;
181 {
182 	u_short ir;
183 
184 	ir = custom.intenar;
185 	if (serconsole == 0)
186 		DELAY(100000);
187 
188 	ser_active |= 1;
189 	ser_vbl_node[0].function = (void (*) (void *)) sermint;
190 	add_vbl_function(&ser_vbl_node[0], SER_VBL_PRIORITY, (void *) 0);
191 #ifdef KGDB
192 	if (kgdb_dev == makedev(sermajor, 0)) {
193 		if (serconsole == 0)
194 			kgdb_dev = NODEV; /* can't debug over console port */
195 		else {
196 			(void) serinit(0, kgdb_rate);
197 			serconsinit = 1;       /* don't re-init in serputc */
198 			if (kgdb_debug_init == 0)
199 				printf(" kgdb enabled\n");
200 			else {
201 				/*
202 				 * Print prefix of device name,
203 				 * let kgdb_connect print the rest.
204 				 */
205 				printf("ser0: ");
206 				kgdb_connect(1);
207 			}
208 		}
209 	}
210 #endif
211 	/*
212 	 * Need to reset baud rate, etc. of next print so reset serconsinit.
213 	 */
214 	if (0 == serconsole)
215 		serconsinit = 0;
216 	if (dp)
217 		printf(" input fifo %d output fifo %d\n", SERIBUF_SIZE,
218 		    SEROBUF_SIZE);
219 }
220 
221 
222 /* ARGSUSED */
223 int
224 seropen(dev, flag, mode, p)
225 	dev_t dev;
226 	int flag, mode;
227 	struct proc *p;
228 {
229 	struct tty *tp;
230 	int unit, error, s;
231 
232 	error = 0;
233 	unit = SERUNIT(dev);
234 
235 	if (unit >= NSER || (ser_active & (1 << unit)) == 0)
236 		return (ENXIO);
237 
238 	s = spltty();
239 
240 	if (ser_tty[unit])
241 		tp = ser_tty[unit];
242 	else
243 		tp = ser_tty[unit] = ttymalloc();
244 
245 	tp->t_oproc = (void (*) (struct tty *)) serstart;
246 	tp->t_param = serparam;
247 	tp->t_dev = dev;
248 
249 	if ((tp->t_state & TS_ISOPEN) == 0) {
250 		tp->t_state |= TS_WOPEN;
251 		ttychars(tp);
252 		if (tp->t_ispeed == 0) {
253 			/*
254 			 * only when cleared do we reset to defaults.
255 			 */
256 			tp->t_iflag = TTYDEF_IFLAG;
257 			tp->t_oflag = TTYDEF_OFLAG;
258 			tp->t_cflag = TTYDEF_CFLAG;
259 			tp->t_lflag = TTYDEF_LFLAG;
260 			tp->t_ispeed = tp->t_ospeed = serdefaultrate;
261 		}
262 		/*
263 		 * do these all the time
264 		 */
265 		if (serswflags & TIOCFLAG_CLOCAL)
266 			tp->t_cflag |= CLOCAL;
267 		if (serswflags & TIOCFLAG_CRTSCTS)
268 			tp->t_cflag |= CRTSCTS;
269 		if (serswflags & TIOCFLAG_MDMBUF)
270 			tp->t_cflag |= MDMBUF;
271 		serparam(tp, &tp->t_termios);
272 		ttsetwater(tp);
273 
274 		(void)sermctl(dev, TIOCM_DTR | TIOCM_RTS, DMSET);
275 		if ((SWFLAGS(dev) & TIOCFLAG_SOFTCAR) ||
276 		    (sermctl(dev, 0, DMGET) & TIOCM_CD))
277 			tp->t_state |= TS_CARR_ON;
278 		else
279 			tp->t_state &= ~TS_CARR_ON;
280 	} else if (tp->t_state & TS_XCLUDE && p->p_ucred->cr_uid != 0) {
281 		splx(s);
282 		return(EBUSY);
283 	}
284 
285 	/*
286 	 * if NONBLOCK requested, ignore carrier
287 	 */
288 	if (flag & O_NONBLOCK)
289 		goto done;
290 
291 	/*
292 	 * block waiting for carrier
293 	 */
294 	while ((tp->t_state & TS_CARR_ON) == 0 && (tp->t_cflag & CLOCAL) == 0) {
295 		tp->t_state |= TS_WOPEN;
296 		error = ttysleep(tp, (caddr_t)&tp->t_rawq,
297 		    TTIPRI | PCATCH, ttopen, 0);
298 		if (error) {
299 			splx(s);
300 			return(error);
301 		}
302 	}
303 done:
304 	splx(s);
305 	/*
306 	 * Reset the tty pointer, as there could have been a dialout
307 	 * use of the tty with a dialin open waiting.
308 	 */
309 	tp->t_dev = dev;
310 	return((*linesw[tp->t_line].l_open)(dev, tp));
311 }
312 
313 /*ARGSUSED*/
314 int
315 serclose(dev, flag, mode, p)
316 	dev_t dev;
317 	int flag, mode;
318 	struct proc *p;
319 {
320 	struct tty *tp;
321 	int unit;
322 
323 	unit = SERUNIT(dev);
324 
325 	tp = ser_tty[unit];
326 	(*linesw[tp->t_line].l_close)(tp, flag);
327 	custom.adkcon = ADKCONF_UARTBRK;	/* clear break */
328 #ifdef KGDB
329 	/*
330 	 * do not disable interrupts if debugging
331 	 */
332 	if (dev != kgdb_dev)
333 #endif
334 		custom.intena = INTF_RBF | INTF_TBE;	/* disable interrups */
335 	custom.intreq = INTF_RBF | INTF_TBE;		/* clear intr request */
336 
337 	/*
338 	 * If the device is closed, it's close, no matter whether we deal with
339 	 * modem control signals nor not.
340 	 */
341 #if 0
342 	if (tp->t_cflag & HUPCL || tp->t_state & TS_WOPEN ||
343 	    (tp->t_state & TS_ISOPEN) == 0)
344 #endif
345 		(void) sermctl(dev, 0, DMSET);
346 	ttyclose(tp);
347 #if not_yet
348 	if (tp != &ser_cons) {
349 		remove_vbl_function(&ser_vbl_node[unit]);
350 		ttyfree(tp);
351 		ser_tty[unit] = (struct tty *) NULL;
352 	}
353 #endif
354 	return (0);
355 }
356 
357 int
358 serread(dev, uio, flag)
359 	dev_t dev;
360 	struct uio *uio;
361 	int flag;
362 {
363 	struct tty *tp;
364 	if ((tp = ser_tty[SERUNIT(dev)]) == NULL)
365 		return(ENXIO);
366 	return((*linesw[tp->t_line].l_read)(tp, uio, flag));
367 }
368 
369 int
370 serwrite(dev, uio, flag)
371 	dev_t dev;
372 	struct uio *uio;
373 	int flag;
374 {
375 	struct tty *tp;
376 
377 	if((tp = ser_tty[SERUNIT(dev)]) == NULL)
378 		return(ENXIO);
379 	return((*linesw[tp->t_line].l_write)(tp, uio, flag));
380 }
381 
382 
383 /*
384  * We don't do any processing of data here, so we store the raw code
385  * obtained from the uart register.  In theory, 110kBaud gives you
386  * 11kcps, so 16k buffer should be more than enough, interrupt
387  * latency of 1s should never happen, or something is seriously
388  * wrong..
389  */
390 
391 static u_short serbuf[SERIBUF_SIZE];
392 static u_short *sbrpt = serbuf;
393 static u_short *sbwpt = serbuf;
394 static u_short sbovfl;
395 
396 /*
397  * This is a replacement for the lack of a hardware fifo.  32k should be
398  * enough (there's only one unit anyway, so this is not going to
399  * accumulate).
400  */
401 void
402 ser_fastint()
403 {
404 	/*
405 	 * We're at RBE-level, which is higher than VBL-level which is used
406 	 * to periodically transmit contents of this buffer up one layer,
407 	 * so no spl-raising is necessary.
408 	 */
409 	register u_short ints, code;
410 
411 	ints = custom.intreqr & INTF_RBF;
412 	if (ints == 0)
413 		return;
414 
415 	/*
416 	 * clear interrupt
417 	 */
418 	custom.intreq = ints;
419 
420 	/*
421 	 * this register contains both data and status bits!
422 	 */
423 	code = custom.serdatr;
424 
425 	/*
426 	 * check for buffer overflow.
427 	 */
428 	if (sbwpt + 1 == sbrpt ||
429 	    (sbwpt == serbuf + SERIBUF_SIZE - 1 && sbrpt == serbuf)) {
430 #if 0
431 		log(LOG_WARNING, "ser_fastint: buffer overflow!");
432 #else
433 		++sbovfl;
434 #endif
435 		return;
436 	}
437 	/*
438 	 * store in buffer
439 	 */
440 	*sbwpt++ = code;
441 	if (sbwpt == serbuf + SERIBUF_SIZE)
442 		sbwpt = serbuf;
443 }
444 
445 
446 int
447 serintr(unit)
448 	int unit;
449 {
450 	int s1, s2, ovfl;
451 
452 	/*
453 	 * Make sure we're not interrupted by another
454 	 * vbl, but allow level5 ints
455 	 */
456 	s1 = spltty();
457 
458 	/*
459 	 * pass along any acumulated information
460 	 */
461 	while (sbrpt != sbwpt) {
462 		/*
463 		 * no collision with ser_fastint()
464 		 */
465 		sereint(unit, *sbrpt);
466 
467 		ovfl = 0;
468 		/* lock against ser_fastint() */
469 		s2 = spl5();
470 		sbrpt++;
471 		if (sbrpt == serbuf + SERIBUF_SIZE)
472 			sbrpt = serbuf;
473 		if (sbovfl != 0) {
474 			ovfl = sbovfl;
475 			sbovfl = 0;
476 		}
477 		splx(s2);
478 		if (ovfl != 0)
479 			log(LOG_WARNING, "ser_fastint: %d buffer overflow!\n", ovfl);
480 	}
481 	splx(s1);
482 }
483 
484 int
485 sereint(unit, stat)
486 	int unit, stat;
487 {
488 	struct tty *tp;
489 	u_char ch;
490 	int c;
491 
492 	tp = ser_tty[unit];
493 	ch = stat & 0xff;
494 	c = ch;
495 
496 	if ((tp->t_state & TS_ISOPEN) == 0) {
497 #ifdef KGDB
498 		/* we don't care about parity errors */
499 		if (kgdb_dev == makedev(sermajor, unit) && c == FRAME_END)
500 			kgdb_connect(0);	/* trap into kgdb */
501 #endif
502 		return;
503 	}
504 
505 	/*
506 	 * Check for break and (if enabled) parity error.
507 	 */
508 	if ((stat & 0x1ff) == 0)
509 		c |= TTY_FE;
510 	else if ((tp->t_cflag & PARENB) &&
511 		    (((ch >> 7) + even_parity[ch & 0x7f]
512 		    + !!(tp->t_cflag & PARODD)) & 1))
513 			c |= TTY_PE;
514 
515 	if (stat & SERDATRF_OVRUN)
516 		log(LOG_WARNING, "ser0: silo overflow\n");
517 
518 	(*linesw[tp->t_line].l_rint)(c, tp);
519 }
520 
521 /*
522  * This interrupt is periodically invoked in the vertical blank
523  * interrupt.  It's used to keep track of the modem control lines
524  * and (new with the fast_int code) to move accumulated data
525  * up into the tty layer.
526  */
527 void
528 sermint(unit)
529 	int unit;
530 {
531 	struct tty *tp;
532 	u_char stat, last, istat;
533 
534 	tp = ser_tty[unit];
535 	if (!tp)
536 		return;
537 
538 	if ((tp->t_state & (TS_ISOPEN | TS_WOPEN)) == 0) {
539 		sbrpt = sbwpt = serbuf;
540 		return;
541 	}
542 	/*
543 	 * empty buffer
544 	 */
545 	serintr(unit);
546 
547 	stat = ciab.pra;
548 	last = last_ciab_pra;
549 	last_ciab_pra = stat;
550 
551 	/*
552 	 * check whether any interesting signal changed state
553 	 */
554 	istat = stat ^ last;
555 
556 	if ((istat & CIAB_PRA_CD) &&
557 	    (SWFLAGS(tp->t_dev) & TIOCFLAG_SOFTCAR) == 0) {
558 		if (ISDCD(stat))
559 			(*linesw[tp->t_line].l_modem)(tp, 1);
560 		else if ((*linesw[tp->t_line].l_modem)(tp, 0) == 0) {
561 			CLRDTR(stat);
562 			CLRRTS(stat);
563 			ciab.pra = stat;
564 			last_ciab_pra = stat;
565 		}
566 	}
567 	if ((istat & CIAB_PRA_CTS) && (tp->t_state & TS_ISOPEN) &&
568 	    (tp->t_cflag & CRTSCTS)) {
569 #if 0
570 		/* the line is up and we want to do rts/cts flow control */
571 		if (ISCTS(stat)) {
572 			tp->t_state &= ~TS_TTSTOP;
573 			ttstart(tp);
574 			/* cause tbe-int if we were stuck there */
575 			custom.intreq = INTF_SETCLR | INTF_TBE;
576 		} else
577 			tp->t_state |= TS_TTSTOP;
578 #else
579 		/* do this on hardware level, not with tty driver */
580 		if (ISCTS(stat)) {
581 			tp->t_state &= ~TS_TTSTOP;
582 			/* cause TBE interrupt */
583 			custom.intreq = INTF_SETCLR | INTF_TBE;
584 		}
585 #endif
586 	}
587 }
588 
589 int
590 serioctl(dev, cmd, data, flag, p)
591 	dev_t	dev;
592 	caddr_t data;
593 	struct proc *p;
594 {
595 	register struct tty *tp;
596 	register int unit = SERUNIT(dev);
597 	register int error;
598 
599 	tp = ser_tty[unit];
600 	if (!tp)
601 		return ENXIO;
602 
603 	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
604 	if (error >= 0)
605 		return(error);
606 
607 	error = ttioctl(tp, cmd, data, flag, p);
608 	if (error >= 0)
609 		return(error);
610 
611 	switch (cmd) {
612 	case TIOCSBRK:
613 		custom.adkcon = ADKCONF_SETCLR | ADKCONF_UARTBRK;
614 		break;
615 
616 	case TIOCCBRK:
617 		custom.adkcon = ADKCONF_UARTBRK;
618 		break;
619 
620 	case TIOCSDTR:
621 		(void) sermctl(dev, TIOCM_DTR | TIOCM_RTS, DMBIS);
622 		break;
623 
624 	case TIOCCDTR:
625 		(void) sermctl(dev, TIOCM_DTR | TIOCM_RTS, DMBIC);
626 		break;
627 
628 	case TIOCMSET:
629 		(void) sermctl(dev, *(int *) data, DMSET);
630 		break;
631 
632 	case TIOCMBIS:
633 		(void) sermctl(dev, *(int *) data, DMBIS);
634 		break;
635 
636 	case TIOCMBIC:
637 		(void) sermctl(dev, *(int *) data, DMBIC);
638 		break;
639 
640 	case TIOCMGET:
641 		*(int *)data = sermctl(dev, 0, DMGET);
642 		break;
643 	case TIOCGFLAGS:
644 		*(int *)data = SWFLAGS(dev);
645 		break;
646 	case TIOCSFLAGS:
647 		error = suser(p->p_ucred, &p->p_acflag);
648 		if (error != 0)
649 			return(EPERM);
650 
651 		serswflags = *(int *)data;
652                 serswflags &= /* only allow valid flags */
653                   (TIOCFLAG_SOFTCAR | TIOCFLAG_CLOCAL | TIOCFLAG_CRTSCTS);
654 		break;
655 	default:
656 		return(ENOTTY);
657 	}
658 
659 	return(0);
660 }
661 
662 int
663 serparam(tp, t)
664 	struct tty *tp;
665 	struct termios *t;
666 {
667 	int cfcr, cflag, unit, ospeed;
668 
669 	cflag = t->c_cflag;
670 	unit = SERUNIT(tp->t_dev);
671 	ospeed = ttspeedtab(t->c_ospeed, serspeedtab);
672 
673 	if (ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed))
674 		return(EINVAL);
675 
676 	/*
677 	 * copy to tty
678 	 */
679 	tp->t_ispeed = t->c_ispeed;
680 	tp->t_ospeed = t->c_ospeed;
681 	tp->t_cflag = cflag;
682 
683 	/*
684 	 * enable interrupts
685 	 */
686 	custom.intena = INTF_SETCLR | INTF_RBF | INTF_TBE;
687 	last_ciab_pra = ciab.pra;
688 
689 	if (ospeed == 0)
690 		(void)sermctl(tp->t_dev, 0, DMSET);	/* hang up line */
691 	else {
692 		/*
693 		 * (re)enable DTR
694 		 * and set baud rate. (8 bit mode)
695 		 */
696 		(void)sermctl(tp->t_dev, TIOCM_DTR | TIOCM_RTS, DMSET);
697 		custom.serper = (0 << 15) | ospeed;
698 	}
699 	return(0);
700 }
701 
702 
703 static void
704 ser_putchar(tp, c)
705 	struct tty *tp;
706 	u_short c;
707 {
708 	if ((tp->t_cflag & CSIZE) == CS7 || (tp->t_cflag & PARENB))
709 		c &= 0x7f;
710 
711 	/*
712 	 * handle parity if necessary
713 	 */
714 	if (tp->t_cflag & PARENB) {
715 		if (even_parity[c])
716 			c |= 0x80;
717 		if (tp->t_cflag & PARODD)
718 			c ^= 0x80;
719 	}
720 	/*
721 	 * add stop bit(s)
722 	 */
723 	if (tp->t_cflag & CSTOPB)
724 		c |= 0x300;
725 	else
726 		c |= 0x100;
727 
728 	custom.serdat = c;
729 }
730 
731 
732 static u_char ser_outbuf[SEROBUF_SIZE];
733 static u_char *sob_ptr = ser_outbuf, *sob_end = ser_outbuf;
734 
735 void
736 ser_outintr()
737 {
738 	struct tty *tp = ser_tty[0];
739 	u_short c;
740 	int s;
741 
742 	tp = ser_tty[0];
743 	s = spltty();
744 
745 	if (tp == 0)
746 		goto out;
747 
748 	if ((custom.intreqr & INTF_TBE) == 0)
749 		goto out;
750 
751 	/*
752 	 * clear interrupt
753 	 */
754 	custom.intreq = INTF_TBE;
755 
756 	if (sob_ptr == sob_end) {
757 		tp->t_state &= ~(TS_BUSY | TS_FLUSH);
758 		if (tp->t_line)
759 			(*linesw[tp->t_line].l_start)(tp);
760 		else
761 			serstart(tp);
762 		goto out;
763 	}
764 
765 	/*
766 	 * Do hardware flow control here.  if the CTS line goes down, don't
767 	 * transmit anything.  That way, we'll be restarted by the periodic
768 	 * interrupt when CTS comes back up.
769 	 */
770 	if (ISCTS(ciab.pra))
771 		ser_putchar(tp, *sob_ptr++);
772 out:
773 	splx(s);
774 }
775 
776 int
777 serstart(tp)
778 	struct tty *tp;
779 {
780 	int cc, s, unit, hiwat;
781 
782 	hiwat = 0;
783 
784 	if ((tp->t_state & TS_ISOPEN) == 0)
785 		return;
786 
787 	unit = SERUNIT(tp->t_dev);
788 
789 	s = spltty();
790 	if (tp->t_state & (TS_TIMEOUT | TS_TTSTOP))
791 		goto out;
792 
793 	cc = tp->t_outq.c_cc;
794 	if (cc <= tp->t_lowat) {
795 		if (tp->t_state & TS_ASLEEP) {
796 			tp->t_state &= ~TS_ASLEEP;
797 			wakeup((caddr_t) & tp->t_outq);
798 		}
799 		selwakeup(&tp->t_wsel);
800 	}
801 	if (cc == 0 || (tp->t_state & TS_BUSY))
802 		goto out;
803 
804 	/*
805 	 * We only do bulk transfers if using CTSRTS flow control, not for
806 	 * (probably sloooow) ixon/ixoff devices.
807 	 */
808 	if ((tp->t_cflag & CRTSCTS) == 0)
809 		cc = 1;
810 
811 	/*
812 	 * Limit the amount of output we do in one burst
813 	 * to prevent hogging the CPU.
814 	 */
815 	if (cc > SEROBUF_SIZE) {
816 		hiwat++;
817 		cc = SEROBUF_SIZE;
818 	}
819 	cc = q_to_b(&tp->t_outq, ser_outbuf, cc);
820 	if (cc > 0) {
821 		tp->t_state |= TS_BUSY;
822 
823 		sob_ptr = ser_outbuf;
824 		sob_end = ser_outbuf + cc;
825 
826 		/*
827 		 * Get first character out, then have TBE-interrupts blow out
828 		 * further characters, until buffer is empty, and TS_BUSY gets
829 		 * cleared.
830 		 */
831 		ser_putchar(tp, *sob_ptr++);
832 	}
833 out:
834 	splx(s);
835 }
836 
837 /*
838  * Stop output on a line.
839  */
840 /*ARGSUSED*/
841 int
842 serstop(tp, flag)
843 	struct tty *tp;
844 {
845 	int s;
846 
847 	s = spltty();
848 	if (tp->t_state & TS_BUSY) {
849 		if ((tp->t_state & TS_TTSTOP) == 0)
850 			tp->t_state |= TS_FLUSH;
851 	}
852 	splx(s);
853 }
854 
855 int
856 sermctl(dev, bits, how)
857 	dev_t dev;
858 	int bits, how;
859 {
860 	int unit, s;
861 	u_char ub;
862 
863 	unit = SERUNIT(dev);
864 
865 	/*
866 	 * convert TIOCM* mask into CIA mask
867 	 * which is active low
868 	 */
869 	if (how != DMGET) {
870 		ub = 0;
871 		if (bits & TIOCM_DTR)
872 			ub |= CIAB_PRA_DTR;
873 		if (bits & TIOCM_RTS)
874 			ub |= CIAB_PRA_RTS;
875 		if (bits & TIOCM_CTS)
876 			ub |= CIAB_PRA_CTS;
877 		if (bits & TIOCM_CD)
878 			ub |= CIAB_PRA_CD;
879 		if (bits & TIOCM_RI)
880 			ub |= CIAB_PRA_SEL;	/* collision with /dev/par ! */
881 		if (bits & TIOCM_DSR)
882 			ub |= CIAB_PRA_DSR;
883 	}
884 	s = spltty();
885 	switch (how) {
886 	case DMSET:
887 		/* invert and set */
888 		ciab.pra = ~ub;
889 		break;
890 
891 	case DMBIC:
892 		ciab.pra |= ub;
893 		ub = ~ciab.pra;
894 		break;
895 
896 	case DMBIS:
897 		ciab.pra &= ~ub;
898 		ub = ~ciab.pra;
899 		break;
900 
901 	case DMGET:
902 		ub = ~ciab.pra;
903 		break;
904 	}
905 	(void)splx(s);
906 
907 	bits = 0;
908 	if (ub & CIAB_PRA_DTR)
909 		bits |= TIOCM_DTR;
910 	if (ub & CIAB_PRA_RTS)
911 		bits |= TIOCM_RTS;
912 	if (ub & CIAB_PRA_CTS)
913 		bits |= TIOCM_CTS;
914 	if (ub & CIAB_PRA_CD)
915 		bits |= TIOCM_CD;
916 	if (ub & CIAB_PRA_SEL)
917 		bits |= TIOCM_RI;
918 	if (ub & CIAB_PRA_DSR)
919 		bits |= TIOCM_DSR;
920 
921 	return(bits);
922 }
923 
924 /*
925  * Following are all routines needed for SER to act as console
926  */
927 int
928 sercnprobe(cp)
929 	struct consdev *cp;
930 {
931 	int unit = CONUNIT;
932 
933 	/* locate the major number */
934 	for (sermajor = 0; sermajor < nchrdev; sermajor++)
935 		if (cdevsw[sermajor].d_open == (void *)seropen)
936 			break;
937 
938 
939 	unit = CONUNIT;			/* XXX: ick */
940 
941 	/*
942 	 * initialize required fields
943 	 */
944 	cp->cn_dev = makedev(sermajor, unit);
945 	if (serconsole == unit)
946 		cp->cn_pri = CN_REMOTE;
947 	else
948 		cp->cn_pri = CN_NORMAL;
949 #ifdef KGDB
950 	if (major(kgdb_dev) == 1)	/* XXX */
951 		kgdb_dev = makedev(sermajor, minor(kgdb_dev));
952 #endif
953 }
954 
955 sercninit(cp)
956 	struct consdev *cp;
957 {
958 	int unit;
959 
960 	unit = SERUNIT(cp->cn_dev);
961 
962 	serinit(unit, serdefaultrate);
963 	serconsole = unit;
964 	serconsinit = 1;
965 }
966 
967 serinit(unit, rate)
968 	int unit, rate;
969 {
970 	int s;
971 
972 	s = splhigh();
973 	/*
974 	 * might want to fiddle with the CIA later ???
975 	 */
976 	custom.serper = ttspeedtab(rate, serspeedtab);
977 	splx(s);
978 }
979 
980 sercngetc(dev)
981 {
982 	u_short stat;
983 	int c, s;
984 
985 	s = splhigh();
986 	/*
987 	 * poll
988 	 */
989 	while (((stat = custom.serdatr & 0xffff) & SERDATRF_RBF) == 0)
990 		;
991 	c = stat & 0xff;
992 	/*
993 	 * clear interrupt
994 	 */
995 	custom.intreq = INTF_RBF;
996 	splx(s);
997 	return(c);
998 }
999 
1000 /*
1001  * Console kernel output character routine.
1002  */
1003 sercnputc(dev, c)
1004 	dev_t dev;
1005 	int c;
1006 {
1007 	register int timo;
1008 	short stat;
1009 	int s;
1010 
1011 	s = splhigh();
1012 
1013 	if (serconsinit == 0) {
1014 		(void)serinit(SERUNIT(dev), serdefaultrate);
1015 		serconsinit = 1;
1016 	}
1017 
1018 	/*
1019 	 * wait for any pending transmission to finish
1020 	 */
1021 	timo = 50000;
1022 	while (!(custom.serdatr & SERDATRF_TBE) && --timo);
1023 
1024 	/*
1025 	 * transmit char.
1026 	 */
1027 	custom.serdat = (c & 0xff) | 0x100;
1028 
1029 	/*
1030 	 * wait for this transmission to complete
1031 	 */
1032 	timo = 1500000;
1033 	while (!(custom.serdatr & SERDATRF_TBE) && --timo)
1034 		;
1035 
1036 	/*
1037 	 * Wait for the device (my vt100..) to process the data, since we
1038 	 * don't do flow-control with cnputc
1039 	 */
1040 	for (timo = 0; timo < 30000; timo++)
1041 		;
1042 
1043 	/*
1044 	 * clear any interrupts generated by this transmission
1045 	 */
1046 	custom.intreq = INTF_TBE;
1047 	splx(s);
1048 }
1049 
1050 #if 0
1051 serspit(c)
1052 	int c;
1053 {
1054 	extern int cold;
1055 	register struct Custom *cu asm("a2") = (struct Custom *) CUSTOMbase;
1056 	register int timo asm("d2");
1057 	int s;
1058 
1059 	if (c == 10)
1060 		serspit(13);
1061 
1062 	s = splhigh();
1063 
1064 	/* wait for any pending transmission to finish */
1065 	timo = 500000;
1066 	while (!(cu->serdatr & (SERDATRF_TBE | SERDATRF_TSRE)) && --timo)
1067 		;
1068 
1069 	cu->serdat = (c & 0xff) | 0x100;
1070 
1071 	/* wait for this transmission to complete */
1072 	timo = 15000000;
1073 	while (!(cu->serdatr & SERDATRF_TBE) && --timo)
1074 		;
1075 
1076 	/* clear any interrupts generated by this transmission */
1077 	cu->intreq = INTF_TBE;
1078 
1079 	for (timo = 0; timo < 30000; timo++)
1080 		;
1081 
1082 	splx(s);
1083 }
1084 serspits(cp)
1085 	char *cp;
1086 {
1087 	while (*cp)
1088 		serspit(*cp++);
1089 }
1090 #endif
1091 #endif
1092