www.pudn.com > 2410winceCE_l80t64.rar > ISR.C


//--------------------------------------------------------------------------- 
// 
//  Copyright (C) 1996-1997. Unpublished Work of Crystal Semiconductor Corp. 
//  All Rights Reserved. 
// 
//  THIS WORK IS AN UNPUBLISHED WORK AND CONTAINS CONFIDENTIAL, 
//  PROPRIETARY AND TRADE SECRET INFORMATION OF CRYSTAL SEMICONDUCTOR. 
//  ACCESS TO THIS WORK IS RESTRICTED TO (I) CRYSTAL SEMICONDUCTOR EMPLOYEES 
//  WHO HAVE A NEED TO KNOW TO PERFORM TASKS WITHIN THE SCOPE OF THEIR 
//  ASSIGNMENTS  AND (II) ENTITIES OTHER THAN CRYSTAL SEMICONDUCTOR WHO 
//  HAVE ENTERED INTO  APPROPRIATE LICENSE AGREEMENTS.  NO PART OF THIS 
//  WORK MAY BE USED, PRACTICED, PERFORMED, COPIED, DISTRIBUTED, REVISED, 
//  MODIFIED, TRANSLATED, ABRIDGED, CONDENSED, EXPANDED, COLLECTED, 
//  COMPILED,LINKED,RECAST, TRANSFORMED, ADAPTED IN ANY FORM OR BY ANY 
//  MEANS,MANUAL, MECHANICAL, CHEMICAL, ELECTRICAL, ELECTRONIC, OPTICAL, 
//  BIOLOGICAL, OR OTHERWISE WITHOUT THE PRIOR WRITTEN PERMISSION AND 
//  CONSENT OF CRYSTAL SEMICONDUCTOR . ANY USE OR EXPLOITATION OF THIS WORK 
//  WITHOUT THE PRIOR WRITTEN CONSENT OF CRYSTAL SEMICONDUCTOR  COULD 
//  SUBJECT THE PERPETRATOR TO CRIMINAL AND CIVIL LIABILITY. 
// 
//--------------------------------------------------------------------------- 
 
#include "cs8900a.h" 
#include "cshrd.h" 
 
 
 
 
// External Prototypes 
 
void  CopyPacketToChip( IN PCHIP ); 
WORD  BidForTransmit( IN PCHIP ); 
void  PurgeTransmitQueue( IN PCHIP ); 
void  ReceivePacket( IN PCHIP, IN WORD ); 
void  ReceiveEarlyPacket( IN PCHIP, IN WORD  ); 
 
// Local Prototypes 
 
void ProcessReceiveInterrupts(IN PCHIP, IN WORD ); 
void ProcessTransmitInterrupts(IN PCHIP, IN WORD ); 
void ProcessBufferInterrupts(IN PCHIP, IN WORD ); 
void ProcessRxOverflowInterrupts(IN PCHIP, IN WORD ); 
void ProcessTxOverflowInterrupts(IN PCHIP, IN WORD ); 
 
typedef void (*VC20_ISQHANDLER)(IN PCHIP, IN WORD ); 
#define MAX_ISQ_EVENTS 5 
 
VC20_ISQHANDLER IsqEventHandler[MAX_ISQ_EVENTS] = { 
                  ProcessReceiveInterrupts, 
                  ProcessTransmitInterrupts, 
                  ProcessBufferInterrupts, 
                  ProcessRxOverflowInterrupts, 
                  ProcessTxOverflowInterrupts, 
                  }; 
 
 
 
 
 
VOID 
CrystalDisableInterrupt( 
    IN  NDIS_HANDLE MiniportAdapterContext 
    ) 
{ 
   //QQQQQQQQQQQ Why mark out? VchipDisableInterrupts( ((PVPMINIPDATA)MiniportAdapterContext)->pChip ); 
 
VchipDisableInterrupts( ((PVPMINIPDATA)MiniportAdapterContext)->pChip ); 
 
 //   DbgPrint("\nCs8900a(): DisableInterrupt() \n"); 
    return; 
} 
 
VOID 
CrystalEnableInterrupt( 
    IN  NDIS_HANDLE MiniportAdapterContext 
    ) 
/*++ 
 
Routine Description: 
 
    This routine is used to turn on all interrupts from the adapter. 
 
Arguments: 
 
    MiniportAdapterContext - A pointer to the VP context 
 
Return Value: 
 
    None. 
 
--*/ 
{ 
 
    VPM_SetupMiniContext; 
    VchipEnableInterrupts( ((PVPMINIPDATA)MiniportAdapterContext)->pChip ); 
//    DbgPrint("\nCs8900a(): EnableInterrupt\n"); 
    return; 
 
} 
 
extern 
VOID 
CrystalInterruptService( 
    OUT PBOOLEAN InterruptRecognized, 
    OUT PBOOLEAN QueueDpc, 
    IN  PVOID Context 
    ) 
 
/*++ 
 
Routine Description: 
 
    Interrupt service routine.  This routine only gets 
    called during initial initialization of the adapter. 
 
Arguments: 
 
    InterruptRecognized - Boolean value which returns TRUE if the 
        ISR recognizes the interrupt as coming from this adapter. 
 
    QueueDpc - TRUE if a DPC should be queued. 
 
    Context - Really a pointer to the adapter. 
 
Return Value: 
 
    Returns true if the card ISR is non-zero. 
 
--*/ 
 
{ 
 
 
   NDIS_HANDLE MiniportAdapterContext = Context; 
   VPM_SetupMiniContext; 
 
 
//    DbgPrint("\nCs8900a(): InterruptService()\n"); 
 
      *InterruptRecognized = TRUE; 
      *QueueDpc = TRUE; 
 
 
 
   return; 
 
} 
 
VOID 
CrystalHandleInterrupt( 
    IN NDIS_HANDLE MiniportAdapterContext 
    ) 
 
/*++ 
 
Routine Description: 
 
    This DPR routine is queued by the wrapper after every interrupt 
    and also by other routines within the driver that notice that 
    some deferred processing needs to be done.  It's main 
    job is to call the interrupt processing code. 
 
Arguments: 
 
    MiniportAdapterContext - Really a pointer to the adapter. 
 
Return Value: 
 
    None. 
 
--*/ 
 
{ 
 
   WORD  Result=TRUE; 
   VPM_SetupMiniContext; 
 
//    DbgPrint("\nCs8900a(): HandleInterrupt 1\n"); 
 
   if (pvMini_Context->CurrentState == NdisHardwareStatusInitializing) { 
      return; 
   } /* endif */ 
 
 
   while (Result) {  // Loop until ISR indicates there was nothing to do 
 
      Result = VchipISR( pvMini_Context->pChip ); 
 
   } /* endwhile */ 
 
    VchipEnableInterrupts (pvMini_Context->pChip ); 
 
//     DbgPrint("\nCs8900a(): HandleInterrupt 2\n"); 
 
	 return; 
 
 } 
 
 
 
 
 
WORD VchipISR( PCHIP pChip ) 
{ 
   WORD  IsqEvent; 
   WORD  EventIndex; 
   PORT  IOBase = pChip->Config.IOBase; 
   PCD   pData = pChip->pData; 
   WORD  BidStatus; 
   WORD  Status=FALSE; 
   WORD  regNum; 
 
   pData->NeedToIssueRcvCmpltFlag = FALSE; 
    
 
   /* Ignore spurrious interrupt that occurs while resetting */ 
   if ( pData->Resetting ) return Status; 
 
 
   do {  // While ISQ != 0 
 
      //  Read ISQ 
      NdisRawReadPortUshort((PORT)(IOBase+CRYSTAL_ISQ_PORT), &IsqEvent  ); 
 
      if (IsqEvent != 0) { 
         Status=TRUE; 
      
         regNum = IsqEvent & CRYSTAL_ISQ_EVENT_MASK; 
         if (regNum == 0x12) //TxCol event 
         { 
             // @melody 11/05/2002 
             // The register number of Tx Collision Counter is not multiple of 4  
             // so we should calculate it separately. 
             EventIndex = 5; 
         } 
         else  
         { 
             EventIndex = regNum/4; 
         }  
 
         if (--EventIndex < MAX_ISQ_EVENTS) { 
            IsqEventHandler[EventIndex](pChip, IsqEvent); 
         } /* endif */ 
      } /* endif */ 
 
 
   } while ( IsqEvent != 0 ); /* enddo */ 
 
 
   if (pData->NeedToIssueRcvCmpltFlag == TRUE) { 
      PVPMINIPDATA pvMini_Context = (PVPMINIPDATA)(pChip->pPSD);  
      NDIS_HANDLE MiniportAdapterHandle = pvMini_Context->vpMiniportAdapterHandle;  
 
      NdisMEthIndicateReceiveComplete( MiniportAdapterHandle ); 
   } /* endif */ 
 
 
 
   // Transmits are handled outside of ISQ Loop to prioritize Receive 
   if ((pData->StartTX) && (pData->TransmitQueue.Head != NULL)) { 
 
      pData->StartTX = FALSE; 
      if (!pData->TransmitBidPending) { 
         BidStatus = BidForTransmit(pChip); 
      } /* endif */ 
      if ((pData->TransmitBidPending) ||  // StartTX & TransmitBidPending means ReadyForTX received 
          (BidStatus == SUCCESS)) { 
         pData->TransmitBidPending = FALSE; 
         CopyPacketToChip(pChip); 
      } 
   } else { 
      pData->StartTX = FALSE; 
   } /* endif */ 
 
   return Status; 
 
} 
 
 
void ProcessReceiveInterrupts( PCHIP pChip, WORD IsqEvent ) 
{ 
   PORT  IOBase = pChip->Config.IOBase; 
   PCD   pData = pChip->pData; 
   WORD  Errors = 0; 
 
   if ( IsqEvent & CRYSTAL_RER_PACKET_RECEIVED_OK) { 
 
      ReceivePacket( pChip, IsqEvent ); 
 
   } else { 
      // 
      // A receive error occurred 
      // 
 
      if (IsqEvent & CRYSTAL_RER_CRC_ERROR) { 
         Errors |= RX_ERR_CRC_ERROR; 
 
         if(IsqEvent & CRYSTAL_RER_DRIBBLE) { 
            Errors |= RX_ERR_DRIBBLE; 
         } 
      } 
      if (IsqEvent & CRYSTAL_RER_EXTRA_DATA) { 
         Errors |= RX_ERR_EXTRA_DATA; 
      } 
      if (IsqEvent & CRYSTAL_RER_RUNT) { 
         Errors |= RX_ERR_RUNT; 
      } 
      VpsRecvError( pChip, Errors ); 
   } 
}; 
 
