📄 i2lib.c
字号:
case STAT_STATUS: pCh->channelStatus = *((debugStatPtr)pc); pc += sizeof(debugStat); break; case STAT_TXCNT: pCh->channelTcount = *((cntStatPtr)pc); pc += sizeof(cntStat); break; case STAT_RXCNT: pCh->channelRcount = *((cntStatPtr)pc); pc += sizeof(cntStat); break; case STAT_BOXIDS: pB->channelBtypes = *((bidStatPtr)pc); pc += sizeof(bidStat); set_baud_params(pB); break; case STAT_HWFAIL: i2QueueCommands (PTYPE_INLINE, pCh, 0, 1, CMD_HW_TEST); pCh->channelFail = *((failStatPtr)pc); pc += sizeof(failStat); break; /* No explicit match? then * Might be an error packet... */ default: switch (uc & STAT_MOD_ERROR) { case STAT_ERROR: if (uc & STAT_E_PARITY) { pCh->dataSetIn |= I2_PAR; pCh->icount.parity++; } if (uc & STAT_E_FRAMING){ pCh->dataSetIn |= I2_FRA; pCh->icount.frame++; } if (uc & STAT_E_OVERRUN){ pCh->dataSetIn |= I2_OVR; pCh->icount.overrun++; } break; case STAT_MODEM: // the answer to DSS_NOW request (not change) pCh->dataSetIn = (pCh->dataSetIn & ~(I2_RI | I2_CTS | I2_DCD | I2_DSR) ) | xlatDss[uc & 0xf]; wake_up_interruptible ( &pCh->dss_now_wait ); default: break; } } /* End of switch on status type */ if (dss_change) {#ifdef USE_IQ schedule_work(&pCh->tqueue_status);#else do_status(pCh);#endif } } else /* Or else, channel is invalid */ { // Even though the channel is invalid, we must test the // status to see how much additional data it has (to be // skipped) switch (*pc++) { case STAT_FLOW: pc += 4; /* Skip the data */ break; default: break; } } } // End of while (there is still some status packet left) break; default: // Neither packet? should be impossible ip2trace (ITRC_NO_PORT, ITRC_SFIFO, 5, 1, PTYPE_OF(pB->i2eLeadoffWord) ); break; } // End of switch on type of packets } //while(board HAS_INPUT) ip2trace (ITRC_NO_PORT, ITRC_SFIFO, ITRC_RETURN, 0 ); // Send acknowledgement to the board even if there was no data! pB->i2eOutMailWaiting |= MB_IN_STRIPPED; return;}//******************************************************************************// Function: i2Write2Fifo(pB,address,count)// Parameters: Pointer to a board structure, source address, byte count// Returns: bytes written//// Description:// Writes count bytes to board io address(implied) from source// Adjusts count, leaves reserve for next time around bypass cmds//******************************************************************************static inti2Write2Fifo(i2eBordStrPtr pB, unsigned char *source, int count,int reserve){ int rc = 0; unsigned long flags; WRITE_LOCK_IRQSAVE(&pB->write_fifo_spinlock,flags); if (!pB->i2eWaitingForEmptyFifo) { if (pB->i2eFifoRemains > (count+reserve)) { pB->i2eFifoRemains -= count; iiWriteBuf(pB, source, count); pB->i2eOutMailWaiting |= MB_OUT_STUFFED; rc = count; } } WRITE_UNLOCK_IRQRESTORE(&pB->write_fifo_spinlock,flags); return rc;}//******************************************************************************// Function: i2StuffFifoBypass(pB)// Parameters: Pointer to a board structure// Returns: Nothing//// Description:// Stuffs as many bypass commands into the fifo as possible. This is simpler// than stuffing data or inline commands to fifo, since we do not have// flow-control to deal with.//******************************************************************************static inline voidi2StuffFifoBypass(i2eBordStrPtr pB){ i2ChanStrPtr pCh; unsigned char *pRemove; unsigned short stripIndex; unsigned short packetSize; unsigned short paddedSize; unsigned short notClogged = 1; unsigned long flags; int bailout = 1000; // Continue processing so long as there are entries, or there is room in the // fifo. Each entry represents a channel with something to do. while ( --bailout && notClogged && (NULL != (pCh = i2DeQueueNeeds(pB,NEED_BYPASS)))) { WRITE_LOCK_IRQSAVE(&pCh->Cbuf_spinlock,flags); stripIndex = pCh->Cbuf_strip; // as long as there are packets for this channel... while (stripIndex != pCh->Cbuf_stuff) { pRemove = &(pCh->Cbuf[stripIndex]); packetSize = CMD_COUNT_OF(pRemove) + sizeof(i2CmdHeader); paddedSize = ROUNDUP(packetSize); if (paddedSize > 0) { if ( 0 == i2Write2Fifo(pB, pRemove, paddedSize,0)) { notClogged = 0; /* fifo full */ i2QueueNeeds(pB, pCh, NEED_BYPASS); // Put back on queue break; // Break from the channel } }#ifdef DEBUG_FIFOWriteDBGBuf("BYPS", pRemove, paddedSize);#endif /* DEBUG_FIFO */ pB->debugBypassCount++; pRemove += packetSize; stripIndex += packetSize; if (stripIndex >= CBUF_SIZE) { stripIndex = 0; pRemove = pCh->Cbuf; } } // Done with this channel. Move to next, removing this one from // the queue of channels if we cleaned it out (i.e., didn't get clogged. pCh->Cbuf_strip = stripIndex; WRITE_UNLOCK_IRQRESTORE(&pCh->Cbuf_spinlock,flags); } // Either clogged or finished all the work#ifdef IP2DEBUG_TRACE if ( !bailout ) { ip2trace (ITRC_NO_PORT, ITRC_ERROR, 1, 0 ); }#endif}//******************************************************************************// Function: i2StuffFifoFlow(pB)// Parameters: Pointer to a board structure// Returns: Nothing//// Description:// Stuffs as many flow control packets into the fifo as possible. This is easier// even than doing normal bypass commands, because there is always at most one// packet, already assembled, for each channel.//******************************************************************************static inline voidi2StuffFifoFlow(i2eBordStrPtr pB){ i2ChanStrPtr pCh; unsigned short paddedSize = ROUNDUP(sizeof(flowIn)); ip2trace (ITRC_NO_PORT, ITRC_SFLOW, ITRC_ENTER, 2, pB->i2eFifoRemains, paddedSize ); // Continue processing so long as there are entries, or there is room in the // fifo. Each entry represents a channel with something to do. while ( (NULL != (pCh = i2DeQueueNeeds(pB,NEED_FLOW)))) { pB->debugFlowCount++; // NO Chan LOCK needed ??? if ( 0 == i2Write2Fifo(pB,(unsigned char *)&(pCh->infl),paddedSize,0)) { break; }#ifdef DEBUG_FIFO WriteDBGBuf("FLOW",(unsigned char *) &(pCh->infl), paddedSize);#endif /* DEBUG_FIFO */ } // Either clogged or finished all the work ip2trace (ITRC_NO_PORT, ITRC_SFLOW, ITRC_RETURN, 0 );}//******************************************************************************// Function: i2StuffFifoInline(pB)// Parameters: Pointer to a board structure// Returns: Nothing//// Description:// Stuffs as much data and inline commands into the fifo as possible. This is// the most complex fifo-stuffing operation, since there if now the channel// flow-control issue to deal with.//******************************************************************************static inline voidi2StuffFifoInline(i2eBordStrPtr pB){ i2ChanStrPtr pCh; unsigned char *pRemove; unsigned short stripIndex; unsigned short packetSize; unsigned short paddedSize; unsigned short notClogged = 1; unsigned short flowsize; unsigned long flags; int bailout = 1000; int bailout2; ip2trace (ITRC_NO_PORT, ITRC_SICMD, ITRC_ENTER, 3, pB->i2eFifoRemains, pB->i2Dbuf_strip, pB->i2Dbuf_stuff ); // Continue processing so long as there are entries, or there is room in the // fifo. Each entry represents a channel with something to do. while ( --bailout && notClogged && (NULL != (pCh = i2DeQueueNeeds(pB,NEED_INLINE))) ) { WRITE_LOCK_IRQSAVE(&pCh->Obuf_spinlock,flags); stripIndex = pCh->Obuf_strip; ip2trace (CHANN, ITRC_SICMD, 3, 2, stripIndex, pCh->Obuf_stuff ); // as long as there are packets for this channel... bailout2 = 1000; while ( --bailout2 && stripIndex != pCh->Obuf_stuff) { pRemove = &(pCh->Obuf[stripIndex]); // Must determine whether this be a data or command packet to // calculate correctly the header size and the amount of // flow-control credit this type of packet will use. if (PTYPE_OF(pRemove) == PTYPE_DATA) { flowsize = DATA_COUNT_OF(pRemove); packetSize = flowsize + sizeof(i2DataHeader); } else { flowsize = CMD_COUNT_OF(pRemove); packetSize = flowsize + sizeof(i2CmdHeader); } flowsize = CREDIT_USAGE(flowsize); paddedSize = ROUNDUP(packetSize); ip2trace (CHANN, ITRC_SICMD, 4, 2, pB->i2eFifoRemains, paddedSize ); // If we don't have enough credits from the board to send the data, // flag the channel that we are waiting for flow control credit, and // break out. This will clean up this channel and remove us from the // queue of hot things to do. ip2trace (CHANN, ITRC_SICMD, 5, 2, pCh->outfl.room, flowsize ); if (pCh->outfl.room <= flowsize) { // Do Not have the credits to send this packet. i2QueueNeeds(pB, pCh, NEED_CREDIT); notClogged = 0; break; // So to do next channel } if ( (paddedSize > 0) && ( 0 == i2Write2Fifo(pB, pRemove, paddedSize, 128))) { // Do Not have room in fifo to send this packet. notClogged = 0; i2QueueNeeds(pB, pCh, NEED_INLINE); break; // Break from the channel }#ifdef DEBUG_FIFOWriteDBGBuf("DATA", pRemove, paddedSize);#endif /* DEBUG_FIFO */ pB->debugInlineCount++; pCh->icount.tx += flowsize; // Update current credits pCh->outfl.room -= flowsize; pCh->outfl.asof += flowsize; if (PTYPE_OF(pRemove) == PTYPE_DATA) { pCh->Obuf_char_count -= DATA_COUNT_OF(pRemove); } pRemove += packetSize; stripIndex += packetSize; ip2trace (CHANN, ITRC_SICMD, 6, 2, stripIndex, pCh->Obuf_strip); if (stripIndex >= OBUF_SIZE) { stripIndex = 0; pRemove = pCh->Obuf; ip2trace (CHANN, ITRC_SICMD, 7, 1, stripIndex ); } } /* while */ if ( !bailout2 ) { ip2trace (CHANN, ITRC_ERROR, 3, 0 ); } // Done with this channel. Move to next, removing this one from the // queue of channels if we cleaned it out (i.e., didn't get clogged. pCh->Obuf_strip = stripIndex; WRITE_UNLOCK_IRQRESTORE(&pCh->Obuf_spinlock,flags); if ( notClogged ) { ip2trace (CHANN, ITRC_SICMD, 8, 0 ); if ( pCh->pTTY ) { ip2_owake(pCh->pTTY); } } } // Either clogged or finished all the work if ( !bailout ) { ip2trace (ITRC_NO_PORT, ITRC_ERROR, 4, 0 ); } ip2trace (ITRC_NO_PORT, ITRC_SICMD, ITRC_RETURN, 1,pB->i2Dbuf_strip);}//******************************************************************************// Function: serviceOutgoingFifo(pB)// Parameters: Pointer to a board structure// Returns: Nothing//// Description:// Helper routine to put data in the outgoing fifo, if we aren't already waiting// for something to be there. If the fifo has only room for a very little data,// go head and hit the board with a mailbox hit immediately. Otherwise, it will// have to happen later in the interrupt processing. Since this routine may be// called both at interrupt and foreground time, we must turn off interrupts// during the entire process.//******************************************************************************static voidserviceOutgoingFifo(i2eBordStrPtr pB){ // If we aren't currently waiting for the board to empty our fifo, service // everything that is pending, in priority order (especially, Bypass before // Inline). if ( ! pB->i2eWaitingForEmptyFifo ) { i2StuffFifoFlow(pB); i2StuffFifoBypass(pB); i2StuffFifoInline(pB); iiSendPendingMail(pB); } }//******************************************************************************// Function: i2ServiceBoard(pB)// Parameters: Pointer to a board structure// Returns: Nothing//// Description:// Normally this is called from interrupt level, but there is deliberately// nothing in here specific to being called from interrupt level. All the// hardware-specific, interrupt-specific things happen at the outer levels.//// For example, a timer interrupt could drive this routine for some sort of// polled operation. The only requirement is that the programmer deal with any// atomiticity/concurrency issues that result.//// This routine responds to the board's having sent mailbox information to the// host (which would normally cause an interrupt). This routine reads the// incoming mailbox. If there is no data in it, this board did not create the// interrupt and/or has nothing to be done to it. (Except, if we have been// waiting to write mailbox data to it, we may do so.//// Based on the value in the mailbox, we may take various actions.//// No checking here of pB validity: after all, it shouldn't have been called by// the handler unless pB were on the list.//******************************************************************************static inline inti2ServiceBoard ( i2eBordStrPtr pB ){ unsigned inmail; unsigned long flags; /* This should be atomic because of the way we are called... */ if (NO_MAIL_HERE == ( inmail = pB->i2eStartMail ) ) { inmail = iiGetMail(pB); } pB->i2eStartMail = NO_MAIL_HERE; ip2trace (ITRC_NO_PORT, ITRC_INTR, 2, 1, inmail ); if (inmail != NO_MAIL_HERE) { // If the board has gone fatal, nothing to do but hit a bit that will // aler
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -