linux/drivers/staging/ath6kl/htc2/AR6000/ar6k_gmbox_hciuart.c
<<
>>
Prefs
   1//------------------------------------------------------------------------------
   2// <copyright file="ar6k_prot_hciUart.c" company="Atheros">
   3//    Copyright (c) 2007-2010 Atheros Corporation.  All rights reserved.
   4// 
   5//
   6// Permission to use, copy, modify, and/or distribute this software for any
   7// purpose with or without fee is hereby granted, provided that the above
   8// copyright notice and this permission notice appear in all copies.
   9//
  10// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  11// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  12// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  13// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  14// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  15// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  16// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  17//
  18//
  19//------------------------------------------------------------------------------
  20//==============================================================================
  21// Protocol module for use in bridging HCI-UART packets over the GMBOX interface
  22//
  23// Author(s): ="Atheros"
  24//==============================================================================
  25#include "a_config.h"
  26#include "athdefs.h"
  27#include "a_types.h"
  28#include "a_osapi.h"
  29#include "../htc_debug.h"
  30#include "hif.h"
  31#include "htc_packet.h"
  32#include "ar6k.h"
  33#include "hci_transport_api.h"
  34#include "gmboxif.h"
  35#include "ar6000_diag.h"
  36#include "hw/apb_map.h"
  37#include "hw/mbox_reg.h"
  38
  39#ifdef ATH_AR6K_ENABLE_GMBOX
  40#define HCI_UART_COMMAND_PKT 0x01
  41#define HCI_UART_ACL_PKT     0x02
  42#define HCI_UART_SCO_PKT     0x03
  43#define HCI_UART_EVENT_PKT   0x04
  44
  45#define HCI_RECV_WAIT_BUFFERS (1 << 0)
  46
  47#define HCI_SEND_WAIT_CREDITS (1 << 0)
  48
  49#define HCI_UART_BRIDGE_CREDIT_SIZE     128
  50
  51#define CREDIT_POLL_COUNT       256
  52
  53#define HCI_DELAY_PER_INTERVAL_MS 10 
  54#define BTON_TIMEOUT_MS           500
  55#define BTOFF_TIMEOUT_MS          500
  56#define BAUD_TIMEOUT_MS           1
  57#define BTPWRSAV_TIMEOUT_MS       1  
  58
  59typedef struct {
  60    HCI_TRANSPORT_CONFIG_INFO   HCIConfig;
  61    A_BOOL                      HCIAttached;
  62    A_BOOL                      HCIStopped;
  63    A_UINT32                    RecvStateFlags;
  64    A_UINT32                    SendStateFlags;
  65    HCI_TRANSPORT_PACKET_TYPE   WaitBufferType;
  66    HTC_PACKET_QUEUE            SendQueue;         /* write queue holding HCI Command and ACL packets */
  67    HTC_PACKET_QUEUE            HCIACLRecvBuffers;  /* recv queue holding buffers for incomming ACL packets */
  68    HTC_PACKET_QUEUE            HCIEventBuffers;    /* recv queue holding buffers for incomming event packets */
  69    AR6K_DEVICE                 *pDev;
  70    A_MUTEX_T                   HCIRxLock;
  71    A_MUTEX_T                   HCITxLock;
  72    int                         CreditsMax;
  73    int                         CreditsConsumed;
  74    int                         CreditsAvailable;
  75    int                         CreditSize;
  76    int                         CreditsCurrentSeek;
  77    int                         SendProcessCount;
  78} GMBOX_PROTO_HCI_UART;
  79
  80#define LOCK_HCI_RX(t)   A_MUTEX_LOCK(&(t)->HCIRxLock);
  81#define UNLOCK_HCI_RX(t) A_MUTEX_UNLOCK(&(t)->HCIRxLock);
  82#define LOCK_HCI_TX(t)   A_MUTEX_LOCK(&(t)->HCITxLock);
  83#define UNLOCK_HCI_TX(t) A_MUTEX_UNLOCK(&(t)->HCITxLock);
  84
  85#define DO_HCI_RECV_INDICATION(p,pt) \
  86{   AR_DEBUG_PRINTF(ATH_DEBUG_RECV,("HCI: Indicate Recv on packet:0x%lX status:%d len:%d type:%d \n",  \
  87      (unsigned long)(pt),(pt)->Status, A_SUCCESS((pt)->Status) ? (pt)->ActualLength : 0, HCI_GET_PACKET_TYPE(pt))); \
  88    (p)->HCIConfig.pHCIPktRecv((p)->HCIConfig.pContext, (pt));                                 \
  89}
  90
  91#define DO_HCI_SEND_INDICATION(p,pt) \
  92{   AR_DEBUG_PRINTF(ATH_DEBUG_SEND,("HCI: Indicate Send on packet:0x%lX status:%d type:%d \n",  \
  93            (unsigned long)(pt),(pt)->Status,HCI_GET_PACKET_TYPE(pt)));                             \
  94    (p)->HCIConfig.pHCISendComplete((p)->HCIConfig.pContext, (pt));                            \
  95}
  96    
  97static A_STATUS HCITrySend(GMBOX_PROTO_HCI_UART *pProt, HTC_PACKET *pPacket, A_BOOL Synchronous);
  98
  99static void HCIUartCleanup(GMBOX_PROTO_HCI_UART *pProtocol)
 100{
 101    A_ASSERT(pProtocol != NULL);
 102    
 103    A_MUTEX_DELETE(&pProtocol->HCIRxLock);
 104    A_MUTEX_DELETE(&pProtocol->HCITxLock);
 105        
 106    A_FREE(pProtocol);    
 107}
 108
 109static A_STATUS InitTxCreditState(GMBOX_PROTO_HCI_UART *pProt)
 110{
 111    A_STATUS    status;
 112    int         credits;
 113    int         creditPollCount = CREDIT_POLL_COUNT;
 114    A_BOOL      gotCredits = FALSE;
 115
 116    pProt->CreditsConsumed = 0;
 117    
 118    do {    
 119        
 120        if (pProt->CreditsMax != 0) {
 121            /* we can only call this only once per target reset */
 122            AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("HCI: InitTxCreditState - already called!  \n"));
 123            A_ASSERT(FALSE);
 124            status = A_EINVAL;
 125            break; 
 126        }
 127        
 128        /* read the credit counter. At startup the target will set the credit counter
 129         * to the max available, we read this in a loop because it may take
 130         * multiple credit counter reads to get all credits  */
 131                 
 132        while (creditPollCount) {
 133            
 134            credits = 0;
 135
 136            status = DevGMboxReadCreditCounter(pProt->pDev, PROC_IO_SYNC, &credits);
 137    
 138            if (A_FAILED(status)) {
 139                break;    
 140            }
 141            
 142            if (!gotCredits && (0 == credits)) {
 143                creditPollCount--;
 144                AR_DEBUG_PRINTF(ATH_DEBUG_SEND,("HCI: credit is 0, retrying (%d)  \n",creditPollCount));
 145                A_MDELAY(HCI_DELAY_PER_INTERVAL_MS);
 146                continue;  
 147            } else {
 148                gotCredits = TRUE;    
 149            }
 150            
 151            if (0 == credits) {
 152                break;    
 153            }
 154            
 155            pProt->CreditsMax += credits;
 156        }
 157        
 158        if (A_FAILED(status)) {
 159            break;    
 160        }
 161        
 162        if (0 == creditPollCount) {
 163            AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
 164                    ("** HCI : Failed to get credits! GMBOX Target was not available \n"));        
 165            status = A_ERROR;
 166            break;
 167        }
 168        
 169            /* now get the size */
 170        status = DevGMboxReadCreditSize(pProt->pDev, &pProt->CreditSize);
 171        
 172        if (A_FAILED(status)) {
 173            break;    
 174        }
 175               
 176    } while (FALSE);
 177    
 178    if (A_SUCCESS(status)) {
 179        pProt->CreditsAvailable = pProt->CreditsMax;
 180        AR_DEBUG_PRINTF(ATH_DEBUG_ANY,("HCI : InitTxCreditState - credits avail: %d, size: %d \n",
 181            pProt->CreditsAvailable, pProt->CreditSize));    
 182    }    
 183    
 184    return status;
 185}
 186
 187static A_STATUS CreditsAvailableCallback(void *pContext, int Credits, A_BOOL CreditIRQEnabled)
 188{
 189    GMBOX_PROTO_HCI_UART *pProt = (GMBOX_PROTO_HCI_UART *)pContext;    
 190    A_BOOL               enableCreditIrq = FALSE;   
 191    A_BOOL               disableCreditIrq = FALSE;
 192    A_BOOL               doPendingSends = FALSE;
 193    A_STATUS             status = A_OK;
 194    
 195    /** this callback is called under 2 conditions:
 196     *   1. The credit IRQ interrupt was enabled and signaled.
 197     *   2. A credit counter read completed.
 198     * 
 199     *   The function must not assume that the calling context can block !
 200     */
 201     
 202    AR_DEBUG_PRINTF(ATH_DEBUG_RECV,("+CreditsAvailableCallback (Credits:%d, IRQ:%s) \n",
 203                Credits, CreditIRQEnabled ? "ON" : "OFF"));
 204    
 205    LOCK_HCI_TX(pProt);
 206    
 207    do {
 208        
 209        if (0 == Credits) {
 210            if (!CreditIRQEnabled) {
 211                    /* enable credit IRQ */
 212                enableCreditIrq = TRUE;    
 213            }
 214            break;
 215        }
 216        
 217        AR_DEBUG_PRINTF(ATH_DEBUG_SEND,("HCI: current credit state, consumed:%d available:%d max:%d seek:%d\n",
 218                         pProt->CreditsConsumed, 
 219                         pProt->CreditsAvailable,  
 220                         pProt->CreditsMax,
 221                         pProt->CreditsCurrentSeek));
 222                         
 223        pProt->CreditsAvailable += Credits;
 224        A_ASSERT(pProt->CreditsAvailable <= pProt->CreditsMax);
 225        pProt->CreditsConsumed  -= Credits;
 226        A_ASSERT(pProt->CreditsConsumed >= 0);
 227            
 228        AR_DEBUG_PRINTF(ATH_DEBUG_SEND,("HCI: new credit state, consumed:%d available:%d max:%d seek:%d\n",
 229                         pProt->CreditsConsumed, 
 230                         pProt->CreditsAvailable,  
 231                         pProt->CreditsMax,
 232                         pProt->CreditsCurrentSeek));
 233        
 234        if (pProt->CreditsAvailable >= pProt->CreditsCurrentSeek) {
 235                /* we have enough credits to fullfill at least 1 packet waiting in the queue */
 236            pProt->CreditsCurrentSeek = 0;
 237            pProt->SendStateFlags &= ~HCI_SEND_WAIT_CREDITS;  
 238            doPendingSends = TRUE;  
 239            if (CreditIRQEnabled) {
 240                    /* credit IRQ was enabled, we shouldn't need it anymore */
 241                disableCreditIrq = TRUE;    
 242            }      
 243        } else {
 244                /* not enough credits yet, enable credit IRQ if we haven't already */
 245            if (!CreditIRQEnabled) {               
 246                enableCreditIrq = TRUE;    
 247            }    
 248        }
 249                      
 250    } while (FALSE);
 251    
 252    UNLOCK_HCI_TX(pProt);
 253
 254    if (enableCreditIrq) {
 255        AR_DEBUG_PRINTF(ATH_DEBUG_RECV,(" Enabling credit count IRQ...\n"));
 256            /* must use async only */
 257        status = DevGMboxIRQAction(pProt->pDev, GMBOX_CREDIT_IRQ_ENABLE, PROC_IO_ASYNC);    
 258    } else if (disableCreditIrq) {
 259            /* must use async only */
 260        AR_DEBUG_PRINTF(ATH_DEBUG_RECV,(" Disabling credit count IRQ...\n"));
 261        status = DevGMboxIRQAction(pProt->pDev, GMBOX_CREDIT_IRQ_DISABLE, PROC_IO_ASYNC); 
 262    }
 263       
 264    if (doPendingSends) {
 265        HCITrySend(pProt, NULL, FALSE);
 266    }
 267
 268    AR_DEBUG_PRINTF(ATH_DEBUG_RECV,("+CreditsAvailableCallback \n"));
 269    return status;
 270}
 271
 272static INLINE void NotifyTransportFailure(GMBOX_PROTO_HCI_UART  *pProt, A_STATUS status)
 273{
 274    if (pProt->HCIConfig.TransportFailure != NULL) {
 275        pProt->HCIConfig.TransportFailure(pProt->HCIConfig.pContext, status);
 276    }
 277}
 278
 279static void FailureCallback(void *pContext, A_STATUS Status)
 280{
 281    GMBOX_PROTO_HCI_UART  *pProt = (GMBOX_PROTO_HCI_UART *)pContext; 
 282    
 283        /* target assertion occured */           
 284    NotifyTransportFailure(pProt, Status);  
 285}
 286
 287static void StateDumpCallback(void *pContext)
 288{
 289    GMBOX_PROTO_HCI_UART  *pProt = (GMBOX_PROTO_HCI_UART *)pContext;
 290   
 291    AR_DEBUG_PRINTF(ATH_DEBUG_ANY,("============ HCIUart State ======================\n"));    
 292    AR_DEBUG_PRINTF(ATH_DEBUG_ANY,("RecvStateFlags   :  0x%X \n",pProt->RecvStateFlags));
 293    AR_DEBUG_PRINTF(ATH_DEBUG_ANY,("SendStateFlags   :  0x%X \n",pProt->SendStateFlags));
 294    AR_DEBUG_PRINTF(ATH_DEBUG_ANY,("WaitBufferType   :  %d   \n",pProt->WaitBufferType));
 295    AR_DEBUG_PRINTF(ATH_DEBUG_ANY,("SendQueue Depth  :  %d   \n",HTC_PACKET_QUEUE_DEPTH(&pProt->SendQueue)));
 296    AR_DEBUG_PRINTF(ATH_DEBUG_ANY,("CreditsMax       :  %d   \n",pProt->CreditsMax));
 297    AR_DEBUG_PRINTF(ATH_DEBUG_ANY,("CreditsConsumed  :  %d   \n",pProt->CreditsConsumed));
 298    AR_DEBUG_PRINTF(ATH_DEBUG_ANY,("CreditsAvailable :  %d   \n",pProt->CreditsAvailable));
 299    AR_DEBUG_PRINTF(ATH_DEBUG_ANY,("==================================================\n"));
 300}
 301
 302static A_STATUS HCIUartMessagePending(void *pContext, A_UINT8 LookAheadBytes[], int ValidBytes)
 303{
 304    GMBOX_PROTO_HCI_UART        *pProt = (GMBOX_PROTO_HCI_UART *)pContext;
 305    A_STATUS                    status = A_OK;
 306    int                         totalRecvLength = 0;
 307    HCI_TRANSPORT_PACKET_TYPE   pktType = HCI_PACKET_INVALID;
 308    A_BOOL                      recvRefillCalled = FALSE;
 309    A_BOOL                      blockRecv = FALSE;
 310    HTC_PACKET                  *pPacket = NULL;
 311    
 312    /** caller guarantees that this is a fully block-able context (synch I/O is allowed) */
 313    
 314    AR_DEBUG_PRINTF(ATH_DEBUG_RECV,("+HCIUartMessagePending Lookahead Bytes:%d \n",ValidBytes));
 315    
 316    LOCK_HCI_RX(pProt);
 317        
 318    do {
 319    
 320        if (ValidBytes < 3) {
 321                /* not enough for ACL or event header */
 322            break;    
 323        }    
 324        
 325        if ((LookAheadBytes[0] == HCI_UART_ACL_PKT) && (ValidBytes < 5)) {
 326                /* not enough for ACL data header */
 327            break;    
 328        }
 329                
 330        switch (LookAheadBytes[0]) {       
 331            case HCI_UART_EVENT_PKT:
 332                AR_DEBUG_PRINTF(ATH_DEBUG_RECV,("HCI Event: %d param length: %d \n",
 333                        LookAheadBytes[1], LookAheadBytes[2]));
 334                totalRecvLength = LookAheadBytes[2];
 335                totalRecvLength += 3; /* add type + event code + length field */
 336                pktType = HCI_EVENT_TYPE;      
 337                break;
 338            case HCI_UART_ACL_PKT:                
 339                totalRecvLength = (LookAheadBytes[4] << 8) | LookAheadBytes[3];                
 340                AR_DEBUG_PRINTF(ATH_DEBUG_RECV,("HCI ACL: conn:0x%X length: %d \n",
 341                        ((LookAheadBytes[2] & 0xF0) << 8) | LookAheadBytes[1], totalRecvLength));
 342                totalRecvLength += 5; /* add type + connection handle + length field */
 343                pktType = HCI_ACL_TYPE;           
 344                break;        
 345            default:
 346                AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("**Invalid HCI packet type: %d \n",LookAheadBytes[0]));
 347                status = A_EPROTO;
 348                break;
 349        }
 350        
 351        if (A_FAILED(status)) {
 352            break;    
 353        }
 354                
 355        if (pProt->HCIConfig.pHCIPktRecvAlloc != NULL) {
 356            UNLOCK_HCI_RX(pProt);
 357                /* user is using a per-packet allocation callback */
 358            pPacket = pProt->HCIConfig.pHCIPktRecvAlloc(pProt->HCIConfig.pContext,
 359                                                        pktType,
 360                                                        totalRecvLength);
 361            LOCK_HCI_RX(pProt);
 362    
 363        } else {
 364            HTC_PACKET_QUEUE *pQueue;
 365                /* user is using a refill handler that can refill multiple HTC buffers */
 366            
 367                /* select buffer queue */
 368            if (pktType == HCI_ACL_TYPE) {
 369                pQueue = &pProt->HCIACLRecvBuffers;    
 370            } else {
 371                pQueue = &pProt->HCIEventBuffers;              
 372            }    
 373            
 374            if (HTC_QUEUE_EMPTY(pQueue)) {
 375                AR_DEBUG_PRINTF(ATH_DEBUG_RECV,
 376                    ("** HCI pkt type: %d has no buffers available calling allocation handler \n", 
 377                    pktType));
 378                    /* check for refill handler */
 379                if (pProt->HCIConfig.pHCIPktRecvRefill != NULL) {
 380                    recvRefillCalled = TRUE;
 381                    UNLOCK_HCI_RX(pProt);
 382                        /* call the re-fill handler */
 383                    pProt->HCIConfig.pHCIPktRecvRefill(pProt->HCIConfig.pContext,
 384                                                       pktType,
 385                                                       0);
 386                    LOCK_HCI_RX(pProt);
 387                        /* check if we have more buffers */
 388                    pPacket = HTC_PACKET_DEQUEUE(pQueue);
 389                        /* fall through */
 390                }
 391            } else {
 392                pPacket = HTC_PACKET_DEQUEUE(pQueue);
 393                AR_DEBUG_PRINTF(ATH_DEBUG_RECV,
 394                    ("HCI pkt type: %d now has %d recv buffers left \n", 
 395                            pktType, HTC_PACKET_QUEUE_DEPTH(pQueue)));    
 396            }
 397        }
 398     
 399        if (NULL == pPacket) {
 400            AR_DEBUG_PRINTF(ATH_DEBUG_RECV,
 401                    ("** HCI pkt type: %d has no buffers available stopping recv...\n", pktType));
 402                /* this is not an error, we simply need to mark that we are waiting for buffers.*/
 403            pProt->RecvStateFlags |= HCI_RECV_WAIT_BUFFERS;
 404            pProt->WaitBufferType = pktType;
 405            blockRecv = TRUE;
 406            break;
 407        }
 408        
 409        if (totalRecvLength > (int)pPacket->BufferLength) {
 410            AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("** HCI-UART pkt: %d requires %d bytes (%d buffer bytes avail) ! \n",
 411                LookAheadBytes[0], totalRecvLength, pPacket->BufferLength));
 412            status = A_EINVAL;
 413            break;
 414        }
 415        
 416    } while (FALSE);
 417    
 418    UNLOCK_HCI_RX(pProt);
 419    
 420        /* locks are released, we can go fetch the packet */
 421        
 422    do {
 423        
 424        if (A_FAILED(status) || (NULL == pPacket)) {
 425            break;    
 426        } 
 427        
 428            /* do this synchronously, we don't need to be fast here */
 429        pPacket->Completion = NULL;
 430        
 431        AR_DEBUG_PRINTF(ATH_DEBUG_RECV,("HCI : getting recv packet len:%d hci-uart-type: %s \n",
 432                totalRecvLength, (LookAheadBytes[0] == HCI_UART_EVENT_PKT) ? "EVENT" : "ACL"));
 433                
 434        status = DevGMboxRead(pProt->pDev, pPacket, totalRecvLength);     
 435        
 436        if (A_FAILED(status)) {
 437            break;    
 438        }
 439        
 440        if (pPacket->pBuffer[0] != LookAheadBytes[0]) {
 441            AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("** HCI buffer does not contain expected packet type: %d ! \n",
 442                        pPacket->pBuffer[0]));
 443            status = A_EPROTO;
 444            break;   
 445        }
 446        
 447        if (pPacket->pBuffer[0] == HCI_UART_EVENT_PKT) {
 448                /* validate event header fields */
 449            if ((pPacket->pBuffer[1] != LookAheadBytes[1]) ||
 450                (pPacket->pBuffer[2] != LookAheadBytes[2])) {
 451                AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("** HCI buffer does not match lookahead! \n"));
 452                DebugDumpBytes(LookAheadBytes, 3, "Expected HCI-UART Header");  
 453                DebugDumpBytes(pPacket->pBuffer, 3, "** Bad HCI-UART Header");  
 454                status = A_EPROTO;
 455                break;       
 456            }   
 457        } else if (pPacket->pBuffer[0] == HCI_UART_ACL_PKT) {
 458                /* validate acl header fields */
 459            if ((pPacket->pBuffer[1] != LookAheadBytes[1]) ||
 460                (pPacket->pBuffer[2] != LookAheadBytes[2]) ||
 461                (pPacket->pBuffer[3] != LookAheadBytes[3]) ||
 462                (pPacket->pBuffer[4] != LookAheadBytes[4])) {
 463                AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("** HCI buffer does not match lookahead! \n"));
 464                DebugDumpBytes(LookAheadBytes, 5, "Expected HCI-UART Header");  
 465                DebugDumpBytes(pPacket->pBuffer, 5, "** Bad HCI-UART Header");  
 466                status = A_EPROTO;
 467                break;       
 468            }   
 469        }
 470        
 471            /* adjust buffer to move past packet ID */
 472        pPacket->pBuffer++;
 473        pPacket->ActualLength = totalRecvLength - 1;
 474        pPacket->Status = A_OK;
 475            /* indicate packet */
 476        DO_HCI_RECV_INDICATION(pProt,pPacket);
 477        pPacket = NULL;
 478        
 479            /* check if we need to refill recv buffers */        
 480        if ((pProt->HCIConfig.pHCIPktRecvRefill != NULL) && !recvRefillCalled) {           
 481            HTC_PACKET_QUEUE *pQueue;
 482            int              watermark;
 483
 484            if (pktType == HCI_ACL_TYPE) {
 485                watermark = pProt->HCIConfig.ACLRecvBufferWaterMark;
 486                pQueue = &pProt->HCIACLRecvBuffers;    
 487            } else {
 488                watermark = pProt->HCIConfig.EventRecvBufferWaterMark;     
 489                pQueue = &pProt->HCIEventBuffers;        
 490            }    
 491            
 492            if (HTC_PACKET_QUEUE_DEPTH(pQueue) < watermark) {
 493                AR_DEBUG_PRINTF(ATH_DEBUG_RECV,
 494                    ("** HCI pkt type: %d watermark hit (%d) current:%d \n", 
 495                    pktType, watermark, HTC_PACKET_QUEUE_DEPTH(pQueue)));
 496                    /* call the re-fill handler */
 497                pProt->HCIConfig.pHCIPktRecvRefill(pProt->HCIConfig.pContext,
 498                                                   pktType,
 499                                                   HTC_PACKET_QUEUE_DEPTH(pQueue));
 500            }
 501        }   
 502        
 503    } while (FALSE);
 504        
 505        /* check if we need to disable the reciever */
 506    if (A_FAILED(status) || blockRecv) {
 507        DevGMboxIRQAction(pProt->pDev, GMBOX_RECV_IRQ_DISABLE, PROC_IO_SYNC); 
 508    }
 509    
 510        /* see if we need to recycle the recv buffer */    
 511    if (A_FAILED(status) && (pPacket != NULL)) {
 512        HTC_PACKET_QUEUE queue;
 513        
 514        if (A_EPROTO == status) {
 515            DebugDumpBytes(pPacket->pBuffer, totalRecvLength, "Bad HCI-UART Recv packet");    
 516        }
 517            /* recycle packet */
 518        HTC_PACKET_RESET_RX(pPacket);
 519        INIT_HTC_PACKET_QUEUE_AND_ADD(&queue,pPacket);
 520        HCI_TransportAddReceivePkts(pProt,&queue);
 521        NotifyTransportFailure(pProt,status);    
 522    }
 523    
 524 
 525    AR_DEBUG_PRINTF(ATH_DEBUG_RECV,("-HCIUartMessagePending \n"));
 526    
 527    return status;
 528}
 529
 530static void HCISendPacketCompletion(void *Context, HTC_PACKET *pPacket)
 531{
 532    GMBOX_PROTO_HCI_UART *pProt = (GMBOX_PROTO_HCI_UART *)Context;
 533    AR_DEBUG_PRINTF(ATH_DEBUG_SEND,("+HCISendPacketCompletion (pPacket:0x%lX) \n",(unsigned long)pPacket));
 534    
 535    if (A_FAILED(pPacket->Status)) {
 536        AR_DEBUG_PRINTF(ATH_DEBUG_ERR,(" Send Packet (0x%lX) failed: %d , len:%d \n",
 537            (unsigned long)pPacket, pPacket->Status, pPacket->ActualLength));        
 538    }
 539    
 540    DO_HCI_SEND_INDICATION(pProt,pPacket);
 541    
 542    AR_DEBUG_PRINTF(ATH_DEBUG_SEND,("+HCISendPacketCompletion \n"));
 543}
 544
 545static A_STATUS SeekCreditsSynch(GMBOX_PROTO_HCI_UART *pProt)
 546{
 547    A_STATUS status = A_OK;
 548    int      credits;
 549    int      retry = 100;
 550    
 551    while (TRUE) {                
 552        credits = 0;
 553        status =  DevGMboxReadCreditCounter(pProt->pDev, PROC_IO_SYNC, &credits);   
 554        if (A_FAILED(status)) {
 555            break;    
 556        }
 557        LOCK_HCI_TX(pProt);
 558        pProt->CreditsAvailable += credits;        
 559        pProt->CreditsConsumed -= credits;        
 560        if (pProt->CreditsAvailable >= pProt->CreditsCurrentSeek) {
 561            pProt->CreditsCurrentSeek = 0;
 562            UNLOCK_HCI_TX(pProt);
 563            break;    
 564        }
 565        UNLOCK_HCI_TX(pProt);
 566        retry--;
 567        if (0 == retry) {
 568            status = A_EBUSY;
 569            break;    
 570        }
 571        A_MDELAY(20);
 572    }   
 573    
 574    return status;
 575}
 576
 577static A_STATUS HCITrySend(GMBOX_PROTO_HCI_UART *pProt, HTC_PACKET *pPacket, A_BOOL Synchronous)
 578{   
 579    A_STATUS    status = A_OK;
 580    int         transferLength;
 581    int         creditsRequired, remainder;
 582    A_UINT8     hciUartType;
 583    A_BOOL      synchSendComplete = FALSE;
 584    
 585    AR_DEBUG_PRINTF(ATH_DEBUG_SEND,("+HCITrySend (pPacket:0x%lX) %s \n",(unsigned long)pPacket,
 586            Synchronous ? "SYNC" :"ASYNC"));
 587    
 588    LOCK_HCI_TX(pProt);
 589     
 590        /* increment write processing count on entry */    
 591    pProt->SendProcessCount++;
 592        
 593    do {
 594                                             
 595        if (pProt->HCIStopped) {
 596            status = A_ECANCELED;
 597            break;     
 598        }   
 599         
 600        if (pPacket != NULL) {  
 601                /* packet was supplied */     
 602            if (Synchronous) {
 603                    /* in synchronous mode, the send queue can only hold 1 packet */
 604                if (!HTC_QUEUE_EMPTY(&pProt->SendQueue)) {
 605                    status = A_EBUSY;
 606                    A_ASSERT(FALSE);
 607                    break;    
 608                }             
 609                
 610                if (pProt->SendProcessCount > 1) {
 611                        /* another thread or task is draining the TX queues  */
 612                    status = A_EBUSY;
 613                    A_ASSERT(FALSE);
 614                    break;
 615                } 
 616                  
 617                HTC_PACKET_ENQUEUE(&pProt->SendQueue,pPacket);
 618                
 619            } else {
 620                    /* see if adding this packet hits the max depth (asynchronous mode only) */
 621                if ((pProt->HCIConfig.MaxSendQueueDepth > 0) && 
 622                    ((HTC_PACKET_QUEUE_DEPTH(&pProt->SendQueue) + 1) >= pProt->HCIConfig.MaxSendQueueDepth)) {
 623                    AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("HCI Send queue is full, Depth:%d, Max:%d \n",
 624                            HTC_PACKET_QUEUE_DEPTH(&pProt->SendQueue), 
 625                            pProt->HCIConfig.MaxSendQueueDepth));
 626                        /* queue will be full, invoke any callbacks to determine what action to take */
 627                    if (pProt->HCIConfig.pHCISendFull != NULL) {
 628                        AR_DEBUG_PRINTF(ATH_DEBUG_SEND, 
 629                                    ("HCI : Calling driver's send full callback.... \n"));
 630                        if (pProt->HCIConfig.pHCISendFull(pProt->HCIConfig.pContext,
 631                                                          pPacket) == HCI_SEND_FULL_DROP) {
 632                                /* drop it */
 633                            status = A_NO_RESOURCE;      
 634                            break;
 635                        }
 636                    }               
 637                }
 638          
 639                HTC_PACKET_ENQUEUE(&pProt->SendQueue,pPacket);
 640            }
 641
 642        }
 643               
 644        if (pProt->SendStateFlags & HCI_SEND_WAIT_CREDITS) {
 645            break;   
 646        }
 647
 648        if (pProt->SendProcessCount > 1) {
 649                /* another thread or task is draining the TX queues  */
 650            break;
 651        }
 652    
 653        /***** beyond this point only 1 thread may enter ******/
 654           
 655        /* now drain the send queue for transmission as long as we have enough
 656         * credits */
 657        while (!HTC_QUEUE_EMPTY(&pProt->SendQueue)) {
 658            
 659            pPacket = HTC_PACKET_DEQUEUE(&pProt->SendQueue);
 660
 661            switch (HCI_GET_PACKET_TYPE(pPacket)) {            
 662                case HCI_COMMAND_TYPE:
 663                    hciUartType = HCI_UART_COMMAND_PKT;
 664                    break;
 665                case HCI_ACL_TYPE:
 666                    hciUartType = HCI_UART_ACL_PKT;
 667                    break;
 668                default:
 669                    status = A_EINVAL;
 670                    A_ASSERT(FALSE);
 671                    break;
 672            }
 673                       
 674            if (A_FAILED(status)) {
 675                break;   
 676            }
 677            
 678            AR_DEBUG_PRINTF(ATH_DEBUG_SEND,("HCI: Got head packet:0x%lX , Type:%d  Length: %d Remaining Queue Depth: %d\n",
 679                (unsigned long)pPacket, HCI_GET_PACKET_TYPE(pPacket), pPacket->ActualLength, 
 680                HTC_PACKET_QUEUE_DEPTH(&pProt->SendQueue)));
 681        
 682            transferLength = 1;  /* UART type header is 1 byte */
 683            transferLength += pPacket->ActualLength;
 684            transferLength = DEV_CALC_SEND_PADDED_LEN(pProt->pDev, transferLength);
 685                   
 686                /* figure out how many credits this message requires */
 687            creditsRequired = transferLength / pProt->CreditSize;
 688            remainder = transferLength % pProt->CreditSize;
 689
 690            if (remainder) {
 691                creditsRequired++;
 692            }
 693
 694            AR_DEBUG_PRINTF(ATH_DEBUG_SEND,("HCI: Creds Required:%d   Got:%d\n",
 695                            creditsRequired, pProt->CreditsAvailable));
 696            
 697            if (creditsRequired > pProt->CreditsAvailable) {
 698                if (Synchronous) {
 699                        /* in synchronous mode we need to seek credits in synchronously */
 700                    pProt->CreditsCurrentSeek = creditsRequired;
 701                    UNLOCK_HCI_TX(pProt);
 702                    status = SeekCreditsSynch(pProt);
 703                    LOCK_HCI_TX(pProt);
 704                    if (A_FAILED(status)) {
 705                        break;    
 706                    }                    
 707                    /* fall through and continue processing this send op */                    
 708                } else {
 709                        /* not enough credits, queue back to the head */
 710                    HTC_PACKET_ENQUEUE_TO_HEAD(&pProt->SendQueue,pPacket);
 711                        /* waiting for credits */
 712                    pProt->SendStateFlags |= HCI_SEND_WAIT_CREDITS;
 713                        /* provide a hint to reduce attempts to re-send if credits are dribbling back
 714                         * this hint is the short fall of credits */
 715                    pProt->CreditsCurrentSeek = creditsRequired;
 716                    AR_DEBUG_PRINTF(ATH_DEBUG_SEND,("HCI: packet:0x%lX placed back in queue. head packet needs: %d credits \n",
 717                                        (unsigned long)pPacket, pProt->CreditsCurrentSeek));
 718                    pPacket = NULL;
 719                    UNLOCK_HCI_TX(pProt);
 720                    
 721                        /* schedule a credit counter read, our CreditsAvailableCallback callback will be called
 722                         * with the result */   
 723                    DevGMboxReadCreditCounter(pProt->pDev, PROC_IO_ASYNC, NULL);
 724                             
 725                    LOCK_HCI_TX(pProt);
 726                    break;              
 727                }          
 728            }
 729        
 730                /* caller guarantees some head room */
 731            pPacket->pBuffer--;
 732            pPacket->pBuffer[0] = hciUartType;
 733            
 734            pProt->CreditsAvailable -= creditsRequired;
 735            pProt->CreditsConsumed  += creditsRequired;
 736            A_ASSERT(pProt->CreditsConsumed <= pProt->CreditsMax);
 737            
 738            AR_DEBUG_PRINTF(ATH_DEBUG_SEND,("HCI: new credit state: consumed:%d   available:%d max:%d\n",
 739                             pProt->CreditsConsumed, pProt->CreditsAvailable,  pProt->CreditsMax));
 740            
 741            UNLOCK_HCI_TX(pProt);   
 742            
 743                /* write it out */   
 744            if (Synchronous) {                            
 745                pPacket->Completion = NULL;
 746                pPacket->pContext = NULL;         
 747            } else {                       
 748                pPacket->Completion = HCISendPacketCompletion;
 749                pPacket->pContext = pProt;    
 750            }
 751            
 752            status = DevGMboxWrite(pProt->pDev,pPacket,transferLength);            
 753            if (Synchronous) {            
 754                synchSendComplete = TRUE;
 755            } else {
 756                pPacket = NULL;    
 757            }
 758            
 759            LOCK_HCI_TX(pProt);
 760              
 761        }
 762        
 763    } while (FALSE);
 764        
 765    pProt->SendProcessCount--;
 766    A_ASSERT(pProt->SendProcessCount >= 0);
 767    UNLOCK_HCI_TX(pProt);
 768    
 769    if (Synchronous) {
 770        A_ASSERT(pPacket != NULL);
 771        if (A_SUCCESS(status) && (!synchSendComplete)) {
 772            status = A_EBUSY;
 773            A_ASSERT(FALSE);
 774            LOCK_HCI_TX(pProt);
 775            if (pPacket->ListLink.pNext != NULL) {
 776                    /* remove from the queue */
 777                HTC_PACKET_REMOVE(&pProt->SendQueue,pPacket);
 778            }
 779            UNLOCK_HCI_TX(pProt);
 780        }
 781    } else {   
 782        if (A_FAILED(status) && (pPacket != NULL)) {
 783            pPacket->Status = status;
 784            DO_HCI_SEND_INDICATION(pProt,pPacket); 
 785        }
 786    }
 787        
 788    AR_DEBUG_PRINTF(ATH_DEBUG_SEND,("-HCITrySend:  \n"));
 789    return status;    
 790}
 791
 792static void FlushSendQueue(GMBOX_PROTO_HCI_UART *pProt)
 793{
 794    HTC_PACKET          *pPacket;
 795    HTC_PACKET_QUEUE    discardQueue;
 796    
 797    INIT_HTC_PACKET_QUEUE(&discardQueue);
 798    
 799    LOCK_HCI_TX(pProt);
 800    
 801    if (!HTC_QUEUE_EMPTY(&pProt->SendQueue)) {
 802        HTC_PACKET_QUEUE_TRANSFER_TO_TAIL(&discardQueue,&pProt->SendQueue);    
 803    }
 804    
 805    UNLOCK_HCI_TX(pProt);
 806    
 807        /* discard packets */
 808    while (!HTC_QUEUE_EMPTY(&discardQueue)) {
 809        pPacket = HTC_PACKET_DEQUEUE(&discardQueue);   
 810        pPacket->Status = A_ECANCELED;
 811        DO_HCI_SEND_INDICATION(pProt,pPacket);
 812    }
 813    
 814}
 815
 816static void FlushRecvBuffers(GMBOX_PROTO_HCI_UART *pProt)
 817{
 818    HTC_PACKET_QUEUE discardQueue;
 819    HTC_PACKET *pPacket;
 820    
 821    INIT_HTC_PACKET_QUEUE(&discardQueue);
 822    
 823    LOCK_HCI_RX(pProt);
 824        /*transfer list items from ACL and event buffer queues to the discard queue */       
 825    if (!HTC_QUEUE_EMPTY(&pProt->HCIACLRecvBuffers)) {
 826        HTC_PACKET_QUEUE_TRANSFER_TO_TAIL(&discardQueue,&pProt->HCIACLRecvBuffers);    
 827    }
 828    if (!HTC_QUEUE_EMPTY(&pProt->HCIEventBuffers)) {
 829        HTC_PACKET_QUEUE_TRANSFER_TO_TAIL(&discardQueue,&pProt->HCIEventBuffers);    
 830    }
 831    UNLOCK_HCI_RX(pProt);
 832    
 833        /* now empty the discard queue */
 834    while (!HTC_QUEUE_EMPTY(&discardQueue)) {
 835        pPacket = HTC_PACKET_DEQUEUE(&discardQueue);      
 836        pPacket->Status = A_ECANCELED;
 837        DO_HCI_RECV_INDICATION(pProt,pPacket);
 838    }
 839    
 840}
 841
 842/*** protocol module install entry point ***/
 843
 844A_STATUS GMboxProtocolInstall(AR6K_DEVICE *pDev)
 845{
 846    A_STATUS                status = A_OK;
 847    GMBOX_PROTO_HCI_UART    *pProtocol = NULL;
 848        
 849    do {
 850        
 851        pProtocol = A_MALLOC(sizeof(GMBOX_PROTO_HCI_UART));
 852        
 853        if (NULL == pProtocol) {
 854            status = A_NO_MEMORY;
 855            break;    
 856        }
 857        
 858        A_MEMZERO(pProtocol, sizeof(*pProtocol));
 859        pProtocol->pDev = pDev;
 860        INIT_HTC_PACKET_QUEUE(&pProtocol->SendQueue);
 861        INIT_HTC_PACKET_QUEUE(&pProtocol->HCIACLRecvBuffers);
 862        INIT_HTC_PACKET_QUEUE(&pProtocol->HCIEventBuffers);
 863        A_MUTEX_INIT(&pProtocol->HCIRxLock);
 864        A_MUTEX_INIT(&pProtocol->HCITxLock);
 865     
 866    } while (FALSE);
 867    
 868    if (A_SUCCESS(status)) {
 869        LOCK_AR6K(pDev);
 870        DEV_GMBOX_SET_PROTOCOL(pDev,
 871                               HCIUartMessagePending,
 872                               CreditsAvailableCallback,
 873                               FailureCallback,
 874                               StateDumpCallback,
 875                               pProtocol);
 876        UNLOCK_AR6K(pDev);
 877    } else {
 878        if (pProtocol != NULL) {
 879            HCIUartCleanup(pProtocol);    
 880        }    
 881    }
 882    
 883    return status;    
 884}
 885
 886/*** protocol module uninstall entry point ***/
 887void GMboxProtocolUninstall(AR6K_DEVICE *pDev)
 888{
 889    GMBOX_PROTO_HCI_UART *pProtocol = (GMBOX_PROTO_HCI_UART *)DEV_GMBOX_GET_PROTOCOL(pDev);
 890    
 891    if (pProtocol != NULL) {
 892        
 893            /* notify anyone attached */    
 894        if (pProtocol->HCIAttached) {
 895            A_ASSERT(pProtocol->HCIConfig.TransportRemoved != NULL);
 896            pProtocol->HCIConfig.TransportRemoved(pProtocol->HCIConfig.pContext);
 897            pProtocol->HCIAttached = FALSE;    
 898        }
 899        
 900        HCIUartCleanup(pProtocol);
 901        DEV_GMBOX_SET_PROTOCOL(pDev,NULL,NULL,NULL,NULL,NULL);       
 902    }
 903    
 904}
 905
 906static A_STATUS NotifyTransportReady(GMBOX_PROTO_HCI_UART  *pProt)
 907{
 908    HCI_TRANSPORT_PROPERTIES props;
 909    A_STATUS                 status = A_OK;
 910    
 911    do {
 912        
 913        A_MEMZERO(&props,sizeof(props));
 914        
 915            /* HCI UART only needs one extra byte at the head to indicate the packet TYPE */
 916        props.HeadRoom = 1;
 917        props.TailRoom = 0;
 918        props.IOBlockPad = pProt->pDev->BlockSize;
 919        if (pProt->HCIAttached) {
 920            AR_DEBUG_PRINTF(ATH_DEBUG_ANY,("HCI: notifying attached client to transport... \n"));    
 921            A_ASSERT(pProt->HCIConfig.TransportReady != NULL);
 922            status = pProt->HCIConfig.TransportReady(pProt,
 923                                                    &props,
 924                                                    pProt->HCIConfig.pContext);
 925        }
 926        
 927    } while (FALSE);
 928    
 929    return status;
 930}
 931
 932/***********  HCI UART protocol implementation ************************************************/
 933
 934HCI_TRANSPORT_HANDLE HCI_TransportAttach(void *HTCHandle, HCI_TRANSPORT_CONFIG_INFO *pInfo)
 935{
 936    GMBOX_PROTO_HCI_UART  *pProtocol = NULL; 
 937    AR6K_DEVICE           *pDev;
 938    
 939    AR_DEBUG_PRINTF(ATH_DEBUG_TRC,("+HCI_TransportAttach \n"));
 940    
 941    pDev = HTCGetAR6KDevice(HTCHandle);
 942    
 943    LOCK_AR6K(pDev);
 944    
 945    do {
 946        
 947        pProtocol = (GMBOX_PROTO_HCI_UART *)DEV_GMBOX_GET_PROTOCOL(pDev);
 948        
 949        if (NULL == pProtocol) {
 950            AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("GMBOX protocol not installed! \n"));
 951            break;
 952        }
 953        
 954        if (pProtocol->HCIAttached) {
 955            AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("GMBOX protocol already attached! \n"));
 956            break;    
 957        }
 958        
 959        A_MEMCPY(&pProtocol->HCIConfig, pInfo, sizeof(HCI_TRANSPORT_CONFIG_INFO));
 960        
 961        A_ASSERT(pProtocol->HCIConfig.pHCIPktRecv != NULL);
 962        A_ASSERT(pProtocol->HCIConfig.pHCISendComplete != NULL);
 963        
 964        pProtocol->HCIAttached = TRUE;
 965        
 966    } while (FALSE);
 967    
 968    UNLOCK_AR6K(pDev);
 969    
 970    if (pProtocol != NULL) {
 971            /* TODO ... should we use a worker? */
 972        NotifyTransportReady(pProtocol);
 973    }
 974    
 975    AR_DEBUG_PRINTF(ATH_DEBUG_TRC,("-HCI_TransportAttach (0x%lX) \n",(unsigned long)pProtocol));
 976    return (HCI_TRANSPORT_HANDLE)pProtocol;
 977}
 978
 979void HCI_TransportDetach(HCI_TRANSPORT_HANDLE HciTrans)
 980{
 981    GMBOX_PROTO_HCI_UART  *pProtocol = (GMBOX_PROTO_HCI_UART *)HciTrans; 
 982    AR6K_DEVICE           *pDev = pProtocol->pDev;
 983    
 984    AR_DEBUG_PRINTF(ATH_DEBUG_TRC,("+HCI_TransportDetach \n"));
 985    
 986    LOCK_AR6K(pDev);
 987    if (!pProtocol->HCIAttached) {
 988        AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("GMBOX protocol not attached! \n"));
 989        UNLOCK_AR6K(pDev);
 990        return;
 991    }
 992    pProtocol->HCIAttached = FALSE;
 993    UNLOCK_AR6K(pDev);
 994    
 995    HCI_TransportStop(HciTrans);
 996    AR_DEBUG_PRINTF(ATH_DEBUG_TRC,("-HCI_TransportAttach \n"));
 997}
 998
 999A_STATUS HCI_TransportAddReceivePkts(HCI_TRANSPORT_HANDLE HciTrans, HTC_PACKET_QUEUE *pQueue)
