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