Home | History | Annotate | Line # | Download | only in dev
ser.c revision 1.7
      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)
    565      dev_t dev;
    566      caddr_t data;
    567 {
    568   register struct tty *tp;
    569   register int unit = SERUNIT(dev);
    570   register struct serdevice *ser;
    571   register int error;
    572 
    573   tp = ser_tty[unit];
    574   if (! tp)
    575     return ENXIO;
    576 
    577   error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag);
    578   if (error >= 0)
    579     return (error);
    580 
    581   error = ttioctl(tp, cmd, data, flag);
    582   if (error >= 0)
    583     return (error);
    584 
    585   ser = ser_addr[unit];
    586   switch (cmd)
    587     {
    588     case TIOCSBRK:
    589       custom.adkcon = ADKCONF_SETCLR | ADKCONF_UARTBRK;
    590       break;
    591 
    592     case TIOCCBRK:
    593       custom.adkcon = ADKCONF_UARTBRK;
    594       break;
    595 
    596     case TIOCSDTR:
    597       (void) sermctl(dev, TIOCM_DTR | TIOCM_RTS, DMBIS);
    598       break;
    599 
    600     case TIOCCDTR:
    601       (void) sermctl(dev, TIOCM_DTR | TIOCM_RTS, DMBIC);
    602       break;
    603 
    604     case TIOCMSET:
    605       (void) sermctl(dev, *(int *)data, DMSET);
    606       break;
    607 
    608     case TIOCMBIS:
    609       (void) sermctl(dev, *(int *)data, DMBIS);
    610       break;
    611 
    612     case TIOCMBIC:
    613       (void) sermctl(dev, *(int *)data, DMBIC);
    614       break;
    615 
    616     case TIOCMGET:
    617       *(int *)data = sermctl(dev, 0, DMGET);
    618       break;
    619 
    620     default:
    621       return (ENOTTY);
    622     }
    623 
    624   return (0);
    625 }
    626 
    627 int
    628 serparam(tp, t)
    629      register struct tty *tp;
    630      register struct termios *t;
    631 {
    632   register struct serdevice *ser;
    633   register int cfcr, cflag = t->c_cflag;
    634   int unit = SERUNIT(tp->t_dev);
    635   int ospeed = ttspeedtab(t->c_ospeed, serspeedtab);
    636 
    637   /* check requested parameters */
    638   if (ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed))
    639     return (EINVAL);
    640 
    641   /* and copy to tty */
    642   tp->t_ispeed = t->c_ispeed;
    643   tp->t_ospeed = t->c_ospeed;
    644   tp->t_cflag = cflag;
    645 
    646   custom.intena = INTF_SETCLR | INTF_RBF | INTF_TBE;
    647   last_ciab_pra = ciab.pra;
    648 
    649   if (ospeed == 0)
    650     {
    651       (void) sermctl(tp->t_dev, 0, DMSET);  /* hang up line */
    652       return (0);
    653     }
    654   else
    655     {
    656       /* make sure any previous hangup is undone, ie.
    657 	 reenable DTR. */
    658       (void) sermctl (tp->t_dev, TIOCM_DTR | TIOCM_RTS, DMSET);
    659     }
    660   /* set the baud rate */
    661   custom.serper = (0<<15) | ospeed;  /* select 8 bit mode (instead of 9 bit) */
    662 
    663   return (0);
    664 }
    665 
    666 
    667 static void
    668 ser_putchar (tp, c)
    669      struct tty *tp;
    670      unsigned short c;
    671 {
    672   /* handle truncation of character if necessary */
    673   if ((tp->t_cflag & CSIZE) == CS7)
    674     c &= 0x7f;
    675 
    676   /* handle parity if necessary (forces CS7) */
    677   if (tp->t_cflag & PARENB)
    678     {
    679       c &= 0x7f;
    680       if (even_parity[c])
    681 	c |= 0x80;
    682       if (tp->t_cflag & PARODD)
    683 	c ^= 0x80;
    684     }
    685 
    686   /* add stop bit(s) */
    687   if (tp->t_cflag & CSTOPB)
    688     c |= 0x300;
    689   else
    690     c |= 0x100;
    691 
    692   custom.serdat = c;
    693 }
    694 
    695 
    696 #define SEROBUF_SIZE	32
    697 static u_char ser_outbuf[SEROBUF_SIZE];
    698 static u_char *sob_ptr=ser_outbuf, *sob_end=ser_outbuf;
    699 void
    700 ser_outintr ()
    701 {
    702   struct tty *tp = ser_tty[0]; /* hmmmmm */
    703   unsigned short c;
    704   int s = spltty ();
    705 
    706   if (! tp)
    707     goto out;
    708 
    709   if (! (custom.intreqr & INTF_TBE))
    710     goto out;
    711 
    712   /* clear interrupt */
    713   custom.intreq = INTF_TBE;
    714 
    715   if (sob_ptr == sob_end)
    716     {
    717       tp->t_state &= ~(TS_BUSY|TS_FLUSH);
    718       if (tp->t_line)
    719 	(*linesw[tp->t_line].l_start)(tp);
    720       else
    721 	serstart (tp);
    722 
    723       goto out;
    724     }
    725 
    726   /* do hardware flow control here. if the CTS line goes down, don't
    727      transmit anything. That way, we'll be restarted by the periodic
    728      interrupt when CTS comes back up. */
    729   if (ISCTS (ciab.pra))
    730     ser_putchar (tp, *sob_ptr++);
    731 out:
    732   splx (s);
    733 }
    734 
    735 int
    736 serstart(tp)
    737      register struct tty *tp;
    738 {
    739   register int cc, s;
    740   int unit;
    741   register struct serdevice *ser;
    742   int hiwat = 0;
    743 
    744   if (! (tp->t_state & TS_ISOPEN))
    745     return;
    746 
    747   unit = SERUNIT(tp->t_dev);
    748   ser = ser_addr[unit];
    749 
    750   s = spltty();
    751   if (tp->t_state & (TS_TIMEOUT|TS_TTSTOP))
    752     goto out;
    753 
    754   cc = tp->t_outq.c_cc;
    755   if (cc <= tp->t_lowat)
    756     {
    757       if (tp->t_state & TS_ASLEEP)
    758 	{
    759 	  tp->t_state &= ~TS_ASLEEP;
    760 	  wakeup((caddr_t)&tp->t_outq);
    761 	}
    762       selwakeup(&tp->t_wsel);
    763     }
    764 
    765   if (! cc || (tp->t_state & TS_BUSY))
    766     goto out;
    767 
    768   /* we only do bulk transfers if using CTSRTS flow control,
    769      not for (probably sloooow) ixon/ixoff devices. */
    770   if (! (tp->t_cflag & CRTSCTS))
    771     cc = 1;
    772 
    773   /*
    774    * Limit the amount of output we do in one burst
    775    * to prevent hogging the CPU.
    776    */
    777   if (cc > SEROBUF_SIZE)
    778     {
    779       hiwat++;
    780       cc = SEROBUF_SIZE;
    781     }
    782   cc = q_to_b (&tp->t_outq, ser_outbuf, cc);
    783   if (cc > 0)
    784     {
    785       tp->t_state |= TS_BUSY;
    786 
    787       sob_ptr = ser_outbuf;
    788       sob_end = ser_outbuf + cc;
    789       /* get first character out, then have tbe-interrupts blow out
    790 	 further characters, until buffer is empty, and TS_BUSY
    791 	 gets cleared. */
    792       ser_putchar (tp, *sob_ptr++);
    793     }
    794 
    795 out:
    796   splx(s);
    797 }
    798 
    799 /*
    800  * Stop output on a line.
    801  */
    802 /*ARGSUSED*/
    803 int
    804 serstop(tp, flag)
    805      register struct tty *tp;
    806 {
    807   register int s;
    808 
    809   s = spltty();
    810   if (tp->t_state & TS_BUSY)
    811     {
    812       if ((tp->t_state & TS_TTSTOP) == 0)
    813 	tp->t_state |= TS_FLUSH;
    814     }
    815   splx(s);
    816 }
    817 
    818 int
    819 sermctl(dev, bits, how)
    820      dev_t dev;
    821      int bits, how;
    822 {
    823   register struct serdevice *ser;
    824   register int unit;
    825   u_char ub;
    826   int s;
    827 
    828   unit = SERUNIT(dev);
    829   ser = ser_addr[unit];
    830 
    831   /* convert TIOCM* mask into CIA mask (which is really low-active!!) */
    832   if (how != DMGET)
    833     {
    834       ub = 0;
    835       if (bits & TIOCM_DTR) ub |= CIAB_PRA_DTR;
    836       if (bits & TIOCM_RTS) ub |= CIAB_PRA_RTS;
    837       if (bits & TIOCM_CTS) ub |= CIAB_PRA_CTS;
    838       if (bits & TIOCM_CD)  ub |= CIAB_PRA_CD;
    839       if (bits & TIOCM_RI)  ub |= CIAB_PRA_SEL;	/* collision with /dev/par ! */
    840       if (bits & TIOCM_DSR) ub |= CIAB_PRA_DSR;
    841     }
    842 
    843 
    844   s = spltty();
    845   switch (how)
    846     {
    847     case DMSET:
    848       /* invert and set */
    849       ciab.pra = ~ub;
    850       break;
    851 
    852     case DMBIC:
    853       ciab.pra |= ub;
    854       ub = ~ciab.pra;
    855       break;
    856 
    857     case DMBIS:
    858       ciab.pra &= ~ub;
    859       ub = ~ciab.pra;
    860       break;
    861 
    862     case DMGET:
    863       ub = ~ciab.pra;
    864       break;
    865     }
    866   (void) splx(s);
    867 
    868   bits = 0;
    869   if (ub & CIAB_PRA_DTR) bits |= TIOCM_DTR;
    870   if (ub & CIAB_PRA_RTS) bits |= TIOCM_RTS;
    871   if (ub & CIAB_PRA_CTS) bits |= TIOCM_CTS;
    872   if (ub & CIAB_PRA_CD)  bits |= TIOCM_CD;
    873   if (ub & CIAB_PRA_SEL) bits |= TIOCM_RI;
    874   if (ub & CIAB_PRA_DSR) bits |= TIOCM_DSR;
    875 
    876   return bits;
    877 }
    878 
    879 /*
    880  * Following are all routines needed for SER to act as console
    881  */
    882 #include "../amiga/cons.h"
    883 
    884 sercnprobe(cp)
    885 	struct consdev *cp;
    886 {
    887   int unit = CONUNIT;
    888   /* locate the major number */
    889   for (sermajor = 0; sermajor < nchrdev; sermajor++)
    890     if (cdevsw[sermajor].d_open == seropen)
    891       break;
    892 
    893   /* XXX: ick */
    894   unit = CONUNIT;
    895 
    896   /* initialize required fields */
    897   cp->cn_dev = makedev(sermajor, unit);
    898 #if 0
    899   /* on ser it really doesn't matter whether we're later
    900      using the tty interface or single-character io thru
    901      cnputc, so don't reach out to later on remember that
    902      our console is here (see ite.c) */
    903   cp->cn_tp = ser_tty[unit];
    904 #endif
    905   cp->cn_pri = CN_NORMAL;
    906 
    907   /*
    908    * If serconsole is initialized, raise our priority.
    909    */
    910   if (serconsole == unit)
    911     cp->cn_pri = CN_REMOTE;
    912 #ifdef KGDB
    913   if (major(kgdb_dev) == 1)			/* XXX */
    914     kgdb_dev = makedev(sermajor, minor(kgdb_dev));
    915 #endif
    916 }
    917 
    918 sercninit(cp)
    919 	struct consdev *cp;
    920 {
    921   int unit = SERUNIT(cp->cn_dev);
    922 
    923   serinit(unit, serdefaultrate);
    924   serconsole = unit;
    925   serconsinit = 1;
    926 }
    927 
    928 serinit(unit, rate)
    929 	int unit, rate;
    930 {
    931   int s;
    932 
    933 #ifdef lint
    934   stat = unit; if (stat) return;
    935 #endif
    936   s = splhigh();
    937   /* might want to fiddle with the CIA later ??? */
    938   custom.serper = ttspeedtab(rate, serspeedtab);
    939   splx(s);
    940 }
    941 
    942 sercngetc(dev)
    943 {
    944   u_short stat;
    945   int c, s;
    946 
    947 #ifdef lint
    948   stat = dev; if (stat) return (0);
    949 #endif
    950   s = splhigh();
    951   while (!((stat = custom.serdatr & 0xffff) & SERDATRF_RBF))
    952     ;
    953   c = stat & 0xff;
    954   /* clear interrupt */
    955   custom.intreq = INTF_RBF;
    956   splx(s);
    957   return (c);
    958 }
    959 
    960 /*
    961  * Console kernel output character routine.
    962  */
    963 sercnputc(dev, c)
    964      dev_t dev;
    965      register int c;
    966 {
    967   register int timo;
    968   short stat;
    969   int s = splhigh();
    970 
    971 #ifdef lint
    972   stat = dev; if (stat) return;
    973 #endif
    974   if (serconsinit == 0)
    975     {
    976       (void) serinit(SERUNIT(dev), serdefaultrate);
    977       serconsinit = 1;
    978     }
    979 
    980   /* wait for any pending transmission to finish */
    981   timo = 50000;
    982   while (! (custom.serdatr & SERDATRF_TBE) && --timo)
    983     ;
    984 
    985   custom.serdat = (c&0xff) | 0x100;
    986   /* wait for this transmission to complete */
    987   timo = 1500000;
    988   while (! (custom.serdatr & SERDATRF_TBE) && --timo)
    989     ;
    990 
    991   /* wait for the device (my vt100..) to process the data, since
    992      we don't do flow-control with cnputc */
    993   for (timo = 0; timo < 30000; timo++) ;
    994 
    995   /* clear any interrupts generated by this transmission */
    996   custom.intreq = INTF_TBE;
    997   splx(s);
    998 }
    999 
   1000 
   1001 serspit(c)
   1002      int c;
   1003 {
   1004   register struct Custom *cu asm("a2") = (struct Custom *)CUSTOMbase;
   1005   register int timo asm("d2");
   1006   extern int cold;
   1007   int s;
   1008 
   1009   if (c == 10)
   1010     serspit (13);
   1011 
   1012   s = splhigh();
   1013 
   1014   /* wait for any pending transmission to finish */
   1015   timo = 500000;
   1016   while (! (cu->serdatr & (SERDATRF_TBE|SERDATRF_TSRE)) && --timo)
   1017     ;
   1018   cu->serdat = (c&0xff) | 0x100;
   1019   /* wait for this transmission to complete */
   1020   timo = 15000000;
   1021   while (! (cu->serdatr & SERDATRF_TBE) && --timo)
   1022     ;
   1023   /* clear any interrupts generated by this transmission */
   1024   cu->intreq = INTF_TBE;
   1025 
   1026   for (timo = 0; timo < 30000; timo++) ;
   1027 
   1028   splx (s);
   1029 }
   1030 
   1031 serspits(cp)
   1032      char *cp;
   1033 {
   1034   while (*cp)
   1035     serspit(*cp++);
   1036 }
   1037 
   1038 int
   1039 serselect(dev, rw, p)
   1040      dev_t dev;
   1041      int rw;
   1042      struct proc *p;
   1043 {
   1044   register struct tty *tp = ser_tty[SERUNIT(dev)];
   1045   int nread;
   1046   int s = spltty();
   1047   struct proc *selp;
   1048 
   1049   switch (rw)
   1050     {
   1051     case FREAD:
   1052       nread = ttnread(tp);
   1053       if (nread > 0 || ((tp->t_cflag&CLOCAL) == 0
   1054 			&& (tp->t_state&TS_CARR_ON) == 0))
   1055 	goto win;
   1056       selrecord(p, &tp->t_rsel);
   1057       break;
   1058 
   1059     case FWRITE:
   1060       if (tp->t_outq.c_cc <= tp->t_lowat)
   1061 	goto win;
   1062       selrecord(p, &tp->t_wsel);
   1063       break;
   1064     }
   1065   splx(s);
   1066   return (0);
   1067 
   1068 win:
   1069   splx(s);
   1070   return (1);
   1071 }
   1072 
   1073 #endif
   1074