📄 i2lib.c
字号:
set_current_state( TASK_INTERRUPTIBLE ); serviceOutgoingFifo( pB ); schedule(); // Now we take our interruptible sleep on // Clean up the queue set_current_state( TASK_RUNNING ); remove_wait_queue(&(pCh->pBookmarkWait), &wait); // if expires == 0 then timer poped, then do not need to del_timer if ((timeout > 0) && pCh->BookmarkTimer.expires && time_before(jiffies, pCh->BookmarkTimer.expires)) { del_timer( &(pCh->BookmarkTimer) ); pCh->BookmarkTimer.expires = 0; ip2trace (CHANN, ITRC_DRAIN, 3, 1, pCh->BookmarkTimer.expires ); } ip2trace (CHANN, ITRC_DRAIN, ITRC_RETURN, 1, pCh->BookmarkTimer.expires ); return;}//******************************************************************************// Function: i2OutputFree(pCh)// Parameters: Pointer to a channel structure// Returns: Space in output buffer//// Description:// Returns -1 if very gross error. Otherwise returns the amount of bytes still// free in the output buffer.//******************************************************************************static inti2OutputFree(i2ChanStrPtr pCh){ int amountToMove; unsigned long flags; // Ensure channel structure seems real if ( !i2Validate ( pCh ) ) { return -1; } 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; } // If this is negative, we will discover later amountToMove -= sizeof(i2DataHeader); return (amountToMove < 0) ? 0 : amountToMove;}static voidip2_owake( PTTY tp){ i2ChanStrPtr pCh; if (tp == NULL) return; pCh = tp->driver_data; ip2trace (CHANN, ITRC_SICMD, 10, 2, tp->flags, (1 << TTY_DO_WRITE_WAKEUP) ); wake_up_interruptible ( &tp->write_wait ); if ( ( tp->flags & (1 << TTY_DO_WRITE_WAKEUP) ) && tp->ldisc.write_wakeup ) { (tp->ldisc.write_wakeup) ( tp ); ip2trace (CHANN, ITRC_SICMD, 11, 0 ); }}static inline voidset_baud_params(i2eBordStrPtr pB) { int i,j; i2ChanStrPtr *pCh; pCh = (i2ChanStrPtr *) pB->i2eChannelPtr; for (i = 0; i < ABS_MAX_BOXES; i++) { if (pB->channelBtypes.bid_value[i]) { if (BID_HAS_654(pB->channelBtypes.bid_value[i])) { for (j = 0; j < ABS_BIGGEST_BOX; j++) { if (pCh[i*16+j] == NULL) break; (pCh[i*16+j])->BaudBase = 921600; // MAX for ST654 (pCh[i*16+j])->BaudDivisor = 96; } } else { // has cirrus cd1400 for (j = 0; j < ABS_BIGGEST_BOX; j++) { if (pCh[i*16+j] == NULL) break; (pCh[i*16+j])->BaudBase = 115200; // MAX for CD1400 (pCh[i*16+j])->BaudDivisor = 12; } } } }}//******************************************************************************// Function: i2StripFifo(pB)// Parameters: Pointer to a board structure// Returns: ?//// Description:// Strips all the available data from the incoming FIFO, identifies the type of// packet, and either buffers the data or does what needs to be done.//// Note there is no overflow checking here: if the board sends more data than it// ought to, we will not detect it here, but blindly overflow...//******************************************************************************// A buffer for reading in blocks for unknown channelsstatic unsigned char junkBuffer[IBUF_SIZE];// A buffer to read in a status packet. Because of the size of the count field// for these things, the maximum packet size must be less than MAX_CMD_PACK_SIZEstatic unsigned char cmdBuffer[MAX_CMD_PACK_SIZE + 4];// This table changes the bit order from MSR order given by STAT_MODEM packet to// status bits used in our library.static char xlatDss[16] = {0 | 0 | 0 | 0 ,0 | 0 | 0 | I2_CTS ,0 | 0 | I2_DSR | 0 ,0 | 0 | I2_DSR | I2_CTS ,0 | I2_RI | 0 | 0 ,0 | I2_RI | 0 | I2_CTS ,0 | I2_RI | I2_DSR | 0 ,0 | I2_RI | I2_DSR | I2_CTS ,I2_DCD | 0 | 0 | 0 ,I2_DCD | 0 | 0 | I2_CTS ,I2_DCD | 0 | I2_DSR | 0 ,I2_DCD | 0 | I2_DSR | I2_CTS ,I2_DCD | I2_RI | 0 | 0 ,I2_DCD | I2_RI | 0 | I2_CTS ,I2_DCD | I2_RI | I2_DSR | 0 ,I2_DCD | I2_RI | I2_DSR | I2_CTS };static inline voidi2StripFifo(i2eBordStrPtr pB){ i2ChanStrPtr pCh; int channel; int count; unsigned short stuffIndex; int amountToRead; unsigned char *pc, *pcLimit; unsigned char uc; unsigned char dss_change; unsigned long bflags,cflags;// ip2trace (ITRC_NO_PORT, ITRC_SFIFO, ITRC_ENTER, 0 ); while (HAS_INPUT(pB)) {// ip2trace (ITRC_NO_PORT, ITRC_SFIFO, 2, 0 ); // Process packet from fifo a one atomic unit WRITE_LOCK_IRQSAVE(&pB->read_fifo_spinlock,bflags); // The first word (or two bytes) will have channel number and type of // packet, possibly other information pB->i2eLeadoffWord[0] = iiReadWord(pB); switch(PTYPE_OF(pB->i2eLeadoffWord)) { case PTYPE_DATA: pB->got_input = 1;// ip2trace (ITRC_NO_PORT, ITRC_SFIFO, 3, 0 ); channel = CHANNEL_OF(pB->i2eLeadoffWord); /* Store channel */ count = iiReadWord(pB); /* Count is in the next word */// NEW: Check the count for sanity! Should the hardware fail, our death// is more pleasant. While an oversize channel is acceptable (just more// than the driver supports), an over-length count clearly means we are// sick! if ( ((unsigned int)count) > IBUF_SIZE ) { pB->i2eFatal = 2; WRITE_UNLOCK_IRQRESTORE(&pB->read_fifo_spinlock,bflags); return; /* Bail out ASAP */ } // Channel is illegally big ? if ((channel >= pB->i2eChannelCnt) || (NULL==(pCh = ((i2ChanStrPtr*)pB->i2eChannelPtr)[channel]))) { iiReadBuf(pB, junkBuffer, count); WRITE_UNLOCK_IRQRESTORE(&pB->read_fifo_spinlock,bflags); break; /* From switch: ready for next packet */ } // Channel should be valid, then // If this is a hot-key, merely post its receipt for now. These are // always supposed to be 1-byte packets, so we won't even check the // count. Also we will post an acknowledgement to the board so that // more data can be forthcoming. Note that we are not trying to use // these sequences in this driver, merely to robustly ignore them. if(ID_OF(pB->i2eLeadoffWord) == ID_HOT_KEY) { pCh->hotKeyIn = iiReadWord(pB) & 0xff; WRITE_UNLOCK_IRQRESTORE(&pB->read_fifo_spinlock,bflags); i2QueueCommands(PTYPE_BYPASS, pCh, 0, 1, CMD_HOTACK); break; /* From the switch: ready for next packet */ } // Normal data! We crudely assume there is room for the data in our // buffer because the board wouldn't have exceeded his credit limit. WRITE_LOCK_IRQSAVE(&pCh->Ibuf_spinlock,cflags); // We have 2 locks now stuffIndex = pCh->Ibuf_stuff; amountToRead = IBUF_SIZE - stuffIndex; if (amountToRead > count) amountToRead = count; // stuffIndex would have been already adjusted so there would // always be room for at least one, and count is always at least // one. iiReadBuf(pB, &(pCh->Ibuf[stuffIndex]), amountToRead); pCh->icount.rx += amountToRead; // Update the stuffIndex by the amount of data moved. Note we could // never ask for more data than would just fit. However, we might // have read in one more byte than we wanted because the read // rounds up to even bytes. If this byte is on the end of the // packet, and is padding, we ignore it. If the byte is part of // the actual data, we need to move it. stuffIndex += amountToRead; if (stuffIndex >= IBUF_SIZE) { if ((amountToRead & 1) && (count > amountToRead)) { pCh->Ibuf[0] = pCh->Ibuf[IBUF_SIZE]; amountToRead++; stuffIndex = 1; } else { stuffIndex = 0; } } // If there is anything left over, read it as well if (count > amountToRead) { amountToRead = count - amountToRead; iiReadBuf(pB, &(pCh->Ibuf[stuffIndex]), amountToRead); pCh->icount.rx += amountToRead; stuffIndex += amountToRead; } // Update stuff index pCh->Ibuf_stuff = stuffIndex; WRITE_UNLOCK_IRQRESTORE(&pCh->Ibuf_spinlock,cflags); WRITE_UNLOCK_IRQRESTORE(&pB->read_fifo_spinlock,bflags);#ifdef USE_IQ schedule_work(&pCh->tqueue_input);#else do_input(pCh);#endif // Note we do not need to maintain any flow-control credits at this // time: if we were to increment .asof and decrement .room, there // would be no net effect. Instead, when we strip data, we will // increment .asof and leave .room unchanged. break; // From switch: ready for next packet case PTYPE_STATUS: ip2trace (ITRC_NO_PORT, ITRC_SFIFO, 4, 0 ); count = CMD_COUNT_OF(pB->i2eLeadoffWord); iiReadBuf(pB, cmdBuffer, count); // We can release early with buffer grab WRITE_UNLOCK_IRQRESTORE(&pB->read_fifo_spinlock,bflags); pc = cmdBuffer; pcLimit = &(cmdBuffer[count]); while (pc < pcLimit) { channel = *pc++; ip2trace (channel, ITRC_SFIFO, 7, 2, channel, *pc ); /* check for valid channel */ if (channel < pB->i2eChannelCnt && (pCh = (((i2ChanStrPtr*)pB->i2eChannelPtr)[channel])) != NULL ) { dss_change = 0; switch (uc = *pc++) { /* Breaks and modem signals are easy: just update status */ case STAT_CTS_UP: if ( !(pCh->dataSetIn & I2_CTS) ) { pCh->dataSetIn |= I2_DCTS; pCh->icount.cts++; dss_change = 1; } pCh->dataSetIn |= I2_CTS; break; case STAT_CTS_DN: if ( pCh->dataSetIn & I2_CTS ) { pCh->dataSetIn |= I2_DCTS; pCh->icount.cts++; dss_change = 1; } pCh->dataSetIn &= ~I2_CTS; break; case STAT_DCD_UP: ip2trace (channel, ITRC_MODEM, 1, 1, pCh->dataSetIn ); if ( !(pCh->dataSetIn & I2_DCD) ) { ip2trace (CHANN, ITRC_MODEM, 2, 0 ); pCh->dataSetIn |= I2_DDCD; pCh->icount.dcd++; dss_change = 1; } pCh->dataSetIn |= I2_DCD; ip2trace (channel, ITRC_MODEM, 3, 1, pCh->dataSetIn ); break; case STAT_DCD_DN: ip2trace (channel, ITRC_MODEM, 4, 1, pCh->dataSetIn ); if ( pCh->dataSetIn & I2_DCD ) { ip2trace (channel, ITRC_MODEM, 5, 0 ); pCh->dataSetIn |= I2_DDCD; pCh->icount.dcd++; dss_change = 1; } pCh->dataSetIn &= ~I2_DCD; ip2trace (channel, ITRC_MODEM, 6, 1, pCh->dataSetIn ); break; case STAT_DSR_UP: if ( !(pCh->dataSetIn & I2_DSR) ) { pCh->dataSetIn |= I2_DDSR; pCh->icount.dsr++; dss_change = 1; } pCh->dataSetIn |= I2_DSR; break; case STAT_DSR_DN: if ( pCh->dataSetIn & I2_DSR ) { pCh->dataSetIn |= I2_DDSR; pCh->icount.dsr++; dss_change = 1; } pCh->dataSetIn &= ~I2_DSR; break; case STAT_RI_UP: if ( !(pCh->dataSetIn & I2_RI) ) { pCh->dataSetIn |= I2_DRI; pCh->icount.rng++; dss_change = 1; } pCh->dataSetIn |= I2_RI ; break; case STAT_RI_DN: // to be compat with serial.c //if ( pCh->dataSetIn & I2_RI ) //{ // pCh->dataSetIn |= I2_DRI; // pCh->icount.rng++; // dss_change = 1; //} pCh->dataSetIn &= ~I2_RI ; break; case STAT_BRK_DET: pCh->dataSetIn |= I2_BRK; pCh->icount.brk++; dss_change = 1; break; // Bookmarks? one less request we're waiting for case STAT_BMARK: pCh->bookMarks--; if (pCh->bookMarks <= 0 ) { pCh->bookMarks = 0; wake_up_interruptible( &pCh->pBookmarkWait ); ip2trace (channel, ITRC_DRAIN, 20, 1, pCh->BookmarkTimer.expires ); } break; // Flow control packets? Update the new credits, and if // someone was waiting for output, queue him up again. case STAT_FLOW: pCh->outfl.room = ((flowStatPtr)pc)->room - (pCh->outfl.asof - ((flowStatPtr)pc)->asof); ip2trace (channel, ITRC_STFLW, 1, 1, pCh->outfl.room ); if (pCh->channelNeeds & NEED_CREDIT) { ip2trace (channel, ITRC_STFLW, 2, 1, pCh->channelNeeds); pCh->channelNeeds &= ~NEED_CREDIT; i2QueueNeeds(pB, pCh, NEED_INLINE); if ( pCh->pTTY ) ip2_owake(pCh->pTTY); } ip2trace (channel, ITRC_STFLW, 3, 1, pCh->channelNeeds); pc += sizeof(flowStat); break; /* Special packets: */ /* Just copy the information into the channel structure */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -