⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 i2lib.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 5 页
字号:
/*********************************************************************************   (c) 1999 by Computone Corporation************************************************************************************   PACKAGE:     Linux tty Device Driver for IntelliPort family of multiport*                serial I/O controllers.**   DESCRIPTION: High-level interface code for the device driver. Uses the*                Extremely Low Level Interface Support (i2ellis.c). Provides an*                interface to the standard loadware, to support drivers or*                application code. (This is included source code, not a separate*                compilation module.)********************************************************************************///------------------------------------------------------------------------------// Note on Strategy:// Once the board has been initialized, it will interrupt us when:// 1) It has something in the fifo for us to read (incoming data, flow control// packets, or whatever).// 2) It has stripped whatever we have sent last time in the FIFO (and// consequently is ready for more).//// Note also that the buffer sizes declared in i2lib.h are VERY SMALL. This// worsens performance considerably, but is done so that a great many channels// might use only a little memory.//------------------------------------------------------------------------------//------------------------------------------------------------------------------// Revision History://// 0.00 -  4/16/91 --- First Draft// 0.01 -  4/29/91 --- 1st beta release// 0.02 -  6/14/91 --- Changes to allow small model compilation// 0.03 -  6/17/91 MAG Break reporting protected from interrupts routines with//                     in-line asm added for moving data to/from ring buffers,//                     replacing a variety of methods used previously.// 0.04 -  6/21/91 MAG Initial flow-control packets not queued until//                     i2_enable_interrupts time. Former versions would enqueue//                     them at i2_init_channel time, before we knew how many//                     channels were supposed to exist!// 0.05 - 10/12/91 MAG Major changes: works through the ellis.c routines now;//                     supports new 16-bit protocol and expandable boards.//      - 10/24/91 MAG Most changes in place and stable.// 0.06 -  2/20/92 MAG Format of CMD_HOTACK corrected: the command takes no//                     argument.// 0.07 -- 3/11/92 MAG Support added to store special packet types at interrupt//                     level (mostly responses to specific commands.)// 0.08 -- 3/30/92 MAG Support added for STAT_MODEM packet// 0.09 -- 6/24/93 MAG i2Link... needed to update number of boards BEFORE//                     turning on the interrupt.// 0.10 -- 6/25/93 MAG To avoid gruesome death from a bad board, we sanity check//                     some incoming.//// 1.1  - 12/25/96 AKM Linux version.//      - 10/09/98 DMC Revised Linux version.//------------------------------------------------------------------------------//************//* Includes *//************#include <linux/sched.h>#include "i2lib.h"//***********************//* Function Prototypes *//***********************static void i2QueueNeeds(i2eBordStrPtr, i2ChanStrPtr, int);static i2ChanStrPtr i2DeQueueNeeds(i2eBordStrPtr, int );static void i2StripFifo(i2eBordStrPtr);static void i2StuffFifoBypass(i2eBordStrPtr);static void i2StuffFifoFlow(i2eBordStrPtr);static void i2StuffFifoInline(i2eBordStrPtr);static int i2RetryFlushOutput(i2ChanStrPtr);// Not a documented part of the library routines (careful...) but the Diagnostic// i2diag.c finds them useful to help the throughput in certain limited// single-threaded operations.static void iiSendPendingMail(i2eBordStrPtr);static void serviceOutgoingFifo(i2eBordStrPtr);// Functions defined in ip2.c as part of interrupt handlingstatic void do_input(void *);static void do_status(void *);//***************//* Debug  Data *//***************#ifdef DEBUG_FIFOunsigned char DBGBuf[0x4000];unsigned short I = 0;static voidWriteDBGBuf(char *s, unsigned char *src, unsigned short n ) {	char *p = src;	// XXX: We need a spin lock here if we ever use this again	while (*s) {	// copy label		DBGBuf[I] = *s++;		I = I++ & 0x3fff;	}	while (n--) {	// copy data		DBGBuf[I] = *p++;		I = I++ & 0x3fff;	}}static voidfatality(i2eBordStrPtr pB ){	int i;	for (i=0;i<sizeof(DBGBuf);i++) {		if ((i%16) == 0)			printk("\n%4x:",i);		printk("%02x ",DBGBuf[i]);	}	printk("\n");	for (i=0;i<sizeof(DBGBuf);i++) {		if ((i%16) == 0)			printk("\n%4x:",i);		if (DBGBuf[i] >= ' ' && DBGBuf[i] <= '~') {			printk(" %c ",DBGBuf[i]);		} else {			printk(" . ");		}	}	printk("\n");	printk("Last index %x\n",I);}#endif /* DEBUG_FIFO *///********//* Code *//********static inline inti2Validate ( i2ChanStrPtr pCh ){	//ip2trace(pCh->port_index, ITRC_VERIFY,ITRC_ENTER,2,pCh->validity,	//	(CHANNEL_MAGIC | CHANNEL_SUPPORT));	return ((pCh->validity & (CHANNEL_MAGIC_BITS | CHANNEL_SUPPORT)) 			  == (CHANNEL_MAGIC | CHANNEL_SUPPORT));}//******************************************************************************// Function:   iiSendPendingMail(pB)// Parameters: Pointer to a board structure// Returns:    Nothing//// Description:// If any outgoing mail bits are set and there is outgoing mailbox is empty,// send the mail and clear the bits.//******************************************************************************static inline voidiiSendPendingMail(i2eBordStrPtr pB){	if (pB->i2eOutMailWaiting && (!pB->i2eWaitingForEmptyFifo) )	{		if (iiTrySendMail(pB, pB->i2eOutMailWaiting))		{			/* If we were already waiting for fifo to empty,			 * or just sent MB_OUT_STUFFED, then we are			 * still waiting for it to empty, until we should			 * receive an MB_IN_STRIPPED from the board.			 */			pB->i2eWaitingForEmptyFifo |=				(pB->i2eOutMailWaiting & MB_OUT_STUFFED);			pB->i2eOutMailWaiting = 0;			pB->SendPendingRetry = 0;		} else {/*		The only time we hit this area is when "iiTrySendMail" has		failed.  That only occurs when the outbound mailbox is		still busy with the last message.  We take a short breather		to let the board catch up with itself and then try again.		16 Retries is the limit - then we got a borked board.			/\/\|=mhw=|\/\/				*/			if( ++pB->SendPendingRetry < 16 ) {				init_timer( &(pB->SendPendingTimer) );				pB->SendPendingTimer.expires  = jiffies + 1;				pB->SendPendingTimer.function = (void*)(unsigned long)iiSendPendingMail;				pB->SendPendingTimer.data     = (unsigned long)pB;				add_timer( &(pB->SendPendingTimer) );			} else {				printk( KERN_ERR "IP2: iiSendPendingMail unable to queue outbound mail\n" );			}		}	}}//******************************************************************************// Function:   i2InitChannels(pB, nChannels, pCh)// Parameters: Pointer to Ellis Board structure//             Number of channels to initialize//             Pointer to first element in an array of channel structures// Returns:    Success or failure//// Description://// This function patches pointers, back-pointers, and initializes all the// elements in the channel structure array.//// This should be run after the board structure is initialized, through having// loaded the standard loadware (otherwise it complains).//// In any case, it must be done before any serious work begins initializing the// irq's or sending commands...////******************************************************************************static inti2InitChannels ( i2eBordStrPtr pB, int nChannels, i2ChanStrPtr pCh){	int index, stuffIndex;	i2ChanStrPtr *ppCh;		if (pB->i2eValid != I2E_MAGIC) {		COMPLETE(pB, I2EE_BADMAGIC);	}	if (pB->i2eState != II_STATE_STDLOADED) {		COMPLETE(pB, I2EE_BADSTATE);	}	LOCK_INIT(&pB->read_fifo_spinlock);	LOCK_INIT(&pB->write_fifo_spinlock);	LOCK_INIT(&pB->Dbuf_spinlock);	LOCK_INIT(&pB->Bbuf_spinlock);	LOCK_INIT(&pB->Fbuf_spinlock);		// NO LOCK needed yet - this is init	pB->i2eChannelPtr = pCh;	pB->i2eChannelCnt = nChannels;	pB->i2Fbuf_strip = pB->i2Fbuf_stuff = 0;	pB->i2Dbuf_strip = pB->i2Dbuf_stuff = 0;	pB->i2Bbuf_strip = pB->i2Bbuf_stuff = 0;	pB->SendPendingRetry = 0;	memset ( pCh, 0, sizeof (i2ChanStr) * nChannels );	for (index = stuffIndex = 0, ppCh = (i2ChanStrPtr *)(pB->i2Fbuf);		  nChannels && index < ABS_MOST_PORTS;		  index++)	{		if ( !(pB->i2eChannelMap[index >> 4] & (1 << (index & 0xf)) ) ) {			continue;		}		LOCK_INIT(&pCh->Ibuf_spinlock);		LOCK_INIT(&pCh->Obuf_spinlock);		LOCK_INIT(&pCh->Cbuf_spinlock);		LOCK_INIT(&pCh->Pbuf_spinlock);		// NO LOCK needed yet - this is init		// Set up validity flag according to support level		if (pB->i2eGoodMap[index >> 4] & (1 << (index & 0xf)) ) {			pCh->validity = CHANNEL_MAGIC | CHANNEL_SUPPORT;		} else {			pCh->validity = CHANNEL_MAGIC;		}		pCh->pMyBord = pB;      /* Back-pointer */		// Prepare an outgoing flow-control packet to send as soon as the chance		// occurs.		if ( pCh->validity & CHANNEL_SUPPORT ) {			pCh->infl.hd.i2sChannel = index;			pCh->infl.hd.i2sCount = 5;			pCh->infl.hd.i2sType = PTYPE_BYPASS;			pCh->infl.fcmd = 37;			pCh->infl.asof = 0;			pCh->infl.room = IBUF_SIZE - 1;			pCh->whenSendFlow = (IBUF_SIZE/5)*4; // when 80% full		// The following is similar to calling i2QueueNeeds, except that this		// is done in longhand, since we are setting up initial conditions on		// many channels at once.			pCh->channelNeeds = NEED_FLOW;  // Since starting from scratch			pCh->sinceLastFlow = 0;         // No bytes received since last flow											// control packet was queued			stuffIndex++;			*ppCh++ = pCh;      // List this channel as needing								// initial flow control packet sent		}		// Don't allow anything to be sent until the status packets come in from		// the board.		pCh->outfl.asof = 0;		pCh->outfl.room = 0;		// Initialize all the ring buffers		pCh->Ibuf_stuff = pCh->Ibuf_strip = 0;		pCh->Obuf_stuff = pCh->Obuf_strip = 0;		pCh->Cbuf_stuff = pCh->Cbuf_strip = 0;		memset( &pCh->icount, 0, sizeof (struct async_icount) );		pCh->hotKeyIn       = HOT_CLEAR;		pCh->channelOptions = 0;		pCh->bookMarks      = 0;		init_waitqueue_head(&pCh->pBookmarkWait);		init_waitqueue_head(&pCh->open_wait);		init_waitqueue_head(&pCh->close_wait);		init_waitqueue_head(&pCh->delta_msr_wait);		// Set base and divisor so default custom rate is 9600		pCh->BaudBase    = 921600;	// MAX for ST654, changed after we get		pCh->BaudDivisor = 96;		// the boxids (UART types) later		pCh->dataSetIn   = 0;		pCh->dataSetOut  = 0;		pCh->wopen       = 0;		pCh->throttled   = 0;		pCh->speed       = CBR_9600;		pCh->flags    = 0;		pCh->ClosingDelay     = 5*HZ/10;		pCh->ClosingWaitTime  = 30*HZ;		// Initialize task queue objects		INIT_WORK(&pCh->tqueue_input, do_input, pCh);		INIT_WORK(&pCh->tqueue_status, do_status, pCh);#ifdef IP2DEBUG_TRACE		pCh->trace = ip2trace;#endif		++pCh;     	--nChannels;	}	// No need to check for wrap here; this is initialization.	pB->i2Fbuf_stuff = stuffIndex;	COMPLETE(pB, I2EE_GOOD);}//******************************************************************************// Function:   i2DeQueueNeeds(pB, type)// Parameters: Pointer to a board structure//             type bit map: may include NEED_INLINE, NEED_BYPASS, or NEED_FLOW// Returns:   //             Pointer to a channel structure//// Description: Returns pointer struct of next channel that needs service of//  the type specified. Otherwise returns a NULL reference.////******************************************************************************static i2ChanStrPtr i2DeQueueNeeds(i2eBordStrPtr pB, int type){	unsigned short queueIndex;	unsigned long flags;	i2ChanStrPtr pCh = NULL;	switch(type) {	case  NEED_INLINE:		WRITE_LOCK_IRQSAVE(&pB->Dbuf_spinlock,flags);		if ( pB->i2Dbuf_stuff != pB->i2Dbuf_strip)		{			queueIndex = pB->i2Dbuf_strip;			pCh = pB->i2Dbuf[queueIndex];			queueIndex++;			if (queueIndex >= CH_QUEUE_SIZE) {				queueIndex = 0;			}			pB->i2Dbuf_strip = queueIndex;			pCh->channelNeeds &= ~NEED_INLINE;		}		WRITE_UNLOCK_IRQRESTORE(&pB->Dbuf_spinlock,flags); 		break;	case NEED_BYPASS:		WRITE_LOCK_IRQSAVE(&pB->Bbuf_spinlock,flags);		if (pB->i2Bbuf_stuff != pB->i2Bbuf_strip)		{			queueIndex = pB->i2Bbuf_strip;			pCh = pB->i2Bbuf[queueIndex];			queueIndex++;			if (queueIndex >= CH_QUEUE_SIZE) {				queueIndex = 0;			}			pB->i2Bbuf_strip = queueIndex;			pCh->channelNeeds &= ~NEED_BYPASS;		}		WRITE_UNLOCK_IRQRESTORE(&pB->Bbuf_spinlock,flags); 		break;		case NEED_FLOW:		WRITE_LOCK_IRQSAVE(&pB->Fbuf_spinlock,flags);		if (pB->i2Fbuf_stuff != pB->i2Fbuf_strip)		{			queueIndex = pB->i2Fbuf_strip;			pCh = pB->i2Fbuf[queueIndex];			queueIndex++;			if (queueIndex >= CH_QUEUE_SIZE) {				queueIndex = 0;			}			pB->i2Fbuf_strip = queueIndex;			pCh->channelNeeds &= ~NEED_FLOW;		}		WRITE_UNLOCK_IRQRESTORE(&pB->Fbuf_spinlock,flags); 		break;	default:		printk(KERN_ERR "i2DeQueueNeeds called with bad type:%x\n",type);		break;	}	return pCh;}//******************************************************************************// Function:   i2QueueNeeds(pB, pCh, type)// Parameters: Pointer to a board structure//             Pointer to a channel structure//             type bit map: may include NEED_INLINE, NEED_BYPASS, or NEED_FLOW// Returns:    Nothing//// Description:// For each type of need selected, if the given channel is not already in the// queue, adds it, and sets the flag indicating it is in the queue.//******************************************************************************

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -