PageRenderTime 58ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/drivers/net/wireless/bcm4330/src/dhd/sys/dhd_bta.c

https://bitbucket.org/thenameisnigel/android_kernel_lge_ls840
C | 465 lines | 360 code | 71 blank | 34 comment | 39 complexity | 20c2be39ee80aeafcd4cb74af4cba337 MD5 | raw file
  1. /*
  2. * BT-AMP support routines
  3. *
  4. * $Copyright Broadcom Corporation$
  5. *
  6. * $Id: dhd_bta.c,v 1.10.4.2 2010/12/22 23:47:23 hharte Exp $
  7. */
  8. #ifndef WLBTAMP
  9. #error "WLBTAMP is not defined"
  10. #endif /* WLBTAMP */
  11. #include <typedefs.h>
  12. #include <osl.h>
  13. #include <bcmcdc.h>
  14. #include <bcmutils.h>
  15. #include <bcmendian.h>
  16. #include <proto/802.11.h>
  17. #include <proto/802.11_bta.h>
  18. #include <proto/bt_amp_hci.h>
  19. #include <dngl_stats.h>
  20. #include <dhd.h>
  21. #ifdef BCMDBUS
  22. #include <dbus.h>
  23. #else
  24. #include <dhd_bus.h>
  25. #endif
  26. #include <dhd_proto.h>
  27. #include <dhdioctl.h>
  28. #include <dhd_dbg.h>
  29. #include <dhd_bta.h>
  30. #ifdef BCMDBG
  31. static void dhd_bta_hcidump_cmd(dhd_pub_t *pub, amp_hci_cmd_t *cmd);
  32. #endif
  33. #ifdef SEND_HCI_CMD_VIA_IOCTL
  34. /* XXX it is just a few hundred (< 300) bytes so it's ok to allocate it on the stack I think
  35. * but we'd better to use MALLOC() to be safe.
  36. */
  37. #define BTA_HCI_CMD_MAX_LEN HCI_CMD_PREAMBLE_SIZE + HCI_CMD_DATA_SIZE
  38. /* Send HCI cmd via wl iovar HCI_cmd to the dongle. */
  39. int
  40. dhd_bta_docmd(dhd_pub_t *pub, void *cmd_buf, uint cmd_len)
  41. {
  42. amp_hci_cmd_t *cmd = (amp_hci_cmd_t *)cmd_buf;
  43. uint8 buf[BTA_HCI_CMD_MAX_LEN + 16];
  44. uint len = sizeof(buf);
  45. wl_ioctl_t ioc;
  46. if (cmd_len < HCI_CMD_PREAMBLE_SIZE)
  47. return BCME_BADLEN;
  48. if ((uint)cmd->plen + HCI_CMD_PREAMBLE_SIZE > cmd_len)
  49. return BCME_BADLEN;
  50. len = bcm_mkiovar("HCI_cmd",
  51. (char *)cmd, (uint)cmd->plen + HCI_CMD_PREAMBLE_SIZE, (char *)buf, len);
  52. #ifdef BCMDBG
  53. if (DHD_BTA_ON())
  54. dhd_bta_hcidump_cmd(pub, cmd);
  55. #endif
  56. memset(&ioc, 0, sizeof(ioc));
  57. ioc.cmd = WLC_SET_VAR;
  58. ioc.buf = buf;
  59. ioc.len = len;
  60. #if defined(BCMINTERNAL) && defined(DONGLEOVERLAYS)
  61. ioc.action = WL_IOCTL_ACTION_SET;
  62. #else
  63. ioc.set = TRUE;
  64. #endif /* defined(BCMINTERNAL) && defined(DONGLEOVERLAYS) */
  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. PKTPULL(pub->osh, pkt, dhd_bus_hdrlen(pub->bus));
  86. dhd_prot_hdrpull(pub, &ifidx, pkt);
  87. if (PKTLEN(pub->osh, pkt) >= RFC1042_HDR_LEN) {
  88. struct ether_header *eh =
  89. (struct ether_header *)PKTDATA(pub->osh, pkt);
  90. if (ntoh16(eh->ether_type) < ETHER_TYPE_MIN) {
  91. struct dot11_llc_snap_header *lsh =
  92. (struct dot11_llc_snap_header *)&eh[1];
  93. if (bcmp(lsh, BT_SIG_SNAP_MPROT,
  94. DOT11_LLC_SNAP_HDR_LEN - 2) == 0 &&
  95. ntoh16(lsh->type) == BTA_PROT_L2CAP) {
  96. amp_hci_ACL_data_t *ACL_data =
  97. (amp_hci_ACL_data_t *)&lsh[1];
  98. uint16 handle = ltoh16(ACL_data->handle);
  99. if (HCI_ACL_DATA_HANDLE(handle) == llh) {
  100. PKTFREE(pub->osh, pkt, TRUE);
  101. count ++;
  102. continue;
  103. }
  104. }
  105. }
  106. }
  107. dhd_prot_hdrpush(pub, ifidx, pkt);
  108. PKTPUSH(pub->osh, pkt, dhd_bus_hdrlen(pub->bus));
  109. if (head_pkt == NULL)
  110. head_pkt = pkt;
  111. pktq_penq(q, prec, pkt);
  112. }
  113. }
  114. dhd_os_sdunlock_txq(pub);
  115. DHD_BTA(("dhd: flushed %u packet(s) for logical link %u...\n", count, llh));
  116. }
  117. /* Handle HCI cmd locally.
  118. * Return 0: continue to send the cmd across SDIO
  119. * < 0: stop, fail
  120. * > 0: stop, succuess
  121. */
  122. static int
  123. _dhd_bta_docmd(dhd_pub_t *pub, amp_hci_cmd_t *cmd)
  124. {
  125. int status = 0;
  126. switch (ltoh16_ua((uint8 *)&cmd->opcode)) {
  127. case HCI_Enhanced_Flush: {
  128. eflush_cmd_parms_t *cmdparms = (eflush_cmd_parms_t *)cmd->parms;
  129. dhd_bta_flush_hcidata(pub, ltoh16_ua(cmdparms->llh));
  130. break;
  131. }
  132. default:
  133. break;
  134. }
  135. return status;
  136. }
  137. /* Send HCI cmd encapsulated in BT-SIG frame via data channel to the dongle. */
  138. int
  139. dhd_bta_docmd(dhd_pub_t *pub, void *cmd_buf, uint cmd_len)
  140. {
  141. amp_hci_cmd_t *cmd = (amp_hci_cmd_t *)cmd_buf;
  142. struct ether_header *eh;
  143. struct dot11_llc_snap_header *lsh;
  144. osl_t *osh = pub->osh;
  145. uint len;
  146. void *p;
  147. int status;
  148. if (cmd_len < HCI_CMD_PREAMBLE_SIZE) {
  149. DHD_ERROR(("dhd_bta_docmd: short command, cmd_len %u\n", cmd_len));
  150. return BCME_BADLEN;
  151. }
  152. if ((len = (uint)cmd->plen + HCI_CMD_PREAMBLE_SIZE) > cmd_len) {
  153. DHD_ERROR(("dhd_bta_docmd: malformed command, len %u cmd_len %u\n",
  154. len, cmd_len));
  155. /* return BCME_BADLEN; */
  156. }
  157. p = PKTGET(osh, pub->hdrlen + RFC1042_HDR_LEN + len, TRUE);
  158. if (p == NULL) {
  159. DHD_ERROR(("dhd_bta_docmd: out of memory\n"));
  160. return BCME_NOMEM;
  161. }
  162. #ifdef BCMDBG
  163. if (DHD_BTA_ON())
  164. dhd_bta_hcidump_cmd(pub, cmd);
  165. #endif
  166. /* intercept and handle the HCI cmd locally */
  167. if ((status = _dhd_bta_docmd(pub, cmd)) > 0)
  168. return 0;
  169. else if (status < 0)
  170. return status;
  171. /* copy in HCI cmd */
  172. PKTPULL(osh, p, pub->hdrlen + RFC1042_HDR_LEN);
  173. bcopy(cmd, PKTDATA(osh, p), len);
  174. /* copy in partial Ethernet header with BT-SIG LLC/SNAP header */
  175. /* XXX the dongle expects locally admin'd address as DA and 0 as type */
  176. PKTPUSH(osh, p, RFC1042_HDR_LEN);
  177. eh = (struct ether_header *)PKTDATA(osh, p);
  178. bzero(eh->ether_dhost, ETHER_ADDR_LEN);
  179. ETHER_SET_LOCALADDR(eh->ether_dhost);
  180. bcopy(&pub->mac, eh->ether_shost, ETHER_ADDR_LEN);
  181. eh->ether_type = hton16(len + DOT11_LLC_SNAP_HDR_LEN);
  182. lsh = (struct dot11_llc_snap_header *)&eh[1];
  183. bcopy(BT_SIG_SNAP_MPROT, lsh, DOT11_LLC_SNAP_HDR_LEN - 2);
  184. lsh->type = 0;
  185. return dhd_sendpkt(pub, 0, p);
  186. }
  187. #endif /* !SEND_HCI_CMD_VIA_IOCTL */
  188. /* Send HCI ACL data to dongle via data channel */
  189. int
  190. dhd_bta_tx_hcidata(dhd_pub_t *pub, void *data_buf, uint data_len)
  191. {
  192. amp_hci_ACL_data_t *data = (amp_hci_ACL_data_t *)data_buf;
  193. struct ether_header *eh;
  194. struct dot11_llc_snap_header *lsh;
  195. osl_t *osh = pub->osh;
  196. uint len;
  197. void *p;
  198. if (data_len < HCI_ACL_DATA_PREAMBLE_SIZE) {
  199. DHD_ERROR(("dhd_bta_tx_hcidata: short data_buf, data_len %u\n", data_len));
  200. return BCME_BADLEN;
  201. }
  202. if ((len = (uint)ltoh16(data->dlen) + HCI_ACL_DATA_PREAMBLE_SIZE) > data_len) {
  203. DHD_ERROR(("dhd_bta_tx_hcidata: malformed hci data, len %u data_len %u\n",
  204. len, data_len));
  205. /* return BCME_BADLEN; */
  206. }
  207. p = PKTGET(osh, pub->hdrlen + RFC1042_HDR_LEN + len, TRUE);
  208. if (p == NULL) {
  209. DHD_ERROR(("dhd_bta_tx_hcidata: out of memory\n"));
  210. return BCME_NOMEM;
  211. }
  212. #ifdef BCMDBG
  213. if (DHD_BTA_ON())
  214. dhd_bta_hcidump_ACL_data(pub, data, TRUE);
  215. #endif
  216. /* copy in HCI ACL data header and HCI ACL data */
  217. PKTPULL(osh, p, pub->hdrlen + RFC1042_HDR_LEN);
  218. bcopy(data, PKTDATA(osh, p), len);
  219. /* copy in partial Ethernet header with BT-SIG LLC/SNAP header */
  220. /* XXX the dongle will fixup the DA */
  221. PKTPUSH(osh, p, RFC1042_HDR_LEN);
  222. eh = (struct ether_header *)PKTDATA(osh, p);
  223. bzero(eh->ether_dhost, ETHER_ADDR_LEN);
  224. bcopy(&pub->mac, eh->ether_shost, ETHER_ADDR_LEN);
  225. eh->ether_type = hton16(len + DOT11_LLC_SNAP_HDR_LEN);
  226. lsh = (struct dot11_llc_snap_header *)&eh[1];
  227. bcopy(BT_SIG_SNAP_MPROT, lsh, DOT11_LLC_SNAP_HDR_LEN - 2);
  228. lsh->type = HTON16(BTA_PROT_L2CAP);
  229. return dhd_sendpkt(pub, 0, p);
  230. }
  231. /* txcomplete callback */
  232. void
  233. dhd_bta_tx_hcidata_complete(dhd_pub_t *dhdp, void *txp, bool success)
  234. {
  235. /* XXX Use packet tag when it is available to store llh */
  236. uint8 *pktdata = (uint8 *)PKTDATA(dhdp->osh, txp);
  237. amp_hci_ACL_data_t *ACL_data = (amp_hci_ACL_data_t *)(pktdata + RFC1042_HDR_LEN);
  238. uint16 handle = ltoh16(ACL_data->handle);
  239. uint16 llh = HCI_ACL_DATA_HANDLE(handle);
  240. wl_event_msg_t event;
  241. uint8 data[HCI_EVT_PREAMBLE_SIZE + sizeof(num_completed_data_blocks_evt_parms_t)];
  242. amp_hci_event_t *evt;
  243. num_completed_data_blocks_evt_parms_t *parms;
  244. uint16 len = HCI_EVT_PREAMBLE_SIZE + sizeof(num_completed_data_blocks_evt_parms_t);
  245. /* update the event struct */
  246. memset(&event, 0, sizeof(event));
  247. event.version = hton16(BCM_EVENT_MSG_VERSION);
  248. event.event_type = hton32(WLC_E_BTA_HCI_EVENT);
  249. event.status = 0;
  250. event.reason = 0;
  251. event.auth_type = 0;
  252. event.datalen = hton32(len);
  253. event.flags = 0;
  254. /* generate Number of Completed Blocks event */
  255. /* XXX - optimize this to indicate more than 1 block/packet at a time? */
  256. evt = (amp_hci_event_t *)data;
  257. evt->ecode = HCI_Number_of_Completed_Data_Blocks;
  258. evt->plen = sizeof(num_completed_data_blocks_evt_parms_t);
  259. parms = (num_completed_data_blocks_evt_parms_t *)evt->parms;
  260. htol16_ua_store(dhdp->maxdatablks, (uint8 *)&parms->num_blocks);
  261. parms->num_handles = 1;
  262. htol16_ua_store(llh, (uint8 *)&parms->completed[0].handle);
  263. parms->completed[0].pkts = 1;
  264. parms->completed[0].blocks = 1;
  265. dhd_sendup_event_common(dhdp, &event, data);
  266. }
  267. /* event callback */
  268. void
  269. dhd_bta_doevt(dhd_pub_t *dhdp, void *data_buf, uint data_len)
  270. {
  271. amp_hci_event_t *evt = (amp_hci_event_t *)data_buf;
  272. switch (evt->ecode) {
  273. case HCI_Command_Complete: {
  274. cmd_complete_parms_t *parms = (cmd_complete_parms_t *)evt->parms;
  275. switch (ltoh16_ua((uint8 *)&parms->opcode)) {
  276. case HCI_Read_Data_Block_Size: {
  277. read_data_block_size_evt_parms_t *parms2 =
  278. (read_data_block_size_evt_parms_t *)parms->parms;
  279. dhdp->maxdatablks = ltoh16_ua((uint8 *)&parms2->data_block_num);
  280. break;
  281. }
  282. }
  283. break;
  284. }
  285. case HCI_Flush_Occurred: {
  286. flush_occurred_evt_parms_t *evt_parms = (flush_occurred_evt_parms_t *)evt->parms;
  287. dhd_bta_flush_hcidata(dhdp, ltoh16_ua((uint8 *)&evt_parms->handle));
  288. break;
  289. }
  290. default:
  291. break;
  292. }
  293. }
  294. #ifdef BCMDBG
  295. static const struct {
  296. uint16 opval;
  297. char *opstr;
  298. } op_map[] = {
  299. { HCI_Read_Logical_Link_Accept_Timeout, "Read Logical Link Accept Timeout" },
  300. { HCI_Write_Logical_Link_Accept_Timeout, "Write Logical Link Accept Timeout" },
  301. { HCI_Read_Buffer_Size, "Read Buffer Size" },
  302. { HCI_Read_Data_Block_Size, "Read Data Block Size" },
  303. { HCI_Reset, "Reset" },
  304. { HCI_Enhanced_Flush, "Enhanced Flush" },
  305. { HCI_Read_Best_Effort_Flush_Timeout, "Read Best Effort Flush Timeout" },
  306. { HCI_Write_Best_Effort_Flush_Timeout, "Write Best Effort Flush Timeout" },
  307. { HCI_Read_Connection_Accept_Timeout, "Read Connection Accept Timeout" },
  308. { HCI_Write_Connection_Accept_Timeout, "Write Connection Accept Timeout" },
  309. { HCI_Read_Link_Supervision_Timeout, "Read Link Supervision Timeout" },
  310. { HCI_Write_Link_Supervision_Timeout, "Write Link Supervision Timeout" },
  311. { HCI_Read_Link_Quality, "Read Link Quality" },
  312. { HCI_Read_Local_AMP_Info, "Read Local AMP Info" },
  313. { HCI_Read_Local_AMP_ASSOC, "Read Local AMP ASSOC" },
  314. { HCI_Write_Remote_AMP_ASSOC, "Write Remote AMP ASSOC" },
  315. { HCI_Create_Physical_Link, "Create Physical Link" },
  316. { HCI_Accept_Physical_Link_Request, "Accept Physical Link Request" },
  317. { HCI_Disconnect_Physical_Link, "Disconnect Physical Link" },
  318. { HCI_Create_Logical_Link, "Create Logical Link" },
  319. { HCI_Accept_Logical_Link, "Accept Logical Link" },
  320. { HCI_Disconnect_Logical_Link, "Disconnect Logical Link" },
  321. { HCI_Logical_Link_Cancel, "Logical Link Cancel" },
  322. { HCI_Short_Range_Mode, "Short Range Mode" }
  323. };
  324. static char *
  325. op2str(uint16 op, char *buf)
  326. {
  327. uint i;
  328. sprintf(buf, "Unknown");
  329. for (i = 0; i < ARRAYSIZE(op_map); i++) {
  330. if (op == op_map[i].opval) {
  331. sprintf(buf, op_map[i].opstr);
  332. }
  333. }
  334. return buf;
  335. }
  336. static void
  337. dhd_bta_hcidump_cmd(dhd_pub_t *pub, amp_hci_cmd_t *cmd)
  338. {
  339. uint16 op = cmd->opcode;
  340. char buf[40];
  341. DHD_BTA(("dhd: < HCI Command: %s(0x%x|0x%x) plen %d\n",
  342. op2str(op, buf), HCI_CMD_OGF(op), HCI_CMD_OCF(op),
  343. cmd->plen));
  344. prhex(NULL, cmd->parms, cmd->plen);
  345. DHD_BTA(("\n"));
  346. }
  347. void
  348. dhd_bta_hcidump_ACL_data(dhd_pub_t *pub, amp_hci_ACL_data_t *ACL_data, bool tx)
  349. {
  350. DHD_BTA(("dhd: %s ACL data: handle 0x%04x flags 0x%02x dlen %d\n",
  351. tx ? "<" : ">", HCI_ACL_DATA_HANDLE(ACL_data->handle),
  352. HCI_ACL_DATA_FLAGS(ACL_data->handle), ACL_data->dlen));
  353. prhex(NULL, ACL_data->data, ACL_data->dlen);
  354. DHD_BTA(("\n"));
  355. }
  356. static const struct {
  357. uint8 evtval;
  358. char *evtstr;
  359. } evt_map[] = {
  360. { HCI_Command_Complete, "Command Complete" },
  361. { HCI_Command_Status, "Command Status" },
  362. { HCI_Flush_Occurred, "Flush Occurred" },
  363. { HCI_Enhanced_Flush_Complete, "Enhanced Flush Complete" },
  364. { HCI_Physical_Link_Complete, "Physical Link Complete" },
  365. { HCI_Channel_Select, "Channel Select" },
  366. { HCI_Disconnect_Physical_Link_Complete, "Disconnect Physical Link Complete" },
  367. { HCI_Logical_Link_Complete, "Logical Link Complete" },
  368. { HCI_Disconnect_Logical_Link_Complete, "Disconnect Logical Link Complete" },
  369. { HCI_Number_of_Completed_Data_Blocks, "Number of Completed Data Blocks" },
  370. { HCI_Short_Range_Mode_Change_Complete, "Short Range Mode Change Complete" },
  371. { HCI_Vendor_Specific, "Vendor Specific" }
  372. };
  373. static char *
  374. evt2str(uint8 evt, char *buf)
  375. {
  376. uint i;
  377. sprintf(buf, "Unknown");
  378. for (i = 0; i < ARRAYSIZE(evt_map); i++) {
  379. if (evt == evt_map[i].evtval) {
  380. sprintf(buf, evt_map[i].evtstr);
  381. }
  382. }
  383. return buf;
  384. }
  385. void
  386. dhd_bta_hcidump_evt(dhd_pub_t *pub, amp_hci_event_t *event)
  387. {
  388. char buf[34];
  389. DHD_BTA(("dhd: > HCI Event: %s(0x%x) plen %d\n",
  390. evt2str(event->ecode, buf), event->ecode, event->plen));
  391. prhex(NULL, event->parms, event->plen);
  392. DHD_BTA(("\n"));
  393. }
  394. #endif /* BCMDBG */