?? car6ktx.cpp
字號:
//------------------------------------------------------------------------------
// <copyright file="car6ktx.cpp" company="Atheros and Microsoft">
// Copyright (c) 2006 Microsoft Corporation. All rights reserved.
// Copyright (c) 2006 Atheros Corporation. All rights reserved.
//
// The use and distribution terms for this software are covered by the
// Microsoft Limited Permissive License (Ms-LPL)
// http://www.microsoft.com/resources/sharedsource/licensingbasics/limitedpermissivelicense.mspx
// which can be found in the file MS-LPL.txt at the root of this distribution.
// By using this software in any fashion, you are agreeing to be bound by
// the terms of this license.
//
// You must not remove this notice, or any other, from this software.
// </copyright>
//
// <summary>
// Windows CE Wifi Driver for AR-6000
// </summary>
//------------------------------------------------------------------------------
//==============================================================================
// AR6000 NDIS Miniport driver packet transmit functions.
//
// Author(s): ="Atheros and Microsoft"
//==============================================================================
#include <windows.h>
#include <ndis.h>
#include "htc_internal.h"
#include "htc.h"
#include "wmi_api.h"
#include "netbuf.h"
#include "ndisnetbuf.h"
extern "C" {
#include "bmi.h"
}
#include "cmini.hpp"
#include "c802_3mini.hpp"
#include "c802_11mini.hpp"
#include "car6k.hpp"
#include "osapi.h"
NDIS_STATUS
CAR6KMini::TransmitBufferBuild(
OUT AR6K_TRANSMIT_BUFFER *pTxBuffer,
IN NDIS_PACKET *pNdisPacket)
//
// This function is called to convert the data in an NDIS_PACKET
// into a contiguous block of data in the format required by the
// AR6K Wireless Module.
//
// The format of a packet sent to the Wireless Module looks like:
// WMI_DATA_HDR:
// UINT8 reserved (always 0)
// UINT8 msgType = 0 (data)
// 802_3_HDR:
// UINT8[6] dstMac
// UINT8[6] srcMac
// UINT8[2] length
// SNAP_HDR:
// UINT8 DSAP = 0xAA
// UINT8 SSAP = 0xAA
// UINT8 CNTL = 0x03
// UINT8[3] CODE = {0x00 0x00 0x00)
// UINT8[2] EthType (e.g. 0x08 00 for IP packet)
// PAYLOAD:
// UINT8[length] packet payload that follows 802_3 header (e.g. IP packet)
{
NDIS_STATUS Status = NDIS_STATUS_INVALID_DATA;
PNDIS_BUFFER pNdisBuffer;
PBYTE pBufferData;
ULONG cbBufferData;
USHORT EthLength;
PBYTE pTxData;
ULONG cbTxDataSpaceRemaining;
boolean bIsDIX = false;
NdisQueryPacketFirstBuffer(pNdisPacket, &pNdisBuffer);
if (NULL == pNdisBuffer)
goto done;
// The first buffer should contain the 802.3 MAC header
NdisQueryBuffer(pNdisBuffer, &pBufferData, &cbBufferData);
if (cbBufferData < sizeof(ETHERNET_MAC_HEADER))
goto done;
pTxBuffer->pNdisPacket = pNdisPacket;
WMI_DATA_HDR_SET_MSG_TYPE( &(pTxBuffer->WMIDataHeader), DATA_MSGTYPE);
// Copy the source and destination MAC addresses
memcpy(&pTxBuffer->MACHeader.DestMACAddress[0], pBufferData, ETHERNET_MAC_ADDRESS_LENGTH * 2);
pBufferData += ETHERNET_MAC_ADDRESS_LENGTH * 2;
cbBufferData -= ETHERNET_MAC_ADDRESS_LENGTH * 2;
// Check the 2 bytes after the dest and source MAC addresses to see if
// they are a length (802.3 format packet) or a type (DIX format)
EthLength = (pBufferData[0] << 8) | pBufferData[1];
if (EthLength <= 0x0600)
{
// Length field is the length in bytes,
// Packet is already in 802.3 format
pTxData = (PBYTE)&pTxBuffer->MACHeader.Length;
}
else
{
// Packet is in DIX format, we will need to insert length field and SNAP header
// to convert it into the 802.3 format that the AR6K requires.
bIsDIX = true;
pTxBuffer->SNAPHeader.dsap = 0xAA;
pTxBuffer->SNAPHeader.ssap = 0xAA;
pTxBuffer->SNAPHeader.cntl = 0x03;
pTxBuffer->SNAPHeader.orgCode[0] = 0;
pTxBuffer->SNAPHeader.orgCode[1] = 0;
pTxBuffer->SNAPHeader.orgCode[2] = 0;
pTxData = (PBYTE)&pTxBuffer->SNAPHeader.Type;
}
cbTxDataSpaceRemaining = (&pTxBuffer->PayloadData[0] - pTxData) + m_MaxTransmitBufferPayloadDataLength;
// Copy remaining data from first buffer, and data from
// all remaining buffers in the NDIS_PaCKET, into the
// contiguous WMI_DATA output buffer
while (TRUE)
{
if (cbBufferData > cbTxDataSpaceRemaining)
{
Status = NDIS_STATUS_BUFFER_TOO_SHORT;
break;
}
NdisMoveMemory(pTxData, pBufferData, cbBufferData);
pTxData += cbBufferData;
cbTxDataSpaceRemaining -= cbBufferData;
NdisGetNextBuffer(pNdisBuffer, &pNdisBuffer);
if (pNdisBuffer == NULL)
{
// Copied all the buffers. Fill in the Ethernet length field if needed
if (bIsDIX)
{
// For an 802.3 packet, the EthLength field is the number of bytes in the Data payload field
EthLength = pTxData - (PBYTE)&pTxBuffer->SNAPHeader;
pTxBuffer->MACHeader.Length = A_CPU2BE16(EthLength);
}
pTxBuffer->cbWMIData = pTxData - (PBYTE)&pTxBuffer->WMIDataHeader;
Status = NDIS_STATUS_SUCCESS;
break;
}
NdisQueryBuffer(pNdisBuffer, &pBufferData, &cbBufferData);
}
done:
return Status;
}
NDIS_STATUS
CAR6KMini::TransmitBufferListAllocate()
//
// Allocate m_MaxTransmitBuffers and put them on the m_TransmitBufferList
//
{
NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
PAR6K_TRANSMIT_BUFFER pTransmitBuffer;
ULONG cbTransmitBuffer = offsetof(AR6K_TRANSMIT_BUFFER, PayloadData) + m_MaxTransmitBufferPayloadDataLength;
// ULONG align the size of a transmit buffer
cbTransmitBuffer = (cbTransmitBuffer + 3) & ~3;
// Allocate the block of storage to hold all the transmit buffers
m_cbTransmitBufferArray = cbTransmitBuffer * m_MaxTransmitBuffers;
m_pTransmitBufferArray = (PAR6K_TRANSMIT_BUFFER)A_MALLOC(m_cbTransmitBufferArray);
if (m_pTransmitBufferArray == NULL)
goto done;
// Put all the transmit buffers on the free list
pTransmitBuffer = &m_pTransmitBufferArray[0];
for (ULONG iBuffer = 0; iBuffer < m_MaxTransmitBuffers; iBuffer++)
{
pTransmitBuffer->pNdisPacket = NULL;
pTransmitBuffer->cbWMIData = 0;
InsertTailList(&m_TransmitBufferList, &pTransmitBuffer->node);
pTransmitBuffer = (PAR6K_TRANSMIT_BUFFER)((PBYTE)pTransmitBuffer + cbTransmitBuffer);
}
done:
return Status;
}
PAR6K_TRANSMIT_BUFFER
CAR6KMini::TransmitBufferListRemoveHead()
//
// This function is called to get the first available transmit buffer
// from the free list. If none are available, then NULL will be returned.
//
{
PAR6K_TRANSMIT_BUFFER pBuffer = NULL;
Lock();
if (!IsListEmpty(&m_TransmitBufferList))
pBuffer = (PAR6K_TRANSMIT_BUFFER)RemoveHeadList(&m_TransmitBufferList);
Unlock();
return pBuffer;
}
void
CAR6KMini::TransmitBufferListInsertHead(
PAR6K_TRANSMIT_BUFFER pBuffer)
//
// This function is called to return a transmit buffer to the free list.
//
{
Lock();
pBuffer->pNdisPacket = NULL;
InsertHeadList(&m_TransmitBufferList, &pBuffer->node);
Unlock();
}
PNDIS_PACKET
CAR6KMini::TransmitNdisPacketListRemoveHead()
//
// Get the first packet from the list of pending send packets.
//
{
PNDIS_PACKET pPacket = NULL;
PLIST_ENTRY pNode;
Lock();
if (!IsListEmpty(&m_TransmitNdisPacketList))
{
pNode = RemoveHeadList(&m_TransmitNdisPacketList);
pPacket = (PNDIS_PACKET)((PBYTE)pNode - offsetof(NDIS_PACKET, MiniportReservedEx));
}
Unlock();
return pPacket;
}
void
CAR6KMini::TransmitNdisPacketListInsertTail(
PNDIS_PACKET pPacket)
//
// This function is called to add a packet to the list of packets
// waiting for transmit buffers to become available so they can be sent.
//
{
PLIST_ENTRY pNode = (PLIST_ENTRY)pPacket->MiniportReservedEx;
Lock();
InsertHeadList(&m_TransmitNdisPacketList, pNode);
Unlock();
}
void
CAR6KMini::SendNdisPacket(
PNDIS_PACKET pPacket,
PAR6K_TRANSMIT_BUFFER pTxBuffer)
//
// Send the specified NDIS_PACKET using the provided buffer.
//
{
NDIS_STATUS Status;
A_STATUS htcStatus;
#ifdef WMM
HTC_ENDPOINT_ID endPointId;
ndis_mini_buf_t osbuf;
A_UINT8 *pData = NULL;
IEEE8021PPRIORITY ndisUserPriority;
#endif
Status = TransmitBufferBuild(pTxBuffer, pPacket);
if (NDIS_STATUS_SUCCESS == Status)
{
#ifdef WMM
/* wmi APIs work with buf structures. So create a dummy buf here to pass to wmi.
* The data pointer in the buf is hacked to point to the WMIDataHeader.
*/
ndisUserPriority=(IEEE8021PPRIORITY)NDIS_PER_PACKET_INFO_FROM_PACKET(pPacket,Ieee8021pPriority);
memset(&osbuf, 0, sizeof(ndis_mini_buf_t));
osbuf.buf_dat = (PBYTE)&pTxBuffer->WMIDataHeader;
Lock();
endPointId = wmi_get_endpoint((wmi_t *)m_pWMI,
wmi_implicit_create_pstream((wmi_t *)m_pWMI, &osbuf, UPLINK_TRAFFIC, (A_UINT32)ndisUserPriority));
Unlock();
#endif
// Send the data to the device
#ifdef WMM
htcStatus = HTCBufferSend(m_pHTCTarget, endPointId, (PBYTE)&pTxBuffer->WMIDataHeader, pTxBuffer->cbWMIData, pTxBuffer);
#else
htcStatus = HTCBufferSend(m_pHTCTarget, ENDPOINT2, (PBYTE)&pTxBuffer->WMIDataHeader, pTxBuffer->cbWMIData, pTxBuffer);
#endif
if (A_PENDING == htcStatus)
Status = NDIS_STATUS_PENDING;
else if (A_OK == htcStatus)
Status = NDIS_STATUS_PENDING; // HTCBufferSend seems to return A_OK even when the send pends
else
Status = NDIS_STATUS_FAILURE;
}
if (NDIS_STATUS_PENDING != Status)
{
// If the packet isn't queued, complete it immediately
NDIS_DEBUG_PRINTF(ATH_LOG_ERR, "AR6K: NDIS - SEND Complete %x FAILURE=%x\n", pPacket, Status);
NdisMSendComplete(m_MiniportAdapterHandle, pPacket, Status);
TransmitBufferListInsertHead(pTxBuffer);
}
}
void
CAR6KMini::HTCDataSendCompleted(
PVOID cookie)
//
// This function is called when an HTCBufferSend request completes on
// the an endpoint used for data packets. It completes the send and
// returns the transmit buffer back to the free list.
//
{
PAR6K_TRANSMIT_BUFFER pTxBuffer = (PAR6K_TRANSMIT_BUFFER)cookie;
PNDIS_PACKET pNdisPacket = pTxBuffer->pNdisPacket;
NDIS_DEBUG_PRINTF(ATH_LOG_SEND, "AR6K: NDIS - SEND Complete %x\n", pNdisPacket);
NdisMSendComplete(m_MiniportAdapterHandle, pNdisPacket, NDIS_STATUS_SUCCESS);
pNdisPacket = TransmitNdisPacketListRemoveHead();
if (pNdisPacket)
{
// pending list is not empty, use the buffer to send the first queued packet
SendNdisPacket(pNdisPacket, pTxBuffer);
}
else
{
// nothing pending to transmit, just add the buffer to the free list
TransmitBufferListInsertHead(pTxBuffer);
}
}
void
CAR6KMini::SendPackets(
IN PPNDIS_PACKET PacketArray,
IN UINT NumberOfPackets)
//
// This function is called by NDIS to send packets through
// the adapter to the network.
//
{
UINT i;
PAR6K_TRANSMIT_BUFFER pTxBuffer;
PNDIS_PACKET pNdisPacket;
if (!m_Connected) {
NDIS_DEBUG_PRINTF(ATH_LOG_ERR, "AR6K: NDIS - SEND Packet failed - Not connected to the network \n");
for (i = 0; i < NumberOfPackets; i++)
{
pNdisPacket = PacketArray[i];
NdisMSendComplete(m_MiniportAdapterHandle, pNdisPacket, NDIS_STATUS_FAILURE);
}
return;
}
for (i = 0; i < NumberOfPackets; i++)
{
pNdisPacket = PacketArray[i];
NDIS_DEBUG_PRINTF(ATH_LOG_SEND, "AR6K: NDIS - SEND Packet %x\n", pNdisPacket);
pTxBuffer = TransmitBufferListRemoveHead();
if (pTxBuffer == NULL)
{
// Out of transmit buffers, we will have to queue
// up the remaining packets to be transmitted when
// buffers become available.
break;
}
SendNdisPacket(pNdisPacket, pTxBuffer);
}
// Add to the queue all the packets that were not transmitted in the
// above loop because all the transmit buffers were in use.
for (; i < NumberOfPackets; i++)
{
pNdisPacket = PacketArray[i];
TransmitNdisPacketListInsertTail(pNdisPacket);
}
}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -