dhd_bta.c 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340
  1. /*
  2. * BT-AMP support routines
  3. *
  4. * Copyright (C) 1999-2014, Broadcom Corporation
  5. *
  6. * Unless you and Broadcom execute a separate written software license
  7. * agreement governing use of this software, this software is licensed to you
  8. * under the terms of the GNU General Public License version 2 (the "GPL"),
  9. * available at http://www.broadcom.com/licenses/GPLv2.php, with the
  10. * following added to such license:
  11. *
  12. * As a special exception, the copyright holders of this software give you
  13. * permission to link this software with independent modules, and to copy and
  14. * distribute the resulting executable under terms of your choice, provided that
  15. * you also meet, for each linked independent module, the terms and conditions of
  16. * the license of that module. An independent module is a module which is not
  17. * derived from this software. The special exception does not apply to any
  18. * modifications of the software.
  19. *
  20. * Notwithstanding the above, under no circumstances may you combine this
  21. * software in any way with any other Broadcom software provided under a license
  22. * other than the GPL, without Broadcom's express prior written consent.
  23. *
  24. * $Id: dhd_bta.c 434656 2013-11-07 01:11:33Z $
  25. */
  26. #ifndef WLBTAMP
  27. #error "WLBTAMP is not defined"
  28. #endif /* WLBTAMP */
  29. #include <typedefs.h>
  30. #include <osl.h>
  31. #include <bcmcdc.h>
  32. #include <bcmutils.h>
  33. #include <bcmendian.h>
  34. #include <proto/802.11.h>
  35. #include <proto/802.11_bta.h>
  36. #include <proto/bt_amp_hci.h>
  37. #include <dngl_stats.h>
  38. #include <dhd.h>
  39. #include <dhd_bus.h>
  40. #include <dhd_proto.h>
  41. #include <dhdioctl.h>
  42. #include <dhd_dbg.h>
  43. #include <dhd_bta.h>
  44. #ifdef SEND_HCI_CMD_VIA_IOCTL
  45. #define BTA_HCI_CMD_MAX_LEN HCI_CMD_PREAMBLE_SIZE + HCI_CMD_DATA_SIZE
  46. /* Send HCI cmd via wl iovar HCI_cmd to the dongle. */
  47. int
  48. dhd_bta_docmd(dhd_pub_t *pub, void *cmd_buf, uint cmd_len)
  49. {
  50. amp_hci_cmd_t *cmd = (amp_hci_cmd_t *)cmd_buf;
  51. uint8 buf[BTA_HCI_CMD_MAX_LEN + 16];
  52. uint len = sizeof(buf);
  53. wl_ioctl_t ioc;
  54. if (cmd_len < HCI_CMD_PREAMBLE_SIZE)
  55. return BCME_BADLEN;
  56. if ((uint)cmd->plen + HCI_CMD_PREAMBLE_SIZE > cmd_len)
  57. return BCME_BADLEN;
  58. len = bcm_mkiovar("HCI_cmd",
  59. (char *)cmd, (uint)cmd->plen + HCI_CMD_PREAMBLE_SIZE, (char *)buf, len);
  60. memset(&ioc, 0, sizeof(ioc));
  61. ioc.cmd = WLC_SET_VAR;
  62. ioc.buf = buf;
  63. ioc.len = len;
  64. ioc.set = TRUE;
  65. return dhd_wl_ioctl(pub, &ioc, ioc.buf, ioc.len);
  66. }
  67. #else /* !SEND_HCI_CMD_VIA_IOCTL */
  68. static void
  69. dhd_bta_flush_hcidata(dhd_pub_t *pub, uint16 llh)
  70. {
  71. int prec;
  72. struct pktq *q;
  73. uint count = 0;
  74. q = dhd_bus_txq(pub->bus);
  75. if (q == NULL)
  76. return;
  77. DHD_BTA(("dhd: flushing HCI ACL data for logical link %u...\n", llh));
  78. dhd_os_sdlock_txq(pub);
  79. /* Walk through the txq and toss all HCI ACL data packets */
  80. PKTQ_PREC_ITER(q, prec) {
  81. void *head_pkt = NULL;
  82. while (pktq_ppeek(q, prec) != head_pkt) {
  83. void *pkt = pktq_pdeq(q, prec);
  84. int ifidx;
  85. dhd_prot_hdrpull(pub, &ifidx, pkt, NULL, NULL);
  86. if (PKTLEN(pub->osh, pkt) >= RFC1042_HDR_LEN) {
  87. struct ether_header *eh =
  88. (struct ether_header *)PKTDATA(pub->osh, pkt);
  89. if (ntoh16(eh->ether_type) < ETHER_TYPE_MIN) {
  90. struct dot11_llc_snap_header *lsh =
  91. (struct dot11_llc_snap_header *)&eh[1];
  92. if (bcmp(lsh, BT_SIG_SNAP_MPROT,
  93. DOT11_LLC_SNAP_HDR_LEN - 2) == 0 &&
  94. ntoh16(lsh->type) == BTA_PROT_L2CAP) {
  95. amp_hci_ACL_data_t *ACL_data =
  96. (amp_hci_ACL_data_t *)&lsh[1];
  97. uint16 handle = ltoh16(ACL_data->handle);
  98. if (HCI_ACL_DATA_HANDLE(handle) == llh) {
  99. PKTFREE(pub->osh, pkt, TRUE);
  100. count ++;
  101. continue;
  102. }
  103. }
  104. }
  105. }
  106. dhd_prot_hdrpush(pub, ifidx, pkt);
  107. if (head_pkt == NULL)
  108. head_pkt = pkt;
  109. pktq_penq(q, prec, pkt);
  110. }
  111. }
  112. dhd_os_sdunlock_txq(pub);
  113. DHD_BTA(("dhd: flushed %u packet(s) for logical link %u...\n", count, llh));
  114. }
  115. /* Handle HCI cmd locally.
  116. * Return 0: continue to send the cmd across SDIO
  117. * < 0: stop, fail
  118. * > 0: stop, succuess
  119. */
  120. static int
  121. _dhd_bta_docmd(dhd_pub_t *pub, amp_hci_cmd_t *cmd)
  122. {
  123. int status = 0;
  124. switch (ltoh16_ua((uint8 *)&cmd->opcode)) {
  125. case HCI_Enhanced_Flush: {
  126. eflush_cmd_parms_t *cmdparms = (eflush_cmd_parms_t *)cmd->parms;
  127. dhd_bta_flush_hcidata(pub, ltoh16_ua(cmdparms->llh));
  128. break;
  129. }
  130. default:
  131. break;
  132. }
  133. return status;
  134. }
  135. /* Send HCI cmd encapsulated in BT-SIG frame via data channel to the dongle. */
  136. int
  137. dhd_bta_docmd(dhd_pub_t *pub, void *cmd_buf, uint cmd_len)
  138. {
  139. amp_hci_cmd_t *cmd = (amp_hci_cmd_t *)cmd_buf;
  140. struct ether_header *eh;
  141. struct dot11_llc_snap_header *lsh;
  142. osl_t *osh = pub->osh;
  143. uint len;
  144. void *p;
  145. int status;
  146. if (cmd_len < HCI_CMD_PREAMBLE_SIZE) {
  147. DHD_ERROR(("dhd_bta_docmd: short command, cmd_len %u\n", cmd_len));
  148. return BCME_BADLEN;
  149. }
  150. if ((len = (uint)cmd->plen + HCI_CMD_PREAMBLE_SIZE) > cmd_len) {
  151. DHD_ERROR(("dhd_bta_docmd: malformed command, len %u cmd_len %u\n",
  152. len, cmd_len));
  153. /* return BCME_BADLEN; */
  154. }
  155. p = PKTGET(osh, pub->hdrlen + RFC1042_HDR_LEN + len, TRUE);
  156. if (p == NULL) {
  157. DHD_ERROR(("dhd_bta_docmd: out of memory\n"));
  158. return BCME_NOMEM;
  159. }
  160. /* intercept and handle the HCI cmd locally */
  161. if ((status = _dhd_bta_docmd(pub, cmd)) > 0)
  162. return 0;
  163. else if (status < 0)
  164. return status;
  165. /* copy in HCI cmd */
  166. PKTPULL(osh, p, pub->hdrlen + RFC1042_HDR_LEN);
  167. bcopy(cmd, PKTDATA(osh, p), len);
  168. /* copy in partial Ethernet header with BT-SIG LLC/SNAP header */
  169. PKTPUSH(osh, p, RFC1042_HDR_LEN);
  170. eh = (struct ether_header *)PKTDATA(osh, p);
  171. bzero(eh->ether_dhost, ETHER_ADDR_LEN);
  172. ETHER_SET_LOCALADDR(eh->ether_dhost);
  173. bcopy(&pub->mac, eh->ether_shost, ETHER_ADDR_LEN);
  174. eh->ether_type = hton16(len + DOT11_LLC_SNAP_HDR_LEN);
  175. lsh = (struct dot11_llc_snap_header *)&eh[1];
  176. bcopy(BT_SIG_SNAP_MPROT, lsh, DOT11_LLC_SNAP_HDR_LEN - 2);
  177. lsh->type = 0;
  178. return dhd_sendpkt(pub, 0, p);
  179. }
  180. #endif /* !SEND_HCI_CMD_VIA_IOCTL */
  181. /* Send HCI ACL data to dongle via data channel */
  182. int
  183. dhd_bta_tx_hcidata(dhd_pub_t *pub, void *data_buf, uint data_len)
  184. {
  185. amp_hci_ACL_data_t *data = (amp_hci_ACL_data_t *)data_buf;
  186. struct ether_header *eh;
  187. struct dot11_llc_snap_header *lsh;
  188. osl_t *osh = pub->osh;
  189. uint len;
  190. void *p;
  191. if (data_len < HCI_ACL_DATA_PREAMBLE_SIZE) {
  192. DHD_ERROR(("dhd_bta_tx_hcidata: short data_buf, data_len %u\n", data_len));
  193. return BCME_BADLEN;
  194. }
  195. if ((len = (uint)ltoh16(data->dlen) + HCI_ACL_DATA_PREAMBLE_SIZE) > data_len) {
  196. DHD_ERROR(("dhd_bta_tx_hcidata: malformed hci data, len %u data_len %u\n",
  197. len, data_len));
  198. /* return BCME_BADLEN; */
  199. }
  200. p = PKTGET(osh, pub->hdrlen + RFC1042_HDR_LEN + len, TRUE);
  201. if (p == NULL) {
  202. DHD_ERROR(("dhd_bta_tx_hcidata: out of memory\n"));
  203. return BCME_NOMEM;
  204. }
  205. /* copy in HCI ACL data header and HCI ACL data */
  206. PKTPULL(osh, p, pub->hdrlen + RFC1042_HDR_LEN);
  207. bcopy(data, PKTDATA(osh, p), len);
  208. /* copy in partial Ethernet header with BT-SIG LLC/SNAP header */
  209. PKTPUSH(osh, p, RFC1042_HDR_LEN);
  210. eh = (struct ether_header *)PKTDATA(osh, p);
  211. bzero(eh->ether_dhost, ETHER_ADDR_LEN);
  212. bcopy(&pub->mac, eh->ether_shost, ETHER_ADDR_LEN);
  213. eh->ether_type = hton16(len + DOT11_LLC_SNAP_HDR_LEN);
  214. lsh = (struct dot11_llc_snap_header *)&eh[1];
  215. bcopy(BT_SIG_SNAP_MPROT, lsh, DOT11_LLC_SNAP_HDR_LEN - 2);
  216. lsh->type = HTON16(BTA_PROT_L2CAP);
  217. return dhd_sendpkt(pub, 0, p);
  218. }
  219. /* txcomplete callback */
  220. void
  221. dhd_bta_tx_hcidata_complete(dhd_pub_t *dhdp, void *txp, bool success)
  222. {
  223. uint8 *pktdata = (uint8 *)PKTDATA(dhdp->osh, txp);
  224. amp_hci_ACL_data_t *ACL_data = (amp_hci_ACL_data_t *)(pktdata + RFC1042_HDR_LEN);
  225. uint16 handle = ltoh16(ACL_data->handle);
  226. uint16 llh = HCI_ACL_DATA_HANDLE(handle);
  227. wl_event_msg_t event;
  228. uint8 data[HCI_EVT_PREAMBLE_SIZE + sizeof(num_completed_data_blocks_evt_parms_t)];
  229. amp_hci_event_t *evt;
  230. num_completed_data_blocks_evt_parms_t *parms;
  231. uint16 len = HCI_EVT_PREAMBLE_SIZE + sizeof(num_completed_data_blocks_evt_parms_t);
  232. /* update the event struct */
  233. memset(&event, 0, sizeof(event));
  234. event.version = hton16(BCM_EVENT_MSG_VERSION);
  235. event.event_type = hton32(WLC_E_BTA_HCI_EVENT);
  236. event.status = 0;
  237. event.reason = 0;
  238. event.auth_type = 0;
  239. event.datalen = hton32(len);
  240. event.flags = 0;
  241. /* generate Number of Completed Blocks event */
  242. evt = (amp_hci_event_t *)data;
  243. evt->ecode = HCI_Number_of_Completed_Data_Blocks;
  244. evt->plen = sizeof(num_completed_data_blocks_evt_parms_t);
  245. parms = (num_completed_data_blocks_evt_parms_t *)evt->parms;
  246. htol16_ua_store(dhdp->maxdatablks, (uint8 *)&parms->num_blocks);
  247. parms->num_handles = 1;
  248. htol16_ua_store(llh, (uint8 *)&parms->completed[0].handle);
  249. parms->completed[0].pkts = 1;
  250. parms->completed[0].blocks = 1;
  251. dhd_sendup_event_common(dhdp, &event, data);
  252. }
  253. /* event callback */
  254. void
  255. dhd_bta_doevt(dhd_pub_t *dhdp, void *data_buf, uint data_len)
  256. {
  257. amp_hci_event_t *evt = (amp_hci_event_t *)data_buf;
  258. ASSERT(dhdp);
  259. ASSERT(evt);
  260. switch (evt->ecode) {
  261. case HCI_Command_Complete: {
  262. cmd_complete_parms_t *parms = (cmd_complete_parms_t *)evt->parms;
  263. switch (ltoh16_ua((uint8 *)&parms->opcode)) {
  264. case HCI_Read_Data_Block_Size: {
  265. read_data_block_size_evt_parms_t *parms2 =
  266. (read_data_block_size_evt_parms_t *)parms->parms;
  267. dhdp->maxdatablks = ltoh16_ua((uint8 *)&parms2->data_block_num);
  268. break;
  269. }
  270. }
  271. break;
  272. }
  273. case HCI_Flush_Occurred: {
  274. flush_occurred_evt_parms_t *evt_parms = (flush_occurred_evt_parms_t *)evt->parms;
  275. dhd_bta_flush_hcidata(dhdp, ltoh16_ua((uint8 *)&evt_parms->handle));
  276. break;
  277. }
  278. default:
  279. break;
  280. }
  281. }