|
|
/*
************************************************************************ * * 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;
case STATE_GOT_BOF: switch (thisch){ case SLOW_IR_BOF: break; case SLOW_IR_EOF: /*
* Garbage */ DBGERR(("EOF in absorbing-BOFs state in DoRcv")); thisDev->portInfo.rcvState = STATE_INIT; break; case SLOW_IR_ESC: /*
* Start of data. * Our first data byte happens to be an ESC sequence. */ thisDev->portInfo.readBufPos = 0; thisDev->portInfo.rcvState = STATE_ESC_SEQUENCE; break; default: thisDev->portInfo.readBuf[0] = thisch; thisDev->portInfo.readBufPos = 1; thisDev->portInfo.rcvState = STATE_ACCEPTING; break; } break;
case STATE_ACCEPTING: switch (thisch){ case SLOW_IR_BOF: /*
* Meaningless garbage */ DBGOUT(("WARNING: BOF during accepting state in DoRcv")); thisDev->portInfo.rcvState = STATE_INIT; thisDev->portInfo.readBufPos = 0; break; case SLOW_IR_EOF: if (thisDev->portInfo.readBufPos < IR_ADDR_SIZE+IR_CONTROL_SIZE+SLOW_IR_FCS_SIZE){ thisDev->portInfo.rcvState = STATE_INIT; thisDev->portInfo.readBufPos = 0; } else { thisDev->portInfo.rcvState = STATE_SAW_EOF; } break; case SLOW_IR_ESC: thisDev->portInfo.rcvState = STATE_ESC_SEQUENCE; break; default: thisDev->portInfo.readBuf[thisDev->portInfo.readBufPos++] = thisch; break; } break;
case STATE_ESC_SEQUENCE: switch (thisch){ case SLOW_IR_EOF: case SLOW_IR_BOF: case SLOW_IR_ESC: /*
* ESC + {EOF|BOF|ESC} is an abort sequence */ DBGERR(("DoRcv - abort sequence; ABORTING IR PACKET: (got following packet + ESC,%xh)", (UINT)thisch)); DBGPRINTBUF(thisDev->portInfo.readBuf, thisDev->portInfo.readBufPos); thisDev->portInfo.rcvState = STATE_INIT; thisDev->portInfo.readBufPos = 0; break;
case SLOW_IR_EOF^SLOW_IR_ESC_COMP: case SLOW_IR_BOF^SLOW_IR_ESC_COMP: case SLOW_IR_ESC^SLOW_IR_ESC_COMP: thisDev->portInfo.readBuf[thisDev->portInfo.readBufPos++] = thisch ^ SLOW_IR_ESC_COMP; thisDev->portInfo.rcvState = STATE_ACCEPTING; break;
default: DBGERR(("Unnecessary escape sequence: (got following packet + ESC,%xh", (UINT)thisch)); DBGPRINTBUF(thisDev->portInfo.readBuf, thisDev->portInfo.readBufPos);
thisDev->portInfo.readBuf[thisDev->portInfo.readBufPos++] = thisch ^ SLOW_IR_ESC_COMP; thisDev->portInfo.rcvState = STATE_ACCEPTING; break; } break;
case STATE_SAW_EOF: default: DBGERR(("Illegal state in DoRcv")); thisDev->portInfo.readBufPos = 0; thisDev->portInfo.rcvState = STATE_INIT; return 0; } } }
/*
* Set result and do any post-cleanup. */ switch (thisDev->portInfo.rcvState){
case STATE_SAW_EOF: /*
* We've read in the entire packet. * Queue it and return TRUE. */ DBGOUT((" *** DoRcv returning with COMPLETE packet, read %d bytes ***", thisDev->portInfo.readBufPos));
if (!IsListEmpty(&thisDev->rcvBufBuf)) { QueueReceivePacket(thisDev, thisDev->portInfo.readBuf, thisDev->portInfo.readBufPos, FALSE);
// The protocol has our buffer. Get a new one.
pListEntry = RemoveHeadList(&thisDev->rcvBufBuf); thisDev->portInfo.readBuf = LIST_ENTRY_TO_RCV_BUF(pListEntry); } else { // No new buffers were available. We just discard this packet.
DBGERR(("No rcvBufBuf available, discarding packet\n")); }
result = TRUE;
if (rawBufPos < rawBytesRead){ /*
* This is ugly. * We have some more unprocessed bytes in the raw buffer. * Move these to the beginning of the raw buffer * go to the CLEANUP state, which indicates that these * bytes be used up during the next call. * (This is typically only 1 or 2 bytes). * Note: We can't just leave these in the raw buffer because * we might be supporting connections to multiple COM ports. */ memcpy(thisDev->portInfo.rawBuf, &thisDev->portInfo.rawBuf[rawBufPos], rawBytesRead-rawBufPos); thisDev->portInfo.readBufPos = rawBytesRead-rawBufPos; thisDev->portInfo.rcvState = STATE_CLEANUP; } else { thisDev->portInfo.rcvState = STATE_INIT; } break;
default: if (thisDev->portInfo.readBufPos > MAX_RCV_DATA_SIZE){ DBGERR(("Overrun in DoRcv : read %d=%xh bytes:", thisDev->portInfo.readBufPos, thisDev->portInfo.readBufPos)); DBGPRINTBUF(thisDev->portInfo.readBuf, thisDev->portInfo.readBufPos); thisDev->portInfo.readBufPos = 0; thisDev->portInfo.rcvState = STATE_INIT; } else { DBGOUT(("DoRcv returning with partial packet, read %d bytes", thisDev->portInfo.readBufPos)); } result = FALSE; break; }
return result; }
/*
************************************************************************* * COM_ISR ************************************************************************* * * */ VOID COM_ISR(IrDevice *thisDev, BOOLEAN *claimingInterrupt, BOOLEAN *requireDeferredCallback) {
LONG NewCount; /*
* Get the interrupt status register value. */ UCHAR intId = GetCOMPort(thisDev->portInfo.ioBase, INT_ID_AND_FIFO_CNTRL_REG_OFFSET);
if (intId & INTID_INTERRUPT_NOT_PENDING){ /*
* This is NOT our interrupt. * Set carry bit to pass the interrupt to the next driver in the chain. */ *claimingInterrupt = *requireDeferredCallback = FALSE; } else { /*
* This is our interrupt */
/*
* In some odd situations, we can get interrupt bits that don't * get cleared; we don't want to loop forever in this case, so keep a counter. */ UINT loops = 0;
*claimingInterrupt = TRUE; *requireDeferredCallback = FALSE;
while (!(intId & INTID_INTERRUPT_NOT_PENDING) && (loops++ < 0x10)){
switch (intId & INTID_INTIDMASK){
case INTID_MODEMSTAT_INT: DBGOUT(("COM INTERRUPT: modem status int")); GetCOMPort(thisDev->portInfo.ioBase, MODEM_STAT_REG_OFFSET); break;
case INTID_XMITREG_INT: DBGOUT(("COM INTERRUPT: xmit reg empty"));
if (thisDev->portInfo.SirWritePending){
/*
* Try to send a few more bytes */ if (StepSendFSM(thisDev)){
/*
* There are no more bytes to send; * reset interrupts for receive mode. */ thisDev->portInfo.SirWritePending = FALSE; InterlockedExchange(&thisDev->portInfo.IsrDoneWithPacket,1);
//
// this will unmask the receive interrupt
//
SetCOMInterrupts(thisDev, TRUE);
/*
* Request a DPC so that we can try * to send other pending write packets. */ *requireDeferredCallback = TRUE; } }
break;
case INTID_RCVDATAREADY_INT: DBGOUT(("COM INTERRUPT: rcv data available!"));
thisDev->nowReceiving = TRUE;
NewCount=NdisInterlockedIncrement(&thisDev->RxInterrupts);
if (!thisDev->mediaBusy && (NewCount > MEDIA_BUSY_THRESHOLD)){
thisDev->mediaBusy = TRUE; thisDev->haveIndicatedMediaBusy = FALSE; *requireDeferredCallback = TRUE; }
if (StepReceiveFSM(thisDev)){ /*
* The receive engine has accumulated an entire frame. * Request a deferred callback so we can deliver the frame * when not in interrupt context. */ *requireDeferredCallback = TRUE; thisDev->nowReceiving = FALSE; }
break;
case INTID_RCVLINESTAT_INT: DBGOUT(("COM INTERRUPT: rcv line stat int!")); break; }
/*
* After we service each interrupt condition, we read the line status register. * This clears the current interrupt, and a new interrupt may then appear in * the interrupt-id register. */ GetCOMPort(thisDev->portInfo.ioBase, LINE_STAT_REG_OFFSET); intId = GetCOMPort(thisDev->portInfo.ioBase, INT_ID_AND_FIFO_CNTRL_REG_OFFSET);
} } }
/*
************************************************************************* * OpenCOM ************************************************************************* * * Initialize UART registers * */ BOOLEAN OpenCOM(IrDevice *thisDev) { BOOLEAN dongleInit; UCHAR intIdReg;
DBGOUT(("-> OpenCOM"));
//
// Make sure bank zero is selected
//
NdisRawWritePortUchar(thisDev->portInfo.ioBase+LCR_BSR_OFFSET, 03);
/*
* Disable all COM interrupts while setting up. */ SyncSetInterruptMask(thisDev, FALSE);
/*
* Set request-to-send and clear data-terminal-ready. * Note: ** Bit 3 must be set to enable interrupts. */ SYNC_SET_COMM_PORT(&thisDev->interruptObj,thisDev->portInfo.ioBase, MODEM_CONTROL_REG_OFFSET, 0x0A);
/*
* Set dongle- or part-specific info to default */ thisDev->portInfo.hwCaps.supportedSpeedsMask = ALL_SLOW_IRDA_SPEEDS; thisDev->portInfo.hwCaps.turnAroundTime_usec = DEFAULT_TURNAROUND_usec; thisDev->portInfo.hwCaps.extraBOFsRequired = 0;
/*
* Set the COM port speed to the default 9600 baud. * Some dongles can only receive cmd sequences at this speed. */ SetUARTSpeed(thisDev, 9600);
dongleInit = NSC_DEMO_Init( thisDev );
/*
* Set request-to-send and clear data-terminal-ready. * Note: ** Bit 3 must be set to enable interrupts. */ SYNC_SET_COMM_PORT(&thisDev->interruptObj,thisDev->portInfo.ioBase, MODEM_CONTROL_REG_OFFSET, 0x0A);
if (!dongleInit){ DBGERR(("Dongle-specific init failed in OpenCOM")); return FALSE; }
/*
* Set speed to default for the entire part. * (This is redundant in most, but not all, cases.) */ thisDev->linkSpeedInfo = &supportedBaudRateTable[BAUDRATE_9600];; SetSpeed(thisDev);
/*
* Clear the FIFO control register */ SYNC_SET_COMM_PORT(&thisDev->interruptObj,thisDev->portInfo.ioBase, INT_ID_AND_FIFO_CNTRL_REG_OFFSET, 0x00);
/*
* Set up the FIFO control register to use both read and write FIFOs (if 16650), * and with a receive FIFO trigger level of 1 byte. */ SYNC_SET_COMM_PORT(&thisDev->interruptObj,thisDev->portInfo.ioBase, INT_ID_AND_FIFO_CNTRL_REG_OFFSET, 0x07); /*
* Check whether we're running on a 16550,which has a 16-byte write FIFO. * In this case, we'll be able to blast up to 16 bytes at a time. */ intIdReg = SYNC_GET_COMM_PORT(&thisDev->interruptObj,thisDev->portInfo.ioBase, INT_ID_AND_FIFO_CNTRL_REG_OFFSET); thisDev->portInfo.haveFIFO = (BOOLEAN)((intIdReg & 0xC0) == 0xC0);
/*
* Start out in receive mode. * We always want to be in receive mode unless we're transmitting a frame. */ SyncSetInterruptMask(thisDev, TRUE);
DBGOUT(("OpenCOM succeeded")); return TRUE; } #if 1
/*
************************************************************************* * CloseCOM ************************************************************************* * */ VOID CloseCOM(IrDevice *thisDev) { /*
* Do special deinit for dongles. * Some dongles can only rcv cmd sequences at 9600, so set this speed first. */ thisDev->linkSpeedInfo = &supportedBaudRateTable[BAUDRATE_9600];; SetSpeed(thisDev); NSC_DEMO_Deinit(thisDev->portInfo.ioBase, thisDev->portInfo.dongleContext);
SyncSetInterruptMask(thisDev, FALSE); } #endif
/*
************************************************************************* * DoRcvDirect ************************************************************************* * * Read up to maxBytes bytes from the UART's receive FIFO. * Return the number of bytes read or (UINT)-1 if an error occurred. * */ UINT DoRcvDirect(PUCHAR ioBase, UCHAR *data, UINT maxBytes) { USHORT bytesRead; UCHAR lineStatReg; UINT i; BOOLEAN goodChar;
for (bytesRead = 0; bytesRead < maxBytes; bytesRead++){
/*
* Wait for data-ready */ i = 0; do { lineStatReg = GetCOMPort(ioBase, LINE_STAT_REG_OFFSET);
/*
* The UART reports framing and break errors as the effected * characters appear on the stack. We drop these characters, * which will probably result in a bad frame checksum. */ if (lineStatReg & (LINESTAT_BREAK | LINESTAT_FRAMINGERROR)){
UCHAR badch = GetCOMPort(ioBase, XFER_REG_OFFSET); DBGERR(("Bad rcv %02xh, LSR=%02xh", (UINT)badch, (UINT)lineStatReg)); return (UINT)-1; } else if (lineStatReg & LINESTAT_DATAREADY){
if (lineStatReg & LINESTAT_OVERRUNERROR) { DBGERR(("Overrun")); }
goodChar = TRUE; } else { /*
* No input char ready */ goodChar = FALSE; }
} while (!goodChar && (++i < REG_POLL_LOOPS)); if (!goodChar){ break; }
/*
* Read in the next data byte */ data[bytesRead] = GetCOMPort(ioBase, XFER_REG_OFFSET); }
return bytesRead; }
/*
************************************************************************* * GetCOMPort ************************************************************************* */ UCHAR GetCOMPort(PUCHAR comBase, comPortRegOffset portOffset) { UCHAR val; #if DBG
{ UCHAR TempVal; //
// This code assumes that bank 0 is current, we will make sure of that
//
NdisRawReadPortUchar(comBase+LCR_BSR_OFFSET, &TempVal);
ASSERT((TempVal & BKSE) == 0); } #endif
NdisRawReadPortUchar(comBase+portOffset, &val); return val; }
/*
************************************************************************* * SetCOMPort ************************************************************************* */ VOID SetCOMPort(PUCHAR comBase, comPortRegOffset portOffset, UCHAR val) {
#if DBG
UCHAR TempVal;
//
// This code assumes that bank 0 is current, we will make sure of that
//
NdisRawReadPortUchar(comBase+LCR_BSR_OFFSET, &TempVal);
ASSERT((TempVal & BKSE) == 0); #endif
NdisRawWritePortUchar(comBase+portOffset, val); }
|