www.pudn.com > 2410winceCE_l80t64.rar > Send.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" 
 
 
void PurgeTransmitQueue(PCHIP pChip); 
void  CopyPacketToChip( PCHIP pChip ); 
WORD  BidForTransmit( PCHIP pChip ); 
 
 
 
extern 
NDIS_STATUS 
CrystalSend( 
    IN NDIS_HANDLE MiniportAdapterContext, 
    IN PNDIS_PACKET Packet, 
    IN UINT SendFlags 
    ) 
 
/*++ 
 
Routine Description: 
 
    The CrystalSend request instructs a driver to transmit a packet through 
    the adapter onto the medium. 
 
Arguments: 
 
    MiniportAdapterContext - Context registered with the wrapper, really 
        a pointer to the Virtual Protocol context. 
 
    Packet - A pointer to a descriptor for the packet that is to be 
    transmitted. 
 
    SendFlags - Optional send flags 
 
Return Value: 
 
    The function value is the status of the operation. 
 
--*/ 
 
{ 
 
    UINT                    PacketLength; 
    PTRANSMIT_QUEUE_ELEMENT TxPacket; 
    PCD                     pData; 
    
    VPM_SetupMiniContext; 
 
    pData = pChip->pData; 
 
//    DbgPrint("\nCs8900a(): Send() \n"); 
 
	// 
	//put in VC20Send checks 
	// 
     if ((pChip->Config.DetectedMediaType == MEDIA_NONE) || 
         (pChip->Config.DetectedMediaType == MEDIA_PENDING)) 
     { 
       pvMini_Context->XmitErrors++; 
       return NDIS_STATUS_SUCCESS; 
     }  
 
     
    NdisQueryPacket( Packet,0L,0L,0L,&PacketLength); 
   
 
   if ( (PacketLength > CRYSTAL_INDICATE_MAXIMUM) || 
        (PacketLength < CRYSTAL_MINIMUM_FRAME_SIZE)) { 
      pvMini_Context->XmitErrors++; 
      return NDIS_STATUS_SUCCESS; 
   } 
 
    
   TxPacket = (PTRANSMIT_QUEUE_ELEMENT) &Packet->MiniportReserved; 
   TxPacket->PacketSize = PacketLength; 
 
     
   ENQ_PACKET( TxPacket, pData->TransmitQueue ); 
 
 
     if (!(pData->TransmitInProgress)) { 
        pData->TransmitInProgress = TRUE; 
        if ( BidForTransmit(pChip) == SUCCESS ) { 
           CopyPacketToChip(pChip); 
        } 
     } /* endif */ 
 
	 
return NDIS_STATUS_PENDING; 
 
 
} 
 
#ifndef NDIS30_MINIPORT 
 
