riointr.c

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

C
658
字号
			 ** Lock the port before we begin working on it.			 */			rio_spin_lock(&PortP->portSem);			/*			 ** If we can't add anything to the transmit queue, then			 ** we need do none of this processing.			 */			if (!can_add_transmit(&PacketP, PortP)) {				rio_dprintk(RIO_DEBUG_INTR, "Can't add to port, so skipping.\n");				rio_spin_unlock(&PortP->portSem);				continue;			}			/*			 ** find corresponding tty structure. The process of mapping			 ** the ports puts these here.			 */			ttyP = PortP->gs.tty;			/* If ttyP is NULL, the port is getting closed. Forget about it. */			if (!ttyP) {				rio_dprintk(RIO_DEBUG_INTR, "no tty, so skipping.\n");				rio_spin_unlock(&PortP->portSem);				continue;			}			/*			 ** If there is more room available we start up the transmit			 ** data process again. This can be direct I/O, if the cookmode			 ** is set to COOK_RAW or COOK_MEDIUM, or will be a call to the			 ** riotproc( T_OUTPUT ) if we are in COOK_WELL mode, to fetch			 ** characters via the line discipline. We must always call			 ** the line discipline,			 ** so that user input characters can be echoed correctly.			 **			 ** ++++ Update +++++			 ** With the advent of double buffering, we now see if			 ** TxBufferOut-In is non-zero. If so, then we copy a packet			 ** to the output place, and set it going. If this empties			 ** the buffer, then we must issue a wakeup( ) on OUT.			 ** If it frees space in the buffer then we must issue			 ** a wakeup( ) on IN.			 **			 ** ++++ Extra! Extra! If PortP->WflushFlag is set, then we			 ** have to send a WFLUSH command down the PHB, to mark the			 ** end point of a WFLUSH. We also need to clear out any			 ** data from the double buffer! ( note that WflushFlag is a			 ** *count* of the number of WFLUSH commands outstanding! )			 **			 ** ++++ And there's more!			 ** If an RTA is powered off, then on again, and rebooted,			 ** whilst it has ports open, then we need to re-open the ports.			 ** ( reasonable enough ). We can't do this when we spot the			 ** re-boot, in interrupt time, because the queue is probably			 ** full. So, when we come in here, we need to test if any			 ** ports are in this condition, and re-open the port before			 ** we try to send any more data to it. Now, the re-booted			 ** RTA will be discarding packets from the PHB until it			 ** receives this open packet, but don't worry tooo much			 ** about that. The one thing that is interesting is the			 ** combination of this effect and the WFLUSH effect!			 */			/* For now don't handle RTA reboots. -- REW.			   Reenabled. Otherwise RTA reboots didn't work. Duh. -- REW */			if (PortP->MagicFlags) {				if (PortP->MagicFlags & MAGIC_REBOOT) {					/*					 ** well, the RTA has been rebooted, and there is room					 ** on its queue to add the open packet that is required.					 **					 ** The messy part of this line is trying to decide if					 ** we need to call the Param function as a tty or as					 ** a modem.					 ** DONT USE CLOCAL AS A TEST FOR THIS!					 **					 ** If we can't param the port, then move on to the					 ** next port.					 */					PortP->InUse = NOT_INUSE;					rio_spin_unlock(&PortP->portSem);					if (RIOParam(PortP, OPEN, ((PortP->Cor2Copy & (COR2_RTSFLOW | COR2_CTSFLOW)) == (COR2_RTSFLOW | COR2_CTSFLOW)) ? 1 : 0, DONT_SLEEP) == RIO_FAIL) {						continue;	/* with next port */					}					rio_spin_lock(&PortP->portSem);					PortP->MagicFlags &= ~MAGIC_REBOOT;				}				/*				 ** As mentioned above, this is a tacky hack to cope				 ** with WFLUSH				 */				if (PortP->WflushFlag) {					rio_dprintk(RIO_DEBUG_INTR, "Want to WFLUSH mark this port\n");					if (PortP->InUse)						rio_dprintk(RIO_DEBUG_INTR, "FAILS - PORT IS IN USE\n");				}				while (PortP->WflushFlag && can_add_transmit(&PacketP, PortP) && (PortP->InUse == NOT_INUSE)) {					int p;					struct PktCmd *PktCmdP;					rio_dprintk(RIO_DEBUG_INTR, "Add WFLUSH marker to data queue\n");					/*					 ** make it look just like a WFLUSH command					 */					PktCmdP = (struct PktCmd *) &PacketP->data[0];					writeb(WFLUSH, &PktCmdP->Command);					p = PortP->HostPort % (u16) PORTS_PER_RTA;					/*					 ** If second block of ports for 16 port RTA, add 8					 ** to index 8-15.					 */					if (PortP->SecondBlock)						p += PORTS_PER_RTA;					writeb(p, &PktCmdP->PhbNum);					/*					 ** to make debuggery easier					 */					writeb('W', &PacketP->data[2]);					writeb('F', &PacketP->data[3]);					writeb('L', &PacketP->data[4]);					writeb('U', &PacketP->data[5]);					writeb('S', &PacketP->data[6]);					writeb('H', &PacketP->data[7]);					writeb(' ', &PacketP->data[8]);					writeb('0' + PortP->WflushFlag, &PacketP->data[9]);					writeb(' ', &PacketP->data[10]);					writeb(' ', &PacketP->data[11]);					writeb('\0', &PacketP->data[12]);					/*					 ** its two bytes long!					 */					writeb(PKT_CMD_BIT | 2, &PacketP->len);					/*					 ** queue it!					 */					if (!(PortP->State & RIO_DELETED)) {						add_transmit(PortP);						/*						 ** Count chars tx'd for port statistics reporting						 */						if (PortP->statsGather)							PortP->txchars += 2;					}					if (--(PortP->WflushFlag) == 0) {						PortP->MagicFlags &= ~MAGIC_FLUSH;					}					rio_dprintk(RIO_DEBUG_INTR, "Wflush count now stands at %d\n", PortP->WflushFlag);				}				if (PortP->MagicFlags & MORE_OUTPUT_EYGOR) {					if (PortP->MagicFlags & MAGIC_FLUSH) {						PortP->MagicFlags |= MORE_OUTPUT_EYGOR;					} else {						if (!can_add_transmit(&PacketP, PortP)) {							rio_spin_unlock(&PortP->portSem);							continue;						}						rio_spin_unlock(&PortP->portSem);						RIOTxEnable((char *) PortP);						rio_spin_lock(&PortP->portSem);						PortP->MagicFlags &= ~MORE_OUTPUT_EYGOR;					}				}			}			/*			 ** If we can't add anything to the transmit queue, then			 ** we need do none of the remaining processing.			 */			if (!can_add_transmit(&PacketP, PortP)) {				rio_spin_unlock(&PortP->portSem);				continue;			}			rio_spin_unlock(&PortP->portSem);			RIOTxEnable((char *) PortP);		}	}}/*** Routine for handling received data for tty drivers*/static void RIOReceive(struct rio_info *p, struct Port *PortP){	struct tty_struct *TtyP;	unsigned short transCount;	struct PKT *PacketP;	register unsigned int DataCnt;	unsigned char *ptr;	unsigned char *buf;	int copied = 0;	static int intCount, RxIntCnt;	/*	 ** The receive data process is to remove packets from the	 ** PHB until there aren't any more or the current cblock	 ** is full. When this occurs, there will be some left over	 ** data in the packet, that we must do something with.	 ** As we haven't unhooked the packet from the read list	 ** yet, we can just leave the packet there, having first	 ** made a note of how far we got. This means that we need	 ** a pointer per port saying where we start taking the	 ** data from - this will normally be zero, but when we	 ** run out of space it will be set to the offset of the	 ** next byte to copy from the packet data area. The packet	 ** length field is decremented by the number of bytes that	 ** we succesfully removed from the packet. When this reaches	 ** zero, we reset the offset pointer to be zero, and free	 ** the packet from the front of the queue.	 */	intCount++;	TtyP = PortP->gs.tty;	if (!TtyP) {		rio_dprintk(RIO_DEBUG_INTR, "RIOReceive: tty is null. \n");		return;	}	if (PortP->State & RIO_THROTTLE_RX) {		rio_dprintk(RIO_DEBUG_INTR, "RIOReceive: Throttled. Can't handle more input.\n");		return;	}	if (PortP->State & RIO_DELETED) {		while (can_remove_receive(&PacketP, PortP)) {			remove_receive(PortP);			put_free_end(PortP->HostP, PacketP);		}	} else {		/*		 ** loop, just so long as:		 **   i ) there's some data ( i.e. can_remove_receive )		 **  ii ) we haven't been blocked		 ** iii ) there's somewhere to put the data		 **  iv ) we haven't outstayed our welcome		 */		transCount = 1;		while (can_remove_receive(&PacketP, PortP)		       && transCount) {			RxIntCnt++;			/*			 ** check that it is not a command!			 */			if (PacketP->len & PKT_CMD_BIT) {				rio_dprintk(RIO_DEBUG_INTR, "RIO: unexpected command packet received on PHB\n");				/*      rio_dprint(RIO_DEBUG_INTR, (" sysport   = %d\n", p->RIOPortp->PortNum)); */				rio_dprintk(RIO_DEBUG_INTR, " dest_unit = %d\n", PacketP->dest_unit);				rio_dprintk(RIO_DEBUG_INTR, " dest_port = %d\n", PacketP->dest_port);				rio_dprintk(RIO_DEBUG_INTR, " src_unit  = %d\n", PacketP->src_unit);				rio_dprintk(RIO_DEBUG_INTR, " src_port  = %d\n", PacketP->src_port);				rio_dprintk(RIO_DEBUG_INTR, " len	   = %d\n", PacketP->len);				rio_dprintk(RIO_DEBUG_INTR, " control   = %d\n", PacketP->control);				rio_dprintk(RIO_DEBUG_INTR, " csum	   = %d\n", PacketP->csum);				rio_dprintk(RIO_DEBUG_INTR, "	 data bytes: ");				for (DataCnt = 0; DataCnt < PKT_MAX_DATA_LEN; DataCnt++)					rio_dprintk(RIO_DEBUG_INTR, "%d\n", PacketP->data[DataCnt]);				remove_receive(PortP);				put_free_end(PortP->HostP, PacketP);				continue;	/* with next packet */			}			/*			 ** How many characters can we move 'upstream' ?			 **			 ** Determine the minimum of the amount of data			 ** available and the amount of space in which to			 ** put it.			 **			 ** 1.        Get the packet length by masking 'len'			 **   for only the length bits.			 ** 2.        Available space is [buffer size] - [space used]			 **			 ** Transfer count is the minimum of packet length			 ** and available space.			 */			transCount = tty_buffer_request_room(TtyP, PacketP->len & PKT_LEN_MASK);			rio_dprintk(RIO_DEBUG_REC, "port %d: Copy %d bytes\n", PortP->PortNum, transCount);			/*			 ** To use the following 'kkprintfs' for debugging - change the '#undef'			 ** to '#define', (this is the only place ___DEBUG_IT___ occurs in the			 ** driver).			 */			ptr = (unsigned char *) PacketP->data + PortP->RxDataStart;			tty_prepare_flip_string(TtyP, &buf, transCount);			rio_memcpy_fromio(buf, ptr, transCount);			PortP->RxDataStart += transCount;			PacketP->len -= transCount;			copied += transCount;			if (PacketP->len == 0) {				/*				 ** If we have emptied the packet, then we can				 ** free it, and reset the start pointer for				 ** the next packet.				 */				remove_receive(PortP);				put_free_end(PortP->HostP, PacketP);				PortP->RxDataStart = 0;			}		}	}	if (copied) {		rio_dprintk(RIO_DEBUG_REC, "port %d: pushing tty flip buffer: %d total bytes copied.\n", PortP->PortNum, copied);		tty_flip_buffer_push(TtyP);	}	return;}

⌨️ 快捷键说明

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