⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 riointr.c

📁 内核linux2.4.20,可跟rtlinux3.2打补丁 组成实时linux系统,编译内核
💻 C
📖 第 1 页 / 共 3 页
字号:
/*** -----------------------------------------------------------------------------****  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#define __NO_VERSION__#include <linux/module.h>#include <linux/slab.h>#include <linux/errno.h>#include <linux/tty.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/compatmac.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"/*** riopoll is called every clock tick. Once the /dev/rio device has been** opened, and polldistributed( ) has been called, this routine is called** every clock tick *by every cpu*. The 'interesting' piece of code that** manipulates 'RIONumCpus' and 'RIOCpuCountdown' is used to fair-share** the work between the CPUs. If there are 'N' cpus, then each poll time** we increment a counter, modulo 'N-1'. When this counter is 0, we call** the interrupt handler. This has the effect that polls are serviced** by processor 'N', 'N-1', 'N-2', ... '0', round and round. Neat.*/voidriopoll(p)struct rio_info *	p;{	int   host;	/*	** Here's the deal. We try to fair share as much as possible amongst	** all the processors that are available. Since each processor 	** should generate HZ ticks per second and since we only need HZ ticks	** in total for proper operation we simply attempt to cycle round each	** processor in turn, using RIOCpuCountdown to decide whether to call	** the interrupt routine. ( In fact the count zeroes when it reaches	** one less than the total number of processors - so e.g. on a two	** processor system RIOService will get called 2*HZ times per second. )	** this_cpu (cur_cpu()) tells us the number of the current processor	** as follows:	**	**		0 - default CPU	**		1 - first extra CPU	**		2 - second extra CPU	**		etc.	*/	/*	** okay, we've got a cpu that hasn't had a go recently 	** - lets check to see what needs doing.	*/	for ( host=0; host<p->RIONumHosts; host++ ) {		struct Host *HostP = &p->RIOHosts[host];		rio_spin_lock( &HostP->HostLock );		if ( ( (HostP->Flags & RUN_STATE) != RC_RUNNING ) ||		     HostP->InIntr ) {			rio_spin_unlock (&HostP->HostLock); 			continue;		}		if ( RWORD( HostP->ParmMapP->rup_intr ) ||			 RWORD( HostP->ParmMapP->rx_intr  ) ||			 RWORD( HostP->ParmMapP->tx_intr  ) ) {			HostP->InIntr = 1;#ifdef FUTURE_RELEASE			if( HostP->Type == RIO_EISA )				INBZ( HostP->Slot, EISA_INTERRUPT_RESET );			else#endif				WBYTE( HostP->ResetInt , 0xff );			rio_spin_lock(&HostP->HostLock); 			p->_RIO_Polled++;			RIOServiceHost(p, HostP, 'p' );			rio_spin_lock( &HostP->HostLock); 			HostP->InIntr = 0;			rio_spin_unlock (&HostP->HostLock);		}	}	rio_spin_unlock (&p->RIOIntrSem); }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 */voidRIOTxEnable(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 << 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);  }}/*** When a real-life interrupt comes in here, we try to find out** which host card it belongs to, and then service only that host** Notice the cunning way that, once we've found a candidate, we** continue just in case we are sharing interrupts.*/voidriointr(p)struct rio_info *	p;{	int host;	for ( host=0; host<p->RIONumHosts; host++ ) {		struct Host *HostP = &p->RIOHosts[host];		rio_dprintk (RIO_DEBUG_INTR,  "riointr() doing host %d type %d\n", host, HostP->Type);		switch( HostP->Type ) {			case RIO_AT:			case RIO_MCA:			case RIO_PCI:			  	rio_spin_lock(&HostP->HostLock);				WBYTE(HostP->ResetInt , 0xff);				if ( !HostP->InIntr ) {					HostP->InIntr = 1;					rio_spin_unlock (&HostP->HostLock);					p->_RIO_Interrupted++;					RIOServiceHost(p, HostP, 'i');					rio_spin_lock(&HostP->HostLock);					HostP->InIntr = 0;				}				rio_spin_unlock(&HostP->HostLock); 				break;#ifdef FUTURE_RELEASE		case RIO_EISA:			if ( ivec == HostP->Ivec )			{				OldSpl = LOCKB( &HostP->HostLock );				INBZ( HostP->Slot, EISA_INTERRUPT_RESET );				if ( !HostP->InIntr )				{					HostP->InIntr = 1;					UNLOCKB( &HostP->HostLock, OldSpl );					if ( this_cpu < RIO_CPU_LIMIT )					{						int intrSpl = LOCKB( &RIOIntrLock );						UNLOCKB( &RIOIntrLock, intrSpl );					}						p->_RIO_Interrupted++;					RIOServiceHost( HostP, 'i' );					OldSpl = LOCKB( &HostP->HostLock );					HostP->InIntr = 0;				}				UNLOCKB( &HostP->HostLock, OldSpl );				done++;			}			break;#endif		}		HostP->IntSrvDone++;	}#ifdef FUTURE_RELEASE	if ( !done )	{		cmn_err( CE_WARN, "RIO: Interrupt received with vector 0x%x\n", ivec );		cmn_err( CE_CONT, "	 Valid vectors are:\n");		for ( host=0; host<RIONumHosts; host++ )		{			switch( RIOHosts[host].Type )			{				case RIO_AT:				case RIO_MCA:				case RIO_EISA:						cmn_err( CE_CONT, "0x%x ", RIOHosts[host].Ivec );						break;				case RIO_PCI:						cmn_err( CE_CONT, "0x%x ", get_intr_arg( RIOHosts[host].PciDevInfo.busnum, IDIST_PCI_IRQ( RIOHosts[host].PciDevInfo.slotnum, RIOHosts[host].PciDevInfo.funcnum ) ));						break;			}		}		cmn_err( CE_CONT, "\n" );	}#endif}/*** RIO Host Service routine. Does all the work traditionally associated with an** interrupt.*/static int	RupIntr;static int	RxIntr;static int	TxIntr;voidRIOServiceHost(p, HostP, From)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 ( RWORD( HostP->ParmMapP->rup_intr ) ) {

⌨️ 快捷键说明

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