current->state = TASK_INTERRUPTIBLE; schedule_timeout(1);
schedule_timeout_interruptible(1);
i2QueueCommands(int type, i2ChanStrPtr pCh, int timeout, int nCommands,					 cmdSyntaxPtr pCs0,...){	int totalsize = 0;	int blocksize;	int lastended;	cmdSyntaxPtr *ppCs;	cmdSyntaxPtr pCs;	int count;	int flag;	i2eBordStrPtr pB;	unsigned short maxBlock;	unsigned short maxBuff;	short bufroom;	unsigned short stuffIndex;	unsigned char *pBuf;	unsigned char *pInsert;	unsigned char *pDest, *pSource;	unsigned short channel;	int cnt;	unsigned long flags = 0;	rwlock_t *lock_var_p = NULL;	// Make sure the channel exists, otherwise do nothing	if ( !i2Validate ( pCh ) ) {		return -1;	}	ip2trace (CHANN, ITRC_QUEUE, ITRC_ENTER, 0 );	pB = pCh->pMyBord;	// Board must also exist, and THE INTERRUPT COMMAND ALREADY SENT	if (pB->i2eValid != I2E_MAGIC || pB->i2eUsingIrq == IRQ_UNDEFINED) {		return -2;	}	// If the board has gone fatal, return bad, and also hit the trap routine if	// it exists.	if (pB->i2eFatal) {		if ( pB->i2eFatalTrap ) {			(*(pB)->i2eFatalTrap)(pB);		}		return -3;	}	// Set up some variables, Which buffers are we using?  How big are they?	switch(type)	{	case PTYPE_INLINE:		flag = INL;		maxBlock = MAX_OBUF_BLOCK;		maxBuff = OBUF_SIZE;		pBuf = pCh->Obuf;		break;	case PTYPE_BYPASS:		flag = BYP;		maxBlock = MAX_CBUF_BLOCK;		maxBuff = CBUF_SIZE;		pBuf = pCh->Cbuf;		break;	default:		return -4;	}	// Determine the total size required for all the commands	totalsize = blocksize = sizeof(i2CmdHeader);	lastended = 0;	ppCs = &pCs0;	for ( count = nCommands; count; count--, ppCs++)	{		pCs = *ppCs;		cnt = pCs->length;		// Will a new block be needed for this one? 		// Two possible reasons: too		// big or previous command has to be at the end of a packet.		if ((blocksize + cnt > maxBlock) || lastended) {			blocksize = sizeof(i2CmdHeader);			totalsize += sizeof(i2CmdHeader);		}		totalsize += cnt;		blocksize += cnt;		// If this command had to end a block, then we will make sure to		// account for it should there be any more blocks.		lastended = pCs->flags & END;	}	for (;;) {		// Make sure any pending flush commands go out before we add more data.		if ( !( pCh->flush_flags && i2RetryFlushOutput( pCh ) ) ) {			// How much room (this time through) ?			switch(type) {			case PTYPE_INLINE:				lock_var_p = &pCh->Obuf_spinlock;				WRITE_LOCK_IRQSAVE(lock_var_p,flags);				stuffIndex = pCh->Obuf_stuff;				bufroom = pCh->Obuf_strip - stuffIndex;				break;			case PTYPE_BYPASS:				lock_var_p = &pCh->Cbuf_spinlock;				WRITE_LOCK_IRQSAVE(lock_var_p,flags);				stuffIndex = pCh->Cbuf_stuff;				bufroom = pCh->Cbuf_strip - stuffIndex;				break;			default:				return -5;			}			if (--bufroom < 0) {				bufroom += maxBuff;			}			ip2trace (CHANN, ITRC_QUEUE, 2, 1, bufroom );			// Check for overflow			if (totalsize <= bufroom) {				// Normal Expected path - We still hold LOCK				break; /* from for()- Enough room: goto proceed */			}		}		ip2trace (CHANN, ITRC_QUEUE, 3, 1, totalsize );		// Prepare to wait for buffers to empty		WRITE_UNLOCK_IRQRESTORE(lock_var_p,flags); 		serviceOutgoingFifo(pB);	// Dump what we got		if (timeout == 0) {			return 0;   // Tired of waiting		}		if (timeout > 0)			timeout--;   // So negative values == forever				if (!in_interrupt()) {			current->state = TASK_INTERRUPTIBLE;			schedule_timeout(1);	// short nap 		} else {			// we cannot sched/sleep in interrrupt silly			return 0;   		}		if (signal_pending(current)) {			return 0;   // Wake up! Time to die!!!		}		ip2trace (CHANN, ITRC_QUEUE, 4, 0 );	}	// end of for(;;)	// At this point we have room and the lock - stick them in.	channel = pCh->infl.hd.i2sChannel;	pInsert = &pBuf[stuffIndex];     // Pointer to start of packet	pDest = CMD_OF(pInsert);         // Pointer to start of command	// When we start counting, the block is the size of the header	for (blocksize = sizeof(i2CmdHeader), count = nCommands,			lastended = 0, ppCs = &pCs0;		count;		count--, ppCs++)	{		pCs = *ppCs;         // Points to command protocol structure		// If this is a bookmark request command, post the fact that a bookmark		// request is pending. NOTE THIS TRICK ONLY WORKS BECAUSE CMD_BMARK_REQ		// has no parameters!  The more general solution would be to reference		// pCs->cmd[0].		if (pCs == CMD_BMARK_REQ) {			pCh->bookMarks++;			ip2trace (CHANN, ITRC_DRAIN, 30, 1, pCh->bookMarks );		}		cnt = pCs->length;		// If this command would put us over the maximum block size or 		// if the last command had to be at the end of a block, we end		// the existing block here and start a new one.		if ((blocksize + cnt > maxBlock) || lastended) {			ip2trace (CHANN, ITRC_QUEUE, 5, 0 );			PTYPE_OF(pInsert) = type;			CHANNEL_OF(pInsert) = channel;			// count here does not include the header			CMD_COUNT_OF(pInsert) = blocksize - sizeof(i2CmdHeader);			stuffIndex += blocksize;			if(stuffIndex >= maxBuff) {				stuffIndex = 0;				pInsert = pBuf;			}			pInsert = &pBuf[stuffIndex];  // Pointer to start of next pkt			pDest = CMD_OF(pInsert);			blocksize = sizeof(i2CmdHeader);		}		// Now we know there is room for this one in the current block		blocksize += cnt;       // Total bytes in this command		pSource = pCs->cmd;     // Copy the command into the buffer		while (cnt--) {			*pDest++ = *pSource++;		}		// If this command had to end a block, then we will make sure to account		// for it should there be any more blocks.		lastended = pCs->flags & END;	}	// end for	// Clean up the final block by writing header, etc	PTYPE_OF(pInsert) = type;	CHANNEL_OF(pInsert) = channel;	// count here does not include the header	CMD_COUNT_OF(pInsert) = blocksize - sizeof(i2CmdHeader);	stuffIndex += blocksize;	if(stuffIndex >= maxBuff) {		stuffIndex = 0;		pInsert = pBuf;	}	// Updates the index, and post the need for service. When adding these to	// the queue of channels, we turn off the interrupt while doing so,	// because at interrupt level we might want to push a channel back to the	// end of the queue.	switch(type)	{	case PTYPE_INLINE:		pCh->Obuf_stuff = stuffIndex;  // Store buffer pointer		WRITE_UNLOCK_IRQRESTORE(&pCh->Obuf_spinlock,flags); 		pB->debugInlineQueued++;		// Add the channel pointer to list of channels needing service (first		// come...), if it's not already there.		i2QueueNeeds(pB, pCh, NEED_INLINE);		break;	case PTYPE_BYPASS:		pCh->Cbuf_stuff = stuffIndex;  // Store buffer pointer		WRITE_UNLOCK_IRQRESTORE(&pCh->Cbuf_spinlock,flags); 		pB->debugBypassQueued++;		// Add the channel pointer to list of channels needing service (first		// come...), if it's not already there.		i2QueueNeeds(pB, pCh, NEED_BYPASS);		break;	}	ip2trace (CHANN, ITRC_QUEUE, ITRC_RETURN, 1, nCommands );	return nCommands; // Good status: number of commands sent}