📄 nscfir.c
字号:
/*
Copyright(c) 1998,1999 SIC/Hitachi,Ltd.
Module Name:
nscfir.c
Revision History:
26th May 1999 Released
*/
//#define OUTMSG
#include "nsc.h"
#include "nsctypes.h"
#include "firregs.h"
#include "cc.h"
/******************************************************************************
* Modification Done by Maneesh Gupta
*
* S1.h has been replaced by platform.h
* Mobytel.h has been removed as it is no longer needed.
*****************************************************************************/
//#include "mobytel.h"
/******************************************************************************
* End of modification Done by Maneesh Gupta
*****************************************************************************/
//#include "dma.h"
VOID NSC_FIR_ISR(IrDevice *thisDev, BOOLEAN *claimingInterrupt,
BOOLEAN *requireDeferredCallback)
{
USHORT IrsrVal;
UCHAR itsr;
DBGISR((TEXT("==> NSC_FIR_ISR(0x%x)"), thisDev));
if(READ_REGISTER_UCHAR(pISIRR) & CC_FIR_ISIRR_SIRMOD){
*claimingInterrupt = FALSE;
*requireDeferredCallback = FALSE;
return;
}
WRITE_REGISTER_UCHAR(pIMSTCR, READ_REGISTER_UCHAR(pIMSTCR) & (CC_FIR_IMSTCR_TXEN|CC_FIR_IMSTCR_RXEN));
if(READ_REGISTER_UCHAR(pIMSTSR) & (CC_FIR_IMSTSR_TMI|CC_FIR_IMSTSR_TXI|CC_FIR_IMSTSR_RXI)){
if((READ_REGISTER_UCHAR(pIMSTSR) & CC_FIR_IMSTSR_RXI) && thisDev->portInfo.writePending==FALSE){
IrsrVal = READ_REGISTER_UCHAR(pIRSR);
if(IrsrVal & CC_FIR_IRSR_RFOVF){
WRITE_REGISTER_UCHAR(pIRSTCR,CC_FIR_IRSTCR_RSTC_RXFIFO);
RETAILMSG(1, (TEXT("ERROR NSC_FI_ISR1. Overrun.\r\n")));
}else{
if(IrsrVal & CC_FIR_IRSR_CRCER){
RETAILMSG(1, (TEXT("ERROR NSC_FIR_ISR2. Frame Error.\r\n")));
}
if(IrsrVal & CC_FIR_IRSR_ABORT){
RETAILMSG(1, (TEXT("ERROR NSC_FIR_ISR3. RxAbort.\r\n")));
}
}
WRITE_REGISTER_UCHAR(pIMSTCR, (READ_REGISTER_UCHAR(pIMSTCR) & CC_FIR_IMSTCR_RST_BANK) | CC_FIR_IMSTCR_BANK1);
thisDev->ReadRFPCount = READ_REGISTER_UCHAR(pIRRFPLR);
thisDev->ReadRFPCount |= ((USHORT)READ_REGISTER_UCHAR(pIRRFPHR) << 8);
WRITE_REGISTER_UCHAR(pIMSTCR, (READ_REGISTER_UCHAR(pIMSTCR) & CC_FIR_IMSTCR_RST_BANK) | CC_FIR_IMSTCR_BANK0);
WRITE_REGISTER_UCHAR(pIRSTCR, CC_FIR_IRSTCR_RSTC_RXSCI);
WRITE_REGISTER_UCHAR(pIMSTCR, (READ_REGISTER_UCHAR(pIMSTCR) & CC_FIR_IMSTCR_RST_BANK) | CC_FIR_IMSTCR_BANK2);
WRITE_REGISTER_UCHAR(pITMR, 0xA0);
WRITE_REGISTER_UCHAR(pIIRC3R, (CC_FIR_IIRC3R_TMIEN|CC_FIR_IIRC3R_TMI));
}
WRITE_REGISTER_UCHAR(pIMSTCR, (READ_REGISTER_UCHAR(pIMSTCR) & CC_FIR_IMSTCR_RST_BANK) | CC_FIR_IMSTCR_BANK0);
if(READ_REGISTER_UCHAR(pIMSTSR) & CC_FIR_IMSTSR_TMI){
WRITE_REGISTER_UCHAR(pIMSTCR, (READ_REGISTER_UCHAR(pIMSTCR) & CC_FIR_IMSTCR_RST_BANK) | CC_FIR_IMSTCR_BANK2);
WRITE_REGISTER_UCHAR(pIIRC3R,CC_FIR_IIRC3R_TMI);
}
*claimingInterrupt = TRUE;
*requireDeferredCallback = TRUE;
// Disable Interrupts
WRITE_REGISTER_UCHAR(pIMSTCR,READ_REGISTER_UCHAR(pIMSTCR) & ~CC_FIR_IMSTCR_IEN);
WRITE_REGISTER_UCHAR(pIMSTCR, (READ_REGISTER_UCHAR(pIMSTCR) & CC_FIR_IMSTCR_RST_BANK) | CC_FIR_IMSTCR_BANK0);
if((READ_REGISTER_UCHAR(pIMSTSR) & CC_FIR_IMSTSR_TXI) &&
thisDev->portInfo.writePending == TRUE){
itsr = READ_REGISTER_UCHAR(pITSR);
if(itsr & CC_FIR_ITSR_TFUR){
// TxFIFO Underrun
#ifdef OUTMSG
RETAILMSG(1, (TEXT("ERROR NSC_FI_ISR1. Underrun.\r\n")));
#endif
}
}
}else{
*claimingInterrupt = FALSE;
*requireDeferredCallback = FALSE;
}
DBGISR((TEXT("<== NSC_FIR_ISR [int recognized = %s, dpc = %s]"),
*claimingInterrupt ? TEXT("TRUE") : TEXT("FALSE"),
*requireDeferredCallback ? TEXT("TRUE") : TEXT("FALSE")));
}
typedef struct {
IrDevice *thisDev;
ULONG Offset; // This is a PUCHAR so we can do math on it.
ULONG Length;
} DMASPACE;
//
// We have two lists of buffers which occupy our DMA space. We
// want to walk this list and find the largest space for putting
// new packets.
//
rcvBuffer *GetNextPacket(DMASPACE *Space,
PLIST_ENTRY *CurrFull,
PLIST_ENTRY *CurrPend)
{
rcvBuffer *Result = NULL;
DBGOUT((TEXT("==>GetNextPacket")));
if (*CurrFull==&Space->thisDev->rcvBufFull)
{
// Full list is finished.
if (*CurrPend!=&Space->thisDev->rcvBufPend)
{
// Any entry on the pend list is valid. Take the
// next one and advance the pointer.
Result = CONTAINING_RECORD(*CurrPend,
rcvBuffer,
listEntry);
*CurrPend = (*CurrPend)->Flink;
}
else
{
// Both lists are finished. We will return NULL.
}
}
else
{
if (*CurrPend==&Space->thisDev->rcvBufPend)
{
// Pend list is finished. Take anything from the
// Full list, advance the pointer.
Result = CONTAINING_RECORD(*CurrFull,
rcvBuffer,
listEntry);
*CurrFull = (*CurrFull)->Flink;
}
else
{
// Both list have valid entries. Compare the two and take the
// one that appears in the buffer first.
rcvBuffer *Full, *Pend;
Full = CONTAINING_RECORD(*CurrFull,
rcvBuffer,
listEntry);
Pend = CONTAINING_RECORD(*CurrPend,
rcvBuffer,
listEntry);
if (Full->dataBuf < Pend->dataBuf)
{
// Full is the winner. Take it.
Result = Full;
*CurrFull = (*CurrFull)->Flink;
}
else
{
// Pend is the winner. Take it.
Result = Pend;
*CurrPend = (*CurrPend)->Flink;
}
}
}
if (Result)
{
ASSERT(Result->isDmaBuf);
}
DBGOUT((TEXT("<==GetNextPacket")));
return Result;
}
BOOLEAN SynchronizedFindLargestSpace(IN PVOID Context)
{
DMASPACE *Space = Context;
IrDevice *thisDev = Space->thisDev;
BOOLEAN Result;
PLIST_ENTRY Full, Pend;
rcvBuffer *Current = NULL;
DBGOUT((TEXT("==>SynchronizedFindLargestSpace")));
ASSERT(sizeof(ULONG)==sizeof(PVOID));
if (IsListEmpty(&thisDev->rcvBufFull) && IsListEmpty(&thisDev->rcvBufPend))
{
Space->Offset = (ULONG)thisDev->portInfo.dmaReadBuf;
Space->Length = RCV_DMA_SIZE;
}
else
{
ULONG EndOfLast;
ULONG ThisSpace;
Full = thisDev->rcvBufFull.Flink;
Pend = thisDev->rcvBufPend.Flink;
Space->Length = 0;
EndOfLast = Space->Offset = (ULONG)thisDev->portInfo.dmaReadBuf;
Current = GetNextPacket(Space, &Full, &Pend);
while (Current)
{
// It's possible to get a packet that is from SIR. If so, skip it.
if (Current->isDmaBuf)
{
ASSERT((ULONG)Current->dataBuf >= EndOfLast);
ThisSpace = (ULONG)Current->dataBuf - EndOfLast;
// ASSERT the pointer is actually in our DMA buffer.
ASSERT(Current->dataBuf >= thisDev->portInfo.dmaReadBuf ||
Current->dataBuf < thisDev->portInfo.dmaReadBuf+RCV_DMA_SIZE);
if (ThisSpace > Space->Length)
{
Space->Offset = EndOfLast;
Space->Length = ThisSpace;
}
EndOfLast = (ULONG)Current->dataBuf + Current->dataLen;
}
Current = GetNextPacket(Space, &Full, &Pend);
}
// Now we do one more calculation for the space after the end of the list.
ThisSpace = (ULONG)thisDev->portInfo.dmaReadBuf + RCV_DMA_SIZE - (ULONG)EndOfLast;
if (ThisSpace > Space->Length)
{
Space->Offset = EndOfLast;
Space->Length = ThisSpace;
}
// Round off to start DMA on 4 byte boundary
Space->Length -= 4 - (Space->Offset & 3);
Space->Offset = (Space->Offset+3) & (~3);
}
// We want space relative to start of buffer.
Space->Offset -= (ULONG)thisDev->portInfo.dmaReadBuf;
Result = (Space->Length >= MAX_RCV_DATA_SIZE + FAST_IR_FCS_SIZE);
if (!Result)
{
DEBUGFIR(DBG_ERR, (TEXT("NSC: ERROR: Not enough space to DMA full packet %x"),
thisDev));
}
DBGOUT((TEXT("<==SynchronizedFindLargestSpace")));
return Result;
}
BOOLEAN FindLargestSpace(IN IrDevice *thisDev,
OUT PULONG pOffset,
OUT PULONG pLength)
{
DMASPACE Space;
BOOLEAN Result;
DBGOUT((TEXT("<==FindLargestSpace")));
Space.Offset = 0;
Space.Length = 0;
Space.thisDev = thisDev;
NdisAcquireSpinLock(&thisDev->QueueLock);
Result = NdisMSynchronizeWithInterrupt(&thisDev->interruptObj,
SynchronizedFindLargestSpace,
&Space);
NdisReleaseSpinLock(&thisDev->QueueLock);
*pOffset = Space.Offset;
*pLength = Space.Length;
DBGOUT((TEXT("<==FindLargestSpace")));
return Result;
}
BOOLEAN FIR_MegaSend(IrDevice *thisDev)
{
NDIS_STATUS stat;
PNDIS_PACKET Packet;
PNDIS_IRDA_PACKET_INFO packetInfo;
int ret_val;
DBGOUT((TEXT("==>FIR_MegaSend")));
LOG(TEXT("==> FIR_MegaSend"), 0);
DEBUGFIR(DBG_TX|DBG_OUT, (TEXT("NSC: ==> FIR_MegaSend(0x%x)"),
(UINT) thisDev));
NdisAcquireSpinLock(&thisDev->QueueLock);
if (IsListEmpty(&thisDev->SendQueue))
{
NdisReleaseSpinLock(&thisDev->QueueLock);
ret_val = FALSE;
}
else
{
/*
* Update statistics.
*/
RegStats.TxPacketsStarted++;
thisDev->portInfo.writePending = TRUE;
DBGOUT((TEXT("writePending = TRUE")));
Packet = HEAD_SEND_PACKET(thisDev);
// Check for min turnaround time set.
packetInfo = GetPacketInfo(Packet);
//
// NOTE: Don't use NdisStallExecution for turnaround delay since
// you shouldn't stall for more than 60 us. Calling
// NdisStallExecution for large times will degrade system
// performance.
//
if (packetInfo->MinTurnAroundTime)
{
UINT usecToWait = packetInfo->MinTurnAroundTime;
UINT msecToWait;
packetInfo->MinTurnAroundTime = 0;
NdisReleaseSpinLock(&thisDev->QueueLock);
// Ndis timer has a 1ms granularity (in theory). Let's round off.
msecToWait = (usecToWait<=1000) ? 1 : (usecToWait+500)/1000;
#ifdef UNDER_CE
NdisMSetTimer(&thisDev->TurnaroundTimer, msecToWait);
#else // UNDER_CE
NdisSetTimer(&thisDev->TurnaroundTimer, msecToWait);
#endif // !UNDER_CE
DEBUGFIR(DBG_TX|DBG_OUT, (TEXT("NSC: MegaSend - do min TAT wait")));
return TRUE; // Say we're successful. We'll come back here.
}
if (thisDev->lastPacketAtOldSpeed==Packet)
{
thisDev->setSpeedAfterCurrentSendPacket = TRUE;
}
NdisToFirPacket(thisDev,
Packet, (UCHAR *) thisDev->portInfo.writeBuf,
MAX_IRDA_DATA_SIZE, &thisDev->portInfo.writeBufLen);
DEBUGFIR(DBG_PKT|DBG_TX, (TEXT("NSC: Sending packet 0x%x, len = %d"),
Packet, thisDev->portInfo.writeBufLen));
DBGPRINTBUF(thisDev->portInfo.writeBuf, thisDev->portInfo.writeBufLen);
NdisReleaseSpinLock(&thisDev->QueueLock);
#if 0
NSC_WriteBankReg(thisDev->portInfo.ioBase, 4, 4, (UCHAR)(thisDev->portInfo.writeBufLen & 0xff));
NSC_WriteBankReg(thisDev->portInfo.ioBase, 4, 5, (UCHAR)((thisDev->portInfo.writeBufLen >> 8) & 0x1f));
#endif
/* Setup Transmit DMA. */
NdisMSetupDmaTransfer(&stat, thisDev->DmaHandle,
thisDev->xmitDmaBuffer, 0,
thisDev->portInfo.writeBufLen, TRUE);
if (stat != NDIS_STATUS_SUCCESS) {
LOG(TEXT("NdisMSetupDmaTransfer(Tx)failed"), 0);
DbgBreakPoint();
ret_val = FALSE;
}
else {
ret_val = TRUE;
LOG(TEXT("FIR_MegaSend number of data bytes sent: "),
thisDev->portInfo.writeBufLen);
DEBUGFIR(DBG_TX|DBG_OUT,
(TEXT("NSC: FIR_MegaSend sent 0x%x bytes of data."),
thisDev->portInfo.writeBufLen));
}
}
LOG(TEXT("<== FIR_MegaSend"), 0);
DEBUGFIR(DBG_TX|DBG_OUT, (TEXT("NSC: <== FIR_MegaSend")));
DBGOUT((TEXT("<==FIR_MegaSend")));
return ret_val;
}
void FIR_MegaSendComplete(IrDevice *thisDev)
{
NDIS_STATUS status;
PLIST_ENTRY ListEntry;
PNDIS_PACKET Packet;
DBGOUT((TEXT("==>FIR_MegaSendComplete")));
LOG(TEXT("==> FIR_MegaSendComplete"), 0);
DEBUGFIR(DBG_TX|DBG_OUT, (TEXT("NSC: ==> FIR_MegaSendComplete(0x%x)"),
(UINT) thisDev));
ListEntry = MyInterlockedRemoveHeadList(&thisDev->SendQueue,
&thisDev->QueueLock);
if (!ListEntry)
{
ASSERT(0);
}
else
{
Packet = CONTAINING_RECORD(ListEntry,
NDIS_PACKET,
MiniportReserved);
RegStats.TxPacketsCompleted++;
NdisMCompleteDmaTransfer(&status, thisDev->DmaHandle,
thisDev->xmitDmaBuffer, 0,
thisDev->portInfo.writeBufLen, TRUE);
if (status != NDIS_STATUS_SUCCESS) {
DbgBreakPoint();
}
/*
* Check for Tx underrun.
*/
WRITE_REGISTER_UCHAR(pIMSTCR, (READ_REGISTER_UCHAR(pIMSTCR) & CC_FIR_IMSTCR_RST_BANK)|CC_FIR_IMSTCR_BANK0);/* Set to Bank 0 */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -