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

📄 comm.c

📁 网络驱动开发
💻 C
📖 第 1 页 / 共 2 页
字号:
/*
 ************************************************************************
 *
 *	COMM.c
 *
 * Portions Copyright (C) 1996-2001 National Semiconductor Corp.
 * All rights reserved.
 * Copyright (C) 1996-2001 Microsoft Corporation. All Rights Reserved.
 *
 *
 *
 *************************************************************************
 */

#include "nsc.h"
#include "comm.tmh"
#define MEDIA_BUSY_THRESHOLD  (16)

#define SYNC_SET_COMM_PORT(_intobj,_port,_index,_value) SyncWriteBankReg(_intobj,_port,0,_index,_value);

#define SYNC_GET_COMM_PORT(_intobj,_port,_index) SyncReadBankReg(_intobj,_port,0,_index)



/*
 *************************************************************************
 *  SetCOMInterrupts
 *************************************************************************
 */
VOID SetCOMInterrupts(IrDevice *thisDev, BOOLEAN enable)
{
	UCHAR newMask;

	if (enable){
		if (thisDev->portInfo.SirWritePending){
			if (thisDev->currentSpeed > MAX_SIR_SPEED){
				newMask = thisDev->FirIntMask;
			}
			else {
				newMask = XMIT_MODE_INTS_ENABLE;
			}
		}	
		else {
			if (thisDev->currentSpeed > MAX_SIR_SPEED){
				newMask = thisDev->FirIntMask;
			}
			else {
				newMask = RCV_MODE_INTS_ENABLE;
			}
		}
	}
	else {
		newMask = ALL_INTS_DISABLE;
	}

	SetCOMPort(thisDev->portInfo.ioBase, INT_ENABLE_REG_OFFSET, newMask);
}

VOID
SyncSetInterruptMask(
    IrDevice *thisDev,
    BOOLEAN enable
    )

{

	UCHAR newMask;

	if (enable){
		if (thisDev->portInfo.SirWritePending){
			if (thisDev->currentSpeed > MAX_SIR_SPEED){
				newMask = thisDev->FirIntMask;
			}
			else {
				newMask = XMIT_MODE_INTS_ENABLE;
			}
		}	
		else {
			if (thisDev->currentSpeed > MAX_SIR_SPEED){
				newMask = thisDev->FirIntMask;
			}
			else {
				newMask = RCV_MODE_INTS_ENABLE;
			}
		}
	}
	else {
		newMask = ALL_INTS_DISABLE;
	}

    SYNC_SET_COMM_PORT(&thisDev->interruptObj,thisDev->portInfo.ioBase, INT_ENABLE_REG_OFFSET, newMask);

}


/*
 *************************************************************************
 *  DoOpen
 *************************************************************************
 *
 *  Open COMM port
 *
 */
BOOLEAN DoOpen(IrDevice *thisDev)
{
	BOOLEAN result;

	DBGOUT(("DoOpen(%d)", thisDev->portInfo.ioBase));

	/*
	 *  This buffer gets swapped with the rcvBuffer data pointer
	 *  and must be the same size.
	 */
	thisDev->portInfo.readBuf = LIST_ENTRY_TO_RCV_BUF(NscMemAlloc(RCV_BUFFER_SIZE));  // Was FALSE -SWA
	if (!thisDev->portInfo.readBuf){
		return FALSE;
	}


	/*
	 *  The write buffer is also used as a DMA buffer.
	 */
	thisDev->portInfo.writeComBuffer = NscMemAlloc(MAX_IRDA_DATA_SIZE );
	if (!thisDev->portInfo.writeComBuffer){
		return FALSE;
	}

	/*
	 *  Initialize send/receive FSMs before OpenCOM(), which enables rcv interrupts.
	 */
	thisDev->portInfo.rcvState = STATE_INIT;
	thisDev->portInfo.SirWritePending = FALSE;
    //
    //  the sir recieve will start automatically
    //
    thisDev->TransmitIsIdle= TRUE;

    NdisInitializeEvent(&thisDev->ReceiveStopped);
    NdisResetEvent(&thisDev->ReceiveStopped);

    NdisInitializeEvent(&thisDev->SendStoppedOnHalt);
    NdisResetEvent(&thisDev->SendStoppedOnHalt);

	result = OpenCOM(thisDev);

	DBGOUT(("DoOpen %s", (CHAR *)(result ? "succeeded" : "failed")));
	return result;

}



/*
 *************************************************************************
 *  DoClose
 *************************************************************************
 *
 *  Close COMM port
 *
 */
VOID DoClose(IrDevice *thisDev)
{
	DBGOUT(("DoClose(COM%d)", thisDev->portInfo.ioBase));

	if (thisDev->portInfo.readBuf){

		NscMemFree(RCV_BUF_TO_LIST_ENTRY(thisDev->portInfo.readBuf));

		thisDev->portInfo.readBuf = NULL;
	}

	if (thisDev->portInfo.writeComBuffer){

		NscMemFree(thisDev->portInfo.writeComBuffer);
		thisDev->portInfo.writeComBuffer = NULL;
	}
#if 0
	CloseCOM(thisDev);
#endif
}

typedef struct _SYNC_SET_SPEED {

    PUCHAR     PortBase;
    UINT       BitsPerSecond;

} SYNC_SET_SPEED, *PSYNC_SET_SPEED;


VOID
SyncSetUARTSpeed(
    PVOID      Context
    )

{

    PSYNC_SET_SPEED     SyncContext=(PSYNC_SET_SPEED)Context;

    NdisRawWritePortUchar(SyncContext->PortBase+LINE_CONTROL_REG_OFFSET,0x83);
    NdisRawWritePortUchar(SyncContext->PortBase+XFER_REG_OFFSET, (UCHAR)(115200/SyncContext->BitsPerSecond));
    NdisRawWritePortUchar(SyncContext->PortBase+INT_ENABLE_REG_OFFSET, (UCHAR)((115200/SyncContext->BitsPerSecond)>>8));
    NdisRawWritePortUchar(SyncContext->PortBase+LINE_CONTROL_REG_OFFSET, 0x03);

    return;

}




/*
 *************************************************************************
 *  SetUARTSpeed
 *************************************************************************
 *
 *
 */
VOID SetUARTSpeed(IrDevice *thisDev, UINT bitsPerSec)
{

	if (bitsPerSec <= MAX_SIR_SPEED){

		/*
		 *  Set speed in the standard UART divisor latch
		 *
		 *  1.	Set up to access the divisor latch.
		 *
		 *	2.	In divisor-latch mode:
		 *			the transfer register doubles as the low divisor latch
		 *			the int-enable register doubles as the hi divisor latch
		 *
		 *		Set the divisor for the given speed.
		 *		The divisor divides the maximum Slow IR speed of 115200 bits/sec.
		 *
		 *  3.	Take the transfer register out of divisor-latch mode.
		 *
		 */

        SYNC_SET_SPEED    SyncContext;

		if (!bitsPerSec){
			bitsPerSec = 9600;
		}


        SyncContext.PortBase=thisDev->portInfo.ioBase;
        SyncContext.BitsPerSecond=bitsPerSec;

        //
        //  since we are changeing the port bank, sync with the interrupt
        //
        NdisMSynchronizeWithInterrupt(
            &thisDev->interruptObj,
            SyncSetUARTSpeed,
            &SyncContext
            );


		NdisStallExecution(5000);
	}
}


/*
 *************************************************************************
 *  SetSpeed
 *************************************************************************
 *
 *
 */
BOOLEAN SetSpeed(IrDevice *thisDev)
{
	UINT bitsPerSec = thisDev->linkSpeedInfo->bitsPerSec;
	BOOLEAN dongleSet, result = TRUE;

//    DbgPrint("nsc: setspeed %d\n",bitsPerSec);
	DBGOUT((" **** SetSpeed(%xh, %d bps) ***************************", thisDev->portInfo.ioBase, bitsPerSec));


	/*
	 *  Disable interrupts while changing speed.
	 *  (This is especially important for the ADAPTEC dongle;
	 *   we may get interrupted while setting command mode
	 *   between writing 0xff and reading 0xc3).
	 */
	SyncSetInterruptMask(thisDev, FALSE);

	/*
	 *  First, set the UART's speed to 9600 baud.
	 *  Some of the dongles need to receive their command sequences at this speed.
	 */
	SetUARTSpeed(thisDev, 9600);

	dongleSet = NSC_DEMO_SetSpeed(thisDev, thisDev->portInfo.ioBase, bitsPerSec, thisDev->portInfo.dongleContext);
	//
	// debug info.
	//
	thisDev->portInfo.PacketsReceived_DEBUG = 0;
	if (!dongleSet){
		DBGERR(("Dongle set-speed failed"));
		result = FALSE;
	}

	/*
	 *  Now set the speed for the COM port
	 */
	SetUARTSpeed(thisDev, bitsPerSec);

	thisDev->currentSpeed = bitsPerSec;

    DebugSpeed=bitsPerSec;

	SyncSetInterruptMask(thisDev, TRUE);

	return result;
}



/*
 *************************************************************************
 *  StepSendFSM
 *************************************************************************
 *
 *
 *  Step the send fsm to send a few more bytes of an IR frame.
 *  Return TRUE only after an entire frame has been sent.
 *
 */
BOOLEAN StepSendFSM(IrDevice *thisDev)
{
	UINT i, bytesAtATime, startPos = thisDev->portInfo.writeComBufferPos;
	UCHAR lineStatReg;
	BOOLEAN result;
	UINT maxLoops;

	/*
	 *  Ordinarily, we want to fill the send FIFO once per interrupt.
	 *  However, at high speeds the interrupt latency is too slow and
	 *  we need to poll inside the ISR to send the whole packet during
	 *  the first interrupt.
	 */
	if (thisDev->currentSpeed > 115200){
		maxLoops = REG_TIMEOUT_LOOPS;
	}
	else {
		maxLoops = REG_POLL_LOOPS;
	}


	/*
	 *  Write databytes as long as we have them and the UART's FIFO hasn't filled up.
	 */
	while (thisDev->portInfo.writeComBufferPos < thisDev->portInfo.writeComBufferLen){

		/*
		 *  If this COM port has a FIFO, we'll send up to the FIFO size (16 bytes).
		 *  Otherwise, we can only send one byte at a time.
		 */
		if (thisDev->portInfo.haveFIFO){
			bytesAtATime = MIN(FIFO_SIZE, (thisDev->portInfo.writeComBufferLen - thisDev->portInfo.writeComBufferPos));
		}
		else {
			bytesAtATime = 1;
		}


		/*
		 *  Wait for ready-to-send.
		 */
		i = 0;
		do {
			lineStatReg = GetCOMPort(thisDev->portInfo.ioBase, LINE_STAT_REG_OFFSET);
		} while (!(lineStatReg & LINESTAT_XMIT_HOLDING_REG_EMPTY) && (++i < maxLoops));
		if (!(lineStatReg & LINESTAT_XMIT_HOLDING_REG_EMPTY)){
			break;
		}

		/*
		 *  Send the next byte or FIFO-volume of bytes.
		 */
		for (i = 0; i < bytesAtATime; i++){
			SetCOMPort(	thisDev->portInfo.ioBase,
						XFER_REG_OFFSET,
						thisDev->portInfo.writeComBuffer[thisDev->portInfo.writeComBufferPos++]);
		}

	}

	/*
	 *  The return value will indicate whether we've sent the entire frame.
	 */
	if (thisDev->portInfo.writeComBufferPos >= thisDev->portInfo.writeComBufferLen){

		if (thisDev->setSpeedAfterCurrentSendPacket){
			/*
			 *  We'll be changing speeds after this packet,
			 *  so poll until the packet bytes have been completely sent out the FIFO.
			 *  After the 16550 says that it is empty, there may still be one remaining
			 *  byte in the FIFO, so flush it out by sending one more BOF.
			 */
			i = 0;
			do {
				lineStatReg = GetCOMPort(thisDev->portInfo.ioBase, LINE_STAT_REG_OFFSET);
			} while (!(lineStatReg & 0x20) && (++i < REG_TIMEOUT_LOOPS));

			SetCOMPort(thisDev->portInfo.ioBase, XFER_REG_OFFSET, (UCHAR)SLOW_IR_EXTRA_BOF);
			i = 0;
			do {
				lineStatReg = GetCOMPort(thisDev->portInfo.ioBase, LINE_STAT_REG_OFFSET);
			} while (!(lineStatReg & 0x20) && (++i < REG_TIMEOUT_LOOPS));
		}

		result = TRUE;
	}
	else {
		result = FALSE;
	}

	DBGOUT(("StepSendFSM wrote %d bytes (%s):", (UINT)(thisDev->portInfo.writeComBufferPos-startPos), (PUCHAR)(result ? "DONE" : "not done")));
	// DBGPRINTBUF(thisDev->portInfo.writeComBuffer+startPos, thisDev->portInfo.writeComBufferPos-startPos);

	return result;
	
}


/*
 *************************************************************************
 *  StepReceiveFSM
 *************************************************************************
 *
 *
 *  Step the receive fsm to read in a piece of an IR frame;
 *  strip the BOFs and EOF, and eliminate escape sequences.
 *  Return TRUE only after an entire frame has been read in.
 *
 */
BOOLEAN StepReceiveFSM(IrDevice *thisDev)
{
	UINT rawBufPos=0, rawBytesRead=0;
	BOOLEAN result;
	UCHAR thisch;
    PLIST_ENTRY pListEntry;

	DBGOUT(("StepReceiveFSM(%xh)", thisDev->portInfo.ioBase));

	/*
	 *  Read in and process groups of incoming bytes from the FIFO.
	 *  NOTE:  We have to loop once more after getting MAX_RCV_DATA_SIZE
	 *         bytes so that we can see the 'EOF'; hence <= and not <.
	 */
	while ((thisDev->portInfo.rcvState != STATE_SAW_EOF) && (thisDev->portInfo.readBufPos <= MAX_RCV_DATA_SIZE)){

		if (thisDev->portInfo.rcvState == STATE_CLEANUP){
			/*
			 *  We returned a complete packet last time, but we had read some
			 *  extra bytes, which we stored into the rawBuf after returning
			 *  the previous complete buffer to the user.
			 *  So instead of calling DoRcvDirect in this first execution of this loop,
			 *  we just use these previously-read bytes.
			 *  (This is typically only 1 or 2 bytes).
			 */
			rawBytesRead = thisDev->portInfo.readBufPos;
			thisDev->portInfo.rcvState = STATE_INIT;
			thisDev->portInfo.readBufPos = 0;
		}
		else {
			rawBytesRead = DoRcvDirect(thisDev->portInfo.ioBase, thisDev->portInfo.rawBuf, FIFO_SIZE);
			if (rawBytesRead == (UINT)-1){
				/*
				 *  Receive error occurred.  Go back to INIT state.
				 */
				thisDev->portInfo.rcvState = STATE_INIT;
				thisDev->portInfo.readBufPos = 0;
				continue;
			}	
			else if (rawBytesRead == 0){
				/*
				 *  No more receive bytes.  Break out.
				 */
				break;
			}
		}

		/*
		 *  Let the receive state machine process this group of characters
		 *  we got from the FIFO.
		 *
		 *  NOTE:  We have to loop once more after getting MAX_RCV_DATA_SIZE
		 *         bytes so that we can see the 'EOF'; hence <= and not <.
		 */
		for (rawBufPos = 0;
		     ((thisDev->portInfo.rcvState != STATE_SAW_EOF) &&
			  (rawBufPos < rawBytesRead) &&
			  (thisDev->portInfo.readBufPos <= MAX_RCV_DATA_SIZE));
			 rawBufPos++){

			thisch = thisDev->portInfo.rawBuf[rawBufPos];

			switch (thisDev->portInfo.rcvState){

				case STATE_INIT:
					switch (thisch){
						case SLOW_IR_BOF:
							thisDev->portInfo.rcvState = STATE_GOT_BOF;
							break;
						case SLOW_IR_EOF:
						case SLOW_IR_ESC:
						default:
							/*
							 *  This is meaningless garbage.  Scan past it.
							 */
							break;
					}
					break;

⌨️ 快捷键说明

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