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