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
54static 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 */
155static 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 */
268void 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. */
342A_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 */
441A_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 */
607A_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
657static 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
684void 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
704