void ProcessTransmitInterrupts( PCHIP pChip, WORD IsqEvent ) 
{ 
   PORT  IOBase = pChip->Config.IOBase; 
   PCD   pData = pChip->pData; 
   WORD  Errors = 0; 
   WORD  Collisions = 0; 
   PTRANSMIT_QUEUE_ELEMENT TxPacket; 
   PNDIS_PACKET Packet; 
   PVPMINIPDATA pvMini_Context = (PVPMINIPDATA)(pChip->pPSD);  
   NDIS_HANDLE MiniportAdapterHandle = pvMini_Context->vpMiniportAdapterHandle;  
 
 
   // 
   // We first in any transmit event must  decrement the counter of the 
   // underrun Threshold 
   // 
 
   if ( pData->TransmitThresholdCount != 0) { 
      (pData->TransmitThresholdCount)--; 
   } 
 
   // 
   // Check if the packet completed OK, and update statistics. 
   // 
      if (IsqEvent & CRYSTAL_TER_EXCESSIVE_COLLISIONS) { 
         Errors |= TX_ERR_EXCESS_COLL; 
      } 
      Collisions = (INT)(IsqEvent & CRYSTAL_TER_COLLISIONS_MASK) >> CRYSTAL_TER_COLLISIONS_SHIFT; 
 
      if (IsqEvent & CRYSTAL_TER_JABBER) { 
         Errors |= TX_ERR_JABBER; 
      } 
 
 
      if (IsqEvent & CRYSTAL_TER_OUT_OF_WINDOW) { 
         Errors |= TX_ERR_OUT_OF_WIN; 
      } 
 
 
   // Dequeue the Packet 
   DEQ_PACKET(&TxPacket, pData->TransmitQueue); 
 
   if (TxPacket != NULL) { 
    
      Packet = CONTAINING_RECORD(TxPacket,NDIS_PACKET,MiniportReserved);	 
 
      if (IsqEvent & CRYSTAL_TER_LOST_CRS) Errors |= TX_ERR_LOSS_CRS; 
      if (IsqEvent & CRYSTAL_TER_SQE_ERROR) Errors |= TX_ERR_SQE_ERROR; 
      if (Errors) { 
         VpsSendError( pChip,Errors ); 
      } /* endif */ 
     
       
      
   	  if (Collisions == 1) { 
   	     pvMini_Context->XmitOneCollisions++; 
   	  } else if (Collisions > 1) { 
   	     pvMini_Context->XmitMoreCollisions++; 
   	  } /* endif */ 
      
      
      pvMini_Context->XmitOKs++; 
      
 
      NdisMSendComplete(MiniportAdapterHandle, 
                              Packet, 
                              NDIS_STATUS_SUCCESS 
                              ); 
 
   } /* endif */ 
 
 
   // 
   // If there is a packet in the transmit queue then try 
   // transmitting it at the end of the ISR 
   // 
   if (pData->TransmitQueue.Head != NULL ) { 
      pData->StartTX = TRUE; 
   } else { 
      pData->TransmitInProgress = FALSE; 
   } 
 
}; 
 
