/*
** -----------------------------------------------------------------------------
**
** Perle Specialix driver for Linux
** Ported from existing RIO Driver for SCO sources.
*
* (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
**
** Module : riointr.c
** SID : 1.2
** Last Modified : 11/6/98 10:33:44
** Retrieved : 11/6/98 10:33:49
**
** ident @(#)riointr.c 1.2
**
** -----------------------------------------------------------------------------
*/
#ifdef SCCS_LABELS
static char *_riointr_c_sccs_ = "@(#)riointr.c 1.2";
#endif
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/errno.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <asm/io.h>
#include <asm/system.h>
#include <asm/string.h>
#include <asm/semaphore.h>
#include <asm/uaccess.h>
#include <linux/termios.h>
#include <linux/serial.h>
#include <linux/generic_serial.h>
#include <linux/delay.h>
#include "linux_compat.h"
#include "rio_linux.h"
#include "typdef.h"
#include "pkt.h"
#include "daemon.h"
#include "rio.h"
#include "riospace.h"
#include "top.h"
#include "cmdpkt.h"
#include "map.h"
#include "riotypes.h"
#include "rup.h"
#include "port.h"
#include "riodrvr.h"
#include "rioinfo.h"
#include "func.h"
#include "errors.h"
#include "pci.h"
#include "parmmap.h"
#include "unixrup.h"
#include "board.h"
#include "host.h"
#include "error.h"
#include "phb.h"
#include "link.h"
#include "cmdblk.h"
#include "route.h"
#include "control.h"
#include "cirrus.h"
#include "rioioctl.h"
static void RIOReceive(struct rio_info *, struct Port *);
static char *firstchars (char *p, int nch)
{
static char buf[2][128];
static int t=0;
t = ! t;
memcpy (buf[t], p, nch);
buf[t][nch] = 0;
return buf[t];
}
#define INCR( P, I ) ((P) = (((P)+(I)) & p->RIOBufferMask))
/* Enable and start the transmission of packets */
void
RIOTxEnable(en)
char * en;
{
struct Port * PortP;
struct rio_info *p;
struct tty_struct* tty;
int c;
struct PKT * PacketP;
unsigned long flags;
PortP = (struct Port *)en;
p = (struct rio_info *)PortP->p;
tty = PortP->gs.tty;
rio_dprintk (RIO_DEBUG_INTR, "tx port %d: %d chars queued.\n",
PortP->PortNum, PortP->gs.xmit_cnt);
if (!PortP->gs.xmit_cnt) return;
/* This routine is an order of magnitude simpler than the specialix
version. One of the disadvantages is that this version will send
an incomplete packet (usually 64 bytes instead of 72) once for
every 4k worth of data. Let's just say that this won't influence
performance significantly..... */
rio_spin_lock_irqsave(&PortP->portSem, flags);
while (can_add_transmit( &PacketP, PortP )) {
c = PortP->gs.xmit_cnt;
if (c > PKT_MAX_DATA_LEN) c = PKT_MAX_DATA_LEN;
/* Don't copy past the end of the source buffer */
if (c > SERIAL_XMIT_SIZE - PortP->gs.xmit_tail)
c = SERIAL_XMIT_SIZE - PortP->gs.xmit_tail;
{ int t;
t = (c > 10)?10:c;
rio_dprintk (RIO_DEBUG_INTR, "rio: tx port %d: copying %d chars: %s - %s\n",
PortP->PortNum, c,
firstchars (PortP->gs.xmit_buf + PortP->gs.xmit_tail , t),
firstchars (PortP->gs.xmit_buf + PortP->gs.xmit_tail + c-t, t));
}
/* If for one reason or another, we can't copy more data,
we're done! */
if (c == 0) break;
rio_memcpy_toio (PortP->HostP->Caddr, (caddr_t)PacketP->data,
PortP->gs.xmit_buf + PortP->gs.xmit_tail, c);
/* udelay (1); */
writeb (c, &(PacketP->len));
if (!( PortP->State & RIO_DELETED ) ) {
add_transmit ( PortP );
/*
** Count chars tx'd for port statistics reporting
*/
if ( PortP->statsGather )
PortP->txchars += c;
}
PortP->gs.xmit_tail = (PortP->gs.xmit_tail + c) & (SERIAL_XMIT_SIZE-1);
PortP->gs.xmit_cnt -= c;
}
rio_spin_unlock_irqrestore(&PortP->portSem, flags);
if (PortP->gs.xmit_cnt <= (PortP->gs.wakeup_chars + 2*PKT_MAX_DATA_LEN)) {
rio_dprintk (RIO_DEBUG_INTR, "Waking up.... ldisc:%d (%d/%d)....",
(int)(PortP->gs.tty->flags & (1