/*
 * Copyright (c) 1982, 1986, 1990 The Regents of the University of California.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *	This product includes software developed by the University of
 *	California, Berkeley and its contributors.
 * 4. Neither the name of the University nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 *	@(#)ql.c	7.12 (Berkeley) 6/27/91
 *
 *   - converted from NetBSD Amiga serial driver to A2232 serial driver
 *     by zik 93/12/7
 */

#include "ql.h"

#if NQL > 0
#include "sys/param.h"
#include "sys/systm.h"
#include "sys/ioctl.h"
#include "sys/tty.h"
#include "sys/proc.h"
#include "sys/conf.h"
#include "sys/file.h"
#include "sys/malloc.h"
#include "sys/uio.h"
#include "sys/kernel.h"
#include "sys/syslog.h"

#include "device.h"
#include "qlreg.h"
#include "machine/cpu.h"

#include "../amiga/custom.h"
#include "../amiga/cia.h"
#include "../amiga/cc.h"

			/* 6502 code for A2232 card */
#include "ql6502.h"

int	qlprobe();
struct	driver qldriver = {
	qlprobe, "ql",
};


/*
 * There is a bit of a "gotcha" concerning the numbering
 * of ql devices and the specification of the number of serial
 * lines in the kernel.
 *
 * Each board has seven lines, but for programming convenience
 * and compatibility with Amiga UNIX the boards' minor device
 * numbers are allocated in groups of sixteen:
 *
 *                     minor device numbers
 * First board		0  2  4  6  8 10 12
 * Second board        16 18 20 22 24 26 28
 * Third board	       32 34 36 38 40 42 44
 *
 * The intermediate minor device numbers are dialin versions
 * of the same devices. ie. 10 is dialout line 6 and 11 is
 * the dialin version of line 6.
 *
 * On the other hand, I have made the NQL config option refer
 * to the total number of a2232 cards, not the maximum
 * minor device number. So you might have NQL=3, in which case
 * you have three boards with minor device numbers from 0 to 45.
 */

int	qlstart(__P(struct tty *)), qlparam(), qlintr();
int	initcard(__P(struct amiga_device *));
int	qldefaultrate = TTYDEF_SPEED;
struct	qldevice qldev[QLSLOTS];	/* device structs for all lines */
struct	tty *ql_tty[QLTTYS];		/* ttys for all lines */
struct	vbl_node ql_vbl_node[NQL];	/* vbl interrupt node per board */


struct speedtab qlspeedtab[] = {
	0,	0,
	50,	QLPARAM_B50,
	75,	QLPARAM_B75,
	110,	QLPARAM_B110,
	134,	QLPARAM_B134,
	150,	QLPARAM_B150,
	300,	QLPARAM_B300,
	600,	QLPARAM_B600,
	1200,	QLPARAM_B1200,
	1800,	QLPARAM_B1800,
	2400,	QLPARAM_B2400,
	3600,	QLPARAM_B3600,
	4800,	QLPARAM_B4800,
	7200,	QLPARAM_B7200,
	9600,	QLPARAM_B9600,
	19200,	QLPARAM_B19200,
	115200,	QLPARAM_B115200,
	-1,	-1
};
  
  

void qlmint (register int unit);

int
qlprobe(ad)
     register struct amiga_device *ad;
{
  volatile struct qlmemory *qlmem;
  struct qldevice *ql;
  int unit;
  int Count;
  unsigned short ir = custom.intenar;
	
  unit = ad->amiga_unit;

  if (initcard(ad) != 0)
  {
    printf("ql%d: Board initialize failed, bad download code.\n", unit);
    return(0);
  }

  printf("ql%d: Board successfully initialized.\n", unit);

  qlmem = (struct qlmemory *) ad->amiga_addr;
  for (Count = 0; Count < 8 && QLSLOTUL(unit, Count) < QLSLOTS; Count++)
    {
    ql = &qldev[QLSLOTUL(unit, Count)];
    ql->board = qlmem;
    ql->port = Count;
    ql->flags = 0;
    ql->active = 1;
    ql->closing = FALSE;
    ql_tty[QLTTYSLOT(QLSLOTUL(unit, Count))] = NULL;
    ql_tty[QLTTYSLOT(QLSLOTUL(unit, Count))+1] = NULL;
    }
  if (QLSLOTUL(unit, NUMLINES) < QLSLOTS)
    qldev[QLSLOTUL(unit, NUMLINES)].active = 0;	/* disable the eighth port */

#if 0
  ad->amiga_ipl = 2;
#endif
  ql_vbl_node[unit].function = qlmint;
  add_vbl_function (&ql_vbl_node[unit], QL_VBL_PRIORITY, (void *)unit);

  return (1);
}

