Add 2.6.31 patches
[openwrt/staging/wigyori.git] / target / linux / s3c24xx / files-2.6.31 / 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