goldfish: R.I.P.
[openwrt.git] / target / linux / s3c24xx / files-2.6.30 / drivers / ar6000 / htc / htc_recv.c
1 /*
2  *
3  * Copyright (c) 2007 Atheros Communications Inc.
4  * All rights reserved.
5  *
6  *
7  *  This program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License version 2 as
9  *  published by the Free Software Foundation;
10  *
11  *  Software distributed under the License is distributed on an "AS
12  *  IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
13  *  implied. See the License for the specific language governing
14  *  rights and limitations under the License.
15  *
16  *
17  *
18  */
19
20 #include "htc_internal.h"
21
22 #define HTCIssueRecv(t, p) \
23     DevRecvPacket(&(t)->Device,  \
24                   (p),          \
25                   (p)->ActualLength)
26
27 #define DO_RCV_COMPLETION(t,p,e)            \
28 {                                           \
29     if ((p)->ActualLength > 0) {            \
30         AR_DEBUG_PRINTF(ATH_DEBUG_RECV, (" completing packet 0x%X (%d bytes) on ep : %d \n", \
31             (A_UINT32)(p), (p)->ActualLength, (p)->Endpoint));  \
32         (e)->EpCallBacks.EpRecv((e)->EpCallBacks.pContext,      \
33                                 (p));                           \
34     } else {                                                    \
35         AR_DEBUG_PRINTF(ATH_DEBUG_RECV, (" recycling empty packet \n"));  \
36         HTC_RECYCLE_RX_PKT((t), (p));                           \
37     }                                                           \
38 }
39
40 #ifdef HTC_EP_STAT_PROFILING
41 #define HTC_RX_STAT_PROFILE(t,ep,lookAhead)            \
42 {                                                      \
43     LOCK_HTC_RX((t));                                  \
44     INC_HTC_EP_STAT((ep), RxReceived, 1);              \
45     if ((lookAhead) != 0) {                            \
46         INC_HTC_EP_STAT((ep), RxLookAheads, 1);        \
47     }                                                  \
48     UNLOCK_HTC_RX((t));                                \
49 }
50 #else
51 #define HTC_RX_STAT_PROFILE(t,ep,lookAhead)
52 #endif
53
54 static INLINE A_STATUS HTCProcessTrailer(HTC_TARGET *target,
55                                          A_UINT8    *pBuffer,
56                                          int         Length,
57                                          A_UINT32   *pNextLookAhead,
58                                          HTC_ENDPOINT_ID FromEndpoint)
59 {
60     HTC_RECORD_HDR          *pRecord;
61     A_UINT8                 *pRecordBuf;
62     HTC_LOOKAHEAD_REPORT    *pLookAhead;
63     A_UINT8                 *pOrigBuffer;
64     int                     origLength;
65     A_STATUS                status;
66
67     AR_DEBUG_PRINTF(ATH_DEBUG_RECV, ("+HTCProcessTrailer (length:%d) \n", Length));
68
69     if (AR_DEBUG_LVL_CHECK(ATH_DEBUG_RECV)) {
70         AR_DEBUG_PRINTBUF(pBuffer,Length,"Recv Trailer");
71     }
72
73     pOrigBuffer = pBuffer;
74     origLength = Length;
75     status = A_OK;
76
77     while (Length > 0) {
78
79         if (Length < sizeof(HTC_RECORD_HDR)) {
80             status = A_EPROTO;
81             break;
82         }
83             /* these are byte aligned structs */
84         pRecord = (HTC_RECORD_HDR *)pBuffer;
85         Length -= sizeof(HTC_RECORD_HDR);
86         pBuffer += sizeof(HTC_RECORD_HDR);
87
88         if (pRecord->Length > Length) {
89                 /* no room left in buffer for record */
90             AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
91                 (" invalid record length: %d (id:%d) buffer has: %d bytes left \n",
92                         pRecord->Length, pRecord->RecordID, Length));
93             status = A_EPROTO;
94             break;
95         }
96             /* start of record follows the header */
97         pRecordBuf = pBuffer;
98
99         switch (pRecord->RecordID) {
100             case HTC_RECORD_CREDITS:
101                 AR_DEBUG_ASSERT(pRecord->Length >= sizeof(HTC_CREDIT_REPORT));
102                 HTCProcessCreditRpt(target,
103                                     (HTC_CREDIT_REPORT *)pRecordBuf,
104                                     pRecord->Length / (sizeof(HTC_CREDIT_REPORT)),
105                                     FromEndpoint);
106                 break;
107             case HTC_RECORD_LOOKAHEAD:
108                 AR_DEBUG_ASSERT(pRecord->Length >= sizeof(HTC_LOOKAHEAD_REPORT));
109                 pLookAhead = (HTC_LOOKAHEAD_REPORT *)pRecordBuf;
110                 if ((pLookAhead->PreValid == ((~pLookAhead->PostValid) & 0xFF)) &&
111                     (pNextLookAhead != NULL)) {
112
113                     AR_DEBUG_PRINTF(ATH_DEBUG_RECV,
114                                 (" LookAhead Report Found (pre valid:0x%X, post valid:0x%X) \n",
115                                 pLookAhead->PreValid,
116                                 pLookAhead->PostValid));
117
118                         /* look ahead bytes are valid, copy them over */
119                     ((A_UINT8 *)pNextLookAhead)[0] = pLookAhead->LookAhead[0];
120                     ((A_UINT8 *)pNextLookAhead)[1] = pLookAhead->LookAhead[1];
121                     ((A_UINT8 *)pNextLookAhead)[2] = pLookAhead->LookAhead[2];
122                     ((A_UINT8 *)pNextLookAhead)[3] = pLookAhead->LookAhead[3];
123
124                     if (AR_DEBUG_LVL_CHECK(ATH_DEBUG_RECV)) {
125                         DebugDumpBytes((A_UINT8 *)pNextLookAhead,4,"Next Look Ahead");
126                     }
127                 }
128                 break;
129             default:
130                 AR_DEBUG_PRINTF(ATH_DEBUG_ERR, (" unhandled record: id:%d length:%d \n",
131                         pRecord->RecordID, pRecord->Length));
132                 break;
133         }
134
135         if (A_FAILED(status)) {
136             break;
137         }
138
139             /* advance buffer past this record for next time around */
140         pBuffer += pRecord->Length;
141         Length -= pRecord->Length;
142     }
143
144     if (A_FAILED(status)) {
145         DebugDumpBytes(pOrigBuffer,origLength,"BAD Recv Trailer");
146     }
147
148     AR_DEBUG_PRINTF(ATH_DEBUG_RECV, ("-HTCProcessTrailer \n"));
149     return status;
150
151 }
152
153 /* process a received message (i.e. strip off header, process any trailer data)
154  * note : locks must be released when this function is called */
155 static A_STATUS HTCProcessRecvHeader(HTC_TARGET *target, HTC_PACKET *pPacket, A_UINT32 *pNextLookAhead)
156 {
157     A_UINT8   temp;
158     A_UINT8   *pBuf;
159     A_STATUS  status = A_OK;
160     A_UINT16  payloadLen;
161     A_UINT32  lookAhead;
162
163     pBuf = pPacket->pBuffer;
164
165     AR_DEBUG_PRINTF(ATH_DEBUG_RECV, ("+HTCProcessRecvHeader \n"));
166
167     if (AR_DEBUG_LVL_CHECK(ATH_DEBUG_RECV)) {
168         AR_DEBUG_PRINTBUF(pBuf,pPacket->ActualLength,"HTC Recv PKT");
169     }
170
171     do {
172         /* note, we cannot assume the alignment of pBuffer, so we use the safe macros to
173          * retrieve 16 bit fields */
174         payloadLen = A_GET_UINT16_FIELD(pBuf, HTC_FRAME_HDR, PayloadLen);
175
176         ((A_UINT8 *)&lookAhead)[0] = pBuf[0];
177         ((A_UINT8 *)&lookAhead)[1] = pBuf[1];
178         ((A_UINT8 *)&lookAhead)[2] = pBuf[2];
179         ((A_UINT8 *)&lookAhead)[3] = pBuf[3];
180
181         if (lookAhead != pPacket->HTCReserved) {
182             /* somehow the lookahead that gave us the full read length did not
183              * reflect the actual header in the pending message */
184              AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
185                     ("HTCProcessRecvHeader, lookahead mismatch! \n"));
186              DebugDumpBytes((A_UINT8 *)&pPacket->HTCReserved,4,"Expected Message LookAhead");
187              DebugDumpBytes(pBuf,sizeof(HTC_FRAME_HDR),"Current Frame Header");
188 #ifdef HTC_CAPTURE_LAST_FRAME
189             DebugDumpBytes((A_UINT8 *)&target->LastFrameHdr,sizeof(HTC_FRAME_HDR),"Last Frame Header");
190             if (target->LastTrailerLength != 0) {
191                 DebugDumpBytes(target->LastTrailer,
192                                target->LastTrailerLength,
193                                "Last trailer");
194             }
195 #endif
196             status = A_EPROTO;
197             break;
198         }
199
200             /* get flags */
201         temp = A_GET_UINT8_FIELD(pBuf, HTC_FRAME_HDR, Flags);
202
203         if (temp & HTC_FLAGS_RECV_TRAILER) {
204             /* this packet has a trailer */
205
206                 /* extract the trailer length in control byte 0 */
207             temp = A_GET_UINT8_FIELD(pBuf, HTC_FRAME_HDR, ControlBytes[0]);
208
209             if ((temp < sizeof(HTC_RECORD_HDR)) || (temp > payloadLen)) {
210                 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
211                     ("HTCProcessRecvHeader, invalid header (payloadlength should be :%d, CB[0] is:%d) \n",
212                         payloadLen, temp));
213                 status = A_EPROTO;
214                 break;
215             }
216
217                 /* process trailer data that follows HDR + application payload */
218             status = HTCProcessTrailer(target,
219                                        (pBuf + HTC_HDR_LENGTH + payloadLen - temp),
220                                        temp,
221                                        pNextLookAhead,
222                                        pPacket->Endpoint);
223
224             if (A_FAILED(status)) {
225                 break;
226             }
227
228 #ifdef HTC_CAPTURE_LAST_FRAME
229             A_MEMCPY(target->LastTrailer, (pBuf + HTC_HDR_LENGTH + payloadLen - temp), temp);
230             target->LastTrailerLength = temp;
231 #endif
232                 /* trim length by trailer bytes */
233             pPacket->ActualLength -= temp;
234         }
235 #ifdef HTC_CAPTURE_LAST_FRAME
236          else {
237             target->LastTrailerLength = 0;
238         }
239 #endif
240
241             /* if we get to this point, the packet is good */
242             /* remove header and adjust length */
243         pPacket->pBuffer += HTC_HDR_LENGTH;
244         pPacket->ActualLength -= HTC_HDR_LENGTH;
245
246     } while (FALSE);
247
248     if (A_FAILED(status)) {
249             /* dump the whole packet */
250         DebugDumpBytes(pBuf,pPacket->ActualLength,"BAD HTC Recv PKT");
251     } else {
252 #ifdef HTC_CAPTURE_LAST_FRAME
253         A_MEMCPY(&target->LastFrameHdr,pBuf,sizeof(HTC_FRAME_HDR));
254 #endif
255         if (AR_DEBUG_LVL_CHECK(ATH_DEBUG_RECV)) {
256             if (pPacket->ActualLength > 0) {
257                 AR_DEBUG_PRINTBUF(pPacket->pBuffer,pPacket->ActualLength,"HTC - Application Msg");
258             }
259         }
260     }
261
262     AR_DEBUG_PRINTF(ATH_DEBUG_RECV, ("-HTCProcessRecvHeader \n"));
263     return status;
264 }
265
266 /* asynchronous completion handler for recv packet fetching, when the device layer
267  * completes a read request, it will call this completion handler */
268 void HTCRecvCompleteHandler(void *Context, HTC_PACKET *pPacket)
269 {
270     HTC_TARGET      *target = (HTC_TARGET *)Context;
271     HTC_ENDPOINT    *pEndpoint;
272     A_UINT32        nextLookAhead = 0;
273     A_STATUS        status;
274
275     AR_DEBUG_PRINTF(ATH_DEBUG_RECV, ("+HTCRecvCompleteHandler (status:%d, ep:%d) \n",
276                 pPacket->Status, pPacket->Endpoint));
277
278     AR_DEBUG_ASSERT(pPacket->Endpoint < ENDPOINT_MAX);
279     pEndpoint = &target->EndPoint[pPacket->Endpoint];
280     pPacket->Completion = NULL;
281
282         /* get completion status */
283     status = pPacket->Status;
284
285     do {
286         if (A_FAILED(status)) {
287             AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("HTCRecvCompleteHandler: request failed (status:%d, ep:%d) \n",
288                 pPacket->Status, pPacket->Endpoint));
289             break;
290         }
291             /* process the header for any trailer data */
292         status = HTCProcessRecvHeader(target,pPacket,&nextLookAhead);
293
294         if (A_FAILED(status)) {
295             break;
296         }
297             /* was there a lookahead for the next packet? */
298         if (nextLookAhead != 0) {
299             A_STATUS nextStatus;
300             AR_DEBUG_PRINTF(ATH_DEBUG_RECV,
301                             ("HTCRecvCompleteHandler - next look ahead was non-zero : 0x%X \n",
302                              nextLookAhead));
303                 /* we have another packet, get the next packet fetch started (pipelined) before
304                  * we call into the endpoint's callback, this will start another async request */
305             nextStatus = HTCRecvMessagePendingHandler(target,nextLookAhead,NULL);
306             if (A_EPROTO == nextStatus) {
307                 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
308                             ("Next look ahead from recv header was INVALID\n"));
309                 DebugDumpBytes((A_UINT8 *)&nextLookAhead,
310                                 4,
311                                 "BAD lookahead from lookahead report");
312             }
313         } else {
314              AR_DEBUG_PRINTF(ATH_DEBUG_RECV,
315             ("HTCRecvCompleteHandler - rechecking for more messages...\n"));
316             /* if we did not get anything on the look-ahead,
317              * call device layer to asynchronously re-check for messages. If we can keep the async
318              * processing going we get better performance.  If there is a pending message we will keep processing
319              * messages asynchronously which should pipeline things nicely */
320             DevCheckPendingRecvMsgsAsync(&target->Device);
321         }
322
323         HTC_RX_STAT_PROFILE(target,pEndpoint,nextLookAhead);
324         DO_RCV_COMPLETION(target,pPacket,pEndpoint);
325
326     } while (FALSE);
327
328     if (A_FAILED(status)) {
329          AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
330                          ("HTCRecvCompleteHandler , message fetch failed (status = %d) \n",
331                          status));
332             /* recyle this packet */
333          HTC_RECYCLE_RX_PKT(target, pPacket);
334     }
335
336     AR_DEBUG_PRINTF(ATH_DEBUG_RECV, ("-HTCRecvCompleteHandler\n"));
337 }
338
339 /* synchronously wait for a control message from the target,
340  * This function is used at initialization time ONLY.  At init messages
341  * on ENDPOINT 0 are expected. */
342 A_STATUS HTCWaitforControlMessage(HTC_TARGET *target, HTC_PACKET **ppControlPacket)
343 {
344     A_STATUS        status;
345     A_UINT32        lookAhead;
346     HTC_PACKET      *pPacket = NULL;
347     HTC_FRAME_HDR   *pHdr;
348
349     AR_DEBUG_PRINTF(ATH_DEBUG_RECV,("+HTCWaitforControlMessage \n"));
350
351     do  {
352
353         *ppControlPacket = NULL;
354
355             /* call the polling function to see if we have a message */
356         status = DevPollMboxMsgRecv(&target->Device,
357                                     &lookAhead,
358                                     HTC_TARGET_RESPONSE_TIMEOUT);
359
360         if (A_FAILED(status)) {
361             break;
362         }
363
364         AR_DEBUG_PRINTF(ATH_DEBUG_RECV,
365                 ("HTCWaitforControlMessage : lookAhead : 0x%X \n", lookAhead));
366
367             /* check the lookahead */
368         pHdr = (HTC_FRAME_HDR *)&lookAhead;
369
370         if (pHdr->EndpointID != ENDPOINT_0) {
371                 /* unexpected endpoint number, should be zero */
372             AR_DEBUG_ASSERT(FALSE);
373             status = A_EPROTO;
374             break;
375         }
376
377         if (A_FAILED(status)) {
378                 /* bad message */
379             AR_DEBUG_ASSERT(FALSE);
380             status = A_EPROTO;
381             break;
382         }
383
384         pPacket = HTC_ALLOC_CONTROL_RX(target);
385
386         if (pPacket == NULL) {
387             AR_DEBUG_ASSERT(FALSE);
388             status = A_NO_MEMORY;
389             break;
390         }
391
392         pPacket->HTCReserved = lookAhead;
393         pPacket->ActualLength = pHdr->PayloadLen + HTC_HDR_LENGTH;
394
395         if (pPacket->ActualLength > pPacket->BufferLength) {
396             AR_DEBUG_ASSERT(FALSE);
397             status = A_EPROTO;
398             break;
399         }
400
401             /* we want synchronous operation */
402         pPacket->Completion = NULL;
403
404             /* get the message from the device, this will block */
405         status = HTCIssueRecv(target, pPacket);
406
407         if (A_FAILED(status)) {
408             break;
409         }
410
411             /* process receive header */
412         status = HTCProcessRecvHeader(target,pPacket,NULL);
413
414         pPacket->Status = status;
415
416         if (A_FAILED(status)) {
417             AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
418                     ("HTCWaitforControlMessage, HTCProcessRecvHeader failed (status = %d) \n",
419                      status));
420             break;
421         }
422
423             /* give the caller this control message packet, they are responsible to free */
424         *ppControlPacket = pPacket;
425
426     } while (FALSE);
427
428     if (A_FAILED(status)) {
429         if (pPacket != NULL) {
430                 /* cleanup buffer on error */
431             HTC_FREE_CONTROL_RX(target,pPacket);
432         }
433     }
434
435     AR_DEBUG_PRINTF(ATH_DEBUG_RECV,("-HTCWaitforControlMessage \n"));
436
437     return status;
438 }
439
440 /* callback when device layer or lookahead report parsing detects a pending message */
441 A_STATUS HTCRecvMessagePendingHandler(void *Context, A_UINT32 LookAhead, A_BOOL *pAsyncProc)
442 {
443     HTC_TARGET      *target = (HTC_TARGET *)Context;
444     A_STATUS         status = A_OK;
445     HTC_PACKET      *pPacket = NULL;
446     HTC_FRAME_HDR   *pHdr;
447     HTC_ENDPOINT    *pEndpoint;
448     A_BOOL          asyncProc = FALSE;
449
450     AR_DEBUG_PRINTF(ATH_DEBUG_RECV,("+HTCRecvMessagePendingHandler LookAhead:0x%X \n",LookAhead));
451
452     if (IS_DEV_IRQ_PROCESSING_ASYNC_ALLOWED(&target->Device)) {
453             /* We use async mode to get the packets if the device layer supports it.
454              * The device layer interfaces with HIF in which HIF may have restrictions on
455              * how interrupts are processed */
456         asyncProc = TRUE;
457     }
458
459     if (pAsyncProc != NULL) {
460             /* indicate to caller how we decided to process this */
461         *pAsyncProc = asyncProc;
462     }
463
464     while (TRUE) {
465
466         pHdr = (HTC_FRAME_HDR *)&LookAhead;
467
468         if (pHdr->EndpointID >= ENDPOINT_MAX) {
469             AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Invalid Endpoint in look-ahead: %d \n",pHdr->EndpointID));
470                 /* invalid endpoint */
471             status = A_EPROTO;
472             break;
473         }
474
475         if (pHdr->PayloadLen > HTC_MAX_PAYLOAD_LENGTH) {
476             AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Payload length %d exceeds max HTC : %d !\n",
477                     pHdr->PayloadLen, HTC_MAX_PAYLOAD_LENGTH));
478             status = A_EPROTO;
479             break;
480         }
481
482         pEndpoint = &target->EndPoint[pHdr->EndpointID];
483
484         if (0 == pEndpoint->ServiceID) {
485             AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Endpoint %d is not connected !\n",pHdr->EndpointID));
486                 /* endpoint isn't even connected */
487             status = A_EPROTO;
488             break;
489         }
490
491             /* lock RX to get a buffer */
492         LOCK_HTC_RX(target);
493
494             /* get a packet from the endpoint recv queue */
495         pPacket = HTC_PACKET_DEQUEUE(&pEndpoint->RxBuffers);
496
497         if (NULL == pPacket) {
498                 /* check for refill handler */
499             if (pEndpoint->EpCallBacks.EpRecvRefill != NULL) {
500                 UNLOCK_HTC_RX(target);
501                     /* call the re-fill handler */
502                 pEndpoint->EpCallBacks.EpRecvRefill(pEndpoint->EpCallBacks.pContext,
503                                                     pHdr->EndpointID);
504                 LOCK_HTC_RX(target);
505                     /* check if we have more buffers */
506                 pPacket = HTC_PACKET_DEQUEUE(&pEndpoint->RxBuffers);
507                     /* fall through */
508             }
509         }
510
511         if (NULL == pPacket) {
512                 /* this is not an error, we simply need to mark that we are waiting for buffers.*/
513             target->HTCStateFlags |= HTC_STATE_WAIT_BUFFERS;
514             target->EpWaitingForBuffers = pHdr->EndpointID;
515             status = A_NO_MEMORY;
516         }
517
518         UNLOCK_HTC_RX(target);
519
520         if (A_FAILED(status)) {
521                 /* no buffers */
522             break;
523         }
524
525         AR_DEBUG_ASSERT(pPacket->Endpoint == pHdr->EndpointID);
526
527             /* make sure this message can fit in the endpoint buffer */
528         if ((pHdr->PayloadLen + HTC_HDR_LENGTH) > pPacket->BufferLength) {
529             AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
530                     ("Payload Length Error : header reports payload of: %d, endpoint buffer size: %d \n",
531                     pHdr->PayloadLen, pPacket->BufferLength));
532             status = A_EPROTO;
533             break;
534         }
535
536         pPacket->HTCReserved = LookAhead; /* set expected look ahead */
537             /* set the amount of data to fetch */
538         pPacket->ActualLength = pHdr->PayloadLen + HTC_HDR_LENGTH;
539
540         if (asyncProc) {
541                 /* we use async mode to get the packet if the device layer supports it
542                  * set our callback and context */
543             pPacket->Completion = HTCRecvCompleteHandler;
544             pPacket->pContext = target;
545         } else {
546                 /* fully synchronous */
547             pPacket->Completion = NULL;
548         }
549
550             /* go fetch the packet */
551         status = HTCIssueRecv(target, pPacket);
552
553         if (A_FAILED(status)) {
554             break;
555         }
556
557         if (asyncProc) {
558                 /* we did this asynchronously so we can get out of the loop, the asynch processing
559                  * creates a chain of requests to continue processing pending messages in the
560                  * context of callbacks  */
561             break;
562         }
563
564             /* in the sync case, we process the packet, check lookaheads and then repeat */
565
566         LookAhead = 0;
567         status = HTCProcessRecvHeader(target,pPacket,&LookAhead);
568
569         if (A_FAILED(status)) {
570             break;
571         }
572
573         HTC_RX_STAT_PROFILE(target,pEndpoint,LookAhead);
574         DO_RCV_COMPLETION(target,pPacket,pEndpoint);
575
576         pPacket = NULL;
577
578         if (0 == LookAhead) {
579             break;
580         }
581
582     }
583
584     if (A_NO_MEMORY == status) {
585         AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
586                 (" Endpoint :%d has no buffers, blocking receiver to prevent overrun.. \n",
587                 pHdr->EndpointID));
588             /* try to stop receive at the device layer */
589         DevStopRecv(&target->Device, asyncProc ? DEV_STOP_RECV_ASYNC : DEV_STOP_RECV_SYNC);
590         status = A_OK;
591     } else if (A_FAILED(status)) {
592         AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
593                         ("Failed to get pending message : LookAhead Value: 0x%X (status = %d) \n",
594                         LookAhead, status));
595         if (pPacket != NULL) {
596                 /* clean up packet on error */
597             HTC_RECYCLE_RX_PKT(target, pPacket);
598         }
599     }
600
601     AR_DEBUG_PRINTF(ATH_DEBUG_RECV,("-HTCRecvMessagePendingHandler \n"));
602
603     return status;
604 }
605
606 /* Makes a buffer available to the HTC module */
607 A_STATUS HTCAddReceivePkt(HTC_HANDLE HTCHandle, HTC_PACKET *pPacket)
608 {
609     HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
610     HTC_ENDPOINT *pEndpoint;
611     A_BOOL       unblockRecv = FALSE;
612     A_STATUS     status = A_OK;
613
614     AR_DEBUG_PRINTF(ATH_DEBUG_SEND,
615                     ("+- HTCAddReceivePkt: endPointId: %d, buffer: 0x%X, length: %d\n",
616                     pPacket->Endpoint, (A_UINT32)pPacket->pBuffer, pPacket->BufferLength));
617
618     do {
619
620         if (HTC_STOPPING(target)) {
621             status = A_ECANCELED;
622             break;
623         }
624
625         AR_DEBUG_ASSERT(pPacket->Endpoint < ENDPOINT_MAX);
626
627         pEndpoint = &target->EndPoint[pPacket->Endpoint];
628
629         LOCK_HTC_RX(target);
630
631             /* store receive packet */
632         HTC_PACKET_ENQUEUE(&pEndpoint->RxBuffers, pPacket);
633
634             /* check if we are blocked waiting for a new buffer */
635         if (target->HTCStateFlags & HTC_STATE_WAIT_BUFFERS) {
636             if (target->EpWaitingForBuffers == pPacket->Endpoint) {
637                 AR_DEBUG_PRINTF(ATH_DEBUG_RECV,(" receiver was blocked on ep:%d, unblocking.. \n",
638                     target->EpWaitingForBuffers));
639                 target->HTCStateFlags &= ~HTC_STATE_WAIT_BUFFERS;
640                 target->EpWaitingForBuffers = ENDPOINT_MAX;
641                 unblockRecv = TRUE;
642             }
643         }
644
645         UNLOCK_HTC_RX(target);
646
647         if (unblockRecv && !HTC_STOPPING(target)) {
648                 /* TODO : implement a buffer threshold count? */
649             DevEnableRecv(&target->Device,DEV_ENABLE_RECV_SYNC);
650         }
651
652     } while (FALSE);
653
654     return status;
655 }
656
657 static void HTCFlushEndpointRX(HTC_TARGET *target, HTC_ENDPOINT *pEndpoint)
658 {
659     HTC_PACKET  *pPacket;
660
661     LOCK_HTC_RX(target);
662
663     while (1) {
664         pPacket = HTC_PACKET_DEQUEUE(&pEndpoint->RxBuffers);
665         if (NULL == pPacket) {
666             break;
667         }
668         UNLOCK_HTC_RX(target);
669         pPacket->Status = A_ECANCELED;
670         pPacket->ActualLength = 0;
671         AR_DEBUG_PRINTF(ATH_DEBUG_RECV, ("  Flushing RX packet:0x%X, length:%d, ep:%d \n",
672                 (A_UINT32)pPacket, pPacket->BufferLength, pPacket->Endpoint));
673             /* give the packet back */
674         pEndpoint->EpCallBacks.EpRecv(pEndpoint->EpCallBacks.pContext,
675                                       pPacket);
676         LOCK_HTC_RX(target);
677     }
678
679     UNLOCK_HTC_RX(target);
680
681
682 }
683
684 void HTCFlushRecvBuffers(HTC_TARGET *target)
685 {
686     HTC_ENDPOINT    *pEndpoint;
687     int             i;
688
689         /* NOTE: no need to flush endpoint 0, these buffers were
690          * allocated as part of the HTC struct */
691     for (i = ENDPOINT_1; i < ENDPOINT_MAX; i++) {
692         pEndpoint = &target->EndPoint[i];
693         if (pEndpoint->ServiceID == 0) {
694                 /* not in use.. */
695             continue;
696         }
697         HTCFlushEndpointRX(target,pEndpoint);
698     }
699
700
701 }
702
703