/* ARGSUSED */
int
#ifdef __STDC__
qlopen(dev_t dev, int flag, int mode, struct proc *p)
#else
qlopen(dev, flag, mode, p)
     dev_t dev;
     int flag, mode;
     struct proc *p;
#endif
{
  register struct tty *tp;
  int error = 0;
  int s;
  int slot;
  int ttyn;
  struct qldevice *ql;
  volatile struct qlstatus *qs;
  
  /* get the device structure */
  slot = QLSLOT(dev);
  ttyn = QLTTY(dev);
  if (slot >= QLSLOTS)
    return ENXIO;
  if (QLLINE(dev) >= NUMLINES)
    return ENXIO;
  ql = &qldev[slot];
  qs = &ql->board->Status[ql->port];

  if (!ql->active)
    return ENXIO;
  s = spltty();
  if (!ql_tty[ttyn]) 
    {
      tp = ttymalloc();
      ql_tty[ttyn] = tp;
      ql_tty[ttyn+1] = tp;
      /* default values are not optimal for this device, increase
	 buffers */
      clfree(&tp->t_rawq);
      clfree(&tp->t_canq);
      clfree(&tp->t_outq);
      clalloc(&tp->t_rawq, 8192, 1);
      clalloc(&tp->t_canq, 8192, 1);
      clalloc(&tp->t_outq, 8192, 0);
    } 
  else
    tp = ql_tty[ttyn];

  tp->t_oproc = qlstart;
  tp->t_param = qlparam;
  tp->t_dev = dev;
 
  /* if port is still closing, just bitbucket remaining characters */
  if (ql->closing)
    {
      qs->OutFlush = TRUE;
      ql->closing = FALSE;
    }

  /* initialise tty */
  if ((tp->t_state & TS_ISOPEN) == 0)
    {
      tp->t_state |= TS_WOPEN;
      ttychars(tp);
      if (tp->t_ispeed == 0) 
	{
	  tp->t_iflag = TTYDEF_IFLAG | IXOFF;	/* XXXXX */
	  tp->t_oflag = TTYDEF_OFLAG;
#if 0
	  tp->t_cflag = TTYDEF_CFLAG;
#else
	  tp->t_cflag = (CREAD | CS8 | CLOCAL); /* XXXXX */
#endif
	  tp->t_lflag = TTYDEF_LFLAG;
	  tp->t_ispeed = tp->t_ospeed = qldefaultrate;
	}
      qlparam(tp, &tp->t_termios);
      ttsetwater(tp);
    } 
  else if (tp->t_state&TS_XCLUDE && p->p_ucred->cr_uid != 0)
    return (EBUSY);

  (void) qlmctl (dev, TIOCM_DTR | TIOCM_RTS, DMSET);
  ql->InTail = qs->InHead;	/* don't get old chars */

  if (!QLDIALIN(dev) || (qlmctl (dev, 0, DMGET) & TIOCM_CD))
    tp->t_state |= TS_CARR_ON;

  while ((flag & O_NONBLOCK) == 0 
	 && (tp->t_cflag & CLOCAL) == 0 
	 && (tp->t_state & TS_CARR_ON) == 0) 
    {
      tp->t_state |= TS_WOPEN;
      if (error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI | PCATCH,
			   ttopen, 0))
	break;
    }
  splx (s);
  if (error == 0)
    {
      /* reset the tty pointer, as there could have been a dialout
	 use of the tty with a dialin open waiting. */
      tp->t_dev = dev;
      error = (*linesw[tp->t_line].l_open)(dev, tp);
    }
  return (error);
}
 

