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