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