int
qlclose(dev, flag, mode, p)
     dev_t dev;
     int flag, mode;
     struct proc *p;
{
  register struct tty *tp;
  int slot;
  volatile struct qlstatus *qs;
  struct qldevice *ql;
  
  /* get the device structure */
  slot = QLSLOT(dev);
  if (slot >= QLSLOTS)
    return ENXIO;
  ql = &qldev[slot];
  if (!ql->active)
    return ENXIO;
  qs = &ql->board->Status[ql->port];
  
  tp = ql_tty[QLTTY(dev)];
  (*linesw[tp->t_line].l_close)(tp, flag);
#if 0
  (void) qlmctl(dev, 0, DMSET);
#endif
  ttyclose(tp);
#if 0
      ttyfree (tp);
      ser_tty[unit] = (struct tty *)NULL;
#endif
  if (ql->flags & TIOCM_DTR)
    ql->closing = TRUE; /* flush remaining characters before dropping DTR */
  else
    qs->OutFlush = TRUE; /* just bitbucket remaining characters */
  return (0);
}
 
int
qlread(dev, uio, flag)
     dev_t dev;
     struct uio *uio;
{
  register struct tty *tp;
  
  tp = ql_tty[QLTTY(dev)];
  if (! tp)
    return ENXIO;

  return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
}
 
int
qlwrite(dev, uio, flag)
     dev_t dev;
     struct uio *uio;
{
  register struct tty *tp;
  
  tp = ql_tty[QLTTY(dev)];
  if (! tp)
    return ENXIO;

  return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
}


/* this interrupt is periodically invoked in the vertical blank 
   interrupt. It's used to keep track of the modem control lines
   and (new with the fast_int code) to move accumulated data
   up into the tty layer. */
void
qlmint (register int unit)
{
  register struct tty *tp;
  register u_char stat, last, istat;
  int slot;
  int maxslot;
  struct qldevice *ql;
  volatile struct qlstatus *qs;
  volatile u_char *buf;
  int newhead;
  int bufpos;
  int bufleft;
  int s;
  u_char event;
  
  /* check each line on this board */
  maxslot = QLSLOTUL(unit, NUMLINES);
  if (maxslot > QLSLOTS)
    maxslot = QLSLOTS;
  for (slot = QLSLOTUL(unit, 0); slot < maxslot; slot++)
    {
      ql = &qldev[slot];
      if (!ql->active)
        continue;
      tp = ql_tty[QLTTYSLOT(slot)];

      /* carrier detect change? */
      qs = &ql->board->Status[ql->port];
      event = qs->InEvent;
      switch (event)
	{
	  case QLEVENT_CarrierOn:
	    qs->InEvent = 0;
#if 0
	    printf("Carrier detected on ql%d\n", slot);
#endif
	    ql->flags |= TIOCM_CD;
	    if (tp && (tp->t_state & (TS_ISOPEN|TS_WOPEN)) && QLDIALIN(tp->t_dev))
	      (*linesw[tp->t_line].l_modem)(tp, 1);
	    break;

	  case QLEVENT_CarrierOff:
	    qs->InEvent = 0;
#if 0
	    printf("Carrier lost on ql%d\n", slot);
#endif
	    ql->flags &= ~TIOCM_CD;
/*	    if (tp && (tp->t_state & (TS_ISOPEN|TS_WOPEN)) && QLDIALIN(tp->t_dev)) */
	    if (tp && QLDIALIN(tp->t_dev))
	      {
	        if ((*linesw[tp->t_line].l_modem)(tp, 0) == 0)
		  {
		    /* clear RTS and DTR, bitbucket output */
		    qs->Command = (qs->Command & ~QLCMD_CMask) | QLCMD_Close;
		    qs->Setup = TRUE;
		    ql->flags &= ~(TIOCM_DTR | TIOCM_RTS);
      		    qs->OutFlush = TRUE;
		  }
	      }
	    break;
	}

      /* if this line isn't open don't get chars from it */
      if (tp && (tp->t_state & (TS_ISOPEN|TS_WOPEN))) 
        {
          s = spltty();
          /* did we get a line status change? */
          if (event == QLEVENT_Break)
	    {
	      qs->InEvent = 0;
#if 0
	      printf("Break received on ql%d\n", slot);
#endif
    	      (*linesw[tp->t_line].l_rint)(TTY_FE, tp);
	    }
	  
	  /* check for input */
	  newhead = qs->InHead;
	  if (newhead != ql->InTail)
	    {
	      /* some characters to get */
	      buf = &ql->board->InBuf[ql->port][0];
	      bufpos = ql->InTail;
	      while (bufpos != newhead)
		{
#if 0
		  printf("ql%d got %d '%c'\n", slot, (int)buf[bufpos], (int)buf[bufpos]);
#endif
		  (*linesw[tp->t_line].l_rint)((int)buf[bufpos++], tp);
		  bufpos &= IOBUFLENMASK;
		}
	      ql->InTail = newhead;
	    }

	  /* send output */
	  if (tp->t_state & (TS_BUSY|TS_FLUSH))
	    {
	      bufpos = qs->OutHead - qs->OutTail;
	      if (bufpos < 0)
		bufpos += IOBUFLEN;

	      /* busy and below low water mark? */
	      if (tp->t_state & TS_BUSY)
	        {
	          if (bufpos < IOBUFLOWWATER)
		    {
		      tp->t_state &= ~TS_BUSY;	/* not busy any more */
		      if (tp->t_line)
		        (*linesw[tp->t_line].l_start)(tp);
		      else
		        qlstart(tp);
		    }
		}

	      /* waiting for flush and buffer empty? */
	      if (tp->t_state & TS_FLUSH)
	        {
	          if (bufpos == 0)
	            tp->t_state &= ~TS_FLUSH;	/* finished flushing */
	        }
	    }

          splx(s);
	}

      /* is this port closing? */
      if (ql->closing)
        {
	  /* if DTR is off, just bitbucket remaining characters */
	  if ( (ql->flags & TIOCM_DTR) == 0)
	    {
	      qs->OutFlush = TRUE;
	      ql->closing = FALSE;
	    }
          else if (qs->OutHead == qs->OutTail)
	  /* if output has drained, drop DTR */
	    {
	      (void) qlmctl(tp->t_dev, 0, DMSET);
	      ql->closing = FALSE;
            }
        }
    }
  
}