void ProcessBufferInterrupts( PCHIP pChip, WORD IsqEvent ) 
{ 
   PORT  IOBase = pChip->Config.IOBase; 
   PCD   pData = pChip->pData; 
 
   // 
   // Then check for READY_FOR_TRANSMIT 
   // 
   if (IsqEvent & CRYSTAL_BER_READY_FOR_TRANSMIT) { 
 
 
      if (pData->TransmitQueue.Head != NULL) { 
         pData->TransmitBidPending = FALSE; 
         pData->StartTX = FALSE; 
         CopyPacketToChip( pChip ); 
      } 
   } 
 
   // 
   // If TX_UNDERRUN occured then update counters. 
   // 
   if (IsqEvent & CRYSTAL_BER_TX_UNDERRUN) { 
 
      if (pData->TransmitQueue.Head != NULL) {  // Resend current Frame 
         VpsSendError( pChip,TX_ERR_UNDERRUN ); 
         pData->StartTX = TRUE; 
      } 
      // 
      //  We have a underrun so we see if we have exceeded the threshold 
      //  if so go to next transmit command 
      // 
 
      (pData->TransmitThresholdCount)++; 
 
      if( pData->TransmitThresholdCount == UNDERRUN_THRESHOLD){ 
 
         (pData->TransmitThresholdCount)= 0; 
 
         if (pData->TransmitCommand < CRYSTAL_TCR_TX_START_ALL_BYTES) { 
 
            pData->TransmitCommand += CRYSTAL_TCR_TX_START_381_BYTES; 
 
         } 
      } 
   } 
 
}; 
 
void ProcessRxOverflowInterrupts( PCHIP pChip, WORD IsqEvent ) 
{ 
   PCD   pData = pChip->pData; 
   IsqEvent = IsqEvent >> 6; 
   do { 
      VpsRecvError( pChip, RX_ERR_OVERRUN ); 
   } while (--IsqEvent !=0); 
}; 
 
void ProcessTxOverflowInterrupts( PCHIP pChip, WORD IsqEvent ) 
{ 
   PCD   pData = pChip->pData; 
   if (pData->TransmitQueue.Head != NULL) {  // Resend current Frame 
      VpsSendError( pChip, TX_ERR_FRAME_ABORT ); // May need better RC here 
   } 
}; 
 
 
 
 
void VchipEnableInterrupts( PCHIP pChip ) 
{ 
 
   WORD  Data; 
   PORT  IOBase = pChip->Config.IOBase; 
 
   if ( ((PCD)(pChip->pData))->Resetting ) return; 
 
   // 
   // Enable  BUS_CTL register Interrupt Enable. 
   // 
 
   NdisRawWritePortUshort((PORT)(IOBase+CRYSTAL_ADDRESS_PORT), 
               CRYSTAL_BUS_CONTROL_REGISTER); 
 
   NdisRawReadPortUshort((PORT)(IOBase+CRYSTAL_DATA_PORT), &Data); 
 
   NdisRawWritePortUshort((PORT)(IOBase+CRYSTAL_DATA_PORT), 
               Data | CRYSTAL_BCR_INTERRUPT_ENABLE); 
 
 
 
}; 
 
 
void VchipDisableInterrupts( PCHIP pChip ) 
{ 
 
 
   WORD  Data; 
   PORT  IOBase = pChip->Config.IOBase; 
 
   if ( ((PCD)(pChip->pData))->Resetting ) return; 
   // 
   // Disable  BUS_CTL register Interrupt Enable. 
   // 
 
   NdisRawWritePortUshort((PORT)(IOBase+CRYSTAL_ADDRESS_PORT), 
               CRYSTAL_BUS_CONTROL_REGISTER); 
 
   NdisRawReadPortUshort((PORT)(IOBase+CRYSTAL_DATA_PORT), &Data); 
 
   NdisRawWritePortUshort((PORT)(IOBase+CRYSTAL_DATA_PORT), 
              Data &(~CRYSTAL_BCR_INTERRUPT_ENABLE) ); 
 
 
};