riointr.c

来自「LINUX 2.6.17.4的源码」· C语言 代码 · 共 658 行 · 第 1/2 页

C
658
字号
/*** -----------------------------------------------------------------------------****  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_LABELSstatic 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 "pkt.h"#include "daemon.h"#include "rio.h"#include "riospace.h"#include "cmdpkt.h"#include "map.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 "phb.h"#include "link.h"#include "cmdblk.h"#include "route.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(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 << TTY_DO_WRITE_WAKEUP)), PortP->gs.wakeup_chars, PortP->gs.xmit_cnt);		if ((PortP->gs.tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && PortP->gs.tty->ldisc.write_wakeup)			(PortP->gs.tty->ldisc.write_wakeup) (PortP->gs.tty);		rio_dprintk(RIO_DEBUG_INTR, "(%d/%d)\n", PortP->gs.wakeup_chars, PortP->gs.xmit_cnt);		wake_up_interruptible(&PortP->gs.tty->write_wait);	}}/*** RIO Host Service routine. Does all the work traditionally associated with an** interrupt.*/static int RupIntr;static int RxIntr;static int TxIntr;void RIOServiceHost(struct rio_info *p, struct Host *HostP, int From){	rio_spin_lock(&HostP->HostLock);	if ((HostP->Flags & RUN_STATE) != RC_RUNNING) {		static int t = 0;		rio_spin_unlock(&HostP->HostLock);		if ((t++ % 200) == 0)			rio_dprintk(RIO_DEBUG_INTR, "Interrupt but host not running. flags=%x.\n", (int) HostP->Flags);		return;	}	rio_spin_unlock(&HostP->HostLock);	if (readw(&HostP->ParmMapP->rup_intr)) {		writew(0, &HostP->ParmMapP->rup_intr);		p->RIORupCount++;		RupIntr++;		rio_dprintk(RIO_DEBUG_INTR, "rio: RUP interrupt on host %Zd\n", HostP - p->RIOHosts);		RIOPollHostCommands(p, HostP);	}	if (readw(&HostP->ParmMapP->rx_intr)) {		int port;		writew(0, &HostP->ParmMapP->rx_intr);		p->RIORxCount++;		RxIntr++;		rio_dprintk(RIO_DEBUG_INTR, "rio: RX interrupt on host %Zd\n", HostP - p->RIOHosts);		/*		 ** Loop through every port. If the port is mapped into		 ** the system ( i.e. has /dev/ttyXXXX associated ) then it is		 ** worth checking. If the port isn't open, grab any packets		 ** hanging on its receive queue and stuff them on the free		 ** list; check for commands on the way.		 */		for (port = p->RIOFirstPortsBooted; port < p->RIOLastPortsBooted + PORTS_PER_RTA; port++) {			struct Port *PortP = p->RIOPortp[port];			struct tty_struct *ttyP;			struct PKT *PacketP;			/*			 ** not mapped in - most of the RIOPortp[] information			 ** has not been set up!			 ** Optimise: ports come in bundles of eight.			 */			if (!PortP->Mapped) {				port += 7;				continue;	/* with the next port */			}			/*			 ** If the host board isn't THIS host board, check the next one.			 ** optimise: ports come in bundles of eight.			 */			if (PortP->HostP != HostP) {				port += 7;				continue;			}			/*			 ** Let us see - is the port open? If not, then don't service it.			 */			if (!(PortP->PortState & PORT_ISOPEN)) {				continue;			}			/*			 ** find corresponding tty structure. The process of mapping			 ** the ports puts these here.			 */			ttyP = PortP->gs.tty;			/*			 ** Lock the port before we begin working on it.			 */			rio_spin_lock(&PortP->portSem);			/*			 ** Process received data if there is any.			 */			if (can_remove_receive(&PacketP, PortP))				RIOReceive(p, PortP);			/*			 ** If there is no data left to be read from the port, and			 ** it's handshake bit is set, then we must clear the handshake,			 ** so that that downstream RTA is re-enabled.			 */			if (!can_remove_receive(&PacketP, PortP) && (readw(&PortP->PhbP->handshake) == PHB_HANDSHAKE_SET)) {				/*				 ** MAGIC! ( Basically, handshake the RX buffer, so that				 ** the RTAs upstream can be re-enabled. )				 */				rio_dprintk(RIO_DEBUG_INTR, "Set RX handshake bit\n");				writew(PHB_HANDSHAKE_SET | PHB_HANDSHAKE_RESET, &PortP->PhbP->handshake);			}			rio_spin_unlock(&PortP->portSem);		}	}	if (readw(&HostP->ParmMapP->tx_intr)) {		int port;		writew(0, &HostP->ParmMapP->tx_intr);		p->RIOTxCount++;		TxIntr++;		rio_dprintk(RIO_DEBUG_INTR, "rio: TX interrupt on host %Zd\n", HostP - p->RIOHosts);		/*		 ** Loop through every port.		 ** If the port is mapped into the system ( i.e. has /dev/ttyXXXX		 ** associated ) then it is worth checking.		 */		for (port = p->RIOFirstPortsBooted; port < p->RIOLastPortsBooted + PORTS_PER_RTA; port++) {			struct Port *PortP = p->RIOPortp[port];			struct tty_struct *ttyP;			struct PKT *PacketP;			/*			 ** not mapped in - most of the RIOPortp[] information			 ** has not been set up!			 */			if (!PortP->Mapped) {				port += 7;				continue;	/* with the next port */			}			/*			 ** If the host board isn't running, then its data structures			 ** are no use to us - continue quietly.			 */			if (PortP->HostP != HostP) {				port += 7;				continue;	/* with the next port */			}			/*			 ** Let us see - is the port open? If not, then don't service it.			 */			if (!(PortP->PortState & PORT_ISOPEN)) {				continue;			}			rio_dprintk(RIO_DEBUG_INTR, "rio: Looking into port %d.\n", port);			/*

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?