int
qlioctl(dev, cmd, data, flag)
     dev_t dev;
     caddr_t data;
{
  register struct tty *tp;
  register int slot;
  register int error;
  struct qldevice *ql;
  volatile struct qlstatus *qs;
  int s;
  
  /* get the device structure */
  slot = QLSLOT(dev);
  if (slot >= QLSLOTS)
    return ENXIO;
  ql = &qldev[slot];
  if (!ql->active)
    return ENXIO;
  qs = &ql->board->Status[ql->port];
  tp = ql_tty[QLTTY(dev)];

  error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag);
  if (error >= 0)
    return (error);

  error = ttioctl(tp, cmd, data, flag);
  if (error >= 0)
    return (error);
  
  switch (cmd) 
    {
    case TIOCSBRK:
      /* send break */
      s = spltty();
      qs->Command = (qs->Command & (~QLCMD_RTSMask)) | QLCMD_Break;
      qs->Setup = TRUE;
      splx(s);
      break;

    case TIOCCBRK:
      /* clear break */
      s = spltty();
      qs->Command = (qs->Command & (~QLCMD_RTSMask)) | QLCMD_RTSOn;
      qs->Setup = TRUE;
      splx(s);
      break;

    case TIOCSDTR:
      (void) qlmctl(dev, TIOCM_DTR | TIOCM_RTS, DMBIS);
      break;
      
    case TIOCCDTR:
      if (!QLDIALIN(dev))	/* don't let dialins drop DTR */
        (void) qlmctl(dev, TIOCM_DTR | TIOCM_RTS, DMBIC);
      break;
      
    case TIOCMSET:
      (void) qlmctl(dev, *(int *)data, DMSET);
      break;
      
    case TIOCMBIS:
      (void) qlmctl(dev, *(int *)data, DMBIS);
      break;
      
    case TIOCMBIC:
      if (QLDIALIN(dev))	/* don't let dialins drop DTR */
        (void) qlmctl(dev, *(int *)data & TIOCM_DTR, DMBIC);
      else
        (void) qlmctl(dev, *(int *)data, DMBIC);
      break;
      
    case TIOCMGET:
      *(int *)data = qlmctl(dev, 0, DMGET);
      break;
      
    default:
      return (ENOTTY);
    }

  return (0);
}


int
qlparam(tp, t)
     register struct tty *tp;
     register struct termios *t;
{
  register int cfcr, cflag = t->c_cflag;
  int slot;
  struct qldevice *ql;
  volatile struct qlstatus *qs;
  int s;
  int ospeed = ttspeedtab(t->c_ospeed, qlspeedtab);
  
  /* get the device structure */
  slot = QLSLOT(tp->t_dev);
  if (slot >= QLSLOTS)
    return ENXIO;
  ql = &qldev[slot];
  if (!ql->active)
    return ENXIO;
  qs = &ql->board->Status[ql->port];

  /* check requested parameters */
  if (ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed))
    return (EINVAL);

  /* and copy to tty */
  tp->t_ispeed = t->c_ispeed;
  tp->t_ospeed = t->c_ospeed;
  tp->t_cflag = cflag;
  
  /* hang up if baud is zero */
  if (ospeed == 0) 
    {
      if (!QLDIALIN(tp->t_dev))  /* don't let dialins drop DTR */
        (void) qlmctl(tp->t_dev, 0, DMSET);
    }
  else
    {
      /* set the baud rate */
      s = spltty();
      qs->Param = (qs->Param & ~QLPARAM_BaudMask) | ospeed | QLPARAM_RcvBaud;

      /* make sure any previous hangup is undone, ie.  reenable DTR. */
      /* also qlmctl will cause the speed to be set */
      (void) qlmctl (tp->t_dev, TIOCM_DTR | TIOCM_RTS, DMSET);
      splx(s);
    }
  
  return (0);
}


int
qlstart(tp)
     register struct tty *tp;
{
  register int cc;
  register char *cp;
  register int qhead;
  int s;
  int slot;
  struct qldevice *ql;
  volatile struct qlstatus *qs;
  volatile char *qob;
  int hiwat = 0;
  int maxout;
  int empty;
  char qltmpbuf[IOBUFLEN];	/* is this a no-no or what? */

  if (! (tp->t_state & TS_ISOPEN))
    return;

  slot = QLSLOT(tp->t_dev);

#if 0
  printf("starting ql%d\n", slot);
#endif

  s = spltty();

#if 0
  /* don't start if explicitly stopped */
  if (tp->t_state & (TS_TIMEOUT|TS_TTSTOP)) 
    goto out;
#endif

  /* wake up if below low water */
  cc = tp->t_outq.c_cc;
  if (cc <= tp->t_lowat) 
    {
      if (tp->t_state & TS_ASLEEP) 
	{
	  tp->t_state &= ~TS_ASLEEP;
	  wakeup((caddr_t)&tp->t_outq);
	}
      selwakeup(&tp->t_wsel);
    }

  /* don't bother if no characters or busy */
  if (! cc || (tp->t_state & TS_BUSY))
    goto out;

  /*
   * Limit the amount of output we do in one burst
   */
  ql = &qldev[slot];
  qs = &ql->board->Status[ql->port];
  qhead = qs->OutHead;
  maxout = qhead - qs->OutTail;
  if (maxout < 0)
      maxout += IOBUFLEN;
  maxout = IOBUFLEN - 1 - maxout;
  empty = cc <= maxout;
  if (cc >= maxout) 
    {
      hiwat++;
      cc = maxout;
    }
  cc = q_to_b (&tp->t_outq, qltmpbuf, cc);
  if (cc > 0)
    {
      tp->t_state |= TS_BUSY;

      qob = &ql->board->OutBuf[ql->port][0];
      cp = &qltmpbuf[0];
      
      /* enable output */
      qs->OutDisable = FALSE;

#if 0
      qltmpbuf[cc] = 0;
      printf("sending '%s'\n", qltmpbuf);
#endif

      /* send the first char across to reduce latency */
      qob[qhead++] = *cp++;
      qhead &= IOBUFLENMASK;
      qs->OutHead = qhead;
      cc--;

      /* copy the rest of the chars across quickly */
      while (cc > 0)
	{
	  qob[qhead++] = *cp++;
	  qhead &= IOBUFLENMASK;
	  cc--;
	}
      qs->OutHead = qhead;

      /* leave the device busy if we've filled the buffer */
      if (!hiwat)
        tp->t_state &= ~TS_BUSY;
    }

out:  
  splx(s);
}
 
/* XXX */
/*
 * Stop output on a line.
 */
/*ARGSUSED*/
int
qlstop(tp, flag)
     register struct tty *tp;
{
  register int s;
  struct qldevice *ql;
  volatile struct qlstatus *qs;

  s = spltty();

  ql = &qldev[QLSLOT(tp->t_dev)];
  qs = &ql->board->Status[ql->port];
  if (tp->t_state & TS_TTSTOP)
    {
      /* stop output */
#if 0
      printf("stopped output on ql%d\n", QLSLOT(tp->t_dev));
      qs->OutDisable = TRUE;
#endif
    }
  else
    {
      /* flush output */
      tp->t_state |= TS_FLUSH;
    }

  splx(s);
}
 
/* bits can be: TIOCM_DTR, TIOCM_RTS, TIOCM_CTS, TIOCM_CD, TIOCM_RI, TIOCM_DSR */
int
qlmctl(dev, bits, how)
     dev_t dev;
     int bits, how;
{
  struct qldevice *ql;
  volatile struct qlstatus *qs;
  int slot;
  int s;
  u_char newcmd;
  int OldFlags;

  /* get the device structure */
  slot = QLSLOT(dev);
  if (slot >= QLSLOTS)
    return ENXIO;
  ql = &qldev[slot];
  if (!ql->active)
    return ENXIO;

  s = spltty();
  if (how != DMGET)
    {
      OldFlags = ql->flags;
      bits &= TIOCM_DTR | TIOCM_RTS; /* can only modify DTR and RTS */
      switch (how) 
        {
        case DMSET:
	  ql->flags = bits;
          break;
      
        case DMBIC:
          ql->flags &= ~bits;
          break;
      
        case DMBIS:
          ql->flags |= ~bits;
          break;
        }

      /* modify modem control state */
      qs = &ql->board->Status[ql->port];
      if (bits & TIOCM_RTS)
	newcmd = QLCMD_RTSOn;
      else
	newcmd = QLCMD_RTSOff;
      if (bits & TIOCM_DTR)
	newcmd |= QLCMD_Enable;

      qs->Command = (qs->Command & (~QLCMD_RTSMask & ~QLCMD_Enable)) | newcmd;
      qs->Setup = TRUE;

      /* if we've dropped DTR, bitbucket any pending output */
      if ( (OldFlags & TIOCM_DTR) && ((bits & TIOCM_DTR) == 0))
        qs->OutFlush = TRUE;
    }
  bits = ql->flags;
  (void) splx(s);
  
  return bits;
}


int
initcard(ad)
  struct amiga_device *ad;
{
  int bcount;
  short zcount;
  u_char *from;
  volatile u_char *to;
  volatile struct qlmemory *qlm;
  struct qldevice *qld;

  /* copy the code across to the board */
  qlm = (volatile struct qldevice *)ad->amiga_addr;	
  to = (u_char *)qlm;
  if (sizeof(ql6502code) != 1)
  {
   for (from = &ql6502code, bcount = sizeof(ql6502code); bcount > 0; bcount -= sizeof(zcount))
    {
      zcount = *(short *)from;
      from += sizeof(zcount);

      if (zcount < 0)
        {
        /* pad with zcount zeros */
        for (zcount = -zcount; zcount > 0; zcount--)
	  *to++ = '\0';
        }
      else
        {
        /* copy across this many bytes */
        bcount -= zcount;
        for ( ; zcount > 0; from++, to++, zcount--)
	  *to = *from;
        }
    }
  
     /* start it running */
     qlm->ResetBoard = 0;

     return(0);

  } /* if */

  return(1);
}

#endif  /* NQL > 0 */

