📄 riocmd.c
字号:
*** *** *** M O D E M S T A T E C H A N G E *** *** *** ************************************************************* \***********************************************************/ /* ** If the device is a modem, then check the modem ** carrier. */ if (PortP->gs.tty == NULL) break; if (PortP->gs.tty->termios == NULL) break; if (!(PortP->gs.tty->termios->c_cflag & CLOCAL) && ((PortP->State & (RIO_MOPEN|RIO_WOPEN)))) { rio_dprintk (RIO_DEBUG_CMD, "Is there a Carrier?\n"); /* ** Is there a carrier? */ if ( PortP->ModemState & MSVR1_CD ) { /* ** Has carrier just appeared? */ if (!(PortP->State & RIO_CARR_ON)) { rio_dprintk (RIO_DEBUG_CMD, "Carrier just came up.\n"); PortP->State |= RIO_CARR_ON; /* ** wakeup anyone in WOPEN */ if (PortP->State & (PORT_ISOPEN | RIO_WOPEN) ) wake_up_interruptible (&PortP->gs.open_wait);#ifdef STATS PortP->Stat.ModemOnCnt++;#endif } } else { /* ** Has carrier just dropped? */ if (PortP->State & RIO_CARR_ON) { if (PortP->State & (PORT_ISOPEN|RIO_WOPEN|RIO_MOPEN)) tty_hangup (PortP->gs.tty); PortP->State &= ~RIO_CARR_ON; rio_dprintk (RIO_DEBUG_CMD, "Carrirer just went down\n");#ifdef STATS PortP->Stat.ModemOffCnt++;#endif } } } }#endif } break; default: rio_dprintk (RIO_DEBUG_CMD, "Unknown command %d on CMD_RUP of host %d\n", RBYTE(PktCmdP->Command),HostP-p->RIOHosts); break; } rio_spin_unlock_irqrestore(&PortP->portSem, flags); func_exit (); return TRUE;}/*** The command mechanism:** Each rup has a chain of commands associated with it.** This chain is maintained by routines in this file.** Periodically we are called and we run a quick check of all the** active chains to determine if there is a command to be executed,** and if the rup is ready to accept it.***//*** Allocate an empty command block.*/struct CmdBlk *RIOGetCmdBlk(void){ struct CmdBlk *CmdBlkP; CmdBlkP = (struct CmdBlk *)sysbrk(sizeof(struct CmdBlk)); if (CmdBlkP) bzero(CmdBlkP, sizeof(struct CmdBlk)); return CmdBlkP;}/*** Return a block to the head of the free list.*/voidRIOFreeCmdBlk(struct CmdBlk *CmdBlkP){ sysfree((void *)CmdBlkP, sizeof(struct CmdBlk));}/*** attach a command block to the list of commands to be performed for** a given rup.*/intRIOQueueCmdBlk(struct Host *HostP, uint Rup, struct CmdBlk *CmdBlkP){ struct CmdBlk **Base; struct UnixRup *UnixRupP; unsigned long flags;#ifdef CHECK CheckHostP( HostP ); CheckRup( Rup ); CheckCmdBlkP( CmdBlkP );#endif if ( Rup >= (ushort)(MAX_RUP+LINKS_PER_UNIT) ) { rio_dprintk (RIO_DEBUG_CMD, "Illegal rup number %d in RIOQueueCmdBlk\n",Rup); RIOFreeCmdBlk( CmdBlkP ); return RIO_FAIL; } UnixRupP = &HostP->UnixRups[Rup]; rio_spin_lock_irqsave(&UnixRupP->RupLock, flags); /* ** If the RUP is currently inactive, then put the request ** straight on the RUP.... */ if ( (UnixRupP->CmdsWaitingP == NULL) && (UnixRupP->CmdPendingP == NULL) && (RWORD(UnixRupP->RupP->txcontrol) == TX_RUP_INACTIVE ) && (CmdBlkP->PreFuncP ? (*CmdBlkP->PreFuncP)(CmdBlkP->PreArg,CmdBlkP) :TRUE)) { rio_dprintk (RIO_DEBUG_CMD, "RUP inactive-placing command straight on. Cmd byte is 0x%x\n", CmdBlkP->Packet.data[0]); /* ** Whammy! blat that pack! */ HostP->Copy( (caddr_t)&CmdBlkP->Packet, RIO_PTR(HostP->Caddr, UnixRupP->RupP->txpkt ), sizeof(PKT) ); /* ** place command packet on the pending position. */ UnixRupP->CmdPendingP = CmdBlkP; /* ** set the command register */ WWORD(UnixRupP->RupP->txcontrol , TX_PACKET_READY); rio_spin_unlock_irqrestore(&UnixRupP->RupLock, flags); return RIO_SUCCESS; } rio_dprintk (RIO_DEBUG_CMD, "RUP active - en-queing\n"); if ( UnixRupP->CmdsWaitingP != NULL) rio_dprintk (RIO_DEBUG_CMD, "Rup active - command waiting\n"); if ( UnixRupP->CmdPendingP != NULL ) rio_dprintk (RIO_DEBUG_CMD, "Rup active - command pending\n"); if ( RWORD(UnixRupP->RupP->txcontrol) != TX_RUP_INACTIVE ) rio_dprintk (RIO_DEBUG_CMD, "Rup active - command rup not ready\n"); Base = &UnixRupP->CmdsWaitingP; rio_dprintk (RIO_DEBUG_CMD, "First try to queue cmdblk 0x%x at 0x%x\n", (int)CmdBlkP,(int)Base); while ( *Base ) { rio_dprintk (RIO_DEBUG_CMD, "Command cmdblk 0x%x here\n", (int)(*Base)); Base = &((*Base)->NextP); rio_dprintk (RIO_DEBUG_CMD, "Now try to queue cmd cmdblk 0x%x at 0x%x\n", (int)CmdBlkP,(int)Base); } rio_dprintk (RIO_DEBUG_CMD, "Will queue cmdblk 0x%x at 0x%x\n",(int)CmdBlkP,(int)Base); *Base = CmdBlkP; CmdBlkP->NextP = NULL; rio_spin_unlock_irqrestore(&UnixRupP->RupLock, flags); return RIO_SUCCESS;}/*** Here we go - if there is an empty rup, fill it!** must be called at splrio() or higher.*/voidRIOPollHostCommands(struct rio_info *p, struct Host *HostP){ register struct CmdBlk *CmdBlkP; register struct UnixRup *UnixRupP; struct PKT *PacketP; ushort Rup; unsigned long flags; Rup = MAX_RUP+LINKS_PER_UNIT; do { /* do this loop for each RUP */ /* ** locate the rup we are processing & lock it */ UnixRupP = &HostP->UnixRups[--Rup]; spin_lock_irqsave(&UnixRupP->RupLock, flags); /* ** First check for incoming commands: */ if ( RWORD(UnixRupP->RupP->rxcontrol) != RX_RUP_INACTIVE ) { int FreeMe; PacketP =(PKT *)RIO_PTR(HostP->Caddr,RWORD(UnixRupP->RupP->rxpkt)); ShowPacket( DBG_CMD, PacketP ); switch ( RBYTE(PacketP->dest_port) ) { case BOOT_RUP: rio_dprintk (RIO_DEBUG_CMD, "Incoming Boot %s packet '%x'\n", RBYTE(PacketP->len) & 0x80 ? "Command":"Data", RBYTE(PacketP->data[0])); rio_spin_unlock_irqrestore(&UnixRupP->RupLock, flags); FreeMe= RIOBootRup(p, Rup,HostP,PacketP); rio_spin_lock_irqsave(&UnixRupP->RupLock, flags); break; case COMMAND_RUP: /* ** Free the RUP lock as loss of carrier causes a ** ttyflush which will (eventually) call another ** routine that uses the RUP lock. */ rio_spin_unlock_irqrestore(&UnixRupP->RupLock, flags); FreeMe= RIOCommandRup(p, Rup,HostP,PacketP); if (PacketP->data[5] == MEMDUMP) { rio_dprintk (RIO_DEBUG_CMD, "Memdump from 0x%x complete\n", *(ushort *) &(PacketP->data[6])); HostP->Copy( (caddr_t)&(PacketP->data[8]), (caddr_t)p->RIOMemDump, 32 ); } rio_spin_lock_irqsave(&UnixRupP->RupLock, flags); break; case ROUTE_RUP: rio_spin_unlock_irqrestore( &UnixRupP->RupLock, flags); FreeMe = RIORouteRup(p, Rup, HostP, PacketP ); rio_spin_lock_irqsave( &UnixRupP->RupLock, flags ); break; default: rio_dprintk (RIO_DEBUG_CMD, "Unknown RUP %d\n", RBYTE(PacketP->dest_port)); FreeMe = 1; break; } if ( FreeMe ) { rio_dprintk (RIO_DEBUG_CMD, "Free processed incoming command packet\n"); put_free_end(HostP,PacketP); WWORD(UnixRupP->RupP->rxcontrol , RX_RUP_INACTIVE); if ( RWORD(UnixRupP->RupP->handshake)==PHB_HANDSHAKE_SET ) { rio_dprintk (RIO_DEBUG_CMD, "Handshake rup %d\n",Rup); WWORD(UnixRupP->RupP->handshake, PHB_HANDSHAKE_SET|PHB_HANDSHAKE_RESET); } } } /* ** IF a command was running on the port, ** and it has completed, then tidy it up. */ if ( (CmdBlkP = UnixRupP->CmdPendingP) && /* ASSIGN! */ (RWORD(UnixRupP->RupP->txcontrol) == TX_RUP_INACTIVE)) { /* ** we are idle. ** there is a command in pending. ** Therefore, this command has finished. ** So, wakeup whoever is waiting for it (and tell them ** what happened). */ if ( CmdBlkP->Packet.dest_port == BOOT_RUP ) rio_dprintk (RIO_DEBUG_CMD, "Free Boot %s Command Block '%x'\n", CmdBlkP->Packet.len & 0x80 ? "Command":"Data", CmdBlkP->Packet.data[0]); rio_dprintk (RIO_DEBUG_CMD, "Command 0x%x completed\n",(int)CmdBlkP); /* ** Clear the Rup lock to prevent mutual exclusion. */ if ( CmdBlkP->PostFuncP ) { rio_spin_unlock_irqrestore(&UnixRupP->RupLock, flags); (*CmdBlkP->PostFuncP) (CmdBlkP->PostArg,CmdBlkP); rio_spin_lock_irqsave(&UnixRupP->RupLock, flags); } /* ** ....clear the pending flag.... */ UnixRupP->CmdPendingP = NULL; /* ** ....and return the command block to the freelist. */ RIOFreeCmdBlk( CmdBlkP ); } /* ** If there is a command for this rup, and the rup ** is idle, then process the command */ if ( (CmdBlkP = UnixRupP->CmdsWaitingP) && /* ASSIGN! */ (UnixRupP->CmdPendingP == NULL) && (RWORD(UnixRupP->RupP->txcontrol) == TX_RUP_INACTIVE)) { /* ** if the pre-function is non-zero, call it. ** If it returns RIO_FAIL then don't ** send this command yet! */#ifdef CHECK CheckCmdBlkP (CmdBlkP);#endif if ( !(CmdBlkP->PreFuncP ? (*CmdBlkP->PreFuncP)(CmdBlkP->PreArg, CmdBlkP) : TRUE)) { rio_dprintk (RIO_DEBUG_CMD, "Not ready to start command 0x%x\n",(int)CmdBlkP); } else { rio_dprintk (RIO_DEBUG_CMD, "Start new command 0x%x Cmd byte is 0x%x\n", (int)CmdBlkP, CmdBlkP->Packet.data[0]); /* ** Whammy! blat that pack! */#ifdef CHECK CheckPacketP ((PKT *)RIO_PTR(HostP->Caddr, UnixRupP->RupP->txpkt));#endif HostP->Copy( (caddr_t)&CmdBlkP->Packet, RIO_PTR(HostP->Caddr, UnixRupP->RupP->txpkt), sizeof(PKT)); /* ** remove the command from the rup command queue... */ UnixRupP->CmdsWaitingP = CmdBlkP->NextP; /* ** ...and place it on the pending position. */ UnixRupP->CmdPendingP = CmdBlkP; /* ** set the command register */ WWORD(UnixRupP->RupP->txcontrol,TX_PACKET_READY); /* ** the command block will be freed ** when the command has been processed. */ } } spin_unlock_irqrestore(&UnixRupP->RupLock, flags); } while ( Rup );}intRIOWFlushMark(int iPortP, struct CmdBlk *CmdBlkP){ struct Port * PortP = (struct Port *)iPortP; unsigned long flags; rio_spin_lock_irqsave(&PortP->portSem, flags);#ifdef CHECK CheckPortP( PortP );#endif PortP->WflushFlag++; PortP->MagicFlags |= MAGIC_FLUSH; rio_spin_unlock_irqrestore(&PortP->portSem, flags); return RIOUnUse( iPortP, CmdBlkP );}intRIORFlushEnable(int iPortP, struct CmdBlk *CmdBlkP){ struct Port * PortP = (struct Port *)iPortP; PKT *PacketP; unsigned long flags; rio_spin_lock_irqsave(&PortP->portSem, flags); while ( can_remove_receive(&PacketP, PortP) ) { remove_receive(PortP); ShowPacket(DBG_PROC, PacketP ); put_free_end( PortP->HostP, PacketP ); } if ( 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_CMD, "Util: Set RX handshake bit\n"); WWORD(PortP->PhbP->handshake, PHB_HANDSHAKE_SET|PHB_HANDSHAKE_RESET); } rio_spin_unlock_irqrestore(&PortP->portSem, flags); return RIOUnUse( iPortP, CmdBlkP );}intRIOUnUse(int iPortP, struct CmdBlk *CmdBlkP){ struct Port * PortP = (struct Port *)iPortP; unsigned long flags; rio_spin_lock_irqsave(&PortP->portSem, flags);#ifdef CHECK CheckPortP( PortP );#endif rio_dprintk (RIO_DEBUG_CMD, "Decrement in use count for port\n"); if (PortP->InUse) { if ( --PortP->InUse != NOT_INUSE ) { rio_spin_unlock_irqrestore(&PortP->portSem, flags); return 0; } } /* ** While PortP->InUse is set (i.e. a preemptive command has been sent to ** the RTA and is awaiting completion), any transmit data is prevented from ** being transferred from the write queue into the transmit packets ** (add_transmit) and no furthur transmit interrupt will be sent for that ** data. The next interrupt will occur up to 500ms later (RIOIntr is called ** twice a second as a saftey measure). This was the case when kermit was ** used to send data into a RIO port. After each packet was sent, TCFLSH ** was called to flush the read queue preemptively. PortP->InUse was ** incremented, thereby blocking the 6 byte acknowledgement packet ** transmitted back. This acknowledgment hung around for 500ms before ** being sent, thus reducing input performance substantially!. ** When PortP->InUse becomes NOT_INUSE, we must ensure that any data ** hanging around in the transmit buffer is sent immediately. */ WWORD(PortP->HostP->ParmMapP->tx_intr, 1); /* What to do here .. wakeup( (caddr_t)&(PortP->InUse) ); */ rio_spin_unlock_irqrestore(&PortP->portSem, flags); return 0;}voidShowPacket(uint Flags, struct PKT *PacketP){}/*** ** How to use this file:** ** To send a command down a rup, you need to allocate a command block, fill** in the packet information, fill in the command number, fill in the pre-** and post- functions and arguments, and then add the command block to the** queue of command blocks for the port in question. When the port is idle,** then the pre-function will be called. If this returns RIO_FAIL then the** command will be re-queued and tried again at a later date (probably in one** clock tick). If the pre-function returns NOT RIO_FAIL, then the command** packet will be queued on the RUP, and the txcontrol field set to the** command number. When the txcontrol field has changed from being the** command number, then the post-function will be called, with the argument** specified earlier, a pointer to the command block, and the value of** txcontrol.** ** To allocate a command block, call RIOGetCmdBlk(). This returns a pointer** to the command block structure allocated, or NULL if there aren't any.** The block will have been zeroed for you.** ** The structure has the following fields:** ** struct CmdBlk** {** struct CmdBlk *NextP; ** Pointer to next command block **** struct PKT Packet; ** A packet, to copy to the rup **** int (*PreFuncP)(); ** The func to call to check if OK **** int PreArg; ** The arg for the func **** int (*PostFuncP)(); ** The func to call when completed **** int PostArg; ** The arg for the func **** };** ** You need to fill in ALL fields EXCEPT NextP, which is used to link the** blocks together either on the free list or on the Rup list.** ** Packet is an actual packet structure to be filled in with the packet** information associated with the command. You need to fill in everything,** as the command processore doesn't process the command packet in any way.** ** The PreFuncP is called before the packet is enqueued on the host rup.** PreFuncP is called as (*PreFuncP)(PreArg, CmdBlkP);. PreFuncP must** return !RIO_FAIL to have the packet queued on the rup, and RIO_FAIL** if the packet is NOT to be queued.** ** The PostFuncP is called when the command has completed. It is called** as (*PostFuncP)(PostArg, CmdBlkP, txcontrol);. PostFuncP is not expected** to return a value. PostFuncP does NOT need to free the command block,** as this happens automatically after PostFuncP returns.** ** Once the command block has been filled in, it is attached to the correct** queue by calling RIOQueueCmdBlk( HostP, Rup, CmdBlkP ) where HostP is** a pointer to the struct Host, Rup is the NUMBER of the rup (NOT a pointer** to it!), and CmdBlkP is the pointer to the command block allocated using** RIOGetCmdBlk().** */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -