PageRenderTime 245ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 0ms

/drivers/staging/ath6kl/htc2/AR6000/ar6k_gmbox_hciuart.c

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