summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorToshi Kikuchi <toshik@google.com>2012-11-30 18:50:29 -0800
committerToshi Kikuchi <toshik@google.com>2012-12-03 11:03:36 -0800
commitd99495a1f8ffae051dda62584f7af474345e5fbd (patch)
tree6f69f249d9cf69adb7057e55f26d1fdf2019b7ea
parent2a61c047fe51b6aa60901a9dea3939bd167fd6a1 (diff)
downloadbt-d99495a1f8ffae051dda62584f7af474345e5fbd.tar.gz
libbt: Add BD address and PCM config commands:
HCI_CMD_MARVELL_WRITE_PCM_SETTINGS 0xFC07 HCI_CMD_MARVELL_WRITE_PCM_SYNC_SETTINGS 0xFC28 HCI_CMD_MARVELL_WRITE_PCM_LINK_SETTINGS 0xFC29 HCI_CMD_MARVELL_SET_SCO_DATA_PATH 0xFC1D HCI_CMD_MARVELL_WRITE_BD_ADDRESS 0xFC22 Change-Id: Ie070fd1acd62367a1c9248055da4b25fda381189 Signed-off-by: Toshi Kikuchi <toshik@google.com>
-rw-r--r--libbt-vendor/Android.mk3
-rw-r--r--libbt-vendor/bt_vendor_mrvl.c195
-rw-r--r--libbt-vendor/hardware_mrvl.c341
3 files changed, 454 insertions, 85 deletions
diff --git a/libbt-vendor/Android.mk b/libbt-vendor/Android.mk
index 86f17bb..1914919 100644
--- a/libbt-vendor/Android.mk
+++ b/libbt-vendor/Android.mk
@@ -5,7 +5,8 @@ include $(CLEAR_VARS)
BDROID_DIR := $(TOP_DIR)external/bluetooth/bluedroid
LOCAL_SRC_FILES := \
- bt_vendor_mrvl.c
+ bt_vendor_mrvl.c \
+ hardware_mrvl.c
LOCAL_C_INCLUDES += \
$(BDROID_DIR)/hci/include
diff --git a/libbt-vendor/bt_vendor_mrvl.c b/libbt-vendor/bt_vendor_mrvl.c
index 93664cc..e1e58d5 100644
--- a/libbt-vendor/bt_vendor_mrvl.c
+++ b/libbt-vendor/bt_vendor_mrvl.c
@@ -15,6 +15,7 @@
* limitations under the License.
*
******************************************************************************/
+#define LOG_TAG "bt_vendor_mrvl"
#include <time.h>
#include <errno.h>
@@ -31,108 +32,134 @@
#include <sys/select.h>
#include <sys/mman.h>
#include <pthread.h>
+#include <utils/Log.h>
+
#include "bt_vendor_lib.h"
-/* ioctl command to release the read thread before driver close */
-#define MBTCHAR_IOCTL_RELEASE _IO ('M',1)
-#define VERSION "M001"
+/* ioctl command to release the read thread before driver close */
+#define MBTCHAR_IOCTL_RELEASE _IO('M', 1)
-static bt_vendor_callbacks_t *vnd_cb = NULL;
+#define VERSION "M002"
-static unsigned char bdaddr[6];
-static char mchar_port[] = "/dev/mbtchar0";
+/***********************************************************
+ * Externs
+ ***********************************************************
+ */
+void hw_mrvl_config_start(void);
+void hw_mrvl_sco_config(void);
+/***********************************************************
+ * Local variables
+ ***********************************************************
+ */
+static const char mchar_port[] = "/dev/mbtchar0";
static int mchar_fd = -1;
-int bt_vnd_mrvl_if_init(const bt_vendor_callbacks_t* p_cb, unsigned char *local_bdaddr)
+/***********************************************************
+ * Global variables
+ ***********************************************************
+ */
+bt_vendor_callbacks_t *vnd_cb;
+unsigned char bdaddr[6];
+
+/***********************************************************
+ * Local functions
+ ***********************************************************
+ */
+static int bt_vnd_mrvl_if_init(const bt_vendor_callbacks_t *p_cb,
+ unsigned char *local_bdaddr)
{
- vnd_cb = p_cb;
- memcpy(bdaddr, local_bdaddr, sizeof(bdaddr));
- return 0;
+ ALOGI("Marvell BT Vendor Lib: ver %s", VERSION);
+ vnd_cb = (bt_vendor_callbacks_t *) p_cb;
+ memcpy(bdaddr, local_bdaddr, sizeof(bdaddr));
+ return 0;
}
-int bt_vnd_mrvl_if_op(bt_vendor_opcode_t opcode, void *param)
+static int bt_vnd_mrvl_if_op(bt_vendor_opcode_t opcode, void *param)
{
- int ret = 0;
- int power_state;
- int local_st = 0;
-
- switch (opcode) {
- case BT_VND_OP_POWER_CTRL:
- power_state = (int *)param;
- if (BT_VND_PWR_OFF == power_state) {
- } else if (BT_VND_PWR_ON == power_state) {
- } else {
- ret = -1;
- }
- break;
- case BT_VND_OP_FW_CFG:
- // TODO: Perform any vendor specific initialization or configuration on the BT Controller
- // ret = xxx
- if (vnd_cb) {
- vnd_cb->fwcfg_cb(ret);
- }
- break;
- case BT_VND_OP_SCO_CFG:
- // TODO: Perform any vendor specific SCO/PCM configuration on the BT Controller.
- // ret = xxx
- if (vnd_cb) {
- vnd_cb->scocfg_cb(ret);
- }
- break;
- case BT_VND_OP_USERIAL_OPEN:
- mchar_fd = open(mchar_port, O_RDWR|O_NOCTTY);
- if (mchar_fd < 0) {
- ret = -1;
- } else {
- ret = 1;
- }
- ((int *)param)[0] = mchar_fd;
- break;
- case BT_VND_OP_USERIAL_CLOSE:
- if (mchar_fd < 0) {
- ret = -1;
- } else {
- /* mbtchar port is blocked on read. Release the port before we close it */
- ioctl(mchar_fd,MBTCHAR_IOCTL_RELEASE,&local_st);
- /* Give it sometime before we close the mbtchar */
- usleep(1000);
- if (close(mchar_fd) < 0) {
- ret = -1;
- } else {
- mchar_fd = -1; /* closed successfully */
- }
- }
- break;
- case BT_VND_OP_GET_LPM_IDLE_TIMEOUT:
- break;
- case BT_VND_OP_LPM_SET_MODE:
- // TODO: Enable or disable LPM mode on BT Controller.
- // ret = xx;
- if (vnd_cb) {
- vnd_cb->lpm_cb(ret);
- }
- break;
- case BT_VND_OP_LPM_WAKE_SET_STATE:
- break;
- default:
- ret = -1;
- break;
- }
- return ret;
+ int ret = 0;
+ int *power_state = NULL;
+ int local_st = 0;
+
+ /* ALOGD("opcode = %d", opcode); */
+ switch (opcode) {
+ case BT_VND_OP_POWER_CTRL:
+ power_state = (int *)param;
+ if (BT_VND_PWR_OFF == *power_state) {
+ ALOGD("Power off");
+ } else if (BT_VND_PWR_ON == *power_state) {
+ ALOGD("Power on");
+ } else {
+ ret = -1;
+ }
+ break;
+ case BT_VND_OP_FW_CFG:
+ hw_mrvl_config_start();
+ break;
+ case BT_VND_OP_SCO_CFG:
+ hw_mrvl_sco_config();
+ break;
+ case BT_VND_OP_USERIAL_OPEN:
+ mchar_fd = open(mchar_port, O_RDWR|O_NOCTTY);
+ if (mchar_fd < 0) {
+ ALOGE("Fail to open port %s", mchar_port);
+ ret = -1;
+ } else {
+ ALOGD("open port %s success", mchar_port);
+ ret = 1;
+ }
+ ((int *)param)[0] = mchar_fd;
+ break;
+ case BT_VND_OP_USERIAL_CLOSE:
+ if (mchar_fd < 0) {
+ ret = -1;
+ } else {
+ /* mbtchar port is blocked on read. Release the port
+ * before we close it.
+ */
+ ioctl(mchar_fd, MBTCHAR_IOCTL_RELEASE, &local_st);
+ /* Give it sometime before we close the mbtchar */
+ usleep(1000);
+ ALOGD("close port %s", mchar_port);
+ if (close(mchar_fd) < 0) {
+ ALOGE("Fail to close port %s", mchar_port);
+ ret = -1;
+ } else {
+ mchar_fd = -1; /* closed successfully */
+ }
+ }
+ break;
+ case BT_VND_OP_GET_LPM_IDLE_TIMEOUT:
+ break;
+ case BT_VND_OP_LPM_SET_MODE:
+ /* TODO: Enable or disable LPM mode on BT Controller.
+ * ret = xx;
+ */
+ if (vnd_cb)
+ vnd_cb->lpm_cb(ret);
+
+ break;
+ case BT_VND_OP_LPM_WAKE_SET_STATE:
+ break;
+ default:
+ ret = -1;
+ break;
+ } /* switch (opcode) */
+
+ return ret;
}
-void bt_vnd_mrvl_if_cleanup(void)
+static void bt_vnd_mrvl_if_cleanup(void)
{
- return;
+ return;
}
const bt_vendor_interface_t BLUETOOTH_VENDOR_LIB_INTERFACE = {
- sizeof(bt_vendor_interface_t),
- bt_vnd_mrvl_if_init,
- bt_vnd_mrvl_if_op,
- bt_vnd_mrvl_if_cleanup,
+ sizeof(bt_vendor_interface_t),
+ bt_vnd_mrvl_if_init,
+ bt_vnd_mrvl_if_op,
+ bt_vnd_mrvl_if_cleanup,
};
diff --git a/libbt-vendor/hardware_mrvl.c b/libbt-vendor/hardware_mrvl.c
new file mode 100644
index 0000000..6ce1ac7
--- /dev/null
+++ b/libbt-vendor/hardware_mrvl.c
@@ -0,0 +1,341 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2012 Marvell International Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "hardware_mrvl"
+
+#include <utils/Log.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+
+#include "bt_vendor_lib.h"
+#include "bt_hci_bdroid.h"
+
+#define HCI_CMD_MARVELL_WRITE_PCM_SETTINGS 0xFC07
+#define HCI_CMD_MARVELL_WRITE_PCM_SYNC_SETTINGS 0xFC28
+#define HCI_CMD_MARVELL_WRITE_PCM_LINK_SETTINGS 0xFC29
+#define HCI_CMD_MARVELL_SET_SCO_DATA_PATH 0xFC1D
+#define HCI_CMD_MARVELL_WRITE_BD_ADDRESS 0xFC22
+
+#define WRITE_PCM_SETTINGS_SIZE 1
+#define WRITE_PCM_SYNC_SETTINGS_SIZE 3
+#define WRITE_PCM_LINK_SETTINGS_SIZE 2
+#define SET_SCO_DATA_PATH_SIZE 1
+#define WRITE_BD_ADDRESS_SIZE 8
+
+
+#define HCI_CMD_PREAMBLE_SIZE 3
+
+#define HCI_EVT_CMD_CMPL_OPCODE 3
+
+#define STREAM_TO_UINT16(u16, p) \
+do { \
+ u16 = ((uint16_t)(*(p)) + (((uint16_t)(*((p) + 1))) << 8)); \
+ (p) += 2; \
+} while (0)
+
+#define UINT16_TO_STREAM(p, u16) \
+do { \
+ *(p)++ = (uint8_t)(u16); \
+ *(p)++ = (uint8_t)((u16) >> 8); \
+} while (0)
+
+struct bt_evt_param_t {
+ uint16_t cmd;
+ uint8_t cmd_ret_param;
+};
+
+/***********************************************************
+ * Externs
+ ***********************************************************
+ */
+extern unsigned char bdaddr[6];
+extern bt_vendor_callbacks_t *vnd_cb;
+
+/***********************************************************
+ * Local variables
+ ***********************************************************
+ */
+static uint8_t write_pcm_settings[WRITE_PCM_SETTINGS_SIZE] = {
+ 0x02
+};
+
+static uint8_t write_pcm_sync_settings[WRITE_PCM_SYNC_SETTINGS_SIZE] = {
+ 0x03,
+ 0x00,
+ 0x03
+};
+
+static uint8_t write_pcm_link_settings[WRITE_PCM_LINK_SETTINGS_SIZE] = {
+ 0x03,
+ 0x00
+};
+
+static uint8_t set_sco_data_path[SET_SCO_DATA_PATH_SIZE] = {
+ 0x01
+};
+
+static uint8_t write_bd_address[WRITE_BD_ADDRESS_SIZE] = {
+ 0xFE, /* Parameter ID */
+ 0x06, /* bd_addr length */
+ 0x00, /* 6th byte of bd_addr */
+ 0x00, /* 5th */
+ 0x00, /* 4th */
+ 0x00, /* 3rd */
+ 0x00, /* 2nd */
+ 0x00 /* 1st */
+};
+
+/***********************************************************
+ * Local functions
+ ***********************************************************
+ */
+static char *cmd_to_str(uint16_t cmd)
+{
+ switch (cmd) {
+ case HCI_CMD_MARVELL_WRITE_PCM_SETTINGS:
+ return "write_pcm_settings";
+ case HCI_CMD_MARVELL_WRITE_PCM_SYNC_SETTINGS:
+ return "write_pcm_sync_settings";
+ case HCI_CMD_MARVELL_WRITE_PCM_LINK_SETTINGS:
+ return "write_pcm_link_settings";
+ case HCI_CMD_MARVELL_SET_SCO_DATA_PATH:
+ return "set_sco_data_path";
+ case HCI_CMD_MARVELL_WRITE_BD_ADDRESS:
+ return "write_bd_address";
+ default:
+ break;
+ }
+
+ return "unknown command";
+}
+
+static void populate_bd_addr_params(uint8_t *params, uint8_t *addr)
+{
+ assert(params && addr);
+
+ *params++ = addr[5];
+ *params++ = addr[4];
+ *params++ = addr[3];
+ *params++ = addr[2];
+ *params++ = addr[1];
+ *params = addr[0];
+}
+
+static HC_BT_HDR *build_cmd_buf(uint16_t cmd, uint8_t pl_len, uint8_t *payload)
+{
+ HC_BT_HDR *p_buf = NULL;
+ uint16_t cmd_len = HCI_CMD_PREAMBLE_SIZE + pl_len;
+ uint8_t *p;
+
+ assert(vnd_cb && payload);
+
+ p_buf = (HC_BT_HDR *) vnd_cb->alloc(BT_HC_HDR_SIZE + cmd_len);
+
+ if (!p_buf)
+ return NULL;
+
+ p_buf->event = MSG_STACK_TO_HC_HCI_CMD;
+ p_buf->offset = 0;
+ p_buf->layer_specific = 0;
+ p_buf->len = cmd_len;
+
+ p = (uint8_t *) (p_buf + 1);
+
+ /* opcode */
+ UINT16_TO_STREAM(p, cmd);
+
+ /* length of payload */
+ *p = pl_len;
+ ++p;
+
+ /* payload */
+ memcpy(p, payload, pl_len);
+
+ return p_buf;
+}
+
+static void parse_evt_buf(HC_BT_HDR *p_evt_buf,
+ struct bt_evt_param_t *evt_params)
+{
+ uint8_t *p = (uint8_t *) (p_evt_buf + 1) + HCI_EVT_CMD_CMPL_OPCODE;
+
+ assert(p_evt_buf && evt_params);
+
+ /* opcode */
+ STREAM_TO_UINT16(evt_params->cmd, p);
+
+ /* command return parameter */
+ evt_params->cmd_ret_param = *p;
+}
+
+static void hw_mrvl_config_start_cb(void *p_mem)
+{
+ HC_BT_HDR *p_evt_buf = (HC_BT_HDR *) p_mem;
+ struct bt_evt_param_t evt_params = {0, 0};
+
+ assert(vnd_cb && p_mem);
+
+ parse_evt_buf(p_evt_buf, &evt_params);
+
+ /* free the buffer */
+ vnd_cb->dealloc(p_evt_buf);
+
+ switch (evt_params.cmd) {
+ case HCI_CMD_MARVELL_WRITE_BD_ADDRESS:
+ /* fw config succeeds */
+ ALOGI("FW config succeeds!");
+ vnd_cb->fwcfg_cb(BT_VND_OP_RESULT_SUCCESS);
+ return;
+
+ default:
+ ALOGE("Received event for unexpected cmd (0x%04hX). Fail.",
+ evt_params.cmd);
+ break;
+ } /* end of switch (evt_params.cmd) */
+
+ ALOGE("Vendor lib fwcfg aborted");
+ vnd_cb->fwcfg_cb(BT_VND_OP_RESULT_FAIL);
+}
+
+static void hw_mrvl_sco_config_cb(void *p_mem)
+{
+ HC_BT_HDR *p_evt_buf = (HC_BT_HDR *) p_mem;
+ struct bt_evt_param_t evt_params = {0, 0};
+ uint16_t cmd;
+ HC_BT_HDR *p_buf;
+
+ assert(vnd_cb && p_mem);
+
+ parse_evt_buf(p_evt_buf, &evt_params);
+
+ /* free the buffer */
+ vnd_cb->dealloc(p_evt_buf);
+
+ switch (evt_params.cmd) {
+ case HCI_CMD_MARVELL_WRITE_PCM_SETTINGS:
+ /* Send HCI_CMD_MARVELL_WRITE_PCM_SYNC_SETTINGS */
+ cmd = HCI_CMD_MARVELL_WRITE_PCM_SYNC_SETTINGS;
+ p_buf = build_cmd_buf(cmd,
+ WRITE_PCM_SYNC_SETTINGS_SIZE,
+ write_pcm_sync_settings);
+ break;
+
+ case HCI_CMD_MARVELL_WRITE_PCM_SYNC_SETTINGS:
+ /* Send HCI_CMD_MARVELL_WRITE_PCM_LINK_SETTINGS */
+ cmd = HCI_CMD_MARVELL_WRITE_PCM_LINK_SETTINGS;
+ p_buf = build_cmd_buf(cmd,
+ WRITE_PCM_LINK_SETTINGS_SIZE,
+ write_pcm_link_settings);
+ break;
+
+ case HCI_CMD_MARVELL_WRITE_PCM_LINK_SETTINGS:
+ /* Send HCI_CMD_MARVELL_SET_SCO_DATA_PATH */
+ cmd = HCI_CMD_MARVELL_SET_SCO_DATA_PATH;
+ p_buf = build_cmd_buf(cmd,
+ SET_SCO_DATA_PATH_SIZE,
+ set_sco_data_path);
+ break;
+
+ case HCI_CMD_MARVELL_SET_SCO_DATA_PATH:
+ /* sco config succeeds */
+ ALOGI("SCO PCM config succeeds!");
+ vnd_cb->scocfg_cb(BT_VND_OP_RESULT_SUCCESS);
+ return;
+
+ default:
+ ALOGE("Received event for unexpected cmd (0x%04hX). Fail.",
+ evt_params.cmd);
+ p_buf = NULL;
+ break;
+ } /* switch (evt_params.cmd) */
+
+ if (p_buf) {
+ ALOGI("Sending hci command 0x%04hX (%s)", cmd, cmd_to_str(cmd));
+ if (vnd_cb->xmit_cb(cmd, p_buf, hw_mrvl_sco_config_cb))
+ return;
+ else
+ vnd_cb->dealloc(p_buf);
+ }
+
+ ALOGE("Vendor lib scocfg aborted");
+ vnd_cb->scocfg_cb(BT_VND_OP_RESULT_FAIL);
+}
+
+/***********************************************************
+ * Global functions
+ ***********************************************************
+ */
+void hw_mrvl_config_start(void)
+{
+ HC_BT_HDR *p_buf;
+ uint16_t cmd;
+
+ assert(vnd_cb);
+
+ ALOGI("Start HW config ...");
+ /* Start with HCI_CMD_MARVELL_WRITE_BD_ADDRESS */
+ ALOGI("Setting bd addr to %02hhX:%02hhX:%02hhX:%02hhX:%02hhX:%02hhX",
+ bdaddr[0], bdaddr[1], bdaddr[2],
+ bdaddr[3], bdaddr[4], bdaddr[5]);
+ populate_bd_addr_params(write_bd_address + 2, bdaddr);
+
+ cmd = HCI_CMD_MARVELL_WRITE_BD_ADDRESS;
+ p_buf = build_cmd_buf(cmd,
+ WRITE_BD_ADDRESS_SIZE,
+ write_bd_address);
+
+ if (p_buf) {
+ ALOGI("Sending hci command 0x%04hX (%s)", cmd, cmd_to_str(cmd));
+ if (vnd_cb->xmit_cb(cmd, p_buf, hw_mrvl_config_start_cb))
+ return;
+ else
+ vnd_cb->dealloc(p_buf);
+ }
+
+ ALOGE("Vendor lib fwcfg aborted");
+ vnd_cb->fwcfg_cb(BT_VND_OP_RESULT_FAIL);
+}
+
+
+void hw_mrvl_sco_config(void)
+{
+ HC_BT_HDR *p_buf;
+ uint16_t cmd;
+
+ assert(vnd_cb);
+
+ ALOGI("Start SCO config ...");
+ /* Start with HCI_CMD_MARVELL_WRITE_PCM_SETTINGS */
+ cmd = HCI_CMD_MARVELL_WRITE_PCM_SETTINGS;
+ p_buf = build_cmd_buf(cmd,
+ WRITE_PCM_SETTINGS_SIZE,
+ write_pcm_settings);
+
+ if (p_buf) {
+ ALOGI("Sending hci command 0x%04hX (%s)", cmd, cmd_to_str(cmd));
+ if (vnd_cb->xmit_cb(cmd, p_buf, hw_mrvl_sco_config_cb))
+ return;
+ else
+ vnd_cb->dealloc(p_buf);
+ }
+
+ ALOGE("Vendor lib scocfg aborted");
+ vnd_cb->scocfg_cb(BT_VND_OP_RESULT_FAIL);
+}