From 11ca257d0f47c782c1ce3e986e5fc40969b29140 Mon Sep 17 00:00:00 2001 From: YK Jeffrey Chao Date: Tue, 14 Aug 2012 14:38:13 -0700 Subject: Add HCI Multi-Channel Transport support (1/2) Revise BT Vendor Lib interface and add support of HCI multi-channel transport. Change-Id: I5a7a7b64798bb30be60ed29bd564bc499bd5b5bc --- hci/Android.mk | 18 +- hci/include/bt_vendor_lib.h | 25 +- hci/include/hci.h | 115 +++++ hci/include/userial.h | 4 +- hci/src/bt_hci_bdroid.c | 28 +- hci/src/bt_hw.c | 9 +- hci/src/hci_h4.c | 161 +++--- hci/src/hci_mct.c | 1204 +++++++++++++++++++++++++++++++++++++++++++ hci/src/userial.c | 95 ++-- hci/src/userial_mct.c | 468 +++++++++++++++++ 10 files changed, 1991 insertions(+), 136 deletions(-) create mode 100644 hci/include/hci.h create mode 100644 hci/src/hci_mct.c create mode 100644 hci/src/userial_mct.c diff --git a/hci/Android.mk b/hci/Android.mk index b21793b..875197c 100644 --- a/hci/Android.mk +++ b/hci/Android.mk @@ -4,13 +4,27 @@ include $(CLEAR_VARS) LOCAL_SRC_FILES := \ src/bt_hci_bdroid.c \ - src/hci_h4.c \ - src/userial.c \ src/lpm.c \ src/bt_hw.c \ src/btsnoop.c \ src/utils.c +ifeq ($(BLUETOOTH_HCI_USE_MCT),true) + +LOCAL_CFLAGS := -DHCI_USE_MCT + +LOCAL_SRC_FILES += \ + src/hci_mct.c \ + src/userial_mct.c + +else + +LOCAL_SRC_FILES += \ + src/hci_h4.c \ + src/userial.c + +endif + LOCAL_C_INCLUDES += \ $(LOCAL_PATH)/include diff --git a/hci/include/bt_vendor_lib.h b/hci/include/bt_vendor_lib.h index 462d4e6..f095f65 100644 --- a/hci/include/bt_vendor_lib.h +++ b/hci/include/bt_vendor_lib.h @@ -101,9 +101,18 @@ typedef enum { * Open UART port on where the BT Controller is attached. * This is called before stack initialization. * [input param] - * None. + * A pointer to int array type for open file descriptors. + * The mapping of HCI channel to fd slot in the int array is given in + * bt_vendor_hci_channels_t. + * And, it requires the vendor lib to fill up the content before returning + * the call. + * Typecasting conversion: (int (*)[]) param. * [return] - * fd - the file descriptor of UART port for Bluetooth. + * Numbers of opened file descriptors. + * Valid number: + * 1 - CMD/EVT/ACL-In/ACL-Out via the same fd (e.g. UART) + * 2 - CMD/EVT on one fd, and ACL-In/ACL-Out on the other fd + * 4 - CMD, EVT, ACL-In, ACL-Out are on their individual fd * [callback] * None. */ @@ -169,6 +178,18 @@ typedef enum { BT_VND_PWR_ON, } bt_vendor_power_state_t; +/** Define HCI channel identifier in the file descriptors array + used in BT_VND_OP_USERIAL_OPEN operation. + */ +typedef enum { + CH_CMD, // HCI Command channel + CH_EVT, // HCI Event channel + CH_ACL_OUT, // HCI ACL downstream channel + CH_ACL_IN, // HCI ACL upstream channel + + CH_MAX // Total channels +} bt_vendor_hci_channels_t; + /** LPM disable/enable request */ typedef enum { BT_VND_LPM_DISABLE, diff --git a/hci/include/hci.h b/hci/include/hci.h new file mode 100644 index 0000000..2682536 --- /dev/null +++ b/hci/include/hci.h @@ -0,0 +1,115 @@ +/****************************************************************************** + * + * 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.h + * + * Description: Contains definitions used for HCI transport controls + * + ******************************************************************************/ + +#ifndef HCI_H +#define HCI_H + +/****************************************************************************** +** Constants & Macros +******************************************************************************/ + +/****************************************************************************** +** Type definitions +******************************************************************************/ + +/** Prototypes for HCI Service interface functions **/ + +/* Initialize transport's control block */ +typedef void (*tHCI_INIT)(void); + +/* Do transport's control block clean-up */ +typedef void (*tHCI_CLEANUP)(void); + +/* Send HCI command/data to the transport */ +typedef void (*tHCI_SEND)(HC_BT_HDR *p_msg); + +/* Handler for HCI upstream path */ +typedef uint16_t (*tHCI_RCV)(void); + +/* Callback function for the returned event of internally issued command */ +typedef void (*tINT_CMD_CBACK)(void *p_mem); + +/* Handler for sending HCI command from the local module */ +typedef uint8_t (*tHCI_SEND_INT)(uint16_t opcode, HC_BT_HDR *p_buf, \ + tINT_CMD_CBACK p_cback); + +/* Handler for getting acl data length */ +typedef void (*tHCI_ACL_DATA_LEN_HDLR)(void); + +/****************************************************************************** +** Extern variables and functions +******************************************************************************/ + +typedef struct { + tHCI_INIT init; + tHCI_CLEANUP cleanup; + tHCI_SEND send; + tHCI_SEND_INT send_int_cmd; + tHCI_ACL_DATA_LEN_HDLR get_acl_max_len; +#ifdef HCI_USE_MCT + tHCI_RCV evt_rcv; + tHCI_RCV acl_rcv; +#else + tHCI_RCV rcv; +#endif +} tHCI_IF; + +/****************************************************************************** +** Functions +******************************************************************************/ + + +#endif /* HCI_H */ + diff --git a/hci/include/userial.h b/hci/include/userial.h index 92458e5..57da4e0 100644 --- a/hci/include/userial.h +++ b/hci/include/userial.h @@ -130,7 +130,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); /******************************************************************************* ** @@ -142,7 +142,7 @@ 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); /******************************************************************************* ** 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 #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 #include #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 +#include +#include +#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 +#include +#include +#include +#include +#include +#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, ¶m)==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,¶m); + 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; + } +} + -- cgit v1.1 From f4e632025a1d0ee7e5f643e2551a3a3a6393280e Mon Sep 17 00:00:00 2001 From: Matthew Xie Date: Mon, 10 Sep 2012 14:00:44 -0700 Subject: Turn off messages that has lower priority than warning. Change-Id: Ib1f39b66b3422164f64fcbbf271636244b6cb1a3 --- conf/bt_stack.conf | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/conf/bt_stack.conf b/conf/bt_stack.conf index 90becc3..a956c14 100644 --- a/conf/bt_stack.conf +++ b/conf/bt_stack.conf @@ -16,18 +16,18 @@ TraceConf=true # BT_TRACE_LEVEL_API 3 ( API traces ) # BT_TRACE_LEVEL_EVENT 4 ( Debug messages for events ) # BT_TRACE_LEVEL_DEBUG 5 ( Full debug messages ) -TRC_BTM=5 -TRC_HCI=5 +TRC_BTM=2 +TRC_HCI=2 TRC_L2CAP=2 -TRC_RFCOMM=3 -TRC_OBEX=3 -TRC_AVCT=3 -TRC_AVDT=3 -TRC_AVRC=3 +TRC_RFCOMM=2 +TRC_OBEX=2 +TRC_AVCT=2 +TRC_AVDT=2 +TRC_AVRC=2 TRC_AVDT_SCB=2 TRC_AVDT_CCB=2 -TRC_A2D=3 -TRC_SDP=5 -TRC_GATT=5 -TRC_SMP=5 -TRC_BTAPP=4 +TRC_A2D=2 +TRC_SDP=2 +TRC_GATT=2 +TRC_SMP=2 +TRC_BTAPP=2 -- cgit v1.1 From 647973129aa9ca6aea62cc047033aa98dce0c600 Mon Sep 17 00:00:00 2001 From: Iliyan Malchev Date: Mon, 10 Sep 2012 15:50:23 -0700 Subject: bluedroid: clean up a2dp log spew Change-Id: I6f9459197724cbb2824f4160f7f366bfe7631556 Signed-off-by: Iliyan Malchev --- audio_a2dp_hw/audio_a2dp_hw.c | 74 ++++++++++++++++++++++--------------------- 1 file changed, 38 insertions(+), 36 deletions(-) diff --git a/audio_a2dp_hw/audio_a2dp_hw.c b/audio_a2dp_hw/audio_a2dp_hw.c index 345930b..36783a9 100644 --- a/audio_a2dp_hw/audio_a2dp_hw.c +++ b/audio_a2dp_hw/audio_a2dp_hw.c @@ -87,9 +87,11 @@ #define CASE_RETURN_STR(const) case const: return #const; #define FNLOG() ALOGV("%s", __FUNCTION__); -#define DEBUG(fmt, ...) ALOGD ("%s: " fmt,__FUNCTION__, ## __VA_ARGS__) +#define DEBUG(fmt, ...) ALOGV("%s: " fmt,__FUNCTION__, ## __VA_ARGS__) +#define INFO(fmt, ...) ALOGI("%s: " fmt,__FUNCTION__, ## __VA_ARGS__) +#define ERROR(fmt, ...) ALOGE("%s: " fmt,__FUNCTION__, ## __VA_ARGS__) -#define ASSERTC(cond, msg, val) if (!(cond)) {ALOGE("### ASSERT : %s line %d %s (%d) ###", __FILE__, __LINE__, msg, val);} +#define ASSERTC(cond, msg, val) if (!(cond)) {ERROR("### ASSERT : %s line %d %s (%d) ###", __FILE__, __LINE__, msg, val);} /***************************************************************************** ** Local type definitions @@ -219,14 +221,14 @@ static int skt_connect(struct a2dp_stream_out *out, char *path) struct sockaddr_un remote; int len; - DEBUG("connect to %s (sz %d)", path, out->buffer_sz); + INFO("connect to %s (sz %d)", path, out->buffer_sz); skt_fd = socket(AF_LOCAL, SOCK_STREAM, 0); if(socket_local_client_connect(skt_fd, path, ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM) < 0) { - ALOGE("failed to connect (%s)", strerror(errno)); + ERROR("failed to connect (%s)", strerror(errno)); close(skt_fd); return -1; } @@ -236,9 +238,9 @@ static int skt_connect(struct a2dp_stream_out *out, char *path) /* only issue warning if failed */ if (ret < 0) - ALOGE("setsockopt failed (%s)", strerror(errno)); + ERROR("setsockopt failed (%s)", strerror(errno)); - DEBUG("connected to stack fd = %d", skt_fd); + INFO("connected to stack fd = %d", skt_fd); return skt_fd; } @@ -263,7 +265,7 @@ static int skt_write(int fd, const void *p, size_t len) if ((sent = send(fd, p, len, MSG_NOSIGNAL)) == -1) { - ALOGE("write failed with errno=%d\n", errno); + ERROR("write failed with errno=%d\n", errno); return -1; } @@ -272,7 +274,7 @@ static int skt_write(int fd, const void *p, size_t len) static int skt_disconnect(int fd) { - DEBUG("fd %d", fd); + INFO("fd %d", fd); if (fd != AUDIO_SKT_DISCONNECTED) { @@ -299,7 +301,7 @@ static int a2dp_command(struct a2dp_stream_out *out, char cmd) /* send command */ if (send(out->ctrl_fd, &cmd, 1, MSG_NOSIGNAL) == -1) { - DEBUG("cmd failed (%s)", strerror(errno)); + ERROR("cmd failed (%s)", strerror(errno)); skt_disconnect(out->ctrl_fd); out->ctrl_fd = AUDIO_SKT_DISCONNECTED; return -1; @@ -308,7 +310,7 @@ static int a2dp_command(struct a2dp_stream_out *out, char cmd) /* wait for ack byte */ if (recv(out->ctrl_fd, &ack, 1, MSG_NOSIGNAL) < 0) { - DEBUG("ack failed (%s)", strerror(errno)); + ERROR("ack failed (%s)", strerror(errno)); skt_disconnect(out->ctrl_fd); out->ctrl_fd = AUDIO_SKT_DISCONNECTED; return -1; @@ -354,7 +356,7 @@ static int start_audio_datapath(struct a2dp_stream_out *out) { int oldstate = out->state; - DEBUG("state %d", out->state); + INFO("state %d", out->state); if (out->ctrl_fd == AUDIO_SKT_DISCONNECTED) return -1; @@ -363,7 +365,7 @@ static int start_audio_datapath(struct a2dp_stream_out *out) if (a2dp_command(out, A2DP_CTRL_CMD_START) < 0) { - DEBUG("audiopath start failed"); + ERROR("audiopath start failed"); out->state = oldstate; return -1; @@ -391,7 +393,7 @@ static int stop_audio_datapath(struct a2dp_stream_out *out) { int oldstate = out->state; - DEBUG("state %d", out->state); + INFO("state %d", out->state); if (out->ctrl_fd == AUDIO_SKT_DISCONNECTED) return -1; @@ -402,7 +404,7 @@ static int stop_audio_datapath(struct a2dp_stream_out *out) if (a2dp_command(out, A2DP_CTRL_CMD_STOP) < 0) { - DEBUG("audiopath stop failed"); + ERROR("audiopath stop failed"); out->state = oldstate; return -1; } @@ -418,7 +420,7 @@ static int stop_audio_datapath(struct a2dp_stream_out *out) static int suspend_audio_datapath(struct a2dp_stream_out *out, bool standby) { - DEBUG("state %d", out->state); + INFO("state %d", out->state); if (out->ctrl_fd == AUDIO_SKT_DISCONNECTED) return -1; @@ -444,11 +446,11 @@ static int suspend_audio_datapath(struct a2dp_stream_out *out, bool standby) static int check_a2dp_ready(struct a2dp_stream_out *out) { - DEBUG("state %d", out->state); + INFO("state %d", out->state); if (a2dp_command(out, A2DP_CTRL_CMD_CHECK_READY) < 0) { - ALOGE("check a2dp ready failed"); + ERROR("check a2dp ready failed"); return -1; } return 0; @@ -467,7 +469,7 @@ static ssize_t out_write(struct audio_stream_out *stream, const void* buffer, struct a2dp_stream_out *out = (struct a2dp_stream_out *)stream; int sent; - ALOGV("write %d bytes (fd %d)", bytes, out->audio_fd); + DEBUG("write %d bytes (fd %d)", bytes, out->audio_fd); if (out->state == AUDIO_A2DP_STATE_SUSPENDED) { @@ -499,7 +501,7 @@ static ssize_t out_write(struct audio_stream_out *stream, const void* buffer, } else if (out->state != AUDIO_A2DP_STATE_STARTED) { - ALOGE("stream not in stopped or standby"); + ERROR("stream not in stopped or standby"); return -1; } @@ -512,7 +514,7 @@ static ssize_t out_write(struct audio_stream_out *stream, const void* buffer, out->state = AUDIO_A2DP_STATE_STOPPED; } - ALOGV("wrote %d bytes out of %d bytes", sent, bytes); + DEBUG("wrote %d bytes out of %d bytes", sent, bytes); return sent; } @@ -521,7 +523,7 @@ static uint32_t out_get_sample_rate(const struct audio_stream *stream) { struct a2dp_stream_out *out = (struct a2dp_stream_out *)stream; - DEBUG("rate %d", out->cfg.rate); + INFO("rate %d", out->cfg.rate); return out->cfg.rate; } @@ -530,11 +532,11 @@ static int out_set_sample_rate(struct audio_stream *stream, uint32_t rate) { struct a2dp_stream_out *out = (struct a2dp_stream_out *)stream; - DEBUG("out_set_sample_rate : %d", rate); + INFO("out_set_sample_rate : %d", rate); if (rate != AUDIO_STREAM_DEFAULT_RATE) { - ALOGE("only rate %d supported", AUDIO_STREAM_DEFAULT_RATE); + ERROR("only rate %d supported", AUDIO_STREAM_DEFAULT_RATE); return -1; } @@ -547,7 +549,7 @@ static size_t out_get_buffer_size(const struct audio_stream *stream) { struct a2dp_stream_out *out = (struct a2dp_stream_out *)stream; - DEBUG("buffer_size : %d", out->buffer_sz); + INFO("buffer_size : %d", out->buffer_sz); return out->buffer_sz; } @@ -556,7 +558,7 @@ static uint32_t out_get_channels(const struct audio_stream *stream) { struct a2dp_stream_out *out = (struct a2dp_stream_out *)stream; - DEBUG("channels 0x%x", out->cfg.channel_flags); + INFO("channels 0x%x", out->cfg.channel_flags); return out->cfg.channel_flags; } @@ -564,14 +566,14 @@ static uint32_t out_get_channels(const struct audio_stream *stream) static audio_format_t out_get_format(const struct audio_stream *stream) { struct a2dp_stream_out *out = (struct a2dp_stream_out *)stream; - DEBUG("format 0x%x", out->cfg.format); + INFO("format 0x%x", out->cfg.format); return out->cfg.format; } static int out_set_format(struct audio_stream *stream, audio_format_t format) { struct a2dp_stream_out *out = (struct a2dp_stream_out *)stream; - DEBUG("setting format not yet supported (0x%x)", format); + ALOGW("setting format not yet supported (0x%x)", format); return -ENOSYS; } @@ -609,7 +611,7 @@ static int out_set_parameters(struct audio_stream *stream, const char *kvpairs) char keyval[16]; int retval = 0; - DEBUG("state %d", out->state); + INFO("state %d", out->state); pthread_mutex_lock(&out->lock); @@ -824,7 +826,7 @@ static int adev_open_output_stream(struct audio_hw_device *dev, int ret = 0; int i; - DEBUG("opening output"); + INFO("opening output"); out = (struct a2dp_stream_out *)calloc(1, sizeof(struct a2dp_stream_out)); @@ -871,7 +873,7 @@ static int adev_open_output_stream(struct audio_hw_device *dev, if (check_a2dp_ready(out) == 0) break; - ALOGE("error : a2dp not ready, wait 250 ms and retry"); + ERROR("error : a2dp not ready, wait 250 ms and retry"); usleep(250000); skt_disconnect(out->ctrl_fd); } @@ -882,7 +884,7 @@ static int adev_open_output_stream(struct audio_hw_device *dev, if (out->ctrl_fd == AUDIO_SKT_DISCONNECTED) { - ALOGE("ctrl socket failed to connect (%s)", strerror(errno)); + ERROR("ctrl socket failed to connect (%s)", strerror(errno)); ret = -1; goto err_open; } @@ -893,7 +895,7 @@ static int adev_open_output_stream(struct audio_hw_device *dev, err_open: free(out); *stream_out = NULL; - ALOGE("failed"); + ERROR("failed"); return ret; } @@ -903,7 +905,7 @@ static void adev_close_output_stream(struct audio_hw_device *dev, struct a2dp_audio_device *a2dp_dev = (struct a2dp_audio_device *)dev; struct a2dp_stream_out *out = (struct a2dp_stream_out *)stream; - DEBUG("closing output (state %d)", out->state); + INFO("closing output (state %d)", out->state); if ((out->state == AUDIO_A2DP_STATE_STARTED) || (out->state == AUDIO_A2DP_STATE_STOPPING)) stop_audio_datapath(out); @@ -924,7 +926,7 @@ static int adev_set_parameters(struct audio_hw_device *dev, const char *kvpairs) if (out == NULL) return retval; - DEBUG("state %d", out->state); + INFO("state %d", out->state); retval = out->stream.common.set_parameters((struct audio_stream *)out, kvpairs); @@ -1070,12 +1072,12 @@ static int adev_open(const hw_module_t* module, const char* name, struct a2dp_audio_device *adev; int ret; - DEBUG (" adev_open in A2dp_hw module"); + INFO(" adev_open in A2dp_hw module"); FNLOG(); if (strcmp(name, AUDIO_HARDWARE_INTERFACE) != 0) { - ALOGE("interface %s not matching [%s]", name, AUDIO_HARDWARE_INTERFACE); + ERROR("interface %s not matching [%s]", name, AUDIO_HARDWARE_INTERFACE); return -EINVAL; } -- cgit v1.1 From ea634cea46f9dc34eed1fc4c7c95cf46dd70f375 Mon Sep 17 00:00:00 2001 From: zzy Date: Thu, 20 Sep 2012 21:19:10 -0700 Subject: bluedroid: add mutex lock when enumerating the hci tx queue Bug: 7167816 Bug: 7136940 This could be fix for most of the hci timeout issues. The root cause seemed like the while loop for sending hci message messed up when another thread try to enque/deque a hci message at same time. Change-Id: Ib7f6a68b49b700b0d575326cafae41a158483b27 Signed-off-by: Iliyan Malchev --- hci/include/utils.h | 23 +++++++++++++++++++++++ hci/src/bt_hci_bdroid.c | 16 +++++++++++----- hci/src/utils.c | 46 ++++++++++++++++++++++++++++++++++------------ 3 files changed, 68 insertions(+), 17 deletions(-) diff --git a/hci/include/utils.h b/hci/include/utils.h index be4406b..0f1517c 100644 --- a/hci/include/utils.h +++ b/hci/include/utils.h @@ -111,6 +111,17 @@ void *utils_dequeue (BUFFER_Q *p_q); /******************************************************************************* ** +** Function utils_dequeue_unlocked +** +** Description Dequeues a buffer from the head of the given queue without lock +** +** Returns NULL if queue is empty, else buffer +** +*******************************************************************************/ +void *utils_dequeue_unlocked (BUFFER_Q *p_q); + +/******************************************************************************* +** ** Function utils_getnext ** ** Description Return a pointer to the next buffer linked to the given buffer @@ -134,6 +145,18 @@ void *utils_remove_from_queue (BUFFER_Q *p_q, void *p_buf); /******************************************************************************* ** +** Function utils_remove_from_queue_unlocked +** +** Description Dequeue the given buffer from the middle of the given queue without lock +** +** Returns NULL if the given queue is empty, else the given buffer +** +*******************************************************************************/ +void *utils_remove_from_queue_unlocked (BUFFER_Q *p_q, void *p_buf); + + +/******************************************************************************* +** ** Function utils_delay ** ** Description sleep unconditionally for timeout milliseconds diff --git a/hci/src/bt_hci_bdroid.c b/hci/src/bt_hci_bdroid.c index e8a8411..27d190e 100644 --- a/hci/src/bt_hci_bdroid.c +++ b/hci/src/bt_hci_bdroid.c @@ -410,9 +410,12 @@ static void *bt_hc_worker_thread(void *arg) * Fine to clear tx_cmd_pkts_pending. */ tx_cmd_pkts_pending = FALSE; - + HC_BT_HDR * sending_msg_que[64]; + int sending_msg_count = 0; + utils_lock(); p_next_msg = tx_q.p_first; - while (p_next_msg) + while (p_next_msg && sending_msg_count < + (int)sizeof(sending_msg_que)/sizeof(sending_msg_que[0])) { if ((p_next_msg->event & MSG_EVT_MASK)==MSG_STACK_TO_HC_HCI_CMD) { @@ -434,10 +437,13 @@ 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); - p_hci_if->send(p_msg); + utils_remove_from_queue_unlocked(&tx_q, p_msg); + sending_msg_que[sending_msg_count++] = p_msg; } - + utils_unlock(); + int i; + for(i = 0; i < sending_msg_count; i++) + p_hci_if->send(sending_msg_que[i]); if (tx_cmd_pkts_pending == TRUE) BTHCDBG("Used up Tx Cmd credits"); diff --git a/hci/src/utils.c b/hci/src/utils.c index 318c985..bfcf724 100644 --- a/hci/src/utils.c +++ b/hci/src/utils.c @@ -116,7 +116,6 @@ void utils_enqueue (BUFFER_Q *p_q, void *p_buf) pthread_mutex_unlock(&utils_mutex); } - /******************************************************************************* ** ** Function utils_dequeue @@ -128,13 +127,28 @@ void utils_enqueue (BUFFER_Q *p_q, void *p_buf) *******************************************************************************/ void *utils_dequeue (BUFFER_Q *p_q) { + pthread_mutex_lock(&utils_mutex); + void* p_buf = utils_dequeue_unlocked(p_q); + pthread_mutex_unlock(&utils_mutex); + return p_buf; +} + +/******************************************************************************* +** +** Function utils_dequeue_unlocked +** +** Description Dequeues a buffer from the head of the given queue without lock +** +** Returns NULL if queue is empty, else buffer +** +*******************************************************************************/ +void *utils_dequeue_unlocked (BUFFER_Q *p_q) +{ HC_BUFFER_HDR_T *p_hdr; - pthread_mutex_lock(&utils_mutex); if (!p_q || !p_q->count) { - pthread_mutex_unlock(&utils_mutex); return (NULL); } @@ -151,9 +165,6 @@ void *utils_dequeue (BUFFER_Q *p_q) p_q->count--; p_hdr->p_next = NULL; - - pthread_mutex_unlock(&utils_mutex); - return ((uint8_t *)p_hdr + BT_HC_BUFFER_HDR_SIZE); } @@ -191,15 +202,29 @@ void *utils_getnext (void *p_buf) *******************************************************************************/ void *utils_remove_from_queue (BUFFER_Q *p_q, void *p_buf) { + pthread_mutex_lock(&utils_mutex); + p_buf = utils_remove_from_queue_unlocked(p_q, p_buf); + pthread_mutex_unlock(&utils_mutex); + return p_buf; +} +/******************************************************************************* +** +** Function utils_remove_from_queue_unlocked +** +** Description Dequeue the given buffer from the middle of the given queue +** +** Returns NULL if the given queue is empty, else the given buffer +** +*******************************************************************************/ +void *utils_remove_from_queue_unlocked (BUFFER_Q *p_q, void *p_buf) +{ HC_BUFFER_HDR_T *p_prev; HC_BUFFER_HDR_T *p_buf_hdr; - pthread_mutex_lock(&utils_mutex); if (p_buf == p_q->p_first) { - pthread_mutex_unlock(&utils_mutex); - return (utils_dequeue (p_q)); + return (utils_dequeue_unlocked (p_q)); } p_buf_hdr = (HC_BUFFER_HDR_T *)((uint8_t *)p_buf - BT_HC_BUFFER_HDR_SIZE); @@ -222,12 +247,9 @@ void *utils_remove_from_queue (BUFFER_Q *p_q, void *p_buf) /* The buffer is now unlinked */ p_buf_hdr->p_next = NULL; - pthread_mutex_unlock(&utils_mutex); return (p_buf); } } - - pthread_mutex_unlock(&utils_mutex); return (NULL); } -- cgit v1.1