summaryrefslogtreecommitdiffstats
path: root/hci/src
diff options
context:
space:
mode:
Diffstat (limited to 'hci/src')
-rw-r--r--hci/src/bt_hci_bdroid.c28
-rw-r--r--hci/src/bt_hw.c9
-rw-r--r--hci/src/hci_h4.c161
-rw-r--r--hci/src/hci_mct.c1204
-rw-r--r--hci/src/userial.c95
-rw-r--r--hci/src/userial_mct.c468
6 files changed, 1835 insertions, 130 deletions
diff --git a/hci/src/bt_hci_bdroid.c b/hci/src/bt_hci_bdroid.c
index 91a80e7..a655650 100644
--- a/hci/src/bt_hci_bdroid.c
+++ b/hci/src/bt_hci_bdroid.c
@@ -61,6 +61,7 @@
#include "bt_hci_bdroid.h"
#include "bt_vendor_lib.h"
#include "utils.h"
+#include "hci.h"
#include "userial.h"
#ifndef BTHC_DBG
@@ -79,11 +80,6 @@
extern bt_vendor_interface_t *bt_vnd_if;
extern int num_hci_cmd_pkts;
-void hci_h4_init(void);
-void hci_h4_cleanup(void);
-void hci_h4_send_msg(HC_BT_HDR *p_msg);
-uint16_t hci_h4_receive_msg(void);
-void hci_h4_get_acl_data_length(void);
void lpm_init(void);
void lpm_cleanup(void);
void lpm_enable(uint8_t turn_on);
@@ -100,6 +96,7 @@ void btsnoop_close(void);
bt_hc_callbacks_t *bt_hc_cbacks = NULL;
BUFFER_Q tx_q;
+tHCI_IF *p_hci_if;
/******************************************************************************
** Local type definitions
@@ -162,7 +159,16 @@ static int init(const bt_hc_callbacks_t* p_cb, unsigned char *local_bdaddr)
init_vnd_if(local_bdaddr);
utils_init();
- hci_h4_init();
+#ifdef HCI_USE_MCT
+ extern tHCI_IF hci_mct_func_table;
+ p_hci_if = &hci_mct_func_table;
+#else
+ extern tHCI_IF hci_h4_func_table;
+ p_hci_if = &hci_h4_func_table;
+#endif
+
+ p_hci_if->init();
+
userial_init();
lpm_init();
@@ -323,7 +329,7 @@ static void cleanup( void )
lpm_cleanup();
userial_close();
- hci_h4_cleanup();
+ p_hci_if->cleanup();
utils_cleanup();
/* Calling vendor-specific part */
@@ -376,9 +382,10 @@ static void *bt_hc_worker_thread(void *arg)
ready_events = 0;
pthread_mutex_unlock(&hc_cb.mutex);
+#ifndef HCI_USE_MCT
if (events & HC_EVENT_RX)
{
- hci_h4_receive_msg();
+ p_hci_if->rcv();
if ((tx_cmd_pkts_pending == TRUE) && (num_hci_cmd_pkts > 0))
{
@@ -389,6 +396,7 @@ static void *bt_hc_worker_thread(void *arg)
events |= HC_EVENT_TX;
}
}
+#endif
if (events & HC_EVENT_PRELOAD)
{
@@ -419,7 +427,7 @@ static void *bt_hc_worker_thread(void *arg)
result = bt_vnd_if->op(BT_VND_OP_SCO_CFG, NULL);
if (result == -1)
- hci_h4_get_acl_data_length();
+ p_hci_if->get_acl_max_len();
}
if (events & HC_EVENT_TX)
@@ -454,7 +462,7 @@ static void *bt_hc_worker_thread(void *arg)
p_msg = p_next_msg;
p_next_msg = utils_getnext(p_msg);
utils_remove_from_queue(&tx_q, p_msg);
- hci_h4_send_msg(p_msg);
+ p_hci_if->send(p_msg);
}
if (tx_cmd_pkts_pending == TRUE)
diff --git a/hci/src/bt_hw.c b/hci/src/bt_hw.c
index 1705213..760a1f3 100644
--- a/hci/src/bt_hw.c
+++ b/hci/src/bt_hw.c
@@ -60,16 +60,15 @@
#include <pthread.h>
#include "bt_vendor_lib.h"
#include "bt_hci_bdroid.h"
+#include "hci.h"
#include "userial.h"
/******************************************************************************
** Externs
******************************************************************************/
-uint8_t hci_h4_send_int_cmd(uint16_t opcode, HC_BT_HDR *p_buf, \
- tINT_CMD_CBACK p_cback);
+extern tHCI_IF *p_hci_if;
void lpm_vnd_cback(uint8_t vnd_result);
-void hci_h4_get_acl_data_length(void);
/******************************************************************************
** Variables
@@ -115,7 +114,7 @@ static void fwcfg_cb(bt_vendor_op_result_t result)
static void scocfg_cb(bt_vendor_op_result_t result)
{
/* Continue rest of postload process*/
- hci_h4_get_acl_data_length();
+ p_hci_if->get_acl_max_len();
}
/******************************************************************************
@@ -189,7 +188,7 @@ static void dealloc(void *p_buf)
******************************************************************************/
static uint8_t xmit_cb(uint16_t opcode, void *p_buf, tINT_CMD_CBACK p_cback)
{
- return hci_h4_send_int_cmd(opcode, (HC_BT_HDR *)p_buf, p_cback);
+ return p_hci_if->send_int_cmd(opcode, (HC_BT_HDR *)p_buf, p_cback);
}
/*****************************************************************************
diff --git a/hci/src/hci_h4.c b/hci/src/hci_h4.c
index 36c692a..6a1c746 100644
--- a/hci/src/hci_h4.c
+++ b/hci/src/hci_h4.c
@@ -3,44 +3,44 @@
* Copyright (C) 2009-2012 Broadcom Corporation
*
* This program is the proprietary software of Broadcom Corporation and/or its
- * licensors, and may only be used, duplicated, modified or distributed
- * pursuant to the terms and conditions of a separate, written license
- * agreement executed between you and Broadcom (an "Authorized License").
- * Except as set forth in an Authorized License, Broadcom grants no license
- * (express or implied), right to use, or waiver of any kind with respect to
- * the Software, and Broadcom expressly reserves all rights in and to the
- * Software and all intellectual property rights therein.
- * IF YOU HAVE NO AUTHORIZED LICENSE, THEN YOU HAVE NO RIGHT TO USE THIS
+ * licensors, and may only be used, duplicated, modified or distributed
+ * pursuant to the terms and conditions of a separate, written license
+ * agreement executed between you and Broadcom (an "Authorized License").
+ * Except as set forth in an Authorized License, Broadcom grants no license
+ * (express or implied), right to use, or waiver of any kind with respect to
+ * the Software, and Broadcom expressly reserves all rights in and to the
+ * Software and all intellectual property rights therein.
+ * IF YOU HAVE NO AUTHORIZED LICENSE, THEN YOU HAVE NO RIGHT TO USE THIS
* SOFTWARE IN ANY WAY, AND SHOULD IMMEDIATELY NOTIFY BROADCOM AND DISCONTINUE
- * ALL USE OF THE SOFTWARE.
+ * ALL USE OF THE SOFTWARE.
*
* Except as expressly set forth in the Authorized License,
*
- * 1. This program, including its structure, sequence and organization,
- * constitutes the valuable trade secrets of Broadcom, and you shall
- * use all reasonable efforts to protect the confidentiality thereof,
- * and to use this information only in connection with your use of
+ * 1. This program, including its structure, sequence and organization,
+ * constitutes the valuable trade secrets of Broadcom, and you shall
+ * use all reasonable efforts to protect the confidentiality thereof,
+ * and to use this information only in connection with your use of
* Broadcom integrated circuit products.
*
- * 2. TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED
- * "AS IS" AND WITH ALL FAULTS AND BROADCOM MAKES NO PROMISES,
- * REPRESENTATIONS OR WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY,
- * OR OTHERWISE, WITH RESPECT TO THE SOFTWARE. BROADCOM SPECIFICALLY
- * DISCLAIMS ANY AND ALL IMPLIED WARRANTIES OF TITLE, MERCHANTABILITY,
- * NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF VIRUSES,
- * ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR
+ * 2. TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED
+ * "AS IS" AND WITH ALL FAULTS AND BROADCOM MAKES NO PROMISES,
+ * REPRESENTATIONS OR WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY,
+ * OR OTHERWISE, WITH RESPECT TO THE SOFTWARE. BROADCOM SPECIFICALLY
+ * DISCLAIMS ANY AND ALL IMPLIED WARRANTIES OF TITLE, MERCHANTABILITY,
+ * NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF VIRUSES,
+ * ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR
* CORRESPONDENCE TO DESCRIPTION. YOU ASSUME THE ENTIRE RISK ARISING OUT
* OF USE OR PERFORMANCE OF THE SOFTWARE.
*
* 3. TO THE MAXIMUM EXTENT PERMITTED BY LAW, IN NO EVENT SHALL BROADCOM OR
- * ITS LICENSORS BE LIABLE FOR
- * (i) CONSEQUENTIAL, INCIDENTAL, SPECIAL, INDIRECT, OR EXEMPLARY
- * DAMAGES WHATSOEVER ARISING OUT OF OR IN ANY WAY RELATING TO
- * YOUR USE OF OR INABILITY TO USE THE SOFTWARE EVEN IF BROADCOM
- * HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES; OR
- * (ii) ANY AMOUNT IN EXCESS OF THE AMOUNT ACTUALLY PAID FOR THE
- * SOFTWARE ITSELF OR U.S. $1, WHICHEVER IS GREATER. THESE
- * LIMITATIONS SHALL APPLY NOTWITHSTANDING ANY FAILURE OF
+ * ITS LICENSORS BE LIABLE FOR
+ * (i) CONSEQUENTIAL, INCIDENTAL, SPECIAL, INDIRECT, OR EXEMPLARY
+ * DAMAGES WHATSOEVER ARISING OUT OF OR IN ANY WAY RELATING TO
+ * YOUR USE OF OR INABILITY TO USE THE SOFTWARE EVEN IF BROADCOM
+ * HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES; OR
+ * (ii) ANY AMOUNT IN EXCESS OF THE AMOUNT ACTUALLY PAID FOR THE
+ * SOFTWARE ITSELF OR U.S. $1, WHICHEVER IS GREATER. THESE
+ * LIMITATIONS SHALL APPLY NOTWITHSTANDING ANY FAILURE OF
* ESSENTIAL PURPOSE OF ANY LIMITED REMEDY.
*
******************************************************************************/
@@ -59,6 +59,7 @@
#include <stdlib.h>
#include <fcntl.h>
#include "bt_hci_bdroid.h"
+#include "hci.h"
#include "userial.h"
#include "utils.h"
@@ -66,14 +67,14 @@
** Constants & Macros
******************************************************************************/
-#ifndef HCIH4_DBG
-#define HCIH4_DBG FALSE
+#ifndef HCI_DBG
+#define HCI_DBG FALSE
#endif
-#if (HCIH4_DBG == TRUE)
-#define HCIH4DBG(param, ...) {LOGD(param, ## __VA_ARGS__);}
+#if (HCI_DBG == TRUE)
+#define HCIDBG(param, ...) {LOGD(param, ## __VA_ARGS__);}
#else
-#define HCIH4DBG(param, ...) {}
+#define HCIDBG(param, ...) {}
#endif
/* Preamble length for HCI Commands:
@@ -124,7 +125,7 @@ static const uint16_t msg_evt_table[] =
#define L2CAP_HEADER_SIZE 4
/* Maximum numbers of allowed internal
-** outstanding command packets at any time
+** outstanding command packets at any time
*/
#define INT_CMD_PKT_MAX_COUNT 8
#define INT_CMD_PKT_IDX_MASK 0x07
@@ -152,8 +153,8 @@ typedef void (*tINT_CMD_CBACK)(void *p_mem);
typedef struct
{
uint16_t opcode; /* OPCODE of outstanding internal commands */
- tINT_CMD_CBACK cback; /* Callback function when return of internal
- * command is received */
+ tINT_CMD_CBACK cback; /* Callback function when return of internal
+ * command is received */
} tINT_CMD_Q;
/* Control block for HCISU_H4 */
@@ -211,8 +212,8 @@ static tHCI_H4_CB h4_cb;
** Function get_acl_data_length_cback
**
** Description Callback function for HCI_READ_BUFFER_SIZE and
-** HCI_LE_READ_BUFFER_SIZE commands if they were sent because
-** of internal request.
+** HCI_LE_READ_BUFFER_SIZE commands if they were sent because
+** of internal request.
**
** Returns None
**
@@ -271,9 +272,9 @@ void get_acl_data_length_cback(void *p_mem)
** Function internal_event_intercept
**
** Description This function is called to parse received HCI event and
-** - update the Num_HCI_Command_Packets
-** - intercept the event if it is the result of an early
-** issued internal command.
+** - update the Num_HCI_Command_Packets
+** - intercept the event if it is the result of an early
+** issued internal command.
**
** Returns TRUE : if the event had been intercepted for internal process
** FALSE : send this event to core stack
@@ -301,7 +302,7 @@ uint8_t internal_event_intercept(void)
if (opcode == p_cb->int_cmd[p_cb->int_cmd_rd_idx].opcode)
{
- HCIH4DBG( \
+ HCIDBG( \
"Intercept CommandCompleteEvent for internal command (0x%04X)",\
opcode);
if (p_cb->int_cmd[p_cb->int_cmd_rd_idx].cback != NULL)
@@ -337,12 +338,12 @@ uint8_t internal_event_intercept(void)
**
** Function acl_rx_frame_buffer_alloc
**
-** Description This function is called from the HCI transport when the
+** Description This function is called from the HCI transport when the
** first 4 or 6 bytes of an HCI ACL packet have been received:
-** - Allocate a new buffer if it is a start pakcet of L2CAP
+** - Allocate a new buffer if it is a start pakcet of L2CAP
** message.
-** - Return the buffer address of the starting L2CAP message
-** frame if the packet is the next segment of a fragmented
+** - Return the buffer address of the starting L2CAP message
+** frame if the packet is the next segment of a fragmented
** L2CAP message.
**
** Returns the address of the receive buffer H4 RX should use
@@ -465,8 +466,8 @@ static HC_BT_HDR *acl_rx_frame_buffer_alloc (void)
** Function acl_rx_frame_end_chk
**
** Description This function is called from the HCI transport when the last
-** byte of an HCI ACL packet has been received. It checks if
-** the L2CAP message is complete, i.e. no more continuation
+** byte of an HCI ACL packet has been received. It checks if
+** the L2CAP message is complete, i.e. no more continuation
** packets are expected.
**
** Returns TRUE if message complete, FALSE if continuation expected
@@ -478,7 +479,7 @@ static uint8_t acl_rx_frame_end_chk (void)
uint16_t handle, hci_len, l2cap_len;
HC_BT_HDR *p_buf;
tHCI_H4_CB *p_cb = &h4_cb;
- uint8_t frame_end=TRUE;
+ uint8_t frame_end=TRUE;
p_buf = p_cb->p_rcv_msg;
p = (uint8_t *)(p_buf + 1);
@@ -491,7 +492,7 @@ static uint8_t acl_rx_frame_end_chk (void)
{
if (l2cap_len > (p_buf->len-(HCI_ACL_PREAMBLE_SIZE+L2CAP_HEADER_SIZE)) )
{
- /* If the L2CAP length has not been reached, tell H4 not to send
+ /* If the L2CAP length has not been reached, tell H4 not to send
* this buffer to stack */
frame_end = FALSE;
}
@@ -506,8 +507,8 @@ static uint8_t acl_rx_frame_end_chk (void)
}
}
- /****
- ** Print snoop trace
+ /****
+ ** Print snoop trace
****/
if (p_buf->offset)
{
@@ -532,7 +533,7 @@ static uint8_t acl_rx_frame_end_chk (void)
/* roll pointer back */
p = p - HCI_ACL_PREAMBLE_SIZE;
- /* adjust `p_buf->offset` & `p_buf->len`
+ /* adjust `p_buf->offset` & `p_buf->len`
* before calling btsnoop_capture() */
p_buf->offset = p_buf->offset - HCI_ACL_PREAMBLE_SIZE;
p_buf->len = p_buf->len - p_buf->offset;
@@ -574,7 +575,7 @@ static uint8_t acl_rx_frame_end_chk (void)
*******************************************************************************/
void hci_h4_init(void)
{
- HCIH4DBG("hci_h4_init");
+ HCIDBG("hci_h4_init");
memset(&h4_cb, 0, sizeof(tHCI_H4_CB));
utils_queue_init(&(h4_cb.acl_rx_q));
@@ -602,7 +603,7 @@ void hci_h4_init(void)
*******************************************************************************/
void hci_h4_cleanup(void)
{
- HCIH4DBG("hci_h4_cleanup");
+ HCIDBG("hci_h4_cleanup");
btsnoop_close();
btsnoop_cleanup();
@@ -662,7 +663,7 @@ void hci_h4_send_msg(HC_BT_HDR *p_msg)
/* Do all the first chunks */
while (p_msg->len > acl_pkt_size)
{
- /* remember layer_specific because uart borrow
+ /* remember layer_specific because uart borrow
one byte from layer_specific for packet type */
lay_spec = p_msg->layer_specific;
@@ -670,14 +671,14 @@ void hci_h4_send_msg(HC_BT_HDR *p_msg)
*p = type;
bytes_to_send = acl_pkt_size + 1; /* packet_size + message type */
- bytes_sent = userial_write((uint8_t *) p, bytes_to_send);
+ bytes_sent = userial_write(event,(uint8_t *) p,bytes_to_send);
/* generate snoop trace message */
btsnoop_capture(p_msg, FALSE);
p_msg->layer_specific = lay_spec;
/* Adjust offset and length for what we just sent */
- p_msg->offset += acl_data_size;
+ p_msg->offset += acl_data_size;
p_msg->len -= acl_data_size;
p = ((uint8_t *)(p_msg + 1)) + p_msg->offset;
@@ -715,7 +716,7 @@ void hci_h4_send_msg(HC_BT_HDR *p_msg)
}
- /* remember layer_specific because uart borrow
+ /* remember layer_specific because uart borrow
one byte from layer_specific for packet type */
lay_spec = p_msg->layer_specific;
@@ -724,7 +725,7 @@ void hci_h4_send_msg(HC_BT_HDR *p_msg)
*p = type;
bytes_to_send = p_msg->len + 1; /* message_size + message type */
- bytes_sent = userial_write((uint8_t *) p, bytes_to_send);
+ bytes_sent = userial_write(event,(uint8_t *) p, bytes_to_send);
p_msg->layer_specific = lay_spec;
@@ -733,7 +734,7 @@ void hci_h4_send_msg(HC_BT_HDR *p_msg)
num_hci_cmd_pkts--;
/* If this is an internal Cmd packet, the layer_specific field would
- * have stored with the opcode of HCI command.
+ * have stored with the opcode of HCI command.
* Retrieve the opcode from the Cmd packet.
*/
p++;
@@ -769,9 +770,10 @@ void hci_h4_send_msg(HC_BT_HDR *p_msg)
**
** Function hci_h4_receive_msg
**
-** Description
+** Description Construct HCI EVENT/ACL packets and send them to stack once
+** complete packet has been received.
**
-** Returns
+** Returns Number of read bytes
**
*******************************************************************************/
uint16_t hci_h4_receive_msg(void)
@@ -785,7 +787,7 @@ uint16_t hci_h4_receive_msg(void)
while (TRUE)
{
/* Read one byte to see if there is anything waiting to be read */
- if (userial_read(&byte, 1) == 0)
+ if (userial_read(0 /*dummy*/, &byte, 1) == 0)
{
break;
}
@@ -837,7 +839,7 @@ uint16_t hci_h4_receive_msg(void)
{
/*
* A start packet & with non-zero data payload length.
- * We want to read 2 more bytes to get L2CAP payload
+ * We want to read 2 more bytes to get L2CAP payload
* length.
*/
p_cb->rcv_len = 2;
@@ -847,15 +849,15 @@ uint16_t hci_h4_receive_msg(void)
}
/*
- * Check for segmented packets. If this is a continuation
- * packet, then we will continue appending data to the
+ * Check for segmented packets. If this is a continuation
+ * packet, then we will continue appending data to the
* original rcv buffer.
*/
p_cb->p_rcv_msg = acl_rx_frame_buffer_alloc();
}
else
{
- /* Received entire preamble.
+ /* Received entire preamble.
* Length is in the last received byte */
msg_len = byte;
p_cb->rcv_len = msg_len;
@@ -910,7 +912,7 @@ uint16_t hci_h4_receive_msg(void)
}
else
{
- /* Message has no additional parameters.
+ /* Message has no additional parameters.
* (Entire message has been received) */
if (p_cb->rcv_msg_type == H4_TYPE_ACL_DATA)
acl_rx_frame_end_chk(); /* to print snoop trace */
@@ -930,7 +932,7 @@ uint16_t hci_h4_receive_msg(void)
if (p_cb->rcv_len > 0)
{
/* Read in the rest of the message */
- len = userial_read( \
+ len = userial_read(0 /*dummy*/, \
((uint8_t *)(p_cb->p_rcv_msg+1) + p_cb->p_rcv_msg->len), \
p_cb->rcv_len);
p_cb->p_rcv_msg->len += len;
@@ -981,13 +983,13 @@ uint16_t hci_h4_receive_msg(void)
/* generate snoop trace message */
/* ACL packet tracing had done in acl_rx_frame_end_chk() */
- if (p_cb->p_rcv_msg->event != MSG_HC_TO_STACK_HCI_ACL)
+ if (p_cb->p_rcv_msg->event != MSG_HC_TO_STACK_HCI_ACL)
btsnoop_capture(p_cb->p_rcv_msg, TRUE);
if (p_cb->p_rcv_msg->event == MSG_HC_TO_STACK_HCI_EVT)
intercepted = internal_event_intercept();
- if ((bt_hc_cbacks) && (intercepted == FALSE))
+ if ((bt_hc_cbacks) && (intercepted == FALSE))
{
bt_hc_cbacks->data_ind((TRANSAC) p_cb->p_rcv_msg, \
(char *) (p_cb->p_rcv_msg + 1), \
@@ -1085,3 +1087,18 @@ void hci_h4_get_acl_data_length(void)
}
}
+
+/******************************************************************************
+** HCI H4 Services interface table
+******************************************************************************/
+
+const tHCI_IF hci_h4_func_table =
+{
+ hci_h4_init,
+ hci_h4_cleanup,
+ hci_h4_send_msg,
+ hci_h4_send_int_cmd,
+ hci_h4_get_acl_data_length,
+ hci_h4_receive_msg
+};
+
diff --git a/hci/src/hci_mct.c b/hci/src/hci_mct.c
new file mode 100644
index 0000000..23337c2
--- /dev/null
+++ b/hci/src/hci_mct.c
@@ -0,0 +1,1204 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ * This program is the proprietary software of Broadcom Corporation and/or its
+ * licensors, and may only be used, duplicated, modified or distributed
+ * pursuant to the terms and conditions of a separate, written license
+ * agreement executed between you and Broadcom (an "Authorized License").
+ * Except as set forth in an Authorized License, Broadcom grants no license
+ * (express or implied), right to use, or waiver of any kind with respect to
+ * the Software, and Broadcom expressly reserves all rights in and to the
+ * Software and all intellectual property rights therein.
+ * IF YOU HAVE NO AUTHORIZED LICENSE, THEN YOU HAVE NO RIGHT TO USE THIS
+ * SOFTWARE IN ANY WAY, AND SHOULD IMMEDIATELY NOTIFY BROADCOM AND DISCONTINUE
+ * ALL USE OF THE SOFTWARE.
+ *
+ * Except as expressly set forth in the Authorized License,
+ *
+ * 1. This program, including its structure, sequence and organization,
+ * constitutes the valuable trade secrets of Broadcom, and you shall
+ * use all reasonable efforts to protect the confidentiality thereof,
+ * and to use this information only in connection with your use of
+ * Broadcom integrated circuit products.
+ *
+ * 2. TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED
+ * "AS IS" AND WITH ALL FAULTS AND BROADCOM MAKES NO PROMISES,
+ * REPRESENTATIONS OR WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY,
+ * OR OTHERWISE, WITH RESPECT TO THE SOFTWARE. BROADCOM SPECIFICALLY
+ * DISCLAIMS ANY AND ALL IMPLIED WARRANTIES OF TITLE, MERCHANTABILITY,
+ * NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF VIRUSES,
+ * ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR
+ * CORRESPONDENCE TO DESCRIPTION. YOU ASSUME THE ENTIRE RISK ARISING OUT
+ * OF USE OR PERFORMANCE OF THE SOFTWARE.
+ *
+ * 3. TO THE MAXIMUM EXTENT PERMITTED BY LAW, IN NO EVENT SHALL BROADCOM OR
+ * ITS LICENSORS BE LIABLE FOR
+ * (i) CONSEQUENTIAL, INCIDENTAL, SPECIAL, INDIRECT, OR EXEMPLARY
+ * DAMAGES WHATSOEVER ARISING OUT OF OR IN ANY WAY RELATING TO
+ * YOUR USE OF OR INABILITY TO USE THE SOFTWARE EVEN IF BROADCOM
+ * HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES; OR
+ * (ii) ANY AMOUNT IN EXCESS OF THE AMOUNT ACTUALLY PAID FOR THE
+ * SOFTWARE ITSELF OR U.S. $1, WHICHEVER IS GREATER. THESE
+ * LIMITATIONS SHALL APPLY NOTWITHSTANDING ANY FAILURE OF
+ * ESSENTIAL PURPOSE OF ANY LIMITED REMEDY.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * Filename: hci_mct.c
+ *
+ * Description: Contains HCI transport send/receive functions
+ * for Multi-Channels Transport
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_mct"
+
+#include <utils/Log.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include "bt_hci_bdroid.h"
+#include "hci.h"
+#include "userial.h"
+#include "utils.h"
+
+/******************************************************************************
+** Constants & Macros
+******************************************************************************/
+
+#ifndef HCI_DBG
+#define HCI_DBG FALSE
+#endif
+
+#if (HCI_DBG == TRUE)
+#define HCIDBG(param, ...) {LOGD(param, ## __VA_ARGS__);}
+#else
+#define HCIDBG(param, ...) {}
+#endif
+
+/* Preamble length for HCI Commands:
+** 2-bytes for opcode and 1 byte for length
+*/
+#define HCI_CMD_PREAMBLE_SIZE 3
+
+/* Preamble length for HCI Events:
+** 1-byte for opcode and 1 byte for length
+*/
+#define HCI_EVT_PREAMBLE_SIZE 2
+
+/* Preamble length for SCO Data:
+** 2-byte for Handle and 1 byte for length
+*/
+#define HCI_SCO_PREAMBLE_SIZE 3
+
+/* Preamble length for ACL Data:
+** 2-byte for Handle and 2 byte for length
+*/
+#define HCI_ACL_PREAMBLE_SIZE 4
+
+#define ACL_RX_PKT_START 2
+#define ACL_RX_PKT_CONTINUE 1
+#define L2CAP_HEADER_SIZE 4
+
+/* Maximum numbers of allowed internal
+** outstanding command packets at any time
+*/
+#define INT_CMD_PKT_MAX_COUNT 8
+#define INT_CMD_PKT_IDX_MASK 0x07
+
+#define HCI_COMMAND_COMPLETE_EVT 0x0E
+#define HCI_COMMAND_STATUS_EVT 0x0F
+#define HCI_READ_BUFFER_SIZE 0x1005
+#define HCI_LE_READ_BUFFER_SIZE 0x2002
+
+/******************************************************************************
+** Local type definitions
+******************************************************************************/
+
+/* MCT Rx States */
+typedef enum {
+ MCT_RX_NEWMSG_ST,
+ MCT_RX_LEN_ST,
+ MCT_RX_DATA_ST,
+ MCT_RX_IGNORE_ST
+} tHCI_MCT_RCV_STATE;
+
+/* Callback function for the returned event of internal issued command */
+typedef void (*tINT_CMD_CBACK)(void *p_mem);
+
+typedef struct
+{
+ uint16_t opcode; /* OPCODE of outstanding internal commands */
+ tINT_CMD_CBACK cback; /* Callback function when return of internal
+ * command is received */
+} tINT_CMD_Q;
+
+typedef struct
+{
+ HC_BT_HDR *p_rcv_msg; /* Buffer to hold current rx HCI message */
+ uint16_t rcv_len; /* Size of current incoming message */
+ tHCI_MCT_RCV_STATE rcv_state; /* Receive state of current rx message */
+ uint8_t preload_count; /* Count numbers of preload bytes */
+ uint8_t preload_buffer[6]; /* HCI_ACL_PREAMBLE_SIZE + 2 */
+} tHCI_RCV_CB;
+
+/* Control block for HCISU_MCT */
+typedef struct
+{
+ tHCI_RCV_CB rcv_evt;
+ tHCI_RCV_CB rcv_acl;
+ uint16_t hc_acl_data_size; /* Controller's max ACL data length */
+ uint16_t hc_ble_acl_data_size; /* Controller's max BLE ACL data length */
+ BUFFER_Q acl_rx_q; /* Queue of base buffers for fragmented ACL pkts */
+ int int_cmd_rsp_pending; /* Num of internal cmds pending for ack */
+ uint8_t int_cmd_rd_idx; /* Read index of int_cmd_opcode queue */
+ uint8_t int_cmd_wrt_idx; /* Write index of int_cmd_opcode queue */
+ tINT_CMD_Q int_cmd[INT_CMD_PKT_MAX_COUNT]; /* FIFO queue */
+} tHCI_MCT_CB;
+
+/******************************************************************************
+** Externs
+******************************************************************************/
+
+extern BUFFER_Q tx_q;
+
+void btsnoop_init(void);
+void btsnoop_close(void);
+void btsnoop_cleanup (void);
+void btsnoop_capture(HC_BT_HDR *p_buf, uint8_t is_rcvd);
+uint8_t hci_mct_send_int_cmd(uint16_t opcode, HC_BT_HDR *p_buf, \
+ tINT_CMD_CBACK p_cback);
+void lpm_wake_assert(void);
+void lpm_tx_done(uint8_t is_tx_done);
+
+/******************************************************************************
+** Variables
+******************************************************************************/
+
+/* Num of allowed outstanding HCI CMD packets */
+volatile int num_hci_cmd_pkts = 1;
+
+/******************************************************************************
+** Static variables
+******************************************************************************/
+
+static tHCI_MCT_CB mct_cb;
+
+/******************************************************************************
+** Static functions
+******************************************************************************/
+
+/*******************************************************************************
+**
+** Function get_acl_data_length_cback
+**
+** Description Callback function for HCI_READ_BUFFER_SIZE and
+** HCI_LE_READ_BUFFER_SIZE commands if they were sent because
+** of internal request.
+**
+** Returns None
+**
+*******************************************************************************/
+void get_acl_data_length_cback(void *p_mem)
+{
+ uint8_t *p, status;
+ uint16_t opcode, len=0;
+ HC_BT_HDR *p_buf = (HC_BT_HDR *) p_mem;
+
+ p = (uint8_t *)(p_buf + 1) + 3;
+ STREAM_TO_UINT16(opcode, p)
+ status = *p++;
+ if (status == 0) /* Success */
+ STREAM_TO_UINT16(len, p)
+
+ if (opcode == HCI_READ_BUFFER_SIZE)
+ {
+ if (status == 0)
+ mct_cb.hc_acl_data_size = len;
+
+ /* reuse the rx buffer for sending HCI_LE_READ_BUFFER_SIZE command */
+ p_buf->event = MSG_STACK_TO_HC_HCI_CMD;
+ p_buf->offset = 0;
+ p_buf->layer_specific = 0;
+ p_buf->len = 3;
+
+ p = (uint8_t *) (p_buf + 1);
+ UINT16_TO_STREAM(p, HCI_LE_READ_BUFFER_SIZE);
+ *p = 0;
+
+ if ((status = hci_mct_send_int_cmd(HCI_LE_READ_BUFFER_SIZE, p_buf, \
+ get_acl_data_length_cback)) == FALSE)
+ {
+ bt_hc_cbacks->dealloc((TRANSAC) p_buf, (char *) (p_buf + 1));
+ bt_hc_cbacks->postload_cb(NULL, BT_HC_POSTLOAD_SUCCESS);
+ }
+ }
+ else if (opcode == HCI_LE_READ_BUFFER_SIZE)
+ {
+ if (status == 0)
+ mct_cb.hc_ble_acl_data_size = (len) ? len : mct_cb.hc_acl_data_size;
+
+ if (bt_hc_cbacks)
+ {
+ bt_hc_cbacks->dealloc((TRANSAC) p_buf, (char *) (p_buf + 1));
+ ALOGE("hci lib postload completed");
+ bt_hc_cbacks->postload_cb(NULL, BT_HC_POSTLOAD_SUCCESS);
+ }
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function internal_event_intercept
+**
+** Description This function is called to parse received HCI event and
+** - update the Num_HCI_Command_Packets
+** - intercept the event if it is the result of an early
+** issued internal command.
+**
+** Returns TRUE : if the event had been intercepted for internal process
+** FALSE : send this event to core stack
+**
+*******************************************************************************/
+uint8_t internal_event_intercept(void)
+{
+ uint8_t *p;
+ uint8_t event_code;
+ uint16_t opcode, len;
+ tHCI_MCT_CB *p_cb = &mct_cb;
+
+ p = (uint8_t *)(p_cb->rcv_evt.p_rcv_msg + 1);
+
+ event_code = *p++;
+ len = *p++;
+
+ if (event_code == HCI_COMMAND_COMPLETE_EVT)
+ {
+ utils_lock();
+ num_hci_cmd_pkts = *p++;
+ utils_unlock();
+
+ // Signal TX event so the worker thread can check if it has anything
+ // to send
+ bthc_signal_event(HC_EVENT_TX);
+
+ if (p_cb->int_cmd_rsp_pending > 0)
+ {
+ STREAM_TO_UINT16(opcode, p)
+
+ if (opcode == p_cb->int_cmd[p_cb->int_cmd_rd_idx].opcode)
+ {
+ HCIDBG( \
+ "Intercept CommandCompleteEvent for internal command (0x%04X)",\
+ opcode);
+ if (p_cb->int_cmd[p_cb->int_cmd_rd_idx].cback != NULL)
+ {
+ p_cb->int_cmd[p_cb->int_cmd_rd_idx].cback(p_cb->rcv_evt.p_rcv_msg);
+ }
+ else
+ {
+ // Missing cback function!
+ // Release the p_rcv_msg buffer.
+ if (bt_hc_cbacks)
+ {
+ bt_hc_cbacks->dealloc((TRANSAC) p_cb->rcv_evt.p_rcv_msg, \
+ (char *) (p_cb->rcv_evt.p_rcv_msg + 1));
+ }
+ }
+ p_cb->int_cmd_rd_idx = ((p_cb->int_cmd_rd_idx+1) & \
+ INT_CMD_PKT_IDX_MASK);
+ p_cb->int_cmd_rsp_pending--;
+ return TRUE;
+ }
+ }
+ }
+ else if (event_code == HCI_COMMAND_STATUS_EVT)
+ {
+ utils_lock();
+ num_hci_cmd_pkts = *(++p);
+ utils_unlock();
+
+ // Signal TX event so the worker thread can check if it has anything
+ // to send
+ bthc_signal_event(HC_EVENT_TX);
+ }
+
+ return FALSE;
+}
+
+/*******************************************************************************
+**
+** Function acl_rx_frame_buffer_alloc
+**
+** Description This function is called from the HCI transport when the
+** first 4 or 6 bytes of an HCI ACL packet have been received:
+** - Allocate a new buffer if it is a start pakcet of L2CAP
+** message.
+** - Return the buffer address of the starting L2CAP message
+** frame if the packet is the next segment of a fragmented
+** L2CAP message.
+**
+** Returns the address of the receive buffer caller should use
+** (CR419: Modified to return NULL in case of error.)
+**
+** NOTE This assumes that the L2CAP MTU size is less than the size
+** of an HCI ACL buffer, so the maximum L2CAP message will fit
+** into one buffer.
+**
+*******************************************************************************/
+static HC_BT_HDR *acl_rx_frame_buffer_alloc (void)
+{
+ uint8_t *p;
+ uint16_t handle;
+ uint16_t hci_len;
+ uint16_t total_len;
+ uint8_t pkt_type;
+ HC_BT_HDR *p_return_buf = NULL;
+ tHCI_MCT_CB *p_cb = &mct_cb;
+
+
+ p = p_cb->rcv_acl.preload_buffer;
+
+ STREAM_TO_UINT16 (handle, p);
+ STREAM_TO_UINT16 (hci_len, p);
+ STREAM_TO_UINT16 (total_len, p);
+
+ pkt_type = (uint8_t)(((handle) >> 12) & 0x0003);
+ handle = (uint16_t)((handle) & 0x0FFF);
+
+ if (p_cb->acl_rx_q.count)
+ {
+ uint16_t save_handle;
+ HC_BT_HDR *p_hdr = p_cb->acl_rx_q.p_first;
+
+ while (p_hdr != NULL)
+ {
+ p = (uint8_t *)(p_hdr + 1);
+ STREAM_TO_UINT16 (save_handle, p);
+ save_handle = (uint16_t)((save_handle) & 0x0FFF);
+ if (save_handle == handle)
+ {
+ p_return_buf = p_hdr;
+ break;
+ }
+ p_hdr = utils_getnext(p_hdr);
+ }
+ }
+
+ if (pkt_type == ACL_RX_PKT_START) /*** START PACKET ***/
+ {
+ /* Might have read 2 bytes for the L2CAP payload length */
+ p_cb->rcv_acl.rcv_len = (hci_len) ? (hci_len - 2) : 0;
+
+ /* Start of packet. If we were in the middle of receiving */
+ /* a packet on the same ACL handle, the original packet is incomplete.
+ * Drop it. */
+ if (p_return_buf)
+ {
+ ALOGW("dropping incomplete ACL frame");
+
+ utils_remove_from_queue(&(p_cb->acl_rx_q), p_return_buf);
+
+ if (bt_hc_cbacks)
+ {
+ bt_hc_cbacks->dealloc((TRANSAC) p_return_buf, \
+ (char *) (p_return_buf + 1));
+ }
+ p_return_buf = NULL;
+ }
+
+ /* Allocate a buffer for message */
+ if (bt_hc_cbacks)
+ {
+ int len = total_len + HCI_ACL_PREAMBLE_SIZE + L2CAP_HEADER_SIZE + \
+ BT_HC_HDR_SIZE;
+ p_return_buf = (HC_BT_HDR *) bt_hc_cbacks->alloc(len);
+ }
+
+ if (p_return_buf)
+ {
+ /* Initialize buffer with preloaded data */
+ p_return_buf->offset = 0;
+ p_return_buf->layer_specific = 0;
+ p_return_buf->event = MSG_HC_TO_STACK_HCI_ACL;
+ p_return_buf->len = p_cb->rcv_acl.preload_count;
+ memcpy((uint8_t *)(p_return_buf + 1), p_cb->rcv_acl.preload_buffer, \
+ p_cb->rcv_acl.preload_count);
+
+ if (hci_len && ((total_len + L2CAP_HEADER_SIZE) > hci_len))
+ {
+ /* Will expect to see fragmented ACL packets */
+ /* Keep the base buffer address in the watching queue */
+ utils_enqueue(&(p_cb->acl_rx_q), p_return_buf);
+ }
+ }
+ }
+ else /*** CONTINUATION PACKET ***/
+ {
+ p_cb->rcv_acl.rcv_len = hci_len;
+
+ if (p_return_buf)
+ {
+ /* Packet continuation and found the original rx buffer */
+ uint8_t *p_f = p = (uint8_t *)(p_return_buf + 1) + 2;
+
+ STREAM_TO_UINT16 (total_len, p);
+
+ /* Update HCI header of first segment (base buffer) with new len */
+ total_len += hci_len;
+ UINT16_TO_STREAM (p_f, total_len);
+ }
+ }
+
+ return (p_return_buf);
+}
+
+/*******************************************************************************
+**
+** Function acl_rx_frame_end_chk
+**
+** Description This function is called from the HCI transport when the last
+** byte of an HCI ACL packet has been received. It checks if
+** the L2CAP message is complete, i.e. no more continuation
+** packets are expected.
+**
+** Returns TRUE if message complete, FALSE if continuation expected
+**
+*******************************************************************************/
+static uint8_t acl_rx_frame_end_chk (void)
+{
+ uint8_t *p;
+ uint16_t handle, hci_len, l2cap_len;
+ HC_BT_HDR *p_buf;
+ tHCI_MCT_CB *p_cb = &mct_cb;
+ uint8_t frame_end=TRUE;
+
+ p_buf = p_cb->rcv_acl.p_rcv_msg;
+ p = (uint8_t *)(p_buf + 1);
+
+ STREAM_TO_UINT16 (handle, p);
+ STREAM_TO_UINT16 (hci_len, p);
+ STREAM_TO_UINT16 (l2cap_len, p);
+
+ if (hci_len > 0)
+ {
+ if (l2cap_len > (p_buf->len-(HCI_ACL_PREAMBLE_SIZE+L2CAP_HEADER_SIZE)) )
+ {
+ /* If the L2CAP length has not been reached, tell caller not to send
+ * this buffer to stack */
+ frame_end = FALSE;
+ }
+ else
+ {
+ /*
+ * The current buffer coulb be in the watching list.
+ * Remove it from the list if it is in.
+ */
+ if (p_cb->acl_rx_q.count)
+ utils_remove_from_queue(&(p_cb->acl_rx_q), p_buf);
+ }
+ }
+
+ /****
+ ** Print snoop trace
+ ****/
+ if (p_buf->offset)
+ {
+ /* CONTINUATION PACKET */
+
+ /* save original p_buf->len content */
+ uint16_t tmp_u16 = p_buf->len;
+
+ /* borrow HCI_ACL_PREAMBLE_SIZE bytes from the payload section */
+ p = (uint8_t *)(p_buf + 1) + p_buf->offset - HCI_ACL_PREAMBLE_SIZE;
+
+ /* save contents */
+ memcpy(p_cb->rcv_acl.preload_buffer, p, HCI_ACL_PREAMBLE_SIZE);
+
+ /* Set packet boundary flags to "continuation packet" */
+ handle = (handle & 0xCFFF) | 0x1000;
+
+ /* write handl & length info */
+ UINT16_TO_STREAM (p, handle);
+ UINT16_TO_STREAM (p, (p_buf->len - p_buf->offset));
+
+ /* roll pointer back */
+ p = p - HCI_ACL_PREAMBLE_SIZE;
+
+ /* adjust `p_buf->offset` & `p_buf->len`
+ * before calling btsnoop_capture() */
+ p_buf->offset = p_buf->offset - HCI_ACL_PREAMBLE_SIZE;
+ p_buf->len = p_buf->len - p_buf->offset;
+
+ btsnoop_capture(p_buf, TRUE);
+
+ /* restore contents */
+ memcpy(p, p_cb->rcv_acl.preload_buffer, HCI_ACL_PREAMBLE_SIZE);
+
+ /* restore p_buf->len */
+ p_buf->len = tmp_u16;
+ }
+ else
+ {
+ /* START PACKET */
+ btsnoop_capture(p_buf, TRUE);
+ }
+
+ if (frame_end == TRUE)
+ p_buf->offset = 0;
+ else
+ p_buf->offset = p_buf->len; /* save current buffer-end position */
+
+ return frame_end;
+}
+
+/*****************************************************************************
+** HCI MCT INTERFACE FUNCTIONS
+*****************************************************************************/
+
+/*******************************************************************************
+**
+** Function hci_mct_init
+**
+** Description Initialize MCT module
+**
+** Returns None
+**
+*******************************************************************************/
+void hci_mct_init(void)
+{
+ HCIDBG("hci_mct_init");
+
+ memset(&mct_cb, 0, sizeof(tHCI_MCT_CB));
+ utils_queue_init(&(mct_cb.acl_rx_q));
+
+ /* Per HCI spec., always starts with 1 */
+ num_hci_cmd_pkts = 1;
+
+ /* Give an initial values of Host Controller's ACL data packet length
+ * Will update with an internal HCI(_LE)_Read_Buffer_Size request
+ */
+ mct_cb.hc_acl_data_size = 1021;
+ mct_cb.hc_ble_acl_data_size = 27;
+
+ btsnoop_init();
+}
+
+/*******************************************************************************
+**
+** Function hci_mct_cleanup
+**
+** Description Clean MCT module
+**
+** Returns None
+**
+*******************************************************************************/
+void hci_mct_cleanup(void)
+{
+ HCIDBG("hci_mct_cleanup");
+
+ btsnoop_close();
+ btsnoop_cleanup();
+}
+
+/*******************************************************************************
+**
+** Function hci_mct_send_msg
+**
+** Description Determine message type, then send message through according
+** channel
+**
+** Returns None
+**
+*******************************************************************************/
+void hci_mct_send_msg(HC_BT_HDR *p_msg)
+{
+ uint16_t handle;
+ uint16_t lay_spec;
+ uint8_t *p = ((uint8_t *)(p_msg + 1)) + p_msg->offset;
+ uint16_t event = p_msg->event & MSG_EVT_MASK;
+ uint16_t sub_event = p_msg->event & MSG_SUB_EVT_MASK;
+ uint16_t acl_pkt_size = 0, acl_data_size = 0;
+
+ /* wake up BT device if its in sleep mode */
+ lpm_wake_assert();
+
+ if (sub_event == LOCAL_BR_EDR_CONTROLLER_ID)
+ {
+ acl_data_size = mct_cb.hc_acl_data_size;
+ acl_pkt_size = mct_cb.hc_acl_data_size + HCI_ACL_PREAMBLE_SIZE;
+ }
+ else
+ {
+ acl_data_size = mct_cb.hc_ble_acl_data_size;
+ acl_pkt_size = mct_cb.hc_ble_acl_data_size + HCI_ACL_PREAMBLE_SIZE;
+ }
+
+ /* Check if sending ACL data that needs fragmenting */
+ if ((event == MSG_STACK_TO_HC_HCI_ACL) && (p_msg->len > acl_pkt_size))
+ {
+ /* Get the handle from the packet */
+ STREAM_TO_UINT16 (handle, p);
+
+ /* Set packet boundary flags to "continuation packet" */
+ handle = (handle & 0xCFFF) | 0x1000;
+
+ /* Do all the first chunks */
+ while (p_msg->len > acl_pkt_size)
+ {
+ p = ((uint8_t *)(p_msg + 1)) + p_msg->offset;
+
+ userial_write(event, (uint8_t *) p, acl_pkt_size);
+
+ /* generate snoop trace message */
+ btsnoop_capture(p_msg, FALSE);
+
+ /* Adjust offset and length for what we just sent */
+ p_msg->offset += acl_data_size;
+ p_msg->len -= acl_data_size;
+
+ p = ((uint8_t *)(p_msg + 1)) + p_msg->offset;
+
+ UINT16_TO_STREAM (p, handle);
+
+ if (p_msg->len > acl_pkt_size)
+ {
+ UINT16_TO_STREAM (p, acl_data_size);
+ }
+ else
+ {
+ UINT16_TO_STREAM (p, p_msg->len - HCI_ACL_PREAMBLE_SIZE);
+ }
+
+ /* If we were only to send partial buffer, stop when done. */
+ /* Send the buffer back to L2CAP to send the rest of it later */
+ if (p_msg->layer_specific)
+ {
+ if (--p_msg->layer_specific == 0)
+ {
+ p_msg->event = MSG_HC_TO_STACK_L2C_SEG_XMIT;
+
+ if (bt_hc_cbacks)
+ {
+ bt_hc_cbacks->tx_result((TRANSAC) p_msg, \
+ (char *) (p_msg + 1), \
+ BT_HC_TX_FRAGMENT);
+ }
+
+ return;
+ }
+ }
+ }
+ }
+
+ p = ((uint8_t *)(p_msg + 1)) + p_msg->offset;
+ userial_write(event, (uint8_t *) p, p_msg->len);
+
+ if (event == MSG_STACK_TO_HC_HCI_CMD)
+ {
+ utils_lock();
+ num_hci_cmd_pkts--;
+ utils_unlock();
+
+ /* If this is an internal Cmd packet, the layer_specific field would
+ * have stored with the opcode of HCI command.
+ * Retrieve the opcode from the Cmd packet.
+ */
+ p++;
+ STREAM_TO_UINT16(lay_spec, p);
+ }
+
+ /* generate snoop trace message */
+ btsnoop_capture(p_msg, FALSE);
+
+ if (bt_hc_cbacks)
+ {
+ if ((event == MSG_STACK_TO_HC_HCI_CMD) && \
+ (mct_cb.int_cmd_rsp_pending > 0) && \
+ (p_msg->layer_specific == lay_spec))
+ {
+ /* dealloc buffer of internal command */
+ bt_hc_cbacks->dealloc((TRANSAC) p_msg, (char *) (p_msg + 1));
+ }
+ else
+ {
+ bt_hc_cbacks->tx_result((TRANSAC) p_msg, (char *) (p_msg + 1), \
+ BT_HC_TX_SUCCESS);
+ }
+ }
+
+ lpm_tx_done(TRUE);
+
+ return;
+}
+
+
+/*******************************************************************************
+**
+** Function hci_mct_receive_evt_msg
+**
+** Description Construct HCI EVENT packet
+**
+** Returns Number of read bytes
+**
+*******************************************************************************/
+uint16_t hci_mct_receive_evt_msg(void)
+{
+ uint16_t bytes_read = 0;
+ uint8_t byte;
+ uint16_t msg_len, len;
+ uint8_t msg_received;
+ tHCI_RCV_CB *p_cb=&mct_cb.rcv_evt;
+ uint8_t continue_fetch_looping = TRUE;
+
+ while (continue_fetch_looping)
+ {
+ /* Read one byte to see if there is anything waiting to be read */
+ if (userial_read(MSG_HC_TO_STACK_HCI_EVT, &byte, 1) == 0)
+ {
+ break;
+ }
+
+ bytes_read++;
+ msg_received = FALSE;
+
+ switch (p_cb->rcv_state)
+ {
+ case MCT_RX_NEWMSG_ST:
+ /* Start of new message */
+ /* Initialize rx parameters */
+ memset(p_cb->preload_buffer, 0 , 6);
+ p_cb->preload_buffer[0] = byte;
+ p_cb->preload_count = 1;
+ p_cb->rcv_len = HCI_EVT_PREAMBLE_SIZE - 1;
+ // p_cb->p_rcv_msg = NULL;
+ p_cb->rcv_state = MCT_RX_LEN_ST; /* Next, wait for length to come */
+ break;
+
+ case MCT_RX_LEN_ST:
+ /* Receiving preamble */
+ p_cb->preload_buffer[p_cb->preload_count++] = byte;
+ p_cb->rcv_len--;
+
+ /* Check if we received entire preamble yet */
+ if (p_cb->rcv_len == 0)
+ {
+ /* Received entire preamble.
+ * Length is in the last received byte */
+ msg_len = byte;
+ p_cb->rcv_len = msg_len;
+
+ /* Allocate a buffer for message */
+ if (bt_hc_cbacks)
+ {
+ len = msg_len + p_cb->preload_count + BT_HC_HDR_SIZE;
+ p_cb->p_rcv_msg = \
+ (HC_BT_HDR *) bt_hc_cbacks->alloc(len);
+ }
+
+ if (p_cb->p_rcv_msg)
+ {
+ /* Initialize buffer with preloaded data */
+ p_cb->p_rcv_msg->offset = 0;
+ p_cb->p_rcv_msg->layer_specific = 0;
+ p_cb->p_rcv_msg->event = MSG_HC_TO_STACK_HCI_EVT;
+ p_cb->p_rcv_msg->len = p_cb->preload_count;
+ memcpy((uint8_t *)(p_cb->p_rcv_msg + 1), \
+ p_cb->preload_buffer, p_cb->preload_count);
+ }
+ else
+ {
+ /* Unable to acquire message buffer. */
+ ALOGE( \
+ "Unable to acquire buffer for incoming HCI message." \
+ );
+
+ if (msg_len == 0)
+ {
+ /* Wait for next message */
+ p_cb->rcv_state = MCT_RX_NEWMSG_ST;
+ continue_fetch_looping = FALSE;
+ }
+ else
+ {
+ /* Ignore rest of the packet */
+ p_cb->rcv_state = MCT_RX_IGNORE_ST;
+ }
+
+ break;
+ }
+
+ /* Message length is valid */
+ if (msg_len)
+ {
+ /* Read rest of message */
+ p_cb->rcv_state = MCT_RX_DATA_ST;
+ }
+ else
+ {
+ /* Message has no additional parameters.
+ * (Entire message has been received) */
+ msg_received = TRUE;
+
+ /* Next, wait for next message */
+ p_cb->rcv_state = MCT_RX_NEWMSG_ST;
+ continue_fetch_looping = FALSE;
+ }
+ }
+ break;
+
+ case MCT_RX_DATA_ST:
+ *((uint8_t *)(p_cb->p_rcv_msg + 1) + p_cb->p_rcv_msg->len++) = byte;
+ p_cb->rcv_len--;
+
+ if (p_cb->rcv_len > 0)
+ {
+ /* Read in the rest of the message */
+ len = userial_read(MSG_HC_TO_STACK_HCI_EVT, \
+ ((uint8_t *)(p_cb->p_rcv_msg+1) + p_cb->p_rcv_msg->len), \
+ p_cb->rcv_len);
+ p_cb->p_rcv_msg->len += len;
+ p_cb->rcv_len -= len;
+ bytes_read += len;
+ }
+
+ /* Check if we read in entire message yet */
+ if (p_cb->rcv_len == 0)
+ {
+ /* Received entire packet. */
+ msg_received = TRUE;
+ /* Next, wait for next message */
+ p_cb->rcv_state = MCT_RX_NEWMSG_ST;
+ continue_fetch_looping = FALSE;
+ }
+ break;
+
+
+ case MCT_RX_IGNORE_ST:
+ /* Ignore reset of packet */
+ p_cb->rcv_len--;
+
+ /* Check if we read in entire message yet */
+ if (p_cb->rcv_len == 0)
+ {
+ /* Next, wait for next message */
+ p_cb->rcv_state = MCT_RX_NEWMSG_ST;
+ continue_fetch_looping = FALSE;
+ }
+ break;
+ }
+
+
+ /* If we received entire message, then send it to the task */
+ if (msg_received)
+ {
+ uint8_t intercepted = FALSE;
+
+ /* generate snoop trace message */
+ btsnoop_capture(p_cb->p_rcv_msg, TRUE);
+
+ intercepted = internal_event_intercept();
+
+ if ((bt_hc_cbacks) && (intercepted == FALSE))
+ {
+ bt_hc_cbacks->data_ind((TRANSAC) p_cb->p_rcv_msg, \
+ (char *) (p_cb->p_rcv_msg + 1), \
+ p_cb->p_rcv_msg->len + BT_HC_HDR_SIZE);
+ }
+ p_cb->p_rcv_msg = NULL;
+ }
+ }
+
+ return (bytes_read);
+}
+
+
+/*******************************************************************************
+**
+** Function hci_mct_receive_acl_msg
+**
+** Description Construct HCI ACL packet
+**
+** Returns Number of read bytes
+**
+*******************************************************************************/
+uint16_t hci_mct_receive_acl_msg(void)
+{
+ uint16_t bytes_read = 0;
+ uint8_t byte;
+ uint16_t msg_len, len;
+ uint8_t msg_received;
+ tHCI_RCV_CB *p_cb=&mct_cb.rcv_acl;
+ uint8_t continue_fetch_looping = TRUE;
+
+ while (continue_fetch_looping)
+ {
+ /* Read one byte to see if there is anything waiting to be read */
+ if (userial_read(MSG_HC_TO_STACK_HCI_ACL, &byte, 1) == 0)
+ {
+ break;
+ }
+
+ bytes_read++;
+ msg_received = FALSE;
+
+ switch (p_cb->rcv_state)
+ {
+ case MCT_RX_NEWMSG_ST:
+ /* Start of new message */
+ /* Initialize rx parameters */
+ memset(p_cb->preload_buffer, 0 , 6);
+ p_cb->preload_buffer[0] = byte;
+ p_cb->preload_count = 1;
+ p_cb->rcv_len = HCI_ACL_PREAMBLE_SIZE - 1;
+ // p_cb->p_rcv_msg = NULL;
+ p_cb->rcv_state = MCT_RX_LEN_ST; /* Next, wait for length to come */
+ break;
+
+ case MCT_RX_LEN_ST:
+ /* Receiving preamble */
+ p_cb->preload_buffer[p_cb->preload_count++] = byte;
+ p_cb->rcv_len--;
+
+ /* Check if we received entire preamble yet */
+ if (p_cb->rcv_len == 0)
+ {
+ /* ACL data lengths are 16-bits */
+ msg_len = p_cb->preload_buffer[3];
+ msg_len = (msg_len << 8) + p_cb->preload_buffer[2];
+
+ if (msg_len && (p_cb->preload_count == 4))
+ {
+ /* Check if this is a start packet */
+ byte = ((p_cb->preload_buffer[1] >> 4) & 0x03);
+
+ if (byte == ACL_RX_PKT_START)
+ {
+ /*
+ * A start packet & with non-zero data payload length.
+ * We want to read 2 more bytes to get L2CAP payload
+ * length.
+ */
+ p_cb->rcv_len = 2;
+
+ break;
+ }
+ }
+
+ /*
+ * Check for segmented packets. If this is a continuation
+ * packet, then we will continue appending data to the
+ * original rcv buffer.
+ */
+ p_cb->p_rcv_msg = acl_rx_frame_buffer_alloc();
+
+ if (p_cb->p_rcv_msg == NULL)
+ {
+ /* Unable to acquire message buffer. */
+ ALOGE( \
+ "Unable to acquire buffer for incoming HCI message." \
+ );
+
+ if (msg_len == 0)
+ {
+ /* Wait for next message */
+ p_cb->rcv_state = MCT_RX_NEWMSG_ST;
+ continue_fetch_looping = FALSE;
+ }
+ else
+ {
+ /* Ignore rest of the packet */
+ p_cb->rcv_state = MCT_RX_IGNORE_ST;
+ }
+
+ break;
+ }
+
+ /* Message length is valid */
+ if (msg_len)
+ {
+ /* Read rest of message */
+ p_cb->rcv_state = MCT_RX_DATA_ST;
+ }
+ else
+ {
+ /* Message has no additional parameters.
+ * (Entire message has been received) */
+ acl_rx_frame_end_chk(); /* to print snoop trace */
+
+ msg_received = TRUE;
+
+ /* Next, wait for next message */
+ p_cb->rcv_state = MCT_RX_NEWMSG_ST;
+ continue_fetch_looping = FALSE;
+ }
+ }
+ break;
+
+ case MCT_RX_DATA_ST:
+ *((uint8_t *)(p_cb->p_rcv_msg + 1) + p_cb->p_rcv_msg->len++) = byte;
+ p_cb->rcv_len--;
+
+ if (p_cb->rcv_len > 0)
+ {
+ /* Read in the rest of the message */
+ len = userial_read(MSG_HC_TO_STACK_HCI_ACL, \
+ ((uint8_t *)(p_cb->p_rcv_msg+1) + p_cb->p_rcv_msg->len), \
+ p_cb->rcv_len);
+ p_cb->p_rcv_msg->len += len;
+ p_cb->rcv_len -= len;
+ bytes_read += len;
+ }
+
+ /* Check if we read in entire message yet */
+ if (p_cb->rcv_len == 0)
+ {
+ /* Received entire packet. */
+ /* Check for segmented l2cap packets */
+ if (acl_rx_frame_end_chk())
+ {
+ msg_received = TRUE;
+ }
+
+ /* Next, wait for next message */
+ p_cb->rcv_state = MCT_RX_NEWMSG_ST;
+ continue_fetch_looping = FALSE;
+ }
+ break;
+
+
+ case MCT_RX_IGNORE_ST:
+ /* Ignore reset of packet */
+ p_cb->rcv_len--;
+
+ /* Check if we read in entire message yet */
+ if (p_cb->rcv_len == 0)
+ {
+ /* Next, wait for next message */
+ p_cb->rcv_state = MCT_RX_NEWMSG_ST;
+ continue_fetch_looping = FALSE;
+ }
+ break;
+ }
+
+
+ /* If we received entire message, then send it to the task */
+ if (msg_received)
+ {
+ if (bt_hc_cbacks)
+ {
+ bt_hc_cbacks->data_ind((TRANSAC) p_cb->p_rcv_msg, \
+ (char *) (p_cb->p_rcv_msg + 1), \
+ p_cb->p_rcv_msg->len + BT_HC_HDR_SIZE);
+ }
+ p_cb->p_rcv_msg = NULL;
+ }
+ }
+
+ return (bytes_read);
+}
+
+/*******************************************************************************
+**
+** Function hci_mct_send_int_cmd
+**
+** Description Place the internal commands (issued internally by hci or
+** vendor lib) in the tx_q.
+**
+** Returns TRUE/FALSE
+**
+*******************************************************************************/
+uint8_t hci_mct_send_int_cmd(uint16_t opcode, HC_BT_HDR *p_buf, \
+ tINT_CMD_CBACK p_cback)
+{
+ if (mct_cb.int_cmd_rsp_pending > INT_CMD_PKT_MAX_COUNT)
+ {
+ ALOGE( \
+ "Allow only %d outstanding internal commands at a time [Reject 0x%04X]"\
+ , INT_CMD_PKT_MAX_COUNT, opcode);
+ return FALSE;
+ }
+
+ mct_cb.int_cmd_rsp_pending++;
+ mct_cb.int_cmd[mct_cb.int_cmd_wrt_idx].opcode = opcode;
+ mct_cb.int_cmd[mct_cb.int_cmd_wrt_idx].cback = p_cback;
+ mct_cb.int_cmd_wrt_idx = ((mct_cb.int_cmd_wrt_idx+1) & INT_CMD_PKT_IDX_MASK);
+
+ /* stamp signature to indicate an internal command */
+ p_buf->layer_specific = opcode;
+
+ utils_enqueue(&tx_q, (void *) p_buf);
+ bthc_signal_event(HC_EVENT_TX);
+
+ return TRUE;
+}
+
+
+/*******************************************************************************
+**
+** Function hci_mct_get_acl_data_length
+**
+** Description Issue HCI_READ_BUFFER_SIZE command to retrieve Controller's
+** ACL data length setting
+**
+** Returns None
+**
+*******************************************************************************/
+void hci_mct_get_acl_data_length(void)
+{
+ HC_BT_HDR *p_buf = NULL;
+ uint8_t *p, ret;
+
+ if (bt_hc_cbacks)
+ {
+ p_buf = (HC_BT_HDR *) bt_hc_cbacks->alloc(BT_HC_HDR_SIZE + \
+ HCI_CMD_PREAMBLE_SIZE);
+ }
+
+ if (p_buf)
+ {
+ p_buf->event = MSG_STACK_TO_HC_HCI_CMD;
+ p_buf->offset = 0;
+ p_buf->layer_specific = 0;
+ p_buf->len = HCI_CMD_PREAMBLE_SIZE;
+
+ p = (uint8_t *) (p_buf + 1);
+ UINT16_TO_STREAM(p, HCI_READ_BUFFER_SIZE);
+ *p = 0;
+
+ if ((ret = hci_mct_send_int_cmd(HCI_READ_BUFFER_SIZE, p_buf, \
+ get_acl_data_length_cback)) == FALSE)
+ {
+ bt_hc_cbacks->dealloc((TRANSAC) p_buf, (char *) (p_buf + 1));
+ }
+ else
+ return;
+ }
+
+ if (bt_hc_cbacks)
+ {
+ ALOGE("hci lib postload aborted");
+ bt_hc_cbacks->postload_cb(NULL, BT_HC_POSTLOAD_FAIL);
+ }
+}
+
+
+/******************************************************************************
+** HCI MCT Services interface table
+******************************************************************************/
+
+const tHCI_IF hci_mct_func_table =
+{
+ hci_mct_init,
+ hci_mct_cleanup,
+ hci_mct_send_msg,
+ hci_mct_send_int_cmd,
+ hci_mct_get_acl_data_length,
+ hci_mct_receive_evt_msg,
+ hci_mct_receive_acl_msg
+};
+
+
diff --git a/hci/src/userial.c b/hci/src/userial.c
index 0b37c3f..71f5ae8 100644
--- a/hci/src/userial.c
+++ b/hci/src/userial.c
@@ -3,44 +3,44 @@
* Copyright (C) 2009-2012 Broadcom Corporation
*
* This program is the proprietary software of Broadcom Corporation and/or its
- * licensors, and may only be used, duplicated, modified or distributed
- * pursuant to the terms and conditions of a separate, written license
- * agreement executed between you and Broadcom (an "Authorized License").
- * Except as set forth in an Authorized License, Broadcom grants no license
- * (express or implied), right to use, or waiver of any kind with respect to
- * the Software, and Broadcom expressly reserves all rights in and to the
- * Software and all intellectual property rights therein.
- * IF YOU HAVE NO AUTHORIZED LICENSE, THEN YOU HAVE NO RIGHT TO USE THIS
- * SOFTWARE IN ANY WAY, AND SHOULD IMMEDIATELY NOTIFY BROADCOM AND DISCONTINUE
- * ALL USE OF THE SOFTWARE.
+ * licensors, and may only be used, duplicated, modified or distributed
+ * pursuant to the terms and conditions of a separate, written license
+ * agreement executed between you and Broadcom (an "Authorized License").
+ * Except as set forth in an Authorized License, Broadcom grants no license
+ * (express or implied), right to use, or waiver of any kind with respect to
+ * the Software, and Broadcom expressly reserves all rights in and to the
+ * Software and all intellectual property rights therein.
+ * IF YOU HAVE NO AUTHORIZED LICENSE, THEN YOU HAVE NO RIGHT TO USE THIS
+ * SOFTWARE IN ANY WAY, AND SHOULD IMMEDIATELY NOTIFY BROADCOM AND DISCONTINUE
+ * ALL USE OF THE SOFTWARE.
*
* Except as expressly set forth in the Authorized License,
*
- * 1. This program, including its structure, sequence and organization,
- * constitutes the valuable trade secrets of Broadcom, and you shall
- * use all reasonable efforts to protect the confidentiality thereof,
- * and to use this information only in connection with your use of
+ * 1. This program, including its structure, sequence and organization,
+ * constitutes the valuable trade secrets of Broadcom, and you shall
+ * use all reasonable efforts to protect the confidentiality thereof,
+ * and to use this information only in connection with your use of
* Broadcom integrated circuit products.
*
- * 2. TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED
- * "AS IS" AND WITH ALL FAULTS AND BROADCOM MAKES NO PROMISES,
- * REPRESENTATIONS OR WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY,
- * OR OTHERWISE, WITH RESPECT TO THE SOFTWARE. BROADCOM SPECIFICALLY
- * DISCLAIMS ANY AND ALL IMPLIED WARRANTIES OF TITLE, MERCHANTABILITY,
- * NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF VIRUSES,
- * ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR
+ * 2. TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED
+ * "AS IS" AND WITH ALL FAULTS AND BROADCOM MAKES NO PROMISES,
+ * REPRESENTATIONS OR WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY,
+ * OR OTHERWISE, WITH RESPECT TO THE SOFTWARE. BROADCOM SPECIFICALLY
+ * DISCLAIMS ANY AND ALL IMPLIED WARRANTIES OF TITLE, MERCHANTABILITY,
+ * NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF VIRUSES,
+ * ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR
* CORRESPONDENCE TO DESCRIPTION. YOU ASSUME THE ENTIRE RISK ARISING OUT
* OF USE OR PERFORMANCE OF THE SOFTWARE.
*
* 3. TO THE MAXIMUM EXTENT PERMITTED BY LAW, IN NO EVENT SHALL BROADCOM OR
- * ITS LICENSORS BE LIABLE FOR
- * (i) CONSEQUENTIAL, INCIDENTAL, SPECIAL, INDIRECT, OR EXEMPLARY
- * DAMAGES WHATSOEVER ARISING OUT OF OR IN ANY WAY RELATING TO
- * YOUR USE OF OR INABILITY TO USE THE SOFTWARE EVEN IF BROADCOM
- * HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES; OR
- * (ii) ANY AMOUNT IN EXCESS OF THE AMOUNT ACTUALLY PAID FOR THE
- * SOFTWARE ITSELF OR U.S. $1, WHICHEVER IS GREATER. THESE
- * LIMITATIONS SHALL APPLY NOTWITHSTANDING ANY FAILURE OF
+ * ITS LICENSORS BE LIABLE FOR
+ * (i) CONSEQUENTIAL, INCIDENTAL, SPECIAL, INDIRECT, OR EXEMPLARY
+ * DAMAGES WHATSOEVER ARISING OUT OF OR IN ANY WAY RELATING TO
+ * YOUR USE OF OR INABILITY TO USE THE SOFTWARE EVEN IF BROADCOM
+ * HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES; OR
+ * (ii) ANY AMOUNT IN EXCESS OF THE AMOUNT ACTUALLY PAID FOR THE
+ * SOFTWARE ITSELF OR U.S. $1, WHICHEVER IS GREATER. THESE
+ * LIMITATIONS SHALL APPLY NOTWITHSTANDING ANY FAILURE OF
* ESSENTIAL PURPOSE OF ANY LIMITED REMEDY.
*
******************************************************************************/
@@ -101,7 +101,7 @@ extern bt_vendor_interface_t *bt_vnd_if;
typedef struct
{
- int sock;
+ int fd;
uint8_t port;
pthread_t read_thread;
BUFFER_Q rx_q;
@@ -262,7 +262,7 @@ static void *userial_read_thread(void *arg)
p_buf->layer_specific = 0;
p = (uint8_t *) (p_buf + 1);
- rx_length = select_read(userial_cb.sock, p, READ_LIMIT);
+ rx_length = select_read(userial_cb.fd, p, READ_LIMIT);
}
else
{
@@ -315,7 +315,7 @@ uint8_t userial_init(void)
{
USERIALDBG("userial_init");
memset(&userial_cb, 0, sizeof(tUSERIAL_CB));
- userial_cb.sock = -1;
+ userial_cb.fd = -1;
utils_queue_init(&(userial_cb.rx_q));
return TRUE;
}
@@ -335,6 +335,7 @@ uint8_t userial_open(uint8_t port)
struct sched_param param;
int policy, result;
pthread_attr_t thread_attr;
+ int fd_array[CH_MAX];
USERIALDBG("userial_open(port:%d)", port);
@@ -354,7 +355,18 @@ uint8_t userial_open(uint8_t port)
/* Calling vendor-specific part */
if (bt_vnd_if)
{
- userial_cb.sock = bt_vnd_if->op(BT_VND_OP_USERIAL_OPEN, NULL);
+ result = bt_vnd_if->op(BT_VND_OP_USERIAL_OPEN, &fd_array);
+
+ if (result != 1)
+ {
+ ALOGE("userial_open: wrong numbers of open fd in vendor lib [%d]!",
+ result);
+ ALOGE("userial_open: HCI UART expects only one open fd");
+ bt_vnd_if->op(BT_VND_OP_USERIAL_CLOSE, NULL);
+ return FALSE;
+ }
+
+ userial_cb.fd = fd_array[0];
}
else
{
@@ -363,13 +375,13 @@ uint8_t userial_open(uint8_t port)
return FALSE;
}
- if (userial_cb.sock == -1)
+ if (userial_cb.fd == -1)
{
ALOGE("userial_open: failed to open UART port");
return FALSE;
}
- USERIALDBG( "sock = %d", userial_cb.sock);
+ USERIALDBG( "fd = %d", userial_cb.fd);
userial_cb.port = port;
@@ -409,7 +421,7 @@ uint8_t userial_open(uint8_t port)
** copied into p_data. This may be less than len.
**
*******************************************************************************/
-uint16_t userial_read(uint8_t *p_buffer, uint16_t len)
+uint16_t userial_read(uint16_t msg_id, uint8_t *p_buffer, uint16_t len)
{
uint16_t total_len = 0;
uint16_t copy_len = 0;
@@ -463,13 +475,13 @@ uint16_t userial_read(uint8_t *p_buffer, uint16_t len)
** may be less than len.
**
*******************************************************************************/
-uint16_t userial_write(uint8_t *p_data, uint16_t len)
+uint16_t userial_write(uint16_t msg_id, uint8_t *p_data, uint16_t len)
{
int ret, total = 0;
while(len != 0)
{
- ret = write(userial_cb.sock, p_data+total, len);
+ ret = write(userial_cb.fd, p_data+total, len);
total += ret;
len -= ret;
}
@@ -491,7 +503,7 @@ void userial_close(void)
int result;
TRANSAC p_buf;
- USERIALDBG("userial_close(sock:%d)", userial_cb.sock);
+ USERIALDBG("userial_close(fd:%d)", userial_cb.fd);
if (userial_running)
send_wakeup_signal(USERIAL_RX_EXIT);
@@ -503,10 +515,7 @@ void userial_close(void)
if (bt_vnd_if)
bt_vnd_if->op(BT_VND_OP_USERIAL_CLOSE, NULL);
- if ((result=close(userial_cb.sock)) < 0)
- ALOGE( "close(sock:%d) FAILED result:%d", userial_cb.sock, result);
-
- userial_cb.sock = -1;
+ userial_cb.fd = -1;
if (bt_hc_cbacks)
{
diff --git a/hci/src/userial_mct.c b/hci/src/userial_mct.c
new file mode 100644
index 0000000..6ccb40f
--- /dev/null
+++ b/hci/src/userial_mct.c
@@ -0,0 +1,468 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ * This program is the proprietary software of Broadcom Corporation and/or its
+ * licensors, and may only be used, duplicated, modified or distributed
+ * pursuant to the terms and conditions of a separate, written license
+ * agreement executed between you and Broadcom (an "Authorized License").
+ * Except as set forth in an Authorized License, Broadcom grants no license
+ * (express or implied), right to use, or waiver of any kind with respect to
+ * the Software, and Broadcom expressly reserves all rights in and to the
+ * Software and all intellectual property rights therein.
+ * IF YOU HAVE NO AUTHORIZED LICENSE, THEN YOU HAVE NO RIGHT TO USE THIS
+ * SOFTWARE IN ANY WAY, AND SHOULD IMMEDIATELY NOTIFY BROADCOM AND DISCONTINUE
+ * ALL USE OF THE SOFTWARE.
+ *
+ * Except as expressly set forth in the Authorized License,
+ *
+ * 1. This program, including its structure, sequence and organization,
+ * constitutes the valuable trade secrets of Broadcom, and you shall
+ * use all reasonable efforts to protect the confidentiality thereof,
+ * and to use this information only in connection with your use of
+ * Broadcom integrated circuit products.
+ *
+ * 2. TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED
+ * "AS IS" AND WITH ALL FAULTS AND BROADCOM MAKES NO PROMISES,
+ * REPRESENTATIONS OR WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY,
+ * OR OTHERWISE, WITH RESPECT TO THE SOFTWARE. BROADCOM SPECIFICALLY
+ * DISCLAIMS ANY AND ALL IMPLIED WARRANTIES OF TITLE, MERCHANTABILITY,
+ * NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF VIRUSES,
+ * ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR
+ * CORRESPONDENCE TO DESCRIPTION. YOU ASSUME THE ENTIRE RISK ARISING OUT
+ * OF USE OR PERFORMANCE OF THE SOFTWARE.
+ *
+ * 3. TO THE MAXIMUM EXTENT PERMITTED BY LAW, IN NO EVENT SHALL BROADCOM OR
+ * ITS LICENSORS BE LIABLE FOR
+ * (i) CONSEQUENTIAL, INCIDENTAL, SPECIAL, INDIRECT, OR EXEMPLARY
+ * DAMAGES WHATSOEVER ARISING OUT OF OR IN ANY WAY RELATING TO
+ * YOUR USE OF OR INABILITY TO USE THE SOFTWARE EVEN IF BROADCOM
+ * HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES; OR
+ * (ii) ANY AMOUNT IN EXCESS OF THE AMOUNT ACTUALLY PAID FOR THE
+ * SOFTWARE ITSELF OR U.S. $1, WHICHEVER IS GREATER. THESE
+ * LIMITATIONS SHALL APPLY NOTWITHSTANDING ANY FAILURE OF
+ * ESSENTIAL PURPOSE OF ANY LIMITED REMEDY.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * Filename: userial_mct.c
+ *
+ * Description: Contains open/read/write/close functions on multi-channels
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_userial_mct"
+
+#include <utils/Log.h>
+#include <pthread.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <stdio.h>
+#include <sys/socket.h>
+#include "bt_hci_bdroid.h"
+#include "userial.h"
+#include "utils.h"
+#include "bt_vendor_lib.h"
+
+/******************************************************************************
+** Constants & Macros
+******************************************************************************/
+
+#define USERIAL_DBG TRUE
+
+#ifndef USERIAL_DBG
+#define USERIAL_DBG FALSE
+#endif
+
+#if (USERIAL_DBG == TRUE)
+#define USERIALDBG(param, ...) {ALOGD(param, ## __VA_ARGS__);}
+#else
+#define USERIALDBG(param, ...) {}
+#endif
+
+#define MAX_SERIAL_PORT (USERIAL_PORT_3 + 1)
+
+enum {
+ USERIAL_RX_EXIT,
+ USERIAL_RX_FLOW_OFF,
+ USERIAL_RX_FLOW_ON
+};
+
+/******************************************************************************
+** Externs
+******************************************************************************/
+
+extern bt_vendor_interface_t *bt_vnd_if;
+uint16_t hci_mct_receive_evt_msg(void);
+uint16_t hci_mct_receive_acl_msg(void);
+
+
+/******************************************************************************
+** Local type definitions
+******************************************************************************/
+
+typedef struct
+{
+ int fd[CH_MAX];
+ uint8_t port;
+ pthread_t read_thread;
+ BUFFER_Q rx_q;
+ HC_BT_HDR *p_rx_hdr;
+} tUSERIAL_CB;
+
+/******************************************************************************
+** Static variables
+******************************************************************************/
+
+static tUSERIAL_CB userial_cb;
+static volatile uint8_t userial_running = 0;
+
+/******************************************************************************
+** Static functions
+******************************************************************************/
+
+/*****************************************************************************
+** Socket signal functions to wake up userial_read_thread for termination
+**
+** creating an unnamed pair of connected sockets
+** - signal_fds[0]: join fd_set in select call of userial_read_thread
+** - signal_fds[1]: trigger from userial_close
+*****************************************************************************/
+static int signal_fds[2]={0,1};
+static uint8_t rx_flow_on = TRUE;
+static inline int create_signal_fds(fd_set* set)
+{
+ if(signal_fds[0]==0 && socketpair(AF_UNIX, SOCK_STREAM, 0, signal_fds)<0)
+ {
+ ALOGE("create_signal_sockets:socketpair failed, errno: %d", errno);
+ return -1;
+ }
+ FD_SET(signal_fds[0], set);
+ return signal_fds[0];
+}
+static inline int send_wakeup_signal(char sig_cmd)
+{
+ return send(signal_fds[1], &sig_cmd, sizeof(sig_cmd), 0);
+}
+static inline char reset_signal()
+{
+ char sig_recv = -1;
+ recv(signal_fds[0], &sig_recv, sizeof(sig_recv), MSG_WAITALL);
+ return sig_recv;
+}
+static inline int is_signaled(fd_set* set)
+{
+ return FD_ISSET(signal_fds[0], set);
+}
+
+/*******************************************************************************
+**
+** Function userial_evt_read_thread
+**
+** Description The reading thread on EVT and ACL_IN channels
+**
+** Returns void *
+**
+*******************************************************************************/
+static void *userial_read_thread(void *arg)
+{
+ fd_set input;
+ int n;
+ char reason = 0;
+
+ USERIALDBG("Entering userial_read_thread()");
+
+ rx_flow_on = TRUE;
+ userial_running = 1;
+
+ while (userial_running)
+ {
+ /* Initialize the input fd set */
+ FD_ZERO(&input);
+ if (rx_flow_on == TRUE)
+ {
+ FD_SET(userial_cb.fd[CH_EVT], &input);
+ FD_SET(userial_cb.fd[CH_ACL_IN], &input);
+ }
+
+ int fd_max = create_signal_fds(&input);
+ fd_max = (fd_max>userial_cb.fd[CH_EVT]) ? fd_max : userial_cb.fd[CH_EVT];
+ fd_max = (fd_max>userial_cb.fd[CH_ACL_IN]) ? fd_max : userial_cb.fd[CH_ACL_IN];
+
+ /* Do the select */
+ n = 0;
+ n = select(fd_max+1, &input, NULL, NULL, NULL);
+ if(is_signaled(&input))
+ {
+ reason = reset_signal();
+ if (reason == USERIAL_RX_EXIT)
+ {
+ ALOGI("exiting userial_read_thread");
+ userial_running = 0;
+ break;
+ }
+ else if (reason == USERIAL_RX_FLOW_OFF)
+ {
+ USERIALDBG("RX flow OFF");
+ rx_flow_on = FALSE;
+ }
+ else if (reason == USERIAL_RX_FLOW_ON)
+ {
+ USERIALDBG("RX flow ON");
+ rx_flow_on = TRUE;
+ }
+ }
+
+ if (n > 0)
+ {
+ /* We might have input */
+ if (FD_ISSET(userial_cb.fd[CH_EVT], &input))
+ {
+ hci_mct_receive_evt_msg();
+ }
+
+ if (FD_ISSET(userial_cb.fd[CH_ACL_IN], &input))
+ {
+ hci_mct_receive_acl_msg();
+ }
+ }
+ else if (n < 0)
+ ALOGW( "select() Failed");
+ else if (n == 0)
+ ALOGW( "Got a select() TIMEOUT");
+ } /* while */
+
+ userial_running = 0;
+ USERIALDBG("Leaving userial_evt_read_thread()");
+ pthread_exit(NULL);
+
+ return NULL; // Compiler friendly
+}
+
+
+/*****************************************************************************
+** Userial API Functions
+*****************************************************************************/
+
+/*******************************************************************************
+**
+** Function userial_init
+**
+** Description Initializes the userial driver
+**
+** Returns TRUE/FALSE
+**
+*******************************************************************************/
+uint8_t userial_init(void)
+{
+ int idx;
+
+ USERIALDBG("userial_init");
+ memset(&userial_cb, 0, sizeof(tUSERIAL_CB));
+ for (idx=0; idx < CH_MAX; idx++)
+ userial_cb.fd[idx] = -1;
+ utils_queue_init(&(userial_cb.rx_q));
+ return TRUE;
+}
+
+
+/*******************************************************************************
+**
+** Function userial_open
+**
+** Description Open Bluetooth device with the port ID
+**
+** Returns TRUE/FALSE
+**
+*******************************************************************************/
+uint8_t userial_open(uint8_t port)
+{
+ struct sched_param param;
+ int policy, result;
+ pthread_attr_t thread_attr;
+
+ USERIALDBG("userial_open(port:%d)", port);
+
+ if (userial_running)
+ {
+ /* Userial is open; close it first */
+ userial_close();
+ utils_delay(50);
+ }
+
+ if (port >= MAX_SERIAL_PORT)
+ {
+ ALOGE("Port > MAX_SERIAL_PORT");
+ return FALSE;
+ }
+
+ /* Calling vendor-specific part */
+ if (bt_vnd_if)
+ {
+ result = bt_vnd_if->op(BT_VND_OP_USERIAL_OPEN, &userial_cb.fd);
+
+ if ((result != 2) && (result != 4))
+ {
+ ALOGE("userial_open: wrong numbers of open fd in vendor lib [%d]!",
+ result);
+ ALOGE("userial_open: HCI MCT expects 2 or 4 open file descriptors");
+ bt_vnd_if->op(BT_VND_OP_USERIAL_CLOSE, NULL);
+ return FALSE;
+ }
+ }
+ else
+ {
+ ALOGE("userial_open: missing vendor lib interface !!!");
+ ALOGE("userial_open: unable to open BT transport");
+ return FALSE;
+ }
+
+ ALOGI("CMD=%d, EVT=%d, ACL_Out=%d, ACL_In=%d", \
+ userial_cb.fd[CH_CMD], userial_cb.fd[CH_EVT], \
+ userial_cb.fd[CH_ACL_OUT], userial_cb.fd[CH_ACL_IN]);
+
+ if ((userial_cb.fd[CH_CMD] == -1) || (userial_cb.fd[CH_EVT] == -1) ||
+ (userial_cb.fd[CH_ACL_OUT] == -1) || (userial_cb.fd[CH_ACL_IN] == -1))
+ {
+ ALOGE("userial_open: failed to open BT transport");
+ bt_vnd_if->op(BT_VND_OP_USERIAL_CLOSE, NULL);
+ return FALSE;
+ }
+
+ userial_cb.port = port;
+
+ /* Start listening thread */
+ pthread_attr_init(&thread_attr);
+
+ if (pthread_create(&(userial_cb.read_thread), &thread_attr, \
+ userial_read_thread, NULL) != 0 )
+ {
+ ALOGE("pthread_create failed!");
+ bt_vnd_if->op(BT_VND_OP_USERIAL_CLOSE, NULL);
+ return FALSE;
+ }
+
+ if(pthread_getschedparam(userial_cb.read_thread, &policy, &param)==0)
+ {
+ policy = BTHC_LINUX_BASE_POLICY;
+#if (BTHC_LINUX_BASE_POLICY!=SCHED_NORMAL)
+ param.sched_priority = BTHC_USERIAL_READ_THREAD_PRIORITY;
+#endif
+ result=pthread_setschedparam(userial_cb.read_thread,policy,&param);
+ if (result != 0)
+ {
+ ALOGW("userial_open: pthread_setschedparam failed (%s)", \
+ strerror(result));
+ }
+ }
+
+ return TRUE;
+}
+
+/*******************************************************************************
+**
+** Function userial_read
+**
+** Description Read data from the userial channel
+**
+** Returns Number of bytes actually read from the userial port and
+** copied into p_data. This may be less than len.
+**
+*******************************************************************************/
+uint16_t userial_read(uint16_t msg_id, uint8_t *p_buffer, uint16_t len)
+{
+ int ret = -1;
+ int ch_idx = (msg_id == MSG_HC_TO_STACK_HCI_EVT) ? CH_EVT : CH_ACL_IN;
+
+ ret = read(userial_cb.fd[ch_idx], p_buffer, (size_t)len);
+ if (ret <= 0)
+ ALOGW( "userial_read: read() returned %d!", ret);
+
+ return (uint16_t) ((ret >= 0) ? ret : 0);
+}
+
+/*******************************************************************************
+**
+** Function userial_write
+**
+** Description Write data to the userial port
+**
+** Returns Number of bytes actually written to the userial port. This
+** may be less than len.
+**
+*******************************************************************************/
+uint16_t userial_write(uint16_t msg_id, uint8_t *p_data, uint16_t len)
+{
+ int ret, total = 0;
+ int ch_idx = (msg_id == MSG_STACK_TO_HC_HCI_CMD) ? CH_CMD : CH_ACL_OUT;
+
+ while(len != 0)
+ {
+ ret = write(userial_cb.fd[ch_idx], p_data+total, len);
+ total += ret;
+ len -= ret;
+ }
+
+ return ((uint16_t)total);
+}
+
+/*******************************************************************************
+**
+** Function userial_close
+**
+** Description Close the userial port
+**
+** Returns None
+**
+*******************************************************************************/
+void userial_close(void)
+{
+ int idx, result;
+
+ USERIALDBG("userial_close");
+
+ if (userial_running)
+ send_wakeup_signal(USERIAL_RX_EXIT);
+
+ if ((result=pthread_join(userial_cb.read_thread, NULL)) < 0)
+ ALOGE( "pthread_join() FAILED result:%d", result);
+
+ /* Calling vendor-specific part */
+ if (bt_vnd_if)
+ bt_vnd_if->op(BT_VND_OP_USERIAL_CLOSE, NULL);
+
+ for (idx=0; idx < CH_MAX; idx++)
+ userial_cb.fd[idx] = -1;
+}
+
+/*******************************************************************************
+**
+** Function userial_ioctl
+**
+** Description ioctl inteface
+**
+** Returns None
+**
+*******************************************************************************/
+void userial_ioctl(userial_ioctl_op_t op, void *p_data)
+{
+ switch(op)
+ {
+ case USERIAL_OP_RXFLOW_ON:
+ if (userial_running)
+ send_wakeup_signal(USERIAL_RX_FLOW_ON);
+ break;
+
+ case USERIAL_OP_RXFLOW_OFF:
+ if (userial_running)
+ send_wakeup_signal(USERIAL_RX_FLOW_OFF);
+ break;
+
+ case USERIAL_OP_INIT:
+ default:
+ break;
+ }
+}
+