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