riocmd.c
来自「LINUX 2.6.17.4的源码」· C语言 代码 · 共 944 行 · 第 1/2 页
C
944 行
PortP->ModemState = ReportedModemStatus; } else { rio_dprintk(RIO_DEBUG_CMD, "Modem status change from 0x%x to 0x%x\n", PortP->ModemState, ReportedModemStatus); PortP->ModemState = ReportedModemStatus;#ifdef MODEM_SUPPORT if (PortP->Mapped) { /***********************************************************\ ************************************************************* *** *** *** 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); } } 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"); } } } }#endif } break; default: rio_dprintk(RIO_DEBUG_CMD, "Unknown command %d on CMD_RUP of host %Zd\n", readb(&PktCmdP->Command), HostP - p->RIOHosts); break; } rio_spin_unlock_irqrestore(&PortP->portSem, flags); func_exit(); return 1;}/*** 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 *)kmalloc(sizeof(struct CmdBlk), GFP_ATOMIC); if (CmdBlkP) memset(CmdBlkP, 0, sizeof(struct CmdBlk)); return CmdBlkP;}/*** Return a block to the head of the free list.*/void RIOFreeCmdBlk(struct CmdBlk *CmdBlkP){ kfree(CmdBlkP);}/*** attach a command block to the list of commands to be performed for** a given rup.*/int RIOQueueCmdBlk(struct Host *HostP, uint Rup, struct CmdBlk *CmdBlkP){ struct CmdBlk **Base; struct UnixRup *UnixRupP; unsigned long flags; if (Rup >= (unsigned short) (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) && (readw(&UnixRupP->RupP->txcontrol) == TX_RUP_INACTIVE) && (CmdBlkP->PreFuncP ? (*CmdBlkP->PreFuncP) (CmdBlkP->PreArg, CmdBlkP) : 1)) { 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(struct PKT)); /* ** place command packet on the pending position. */ UnixRupP->CmdPendingP = CmdBlkP; /* ** set the command register */ writew(TX_PACKET_READY, &UnixRupP->RupP->txcontrol); rio_spin_unlock_irqrestore(&UnixRupP->RupLock, flags); return 0; } 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 (readw(&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 %p at %p\n", CmdBlkP, Base); while (*Base) { rio_dprintk(RIO_DEBUG_CMD, "Command cmdblk %p here\n", *Base); Base = &((*Base)->NextP); rio_dprintk(RIO_DEBUG_CMD, "Now try to queue cmd cmdblk %p at %p\n", CmdBlkP, Base); } rio_dprintk(RIO_DEBUG_CMD, "Will queue cmdblk %p at %p\n", CmdBlkP, Base); *Base = CmdBlkP; CmdBlkP->NextP = NULL; rio_spin_unlock_irqrestore(&UnixRupP->RupLock, flags); return 0;}/*** Here we go - if there is an empty rup, fill it!** must be called at splrio() or higher.*/void RIOPollHostCommands(struct rio_info *p, struct Host *HostP){ struct CmdBlk *CmdBlkP; struct UnixRup *UnixRupP; struct PKT *PacketP; unsigned short 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 (readw(&UnixRupP->RupP->rxcontrol) != RX_RUP_INACTIVE) { int FreeMe; PacketP = (struct PKT *) RIO_PTR(HostP->Caddr, readw(&UnixRupP->RupP->rxpkt)); switch (readb(&PacketP->dest_port)) { case BOOT_RUP: rio_dprintk(RIO_DEBUG_CMD, "Incoming Boot %s packet '%x'\n", readb(&PacketP->len) & 0x80 ? "Command" : "Data", readb(&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", *(unsigned short *) & (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", readb(&PacketP->dest_port)); FreeMe = 1; break; } if (FreeMe) { rio_dprintk(RIO_DEBUG_CMD, "Free processed incoming command packet\n"); put_free_end(HostP, PacketP); writew(RX_RUP_INACTIVE, &UnixRupP->RupP->rxcontrol); if (readw(&UnixRupP->RupP->handshake) == PHB_HANDSHAKE_SET) { rio_dprintk(RIO_DEBUG_CMD, "Handshake rup %d\n", Rup); writew(PHB_HANDSHAKE_SET | PHB_HANDSHAKE_RESET, &UnixRupP->RupP->handshake); } } } /* ** IF a command was running on the port, ** and it has completed, then tidy it up. */ if ((CmdBlkP = UnixRupP->CmdPendingP) && /* ASSIGN! */ (readw(&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 %p completed\n", 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) && (readw(&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! */ if (!(CmdBlkP->PreFuncP ? (*CmdBlkP->PreFuncP) (CmdBlkP->PreArg, CmdBlkP) : 1)) { rio_dprintk(RIO_DEBUG_CMD, "Not ready to start command %p\n", CmdBlkP); } else { rio_dprintk(RIO_DEBUG_CMD, "Start new command %p Cmd byte is 0x%x\n", CmdBlkP, CmdBlkP->Packet.data[0]); /* ** Whammy! blat that pack! */ HostP->Copy((caddr_t) & CmdBlkP->Packet, RIO_PTR(HostP->Caddr, UnixRupP->RupP->txpkt), sizeof(struct 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 */ writew(TX_PACKET_READY, &UnixRupP->RupP->txcontrol); /* ** the command block will be freed ** when the command has been processed. */ } } spin_unlock_irqrestore(&UnixRupP->RupLock, flags); } while (Rup);}int RIOWFlushMark(unsigned long iPortP, struct CmdBlk *CmdBlkP){ struct Port *PortP = (struct Port *) iPortP; unsigned long flags; rio_spin_lock_irqsave(&PortP->portSem, flags); PortP->WflushFlag++; PortP->MagicFlags |= MAGIC_FLUSH; rio_spin_unlock_irqrestore(&PortP->portSem, flags); return RIOUnUse(iPortP, CmdBlkP);}int RIORFlushEnable(unsigned long iPortP, struct CmdBlk *CmdBlkP){ struct Port *PortP = (struct Port *) iPortP; struct PKT *PacketP; unsigned long flags; rio_spin_lock_irqsave(&PortP->portSem, flags); while (can_remove_receive(&PacketP, PortP)) { remove_receive(PortP); put_free_end(PortP->HostP, PacketP); } if (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_CMD, "Util: Set RX handshake bit\n"); writew(PHB_HANDSHAKE_SET | PHB_HANDSHAKE_RESET, &PortP->PhbP->handshake); } rio_spin_unlock_irqrestore(&PortP->portSem, flags); return RIOUnUse(iPortP, CmdBlkP);}int RIOUnUse(unsigned long iPortP, struct CmdBlk *CmdBlkP){ struct Port *PortP = (struct Port *) iPortP; unsigned long flags; rio_spin_lock_irqsave(&PortP->portSem, flags); 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. */ writew(1, &PortP->HostP->ParmMapP->tx_intr); /* What to do here .. wakeup( (caddr_t)&(PortP->InUse) ); */ rio_spin_unlock_irqrestore(&PortP->portSem, flags); return 0;}/*** ** 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 + =
减小字号Ctrl + -
显示快捷键?