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;
};