|
|
/*++
Copyright (c) 1992 Microsoft Corporation
Module Name:
lttimer.c
Abstract:
This module contains the polling timer processing routines.
Author:
Stephen Hou (stephh@microsoft.com) Nikhil Kamkolkar (nikhilk@microsoft.com)
Revision History: 19 Jun 1992 Initial Version (dch@pacvax.pacersoft.com)
Notes: Tab stop: 4 --*/
#define LTTIMER_H_LOCALS
#include "ltmain.h"
#include "lttimer.h"
#include "ltreset.h"
// Define file id for errorlogging
#define FILENUM LTTIMER
VOID LtTimerPoll( IN PVOID SystemSpecific1, IN PVOID Context, IN PVOID SystemSpecific2, IN PVOID SystemSpecific3 ) /*++
Routine Description:
This is the polling timer routine. It will receive data from the card and process all the queues that are there- send/receive/loopback. NOTE: Priority must be given to sends.
Arguments:
Context : Pointer to the Adapter structure. All other parameters as described in NDIS 3.0
Return Value:
None.
--*/ { USHORT ResponseLength; UCHAR Data, ResponseType; LT_INIT_RESPONSE InitPacket; PRECV_DESC RecvDesc; PUCHAR RecvPkt; NDIS_STATUS Status;
BOOLEAN ProcessReset = FALSE;
BOOLEAN ClearCardData = FALSE; PLT_ADAPTER Adapter = (PLT_ADAPTER)Context;
DBGPRINT(DBG_COMP_TIMER, DBG_LEVEL_LOW, ("LtTimerPoll: Entering...\n"));
LtReferenceAdapter(Adapter, &Status); if (Status != NDIS_STATUS_SUCCESS) { // We are probably shutting down.
ASSERTMSG("LtTimerPoll: Adapter not closing!\n", ((Adapter->Flags & ADAPTER_CLOSING) == 0));
// Remove the reference we added at timer set.
LtDeReferenceAdapter(Adapter); return; }
// BUGBUG: Verify reset handling.
// !!! Send's get very high priority. In total, the queue is processed
// !!! three times, twice in the timer and once in LtSend
LtSendProcessQueue(Adapter);
// Check for receive data
NdisRawReadPortUchar(SC_PORT, &Data);
if (Data & RX_READY) { // Get the length of the response on the card
NdisRawReadPortUchar(XFER_PORT, &Data);
ResponseLength = (USHORT)(Data & 0xFF);
NdisRawReadPortUchar(XFER_PORT, &Data);
ResponseLength |= (Data << 8);
// Now get the IO code.
NdisRawReadPortUchar(XFER_PORT, &ResponseType);
DBGPRINT(DBG_COMP_TIMER, DBG_LEVEL_INFO, ("LtPoll: RespType = %x, RespLength = %d\n", ResponseType, ResponseLength));
switch (ResponseType) { case LT_RSP_LAP_INIT:
if (ResponseLength != sizeof(LT_INIT_RESPONSE)) { DBGPRINT(DBG_COMP_TIMER, DBG_LEVEL_ERR, ("LtTimerPoll: Bad response length %lx! \n", ResponseLength));
ClearCardData = TRUE; } break;
case LT_RSP_LAP_FRAME:
// Verify the frame is of the maximum packet size possible.
if (ResponseLength > LT_MAX_PACKET_SIZE) { DBGPRINT(DBG_COMP_TIMER, DBG_LEVEL_ERR, ("LtTimerPoll: Bad packet length %lx! \n", ResponseLength));
// Keep track of number of bad receives
NdisDprAcquireSpinLock(&Adapter->Lock); ++Adapter->GeneralMandatory[GM_RECEIVE_BAD]; NdisDprReleaseSpinLock(&Adapter->Lock);
ClearCardData = TRUE; break; }
// Allocate a receive buffer descriptor for the packet.
NdisAllocateMemory( &RecvDesc, (UINT)(sizeof(RECV_DESC)+ResponseLength), 0, LtNdisPhyAddr);
if (RecvDesc == NULL) { // Keep track of the number of times we couldnt get a buffer.
NdisDprAcquireSpinLock(&Adapter->Lock); ++Adapter->GeneralMandatory[GM_RECEIVE_NO_BUFFER]; NdisDprReleaseSpinLock(&Adapter->Lock);
ClearCardData = TRUE; break; }
// Get a pointer to the receive packet storage.
RecvPkt = (PUCHAR)((PUCHAR)RecvDesc + sizeof(RECV_DESC));
NdisRawReadPortBufferUchar(XFER_PORT, RecvPkt, ResponseLength); RecvDesc->Broadcast = IS_PACKET_BROADCAST(RecvPkt); RecvDesc->BufferLength = ResponseLength; DBGPRINT(DBG_COMP_TIMER, DBG_LEVEL_INFO, ("LtTimerPoll: Recd Pkt Desc %lx Pkt %lx! \n", RecvDesc, RecvPkt));
NdisDprAcquireSpinLock(&Adapter->Lock); ++Adapter->GeneralMandatory[GM_RECEIVE_GOOD]; if (RecvDesc->Broadcast) { ++Adapter->GeneralOptionalFrameCount[GO_BROADCAST_RECEIVES]; LtAddLongToLargeInteger( Adapter->GeneralOptionalByteCount[GO_BROADCAST_RECEIVES], RecvDesc->BufferLength);
Adapter->MediaMandatory[MM_IN_BROADCASTS]++; } else { ++Adapter->GeneralOptionalFrameCount[GO_DIRECTED_RECEIVES]; LtAddLongToLargeInteger( Adapter->GeneralOptionalByteCount[GO_DIRECTED_RECEIVES], RecvDesc->BufferLength); } InsertTailList( &Adapter->Receive, &RecvDesc->Linkage); NdisDprReleaseSpinLock(&Adapter->Lock); break;
case LT_RSP_STATUS:
if (ResponseLength != sizeof(LT_STATUS_RESPONSE)) { ClearCardData = TRUE; break; } NdisRawReadPortBufferUchar(XFER_PORT, (PUCHAR)&Adapter->LastCardStatusResponse, ResponseLength); DBGPRINT(DBG_COMP_TIMER, DBG_LEVEL_INFO, ("Node ID = %lx, Rom Ver = %lx, FirmWare Ver %lx\n", Adapter->LastCardStatusResponse.NodeId, Adapter->LastCardStatusResponse.RomVer, Adapter->LastCardStatusResponse.SwVer));
break;
default: DBGPRINT(DBG_COMP_TIMER, DBG_LEVEL_ERR, ("LtTimerPoll: Unknown response type %lx\n", ResponseType));
ClearCardData = TRUE; break; } }
if (ClearCardData) { DBGPRINT(DBG_COMP_TIMER, DBG_LEVEL_WARN, ("LtTimerPoll: Clearing Card of response %d\n", ResponseLength));
while (ResponseLength-- > 0 ) { NdisRawReadPortUchar(XFER_PORT, &Data); } }
// Call all the processing routines if their respective queues are
// not empty!
NdisDprAcquireSpinLock(&Adapter->Lock);
ASSERT (Adapter->Flags & ADAPTER_NODE_ID_VALID);
if (Adapter->Flags & ADAPTER_RESET_IN_PROGRESS) { ProcessReset = TRUE; } NdisDprReleaseSpinLock(&Adapter->Lock);
if (ProcessReset) { LtResetComplete(Adapter); }
// Process our receive queue.
LtRecvProcessQueue(Adapter);
// Process send queue as processing receives would have entailed
// some sends.
// NOTE: Process LoopQueue after SendQueue as the Send Packet
// goes into the loop queue if it is a broadcast, after
// being sent out on the net.
LtSendProcessQueue(Adapter); LtLoopProcessQueue(Adapter); DBGPRINT(DBG_COMP_TIMER, DBG_LEVEL_LOW, ("LtTimerPoll: Setting timer and Leaving...\n"));
// Re-arm the timer
NdisSetTimer(&Adapter->PollingTimer, LT_POLLING_TIME);
// Remove the reference we added at the beginning of this routine.
LtDeReferenceAdapter(Adapter); }
|