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