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