1000{
1001    GMBOX_PROTO_HCI_UART  *pProt = (GMBOX_PROTO_HCI_UART *)HciTrans; 
1002    A_STATUS              status = A_OK;
1003    A_BOOL                unblockRecv = FALSE;
1004    HTC_PACKET            *pPacket;
1005    
1006    AR_DEBUG_PRINTF(ATH_DEBUG_RECV,("+HCI_TransportAddReceivePkt \n"));
1007    
1008    LOCK_HCI_RX(pProt);
1009   
1010    do {
1011         
1012        if (pProt->HCIStopped) {
1013            status = A_ECANCELED;
1014            break;    
1015        }
1016        
1017        pPacket = HTC_GET_PKT_AT_HEAD(pQueue);
1018        
1019        if (NULL == pPacket) {
1020            status = A_EINVAL;
1021            break;    
1022        }
1023        
1024        AR_DEBUG_PRINTF(ATH_DEBUG_RECV,(" HCI recv packet added, type :%d, len:%d num:%d \n",
1025                        HCI_GET_PACKET_TYPE(pPacket), pPacket->BufferLength, HTC_PACKET_QUEUE_DEPTH(pQueue)));
1026                        
1027        if (HCI_GET_PACKET_TYPE(pPacket) == HCI_EVENT_TYPE) {
1028            HTC_PACKET_QUEUE_TRANSFER_TO_TAIL(&pProt->HCIEventBuffers, pQueue);
1029        } else if (HCI_GET_PACKET_TYPE(pPacket) == HCI_ACL_TYPE) {
1030            HTC_PACKET_QUEUE_TRANSFER_TO_TAIL(&pProt->HCIACLRecvBuffers, pQueue);    
1031        } else {
1032            status = A_EINVAL;
1033            break;    
1034        }
1035        
1036        if (pProt->RecvStateFlags & HCI_RECV_WAIT_BUFFERS) {
1037            if (pProt->WaitBufferType == HCI_GET_PACKET_TYPE(pPacket)) {
1038                AR_DEBUG_PRINTF(ATH_DEBUG_RECV,(" HCI recv was blocked on packet type :%d, unblocking.. \n",
1039                        pProt->WaitBufferType));
1040                pProt->RecvStateFlags &= ~HCI_RECV_WAIT_BUFFERS;
1041                pProt->WaitBufferType = HCI_PACKET_INVALID;
1042                unblockRecv = TRUE;
1043            }
1044        }
1045        
1046    } while (FALSE);
1047    
1048    UNLOCK_HCI_RX(pProt);
1049    
1050    if (A_FAILED(status)) {
1051        while (!HTC_QUEUE_EMPTY(pQueue)) {
1052            pPacket = HTC_PACKET_DEQUEUE(pQueue);      
1053            pPacket->Status = A_ECANCELED;
1054            DO_HCI_RECV_INDICATION(pProt,pPacket);
1055        }   
1056    }
1057    
1058    if (unblockRecv) {
1059        DevGMboxIRQAction(pProt->pDev, GMBOX_RECV_IRQ_ENABLE, PROC_IO_ASYNC);
1060    }
1061    
1062    AR_DEBUG_PRINTF(ATH_DEBUG_RECV,("-HCI_TransportAddReceivePkt \n"));
1063    
1064    return A_OK;    
1065}
1066
1067A_STATUS HCI_TransportSendPkt(HCI_TRANSPORT_HANDLE HciTrans, HTC_PACKET *pPacket, A_BOOL Synchronous)
1068{
1069    GMBOX_PROTO_HCI_UART  *pProt = (GMBOX_PROTO_HCI_UART *)HciTrans;  
1070    
1071    return HCITrySend(pProt,pPacket,Synchronous);
1072}
1073
1074void HCI_TransportStop(HCI_TRANSPORT_HANDLE HciTrans)
1075{
1076    GMBOX_PROTO_HCI_UART  *pProt = (GMBOX_PROTO_HCI_UART *)HciTrans; 
1077    
1078    AR_DEBUG_PRINTF(ATH_DEBUG_TRC,("+HCI_TransportStop \n"));
1079     
1080    LOCK_AR6K(pProt->pDev);
1081    if (pProt->HCIStopped) {
1082        UNLOCK_AR6K(pProt->pDev);
1083        AR_DEBUG_PRINTF(ATH_DEBUG_TRC,("-HCI_TransportStop \n"));
1084        return;    
1085    }
1086    pProt->HCIStopped = TRUE;
1087    UNLOCK_AR6K(pProt->pDev);
1088     
1089        /* disable interrupts */
1090    DevGMboxIRQAction(pProt->pDev, GMBOX_DISABLE_ALL, PROC_IO_SYNC);
1091    FlushSendQueue(pProt);
1092    FlushRecvBuffers(pProt);
1093    
1094        /* signal bridge side to power down BT */
1095    DevGMboxSetTargetInterrupt(pProt->pDev, MBOX_SIG_HCI_BRIDGE_BT_OFF, BTOFF_TIMEOUT_MS);
1096           
1097    AR_DEBUG_PRINTF(ATH_DEBUG_TRC,("-HCI_TransportStop \n"));
1098}
1099
1100A_STATUS HCI_TransportStart(HCI_TRANSPORT_HANDLE HciTrans)
1101{
1102    A_STATUS              status;
1103    GMBOX_PROTO_HCI_UART  *pProt = (GMBOX_PROTO_HCI_UART *)HciTrans;
1104    
1105    AR_DEBUG_PRINTF(ATH_DEBUG_TRC,("+HCI_TransportStart \n"));
1106    
1107        /* set stopped in case we have a problem in starting */
1108    pProt->HCIStopped = TRUE;
1109    
1110    do {
1111        
1112        status = InitTxCreditState(pProt);   
1113        
1114        if (A_FAILED(status)) {
1115            break;    
1116        }     
1117        
1118        status = DevGMboxIRQAction(pProt->pDev, GMBOX_ERRORS_IRQ_ENABLE, PROC_IO_SYNC);   
1119        
1120        if (A_FAILED(status)) {
1121            break;   
1122        } 
1123            /* enable recv */   
1124        status = DevGMboxIRQAction(pProt->pDev, GMBOX_RECV_IRQ_ENABLE, PROC_IO_SYNC);
1125        
1126        if (A_FAILED(status)) {
1127            break;   
1128        } 
1129            /* signal bridge side to power up BT */
1130        status = DevGMboxSetTargetInterrupt(pProt->pDev, MBOX_SIG_HCI_BRIDGE_BT_ON, BTON_TIMEOUT_MS);
1131        
1132        if (A_FAILED(status)) {
1133            AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("HCI_TransportStart : Failed to trigger BT ON \n"));
1134            break;   
1135        } 
1136        
1137            /* we made it */
1138        pProt->HCIStopped = FALSE;
1139        
1140    } while (FALSE);
1141    
1142    AR_DEBUG_PRINTF(ATH_DEBUG_TRC,("-HCI_TransportStart \n"));
1143    
1144    return status;
1145}
1146
1147A_STATUS HCI_TransportEnableDisableAsyncRecv(HCI_TRANSPORT_HANDLE HciTrans, A_BOOL Enable)
1148{
1149    GMBOX_PROTO_HCI_UART  *pProt = (GMBOX_PROTO_HCI_UART *)HciTrans;
1150    return DevGMboxIRQAction(pProt->pDev, 
1151                             Enable ? GMBOX_RECV_IRQ_ENABLE : GMBOX_RECV_IRQ_DISABLE, 
1152                             PROC_IO_SYNC);
1153                             
1154}
1155
1156A_STATUS HCI_TransportRecvHCIEventSync(HCI_TRANSPORT_HANDLE HciTrans,
1157                                       HTC_PACKET           *pPacket,
1158                                       int                  MaxPollMS)
1159{
1160    GMBOX_PROTO_HCI_UART  *pProt = (GMBOX_PROTO_HCI_UART *)HciTrans;
1161    A_STATUS              status = A_OK;
1162    A_UINT8               lookAhead[8];
1163    int                   bytes;
1164    int                   totalRecvLength;
1165    
1166    MaxPollMS = MaxPollMS / 16;
1167    
1168    if (MaxPollMS < 2) {
1169        MaxPollMS = 2;    
1170    }
1171    
1172    while (MaxPollMS) {
1173        
1174        bytes = sizeof(lookAhead);
1175        status = DevGMboxRecvLookAheadPeek(pProt->pDev,lookAhead,&bytes);
1176        if (A_FAILED(status)) {
1177            break;    
1178        }        
1179                
1180        if (bytes < 3) {
1181            AR_DEBUG_PRINTF(ATH_DEBUG_RECV,("HCI recv poll got bytes: %d, retry : %d \n",
1182                        bytes, MaxPollMS));
1183            A_MDELAY(16);
1184            MaxPollMS--;        
1185            continue;
1186        }
1187        
1188        totalRecvLength = 0;
1189        switch (lookAhead[0]) {       
1190            case HCI_UART_EVENT_PKT:
1191                AR_DEBUG_PRINTF(ATH_DEBUG_RECV,("HCI Event: %d param length: %d \n",
1192                        lookAhead[1], lookAhead[2]));
1193                totalRecvLength = lookAhead[2];
1194                totalRecvLength += 3; /* add type + event code + length field */
1195                break;
1196            default:
1197                AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("**Invalid HCI packet type: %d \n",lookAhead[0]));
1198                status = A_EPROTO;
1199                break;
1200        }
1201        
1202        if (A_FAILED(status)) {
1203            break;    
1204        }
1205        
1206        pPacket->Completion = NULL;
1207        status = DevGMboxRead(pProt->pDev,pPacket,totalRecvLength); 
1208        if (A_FAILED(status)) {
1209            break;    
1210        }
1211        
1212        pPacket->pBuffer++;
1213        pPacket->ActualLength = totalRecvLength - 1;
1214        pPacket->Status = A_OK;        
1215        break; 
1216    }
1217    
1218    if (MaxPollMS == 0) {
1219        AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("HCI recv poll timeout! \n"));
1220        status = A_ERROR;    
1221    }
1222    
1223    return status;
1224}
1225
1226#define LSB_SCRATCH_IDX     4
1227#define MSB_SCRATCH_IDX     5
1228A_STATUS HCI_TransportSetBaudRate(HCI_TRANSPORT_HANDLE HciTrans, A_UINT32 Baud)
1229{
1230    GMBOX_PROTO_HCI_UART  *pProt = (GMBOX_PROTO_HCI_UART *)HciTrans;
1231    HIF_DEVICE *pHIFDevice = (HIF_DEVICE *)(pProt->pDev->HIFDevice);
1232    A_UINT32 scaledBaud, scratchAddr;
1233    A_STATUS status = A_OK;
1234
1235    /* Divide the desired baud rate by 100
1236     * Store the LSB in the local scratch register 4 and the MSB in the local
1237     * scratch register 5 for the target to read
1238     */
1239    scratchAddr = MBOX_BASE_ADDRESS | (LOCAL_SCRATCH_ADDRESS + 4 * LSB_SCRATCH_IDX);
1240    scaledBaud = (Baud / 100) & LOCAL_SCRATCH_VALUE_MASK;
1241    status = ar6000_WriteRegDiag(pHIFDevice, &scratchAddr, &scaledBaud);                     
1242    scratchAddr = MBOX_BASE_ADDRESS | (LOCAL_SCRATCH_ADDRESS + 4 * MSB_SCRATCH_IDX);
1243    scaledBaud = ((Baud / 100) >> (LOCAL_SCRATCH_VALUE_MSB+1)) & LOCAL_SCRATCH_VALUE_MASK;
1244    status |= ar6000_WriteRegDiag(pHIFDevice, &scratchAddr, &scaledBaud);                     
1245    if (A_OK != status) {
1246        AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Failed to set up baud rate in scratch register!"));            
1247        return status;
1248    }
1249
1250    /* Now interrupt the target to tell it about the baud rate */
1251    status = DevGMboxSetTargetInterrupt(pProt->pDev, MBOX_SIG_HCI_BRIDGE_BAUD_SET, BAUD_TIMEOUT_MS);
1252    if (A_OK != status) {
1253        AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Failed to tell target to change baud rate!"));            
1254    }
1255    
1256    return status;
1257}
1258
1259A_STATUS HCI_TransportEnablePowerMgmt(HCI_TRANSPORT_HANDLE HciTrans, A_BOOL Enable)
1260{
1261    A_STATUS status;
1262    GMBOX_PROTO_HCI_UART  *pProt = (GMBOX_PROTO_HCI_UART *)HciTrans;
1263                             
1264    if (Enable) {
1265        status = DevGMboxSetTargetInterrupt(pProt->pDev, MBOX_SIG_HCI_BRIDGE_PWR_SAV_ON, BTPWRSAV_TIMEOUT_MS);
1266    } else {
1267        status = DevGMboxSetTargetInterrupt(pProt->pDev, MBOX_SIG_HCI_BRIDGE_PWR_SAV_OFF, BTPWRSAV_TIMEOUT_MS);
1268    }
1269
1270    if (A_FAILED(status)) {
1271        AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Failed to enable/disable HCI power management!\n"));
1272    } else {
1273        AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("HCI power management enabled/disabled!\n"));
1274    }
1275
1276    return status;
1277}
1278
1279#endif  //ATH_AR6K_ENABLE_GMBOX
1280
1281