extern 
VOID CrystalSendPackets( 
         IN NDIS_HANDLE  MiniportAdapterContext, 
         IN PPNDIS_PACKET  PacketArray, 
         IN UINT  NumberOfPackets 
         ) 
{ 
        UINT i; 
        NDIS_STATUS Status; 
 
//    DbgPrint("\nCs8900a(): SendPackets()\n"); 
 
    for (i=0; iXmitErrors++; 
      if (Errors & TX_ERR_EXCESS_COLL){ 
         pvMini_Context->XmitMaxCollisions++; 
      } 
      if (Errors & TX_ERR_UNDERRUN){ 
         pvMini_Context->XmitUnderrun++; 
      } 
      if (Errors & TX_ERR_LOSS_CRS){ 
         pvMini_Context->XmitLostCRS++; 
      } 
 
}; 
 
 
void PurgeTransmitQueue(PCHIP pChip) 
{ 
   PCD   pData = pChip->pData; 
   PTRANSMIT_QUEUE_ELEMENT TxPacket; 
   PVPMINIPDATA pvMini_Context = (PVPMINIPDATA)(pChip->pPSD);  
   NDIS_HANDLE MiniportAdapterHandle = pvMini_Context->vpMiniportAdapterHandle;  
   PNDIS_PACKET	Packet; 
 
   DEQ_PACKET(&TxPacket, pData->TransmitQueue); 
 
   while(TxPacket != NULL) 
   { 
     
      pvMini_Context->XmitOKs++; 
    
      Packet = CONTAINING_RECORD(TxPacket,NDIS_PACKET,MiniportReserved);	 
      
      NdisMSendComplete(MiniportAdapterHandle, 
                              Packet, 
                              NDIS_STATUS_SUCCESS 
                              ); 
      
      DEQ_PACKET(&TxPacket, pData->TransmitQueue) 
 
   } /* endfor */ 
 
}; 
 
void  CopyPacketToChip( PCHIP pChip ) 
{ 
   PORT  IOBase = pChip->Config.IOBase; 
   PCD   pData = pChip->pData; 
   // 
   // Holds the virtual address of the current buffer. 
   // 
   PVOID VirtualAddress; 
   // 
   // Holds the length of the current buffer of the packet. 
   // 
   DWORD CurrentLength; 
   // 
   // Holds the length of the Packet. 
   // 
   DWORD BytesToCopy; 
   // 
   // Keep a local variable of BytesCopied so we aren't referencing 
   // through a pointer. 
   // 
   DWORD LocalBytesCopied = 0; 
   // 
   // First packet to be processed. 
   // 
   PTRANSMIT_QUEUE_ELEMENT TxPacket; 
   // 
   // This flag indicates that an odd byte is to be transferred in the previous 
   // fragment which is to be transferred with a byte from next fragment 
   // 
   WORD OddWordFlag   = FALSE; 
   // 
   // The variable to store the odd byte to be transferred with the next 
   // fragment. 
   // 
   WORD OddWordValue   = 0; 
 
   WORD    i; 
   PNDIS_BUFFER pNDISBuffer; 
   PNDIS_PACKET	Packet; 
 
#if defined(SHx_PROCESSOR) 
   /* "&dwAligned" is aligned to a 32 bit boundary address. */  
   DWORD dwAligned;  
#elif defined(ARM_PROCESSOR) 
   /* "&wAligned1" is aligned to a 16 bit boundary address. */  
   WORD wAligned1;  
#endif 
 
   TxPacket = pData->TransmitQueue.Head; 
   if (TxPacket == NULL) { 
      return; 
   } /* endif */ 
    
   BytesToCopy = TxPacket->PacketSize; 
   
   Packet = CONTAINING_RECORD(TxPacket,NDIS_PACKET,MiniportReserved);	 
 
     
   NdisQueryPacket( Packet,0L,0L,&pNDISBuffer,0L); 
 
   
   NdisQueryBuffer(pNDISBuffer,&VirtualAddress,&CurrentLength); 
 
   
   while (LocalBytesCopied < BytesToCopy) { 
 
      while (!CurrentLength) { 
 
         NdisGetNextBuffer(pNDISBuffer,&pNDISBuffer); 
		 NdisQueryBuffer(pNDISBuffer,&VirtualAddress,&CurrentLength); 
 
      } 
 
      LocalBytesCopied += CurrentLength; 
 
      // 
      // Copy the data. 
      // 
      // 
      //   Decrement the fragment length left to be transmitted as a byte 
      // from this fragment was transmitted with a byte left to be 
      //   transmitted from previous fragment. 
      // 
 
 
      if(OddWordFlag) { 
 
         OddWordValue |= ((USHORT)(*(PUCHAR)VirtualAddress)) << 8; 
         NdisRawWritePortUshort((PORT)(IOBase+CRYSTAL_TRANSMIT_FRAME_PORT), 
                    OddWordValue ); 
         CurrentLength--; 
         OddWordFlag = FALSE; 
         OddWordValue=0; 
         ((PUCHAR)VirtualAddress)++; 
      } 
 
 
  
	   
#if defined(ARM_PROCESSOR) 
	  /* ARM can read/write only 16 bit data at a time under WinCE.  
	     NdisRawWritePortUlong() does NOT work for ARM.*/ 
	  if ( (ULONG)VirtualAddress & 0x1 != 0) { 
         for (i=0; i < CurrentLength/2; i++) { 
           /* for ARM 16 bit data-write alignment*/ 
		    /* VirtualAddress may not point to a 16 bit boundary address.  Use  
			memcpy() to move data from unaligned memory to aligned memory. 
			It works since memcpy() casts pointers it copies to char* */ 
            memcpy(&wAligned1, (WORD*)VirtualAddress, sizeof(WORD)); 
            NdisRawWritePortUshort((PORT)(IOBase+CRYSTAL_TRANSMIT_FRAME_PORT),wAligned1 ); 
            ++((WORD*)VirtualAddress); 
         } /* end for */ 
	  } /* end if */ 
	  else { 
         for (i=0; i < CurrentLength/2; i++) { 
            NdisRawWritePortUshort((PORT)(IOBase+CRYSTAL_TRANSMIT_FRAME_PORT), 
                    *((PWORD)VirtualAddress)++ ); 
		 } /* end for */ 
	  }	/* end else */ 
 
 
	  if ( CurrentLength % 2 == 1 ) { 
            // 
            // Store the byte from the current fragment to be transmitted 
            // with the next fragment and set the odd_bytes flag. 
            // 
            OddWordValue = *((PUCHAR)VirtualAddress); 
            OddWordFlag  = TRUE; 
      } 
 
#elif defined(SHx_PROCESSOR) 
	  if ( (ULONG)VirtualAddress & 0x3 != 0) { 
         for (i=0; i < CurrentLength/4; i++) { 
           /* for SHx 32bit-alignment*/ 
		    /* VirtualAddress may not point to a 32bit boundary address.  Use  
			memcpy() to move data from unaligned memory to aligned memory. 
			It works since memcpy() casts pointers it copies to char* */ 
            memcpy(&dwAligned, (DWORD*)VirtualAddress, sizeof(DWORD)); 
            NdisRawWritePortUlong((PORT)(IOBase+CRYSTAL_TRANSMIT_FRAME_PORT),dwAligned ); 
            ++((DWORD*)VirtualAddress); 
		 } /* end for */ 
	  } /* end if */ 
	  else { 
         for (i=0; i < CurrentLength/4; i++) { 
            NdisRawWritePortUlong((PORT)(IOBase+CRYSTAL_TRANSMIT_FRAME_PORT), 
                    *((PDWORD)VirtualAddress)++ ); 
		 } /* endfor */ 
	  }	/* end else */ 
 
#else 
      for (i=0; i < CurrentLength/4; i++) { 
         NdisRawWritePortUlong((PORT)(IOBase+CRYSTAL_TRANSMIT_FRAME_PORT), 
                    *((PDWORD)VirtualAddress)++ ); 
      } /* end for */ 
#endif 
 
#ifndef ARM_PROCESSOR  
      switch (CurrentLength%4) { 
 
         case 1: 
            // 
            // Store the byte from the current fragment to be transmitted 
            // with the next fragment and set the odd_bytes flag. 
            // 
            OddWordValue = *((PUCHAR)VirtualAddress); 
            OddWordFlag  = TRUE; 
            break; 
 
         case 2: 
 
            NdisRawWritePortUshort((PORT)(IOBase+CRYSTAL_TRANSMIT_FRAME_PORT), 
                       *((PUSHORT)VirtualAddress) ); 
			/* @melody 10/19/2001*/ 
           ((PUSHORT)VirtualAddress)++; 
             break; 
 
         case 3: 
            NdisRawWritePortUshort((PORT)(IOBase+CRYSTAL_TRANSMIT_FRAME_PORT), 
                       *((PUSHORT)VirtualAddress) ); 
            ((PUSHORT)VirtualAddress)++; 
            OddWordValue = *((PUCHAR)VirtualAddress); 
            OddWordFlag  = TRUE; 
            break; 
      } 
#endif 
 
      CurrentLength = 0; 
 
   } // end of while loop. 
 
 
   if(OddWordFlag) { 
      NdisRawWritePortUshort((PORT)(IOBase+CRYSTAL_TRANSMIT_FRAME_PORT), 
                 OddWordValue ); 
   } 
 
 
}; 
 
WORD  BidForTransmit( PCHIP pChip ) 
{ 
   WORD Data; 
   PCD   pData = pChip->pData; 
   PORT  IOBase = pChip->Config.IOBase; 
 
 
#ifdef CEDEBUG 
       DEBUGINT3 
#endif 
   pData->TransmitStarted = TRUE; 
   NdisRawWritePortUshort((PORT)(IOBase+CRYSTAL_TRANSMIT_COMMAND_PORT), 
                     pData->TransmitCommand ); 
 
   NdisRawWritePortUshort((PORT)(IOBase+CRYSTAL_TRANSMIT_LENGTH_PORT), 
              pData->TransmitQueue.Head->PacketSize); 
 
   // 
   // Now, check whether the chip is ready to transmit by checking the 
   // Ready for transmit bit of the BusStatusRegister. 
   // 
 
   NdisRawWritePortUshort( (PORT)(IOBase+CRYSTAL_ADDRESS_PORT), 
               CRYSTAL_BUS_STATUS_REGISTER ); 
 
   NdisRawReadPortUshort( (PORT)(IOBase+CRYSTAL_DATA_PORT), &Data ); 
 
 
   if(Data & CRYSTAL_BSR_TX_BID_ERROR) { 
       pData->StartTX = TRUE;  // Better start another TX at end of next interrupt 
                             // Assumes Receives are cause of bid failure 
       return FAILURE; 
   } 
 
   if(Data & CRYSTAL_BSR_READY_FOR_TRANSMIT_NOW) { 
       return SUCCESS; 
   } 
   else pData->TransmitBidPending = TRUE; 
 
   return FAILURE; 
};