📄 nsc.c
字号:
*
*/
BOOLEAN DeliverFullBuffers(IrDevice *thisDev)
{
BOOLEAN result = FALSE;
PLIST_ENTRY ListEntry;
LOG(TEXT("==> DeliverFullBuffers"), 0);
DBGOUT((TEXT("==> DeliverFullBuffers(0x%x)"), (UINT) thisDev));
/*
* Deliver all full rcv buffers
*/
for (
ListEntry = NDISSynchronizedRemoveHeadList(&thisDev->rcvBufFull,
&thisDev->interruptObj);
ListEntry;
ListEntry = NDISSynchronizedRemoveHeadList(&thisDev->rcvBufFull,
&thisDev->interruptObj)
)
{
rcvBuffer *rcvBuf = CONTAINING_RECORD(ListEntry,
rcvBuffer,
listEntry);
NDIS_STATUS stat;
PNDIS_BUFFER packetBuf;
SLOW_IR_FCS_TYPE fcs;
VerifyNdisPacket(rcvBuf->packet, 0);
if (thisDev->currentSpeed <= MAX_SIR_SPEED) {
/*
* The packet we have already has had BOFs,
* EOF, and * escape-sequences removed. It
* contains an FCS code at the end, which we
* need to verify and then remove before
* delivering the frame. We compute the FCS
* on the packet with the packet FCS attached;
* this should produce the constant value
* GOOD_FCS.
*/
fcs = ComputeFCS(rcvBuf->dataBuf,
rcvBuf->dataLen);
if (fcs != GOOD_FCS) {
/*
* FCS Error. Drop this frame.
*/
LOG(TEXT("Error: Bad FCS in DeliverFullBuffers"), fcs);
DBGERR((TEXT("Bad FCS in DeliverFullBuffers bad != good 0x%x!=0x%x."),
(UINT)fcs, (UINT) GOOD_FCS));
rcvBuf->state = STATE_FREE;
DBGSTAT((TEXT("Dropped %d/%d pkts; BAD FCS (%xh!=%xh):"),
++thisDev->packetsDropped,
thisDev->packetsDropped +
thisDev->packetsRcvd, fcs,
GOOD_FCS));
DBGPRINTBUF(rcvBuf->dataBuf,
rcvBuf->dataLen);
if (!rcvBuf->isDmaBuf)
{
NDISSynchronizedInsertTailList(&thisDev->rcvBufBuf,
RCV_BUF_TO_LIST_ENTRY(rcvBuf->dataBuf),
&thisDev->interruptObj);
}
rcvBuf->dataBuf = NULL;
rcvBuf->isDmaBuf = FALSE;
VerifyNdisPacket(rcvBuf->packet, 0);
NDISSynchronizedInsertHeadList(&thisDev->rcvBufFree,
&rcvBuf->listEntry,
&thisDev->interruptObj);
//break;
continue;
}
/* Remove the FCS from the end of the packet. */
rcvBuf->dataLen -= SLOW_IR_FCS_SIZE;
}
#ifdef DBG_ADD_PKT_ID
if (addPktIdOn) {
/* Remove dbg packet id. */
USHORT uniqueId;
rcvBuf->dataLen -= sizeof(USHORT);
uniqueId = *(USHORT *)(rcvBuf->dataBuf+
rcvBuf->dataLen);
DBGOUT(("ID: RCVing packet %xh **",
(UINT)uniqueId));
LOG("ID: Rcv Pkt id:", uniqueId);
}
#endif
/*
* The packet array is set up with its NDIS_PACKET.
* Now we need to allocate a single NDIS_BUFFER for
* the NDIS_PACKET and set the NDIS_BUFFER to the
* part of dataBuf that we want to deliver.
*/
NdisAllocateBuffer(&stat, &packetBuf,
thisDev->bufferPoolHandle,
(PVOID)rcvBuf->dataBuf, rcvBuf->dataLen);
if (stat != NDIS_STATUS_SUCCESS){
LOG(TEXT("Error: NdisAllocateBuffer failed"), 0);
DBGERR((TEXT("NdisAllocateBuffer failed")));
DbgBreakPoint();
break;
}
VerifyNdisPacket(rcvBuf->packet, 0);
NdisChainBufferAtFront(rcvBuf->packet, packetBuf);
LOG_PacketChain(thisDev, rcvBuf->packet);
VerifyNdisPacket(rcvBuf->packet, 1);
/*
* Fix up some other packet fields.
*/
NDIS_SET_PACKET_HEADER_SIZE(rcvBuf->packet,
IR_ADDR_SIZE+IR_CONTROL_SIZE);
DBGPKT((TEXT("Indicating rcv packet 0x%x."),
(UINT)rcvBuf->packet));
DBGPRINTBUF(rcvBuf->dataBuf, rcvBuf->dataLen);
/*
* Indicate to the protocol that another packet is
* ready. Set the rcv buffer's state to PENDING first
* to avoid a race condition with NDIS's call to the
* return packet handler.
*/
rcvBuf->state = STATE_PENDING;
*(rcvBuffer **)rcvBuf->packet->MiniportReserved = rcvBuf;
InterlockedInsertBufferSorted(&thisDev->rcvBufPend,
rcvBuf,
&thisDev->QueueLock);
VerifyNdisPacket(rcvBuf->packet, 1);
LOG_Data2(thisDev, rcvBuf->dataBuf);
NdisMIndicateReceivePacket(thisDev->ndisAdapterHandle,
&rcvBuf->packet, 1);
IRFIR_LOG_NDIS_PACKET(LOG_RXFRAME, rcvBuf->packet);
result = TRUE;
stat = NDIS_GET_PACKET_STATUS(rcvBuf->packet);
if (stat == NDIS_STATUS_PENDING) {
/*
* The packet is being delivered asynchronously.
* Leave the rcv buffer's state as PENDING;
* we'll get a callback when the transfer is
* complete. Do NOT step firstRcvBufIndex.
* We don't really need to break out here,
* but we will anyways just to make things
* simple. This is ok since we get this
* deferred interrupt callback for each packet
* anyway. It'll give the protocol a chance
* to catch up.
*/
LOG(TEXT("Indicated rcv complete (Async) bytes:"),
rcvBuf->dataLen);
DBGSTAT((TEXT("Rcv Pending. Rcvd %d packets"),
++thisDev->packetsRcvd));
}
else {
/*
* If there was an error, we are dropping this
* packet; otherwise, this packet was delivered
* synchronously. We can free the packet
* buffer and make this rcv frame available.
*/
LOG_RemoveEntryList(thisDev, rcvBuf);
NdisAcquireSpinLock(&thisDev->QueueLock);
RemoveEntryList(&rcvBuf->listEntry);
NdisReleaseSpinLock(&thisDev->QueueLock);
LOG(TEXT("Indicated rcv complete (sync) bytes:"),
rcvBuf->dataLen);
LOG_PacketUnchain(thisDev, rcvBuf->packet);
NdisUnchainBufferAtFront(rcvBuf->packet,
&packetBuf);
if (packetBuf){
NdisFreeBuffer(packetBuf);
}
rcvBuf->state = STATE_FREE;
VerifyNdisPacket(rcvBuf->packet, 0);
if (!rcvBuf->isDmaBuf) {
//
// At SIR speeds, we manage a group of buffers that
// we keep on the rcvBufBuf queue.
//
NDISSynchronizedInsertTailList(&thisDev->rcvBufBuf,
RCV_BUF_TO_LIST_ENTRY(rcvBuf->dataBuf),
&thisDev->interruptObj);
// ASSERT the pointer is actually outside our FIR DMA buffer
ASSERT(rcvBuf->dataBuf < thisDev->portInfo.dmaReadBuf ||
rcvBuf->dataBuf >= thisDev->portInfo.dmaReadBuf+RCV_DMA_SIZE);
}
rcvBuf->dataBuf = NULL;
VerifyNdisPacket(rcvBuf->packet, 0);
NDISSynchronizedInsertHeadList(&thisDev->rcvBufFree,
&rcvBuf->listEntry,
&thisDev->interruptObj);
if (stat == NDIS_STATUS_SUCCESS){
DBGSTAT((TEXT("Rcvd %d packets"),
++thisDev->packetsRcvd));
}
else {
DBGSTAT((TEXT("Dropped %d/%d rcv packets."),
thisDev->packetsDropped++,
thisDev->packetsDropped +
thisDev->packetsRcvd));
}
}
}
LOG(TEXT("<== DeliverFullBuffers"), 1);
DBGOUT((TEXT("<== DeliverFullBuffers")));
return result;
}
/*
*************************************************************************
* MiniportHandleInterrupt
*************************************************************************
*
*
* This is the deferred interrupt processing routine (DPC) which is
* optionally called following an interrupt serviced by MiniportISR.
*
*/
VOID MiniportHandleInterrupt(NDIS_HANDLE MiniportAdapterContext)
{
IrDevice *thisDev = CONTEXT_TO_DEV( MiniportAdapterContext);
LOG(TEXT("==> MiniportHandleInterrupt"), 0);
DBGOUT((TEXT("==> MiniportHandleInterrupt(0x%x)"),
(UINT)MiniportAdapterContext));
if (thisDev->resourcesReleased){
DBGOUT((TEXT("<== MiniportHandleInterrupt, blow off, no resources!")));
return;
}
/*
* If we finished the last send packet in the interrupt, we must change
* speed.
*/
if (thisDev->setSpeedNow){
thisDev->setSpeedNow = FALSE;
SetSpeed(thisDev);
}
/*
* If we have just started receiving a packet, indicate media-busy
* to the protocol.
*/
if (thisDev->mediaBusy && !thisDev->haveIndicatedMediaBusy) {
DBGISR((TEXT("HandleInterrupt indicating media busy")));
if (thisDev->currentSpeed > MAX_SIR_SPEED) {
LOG(TEXT("Error: MiniportHandleInterrupt is in wrong state"),
thisDev->currentSpeed);
DBGERR((TEXT("%s speed is 0x%x"),
TEXT("MiniportHandleInterrupt is in wrong state:"),
thisDev->currentSpeed));
DbgBreakPoint();
#ifdef OUTMSG
RETAILMSG(1, (TEXT("Error: MiniportHandleInterrupt is in wrong state\r\n")));
#endif
}
NdisMIndicateStatus(thisDev->ndisAdapterHandle,
NDIS_STATUS_MEDIA_BUSY, NULL, 0);
NdisMIndicateStatusComplete(thisDev->ndisAdapterHandle);
thisDev->haveIndicatedMediaBusy = TRUE;
}
/* FIR mode */
if (thisDev->currentSpeed > MAX_SIR_SPEED) {
DBGISR((TEXT("HandleInterrupt - FIR")));
if (thisDev->portInfo.writePending) {
FIR_MegaSendComplete(thisDev);
/*
* Any more Tx packets?
*/
if (!IsListEmpty(&thisDev->SendQueue))
{
/* Kick off another Tx. */
FIR_MegaSend(thisDev);
}
else {
thisDev->IntMask = 0x04;
SetupRecv(thisDev);
/*
* If we just sent the last frame to be sent at the old speed,
* set the hardware to the new speed.
* From OLD sytle!
*/
if (thisDev->setSpeedAfterCurrentSendPacket) {
thisDev->setSpeedAfterCurrentSendPacket = FALSE;
SetSpeed(thisDev);
}
}
}
else {
FIR_DeliverFrames(thisDev);
if (DeliverFullBuffers(thisDev)) {
// ???
MiniportSyncHandleInterrupt((PVOID) thisDev);
}
}
}
/* SIR mode */
else {
DBGISR((TEXT("HandleInterrupt - SIR")));
/*
* We delivered a receive packet. Update the rcv queue
* 'first' and 'last' pointers. We cannot use a spinlock
* to coordinate accesses to the rcv buffers with the ISR,
* since ISR's are not allowed to acquire spinlocks. So
* instead, we synchronize with the ISR using this special
* mechanism. MiniportSyncHandleInterrupt will do our work
* for us with the IRQ masked out in the PIC.
*/
if (DeliverFullBuffers(thisDev)) {
#if 0
NdisMSynchronizeWithInterrupt(&thisDev->interruptObj,
MiniportSyncHandleInterrupt,
(PVOID)MiniportAdapterContext);
#endif
}
/*
* Send any pending write packets if possible.
*/
if (IsCommReadyForTransmit(thisDev)) {
PortReadyForWrite(thisDev, TRUE);
}
}
LOG(TEXT("<== MiniportHandleInterrupt"), 1);
DBGOUT((TEXT("<== MiniportHandleInterrupt")));
}
#ifndef UNDER_CE
/*
*************************************************************************
* GetPnPResources
*************************************************************************
*
*
*/
BOOLEAN GetPnPResources(IrDevice *thisDev, NDIS_HANDLE WrapperConfigurationContext)
{
NDIS_STATUS stat;
BOOLEAN result = FALSE;
/*
* We should only need 2 adapter resources (2 IO and 1 interrupt),
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -