/* ************************************************************************ * * 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); }