📄 riointr.c
字号:
WWORD( HostP->ParmMapP->rup_intr , 0 ); p->RIORupCount++; RupIntr++; rio_dprintk (RIO_DEBUG_INTR, "rio: RUP interrupt on host %d\n", HostP-p->RIOHosts); RIOPollHostCommands(p, HostP ); } if ( RWORD( HostP->ParmMapP->rx_intr ) ) { int port; WWORD( HostP->ParmMapP->rx_intr , 0 ); p->RIORxCount++; RxIntr++; rio_dprintk (RIO_DEBUG_INTR, "rio: RX interrupt on host %d\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 ) && ( RWORD( 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"); WWORD( PortP->PhbP->handshake, PHB_HANDSHAKE_SET|PHB_HANDSHAKE_RESET ); } rio_spin_unlock(&PortP->portSem); } } if ( RWORD( HostP->ParmMapP->tx_intr ) ) { int port; WWORD( HostP->ParmMapP->tx_intr , 0); p->RIOTxCount++; TxIntr++; rio_dprintk (RIO_DEBUG_INTR, "rio: TX interrupt on host %d\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); /* ** 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 1 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 ) ) ? TRUE : FALSE, DONT_SLEEP ) == RIO_FAIL ) { continue; /* with next port */ } rio_spin_lock(&PortP->portSem); PortP->MagicFlags &= ~MAGIC_REBOOT; }#endif /* ** 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]; WBYTE( PktCmdP->Command , WFLUSH ); p = PortP->HostPort % ( ushort )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; WBYTE( PktCmdP->PhbNum, p ); /* ** to make debuggery easier */ WBYTE( PacketP->data[ 2], 'W' ); WBYTE( PacketP->data[ 3], 'F' ); WBYTE( PacketP->data[ 4], 'L' ); WBYTE( PacketP->data[ 5], 'U' ); WBYTE( PacketP->data[ 6], 'S' ); WBYTE( PacketP->data[ 7], 'H' ); WBYTE( PacketP->data[ 8], ' ' ); WBYTE( PacketP->data[ 9], '0'+PortP->WflushFlag ); WBYTE( PacketP->data[10], ' ' ); WBYTE( PacketP->data[11], ' ' ); WBYTE( PacketP->data[12], '\0' ); /* ** its two bytes long! */ WBYTE( PacketP->len , PKT_CMD_BIT | 2 ); /* ** 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 clist drivers.** NB: Called with the tty locked. The spl from the lockb( ) is passed.** we return the ttySpl level that we re-locked at.*/voidRIOReceive(p, PortP)struct rio_info * p;struct Port * PortP;{ struct tty_struct *TtyP; register ushort transCount; struct PKT *PacketP; register uint DataCnt; uchar * ptr; 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.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -