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