Home | History | Annotate | Line # | Download | only in dev
ser.c revision 1.2
      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  *	from: @(#)ser.c	7.12 (Berkeley) 6/27/91
     34  *	$Id: ser.c,v 1.2 1993/08/01 19:23:20 mycroft Exp $
     35  */
     36 
     37 #include "ser.h"
     38 
     39 #if NSER > 0
     40 #include "sys/param.h"
     41 #include "sys/systm.h"
     42 #include "sys/ioctl.h"
     43 #include "sys/tty.h"
     44 #include "sys/proc.h"
     45 #include "sys/conf.h"
     46 #include "sys/file.h"
     47 #include "sys/malloc.h"
     48 #include "sys/uio.h"
     49 #include "sys/kernel.h"
     50 #include "sys/syslog.h"
     51 
     52 #include "device.h"
     53 #include "serreg.h"
     54 #include "machine/cpu.h"
     55 
     56 #include "../amiga/custom.h"
     57 #include "../amiga/cia.h"
     58 
     59 int	serprobe();
     60 struct	driver serdriver = {
     61 	serprobe, "ser",
     62 };
     63 
     64 int	serstart(), serparam(), serintr();
     65 int	sersoftCAR;
     66 int	ser_active;
     67 int	ser_hasfifo;
     68 int	nser = NSER;
     69 #ifdef SERCONSOLE
     70 int	serconsole = SERCONSOLE;
     71 #else
     72 int	serconsole = -1;
     73 #endif
     74 int	serconsinit;
     75 int	serdefaultrate = TTYDEF_SPEED;
     76 int	sermajor;
     77 struct	serdevice *ser_addr[NSER];
     78 struct	tty ser_cons;
     79 struct	tty *ser_tty[NSER] = { &ser_cons };
     80 
     81 struct speedtab serspeedtab[] = {
     82 	0,	0,
     83 	50,	SERBRD(50),
     84 	75,	SERBRD(75),
     85 	110,	SERBRD(110),
     86 	134,	SERBRD(134),
     87 	150,	SERBRD(150),
     88 	200,	SERBRD(200),
     89 	300,	SERBRD(300),
     90 	600,	SERBRD(600),
     91 	1200,	SERBRD(1200),
     92 	1800,	SERBRD(1800),
     93 	2400,	SERBRD(2400),
     94 	4800,	SERBRD(4800),
     95 	9600,	SERBRD(9600),
     96 	19200,	SERBRD(19200),
     97 	38400,	SERBRD(38400),
     98 	-1,	-1
     99 };
    100 
    101 
    102 /* since this UART is not particularly bright (nice put), we'll have to do
    103    parity stuff on our own. this table contains the 8th bit in 7bit character
    104    mode, for even parity. If you want odd parity, flip the bit. (for
    105    generation of the table, see genpar.c) */
    106 
    107 u_char even_parity[] = {
    108    0,  1,  1,  0,  1,  0,  0,  1,  1,  0,  0,  1,  0,  1,  1,  0,
    109    1,  0,  0,  1,  0,  1,  1,  0,  0,  1,  1,  0,  1,  0,  0,  1,
    110    1,  0,  0,  1,  0,  1,  1,  0,  0,  1,  1,  0,  1,  0,  0,  1,
    111    0,  1,  1,  0,  1,  0,  0,  1,  1,  0,  0,  1,  0,  1,  1,  0,
    112    1,  0,  0,  1,  0,  1,  1,  0,  0,  1,  1,  0,  1,  0,  0,  1,
    113    0,  1,  1,  0,  1,  0,  0,  1,  1,  0,  0,  1,  0,  1,  1,  0,
    114    0,  1,  1,  0,  1,  0,  0,  1,  1,  0,  0,  1,  0,  1,  1,  0,
    115    1,  0,  0,  1,  0,  1,  1,  0,  0,  1,  1,  0,  1,  0,  0,  1,
    116 };
    117 
    118 
    119 /* since we don't get interrupts for changes on the modem control line,
    120    well have to fake them by comparing current settings to the settings
    121    we remembered on last invocation. */
    122 u_char last_ciab_pra;
    123 
    124 extern	struct tty *constty;
    125 #ifdef KGDB
    126 #include "machine/remote-sl.h"
    127 
    128 extern dev_t kgdb_dev;
    129 extern int kgdb_rate;
    130 extern int kgdb_debug_init;
    131 #endif
    132 
    133 #if 0
    134 #define	UNIT(x)		minor(x)
    135 #else
    136 /* just always force this to 0, so we can later interprete special
    137    settings out of the unit number.. */
    138 #define UNIT(x)		0
    139 #endif
    140 
    141 #ifdef DEBUG
    142 long	fifoin[17];
    143 long	fifoout[17];
    144 long	serintrcount[16];
    145 long	sermintcount[16];
    146 #endif
    147 
    148 serprobe(ad)
    149 	register struct amiga_device *ad;
    150 {
    151 	register struct serdevice *ser;
    152 	register int unit;
    153 
    154 	ser = (struct serdevice *) ad->amiga_addr;
    155 	unit = ad->amiga_unit;
    156 	if (unit == serconsole)
    157 		DELAY(100000);
    158 
    159 	ad->amiga_ipl = 2;
    160 	ser_addr[unit] = ser;
    161 	ser_active |= 1 << unit;
    162 	sersoftCAR = ad->amiga_flags;
    163 #ifdef KGDB
    164 	if (kgdb_dev == makedev(sermajor, unit)) {
    165 		if (serconsole == unit)
    166 			kgdb_dev = NODEV; /* can't debug over console port */
    167 		else {
    168 			(void) serinit(unit, kgdb_rate);
    169 			serconsinit = 1;	/* don't re-init in serputc */
    170 			if (kgdb_debug_init) {
    171 				/*
    172 				 * Print prefix of device name,
    173 				 * let kgdb_connect print the rest.
    174 				 */
    175 				printf("ser%d: ", unit);
    176 				kgdb_connect(1);
    177 			} else
    178 				printf("ser%d: kgdb enabled\n", unit);
    179 		}
    180 	}
    181 #endif
    182 	/*
    183 	 * Need to reset baud rate, etc. of next print so reset serconsinit.
    184 	 * Also make sure console is always "hardwired."
    185 	 */
    186 	if (unit == serconsole) {
    187 		serconsinit = 0;
    188 		sersoftCAR |= (1 << unit);
    189 	}
    190 	return (1);
    191 }
    192 
    193 /* ARGSUSED */
    194 #ifdef __STDC__
    195 seropen(dev_t dev, int flag, int mode, struct proc *p)
    196 #else
    197 seropen(dev, flag, mode, p)
    198 	dev_t dev;
    199 	int flag, mode;
    200 	struct proc *p;
    201 #endif
    202 {
    203 	register struct tty *tp;
    204 	register int unit;
    205 	int error = 0;
    206 
    207 	unit = minor (dev);
    208 
    209 	if (unit == 1)
    210 	  {
    211 	    unit = 0;
    212 	    sersoftCAR = 0;
    213 	  }
    214 	else if (unit == 2)
    215 	  {
    216 	    unit = 0;
    217 	    sersoftCAR = 0xff;
    218 	  }
    219 	else
    220 	  unit = 0;
    221 
    222 	if (unit >= NSER || (ser_active & (1 << unit)) == 0)
    223 		return (ENXIO);
    224 	if(!ser_tty[unit]) {
    225 		MALLOC(tp, struct tty *, sizeof(struct tty), M_TTYS, M_WAITOK);
    226 		bzero(tp, sizeof(struct tty));
    227 		ser_tty[unit] = tp;
    228 	} else
    229 		tp = ser_tty[unit];
    230 	tp->t_oproc = serstart;
    231 	tp->t_param = serparam;
    232 	tp->t_dev = dev;
    233 	if ((tp->t_state & TS_ISOPEN) == 0) {
    234 		tp->t_state |= TS_WOPEN;
    235 		ttychars(tp);
    236 		if (tp->t_ispeed == 0) {
    237 			tp->t_iflag = TTYDEF_IFLAG | IXOFF;	/* XXXXX */
    238 			tp->t_oflag = TTYDEF_OFLAG;
    239 #if 0
    240 			tp->t_cflag = TTYDEF_CFLAG;
    241 #else
    242 			tp->t_cflag = (CREAD | CS8 | CLOCAL);	/* XXXXX */
    243 #endif
    244 			tp->t_lflag = TTYDEF_LFLAG;
    245 			tp->t_ispeed = tp->t_ospeed = serdefaultrate;
    246 		}
    247 		serparam(tp, &tp->t_termios);
    248 		ttsetwater(tp);
    249 	} else if (tp->t_state&TS_XCLUDE && p->p_ucred->cr_uid != 0)
    250 		return (EBUSY);
    251 	(void) sermctl (dev, TIOCM_DTR | TIOCM_RTS, DMSET);
    252 	if ((sersoftCAR & (1 << unit)) || (sermctl(dev, 0, DMGET) & TIOCM_CD))
    253 		tp->t_state |= TS_CARR_ON;
    254 	(void) spltty();
    255 	while ((flag&O_NONBLOCK) == 0 && (tp->t_cflag&CLOCAL) == 0 &&
    256 	       (tp->t_state & TS_CARR_ON) == 0) {
    257 		tp->t_state |= TS_WOPEN;
    258 		if (error = ttysleep(tp, (caddr_t)&tp->t_raw, TTIPRI | PCATCH,
    259 		    ttopen, 0))
    260 			break;
    261 	}
    262 	(void) spl0();
    263 	if (error == 0)
    264 		error = (*linesw[tp->t_line].l_open)(dev, tp);
    265 	return (error);
    266 }
    267 
    268 /*ARGSUSED*/
    269 serclose(dev, flag, mode, p)
    270 	dev_t dev;
    271 	int flag, mode;
    272 	struct proc *p;
    273 {
    274 	register struct tty *tp;
    275 	register struct serdevice *ser;
    276 	register int unit;
    277 
    278 	unit = UNIT(dev);
    279 
    280 	ser = ser_addr[unit];
    281 	tp = ser_tty[unit];
    282 	(*linesw[tp->t_line].l_close)(tp, flag);
    283 	custom.adkcon = ADKCONF_UARTBRK;	/* clear break */
    284 #ifdef KGDB
    285 	/* do not disable interrupts if debugging */
    286 	if (dev != kgdb_dev)
    287 #endif
    288 	custom.intena = INTF_RBF | INTF_VERTB; /* clear interrupt enable */
    289 	custom.intreq = INTF_RBF | INTF_VERTB; /* and   interrupt request */
    290 #if 0
    291 /* if the device is closed, it's close, no matter whether we deal with modem
    292    control signals nor not. */
    293 	if (tp->t_cflag&HUPCL || tp->t_state&TS_WOPEN ||
    294 	    (tp->t_state&TS_ISOPEN) == 0)
    295 #endif
    296 		(void) sermctl(dev, 0, DMSET);
    297 	ttyclose(tp);
    298 #if 0
    299 	if (tp != &ser_cons)
    300 	  {
    301 	    FREE(tp, M_TTYS);
    302 	    ser_tty[unit] = (struct tty *)NULL;
    303 	  }
    304 #endif
    305 	return (0);
    306 }
    307 
    308 serread(dev, uio, flag)
    309 	dev_t dev;
    310 	struct uio *uio;
    311 {
    312 	register struct tty *tp = ser_tty[UNIT(dev)];
    313 	int error = (*linesw[tp->t_line].l_read)(tp, uio, flag);
    314 
    315 	return error;
    316 }
    317 
    318 serwrite(dev, uio, flag)
    319 	dev_t dev;
    320 	struct uio *uio;
    321 {
    322 	int unit = UNIT(dev);
    323 	register struct tty *tp = ser_tty[unit];
    324 
    325 	/*
    326 	 * (XXX) We disallow virtual consoles if the physical console is
    327 	 * a serial port.  This is in case there is a display attached that
    328 	 * is not the console.  In that situation we don't need/want the X
    329 	 * server taking over the console.
    330 	 */
    331 	if (constty && unit == serconsole)
    332 		constty = NULL;
    333 	return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
    334 }
    335 
    336 serintr(unit)
    337 	register int unit;
    338 {
    339 	register struct serdevice *ser;
    340 	register u_short code;
    341 	register u_char ch;
    342 	register u_short ints;
    343 	register struct tty *tp;
    344 
    345 	ser = ser_addr[unit];
    346 
    347 again:
    348 	ints = custom.intreqr & INTF_RBF;
    349 	if (! ints)
    350 	  return 0;
    351 
    352 	/* clear interrupt(s) */
    353 	custom.intreq = ints;
    354 
    355 	/* this register contains both data and status bits! */
    356 	code = custom.serdatr;
    357 
    358 	if (ints & INTF_RBF)
    359 	  {
    360 	    tp = ser_tty[unit];
    361 /*
    362  * Process a received byte.  Inline for speed...
    363  */
    364 #ifdef KGDB
    365 #define	RCVBYTE() \
    366 	    ch = code & 0xff; \
    367 	    if ((tp->t_state & TS_ISOPEN) == 0) { \
    368 		if (ch == FRAME_END && \
    369 		    kgdb_dev == makedev(sermajor, unit)) \
    370 			kgdb_connect(0); /* trap into kgdb */ \
    371 	    }
    372 #else
    373 #define	RCVBYTE()
    374 #endif
    375 	    RCVBYTE();
    376 	    /* sereint does the receive-processing */
    377 	    sereint (unit, code, ser);
    378 	  }
    379 
    380 	/* fake modem-control interrupt */
    381 	sermint (unit, ser);
    382 	/* try to save interrupt load.. */
    383 	goto again;
    384 }
    385 
    386 sereint(unit, stat, ser)
    387 	register int unit, stat;
    388 	register struct serdevice *ser;
    389 {
    390 	register struct tty *tp;
    391 	register int c;
    392 	register u_char ch;
    393 
    394 	tp = ser_tty[unit];
    395 	if ((tp->t_state & TS_ISOPEN) == 0) {
    396 #ifdef KGDB
    397 		/* we don't care about parity errors */
    398 		if (kgdb_dev == makedev(sermajor, unit) && c == FRAME_END)
    399 			kgdb_connect(0); /* trap into kgdb */
    400 #endif
    401 		return;
    402 	}
    403 	ch = stat & 0xff;
    404 	c = ch;
    405 	/* all databits 0 including stop indicate break condition */
    406 	if (!(stat & 0x1ff))
    407 	  c |= TTY_FE;
    408 
    409 	/* if parity checking enabled, check parity */
    410 	else if ((tp->t_cflag & PARENB) &&
    411 		 (((ch >> 7) + even_parity[ch & 0x7f] + !!(tp->t_cflag & PARODD)) & 1))
    412 	  c |= TTY_PE;
    413 
    414 	if (stat & SERDATRF_OVRUN)
    415 	  log(LOG_WARNING, "ser%d: silo overflow\n", unit);
    416 
    417 	(*linesw[tp->t_line].l_rint)(c, tp);
    418 }
    419 
    420 sermint(unit)
    421 	register int unit;
    422 {
    423 	register struct tty *tp;
    424 	register u_char stat, last, istat;
    425 	register struct serdevice *ser;
    426 
    427 	tp = ser_tty[unit];
    428 	stat = ciab.pra;
    429 	last = last_ciab_pra;
    430 	last_ciab_pra = stat;
    431 
    432 	/* check whether any interesting signal changed state */
    433 	istat = stat ^ last;
    434 
    435 	if ((istat & CIAB_PRA_CD) && (sersoftCAR & (1 << unit)) == 0)
    436 	  {
    437 	    if (ISDCD (stat))
    438 	      (*linesw[tp->t_line].l_modem)(tp, 1);
    439 	    else if ((*linesw[tp->t_line].l_modem)(tp, 0) == 0)
    440 	      {
    441 	        CLRDTR (stat);
    442 	        CLRRTS (stat);
    443 	        ciab.pra = stat;
    444 	        last_ciab_pra = stat;
    445 	      }
    446 	  }
    447 	else if ((istat & CIAB_PRA_CTS) && (tp->t_state & TS_ISOPEN) &&
    448 		 (tp->t_flags & CRTSCTS))
    449 	  {
    450 	    /* the line is up and we want to do rts/cts flow control */
    451 	    if (ISCTS (stat))
    452 	      {
    453 		tp->t_state &=~ TS_TTSTOP;
    454 		ttstart(tp);
    455 	      }
    456 	    else
    457 	      tp->t_state |= TS_TTSTOP;
    458 	}
    459 }
    460 
    461 serioctl(dev, cmd, data, flag)
    462 	dev_t dev;
    463 	caddr_t data;
    464 {
    465 	register struct tty *tp;
    466 	register int unit = UNIT(dev);
    467 	register struct serdevice *ser;
    468 	register int error;
    469 
    470 	tp = ser_tty[unit];
    471 	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag);
    472 	if (error >= 0)
    473 		return (error);
    474 	error = ttioctl(tp, cmd, data, flag);
    475 	if (error >= 0)
    476 		return (error);
    477 
    478 	ser = ser_addr[unit];
    479 	switch (cmd) {
    480 
    481 	case TIOCSBRK:
    482 		custom.adkcon = ADKCONF_SETCLR | ADKCONF_UARTBRK;
    483 		break;
    484 
    485 	case TIOCCBRK:
    486 		custom.adkcon = ADKCONF_UARTBRK;
    487 		break;
    488 
    489 	case TIOCSDTR:
    490 		(void) sermctl(dev, TIOCM_DTR | TIOCM_RTS, DMBIS);
    491 		break;
    492 
    493 	case TIOCCDTR:
    494 		(void) sermctl(dev, TIOCM_DTR | TIOCM_RTS, DMBIC);
    495 		break;
    496 
    497 	case TIOCMSET:
    498 		(void) sermctl(dev, *(int *)data, DMSET);
    499 		break;
    500 
    501 	case TIOCMBIS:
    502 		(void) sermctl(dev, *(int *)data, DMBIS);
    503 		break;
    504 
    505 	case TIOCMBIC:
    506 		(void) sermctl(dev, *(int *)data, DMBIC);
    507 		break;
    508 
    509 	case TIOCMGET:
    510 		*(int *)data = sermctl(dev, 0, DMGET);
    511 		break;
    512 
    513 	default:
    514 		return (ENOTTY);
    515 	}
    516 	return (0);
    517 }
    518 
    519 serparam(tp, t)
    520 	register struct tty *tp;
    521 	register struct termios *t;
    522 {
    523 	register struct serdevice *ser;
    524 	register int cfcr, cflag = t->c_cflag;
    525 	int unit = UNIT(tp->t_dev);
    526 	int ospeed = ttspeedtab(t->c_ospeed, serspeedtab);
    527 
    528 	/* check requested parameters */
    529         if (ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed))
    530                 return (EINVAL);
    531         /* and copy to tty */
    532         tp->t_ispeed = t->c_ispeed;
    533         tp->t_ospeed = t->c_ospeed;
    534         tp->t_cflag = cflag;
    535 
    536 	custom.intena = INTF_SETCLR | INTF_RBF;
    537 	custom.intreq = INTF_RBF;
    538 	last_ciab_pra = ciab.pra;
    539 
    540 	if (ospeed == 0) {
    541 		(void) sermctl(unit, 0, DMSET);	/* hang up line */
    542 		return (0);
    543 	}
    544 	/* set the baud rate */
    545 	custom.serper = (0<<15) | ospeed;  /* select 8 bit mode (instead of 9 bit) */
    546 
    547 	return (0);
    548 }
    549 
    550 serstart(tp)
    551 	register struct tty *tp;
    552 {
    553 	register struct serdevice *ser;
    554 	int s, unit;
    555 	u_short c;
    556 
    557 	unit = UNIT(tp->t_dev);
    558 	ser = ser_addr[unit];
    559 	s = spltty();
    560 again:
    561 	if (tp->t_state & (TS_TIMEOUT|TS_TTSTOP))
    562 		goto out;
    563 	if (RB_LEN(&tp->t_out) <= tp->t_lowat) {
    564 		if (tp->t_state&TS_ASLEEP) {
    565 			tp->t_state &= ~TS_ASLEEP;
    566 			wakeup((caddr_t)&tp->t_out);
    567 		}
    568 		selwakeup (&tp->t_wsel);
    569 	}
    570 	if (RB_LEN(&tp->t_out) == 0)
    571 		goto out;
    572 
    573 	while (! (custom.serdatr & SERDATRF_TBE)) ;
    574 
    575 	c = rbgetc(&tp->t_out);
    576 	/* tp->t_state |= TS_BUSY; */
    577 
    578 	/* handle truncation of character if necessary */
    579 	if ((tp->t_cflag & CSIZE) == CS7)
    580 	  c &= 0x7f;
    581 
    582 	/* handle parity if necessary (forces CS7) */
    583 	if (tp->t_cflag & PARENB)
    584 	  {
    585 	    if (even_parity[c & 0x7f])
    586 	      c |= 0x80;
    587 	    if (tp->t_cflag & PARODD)
    588 	      c ^= 0x80;
    589 	  }
    590 
    591 	/* add stop bit(s) */
    592 	if (tp->t_cflag & CSTOPB)
    593 	  c |= 0x300;
    594 	else
    595 	  c |= 0x100;
    596 
    597 	custom.serdat = c;
    598 
    599 	/* if there's input on the line, stop spitting out characters */
    600 	if (! (custom.intreqr & INTF_RBF))
    601 	  goto again;
    602 
    603 out:
    604 	splx(s);
    605 }
    606 
    607 /*
    608  * Stop output on a line.
    609  */
    610 /*ARGSUSED*/
    611 serstop(tp, flag)
    612 	register struct tty *tp;
    613 {
    614 	register int s;
    615 
    616 	s = spltty();
    617 	if (tp->t_state & TS_BUSY) {
    618 		if ((tp->t_state&TS_TTSTOP)==0)
    619 			tp->t_state |= TS_FLUSH;
    620 	}
    621 	splx(s);
    622 }
    623 
    624 sermctl(dev, bits, how)
    625 	dev_t dev;
    626 	int bits, how;
    627 {
    628 	register struct serdevice *ser;
    629 	register int unit;
    630 	u_char ub;
    631 	int s;
    632 
    633 	unit = UNIT(dev);
    634 	ser = ser_addr[unit];
    635 
    636 	/* convert TIOCM* mask into CIA mask (which is really low-active!!) */
    637 	if (how != DMGET)
    638 	  {
    639 	    ub = 0;
    640 	    if (bits & TIOCM_DTR) ub |= CIAB_PRA_DTR;
    641 	    if (bits & TIOCM_RTS) ub |= CIAB_PRA_RTS;
    642 	    if (bits & TIOCM_CTS) ub |= CIAB_PRA_CTS;
    643 	    if (bits & TIOCM_CD)  ub |= CIAB_PRA_CD;
    644 	    if (bits & TIOCM_RI)  ub |= CIAB_PRA_SEL;	/* collision with /dev/par ! */
    645 	    if (bits & TIOCM_DSR) ub |= CIAB_PRA_DSR;
    646 	  }
    647 
    648 
    649 	s = spltty();
    650 	switch (how) {
    651 
    652 	case DMSET:
    653 		/* invert and set */
    654 		ciab.pra = ~ub;
    655 		break;
    656 
    657 	case DMBIC:
    658 		ciab.pra |= ub;
    659 		ub = ~ciab.pra;
    660 		break;
    661 
    662 	case DMBIS:
    663 		ciab.pra &= ~ub;
    664 		ub = ~ciab.pra;
    665 		break;
    666 
    667 	case DMGET:
    668 		ub = ~ciab.pra;
    669 		break;
    670 	}
    671 	(void) splx(s);
    672 
    673 	bits = 0;
    674 	if (ub & CIAB_PRA_DTR) bits |= TIOCM_DTR;
    675 	if (ub & CIAB_PRA_RTS) bits |= TIOCM_RTS;
    676 	if (ub & CIAB_PRA_CTS) bits |= TIOCM_CTS;
    677 	if (ub & CIAB_PRA_CD)  bits |= TIOCM_CD;
    678 	if (ub & CIAB_PRA_SEL) bits |= TIOCM_RI;
    679 	if (ub & CIAB_PRA_DSR) bits |= TIOCM_DSR;
    680 
    681 	return bits;
    682 }
    683 
    684 /*
    685  * Following are all routines needed for SER to act as console
    686  */
    687 #include "../amiga/cons.h"
    688 
    689 sercnprobe(cp)
    690 	struct consdev *cp;
    691 {
    692 	int unit = CONUNIT;
    693 
    694 	/* locate the major number */
    695 	for (sermajor = 0; sermajor < nchrdev; sermajor++)
    696 		if (cdevsw[sermajor].d_open == seropen)
    697 			break;
    698 
    699 	/* XXX: ick */
    700 	unit = CONUNIT;
    701 
    702 	/* initialize required fields */
    703 	cp->cn_dev = makedev(sermajor, unit);
    704 	cp->cn_tp = ser_tty[unit];
    705 	cp->cn_pri = CN_NORMAL;
    706 
    707 	/*
    708 	 * If serconsole is initialized, raise our priority.
    709 	 */
    710 	if (serconsole == unit)
    711 		cp->cn_pri = CN_REMOTE;
    712 #ifdef KGDB
    713 	if (major(kgdb_dev) == 1)			/* XXX */
    714 		kgdb_dev = makedev(sermajor, minor(kgdb_dev));
    715 #endif
    716 }
    717 
    718 sercninit(cp)
    719 	struct consdev *cp;
    720 {
    721 	int unit = UNIT(cp->cn_dev);
    722 
    723 	serinit(unit, serdefaultrate);
    724 	serconsole = unit;
    725 	serconsinit = 1;
    726 }
    727 
    728 serinit(unit, rate)
    729 	int unit, rate;
    730 {
    731 	int s;
    732 
    733 #ifdef lint
    734 	stat = unit; if (stat) return;
    735 #endif
    736 	s = splhigh();
    737 	/* might want to fiddle with the CIA later ??? */
    738 	custom.serper = ttspeedtab(rate, serspeedtab);
    739 	splx(s);
    740 }
    741 
    742 sercngetc(dev)
    743 {
    744 	u_short stat;
    745 	int c, s;
    746 
    747 #ifdef lint
    748 	stat = dev; if (stat) return (0);
    749 #endif
    750 	s = splhigh();
    751 	while (!((stat = custom.serdatr & 0xffff) & SERDATRF_RBF))
    752 		;
    753 	c = stat & 0xff;
    754 	/* clear interrupt */
    755 	custom.intreq = INTF_RBF;
    756 	splx(s);
    757 	return (c);
    758 }
    759 
    760 /*
    761  * Console kernel output character routine.
    762  */
    763 sercnputc(dev, c)
    764 	dev_t dev;
    765 	register int c;
    766 {
    767 	register int timo;
    768 	short stat;
    769 	int s = splhigh();
    770 
    771 #ifdef lint
    772 	stat = dev; if (stat) return;
    773 #endif
    774 	if (serconsinit == 0) {
    775 		(void) serinit(UNIT(dev), serdefaultrate);
    776 		serconsinit = 1;
    777 	}
    778 	/* wait for any pending transmission to finish */
    779 	timo = 50000;
    780         while (! (custom.serdatr & SERDATRF_TBE) && --timo)
    781 		;
    782         custom.serdat = (c&0xff) | 0x100;
    783 	/* wait for this transmission to complete */
    784 	timo = 1500000;
    785         while (! (custom.serdatr & SERDATRF_TBE) && --timo)
    786 		;
    787 	/* wait for the device (my vt100..) to process the data, since
    788 	   we don't do flow-control with cnputc */
    789         for (timo = 0; timo < 30000; timo++) ;
    790 
    791 	/* clear any interrupts generated by this transmission */
    792         custom.intreq = INTF_TBE;
    793 	splx(s);
    794 }
    795 
    796 
    797 serspit(c)
    798 	int c;
    799 {
    800 	register struct Custom *cu asm("a2") = CUSTOMbase;
    801 	register int timo asm("d2");
    802 	extern int cold;
    803 	int s;
    804 
    805 	if (c == 10)
    806 	  serspit (13);
    807 
    808 	s = splhigh();
    809 
    810 	/* wait for any pending transmission to finish */
    811 	timo = 500000;
    812         while (! (cu->serdatr & (SERDATRF_TBE|SERDATRF_TSRE)) && --timo)
    813 		;
    814         cu->serdat = (c&0xff) | 0x100;
    815 	/* wait for this transmission to complete */
    816 	timo = 15000000;
    817         while (! (cu->serdatr & SERDATRF_TBE) && --timo)
    818 		;
    819 	/* clear any interrupts generated by this transmission */
    820         cu->intreq = INTF_TBE;
    821 
    822         for (timo = 0; timo < 30000; timo++) ;
    823 
    824 	splx (s);
    825 }
    826 
    827 int
    828 serselect(dev, rw, p)
    829 	dev_t dev;
    830 	int rw;
    831 	struct proc *p;
    832 {
    833 	register struct tty *tp = ser_tty[UNIT(dev)];
    834 	int nread;
    835 	int s = spltty();
    836         struct proc *selp;
    837 
    838 	switch (rw) {
    839 
    840 	case FREAD:
    841 		nread = ttnread(tp);
    842 		if (nread > 0 ||
    843 		   ((tp->t_cflag&CLOCAL) == 0 && (tp->t_state&TS_CARR_ON) == 0))
    844 			goto win;
    845 		selrecord(p, &tp->t_rsel);
    846 		break;
    847 
    848 	case FWRITE:
    849 		if (RB_LEN(&tp->t_out) <= tp->t_lowat)
    850 			goto win;
    851 		selrecord(p, &tp->t_wsel);
    852 		break;
    853 	}
    854 	splx(s);
    855 	return (0);
    856   win:
    857 	splx(s);
    858 	return (1);
    859 }
    860 
    861 #endif
    862