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