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