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 + -
显示快捷键?