current->state = TASK_INTERRUPTIBLE; schedule_timeout(2);
schedule_timeout_interruptible(2);
i2Output(i2ChanStrPtr pCh, const char *pSource, int count, int user ){	i2eBordStrPtr pB;	unsigned char *pInsert;	int amountToMove;	int countOriginal = count;	unsigned short channel;	unsigned short stuffIndex;	unsigned long flags;	int rc = 0;	int bailout = 10;	ip2trace (CHANN, ITRC_OUTPUT, ITRC_ENTER, 2, count, user );	// Ensure channel structure seems real	if ( !i2Validate ( pCh ) ) 		return -1;	// initialize some accelerators and private copies	pB = pCh->pMyBord;	channel = pCh->infl.hd.i2sChannel;	// 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 -1;	}	// Proceed as though we would do everything	while ( count > 0 ) {		// How much room in output buffer is there?		READ_LOCK_IRQSAVE(&pCh->Obuf_spinlock,flags);		amountToMove = pCh->Obuf_strip - pCh->Obuf_stuff - 1;		READ_UNLOCK_IRQRESTORE(&pCh->Obuf_spinlock,flags);		if (amountToMove < 0) {			amountToMove += OBUF_SIZE;		}		// Subtract off the headers size and see how much room there is for real		// data. If this is negative, we will discover later.		amountToMove -= sizeof (i2DataHeader);		// Don't move more (now) than can go in a single packet		if ( amountToMove > (int)(MAX_OBUF_BLOCK - sizeof(i2DataHeader)) ) {			amountToMove = MAX_OBUF_BLOCK - sizeof(i2DataHeader);		}		// Don't move more than the count we were given		if (amountToMove > count) {			amountToMove = count;		}		// Now we know how much we must move: NB because the ring buffers have		// an overflow area at the end, we needn't worry about wrapping in the		// middle of a packet.// Small WINDOW here with no LOCK but I can't call Flush with LOCK// We would be flushing (or ending flush) anyway		ip2trace (CHANN, ITRC_OUTPUT, 10, 1, amountToMove );		if ( !(pCh->flush_flags && i2RetryFlushOutput(pCh) ) 				&& amountToMove > 0 )		{			WRITE_LOCK_IRQSAVE(&pCh->Obuf_spinlock,flags);			stuffIndex = pCh->Obuf_stuff;      			// Had room to move some data: don't know whether the block size,			// buffer space, or what was the limiting factor...			pInsert = &(pCh->Obuf[stuffIndex]);			// Set up the header			CHANNEL_OF(pInsert)     = channel;			PTYPE_OF(pInsert)       = PTYPE_DATA;			TAG_OF(pInsert)         = 0;			ID_OF(pInsert)          = ID_ORDINARY_DATA;			DATA_COUNT_OF(pInsert)  = amountToMove;			// Move the data			if ( user ) {				rc = copy_from_user((char*)(DATA_OF(pInsert)), pSource,						amountToMove );			} else {				memcpy( (char*)(DATA_OF(pInsert)), pSource, amountToMove );			}			// Adjust pointers and indices			pSource					+= amountToMove;			pCh->Obuf_char_count	+= amountToMove;			stuffIndex 				+= amountToMove + sizeof(i2DataHeader);			count 					-= amountToMove;			if (stuffIndex >= OBUF_SIZE) {				stuffIndex = 0;			}			pCh->Obuf_stuff = stuffIndex;			WRITE_UNLOCK_IRQRESTORE(&pCh->Obuf_spinlock,flags);			ip2trace (CHANN, ITRC_OUTPUT, 13, 1, stuffIndex );		} else {			// Cannot move data			// becuz we need to stuff a flush 			// or amount to move is <= 0			ip2trace(CHANN, ITRC_OUTPUT, 14, 3,				amountToMove,  pB->i2eFifoRemains,				pB->i2eWaitingForEmptyFifo );			// Put this channel back on queue			// this ultimatly gets more data or wakes write output			i2QueueNeeds(pB, pCh, NEED_INLINE);			if ( pB->i2eWaitingForEmptyFifo ) {				ip2trace (CHANN, ITRC_OUTPUT, 16, 0 );				// or schedule				if (!in_interrupt()) {					ip2trace (CHANN, ITRC_OUTPUT, 61, 0 );					current->state = TASK_INTERRUPTIBLE;					schedule_timeout(2);					if (signal_pending(current)) {						break;					}					continue;				} else {					ip2trace (CHANN, ITRC_OUTPUT, 62, 0 );					// let interrupt in = WAS restore_flags()					// We hold no lock nor is irq off anymore???										break;				}				break;   // from while(count)			}			else if ( pB->i2eFifoRemains < 32 && !pB->i2eTxMailEmpty ( pB ) )			{				ip2trace (CHANN, ITRC_OUTPUT, 19, 2,					pB->i2eFifoRemains,					pB->i2eTxMailEmpty );				break;   // from while(count)			} else if ( pCh->channelNeeds & NEED_CREDIT ) {				ip2trace (CHANN, ITRC_OUTPUT, 22, 0 );				break;   // from while(count)			} else if ( --bailout) {				// Try to throw more things (maybe not us) in the fifo if we're				// not already waiting for it.					ip2trace (CHANN, ITRC_OUTPUT, 20, 0 );				serviceOutgoingFifo(pB);				//break;  CONTINUE;			} else {				ip2trace (CHANN, ITRC_OUTPUT, 21, 3,					pB->i2eFifoRemains,					pB->i2eOutMailWaiting,					pB->i2eWaitingForEmptyFifo );				break;   // from while(count)			}		}	} // End of while(count)	i2QueueNeeds(pB, pCh, NEED_INLINE);	// We drop through either when the count expires, or when there is some	// count left, but there was a non-blocking write.	if (countOriginal > count) {		ip2trace (CHANN, ITRC_OUTPUT, 17, 2, countOriginal, count );		serviceOutgoingFifo( pB );	}	ip2trace (CHANN, ITRC_OUTPUT, ITRC_RETURN, 2, countOriginal, count );	return countOriginal - count;}