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