diff --git a/fm_hci/Android.mk b/fm_hci/Android.mk new file mode 100644 index 0000000000000000000000000000000000000000..1c4b9495980a8b58c422f04418f7edbe51cd3cfc --- /dev/null +++ b/fm_hci/Android.mk @@ -0,0 +1,37 @@ +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) + +# Setup bdroid local make variables for handling configuration +ifneq ($(BOARD_BLUETOOTH_BDROID_BUILDCFG_INCLUDE_DIR),) + bdroid_C_INCLUDES := $(BOARD_BLUETOOTH_BDROID_BUILDCFG_INCLUDE_DIR) + bdroid_CFLAGS += -DHAS_BDROID_BUILDCFG +else + bdroid_C_INCLUDES := + bdroid_CFLAGS += -DHAS_NO_BDROID_BUILDCFG +endif + +BDROID_DIR:= external/bluetooth/bluedroid + +LOCAL_CFLAGS += $(bdroid_CFLAGS) + +LOCAL_SRC_FILES := \ + fm_hci.c + +LOCAL_SHARED_LIBRARIES := \ + libdl \ + libcutils + +LOCAL_CFLAGS := -Wno-unused-parameter + +LOCAL_CFLAGS += -std=c99 + +LOCAL_C_INCLUDES += \ + $(BDROID_DIR)/hci/include \ + $(LOCAL_PATH)/../helium + +LOCAL_MODULE := libfm-hci +LOCAL_MODULE_TAGS := optional +LOCAL_MODULE_CLASS := SHARED_LIBRARIES + +include $(BUILD_SHARED_LIBRARY) diff --git a/fm_hci/fm_hci.c b/fm_hci/fm_hci.c new file mode 100644 index 0000000000000000000000000000000000000000..2c3e2dfd5f9f9e86f1700d5170b5441bbcf742b5 --- /dev/null +++ b/fm_hci/fm_hci.c @@ -0,0 +1,508 @@ +/* + * Copyright (c) 2015, The Linux Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#define LOG_TAG "fm_hci_helium" + +#include <assert.h> +#include <utils/Log.h> + +#include "bt_hci_bdroid.h" +#include "bt_vendor_lib.h" +#include "hci.h" +#include "userial.h" +#include "utils.h" +#include "fm_hci.h" +#include "wcnss_hci.h" +#include <dlfcn.h> +#include <sys/eventfd.h> +#include <errno.h> + +int fd; +fm_hal_cb *hal_cb; + +void event_notification(uint16_t event) +{ + pthread_mutex_lock(&fmHCIControlBlock.event_lock); + ready_events |= event; + pthread_cond_signal(&fmHCIControlBlock.event_cond); + ALOGI("%s: Notifying worker thread with event: %d", __func__, event); + pthread_mutex_unlock(&fmHCIControlBlock.event_lock); +} + +bt_vendor_interface_t *fm_vnd_if = NULL; +void init_vnd_if() +{ + void *dlhandle; + unsigned char bdaddr[] = {0xaa, 0xbb, 0xcc, 0x11, 0x22, 0x33}; + + dlhandle = dlopen("libbt-vendor.so", RTLD_NOW); + if (!dlhandle) + { + ALOGE("!!! Failed to load libbt-vendor.so !!!"); + return; + } + + fm_vnd_if = (bt_vendor_interface_t *) dlsym(dlhandle, "BLUETOOTH_VENDOR_LIB_INTERFACE"); + if (!fm_vnd_if) + { + ALOGE("!!! Failed to get bt vendor interface !!!"); + return; + } + + ALOGI("FM-HCI: Registering the WCNSS HAL library by passing CBs and BD addr."); + fm_vnd_if->init(&fm_vendor_callbacks, bdaddr); +} + +volatile uint16_t command_credits; + +/* De-queues the FM CMD from the TX_Q */ +void dequeue_fm_tx_cmd() +{ + TX_Q *new_first, *new_last; + static int cmd_count = 0; + static uint8_t credits = 0; + uint8_t i; + uint8_t temp_1 = 0x11; + + if (cmd_count >= MAX_FM_CMD_CNT) { + ALOGI("\n\n\t\tReached Max. CMD COUNT!!\n\n"); + lib_running = 0; + return; + } + + /* + * Save the 'first' pointer and make it NULL. + * This is to allow the FM-HAL to enqueue more CMDs to the TX_Q + * without having to contend for the 'tx_q_lock' with the FM-HCI thread. + * Once the pointer to the 'first' element in the TX_Q is available, + * send all the commands in the queue to WCNSS FILTER based on the + * command credits provided by the Controller. If command credits are + * not available, then wait for the same. + */ + pthread_mutex_lock(&fmHCIControlBlock.tx_q_lock); + if (!fmHCIControlBlock.first) { + ALOGI("No FM CMD available in the Q\n"); + pthread_mutex_unlock(&fmHCIControlBlock.tx_q_lock); + return; + } + else { + new_first = fmHCIControlBlock.first; + new_last = fmHCIControlBlock.last; + fmHCIControlBlock.first = fmHCIControlBlock.last = NULL; + } + pthread_mutex_unlock(&fmHCIControlBlock.tx_q_lock); + + //credits = command_credits; + + TX_Q *temp = new_first; + while(temp != NULL) { + +wait_for_cmd_credits: + pthread_mutex_lock(&fmHCIControlBlock.credit_lock); + while (command_credits == 0) { + ALOGI("\n\n\t\tWaiting for COMMAND CREDITS from CONTROLLER\n\n"); + pthread_cond_wait(&fmHCIControlBlock.cmd_credits_cond, &fmHCIControlBlock.credit_lock); + } + pthread_mutex_unlock(&fmHCIControlBlock.credit_lock); + + /* Check if we really got the command credits */ + //REVISIT this area + //if (credits) { + if (command_credits) { + ALOGI("%s: Sending the FM-CMD(prot_byte: 0x%x): 0x%x dequeued from TX_Q\n", __func__, temp->hdr->protocol_byte, temp->hdr->opcode); + + if (temp->hdr->plen) { + ALOGI("%s: CMD-PARAMS:", __func__); + for (i = 0; i < temp->hdr->plen; i++) + ALOGI(" <0x%x> ", temp->hdr->cmd_params[i]); + } else + ALOGE("%s: NO CMD-PARAMS available for this command", __func__); + + ALOGE("%s: Sizeof FM_HDR: %d", __func__, (int)sizeof(temp->hdr)); + /* Use socket 'fd' to send the command down to WCNSS Filter */ + write(fd, (uint8_t *)temp->hdr, (sizeof(FM_HDR) + temp->hdr->plen)); + //write(fd, &temp_1, 1); + + /* Decrement cmd credits by '1' after sending the cmd*/ + command_credits--; + + /* TODO: + * Initialize 'cmd_cnt' to MAX_FM_CMD(?). Should we have any limit on the + * number of outstanding commands in the TX-Q ?? + */ + cmd_count--; + + /* Fetch the next cmd to be sent */ + temp = temp->next; + } else { + if (!lib_running) + break; + + ALOGI("\n\n\t\tFalse wakeup: Yet to get COMMAND CREDITS from CONTROLLER\n\n"); + goto wait_for_cmd_credits; + } + } +} + + +static int event_fd = -1; + +static inline int add_event_fd(fd_set *set) { + if (event_fd == -1) { + event_fd = eventfd(0, 0); + if (event_fd == -1) { + ALOGE("%s unable to create event fd: %s", __func__, strerror(errno)); + return -1; + } + } + + FD_SET(event_fd, set); + return event_fd; +} + +static inline uint64_t read_event() { + assert(event_fd != -1); + + uint64_t value = 0; + eventfd_read(event_fd, &value); + return value; +} + +static int read_fm_event(int fd, FM_EVT_HDR *pbuf, int len) +{ + fd_set readFds; + int n = 0, ret = -1, evt_type = -1, evt_len = -1; + + while (lib_running) + { + FD_ZERO(&readFds); + FD_SET(fd, &readFds); + + if (event_fd == -1) { + event_fd = eventfd(0, 0); + if (event_fd == -1) { + ALOGE("%s: unable to create event fd: %s", __func__, strerror(errno)); + return -1; + } + } + FD_SET(event_fd, &readFds); + int fd_max = (event_fd > fd ? event_fd : fd); + + ALOGE("%s: Waiting for events from WCNSS FILTER...\n", __func__); + + /* Wait for event/data from WCNSS Filter */ + n = select(fd_max+1, &readFds, NULL, NULL, NULL); + if (n > 0) + { + /* Check if event is available or not */ +#if 1 + if (FD_ISSET(fd, &readFds)) { + ret = read(fd, (uint8_t *)pbuf, (size_t)(sizeof(FM_EVT_HDR) + MAX_FM_EVT_PARAMS)); + if (0 == ret) { + ALOGE("%s: read() returned '0' bytes\n", __func__); + } + else { + ALOGE("%s: read() returned %d bytes of FM event/data\n", __func__, ret); + while (ret > 0) { + if (pbuf->evt_code == FM_CMD_COMPLETE) { + ALOGE("\n\t%s: Received %d bytes of CC event data from WCNSS FILTER!!!\n\t" + "Evt type\t: 0x%x \n\tEvt Code\t: 0x%x \n\tEvt len\t\t: 0x%x \n\topcode\t\t: 0x%x%x \n\tCmd Credits\t: 0x%x \n\tStatus\t\t: 0x%x\n", + __func__, ret, pbuf->protocol_byte, pbuf->evt_code, pbuf->evt_len, pbuf->cmd_params[2], pbuf->cmd_params[1], + pbuf->cmd_params[0], pbuf->cmd_params[3]); + evt_type = FM_CMD_COMPLETE; + } else if (pbuf->evt_code == FM_CMD_STATUS) { + ALOGE("\n\t%s: Received %d bytes of CS event data from WCNSS FILTER!!!\n\t" + "Evt type\t: 0x%x \n\tEvt Code\t: 0x%x \n\tEvt len\t\t: 0x%x \n\topcode\t\t: 0x%x%x \n\tCmd Credits\t: 0x%x \n\tStatus\t\t: 0x%x\n", + __func__, ret, pbuf->protocol_byte, pbuf->evt_code, pbuf->evt_len, pbuf->cmd_params[3], pbuf->cmd_params[2], + pbuf->cmd_params[1], pbuf->cmd_params[0]); + evt_type = FM_CMD_STATUS; + } else { + ALOGI("%s: Not CS/CC Event: Recvd. Event Code: 0x%2x", __func__, pbuf->evt_code); + evt_type = -1; + } + + evt_len = pbuf->evt_len; + + /* Notify 'fmHCITask' about availability of event or data */ + ALOGE("%s: \nNotifying 'fmHCITask' availability of FM event or data...\n", __func__); + event_notification(HC_EVENT_RX); + + if (hal_cb && hal_cb->fm_evt_notify != NULL) + hal_cb->fm_evt_notify((uint8_t *)pbuf); + else + ALOGE("%s: ASSERT $$$$$$ Callback function NULL $$$$$", __func__); + + if((evt_type == FM_CMD_STATUS) || (evt_type == FM_CMD_COMPLETE)) { + /* Provide command credits to allow fmHCITask to send cmds */ + pthread_mutex_lock(&fmHCIControlBlock.credit_lock); + if (evt_type == FM_CMD_COMPLETE) { + ALOGE("\n%s: Command Credit(s): '%d' received as part of CC Event for FM-CMD: 0x%x%x \n", __func__, pbuf->cmd_params[0], + pbuf->cmd_params[2], pbuf->cmd_params[1]); + command_credits = pbuf->cmd_params[0]; + } else if (evt_type == FM_CMD_STATUS) { + ALOGE("\n%s: Command Credit(s): '%d' received as part of CS Event for FM-CMD: 0x%x%x \n", __func__, pbuf->cmd_params[1], + pbuf->cmd_params[3], pbuf->cmd_params[2]); + command_credits = pbuf->cmd_params[1]; + } + pthread_cond_signal(&fmHCIControlBlock.cmd_credits_cond); + pthread_mutex_unlock(&fmHCIControlBlock.credit_lock); + } + + ret = ret - (evt_len + 3); + ALOGE("%s: Length of available bytes @ HCI Layer: %d", __func__, ret); + + if (ret > 0) { + ALOGE("%s: Remaining bytes of event/data: %d", __func__, ret); + pbuf = (FM_EVT_HDR *)&pbuf->cmd_params[evt_len]; + ALOGE("%s: Protocol byte of next packet: 0x%2x", __func__, pbuf[0]); + } + + } + } //end of processing the event + + } else + ALOGE("%s: No data available, though select returned!!!\n", __func__); +#endif + } + else if (n < 0) + ALOGE("%s: select() failed with return value: %d", __func__, ret); + else if (n == 0) + ALOGE("%s: select() timeout!!!", __func__); + } + + return ret; +} + +static void *userial_read_thread(void *arg) +{ + int length; + + while(lib_running) { + + FM_EVT_HDR *evt_buf = (FM_EVT_HDR *) malloc(sizeof(FM_EVT_HDR) + MAX_FM_EVT_PARAMS); + + ALOGE("%s: Wait for events from the WCNSS Filter", __func__); + length = read_fm_event(fd, evt_buf, sizeof(FM_EVT_HDR) + MAX_FM_EVT_PARAMS); + +#if 0 + if (length > 0) { + //TODO: Copy the data to the RX-Q + //TODO: Notify event/data availability + ALOGE("%s: FM Event or RDS data available: Notify FM-HAL Layer", __func__); + event_notification(HC_EVENT_RX); + } else + ALOGE("%s: return value from read_fm_event(): %d", __func__, length); +#endif + //TODO: Have condition for breaking from the loop! + } + lib_running = 0; + ALOGE("%s: Leaving userial_read_thread()", __func__); + pthread_exit(NULL); + + return arg; +} + +/* + * Reads the FM-CMDs from the TX_Q and sends it down to WCNSS Filter + * Reads events sent by the WCNSS Filter and copies onto RX_Q + */ +static void* fmHCITask(void *arg) +{ + static uint16_t events; + + while (lib_running) { + pthread_mutex_lock(&fmHCIControlBlock.event_lock); + while (ready_events == 0) { + pthread_cond_wait(&fmHCIControlBlock.event_cond, &fmHCIControlBlock.event_lock); + } + + events = ready_events; + ready_events = 0; + pthread_mutex_unlock(&fmHCIControlBlock.event_lock); + + if ((events & 0xFFF8) == HC_EVENT_TX) { + ALOGI("\n@@@@@ FM-HCI Task : EVENT_TX available @@@@@\n"); + dequeue_fm_tx_cmd(); + } + if ((events & 0xFFF4) == HC_EVENT_RX) { + ALOGI("\n##### FM-HCI Task : EVENT_RX available #####\n"); + //TODO: Notify FM-HAL about event/data availablity + } + } + ALOGE("%s: ##### Exiting fmHCITask Worker thread!!! #####", __func__); + return arg; +} + +int fm_hci_init(fm_hal_cb *p_cb) +{ + pthread_attr_t thread_attr; + struct sched_param param; + int policy, result, hci_type; + + ALOGI("FM-HCI: init"); + + /* Save the FM-HAL event notofication callback func. */ + hal_cb = p_cb; + + ALOGI("FM-HCI: Loading the WCNSS HAL library..."); + init_vnd_if(); + + ALOGI("%s: Initializing FM-HCI layer...", __func__); + lib_running = 1; + ready_events = 0; + command_credits = 1; + + pthread_mutex_init(&fmHCIControlBlock.tx_q_lock, NULL); + pthread_mutex_init(&fmHCIControlBlock.credit_lock, NULL); + pthread_mutex_init(&fmHCIControlBlock.event_lock, NULL); + + pthread_cond_init(&fmHCIControlBlock.event_cond, NULL); + pthread_cond_init(&fmHCIControlBlock.cmd_credits_cond, NULL); + + pthread_attr_init(&thread_attr); + + ALOGI("FM-HCI: Creating the FM-HCI TASK..."); + if (pthread_create(&fmHCIControlBlock.fmHCITaskThreadId, &thread_attr, \ + fmHCITask, NULL) != 0) + { + ALOGE("pthread_create failed!"); + lib_running = 0; + return FM_HC_STATUS_FAIL; + } + + ALOGI("FM-HCI: Configuring the scheduling policy and priority of the FM HCI thread"); + if(pthread_getschedparam(fmHCIControlBlock.fmHCITaskThreadId, &policy, ¶m)==0) + { + policy = SCHED_NORMAL; +#if (BTHC_LINUX_BASE_POLICY!=SCHED_NORMAL) + param.sched_priority = BTHC_MAIN_THREAD_PRIORITY; +#endif + result = pthread_setschedparam(fmHCIControlBlock.fmHCITaskThreadId, policy, ¶m); + if (result != 0) + { + ALOGW("libbt-hci init: pthread_setschedparam failed (%s)", \ + strerror(result)); + } + } else + ALOGI("FM-HCI: Failed to get the Scheduling parameters!!!"); + + return FM_HC_STATUS_SUCCESS; +} + + +void fm_power(fm_power_state state) +{ + int val; + + if (state) { + ALOGI("FM-HCI: %s: Turning FM ON", __func__); + val = state; + fm_vnd_if->op(FM_VND_OP_POWER_CTRL, &val); + } else { + ALOGI("FM-HCI: %s: Turning FM OFF", __func__); + val = state; + fm_vnd_if->op(FM_VND_OP_POWER_CTRL, &val); + } +} + +#define CH_MAX 3 +int open_serial_port() +{ + int i, ret; + int fd_array[CH_MAX]; + + for (int i = 0; i < CH_MAX; i++) + fd_array[i] = -1; + + ALOGI("%s: Opening the TTy Serial port...", __func__); + ret = fm_vnd_if->op(BT_VND_OP_FM_USERIAL_OPEN, &fd_array); + + fd = fd_array[0]; + if (fd == -1) { + ALOGE("%s unable to open TTY serial port", __func__); + goto err; + } + + //TODO: Start the userial read thread here + ALOGE("%s: Starting the userial read thread....", __func__); + if (pthread_create(&fmHCIControlBlock.fmRxTaskThreadId, NULL, \ + userial_read_thread, NULL) != 0) + { + ALOGE("pthread_create failed!"); + lib_running = 0; + return FM_HC_STATUS_FAIL; + } + + return 0; + +err: + ALOGI("%s: Closing the TTy Serial port due to error!!!", __func__); + ret = fm_vnd_if->op(BT_VND_OP_FM_USERIAL_CLOSE, NULL); + return -1; +} + +void enqueue_fm_tx_cmd(FM_HDR *pbuf) +{ + + pthread_mutex_lock(&fmHCIControlBlock.tx_q_lock); + + if (!fmHCIControlBlock.first) { + fmHCIControlBlock.first = (TX_Q *) malloc(sizeof(TX_Q)); + if (!fmHCIControlBlock.first) { + printf("Failed to allocate memory for first!!\n"); + pthread_mutex_unlock(&fmHCIControlBlock.tx_q_lock); + return; + } + fmHCIControlBlock.first->hdr = pbuf; + fmHCIControlBlock.first->next = NULL; + fmHCIControlBlock.last = fmHCIControlBlock.first; + ALOGI("%s: FM-CMD ENQUEUED SUCCESSFULLY", __func__); + } else { + TX_Q *element = (TX_Q *) malloc(sizeof(TX_Q)); + if (!element) { + printf("Failed to allocate memory for element!!\n"); + pthread_mutex_unlock(&fmHCIControlBlock.tx_q_lock); + return; + } + fmHCIControlBlock.last->next = element; + element->hdr = pbuf; + element->next = NULL; + fmHCIControlBlock.last = element; + ALOGI("%s: fm-cmd enqueued successfully", __func__); + } + + pthread_mutex_unlock(&fmHCIControlBlock.tx_q_lock); +} + +/** Transmit frame */ +void transmit(FM_HDR *pbuf) +{ + enqueue_fm_tx_cmd(pbuf); + event_notification(HC_EVENT_TX); +} diff --git a/fm_hci/fm_hci.h b/fm_hci/fm_hci.h new file mode 100644 index 0000000000000000000000000000000000000000..585411eae4e4c24edcaf0f07261e04cb3cfd5fcb --- /dev/null +++ b/fm_hci/fm_hci.h @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2015, The Linux Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __FM_HCI__ +#define __FM_HCI__ + +#pragma pack(1) + +#include <radio-helium.h> + +/** Host/Controller Library Return Status */ +typedef enum { + FM_HC_STATUS_SUCCESS, + FM_HC_STATUS_FAIL, + FM_HC_STATUS_NOT_READY, + FM_HC_STATUS_NOMEM, + FM_HC_STATUS_BUSY, + FM_HC_STATUS_CORRUPTED_BUFFER +} fm_hc_status_t; + +typedef enum { + FM_RADIO_DISABLE, + FM_RADIO_ENABLE +}fm_power_state; + +/* Host/Controller lib internal event ID */ +#define HC_EVENT_PRELOAD 0x0001 +#define HC_EVENT_POSTLOAD 0x0002 +#define HC_EVENT_RX 0x0004 +#define HC_EVENT_TX 0x0008 +#define HC_EVENT_LPM_ENABLE 0x0010 +#define HC_EVENT_LPM_DISABLE 0x0020 +#define HC_EVENT_LPM_WAKE_DEVICE 0x0040 +#define HC_EVENT_LPM_ALLOW_SLEEP 0x0080 +#define HC_EVENT_LPM_IDLE_TIMEOUT 0x0100 +#define HC_EVENT_EXIT 0x0200 +#define HC_EVENT_EPILOG 0x0400 + +#define MAX_FM_CMD_CNT 100 +#define FM_CMD 0x11 +#define FM_EVT 0x14 +#define MAX_FM_EVT_PARAMS 255 + +#define FM_CMD_COMPLETE 0x0f +#define FM_CMD_STATUS 0x10 + +static pthread_mutex_t utils_mutex; + +static volatile uint8_t lib_running = 0; +static volatile uint16_t ready_events = 0; + +FILE *fd_wcnss_filter; + +typedef struct { + uint8_t protocol_byte; + uint16_t opcode; + uint8_t plen; + uint8_t cmd_params[]; +} FM_HDR; + +typedef struct { + uint8_t protocol_byte; + uint8_t evt_code; + uint8_t evt_len; + uint8_t cmd_params[]; +} FM_EVT_HDR; + +typedef struct hdr +{ + FM_HDR *hdr; + struct hdr *next; +} TX_Q; + +void transmit(FM_HDR *pbuf); +int fm_hci_init(fm_hal_cb *); +void fm_power(fm_power_state state); +int open_serial_port(void); + +typedef struct { + pthread_mutex_t tx_q_lock; + pthread_mutex_t credit_lock; + pthread_mutex_t event_lock; + + pthread_cond_t event_cond; + pthread_cond_t cmd_credits_cond; + + pthread_t fmHALTaskThreadId; + pthread_t fmHCITaskThreadId; + pthread_t fmRxTaskThreadId; + + TX_Q *first; + TX_Q *last; + +} fmHCIControlStructure; + +fmHCIControlStructure fmHCIControlBlock; + +#endif diff --git a/fm_hci/wcnss_hci.h b/fm_hci/wcnss_hci.h new file mode 100644 index 0000000000000000000000000000000000000000..95fa9c125bf9d31d125c8f613f63abcb3cda825d --- /dev/null +++ b/fm_hci/wcnss_hci.h @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2015, The Linux Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __WCNSS_HCI__ +#define __WCNSS_HCI__ +static void vendor_fwcfg_cb(bt_vendor_op_result_t result) { +} + +static void vendor_scocfg_cb(bt_vendor_op_result_t result) { +} + +static void vendor_lpm_vnd_cb(bt_vendor_op_result_t result) { +} + +static void sco_audiostate_cb(bt_vendor_op_result_t result) { +} + +static void* vendor_alloc(int size) { + return NULL; +} + +static void vendor_dealloc(void *p_buf) { +} + +static uint8_t vendor_xmit_cb(uint16_t opcode, void *p_buf, tINT_CMD_CBACK p_cback) { + return 0; +} + +static void vendor_epilog_cb(bt_vendor_op_result_t result) { +} + + +static const bt_vendor_callbacks_t fm_vendor_callbacks = { + sizeof(fm_vendor_callbacks), + vendor_fwcfg_cb, + vendor_scocfg_cb, + vendor_lpm_vnd_cb, + sco_audiostate_cb, + vendor_alloc, + vendor_dealloc, + vendor_xmit_cb, + vendor_epilog_cb +}; +#endif