diff options
author | Toshi Kikuchi <toshik@google.com> | 2012-11-30 18:50:29 -0800 |
---|---|---|
committer | Toshi Kikuchi <toshik@google.com> | 2012-12-03 11:03:36 -0800 |
commit | d99495a1f8ffae051dda62584f7af474345e5fbd (patch) | |
tree | 6f69f249d9cf69adb7057e55f26d1fdf2019b7ea | |
parent | 2a61c047fe51b6aa60901a9dea3939bd167fd6a1 (diff) | |
download | bt-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.mk | 3 | ||||
-rw-r--r-- | libbt-vendor/bt_vendor_mrvl.c | 195 | ||||
-rw-r--r-- | libbt-vendor/hardware_mrvl.c | 341 |
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); +} |