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