📄 i2lib.c
字号:
static voidi2QueueNeeds(i2eBordStrPtr pB, i2ChanStrPtr pCh, int type){ unsigned short queueIndex; unsigned long flags; // We turn off all the interrupts during this brief process, since the // interrupt-level code might want to put things on the queue as well. switch (type) { case NEED_INLINE: WRITE_LOCK_IRQSAVE(&pB->Dbuf_spinlock,flags); if ( !(pCh->channelNeeds & NEED_INLINE) ) { pCh->channelNeeds |= NEED_INLINE; queueIndex = pB->i2Dbuf_stuff; pB->i2Dbuf[queueIndex++] = pCh; if (queueIndex >= CH_QUEUE_SIZE) queueIndex = 0; pB->i2Dbuf_stuff = queueIndex; } WRITE_UNLOCK_IRQRESTORE(&pB->Dbuf_spinlock,flags); break; case NEED_BYPASS: WRITE_LOCK_IRQSAVE(&pB->Bbuf_spinlock,flags); if ((type & NEED_BYPASS) && !(pCh->channelNeeds & NEED_BYPASS)) { pCh->channelNeeds |= NEED_BYPASS; queueIndex = pB->i2Bbuf_stuff; pB->i2Bbuf[queueIndex++] = pCh; if (queueIndex >= CH_QUEUE_SIZE) queueIndex = 0; pB->i2Bbuf_stuff = queueIndex; } WRITE_UNLOCK_IRQRESTORE(&pB->Bbuf_spinlock,flags); break; case NEED_FLOW: WRITE_LOCK_IRQSAVE(&pB->Fbuf_spinlock,flags); if ((type & NEED_FLOW) && !(pCh->channelNeeds & NEED_FLOW)) { pCh->channelNeeds |= NEED_FLOW; queueIndex = pB->i2Fbuf_stuff; pB->i2Fbuf[queueIndex++] = pCh; if (queueIndex >= CH_QUEUE_SIZE) queueIndex = 0; pB->i2Fbuf_stuff = queueIndex; } WRITE_UNLOCK_IRQRESTORE(&pB->Fbuf_spinlock,flags); break; case NEED_CREDIT: pCh->channelNeeds |= NEED_CREDIT; break; default: printk(KERN_ERR "i2QueueNeeds called with bad type:%x\n",type); break; } return;}//******************************************************************************// Function: i2QueueCommands(type, pCh, timeout, nCommands, pCs,...)// Parameters: type - PTYPE_BYPASS or PTYPE_INLINE// pointer to the channel structure// maximum period to wait// number of commands (n)// n commands// Returns: Number of commands sent, or -1 for error//// get board lock before calling//// Description:// Queues up some commands to be sent to a channel. To send possibly several// bypass or inline commands to the given channel. The timeout parameter// indicates how many HUNDREDTHS OF SECONDS to wait until there is room:// 0 = return immediately if no room, -ive = wait forever, +ive = number of// 1/100 seconds to wait. Return values:// -1 Some kind of nasty error: bad channel structure or invalid arguments.// 0 No room to send all the commands// (+) Number of commands sent//******************************************************************************static inti2QueueCommands(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()) { schedule_timeout_interruptible(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}//******************************************************************************// Function: i2GetStatus(pCh,resetBits)// Parameters: Pointer to a channel structure// Bit map of status bits to clear// Returns: Bit map of current status bits//// Description:// Returns the state of data set signals, and whether a break has been received,// (see i2lib.h for bit-mapped result). resetBits is a bit-map of any status// bits to be cleared: I2_BRK, I2_PAR, I2_FRA, I2_OVR,... These are cleared// AFTER the condition is passed. If pCh does not point to a valid channel,// returns -1 (which would be impossible otherwise.//******************************************************************************static inti2GetStatus(i2ChanStrPtr pCh, int resetBits){ unsigned short status; i2eBordStrPtr pB; ip2trace (CHANN, ITRC_STATUS, ITRC_ENTER, 2, pCh->dataSetIn, resetBits ); // Make sure the channel exists, otherwise do nothing */ if ( !i2Validate ( pCh ) ) return -1; pB = pCh->pMyBord; status = pCh->dataSetIn; // Clear any specified error bits: but note that only actual error bits can // be cleared, regardless of the value passed. if (resetBits) { pCh->dataSetIn &= ~(resetBits & (I2_BRK | I2_PAR | I2_FRA | I2_OVR)); pCh->dataSetIn &= ~(I2_DDCD | I2_DCTS | I2_DDSR | I2_DRI); } ip2trace (CHANN, ITRC_STATUS, ITRC_RETURN, 1, pCh->dataSetIn ); return status;}//******************************************************************************// Function: i2Input(pChpDest,count)// Parameters: Pointer to a channel structure// Pointer to data buffer// Number of bytes to read// Returns: Number of bytes read, or -1 for error//// Description:// Strips data from the input buffer and writes it to pDest. If there is a// collosal blunder, (invalid structure pointers or the like), returns -1.// Otherwise, returns the number of bytes read.//******************************************************************************static inti2Input(i2ChanStrPtr pCh){ int amountToMove; unsigned short stripIndex; int count; unsigned long flags = 0; ip2trace (CHANN, ITRC_INPUT, ITRC_ENTER, 0); // Ensure channel structure seems real if ( !i2Validate( pCh ) ) { count = -1; goto i2Input_exit; } WRITE_LOCK_IRQSAVE(&pCh->Ibuf_spinlock,flags); // initialize some accelerators and private copies stripIndex = pCh->Ibuf_strip; count = pCh->Ibuf_stuff - stripIndex; // If buffer is empty or requested data count was 0, (trivial case) return // without any further thought. if ( count == 0 ) { WRITE_UNLOCK_IRQRESTORE(&pCh->Ibuf_spinlock,flags); goto i2Input_exit; } // Adjust for buffer wrap if ( count < 0 ) { count += IBUF_SIZE; } // Don't give more than can be taken by the line discipline amountToMove = pCh->pTTY->ldisc.receive_room( pCh->pTTY ); if (count > amountToMove) { count = amountToMove; } // How much could we copy without a wrap? amountToMove = IBUF_SIZE - stripIndex; if (amountToMove > count) { amountToMove = count; } // Move the first block pCh->pTTY->ldisc.receive_buf( pCh->pTTY, &(pCh->Ibuf[stripIndex]), NULL, amountToMove ); // If we needed to wrap, do the second data move if (count > amountToMove) { pCh->pTTY->ldisc.receive_buf( pCh->pTTY, pCh->Ibuf, NULL, count - amountToMove ); } // Bump and wrap the stripIndex all at once by the amount of data read. This // method is good regardless of whether the data was in one or two pieces.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -