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