blob: 6ce1ac7f6a2acc968b347c94e1c60379ac43f6cb [file] [log] [blame]
Toshi Kikuchid99495a2012-11-30 18:50:29 -08001/******************************************************************************
2 *
3 * Copyright (C) 2012 Marvell International Ltd.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at:
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 ******************************************************************************/
18
19#define LOG_TAG "hardware_mrvl"
20
21#include <utils/Log.h>
22#include <stdlib.h>
23#include <stdio.h>
24#include <string.h>
25#include <assert.h>
26
27#include "bt_vendor_lib.h"
28#include "bt_hci_bdroid.h"
29
30#define HCI_CMD_MARVELL_WRITE_PCM_SETTINGS 0xFC07
31#define HCI_CMD_MARVELL_WRITE_PCM_SYNC_SETTINGS 0xFC28
32#define HCI_CMD_MARVELL_WRITE_PCM_LINK_SETTINGS 0xFC29
33#define HCI_CMD_MARVELL_SET_SCO_DATA_PATH 0xFC1D
34#define HCI_CMD_MARVELL_WRITE_BD_ADDRESS 0xFC22
35
36#define WRITE_PCM_SETTINGS_SIZE 1
37#define WRITE_PCM_SYNC_SETTINGS_SIZE 3
38#define WRITE_PCM_LINK_SETTINGS_SIZE 2
39#define SET_SCO_DATA_PATH_SIZE 1
40#define WRITE_BD_ADDRESS_SIZE 8
41
42
43#define HCI_CMD_PREAMBLE_SIZE 3
44
45#define HCI_EVT_CMD_CMPL_OPCODE 3
46
47#define STREAM_TO_UINT16(u16, p) \
48do { \
49 u16 = ((uint16_t)(*(p)) + (((uint16_t)(*((p) + 1))) << 8)); \
50 (p) += 2; \
51} while (0)
52
53#define UINT16_TO_STREAM(p, u16) \
54do { \
55 *(p)++ = (uint8_t)(u16); \
56 *(p)++ = (uint8_t)((u16) >> 8); \
57} while (0)
58
59struct bt_evt_param_t {
60 uint16_t cmd;
61 uint8_t cmd_ret_param;
62};
63
64/***********************************************************
65 * Externs
66 ***********************************************************
67 */
68extern unsigned char bdaddr[6];
69extern bt_vendor_callbacks_t *vnd_cb;
70
71/***********************************************************
72 * Local variables
73 ***********************************************************
74 */
75static uint8_t write_pcm_settings[WRITE_PCM_SETTINGS_SIZE] = {
76 0x02
77};
78
79static uint8_t write_pcm_sync_settings[WRITE_PCM_SYNC_SETTINGS_SIZE] = {
80 0x03,
81 0x00,
82 0x03
83};
84
85static uint8_t write_pcm_link_settings[WRITE_PCM_LINK_SETTINGS_SIZE] = {
86 0x03,
87 0x00
88};
89
90static uint8_t set_sco_data_path[SET_SCO_DATA_PATH_SIZE] = {
91 0x01
92};
93
94static uint8_t write_bd_address[WRITE_BD_ADDRESS_SIZE] = {
95 0xFE, /* Parameter ID */
96 0x06, /* bd_addr length */
97 0x00, /* 6th byte of bd_addr */
98 0x00, /* 5th */
99 0x00, /* 4th */
100 0x00, /* 3rd */
101 0x00, /* 2nd */
102 0x00 /* 1st */
103};
104
105/***********************************************************
106 * Local functions
107 ***********************************************************
108 */
109static char *cmd_to_str(uint16_t cmd)
110{
111 switch (cmd) {
112 case HCI_CMD_MARVELL_WRITE_PCM_SETTINGS:
113 return "write_pcm_settings";
114 case HCI_CMD_MARVELL_WRITE_PCM_SYNC_SETTINGS:
115 return "write_pcm_sync_settings";
116 case HCI_CMD_MARVELL_WRITE_PCM_LINK_SETTINGS:
117 return "write_pcm_link_settings";
118 case HCI_CMD_MARVELL_SET_SCO_DATA_PATH:
119 return "set_sco_data_path";
120 case HCI_CMD_MARVELL_WRITE_BD_ADDRESS:
121 return "write_bd_address";
122 default:
123 break;
124 }
125
126 return "unknown command";
127}
128
129static void populate_bd_addr_params(uint8_t *params, uint8_t *addr)
130{
131 assert(params && addr);
132
133 *params++ = addr[5];
134 *params++ = addr[4];
135 *params++ = addr[3];
136 *params++ = addr[2];
137 *params++ = addr[1];
138 *params = addr[0];
139}
140
141static HC_BT_HDR *build_cmd_buf(uint16_t cmd, uint8_t pl_len, uint8_t *payload)
142{
143 HC_BT_HDR *p_buf = NULL;
144 uint16_t cmd_len = HCI_CMD_PREAMBLE_SIZE + pl_len;
145 uint8_t *p;
146
147 assert(vnd_cb && payload);
148
149 p_buf = (HC_BT_HDR *) vnd_cb->alloc(BT_HC_HDR_SIZE + cmd_len);
150
151 if (!p_buf)
152 return NULL;
153
154 p_buf->event = MSG_STACK_TO_HC_HCI_CMD;
155 p_buf->offset = 0;
156 p_buf->layer_specific = 0;
157 p_buf->len = cmd_len;
158
159 p = (uint8_t *) (p_buf + 1);
160
161 /* opcode */
162 UINT16_TO_STREAM(p, cmd);
163
164 /* length of payload */
165 *p = pl_len;
166 ++p;
167
168 /* payload */
169 memcpy(p, payload, pl_len);
170
171 return p_buf;
172}
173
174static void parse_evt_buf(HC_BT_HDR *p_evt_buf,
175 struct bt_evt_param_t *evt_params)
176{
177 uint8_t *p = (uint8_t *) (p_evt_buf + 1) + HCI_EVT_CMD_CMPL_OPCODE;
178
179 assert(p_evt_buf && evt_params);
180
181 /* opcode */
182 STREAM_TO_UINT16(evt_params->cmd, p);
183
184 /* command return parameter */
185 evt_params->cmd_ret_param = *p;
186}
187
188static void hw_mrvl_config_start_cb(void *p_mem)
189{
190 HC_BT_HDR *p_evt_buf = (HC_BT_HDR *) p_mem;
191 struct bt_evt_param_t evt_params = {0, 0};
192
193 assert(vnd_cb && p_mem);
194
195 parse_evt_buf(p_evt_buf, &evt_params);
196
197 /* free the buffer */
198 vnd_cb->dealloc(p_evt_buf);
199
200 switch (evt_params.cmd) {
201 case HCI_CMD_MARVELL_WRITE_BD_ADDRESS:
202 /* fw config succeeds */
203 ALOGI("FW config succeeds!");
204 vnd_cb->fwcfg_cb(BT_VND_OP_RESULT_SUCCESS);
205 return;
206
207 default:
208 ALOGE("Received event for unexpected cmd (0x%04hX). Fail.",
209 evt_params.cmd);
210 break;
211 } /* end of switch (evt_params.cmd) */
212
213 ALOGE("Vendor lib fwcfg aborted");
214 vnd_cb->fwcfg_cb(BT_VND_OP_RESULT_FAIL);
215}
216
217static void hw_mrvl_sco_config_cb(void *p_mem)
218{
219 HC_BT_HDR *p_evt_buf = (HC_BT_HDR *) p_mem;
220 struct bt_evt_param_t evt_params = {0, 0};
221 uint16_t cmd;
222 HC_BT_HDR *p_buf;
223
224 assert(vnd_cb && p_mem);
225
226 parse_evt_buf(p_evt_buf, &evt_params);
227
228 /* free the buffer */
229 vnd_cb->dealloc(p_evt_buf);
230
231 switch (evt_params.cmd) {
232 case HCI_CMD_MARVELL_WRITE_PCM_SETTINGS:
233 /* Send HCI_CMD_MARVELL_WRITE_PCM_SYNC_SETTINGS */
234 cmd = HCI_CMD_MARVELL_WRITE_PCM_SYNC_SETTINGS;
235 p_buf = build_cmd_buf(cmd,
236 WRITE_PCM_SYNC_SETTINGS_SIZE,
237 write_pcm_sync_settings);
238 break;
239
240 case HCI_CMD_MARVELL_WRITE_PCM_SYNC_SETTINGS:
241 /* Send HCI_CMD_MARVELL_WRITE_PCM_LINK_SETTINGS */
242 cmd = HCI_CMD_MARVELL_WRITE_PCM_LINK_SETTINGS;
243 p_buf = build_cmd_buf(cmd,
244 WRITE_PCM_LINK_SETTINGS_SIZE,
245 write_pcm_link_settings);
246 break;
247
248 case HCI_CMD_MARVELL_WRITE_PCM_LINK_SETTINGS:
249 /* Send HCI_CMD_MARVELL_SET_SCO_DATA_PATH */
250 cmd = HCI_CMD_MARVELL_SET_SCO_DATA_PATH;
251 p_buf = build_cmd_buf(cmd,
252 SET_SCO_DATA_PATH_SIZE,
253 set_sco_data_path);
254 break;
255
256 case HCI_CMD_MARVELL_SET_SCO_DATA_PATH:
257 /* sco config succeeds */
258 ALOGI("SCO PCM config succeeds!");
259 vnd_cb->scocfg_cb(BT_VND_OP_RESULT_SUCCESS);
260 return;
261
262 default:
263 ALOGE("Received event for unexpected cmd (0x%04hX). Fail.",
264 evt_params.cmd);
265 p_buf = NULL;
266 break;
267 } /* switch (evt_params.cmd) */
268
269 if (p_buf) {
270 ALOGI("Sending hci command 0x%04hX (%s)", cmd, cmd_to_str(cmd));
271 if (vnd_cb->xmit_cb(cmd, p_buf, hw_mrvl_sco_config_cb))
272 return;
273 else
274 vnd_cb->dealloc(p_buf);
275 }
276
277 ALOGE("Vendor lib scocfg aborted");
278 vnd_cb->scocfg_cb(BT_VND_OP_RESULT_FAIL);
279}
280
281/***********************************************************
282 * Global functions
283 ***********************************************************
284 */
285void hw_mrvl_config_start(void)
286{
287 HC_BT_HDR *p_buf;
288 uint16_t cmd;
289
290 assert(vnd_cb);
291
292 ALOGI("Start HW config ...");
293 /* Start with HCI_CMD_MARVELL_WRITE_BD_ADDRESS */
294 ALOGI("Setting bd addr to %02hhX:%02hhX:%02hhX:%02hhX:%02hhX:%02hhX",
295 bdaddr[0], bdaddr[1], bdaddr[2],
296 bdaddr[3], bdaddr[4], bdaddr[5]);
297 populate_bd_addr_params(write_bd_address + 2, bdaddr);
298
299 cmd = HCI_CMD_MARVELL_WRITE_BD_ADDRESS;
300 p_buf = build_cmd_buf(cmd,
301 WRITE_BD_ADDRESS_SIZE,
302 write_bd_address);
303
304 if (p_buf) {
305 ALOGI("Sending hci command 0x%04hX (%s)", cmd, cmd_to_str(cmd));
306 if (vnd_cb->xmit_cb(cmd, p_buf, hw_mrvl_config_start_cb))
307 return;
308 else
309 vnd_cb->dealloc(p_buf);
310 }
311
312 ALOGE("Vendor lib fwcfg aborted");
313 vnd_cb->fwcfg_cb(BT_VND_OP_RESULT_FAIL);
314}
315
316
317void hw_mrvl_sco_config(void)
318{
319 HC_BT_HDR *p_buf;
320 uint16_t cmd;
321
322 assert(vnd_cb);
323
324 ALOGI("Start SCO config ...");
325 /* Start with HCI_CMD_MARVELL_WRITE_PCM_SETTINGS */
326 cmd = HCI_CMD_MARVELL_WRITE_PCM_SETTINGS;
327 p_buf = build_cmd_buf(cmd,
328 WRITE_PCM_SETTINGS_SIZE,
329 write_pcm_settings);
330
331 if (p_buf) {
332 ALOGI("Sending hci command 0x%04hX (%s)", cmd, cmd_to_str(cmd));
333 if (vnd_cb->xmit_cb(cmd, p_buf, hw_mrvl_sco_config_cb))
334 return;
335 else
336 vnd_cb->dealloc(p_buf);
337 }
338
339 ALOGE("Vendor lib scocfg aborted");
340 vnd_cb->scocfg_cb(BT_VND_OP_RESULT_FAIL);
341}