📄 i2lib.c
字号:
stripIndex += count; if (stripIndex >= IBUF_SIZE) { stripIndex -= IBUF_SIZE; } pCh->Ibuf_strip = stripIndex; // Update our flow control information and possibly queue ourselves to send // it, depending on how much data has been stripped since the last time a // packet was sent. pCh->infl.asof += count; if ((pCh->sinceLastFlow += count) >= pCh->whenSendFlow) { pCh->sinceLastFlow -= pCh->whenSendFlow; WRITE_UNLOCK_IRQRESTORE(&pCh->Ibuf_spinlock,flags); i2QueueNeeds(pCh->pMyBord, pCh, NEED_FLOW); } else { WRITE_UNLOCK_IRQRESTORE(&pCh->Ibuf_spinlock,flags); }i2Input_exit: ip2trace (CHANN, ITRC_INPUT, ITRC_RETURN, 1, count); return count;}//******************************************************************************// Function: i2InputFlush(pCh)// Parameters: Pointer to a channel structure// Returns: Number of bytes stripped, or -1 for error//// Description:// Strips any data from the input buffer. If there is a collosal blunder,// (invalid structure pointers or the like), returns -1. Otherwise, returns the// number of bytes stripped.//******************************************************************************static inti2InputFlush(i2ChanStrPtr pCh){ int count; unsigned long flags; // Ensure channel structure seems real if ( !i2Validate ( pCh ) ) return -1; ip2trace (CHANN, ITRC_INPUT, 10, 0); WRITE_LOCK_IRQSAVE(&pCh->Ibuf_spinlock,flags); count = pCh->Ibuf_stuff - pCh->Ibuf_strip; // Adjust for buffer wrap if (count < 0) { count += IBUF_SIZE; } // Expedient way to zero out the buffer pCh->Ibuf_strip = pCh->Ibuf_stuff; // Update our flow control information and possibly queue ourselves to send // it, depending on how much data has been stripped since the last time a // packet was sent. pCh->infl.asof += count; if ( (pCh->sinceLastFlow += count) >= pCh->whenSendFlow ) { pCh->sinceLastFlow -= pCh->whenSendFlow; WRITE_UNLOCK_IRQRESTORE(&pCh->Ibuf_spinlock,flags); i2QueueNeeds(pCh->pMyBord, pCh, NEED_FLOW); } else { WRITE_UNLOCK_IRQRESTORE(&pCh->Ibuf_spinlock,flags); } ip2trace (CHANN, ITRC_INPUT, 19, 1, count); return count;}//******************************************************************************// Function: i2InputAvailable(pCh)// Parameters: Pointer to a channel structure// Returns: Number of bytes available, or -1 for error//// Description:// If there is a collosal blunder, (invalid structure pointers or the like),// returns -1. Otherwise, returns the number of bytes stripped. Otherwise,// returns the number of bytes available in the buffer.//******************************************************************************#if 0static inti2InputAvailable(i2ChanStrPtr pCh){ int count; // Ensure channel structure seems real if ( !i2Validate ( pCh ) ) return -1; // initialize some accelerators and private copies READ_LOCK_IRQSAVE(&pCh->Ibuf_spinlock,flags); count = pCh->Ibuf_stuff - pCh->Ibuf_strip; READ_UNLOCK_IRQRESTORE(&pCh->Ibuf_spinlock,flags); // Adjust for buffer wrap if (count < 0) { count += IBUF_SIZE; } return count;}#endif //******************************************************************************// Function: i2Output(pCh, pSource, count)// Parameters: Pointer to channel structure// Pointer to source data// Number of bytes to send// Returns: Number of bytes sent, or -1 for error//// Description:// Queues the data at pSource to be sent as data packets to the board. If there// is a collosal blunder, (invalid structure pointers or the like), returns -1.// Otherwise, returns the number of bytes written. What if there is not enough// room for all the data? If pCh->channelOptions & CO_NBLOCK_WRITE is set, then// we transfer as many characters as we can now, then return. If this bit is// clear (default), routine will spin along until all the data is buffered.// Should this occur, the 1-ms delay routine is called while waiting to avoid// applications that one cannot break out of.//******************************************************************************static inti2Output(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 ); schedule_timeout_interruptible(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;}//******************************************************************************// Function: i2FlushOutput(pCh)// Parameters: Pointer to a channel structure// Returns: Nothing//// Description:// Sends bypass command to start flushing (waiting possibly forever until there// is room), then sends inline command to stop flushing output, (again waiting// possibly forever).//******************************************************************************static inline voidi2FlushOutput(i2ChanStrPtr pCh){ ip2trace (CHANN, ITRC_FLUSH, 1, 1, pCh->flush_flags ); if (pCh->flush_flags) return; if ( 1 != i2QueueCommands(PTYPE_BYPASS, pCh, 0, 1, CMD_STARTFL) ) { pCh->flush_flags = STARTFL_FLAG; // Failed - flag for later ip2trace (CHANN, ITRC_FLUSH, 2, 0 ); } else if ( 1 != i2QueueCommands(PTYPE_INLINE, pCh, 0, 1, CMD_STOPFL) ) { pCh->flush_flags = STOPFL_FLAG; // Failed - flag for later ip2trace (CHANN, ITRC_FLUSH, 3, 0 ); }}static int i2RetryFlushOutput(i2ChanStrPtr pCh){ int old_flags = pCh->flush_flags; ip2trace (CHANN, ITRC_FLUSH, 14, 1, old_flags ); pCh->flush_flags = 0; // Clear flag so we can avoid recursion // and queue the commands if ( old_flags & STARTFL_FLAG ) { if ( 1 == i2QueueCommands(PTYPE_BYPASS, pCh, 0, 1, CMD_STARTFL) ) { old_flags = STOPFL_FLAG; //Success - send stop flush } else { old_flags = STARTFL_FLAG; //Failure - Flag for retry later } ip2trace (CHANN, ITRC_FLUSH, 15, 1, old_flags ); } if ( old_flags & STOPFL_FLAG ) { if (1 == i2QueueCommands(PTYPE_INLINE, pCh, 0, 1, CMD_STOPFL)) { old_flags = 0; // Success - clear flags } ip2trace (CHANN, ITRC_FLUSH, 16, 1, old_flags ); } pCh->flush_flags = old_flags; ip2trace (CHANN, ITRC_FLUSH, 17, 1, old_flags ); return old_flags;}//******************************************************************************// Function: i2DrainOutput(pCh,timeout)// Parameters: Pointer to a channel structure// Maximum period to wait// Returns: ?//// Description:// Uses the bookmark request command to ask the board to send a bookmark back as// soon as all the data is completely sent.//******************************************************************************static voidi2DrainWakeup(i2ChanStrPtr pCh){ ip2trace (CHANN, ITRC_DRAIN, 10, 1, pCh->BookmarkTimer.expires ); pCh->BookmarkTimer.expires = 0; wake_up_interruptible( &pCh->pBookmarkWait );}static voidi2DrainOutput(i2ChanStrPtr pCh, int timeout){ wait_queue_t wait; i2eBordStrPtr pB; ip2trace (CHANN, ITRC_DRAIN, ITRC_ENTER, 1, pCh->BookmarkTimer.expires); pB = pCh->pMyBord; // 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; } if ((timeout > 0) && (pCh->BookmarkTimer.expires == 0 )) { // One per customer (channel) init_timer( &(pCh->BookmarkTimer) ); pCh->BookmarkTimer.expires = jiffies + timeout; pCh->BookmarkTimer.function = (void*)(unsigned long)i2DrainWakeup; pCh->BookmarkTimer.data = (unsigned long)pCh; ip2trace (CHANN, ITRC_DRAIN, 1, 1, pCh->BookmarkTimer.expires ); add_timer( &(pCh->BookmarkTimer) ); } i2QueueCommands( PTYPE_INLINE, pCh, -1, 1, CMD_BMARK_REQ ); init_waitqueue_entry(&wait, current); add_wait_queue(&(pCh->pBookmarkWait), &wait);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -