Home | History | Annotate | Line # | Download | only in dev
ser.c revision 1.8
      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 int	ser_active;
     66 int	ser_hasfifo;
     67 int	nser = NSER;
     68 #ifdef SERCONSOLE
     69 int	serconsole = SERCONSOLE;
     70 #else
     71 int	serconsole = -1;
     72 #endif
     73 int	serconsinit;
     74 int	serdefaultrate = TTYDEF_SPEED;
     75 int	sermajor;
     76 struct	serdevice *ser_addr[NSER];
     77 struct	vbl_node ser_vbl_node[NSER];
     78 struct	tty ser_cons;
     79 struct	tty *ser_tty[NSER];
     80 
     81 struct speedtab serspeedtab[] = {
     82 	0,	0,
     83 	50,	SERBRD(50),
     84 	75,	SERBRD(75),
     85 	110,	SERBRD(110),
     86 	134,	SERBRD(134),
     87 	150,	SERBRD(150),
     88 	200,	SERBRD(200),
     89 	300,	SERBRD(300),
     90 	600,	SERBRD(600),
     91 	1200,	SERBRD(1200),
     92 	1800,	SERBRD(1800),
     93 	2400,	SERBRD(2400),
     94 	4800,	SERBRD(4800),
     95 	9600,	SERBRD(9600),
     96 	19200,	SERBRD(19200),
     97 	38400,	SERBRD(38400),
     98 	-1,	-1
     99 };
    100 
    101 
    102 /* since this UART is not particularly bright (nice put), we'll have to do
    103    parity stuff on our own. this table contains the 8th bit in 7bit character
    104    mode, for even parity. If you want odd parity, flip the bit. (for
    105    generation of the table, see genpar.c) */
    106 
    107 u_char even_parity[] = {
    108    0,  1,  1,  0,  1,  0,  0,  1,  1,  0,  0,  1,  0,  1,  1,  0,
    109    1,  0,  0,  1,  0,  1,  1,  0,  0,  1,  1,  0,  1,  0,  0,  1,
    110    1,  0,  0,  1,  0,  1,  1,  0,  0,  1,  1,  0,  1,  0,  0,  1,
    111    0,  1,  1,  0,  1,  0,  0,  1,  1,  0,  0,  1,  0,  1,  1,  0,
    112    1,  0,  0,  1,  0,  1,  1,  0,  0,  1,  1,  0,  1,  0,  0,  1,
    113    0,  1,  1,  0,  1,  0,  0,  1,  1,  0,  0,  1,  0,  1,  1,  0,
    114    0,  1,  1,  0,  1,  0,  0,  1,  1,  0,  0,  1,  0,  1,  1,  0,
    115    1,  0,  0,  1,  0,  1,  1,  0,  0,  1,  1,  0,  1,  0,  0,  1,
    116 };
    117 
    118 
    119 /* since we don't get interrupts for changes on the modem control line,
    120    well have to fake them by comparing current settings to the settings
    121    we remembered on last invocation. */
    122 u_char last_ciab_pra;
    123 
    124 extern	struct tty *constty;
    125 #ifdef KGDB
    126 #include "machine/remote-sl.h"
    127 
    128 extern dev_t kgdb_dev;
    129 extern int kgdb_rate;
    130 extern int kgdb_debug_init;
    131 #endif
    132 
    133 #ifdef DEBUG
    134 long	fifoin[17];
    135 long	fifoout[17];
    136 long	serintrcount[16];
    137 long	sermintcount[16];
    138 #endif
    139 
    140 void sermint (register int unit);
    141 
    142 int
    143 serprobe(ad)
    144      register struct amiga_device *ad;
    145 {
    146   register struct serdevice *ser;
    147   register int unit;
    148   unsigned short ir = custom.intenar;
    149 
    150   ser = (struct serdevice *) ad->amiga_addr;
    151   unit = ad->amiga_unit;
    152   if (unit == serconsole)
    153     DELAY(100000);
    154 
    155   ad->amiga_ipl = 2;
    156   ser_addr[unit] = ser;
    157   ser_active |= 1 << unit;
    158   ser_vbl_node[unit].function = (void (*)(void *))sermint;
    159   add_vbl_function (&ser_vbl_node[unit], SER_VBL_PRIORITY, (void *)unit);
    160 #ifdef KGDB
    161   if (kgdb_dev == makedev(sermajor, unit)) {
    162     if (serconsole == unit)
    163       kgdb_dev = NODEV;		/* can't debug over console port */
    164     else {
    165       (void) serinit(unit, kgdb_rate);
    166       serconsinit = 1;		/* don't re-init in serputc */
    167       if (kgdb_debug_init) {
    168 	/*
    169 	 * Print prefix of device name,
    170 	 * let kgdb_connect print the rest.
    171 	 */
    172 	printf("ser%d: ", unit);
    173 	kgdb_connect(1);
    174       } else
    175 	printf("ser%d: kgdb enabled\n", unit);
    176     }
    177   }
    178 #endif
    179   /*
    180    * Need to reset baud rate, etc. of next print so reset serconsinit.
    181    */
    182   if (unit == serconsole)
    183     serconsinit = 0;
    184 
    185   return (1);
    186 }
    187 
    188 /* ARGSUSED */
    189 int
    190 #ifdef __STDC__
    191 seropen(dev_t dev, int flag, int mode, struct proc *p)
    192 #else
    193 seropen(dev, flag, mode, p)
    194      dev_t dev;
    195      int flag, mode;
    196      struct proc *p;
    197 #endif
    198 {
    199   register struct tty *tp;
    200   register int unit;
    201   int error = 0;
    202   int s;
    203 
    204   unit = SERUNIT(dev);
    205 
    206   if (unit >= NSER || (ser_active & (1 << unit)) == 0)
    207     return (ENXIO);
    208   if(!ser_tty[unit])
    209     {
    210       tp = ser_tty[unit] = ttymalloc();
    211       /* default values are not optimal for this device, increase
    212 	 buffers */
    213       clfree(&tp->t_rawq);
    214       clfree(&tp->t_canq);
    215       clfree(&tp->t_outq);
    216       clalloc(&tp->t_rawq, 8192, 1);
    217       clalloc(&tp->t_canq, 8192, 1);
    218       clalloc(&tp->t_outq, 8192, 0);
    219     }
    220   else
    221     tp = ser_tty[unit];
    222 
    223   tp->t_oproc = (void (*)(struct tty *)) serstart;
    224   tp->t_param = serparam;
    225   tp->t_dev = dev;
    226 
    227   if ((tp->t_state & TS_ISOPEN) == 0)
    228     {
    229       tp->t_state |= TS_WOPEN;
    230       ttychars(tp);
    231       if (tp->t_ispeed == 0)
    232 	{
    233 	  tp->t_iflag = TTYDEF_IFLAG | IXOFF;	/* XXXXX */
    234 	  tp->t_oflag = TTYDEF_OFLAG;
    235 #if 0
    236 	  tp->t_cflag = TTYDEF_CFLAG;
    237 #else
    238 	  tp->t_cflag = (CREAD | CS8 | CLOCAL); /* XXXXX */
    239 #endif
    240 	  tp->t_lflag = TTYDEF_LFLAG;
    241 	  tp->t_ispeed = tp->t_ospeed = serdefaultrate;
    242 	}
    243       serparam(tp, &tp->t_termios);
    244       ttsetwater(tp);
    245     }
    246   else if (tp->t_state&TS_XCLUDE && p->p_ucred->cr_uid != 0)
    247     return (EBUSY);
    248 
    249   (void) sermctl (dev, TIOCM_DTR | TIOCM_RTS, DMSET);
    250 
    251   if (DIALOUT(dev) || (sermctl (dev, 0, DMGET) & TIOCM_CD))
    252     tp->t_state |= TS_CARR_ON;
    253 
    254   s = spltty();
    255   while ((flag & O_NONBLOCK) == 0
    256 	 && (tp->t_cflag & CLOCAL) == 0
    257 	 && (tp->t_state & TS_CARR_ON) == 0)
    258     {
    259       tp->t_state |= TS_WOPEN;
    260       if (error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI | PCATCH,
    261 			   ttopen, 0))
    262 	break;
    263     }
    264   splx (s);
    265   if (error == 0)
    266     {
    267       /* reset the tty pointer, as there could have been a dialout
    268 	 use of the tty with a dialin open waiting. */
    269       tp->t_dev = dev;
    270       error = (*linesw[tp->t_line].l_open)(dev, tp);
    271     }
    272   return (error);
    273 }
    274 
    275 /*ARGSUSED*/
    276 int
    277 serclose(dev, flag, mode, p)
    278      dev_t dev;
    279      int flag, mode;
    280      struct proc *p;
    281 {
    282   register struct tty *tp;
    283   register struct serdevice *ser;
    284   register int unit;
    285 
    286   unit = SERUNIT(dev);
    287 
    288   ser = ser_addr[unit];
    289   tp = ser_tty[unit];
    290   (*linesw[tp->t_line].l_close)(tp, flag);
    291   custom.adkcon = ADKCONF_UARTBRK; /* clear break */
    292 #ifdef KGDB
    293   /* do not disable interrupts if debugging */
    294   if (dev != kgdb_dev)
    295 #endif
    296     custom.intena = INTF_RBF|INTF_TBE; /* clear interrupt enable */
    297   custom.intreq = INTF_RBF|INTF_TBE; /* and   interrupt request */
    298 #if 0
    299   /* if the device is closed, it's close, no matter whether we deal with modem
    300      control signals nor not. */
    301   if (tp->t_cflag&HUPCL || tp->t_state&TS_WOPEN ||
    302       (tp->t_state&TS_ISOPEN) == 0)
    303 #endif
    304     (void) sermctl(dev, 0, DMSET);
    305   ttyclose(tp);
    306 #if 0
    307   if (tp != &ser_cons)
    308     {
    309       remove_vbl_function (&ser_vbl_node[unit]);
    310       ttyfree (tp);
    311       ser_tty[unit] = (struct tty *)NULL;
    312     }
    313 #endif
    314   return (0);
    315 }
    316 
    317 int
    318 serread(dev, uio, flag)
    319      dev_t dev;
    320      struct uio *uio;
    321 {
    322   register struct tty *tp = ser_tty[SERUNIT(dev)];
    323   int error;
    324 
    325   if (! tp)
    326     return ENXIO;
    327 
    328   error = (*linesw[tp->t_line].l_read)(tp, uio, flag);
    329 
    330   return error;
    331 }
    332 
    333 int
    334 serwrite(dev, uio, flag)
    335      dev_t dev;
    336      struct uio *uio;
    337 {
    338   int unit = SERUNIT(dev);
    339   register struct tty *tp = ser_tty[unit];
    340 
    341   if (! tp)
    342     return ENXIO;
    343 
    344   /*
    345    * (XXX) We disallow virtual consoles if the physical console is
    346    * a serial port.  This is in case there is a display attached that
    347    * is not the console.  In that situation we don't need/want the X
    348    * server taking over the console.
    349    */
    350   if (constty && unit == serconsole)
    351     constty = NULL;
    352   return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
    353 }
    354 
    355 
    356 /* don't do any processing of data here, so we store the raw code
    357    obtained from the uart register. In theory, 110kBaud gives you
    358    11kcps, so 16k buffer should be more than enough, interrupt
    359    latency of 1s should never happen, or something is seriously
    360    wrong.. */
    361 #define SERIBUF_SIZE 16384
    362 static u_short serbuf[SERIBUF_SIZE];
    363 static u_short *sbrpt = serbuf;
    364 static u_short *sbwpt = serbuf;
    365 
    366 
    367 /* this is a replacement for the lack of a hardware fifo. 32k should be
    368    enough (there's only one unit anyway, so this is not going to
    369    accumulate). */
    370 void
    371 ser_fastint ()
    372 {
    373   /* we're at RBE-level, which is higher than VBL-level which is used
    374      to periodically transmit contents of this buffer up one layer,
    375      so no spl-raising is necessary. */
    376 
    377   register u_short ints, code;
    378 
    379   ints = custom.intreqr & INTF_RBF;
    380   if (! ints)
    381     return;
    382 
    383   /* clear interrupt */
    384   custom.intreq = ints;
    385   /* this register contains both data and status bits! */
    386   code = custom.serdatr;
    387 
    388   /* should really not happen, but you never know.. buffer
    389      overflow. */
    390   if (sbwpt + 1 == sbrpt
    391       || (sbwpt == serbuf + SERIBUF_SIZE - 1 && sbrpt == serbuf))
    392     {
    393       log (LOG_WARNING, "ser_fastint: buffer overflow!");
    394       return;
    395     }
    396 
    397   *sbwpt++ = code;
    398   if (sbwpt == serbuf + SERIBUF_SIZE)
    399     sbwpt = serbuf;
    400 }
    401 
    402 
    403 int
    404 serintr (unit)
    405      register int unit;
    406 {
    407   register struct serdevice *ser;
    408   int s1, s2;
    409 
    410   ser = ser_addr[unit];
    411 
    412   /* make sure we're not interrupted by another
    413      vbl, but allow level5 ints */
    414   s1 = spltty();
    415 
    416   /* ok, pass along any acumulated information .. */
    417   while (sbrpt != sbwpt)
    418     {
    419       /* no collision with ser_fastint() */
    420       sereint (unit, *sbrpt, ser);
    421       /* lock against ser_fastint() */
    422       s2 = spl5();
    423       {
    424 	sbrpt++;
    425 	if (sbrpt == serbuf + SERIBUF_SIZE)
    426 	  sbrpt = serbuf;
    427       }
    428       splx (s2);
    429     }
    430 
    431   splx (s1);
    432 
    433 #if 0
    434 /* add the code below if you really need it */
    435 	  {
    436 /*
    437  * Process a received byte.  Inline for speed...
    438  */
    439 #ifdef KGDB
    440 #define	RCVBYTE() \
    441 	    ch = code & 0xff; \
    442 	    if ((tp->t_state & TS_ISOPEN) == 0) { \
    443 		if (ch == FRAME_END && \
    444 		    kgdb_dev == makedev(sermajor, unit)) \
    445 			kgdb_connect(0); /* trap into kgdb */ \
    446 	    }
    447 #else
    448 #define	RCVBYTE()
    449 #endif
    450 	    RCVBYTE();
    451 	    /* sereint does the receive-processing */
    452 	    sereint (unit, code, ser);
    453 	  }
    454 #endif
    455 }
    456 
    457 int
    458 sereint(unit, stat, ser)
    459      register int unit, stat;
    460      register struct serdevice *ser;
    461 {
    462   register struct tty *tp;
    463   register int c;
    464   register u_char ch;
    465 
    466   tp = ser_tty[unit];
    467   if ((tp->t_state & TS_ISOPEN) == 0)
    468     {
    469 #ifdef KGDB
    470       /* we don't care about parity errors */
    471       if (kgdb_dev == makedev(sermajor, unit) && c == FRAME_END)
    472 	kgdb_connect(0); /* trap into kgdb */
    473 #endif
    474       return;
    475     }
    476 
    477   ch = stat & 0xff;
    478   c = ch;
    479   /* all databits 0 including stop indicate break condition */
    480   if (!(stat & 0x1ff))
    481     c |= TTY_FE;
    482 
    483   /* if parity checking enabled, check parity */
    484   else if ((tp->t_cflag & PARENB) &&
    485 	   (((ch >> 7) + even_parity[ch & 0x7f] + !!(tp->t_cflag & PARODD)) & 1))
    486     c |= TTY_PE;
    487 
    488   if (stat & SERDATRF_OVRUN)
    489     log(LOG_WARNING, "ser%d: silo overflow\n", unit);
    490 
    491   (*linesw[tp->t_line].l_rint)(c, tp);
    492 }
    493 
    494 /* this interrupt is periodically invoked in the vertical blank
    495    interrupt. It's used to keep track of the modem control lines
    496    and (new with the fast_int code) to move accumulated data
    497    up into the tty layer. */
    498 void
    499 sermint (register int unit)
    500 {
    501   register struct tty *tp;
    502   register u_char stat, last, istat;
    503   register struct serdevice *ser;
    504 
    505   tp = ser_tty[unit];
    506   if (!tp)
    507     return;
    508 
    509   if ((tp->t_state & (TS_ISOPEN|TS_WOPEN)) == 0)
    510     {
    511       sbrpt = sbwpt = serbuf;
    512       return;
    513     }
    514 
    515   /* first empty buffer */
    516   serintr (unit);
    517 
    518   stat = ciab.pra;
    519   last = last_ciab_pra;
    520   last_ciab_pra = stat;
    521 
    522   /* check whether any interesting signal changed state */
    523   istat = stat ^ last;
    524 
    525   if ((istat & CIAB_PRA_CD) && DIALIN(tp->t_dev))
    526     {
    527       if (ISDCD (stat))
    528 	(*linesw[tp->t_line].l_modem)(tp, 1);
    529       else if ((*linesw[tp->t_line].l_modem)(tp, 0) == 0)
    530 	{
    531 	  CLRDTR (stat);
    532 	  CLRRTS (stat);
    533 	  ciab.pra = stat;
    534 	  last_ciab_pra = stat;
    535 	}
    536     }
    537   if ((istat & CIAB_PRA_CTS) && (tp->t_state & TS_ISOPEN) &&
    538 	   (tp->t_cflag & CRTSCTS))
    539     {
    540 #if 0
    541       /* the line is up and we want to do rts/cts flow control */
    542       if (ISCTS (stat))
    543 	{
    544 	  tp->t_state &=~ TS_TTSTOP;
    545 	  ttstart(tp);
    546 	  /* cause tbe-int if we were stuck there */
    547 	  custom.intreq = INTF_SETCLR | INTF_TBE;
    548 	}
    549       else
    550 	tp->t_state |= TS_TTSTOP;
    551 #else
    552       /* do this on hardware level, not with tty driver */
    553       if (ISCTS (stat))
    554 	{
    555 	  tp->t_state &= ~TS_TTSTOP;
    556 	  /* cause TBE interrupt */
    557 	  custom.intreq = INTF_SETCLR | INTF_TBE;
    558 	}
    559 #endif
    560     }
    561 }
    562 
    563 int
    564 serioctl(dev, cmd, data, flag, p)
    565 	dev_t dev;
    566 	caddr_t data;
    567 	struct proc *p;
    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, p);
    579   if (error >= 0)
    580     return (error);
    581 
    582   error = ttioctl(tp, cmd, data, flag, p);
    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((caddr_t)&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") = (struct Custom *)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