www.pudn.com > sdio-2.6.18-full.rar > htc_recv.c
/*
* Copyright (c) 2004-2006 Atheros Communications Inc.
*
* Wireless Network driver for Atheros AR6001
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation;
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
*
* This file contains the routines handling the receive path.
*/
#include "htc_internal.h"
/* ------ Global Variable Declarations ------- */
#ifdef DEBUG
extern A_UINT32 debughtc;
#endif
/* ------ Static Variables ------ */
/* ------ Functions ------ */
/* Makes a buffer available to the HTC module */
A_STATUS
HTCBufferReceive(HTC_TARGET *target,
HTC_ENDPOINT_ID endPointId,
A_UCHAR *buffer,
A_UINT32 length,
void *cookie)
{
A_STATUS status;
HTC_ENDPOINT *endPoint;
HTC_DATA_REQUEST_QUEUE *recvQueue;
AR_DEBUG_PRINTF(ATH_DEBUG_TRC | ATH_DEBUG_RECV,
("HTCBufferReceive: Enter (endPointId: %d, buffer: 0x%p, length: %d, cookie: 0x%p)\n", endPointId, buffer, length, cookie));
AR_DEBUG_ASSERT((endPointId >= ENDPOINT1) && (endPointId <= ENDPOINT4));
/* Extract the end point instance */
endPoint = &target->endPoint[endPointId];
AR_DEBUG_ASSERT(endPoint != NULL);
recvQueue = &endPoint->recvQueue;
AR_DEBUG_PRINTF(ATH_DEBUG_INF | ATH_DEBUG_RECV, ("recvQueue: %p\n",
recvQueue));
/* Add this posted buffer to the pending receive queue */
status = addToMboxQueue(recvQueue, buffer, length, 0, cookie);
if (status != A_OK) {
AR_DEBUG_PRINTF(ATH_DEBUG_ERR | ATH_DEBUG_RECV,
("Mailbox (%d) Send queue full. Unable to add buffer\n",
GET_ENDPOINT_ID(endPoint)));
return A_ERROR;
}
/*
* If this API was called as a result of a HTC_DATA_AVAILABLE event to
* the upper layer, indicating that HTC is out of buffers, then we should
* receive the frame in the buffer supplied otherwise we simply add the
* buffer to the Pending Receive Queue
*/
if (endPoint->rxLengthPending) {
htcReceiveFrame(endPoint);
}
AR_DEBUG_PRINTF(ATH_DEBUG_TRC | ATH_DEBUG_RECV,
("HTCBufferReceive: Exit\n"));
return A_OK;
}
void
htcReceiveFrame(HTC_ENDPOINT *endPoint)
{
A_STATUS status;
A_UINT32 address;
A_UINT32 paddedLength;
A_UINT32 frameLength;
HIF_REQUEST request;
HTC_ENDPOINT_ID endPointId;
HTC_QUEUE_ELEMENT *element;
HTC_MBOX_BUFFER *mboxBuffer;
HTC_DATA_REQUEST_QUEUE *recvQueue;
HTC_TARGET *target;
HTC_EVENT_INFO eventInfo;
HIF_DATAMODE dmode;
AR_DEBUG_PRINTF(ATH_DEBUG_TRC | ATH_DEBUG_RECV,
("htcReceiveFrame - Enter\n"));
/* Get the context */
AR_DEBUG_ASSERT(endPoint != NULL);
endPointId = GET_ENDPOINT_ID(endPoint);
target = endPoint->target;
AR_DEBUG_ASSERT(target != NULL);
recvQueue = &endPoint->recvQueue;
AR_DEBUG_ASSERT(recvQueue != NULL);
/*
* Receive the frame if we have any pending frames and a buffer to
* receive it into.
*/
if (IS_DATA_QUEUE_EMPTY(recvQueue)) {
AR_DEBUG_PRINTF(ATH_DEBUG_WARN | ATH_DEBUG_RECV,
("Mailbox (%d) recv queue empty. Unable to remove buffer\n", endPointId));
/*
* Communicate this situation to the host via the HTC_DATA_AVAILABLE
* event to request some buffers in the queue.
*/
endPoint->rxLengthPending = htcGetFrameLength(endPoint);
AR_DEBUG_ASSERT(endPoint->rxLengthPending);
FRAME_EVENT(eventInfo, NULL, endPoint->rxLengthPending,
0, A_OK, NULL);
dispatchEvent(target, endPointId, HTC_DATA_AVAILABLE, &eventInfo);
return;
}
/*
* Get the length from the lookahead register if there is nothing
* pending.
*/
if (endPoint->rxLengthPending) {
frameLength = endPoint->rxLengthPending;
endPoint->rxLengthPending = 0;
} else {
frameLength = htcGetFrameLength(endPoint);
}
AR_DEBUG_ASSERT((frameLength > 0) &&
(frameLength <= HTC_MESSAGE_SIZE_MAX));
AR_DEBUG_PRINTF(ATH_DEBUG_INF | ATH_DEBUG_RECV, ("Frame Length: %d\n",
frameLength));
/* Adjust the length to be a multiple of block size if appropriate */
paddedLength = (frameLength + (endPoint->blockSize - 1)) &
(~(endPoint->blockSize - 1));
/*
* Receive the frame(s). Pull an empty buffer from the head of the
* Pending Receive Queue.
*/
element = removeFromMboxQueue(recvQueue);
mboxBuffer = GET_MBOX_BUFFER(element);
mboxBuffer->actualLength = paddedLength;
dmode = (endPoint->blockSize > 1) ? HIF_BLOCK_BASIS : HIF_BYTE_BASIS;
HIF_FRAME_REQUEST(&request, HIF_READ, HIF_EXTENDED_IO,
HIF_ASYNCHRONOUS, dmode, HIF_INCREMENTAL_ADDRESS);
address = endPoint->address;
status = HIFReadWrite(target->device, address, mboxBuffer->buffer,
mboxBuffer->actualLength, &request, element);
#ifndef HTC_SYNC
if (status != A_OK) {
#else
if (status != A_OK && status != A_PENDING) {
#endif
AR_DEBUG_PRINTF(ATH_DEBUG_ERR | ATH_DEBUG_RECV,
("Frame reception failed\n"));
if (!IS_ELEMENT_FREE(element)) {
mboxBuffer->actualLength = 0;
FRAME_EVENT(eventInfo, mboxBuffer->buffer,
mboxBuffer->bufferLength, mboxBuffer->actualLength,
A_ECANCELED, mboxBuffer->cookie);
RECYCLE_DATA_REQUEST_ELEMENT(element);
dispatchEvent(target, endPointId, HTC_BUFFER_RECEIVED,
&eventInfo);
AR_DEBUG_PRINTF(ATH_DEBUG_TRC | ATH_DEBUG_RECV,
("htcReceiveFrame - Exit\n"));
return;
}
}
#ifdef HTC_SYNC
else if (status == A_OK) {
element->completionCB(element, status);
}
#endif
AR_DEBUG_PRINTF(ATH_DEBUG_TRC | ATH_DEBUG_RECV,
("htcReceiveFrame - Exit\n"));
}
A_UINT32
htcGetFrameLength(HTC_ENDPOINT *endPoint)
{
HTC_TARGET *target;
A_UINT32 frameLength;
HTC_ENDPOINT_ID endPointId;
/* Get the context */
AR_DEBUG_ASSERT(endPoint != NULL);
target = endPoint->target;
AR_DEBUG_ASSERT(target != NULL);
endPointId = GET_ENDPOINT_ID(endPoint);
AR_DEBUG_ASSERT(target->table.rx_lookahead_valid & (1 << endPointId));
/* The length is contained in the first two bytes - HTC_HEADER_LEN */
frameLength = (target->table.rx_lookahead[endPointId] & 0xFFFF) +
HTC_HEADER_LEN;
AR_DEBUG_ASSERT(frameLength);
return frameLength;
}