📄 hal.c
字号:
//
// NAME uiHALcopyPacket
//
// PARAMETERS paucSA Pointer to location where ethernet source
// address should be placed.
// paucDA Pointer to location where ethernet destination
// address should be placed.
// psPayloadDesc Pointer to buffer descriptor where the payload
// should be copied to.
// psSrcPkt Pointer to packet descriptor where the data
// should be copied from.
//
// RETURNS The length of the packet including the ethernet header.
//
// DESCRIPTION This function is used to copy the contents of a Packet supplied
// by a protocol driver into a physically contiguous buffer
// allocated within the driver i.e. ensures that the packet is
// completely contained in one memory page.
//
//-----------------------------------------------------------------------------
ULONG
uiHALcopyPacket(
PUCHAR paucSA,
PUCHAR paucDA,
PUCHAR psPayloadDesc,
PNDIS_PACKET psSrcPkt
)
{
ULONG uiPktLength = 0;
ULONG uiBufLength;
PVOID pvSrcAddr;
PUCHAR paucPayloadBuf;
BOOLEAN boFirst = TRUE;
ULONG uiPhysicalBufferCount;
PNDIS_BUFFER psSrcBuf;
paucPayloadBuf = psPayloadDesc;
NdisQueryPacket( psSrcPkt, &uiPhysicalBufferCount, NULL, &psSrcBuf, &uiPktLength );
while ( psSrcBuf != NULL )
{
#ifdef NDIS51_MINIPORT
NdisQueryBufferSafe( psSrcBuf, &pvSrcAddr, &uiBufLength, HighPagePriority );
#else
NdisQueryBuffer( psSrcBuf, &pvSrcAddr, &uiBufLength );
#endif
if ( pvSrcAddr != NULL )
{
if ( boFirst )
{
// We assume the first buffer must include at least the Ethernet header.
ASSERT ( uiBufLength >= DAT_SIZE_ETHERNET_HDR );
if ( uiBufLength >= DAT_SIZE_ETHERNET_HDR )
{
ETH_COPY_NETWORK_ADDRESS( paucSA, DAT_ETHERNET_SRC(pvSrcAddr) );
ETH_COPY_NETWORK_ADDRESS( paucDA, DAT_ETHERNET_DEST(pvSrcAddr) );
uiBufLength -= (DAT_SIZE_ETHERNET_HDR - DAT_SIZE_ETHERNET_TYPE);
pvSrcAddr = (PVOID)((ULONG)pvSrcAddr + (DAT_SIZE_ETHERNET_HDR - DAT_SIZE_ETHERNET_TYPE));
}
// add LLC and SNAP headers - but not including SNAP type.
*paucPayloadBuf++ = 0xAA; // DSAP
*paucPayloadBuf++ = 0xAA; // SSAP
*paucPayloadBuf++ = 0x03; // cntl
*paucPayloadBuf++ = 0x00; // org code[3]
*paucPayloadBuf++ = 0x00;
*paucPayloadBuf++ = 0x00;
// Only take out addresses and add snap with the first fragment of the chained buffer.
boFirst = FALSE;
}
OS_MEMCPY( paucPayloadBuf, pvSrcAddr, uiBufLength );
paucPayloadBuf += uiBufLength;
}
NdisGetNextBuffer( psSrcBuf, &psSrcBuf );
}
return uiPktLength;
}
//-----------------------------------------------------------------------------
//
// NAME vHALflushTxQueues
//
// PARAMETERS psAdapter Pointer to adapter context.
//
// RETURNS None
//
// DESCRIPTION This routine flushes all packets in the internal TX queues,
// typically on shutdown, etc.
//
//-----------------------------------------------------------------------------
VOID
vHALflushTxQueues( PEND_CONTEXT psAdapter )
{
PHAL_CONTEXT psHAL = &psAdapter->sHAL;
UINT uiLoop;
UINT uiNxtHead;
PNDIS_PACKET pPacket;
TRACE(TRACE_CFSD_NDHAL, 0);
DBG_LEV1(("Flushing TX queues\n"));
for (uiLoop = 0; uiLoop < 4; uiLoop++)
{
while (psHAL->ulQueueHeads[uiLoop] != psHAL->ulQueueTails[uiLoop])
{
uiNxtHead = (psHAL->ulQueueHeads[uiLoop] + 1) % HAL_TX_QUEUE_LEN;
pPacket = psHAL->apTxQueues[uiLoop][uiNxtHead];
psHAL->ulQueueHeads[uiLoop] = uiNxtHead;
NdisMSendComplete(psAdapter->hMiniportAdapterHandle,
pPacket,
NDIS_STATUS_FAILURE );
}
}
}
//-----------------------------------------------------------------------------
//
// NAME vHALpushTxToImem
//
// PARAMETERS psAdapter Pointer to adapter context.
//
// RETURNS void
//
// DESCRIPTION This is the target of the workqueue for serializing TX requests.
//
//-----------------------------------------------------------------------------
void vHALpushTxToImem(void *psAdapter)
{
TRACE(TRACE_CFSD_NDHAL, 0);
// push to imem as many as possible
while (bHAL_PickAndSendPacket(psAdapter) == TRUE);
TRACE(TRACE_CFSD_NDHAL, 0);
}
//-----------------------------------------------------------------------------
//
// NAME iHAL_PickAndSendPacket
//
// PARAMETERS psAdapter Pointer to adapter context.
//
// RETURNS boolean - TRUE if packet sent, FALSE otherwise
//
// DESCRIPTION This routine picks the next packet to enter imem based on
// a priority weighted random choice, and starts the packet TX
// if there is an imem space available.
//
//-----------------------------------------------------------------------------
BOOLEAN bHAL_PickAndSendPacket(PEND_CONTEXT psAdapter)
{
PHAL_CONTEXT psHAL = &psAdapter->sHAL;
UINT uiRange;
UINT uiRand;
UINT uiLoop;
UINT uiPriority = 1;
UINT uiNxtHead;
BOOLEAN ret;
int iStatus;
PNDIS_PACKET pPacket;
static long idum = 0;
// relative odds of sending priorities background, best effort,
// video, voice - so VOICE is 273/65 times more likely to go out
// than best effort.
static UINT uiPriOdds[4] = {65, 105, 195, 273};
TRACE(TRACE_CFSD_NDHAL, 0);
// make sure we can send TX packets ...
if (psAdapter->eNetState != NET_CONNECTED)
{
return FALSE;
}
if ( psHAL->ePowerState != HAL_PS_AWAKE )
{
DBG_LEV2(("Tx resources, power state = 0x%x\n", psHAL->ePowerState));
TRACE(TRACE_CFSD_NDHAL, psHAL->ePowerState);
if ( psHAL->ePowerState == HAL_PS_ASLEEP )
{
psHAL->ePowerState = HAL_PS_WAKING;
// Try to wake up the device.
vHALwakeupDevice( psHAL );
}
return FALSE;
}
// choose a packet priority ...
uiRange = 0;
for (uiLoop = 0; uiLoop < 4; uiLoop++)
{
if (psHAL->ulQueueHeads[uiLoop] != psHAL->ulQueueTails[uiLoop])
{
uiRange += uiPriOdds[uiLoop];
}
}
// No more packets in queue, nothing to do.
if ( uiRange == 0 )
{
TRACE(TRACE_CFSD_NDHAL, 0);
return FALSE;
}
// check whether there is space available ...
if ( psHAL->sTxBuf[psHAL->ulTxBufferIndex].boBufAvail != TRUE )
{
psAdapter->boSendNoResourcesFlag = TRUE;
TRACE(TRACE_CFSD_NDHAL, 0);
return FALSE;
}
uiRange--;
uiRand = (unsigned int)((uiGenRand( &idum ) * (ULONGLONG)uiRange) / RND_MAX);
uiRange = 0;
for (uiLoop = 0; uiLoop < 4; uiLoop++)
{
if (psHAL->ulQueueHeads[uiLoop] != psHAL->ulQueueTails[uiLoop])
{
uiRange += uiPriOdds[uiLoop];
if (uiRand < uiRange)
{
uiPriority = uiLoop;
break;
}
}
}
ASSERT(uiLoop < 4);
ASSERT(psHAL->ulQueueHeads[uiPriority] != psHAL->ulQueueTails[uiPriority]);
// try to send the packet ...
uiNxtHead = (psHAL->ulQueueHeads[uiPriority] + 1) % HAL_TX_QUEUE_LEN;
pPacket = psHAL->apTxQueues[uiPriority][uiNxtHead];
psHAL->ulQueueHeads[uiPriority] = uiNxtHead;
iStatus = iHALsendPacket(
&psAdapter->sHAL,
pPacket,
(uint32)NDIS_PER_PACKET_INFO_FROM_PACKET(
pPacket,
Ieee8021pPriority)
);
if (iStatus == 0)
{
// No more packets can be sent at this time - leave
// remainder pending.
psAdapter->boSendNoResourcesFlag = TRUE;
}
// if failure, maybe we should try to requeue???
// return packet descriptor to NDIS
NdisMSendComplete(psAdapter->hMiniportAdapterHandle,
pPacket,
NDIS_STATUS_SUCCESS);
if (iStatus == 0)
{
// No more packets can be sent at this time - leave
// remainder pending.
ret = FALSE;
}
else if ( iStatus == 1 )
{
// remove packet from queue ...
psAdapter->sStats.ulTotalPktsTxedOk++;
ret = TRUE;
}
else
{
// HAL not running. Leave packets pending for now.
psAdapter->sStats.ulTotalPktsTxedError++;
ret = FALSE;
}
TRACE(TRACE_CFSD_NDHAL, ret);
return ret;
}
//-----------------------------------------------------------------------------
//
// NAME iHALsendPacket
//
// PARAMETERS psHAL Pointer to HAL context.
// psPktDesc Packet pointer.
//
// RETURNS -1 for failure, 0 for out of resources, 1 for success
//
// DESCRIPTION This routine send a packet to Target.
//
//-----------------------------------------------------------------------------
int
iHALsendPacket(
IN PHAL_CONTEXT psHAL,
IN PNDIS_PACKET psPktDesc,
IN uint32 ulPriority
)
{
int iStatus = -1;
ULONG ulBufferIndex, ulLoopIndex;
UMI_DATA *psData;
PUCHAR paucPayloadBuf;
ULONG ulLength;
ULONG ulAddrTarget;
TRACE(TRACE_CFSD_NDHAL, ulPriority);
if ( psHAL->eState != HAL_RUNNING )
{
DBG_LEV0(("ERROR: Attempt to send packet in invalid state, %d.\n", psHAL->eState));
TRACE(TRACE_CFSD_NDHAL, psHAL->eState);
}
else if ( psHAL->ePowerState != HAL_PS_AWAKE )
{
DBG_LEV2(("Tx resources, power state = 0x%x\n", psHAL->ePowerState));
TRACE(TRACE_CFSD_NDHAL, psHAL->ePowerState);
// Ask upper to queue the packet if not under AWAKE state.
iStatus = 0;
if ( psHAL->ePowerState == HAL_PS_ASLEEP )
{
psHAL->ePowerState = HAL_PS_WAKING;
// Try to wake up the device.
vHALwakeupDevice( psHAL );
}
}
else
{
ulLoopIndex = 0;
ulBufferIndex = psHAL->ulTxBufferIndex;
if ( psHAL->sTxBuf[ulBufferIndex].boBufAvail == TRUE )
{
psHAL->sTxBuf[ulBufferIndex].boBufAvail = FALSE;
// Adjust the Tx buffer index.
psHAL->ulTxBufferIndex = (ulBufferIndex + 1) % psHAL->ulTxBufNum;
}
else
{
ulLoopIndex = psHAL->ulTxBufNum;
}
if ( ulLoopIndex >= psHAL->ulTxBufNum )
{
// No free Tx buffer.
iStatus = 0;
}
else
{
ulAddrTarget = psHAL->sTxBuf[ulBufferIndex].ulBufAddr;
psData = (UMI_DATA *)psHAL->sTxBuf[ulBufferIndex].pulocalAddr;
paucPayloadBuf = (PUCHAR)psData + sizeof(UMI_DATA);
// Copy the packet to Tx buffer.
ulLength = uiHALcopyPacket(
psData->sSA.au8Addr,
psData->sDA.au8Addr,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -