2 * BT-AMP support routines
4 * Copyright (C) 1999-2016, Broadcom Corporation
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:
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.
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.
25 * <<Broadcom-WL-IPTag/Open:>>
27 * $Id: dhd_bta.c 514727 2014-11-12 03:02:48Z $
29 #error "WLBTAMP is not defined"
35 #include <bcmendian.h>
36 #include <proto/802.11.h>
37 #include <proto/802.11_bta.h>
38 #include <proto/bt_amp_hci.h>
39 #include <dngl_stats.h>
42 #include <dhd_proto.h>
49 #ifdef SEND_HCI_CMD_VIA_IOCTL
50 #define BTA_HCI_CMD_MAX_LEN HCI_CMD_PREAMBLE_SIZE + HCI_CMD_DATA_SIZE
52 /* Send HCI cmd via wl iovar HCI_cmd to the dongle. */
54 dhd_bta_docmd(dhd_pub_t *pub, void *cmd_buf, uint cmd_len)
56 amp_hci_cmd_t *cmd = (amp_hci_cmd_t *)cmd_buf;
57 uint8 buf[BTA_HCI_CMD_MAX_LEN + 16];
58 uint len = sizeof(buf);
61 if (cmd_len < HCI_CMD_PREAMBLE_SIZE)
64 if ((uint)cmd->plen + HCI_CMD_PREAMBLE_SIZE > cmd_len)
67 len = bcm_mkiovar("HCI_cmd",
68 (char *)cmd, (uint)cmd->plen + HCI_CMD_PREAMBLE_SIZE, (char *)buf, len);
71 memset(&ioc, 0, sizeof(ioc));
73 ioc.cmd = WLC_SET_VAR;
78 return dhd_wl_ioctl(pub, &ioc, ioc.buf, ioc.len);
80 #else /* !SEND_HCI_CMD_VIA_IOCTL */
83 dhd_bta_flush_hcidata(dhd_pub_t *pub, uint16 llh)
89 q = dhd_bus_txq(pub->bus);
93 DHD_BTA(("dhd: flushing HCI ACL data for logical link %u...\n", llh));
95 dhd_os_sdlock_txq(pub);
97 /* Walk through the txq and toss all HCI ACL data packets */
98 PKTQ_PREC_ITER(q, prec) {
99 void *head_pkt = NULL;
101 while (pktq_ppeek(q, prec) != head_pkt) {
102 void *pkt = pktq_pdeq(q, prec);
105 dhd_prot_hdrpull(pub, &ifidx, pkt, NULL, NULL);
107 if (PKTLEN(pub->osh, pkt) >= RFC1042_HDR_LEN) {
108 struct ether_header *eh =
109 (struct ether_header *)PKTDATA(pub->osh, pkt);
111 if (ntoh16(eh->ether_type) < ETHER_TYPE_MIN) {
112 struct dot11_llc_snap_header *lsh =
113 (struct dot11_llc_snap_header *)&eh[1];
115 if (bcmp(lsh, BT_SIG_SNAP_MPROT,
116 DOT11_LLC_SNAP_HDR_LEN - 2) == 0 &&
117 ntoh16(lsh->type) == BTA_PROT_L2CAP) {
118 amp_hci_ACL_data_t *ACL_data =
119 (amp_hci_ACL_data_t *)&lsh[1];
120 uint16 handle = ltoh16(ACL_data->handle);
122 if (HCI_ACL_DATA_HANDLE(handle) == llh) {
123 PKTFREE(pub->osh, pkt, TRUE);
131 dhd_prot_hdrpush(pub, ifidx, pkt);
133 if (head_pkt == NULL)
135 pktq_penq(q, prec, pkt);
139 dhd_os_sdunlock_txq(pub);
141 DHD_BTA(("dhd: flushed %u packet(s) for logical link %u...\n", count, llh));
144 /* Handle HCI cmd locally.
145 * Return 0: continue to send the cmd across SDIO
147 * > 0: stop, succuess
150 _dhd_bta_docmd(dhd_pub_t *pub, amp_hci_cmd_t *cmd)
154 switch (ltoh16_ua((uint8 *)&cmd->opcode)) {
155 case HCI_Enhanced_Flush: {
156 eflush_cmd_parms_t *cmdparms = (eflush_cmd_parms_t *)cmd->parms;
157 dhd_bta_flush_hcidata(pub, ltoh16_ua(cmdparms->llh));
167 /* Send HCI cmd encapsulated in BT-SIG frame via data channel to the dongle. */
169 dhd_bta_docmd(dhd_pub_t *pub, void *cmd_buf, uint cmd_len)
171 amp_hci_cmd_t *cmd = (amp_hci_cmd_t *)cmd_buf;
172 struct ether_header *eh;
173 struct dot11_llc_snap_header *lsh;
174 osl_t *osh = pub->osh;
179 if (cmd_len < HCI_CMD_PREAMBLE_SIZE) {
180 DHD_ERROR(("dhd_bta_docmd: short command, cmd_len %u\n", cmd_len));
184 if ((len = (uint)cmd->plen + HCI_CMD_PREAMBLE_SIZE) > cmd_len) {
185 DHD_ERROR(("dhd_bta_docmd: malformed command, len %u cmd_len %u\n",
187 /* return BCME_BADLEN; */
190 p = PKTGET(osh, pub->hdrlen + RFC1042_HDR_LEN + len, TRUE);
192 DHD_ERROR(("dhd_bta_docmd: out of memory\n"));
197 /* intercept and handle the HCI cmd locally */
198 if ((status = _dhd_bta_docmd(pub, cmd)) > 0)
203 /* copy in HCI cmd */
204 PKTPULL(osh, p, pub->hdrlen + RFC1042_HDR_LEN);
205 bcopy(cmd, PKTDATA(osh, p), len);
207 /* copy in partial Ethernet header with BT-SIG LLC/SNAP header */
208 PKTPUSH(osh, p, RFC1042_HDR_LEN);
209 eh = (struct ether_header *)PKTDATA(osh, p);
210 bzero(eh->ether_dhost, ETHER_ADDR_LEN);
211 ETHER_SET_LOCALADDR(eh->ether_dhost);
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);
218 return dhd_sendpkt(pub, 0, p);
220 #endif /* !SEND_HCI_CMD_VIA_IOCTL */
222 /* Send HCI ACL data to dongle via data channel */
224 dhd_bta_tx_hcidata(dhd_pub_t *pub, void *data_buf, uint data_len)
226 amp_hci_ACL_data_t *data = (amp_hci_ACL_data_t *)data_buf;
227 struct ether_header *eh;
228 struct dot11_llc_snap_header *lsh;
229 osl_t *osh = pub->osh;
233 if (data_len < HCI_ACL_DATA_PREAMBLE_SIZE) {
234 DHD_ERROR(("dhd_bta_tx_hcidata: short data_buf, data_len %u\n", data_len));
238 if ((len = (uint)ltoh16(data->dlen) + HCI_ACL_DATA_PREAMBLE_SIZE) > data_len) {
239 DHD_ERROR(("dhd_bta_tx_hcidata: malformed hci data, len %u data_len %u\n",
241 /* return BCME_BADLEN; */
244 p = PKTGET(osh, pub->hdrlen + RFC1042_HDR_LEN + len, TRUE);
246 DHD_ERROR(("dhd_bta_tx_hcidata: out of memory\n"));
251 /* copy in HCI ACL data header and HCI ACL data */
252 PKTPULL(osh, p, pub->hdrlen + RFC1042_HDR_LEN);
253 bcopy(data, PKTDATA(osh, p), len);
255 /* copy in partial Ethernet header with BT-SIG LLC/SNAP header */
256 PKTPUSH(osh, p, RFC1042_HDR_LEN);
257 eh = (struct ether_header *)PKTDATA(osh, p);
258 bzero(eh->ether_dhost, ETHER_ADDR_LEN);
259 bcopy(&pub->mac, eh->ether_shost, ETHER_ADDR_LEN);
260 eh->ether_type = hton16(len + DOT11_LLC_SNAP_HDR_LEN);
261 lsh = (struct dot11_llc_snap_header *)&eh[1];
262 bcopy(BT_SIG_SNAP_MPROT, lsh, DOT11_LLC_SNAP_HDR_LEN - 2);
263 lsh->type = HTON16(BTA_PROT_L2CAP);
265 return dhd_sendpkt(pub, 0, p);
268 /* txcomplete callback */
270 dhd_bta_tx_hcidata_complete(dhd_pub_t *dhdp, void *txp, bool success)
272 uint8 *pktdata = (uint8 *)PKTDATA(dhdp->osh, txp);
273 amp_hci_ACL_data_t *ACL_data = (amp_hci_ACL_data_t *)(pktdata + RFC1042_HDR_LEN);
274 uint16 handle = ltoh16(ACL_data->handle);
275 uint16 llh = HCI_ACL_DATA_HANDLE(handle);
277 wl_event_msg_t event;
278 uint8 data[HCI_EVT_PREAMBLE_SIZE + sizeof(num_completed_data_blocks_evt_parms_t)];
279 amp_hci_event_t *evt;
280 num_completed_data_blocks_evt_parms_t *parms;
282 uint16 len = HCI_EVT_PREAMBLE_SIZE + sizeof(num_completed_data_blocks_evt_parms_t);
284 /* update the event struct */
285 memset(&event, 0, sizeof(event));
286 event.version = hton16(BCM_EVENT_MSG_VERSION);
287 event.event_type = hton32(WLC_E_BTA_HCI_EVENT);
291 event.datalen = hton32(len);
294 /* generate Number of Completed Blocks event */
295 evt = (amp_hci_event_t *)data;
296 evt->ecode = HCI_Number_of_Completed_Data_Blocks;
297 evt->plen = sizeof(num_completed_data_blocks_evt_parms_t);
299 parms = (num_completed_data_blocks_evt_parms_t *)evt->parms;
300 htol16_ua_store(dhdp->maxdatablks, (uint8 *)&parms->num_blocks);
301 parms->num_handles = 1;
302 htol16_ua_store(llh, (uint8 *)&parms->completed[0].handle);
303 parms->completed[0].pkts = 1;
304 parms->completed[0].blocks = 1;
306 dhd_sendup_event_common(dhdp, &event, data);
311 dhd_bta_doevt(dhd_pub_t *dhdp, void *data_buf, uint data_len)
313 amp_hci_event_t *evt = (amp_hci_event_t *)data_buf;
318 switch (evt->ecode) {
319 case HCI_Command_Complete: {
320 cmd_complete_parms_t *parms = (cmd_complete_parms_t *)evt->parms;
321 switch (ltoh16_ua((uint8 *)&parms->opcode)) {
322 case HCI_Read_Data_Block_Size: {
323 read_data_block_size_evt_parms_t *parms2 =
324 (read_data_block_size_evt_parms_t *)parms->parms;
325 dhdp->maxdatablks = ltoh16_ua((uint8 *)&parms2->data_block_num);
332 case HCI_Flush_Occurred: {
333 flush_occurred_evt_parms_t *evt_parms = (flush_occurred_evt_parms_t *)evt->parms;
334 dhd_bta_flush_hcidata(dhdp, ltoh16_ua((uint8 *)&evt_parms->handle));