summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorZach Johnson <zachoverflow@google.com>2014-08-15 17:00:17 -0700
committerAndre Eisenbach <eisenbach@google.com>2015-03-16 16:51:29 -0700
commitfbbd42b1fc1aae7a106f46275ab1fd86452cce78 (patch)
treef007ac5ff92281416aea266b30a88262182781e0
parentd18cfd09c96740f57c5645b18d9582aa8afffced (diff)
downloadandroid_system_bt-fbbd42b1fc1aae7a106f46275ab1fd86452cce78.tar.gz
android_system_bt-fbbd42b1fc1aae7a106f46275ab1fd86452cce78.tar.bz2
android_system_bt-fbbd42b1fc1aae7a106f46275ab1fd86452cce78.zip
Refactor HCI layer
Refactor the HCI layer for better testability. A future CL will add a HAL implementation for multi channel transport. Since btsnoop and vendor are modified, it's not easy to incrementally introduce these changes.
-rw-r--r--hci/Android.mk66
-rw-r--r--hci/include/btsnoop.h36
-rw-r--r--hci/include/hci.h86
-rw-r--r--hci/include/hci_hal.h84
-rw-r--r--hci/include/hci_inject.h19
-rw-r--r--hci/include/hci_internals.h31
-rw-r--r--hci/include/hci_layer.h120
-rw-r--r--hci/include/low_power_manager.h47
-rw-r--r--hci/include/packet_fragmenter.h57
-rw-r--r--hci/include/utils.h194
-rw-r--r--hci/include/vendor.h51
-rw-r--r--hci/src/bt_hci_bdroid.c506
-rw-r--r--hci/src/btsnoop.c42
-rw-r--r--hci/src/hci_h4.c1062
-rw-r--r--hci/src/hci_hal_h4.c224
-rw-r--r--hci/src/hci_inject.c29
-rw-r--r--hci/src/hci_layer.c677
-rw-r--r--hci/src/low_power_manager.c242
-rw-r--r--hci/src/lpm.c362
-rw-r--r--hci/src/packet_fragmenter.c232
-rw-r--r--hci/src/userial.c418
-rw-r--r--hci/src/utils.c309
-rw-r--r--hci/src/vendor.c148
-rw-r--r--hci/test/hci_hal_h4_test.cpp259
-rw-r--r--hci/test/hci_layer_test.cpp584
-rw-r--r--hci/test/low_power_manager_test.cpp140
-rw-r--r--hci/test/packet_fragmenter_test.cpp367
-rwxr-xr-xmain/bte_main.c275
28 files changed, 3413 insertions, 3254 deletions
diff --git a/hci/Android.mk b/hci/Android.mk
index 8a5c3adf5..56f89f40e 100644
--- a/hci/Android.mk
+++ b/hci/Android.mk
@@ -5,13 +5,13 @@ include $(CLEAR_VARS)
LOCAL_CFLAGS += $(bdroid_CFLAGS)
LOCAL_SRC_FILES := \
- src/bt_hci_bdroid.c \
- src/btsnoop.c \
- src/btsnoop_net.c \
- src/hci_inject.c \
- src/lpm.c \
- src/utils.c \
- src/vendor.c
+ src/btsnoop.c \
+ src/btsnoop_net.c \
+ src/hci_inject.c \
+ src/hci_layer.c \
+ src/low_power_manager.c \
+ src/packet_fragmenter.c \
+ src/vendor.c
LOCAL_CFLAGS := -Wno-unused-parameter
@@ -20,27 +20,59 @@ ifeq ($(BLUETOOTH_HCI_USE_MCT),true)
LOCAL_CFLAGS += -DHCI_USE_MCT
LOCAL_SRC_FILES += \
- src/hci_mct.c \
- src/userial_mct.c
+ src/hci_mct.c \
+ src/userial_mct.c
else
LOCAL_SRC_FILES += \
- src/hci_h4.c \
- src/userial.c
+ src/hci_hal_h4.c
+
endif
LOCAL_CFLAGS += -std=c99
LOCAL_C_INCLUDES += \
- $(LOCAL_PATH)/include \
- $(LOCAL_PATH)/../osi/include \
- $(LOCAL_PATH)/../utils/include \
- $(LOCAL_PATH)/../stack/include \
- $(LOCAL_PATH)/../gki/ulinux \
- $(bdroid_C_INCLUDES)
+ $(LOCAL_PATH)/include \
+ $(LOCAL_PATH)/../include \
+ $(LOCAL_PATH)/../gki/common \
+ $(LOCAL_PATH)/../gki/ulinux \
+ $(LOCAL_PATH)/../osi/include \
+ $(LOCAL_PATH)/../stack/include \
+ $(LOCAL_PATH)/../utils/include \
+ $(bdroid_C_INCLUDES)
LOCAL_MODULE := libbt-hci
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE_CLASS := STATIC_LIBRARIES
include $(BUILD_STATIC_LIBRARY)
+
+#####################################################
+
+include $(CLEAR_VARS)
+
+LOCAL_C_INCLUDES := \
+ $(LOCAL_PATH)/include \
+ $(LOCAL_PATH)/../include \
+ $(LOCAL_PATH)/../gki/common \
+ $(LOCAL_PATH)/../gki/ulinux \
+ $(LOCAL_PATH)/../osi/include \
+ $(LOCAL_PATH)/../osi/test \
+ $(LOCAL_PATH)/../stack/include \
+ $(LOCAL_PATH)/../utils/include \
+ $(bdroid_C_INCLUDES)
+
+LOCAL_SRC_FILES := \
+ ../osi/test/AlarmTestHarness.cpp \
+ ./test/hci_hal_h4_test.cpp \
+ ./test/hci_layer_test.cpp \
+ ./test/low_power_manager_test.cpp \
+ ./test/packet_fragmenter_test.cpp
+
+LOCAL_CFLAGS := -Wall -Werror
+LOCAL_MODULE := libbt-hcitests
+LOCAL_MODULE_TAGS := tests
+LOCAL_SHARED_LIBRARIES := liblog libdl
+LOCAL_STATIC_LIBRARIES := libbt-hci libosi
+
+include $(BUILD_NATIVE_TEST)
diff --git a/hci/include/btsnoop.h b/hci/include/btsnoop.h
index 83c810711..614bbf017 100644
--- a/hci/include/btsnoop.h
+++ b/hci/include/btsnoop.h
@@ -1,10 +1,38 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
#pragma once
#include <stdbool.h>
-#include "bt_hci_bdroid.h"
+#include "bt_types.h"
+
+typedef struct btsnoop_interface_t {
+ // Open btsnoop, and dump captured packets to the file pointed to by |path|.
+ void (*open)(const char *path);
+
+ // Close btsnoop, so no more packets are captured.
+ void (*close)(void);
-void btsnoop_open(const char *p_path, const bool save_existing);
-void btsnoop_close(void);
+ // Capture |packet| and dump it to the btsnoop logs. If |is_received| is
+ // true, the packet is marked as incoming. Otherwise, the packet is marked
+ // as outgoing.
+ void (*capture)(const BT_HDR *packet, bool is_received);
+} btsnoop_interface_t;
-void btsnoop_capture(const HC_BT_HDR *p_buf, bool is_rcvd);
+const btsnoop_interface_t *btsnoop_get_interface();
diff --git a/hci/include/hci.h b/hci/include/hci.h
deleted file mode 100644
index 0bfec2b68..000000000
--- a/hci/include/hci.h
+++ /dev/null
@@ -1,86 +0,0 @@
-/******************************************************************************
- *
- * Copyright (C) 2009-2012 Broadcom Corporation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- ******************************************************************************/
-
-/******************************************************************************
- *
- * 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/hci_hal.h b/hci/include/hci_hal.h
new file mode 100644
index 000000000..3fa9a89b2
--- /dev/null
+++ b/hci/include/hci_hal.h
@@ -0,0 +1,84 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#pragma once
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include "thread.h"
+#include "vendor.h"
+
+typedef enum {
+ DATA_TYPE_COMMAND = 1,
+ DATA_TYPE_ACL = 2,
+ DATA_TYPE_SCO = 3,
+ DATA_TYPE_EVENT = 4
+} serial_data_type_t;
+
+typedef void (*data_ready_cb)(serial_data_type_t type);
+
+typedef struct {
+ // Called when the HAL detects inbound data.
+ // Data |type| may be ACL, SCO, or EVENT.
+ // Executes in the context of the thread supplied to |init|.
+ data_ready_cb data_ready;
+
+ /*
+ // Called when the HAL detects inbound astronauts named Dave.
+ // HAL will deny all requests to open the pod bay doors after this.
+ dave_ready_cb dave_ready;
+ */
+} hci_hal_callbacks_t;
+
+typedef struct hci_hal_interface_t {
+ // Initialize the HAL, with |upper_callbacks| and |upper_thread| to run in the context of.
+ bool (*init)(const hci_hal_callbacks_t *upper_callbacks, thread_t *upper_thread);
+
+ // Connect to the underlying hardware, and let data start flowing.
+ bool (*open)(void);
+ // Disconnect from the underlying hardware, and close the HAL.
+ // "Daisy, Daisy..."
+ void (*close)(void);
+
+ // Retrieve bytes for ACL, SCO, or EVENT data packets.
+ // Only guaranteed to be correct in the context of a data_ready callback
+ // of the corresponding type.
+ uint8_t (*read_byte)(serial_data_type_t type);
+ // Returns true if there is a byte available of the specified |type|.
+ bool (*has_byte)(serial_data_type_t type);
+ // The upper layer must call this to notify the HAL that it has finished
+ // reading a packet of the specified |type|. Underlying implementations that
+ // use shared channels for multiple data types depend on this to know when
+ // to reinterpret the data stream.
+ void (*packet_finished)(serial_data_type_t type);
+ // Transmit COMMAND, ACL, or SCO data packets.
+ // |data| may not be NULL. |length| must be greater than zero.
+ //
+ // IMPORTANT NOTE:
+ // Depending on the underlying implementation, the byte right
+ // before the beginning of |data| may be borrowed during this call
+ // and then restored to its original value.
+ // This is safe in the bluetooth context, because there is always a buffer
+ // header that prefixes data you're sending.
+ uint16_t (*transmit_data)(serial_data_type_t type, uint8_t *data, uint16_t length);
+} hci_hal_interface_t;
+
+const hci_hal_interface_t *hci_hal_get_interface();
+const hci_hal_interface_t *hci_hal_get_test_interface(vendor_interface_t *vendor_interface);
+
diff --git a/hci/include/hci_inject.h b/hci/include/hci_inject.h
index daef04b1a..1e9bca885 100644
--- a/hci/include/hci_inject.h
+++ b/hci/include/hci_inject.h
@@ -20,9 +20,18 @@
#include <stdbool.h>
-// Starts the HCI injection module. Returns true on success, false on
-// failure. Once started, this module must be shut down with |hci_inject_close|.
-bool hci_inject_open(void);
+#include "allocator.h"
-// Shuts down the HCI injection module.
-void hci_inject_close(void);
+typedef struct hci_interface_t hci_interface_t;
+
+typedef struct hci_inject_interface_t {
+ // Starts the HCI injection module, using the provided |buffer_allocator|.
+ // Returns true on success, false on failure. Once started, this module
+ // must be shut down with |hci_inject_close|.
+ bool (*open)(const hci_interface_t *hci_interface, const allocator_t *buffer_allocator);
+
+ // Shuts down the HCI injection module.
+ void (*close)(void);
+} hci_inject_interface_t;
+
+const hci_inject_interface_t *hci_inject_get_interface();
diff --git a/hci/include/hci_internals.h b/hci/include/hci_internals.h
new file mode 100644
index 000000000..70dacff46
--- /dev/null
+++ b/hci/include/hci_internals.h
@@ -0,0 +1,31 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#pragma once
+
+// 2 bytes for opcode, 1 byte for parameter length (Volume 2, Part E, 5.4.1)
+#define HCI_COMMAND_PREAMBLE_SIZE 3
+// 2 bytes for handle, 2 bytes for data length (Volume 2, Part E, 5.4.2)
+#define HCI_ACL_PREAMBLE_SIZE 4
+// 2 bytes for handle, 1 byte for data length (Volume 2, Part E, 5.4.3)
+#define HCI_SCO_PREAMBLE_SIZE 3
+// 1 byte for event code, 1 byte for parameter length (Volume 2, Part E, 5.4.4)
+#define HCI_EVENT_PREAMBLE_SIZE 2
+
+typedef void (*internal_command_cb)(void *response);
+
diff --git a/hci/include/hci_layer.h b/hci/include/hci_layer.h
new file mode 100644
index 000000000..d6f0ac0d3
--- /dev/null
+++ b/hci/include/hci_layer.h
@@ -0,0 +1,120 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#pragma once
+
+#include <stdbool.h>
+
+#include "allocator.h"
+#include "data_dispatcher.h"
+#include "osi.h"
+
+///// LEGACY DEFINITIONS /////
+
+/* Message event mask across Host/Controller lib and stack */
+#define MSG_EVT_MASK 0xFF00 /* eq. BT_EVT_MASK */
+#define MSG_SUB_EVT_MASK 0x00FF /* eq. BT_SUB_EVT_MASK */
+
+/* Message event ID passed from Host/Controller lib to stack */
+#define MSG_HC_TO_STACK_HCI_ERR 0x1300 /* eq. BT_EVT_TO_BTU_HCIT_ERR */
+#define MSG_HC_TO_STACK_HCI_ACL 0x1100 /* eq. BT_EVT_TO_BTU_HCI_ACL */
+#define MSG_HC_TO_STACK_HCI_SCO 0x1200 /* eq. BT_EVT_TO_BTU_HCI_SCO */
+#define MSG_HC_TO_STACK_HCI_EVT 0x1000 /* eq. BT_EVT_TO_BTU_HCI_EVT */
+#define MSG_HC_TO_STACK_L2C_SEG_XMIT 0x1900 /* eq. BT_EVT_TO_BTU_L2C_SEG_XMIT */
+
+/* Message event ID passed from stack to vendor lib */
+#define MSG_STACK_TO_HC_HCI_ACL 0x2100 /* eq. BT_EVT_TO_LM_HCI_ACL */
+#define MSG_STACK_TO_HC_HCI_SCO 0x2200 /* eq. BT_EVT_TO_LM_HCI_SCO */
+#define MSG_STACK_TO_HC_HCI_CMD 0x2000 /* eq. BT_EVT_TO_LM_HCI_CMD */
+
+/* Local Bluetooth Controller ID for BR/EDR */
+#define LOCAL_BR_EDR_CONTROLLER_ID 0
+
+///// END LEGACY DEFINITIONS /////
+
+typedef struct hci_hal_interface_t hci_hal_interface_t;
+typedef struct btsnoop_interface_t btsnoop_interface_t;
+typedef struct hci_inject_interface_t hci_inject_interface_t;
+typedef struct packet_fragmenter_interface_t packet_fragmenter_interface_t;
+typedef struct vendor_interface_t vendor_interface_t;
+typedef struct low_power_manager_interface_t low_power_manager_interface_t;
+
+typedef unsigned char * bdaddr_t;
+
+typedef enum {
+ LPM_DISABLE,
+ LPM_ENABLE,
+ LPM_WAKE_ASSERT,
+ LPM_WAKE_DEASSERT
+} low_power_command_t;
+
+typedef void (*preload_finished_cb)(bool success);
+typedef void (*transmit_finished_cb)(void *buffer, bool all_fragments_sent);
+
+typedef struct {
+ // Called when the HCI layer finishes the preload sequence.
+ preload_finished_cb preload_finished;
+
+ // Called when the HCI layer finishes sending a packet.
+ transmit_finished_cb transmit_finished;
+} hci_callbacks_t;
+
+typedef struct hci_interface_t {
+ // Initialize the hci layer, with the specified |local_bdaddr|.
+ bool (*init)(
+ bdaddr_t local_bdaddr,
+ const allocator_t *upward_buffer_allocator,
+ const hci_callbacks_t *upper_callbacks
+ );
+
+ // Tear down and relese all resources
+ void (*cleanup)(void);
+
+ // Turn the Bluetooth chip on or off, depending on |value|.
+ void (*set_chip_power_on)(bool value);
+
+ // Send a low power command, if supported and the low power manager is enabled.
+ void (*send_low_power_command)(low_power_command_t command);
+
+ // Do the preload sequence (call before the rest of the BT stack initializes).
+ void (*do_preload)(void);
+
+ // Do the postload sequence (call after the rest of the BT stack initializes).
+ void (*do_postload)(void);
+
+ // Turn logging on, and log to the specified |path|.
+ void (*turn_on_logging)(const char *path);
+
+ void (*turn_off_logging)(void);
+
+ // Register with this data dispatcher to receive data flowing upward out of the HCI layer
+ data_dispatcher_t *upward_dispatcher;
+
+ // Send some data downward through the HCI layer
+ void (*transmit_downward)(data_dispatcher_type_t type, void *data);
+} hci_interface_t;
+
+const hci_interface_t *hci_layer_get_interface();
+
+const hci_interface_t *hci_layer_get_test_interface(
+ const hci_hal_interface_t *hal_interface,
+ const btsnoop_interface_t *btsnoop_interface,
+ const hci_inject_interface_t *hci_inject_interface,
+ const packet_fragmenter_interface_t *packet_fragmenter_interface,
+ const vendor_interface_t *vendor_interface,
+ const low_power_manager_interface_t *low_power_manager_interface);
diff --git a/hci/include/low_power_manager.h b/hci/include/low_power_manager.h
new file mode 100644
index 000000000..e5da615f1
--- /dev/null
+++ b/hci/include/low_power_manager.h
@@ -0,0 +1,47 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#pragma once
+
+#include "hci_layer.h"
+
+typedef struct thread_t thread_t;
+typedef struct vendor_interface_t vendor_interface_t;
+
+typedef struct low_power_manager_interface_t {
+ // Initialize the low power manager, and use |post_thread| to synchronize actions.
+ void (*init)(thread_t *post_thread);
+
+ // Clean up the low power manager and release resources.
+ void (*cleanup)(void);
+
+ // Performs |command| synchronized on the thread that was provided
+ // at initialization time.
+ void (*post_command)(low_power_command_t command);
+
+ // Assert wake (for transmission). Must be called on the thread provided
+ // at initialization time.
+ void (*wake_assert)(void);
+
+ // Tell the low power manager that you're done transmitting data. Must be
+ // called on the thread provided at initialization time.
+ void (*transmit_done)(void);
+} low_power_manager_interface_t;
+
+const low_power_manager_interface_t *low_power_manager_get_interface();
+const low_power_manager_interface_t *low_power_manager_get_test_interface(const vendor_interface_t *vendor_interface);
diff --git a/hci/include/packet_fragmenter.h b/hci/include/packet_fragmenter.h
new file mode 100644
index 000000000..7d13c905b
--- /dev/null
+++ b/hci/include/packet_fragmenter.h
@@ -0,0 +1,57 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#pragma once
+
+#include "bt_types.h"
+#include "hci_layer.h"
+
+typedef void (*packet_reassembled_cb)(BT_HDR *packet);
+typedef void (*packet_fragmented_cb)(BT_HDR *packet, bool send_transmit_finished);
+
+typedef struct {
+ // Called for every packet fragment.
+ packet_fragmented_cb fragmented;
+
+ // Called for every completely reassembled packet.
+ packet_reassembled_cb reassembled;
+
+ // Called when the fragmenter finishes sending all requested fragments,
+ // but the packet has not been entirely sent.
+ transmit_finished_cb transmit_finished;
+} packet_fragmenter_callbacks_t;
+
+typedef struct packet_fragmenter_interface_t {
+ // Initialize the fragmenter, specifying the |result_callbacks|. |buffer_allocator|
+ // is used to allocate and free buffers for the reassembled packets.
+ void (*init)(const packet_fragmenter_callbacks_t *result_callbacks, const allocator_t *buffer_allocator);
+
+ // Sets the fragmentation size for normal acl data.
+ void (*set_acl_data_size)(uint16_t size);
+ // Sets the fragmentation size for bluetooth low energy acl data.
+ void (*set_ble_acl_data_size)(uint16_t size);
+
+ // Fragments |packet| if necessary and hands off everything to the fragmented callback.
+ void (*fragment_and_dispatch)(BT_HDR *packet);
+ // If |packet| is a complete packet, forwards to the reassembled callback. Otherwise
+ // holds onto it until all fragments arrive, at which point the reassembled callback is called
+ // with the reassembled data.
+ void (*reassemble_and_dispatch)(BT_HDR *packet);
+} packet_fragmenter_interface_t;
+
+const packet_fragmenter_interface_t *packet_fragmenter_get_interface();
diff --git a/hci/include/utils.h b/hci/include/utils.h
deleted file mode 100644
index 0f1517c9f..000000000
--- a/hci/include/utils.h
+++ /dev/null
@@ -1,194 +0,0 @@
-/******************************************************************************
- *
- * Copyright (C) 2009-2012 Broadcom Corporation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- ******************************************************************************/
-
-/******************************************************************************
- *
- * Filename: utils.h
- *
- * Description: Utility functions declaration
- *
- ******************************************************************************/
-
-#ifndef UTILS_H
-#define UTILS_H
-
-/******************************************************************************
-** Constants & Macros
-******************************************************************************/
-
-#define STREAM_TO_UINT16(u16, p) {u16 = ((uint16_t)(*(p)) + (((uint16_t)(*((p) + 1))) << 8)); (p) += 2;}
-#define UINT16_TO_STREAM(p, u16) {*(p)++ = (uint8_t)(u16); *(p)++ = (uint8_t)((u16) >> 8);}
-#define UINT32_TO_STREAM(p, u32) {*(p)++ = (uint8_t)(u32); *(p)++ = (uint8_t)((u32) >> 8); *(p)++ = (uint8_t)((u32) >> 16); *(p)++ = (uint8_t)((u32) >> 24);}
-
-/******************************************************************************
-** Type definitions
-******************************************************************************/
-
-typedef struct
-{
- void *p_first;
- void *p_last;
- uint16_t count;
-} BUFFER_Q;
-
-/******************************************************************************
-** Extern variables and functions
-******************************************************************************/
-
-/******************************************************************************
-** Functions
-******************************************************************************/
-
-/*******************************************************************************
-**
-** Function utils_init
-**
-** Description Utils initialization
-**
-** Returns None
-**
-*******************************************************************************/
-void utils_init ();
-
-/*******************************************************************************
-**
-** Function utils_cleanup
-**
-** Description Utils cleanup
-**
-** Returns None
-**
-*******************************************************************************/
-void utils_cleanup ();
-
-/*******************************************************************************
-**
-** Function utils_queue_init
-**
-** Description Initialize the given buffer queue
-**
-** Returns None
-**
-*******************************************************************************/
-void utils_queue_init (BUFFER_Q *p_q);
-
-/*******************************************************************************
-**
-** Function utils_enqueue
-**
-** Description Enqueue a buffer at the tail of the given queue
-**
-** Returns None
-**
-*******************************************************************************/
-void utils_enqueue (BUFFER_Q *p_q, void *p_buf);
-
-/*******************************************************************************
-**
-** Function utils_dequeue
-**
-** Description Dequeues a buffer from the head of the given queue
-**
-** Returns NULL if queue is empty, else buffer
-**
-*******************************************************************************/
-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
-**
-** Returns NULL if the given buffer does not point to any next buffer,
-** else next buffer address
-**
-*******************************************************************************/
-void *utils_getnext (void *p_buf);
-
-/*******************************************************************************
-**
-** Function utils_remove_from_queue
-**
-** 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 (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
-**
-** Returns None
-**
-*******************************************************************************/
-void utils_delay (uint32_t timeout);
-
-/*******************************************************************************
-**
-** Function utils_lock
-**
-** Description application calls this function before entering critical
-** section
-**
-** Returns None
-**
-*******************************************************************************/
-void utils_lock (void);
-
-/*******************************************************************************
-**
-** Function utils_unlock
-**
-** Description application calls this function when leaving critical
-** section
-**
-** Returns None
-**
-*******************************************************************************/
-void utils_unlock (void);
-
-#endif /* UTILS_H */
-
diff --git a/hci/include/vendor.h b/hci/include/vendor.h
index 6c13c9c25..74ea44d82 100644
--- a/hci/include/vendor.h
+++ b/hci/include/vendor.h
@@ -21,15 +21,50 @@
#include <stdbool.h>
#include <stdint.h>
+#include "allocator.h"
+#include "bt_types.h"
#include "bt_vendor_lib.h"
+#include "hci_internals.h"
-// Opens the vendor-specific library and sets the Bluetooth
-// address of the adapter to |local_bdaddr|.
-bool vendor_open(const uint8_t *local_bdaddr);
+typedef enum {
+ VENDOR_CHIP_POWER_CONTROL = BT_VND_OP_POWER_CTRL,
+ VENDOR_OPEN_USERIAL = BT_VND_OP_USERIAL_OPEN,
+ VENDOR_CLOSE_USERIAL = BT_VND_OP_USERIAL_CLOSE,
+ VENDOR_GET_LPM_IDLE_TIMEOUT = BT_VND_OP_GET_LPM_IDLE_TIMEOUT,
+ VENDOR_SET_LPM_WAKE_STATE = BT_VND_OP_LPM_WAKE_SET_STATE
+} vendor_opcode_t;
-// Closes the vendor-specific library and frees all associated resources.
-// Only |vendor_open| may be called after |vendor_close|.
-void vendor_close(void);
+typedef enum {
+ VENDOR_CONFIGURE_FIRMWARE = BT_VND_OP_FW_CFG,
+ VENDOR_CONFIGURE_SCO = BT_VND_OP_SCO_CFG,
+ VENDOR_SET_LPM_MODE = BT_VND_OP_LPM_SET_MODE,
+ VENDOR_DO_EPILOG = BT_VND_OP_EPILOG
+} vendor_async_opcode_t;
-// Sends a vendor-specific command to the library.
-int vendor_send_command(bt_vendor_opcode_t opcode, void *param);
+typedef void (*vendor_cb)(bool success);
+typedef bool (*send_internal_command_cb)(uint16_t opcode, BT_HDR *buffer, internal_command_cb callback);
+
+typedef struct vendor_interface_t{
+ // Opens the vendor-specific library and sets the Bluetooth
+ // address of the adapter to |local_bdaddr|. |allocator| is used
+ // when the vendor library requests buffers.
+ bool (*open)(const uint8_t *local_bdaddr, const allocator_t *allocator);
+
+ // Closes the vendor-specific library and frees all associated resources.
+ // Only |vendor_open| may be called after |vendor_close|.
+ void (*close)(void);
+
+ // Sends a vendor-specific command to the library.
+ int (*send_command)(vendor_opcode_t opcode, void *param);
+
+ // Sends an asynchronous vendor-specific command to the library.
+ int (*send_async_command)(vendor_async_opcode_t opcode, void *param);
+
+ // Registers a callback for an asynchronous vendor-specific command.
+ void (*set_callback)(vendor_async_opcode_t opcode, vendor_cb callback);
+
+ // Set the callback for sending internal commands;
+ void (*set_send_internal_command_callback)(send_internal_command_cb callback);
+} vendor_interface_t;
+
+const vendor_interface_t *vendor_get_interface();
diff --git a/hci/src/bt_hci_bdroid.c b/hci/src/bt_hci_bdroid.c
deleted file mode 100644
index 0f0820ad6..000000000
--- a/hci/src/bt_hci_bdroid.c
+++ /dev/null
@@ -1,506 +0,0 @@
-/******************************************************************************
- *
- * Copyright (C) 2009-2012 Broadcom Corporation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- ******************************************************************************/
-
-/******************************************************************************
- *
- * Filename: bt_hci_bdroid.c
- *
- * Description: Bluedroid Bluetooth Host/Controller interface library
- * implementation
- *
- ******************************************************************************/
-
-#define LOG_TAG "bt_hci_bdroid"
-
-#include <assert.h>
-#include <utils/Log.h>
-
-#include "alarm.h"
-#include "btsnoop.h"
-#include "bt_hci_bdroid.h"
-#include "bt_utils.h"
-#include "bt_vendor_lib.h"
-#include "hci.h"
-#include "hci_inject.h"
-#include "osi.h"
-#include "thread.h"
-#include "userial.h"
-#include "utils.h"
-#include "vendor.h"
-
-#ifndef BTHC_DBG
-#define BTHC_DBG FALSE
-#endif
-
-#if (BTHC_DBG == TRUE)
-#define BTHCDBG(param, ...) {ALOGD(param, ## __VA_ARGS__);}
-#else
-#define BTHCDBG(param, ...) {}
-#endif
-
-/* Vendor epilog process timeout period */
-static const uint32_t EPILOG_TIMEOUT_MS = 3000;
-
-/******************************************************************************
-** Externs
-******************************************************************************/
-
-extern int num_hci_cmd_pkts;
-void lpm_init(void);
-void lpm_cleanup(void);
-void lpm_enable(uint8_t turn_on);
-void lpm_wake_deassert(void);
-void lpm_allow_bt_device_sleep(void);
-void lpm_wake_assert(void);
-void init_vnd_if(unsigned char *local_bdaddr);
-
-/******************************************************************************
-** Variables
-******************************************************************************/
-
-bt_hc_callbacks_t *bt_hc_cbacks = NULL;
-tHCI_IF *p_hci_if;
-volatile bool fwcfg_acked;
-// Cleanup state indication.
-volatile bool has_cleaned_up = false;
-
-/******************************************************************************
-** Local type definitions
-******************************************************************************/
-
-/* Host/Controller lib thread control block */
-typedef struct
-{
- thread_t *worker_thread;
- pthread_mutex_t worker_thread_lock;
- alarm_t *alarm;
-} bt_hc_cb_t;
-
-/******************************************************************************
-** Static Variables
-******************************************************************************/
-
-static bt_hc_cb_t hc_cb;
-static bool tx_cmd_pkts_pending = false;
-static BUFFER_Q tx_q;
-
-/******************************************************************************
-** Functions
-******************************************************************************/
-
-static void event_preload(UNUSED_ATTR void *context) {
- userial_open(USERIAL_PORT_1);
- vendor_send_command(BT_VND_OP_FW_CFG, NULL);
-}
-
-static void event_postload(UNUSED_ATTR void *context) {
- /* Start from SCO related H/W configuration, if SCO configuration
- * is required. Then, follow with reading requests of getting
- * ACL data length for both BR/EDR and LE.
- */
- int result = vendor_send_command(BT_VND_OP_SCO_CFG, NULL);
- if (result == -1)
- p_hci_if->get_acl_max_len();
-}
-
-static void event_tx(UNUSED_ATTR void *context) {
- /*
- * We will go through every packets in the tx queue.
- * Fine to clear tx_cmd_pkts_pending.
- */
- tx_cmd_pkts_pending = false;
- HC_BT_HDR *sending_msg_que[64];
- size_t sending_msg_count = 0;
- int sending_hci_cmd_pkts_count = 0;
- utils_lock();
- HC_BT_HDR *p_next_msg = tx_q.p_first;
- while (p_next_msg && sending_msg_count < ARRAY_SIZE(sending_msg_que))
- {
- if ((p_next_msg->event & MSG_EVT_MASK)==MSG_STACK_TO_HC_HCI_CMD)
- {
- /*
- * if we have used up controller's outstanding HCI command
- * credits (normally is 1), skip all HCI command packets in
- * the queue.
- * The pending command packets will be sent once controller
- * gives back us credits through CommandCompleteEvent or
- * CommandStatusEvent.
- */
- if (tx_cmd_pkts_pending ||
- (sending_hci_cmd_pkts_count >= num_hci_cmd_pkts))
- {
- tx_cmd_pkts_pending = true;
- p_next_msg = utils_getnext(p_next_msg);
- continue;
- }
- sending_hci_cmd_pkts_count++;
- }
-
- HC_BT_HDR *p_msg = p_next_msg;
- p_next_msg = utils_getnext(p_msg);
- utils_remove_from_queue_unlocked(&tx_q, p_msg);
- sending_msg_que[sending_msg_count++] = p_msg;
- }
- utils_unlock();
- for(size_t i = 0; i < sending_msg_count; i++)
- p_hci_if->send(sending_msg_que[i]);
- if (tx_cmd_pkts_pending)
- BTHCDBG("Used up Tx Cmd credits");
-}
-
-static void event_rx(UNUSED_ATTR void *context) {
-#ifndef HCI_USE_MCT
- p_hci_if->rcv();
-
- if (tx_cmd_pkts_pending && num_hci_cmd_pkts > 0) {
- // Got HCI Cmd credits from controller. Send whatever data
- // we have in our tx queue. We can call |event_tx| directly
- // here since we're already on the worker thread.
- event_tx(NULL);
- }
-#endif
-}
-
-static void event_lpm_enable(UNUSED_ATTR void *context) {
- lpm_enable(true);
-}
-
-static void event_lpm_disable(UNUSED_ATTR void *context) {
- lpm_enable(false);
-}
-
-static void event_lpm_wake_device(UNUSED_ATTR void *context) {
- lpm_wake_assert();
-}
-
-static void event_lpm_allow_sleep(UNUSED_ATTR void *context) {
- lpm_allow_bt_device_sleep();
-}
-
-static void event_lpm_idle_timeout(UNUSED_ATTR void *context) {
- lpm_wake_deassert();
-}
-
-static void event_epilog(UNUSED_ATTR void *context) {
- vendor_send_command(BT_VND_OP_EPILOG, NULL);
-}
-
-static void event_tx_cmd(void *msg) {
- HC_BT_HDR *p_msg = (HC_BT_HDR *)msg;
-
- BTHCDBG("%s: p_msg: %p, event: 0x%x", __func__, p_msg, p_msg->event);
-
- int event = p_msg->event & MSG_EVT_MASK;
- int sub_event = p_msg->event & MSG_SUB_EVT_MASK;
- if (event == MSG_CTRL_TO_HC_CMD && sub_event == BT_HC_AUDIO_STATE) {
- vendor_send_command(BT_VND_OP_SET_AUDIO_STATE, p_msg->data);
- } else {
- ALOGW("%s (event: 0x%x, sub_event: 0x%x) not supported", __func__, event, sub_event);
- }
-
- bt_hc_cbacks->dealloc(msg);
-}
-
-void bthc_rx_ready(void) {
- pthread_mutex_lock(&hc_cb.worker_thread_lock);
-
- if (hc_cb.worker_thread)
- thread_post(hc_cb.worker_thread, event_rx, NULL);
-
- pthread_mutex_unlock(&hc_cb.worker_thread_lock);
-}
-
-void bthc_tx(HC_BT_HDR *buf) {
- pthread_mutex_lock(&hc_cb.worker_thread_lock);
-
- if (hc_cb.worker_thread) {
- if (buf)
- utils_enqueue(&tx_q, buf);
- thread_post(hc_cb.worker_thread, event_tx, NULL);
- }
-
- pthread_mutex_unlock(&hc_cb.worker_thread_lock);
-}
-
-void bthc_idle_timeout(void) {
- pthread_mutex_lock(&hc_cb.worker_thread_lock);
-
- if (hc_cb.worker_thread)
- thread_post(hc_cb.worker_thread, event_lpm_idle_timeout, NULL);
-
- pthread_mutex_unlock(&hc_cb.worker_thread_lock);
-}
-
-/*******************************************************************************
-**
-** Function epilog_wait_timeout
-**
-** Description Timeout thread of epilog watchdog timer
-**
-** Returns None
-**
-*******************************************************************************/
-static void epilog_wait_timeout(UNUSED_ATTR void *context)
-{
- ALOGI("...epilog_wait_timeout...");
-
- thread_free(hc_cb.worker_thread);
-
- pthread_mutex_lock(&hc_cb.worker_thread_lock);
- hc_cb.worker_thread = NULL;
- pthread_mutex_unlock(&hc_cb.worker_thread_lock);
-}
-
-/*******************************************************************************
-**
-** Function epilog_wait_timer
-**
-** Description Launch epilog watchdog timer
-**
-** Returns None
-**
-*******************************************************************************/
-static void epilog_wait_timer(void)
-{
- alarm_set(hc_cb.alarm, EPILOG_TIMEOUT_MS, epilog_wait_timeout, NULL);
-}
-
-/*****************************************************************************
-**
-** BLUETOOTH HOST/CONTROLLER INTERFACE LIBRARY FUNCTIONS
-**
-*****************************************************************************/
-
-static int init(const bt_hc_callbacks_t* p_cb, unsigned char *local_bdaddr)
-{
- int result;
-
- ALOGI("init");
-
- if (p_cb == NULL)
- {
- ALOGE("init failed with no user callbacks!");
- return BT_HC_STATUS_FAIL;
- }
-
- fwcfg_acked = false;
- has_cleaned_up = false;
-
- pthread_mutex_init(&hc_cb.worker_thread_lock, NULL);
- hc_cb.alarm = alarm_new();
-
- /* store reference to user callbacks */
- bt_hc_cbacks = (bt_hc_callbacks_t *) p_cb;
-
- vendor_open(local_bdaddr);
-
- utils_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();
-
- utils_queue_init(&tx_q);
-
- if (hc_cb.worker_thread)
- {
- ALOGW("init has been called repeatedly without calling cleanup ?");
- }
-
- // Set prio here and let hci worker thread inherit prio
- // remove once new thread api (thread_set_priority() ?)
- // can switch prio
- raise_priority_a2dp(TASK_HIGH_HCI_WORKER);
-
- hc_cb.worker_thread = thread_new_sized("bt_hc_worker", 1024);
- if (!hc_cb.worker_thread) {
- ALOGE("%s unable to create worker thread.", __func__);
- return BT_HC_STATUS_FAIL;
- }
-
- if (!hci_inject_open()) {
- // TODO(sharvil): gracefully propagate failures from this layer.
- }
-
- return BT_HC_STATUS_SUCCESS;
-}
-
-
-/** Chip power control */
-static void set_power(bt_hc_chip_power_state_t state)
-{
- int pwr_state;
-
- BTHCDBG("set_power %d", state);
-
- /* Calling vendor-specific part */
- pwr_state = (state == BT_HC_CHIP_PWR_ON) ? BT_VND_PWR_ON : BT_VND_PWR_OFF;
-
- vendor_send_command(BT_VND_OP_POWER_CTRL, &pwr_state);
-}
-
-
-/** Configure low power mode wake state */
-static int lpm(bt_hc_low_power_event_t event)
-{
- switch (event)
- {
- case BT_HC_LPM_DISABLE:
- thread_post(hc_cb.worker_thread, event_lpm_disable, NULL);
- break;
-
- case BT_HC_LPM_ENABLE:
- thread_post(hc_cb.worker_thread, event_lpm_enable, NULL);
- break;
-
- case BT_HC_LPM_WAKE_ASSERT:
- thread_post(hc_cb.worker_thread, event_lpm_wake_device, NULL);
- break;
-
- case BT_HC_LPM_WAKE_DEASSERT:
- thread_post(hc_cb.worker_thread, event_lpm_allow_sleep, NULL);
- break;
- }
- return BT_HC_STATUS_SUCCESS;
-}
-
-
-/** Called prior to stack initialization */
-static void preload(UNUSED_ATTR TRANSAC transac) {
- BTHCDBG("preload");
- thread_post(hc_cb.worker_thread, event_preload, NULL);
-}
-
-/** Called post stack initialization */
-static void postload(UNUSED_ATTR TRANSAC transac) {
- BTHCDBG("postload");
- thread_post(hc_cb.worker_thread, event_postload, NULL);
-}
-
-/** Transmit frame */
-static int transmit_buf(TRANSAC transac, UNUSED_ATTR char *p_buf, UNUSED_ATTR int len) {
- bthc_tx((HC_BT_HDR *)transac);
- return BT_HC_STATUS_SUCCESS;
-}
-
-/** Controls HCI logging on/off */
-static int logging(bt_hc_logging_state_t state, char *p_path, bool save_existing) {
- BTHCDBG("logging %d", state);
-
- if (state != BT_HC_LOGGING_ON)
- btsnoop_close();
- else if (p_path != NULL)
- btsnoop_open(p_path, save_existing);
-
- return BT_HC_STATUS_SUCCESS;
-}
-
-/** sends command HC controller to configure platform specific behaviour */
-static int tx_hc_cmd(TRANSAC transac, char *p_buf, int len) {
- BTHCDBG("tx_hc_cmd: transac %p", transac);
-
- if (!transac)
- return BT_HC_STATUS_FAIL;
-
- thread_post(hc_cb.worker_thread, event_tx_cmd, transac);
- return BT_HC_STATUS_SUCCESS;
-}
-
-// Closes the interface.
-// This routine is not thread safe.
-static void cleanup(void)
-{
- if (has_cleaned_up) {
- ALOGW("%s Already cleaned up for this session\n", __func__);
- return;
- }
-
- BTHCDBG("cleanup");
-
- hci_inject_close();
-
- if (hc_cb.worker_thread)
- {
- if (fwcfg_acked)
- {
- epilog_wait_timer();
- // Stop reading thread
- userial_close_reader();
-
- thread_post(hc_cb.worker_thread, event_epilog, NULL);
- }
- thread_free(hc_cb.worker_thread);
-
- pthread_mutex_lock(&hc_cb.worker_thread_lock);
- hc_cb.worker_thread = NULL;
- pthread_mutex_unlock(&hc_cb.worker_thread_lock);
- }
- BTHCDBG("%s Finalizing cleanup\n", __func__);
-
- alarm_free(hc_cb.alarm);
- hc_cb.alarm = NULL;
-
- lpm_cleanup();
- userial_close();
- p_hci_if->cleanup();
- utils_cleanup();
-
- set_power(BT_VND_PWR_OFF);
- vendor_close();
-
- pthread_mutex_destroy(&hc_cb.worker_thread_lock);
-
- fwcfg_acked = false;
- bt_hc_cbacks = NULL;
- has_cleaned_up = true;
-}
-
-static const bt_hc_interface_t bluetoothHCLibInterface = {
- sizeof(bt_hc_interface_t),
- init,
- set_power,
- lpm,
- preload,
- postload,
- transmit_buf,
- logging,
- cleanup,
- tx_hc_cmd,
-};
-
-/*******************************************************************************
-**
-** Function bt_hc_get_interface
-**
-** Description Caller calls this function to get API instance
-**
-** Returns API table
-**
-*******************************************************************************/
-const bt_hc_interface_t *bt_hc_get_interface(void)
-{
- return &bluetoothHCLibInterface;
-}
diff --git a/hci/src/btsnoop.c b/hci/src/btsnoop.c
index e31af35f2..9df0c5dd7 100644
--- a/hci/src/btsnoop.c
+++ b/hci/src/btsnoop.c
@@ -32,9 +32,10 @@
#include <sys/time.h>
#include <unistd.h>
-#include "bt_hci_bdroid.h"
+#include "btsnoop.h"
+#include "bt_types.h"
#include "bt_utils.h"
-#include "utils.h"
+#include "hci_layer.h"
typedef enum {
kCommandPacket = 1,
@@ -105,9 +106,6 @@ static void btsnoop_write_packet(packet_type_t type, const uint8_t *packet, bool
time_hi = htonl(time_hi);
time_lo = htonl(time_lo);
- // This function is called from different contexts.
- utils_lock();
-
btsnoop_write(&length, 4);
btsnoop_write(&length, 4);
btsnoop_write(&flags, 4);
@@ -116,11 +114,9 @@ static void btsnoop_write_packet(packet_type_t type, const uint8_t *packet, bool
btsnoop_write(&time_lo, 4);
btsnoop_write(&type, 1);
btsnoop_write(packet, length_he - 1);
-
- utils_unlock();
}
-void btsnoop_open(const char *p_path, const bool save_existing) {
+static void btsnoop_open(const char *p_path) {
assert(p_path != NULL);
assert(*p_path != '\0');
@@ -131,14 +127,6 @@ void btsnoop_open(const char *p_path, const bool save_existing) {
return;
}
- if (save_existing)
- {
- char fname_backup[266] = {0};
- strncat(fname_backup, p_path, 255);
- strcat(fname_backup, ".last");
- rename(p_path, fname_backup);
- }
-
hci_btsnoop_fd = open(p_path,
O_WRONLY | O_CREAT | O_TRUNC,
S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH);
@@ -151,7 +139,7 @@ void btsnoop_open(const char *p_path, const bool save_existing) {
write(hci_btsnoop_fd, "btsnoop\0\0\0\0\1\0\0\x3\xea", 16);
}
-void btsnoop_close(void) {
+static void btsnoop_close(void) {
if (hci_btsnoop_fd != -1)
close(hci_btsnoop_fd);
hci_btsnoop_fd = -1;
@@ -159,26 +147,36 @@ void btsnoop_close(void) {
btsnoop_net_close();
}
-void btsnoop_capture(const HC_BT_HDR *p_buf, bool is_rcvd) {
- const uint8_t *p = (const uint8_t *)(p_buf + 1) + p_buf->offset;
+static void btsnoop_capture(const BT_HDR *buffer, bool is_received) {
+ const uint8_t *p = buffer->data + buffer->offset;
if (hci_btsnoop_fd == -1)
return;
- switch (p_buf->event & MSG_EVT_MASK) {
+ switch (buffer->event & MSG_EVT_MASK) {
case MSG_HC_TO_STACK_HCI_EVT:
btsnoop_write_packet(kEventPacket, p, false);
break;
case MSG_HC_TO_STACK_HCI_ACL:
case MSG_STACK_TO_HC_HCI_ACL:
- btsnoop_write_packet(kAclPacket, p, is_rcvd);
+ btsnoop_write_packet(kAclPacket, p, is_received);
break;
case MSG_HC_TO_STACK_HCI_SCO:
case MSG_STACK_TO_HC_HCI_SCO:
- btsnoop_write_packet(kScoPacket, p, is_rcvd);
+ btsnoop_write_packet(kScoPacket, p, is_received);
break;
case MSG_STACK_TO_HC_HCI_CMD:
btsnoop_write_packet(kCommandPacket, p, true);
break;
}
}
+
+static const btsnoop_interface_t interface = {
+ btsnoop_open,
+ btsnoop_close,
+ btsnoop_capture
+};
+
+const btsnoop_interface_t *btsnoop_get_interface() {
+ return &interface;
+}
diff --git a/hci/src/hci_h4.c b/hci/src/hci_h4.c
deleted file mode 100644
index ba6e2a2bc..000000000
--- a/hci/src/hci_h4.c
+++ /dev/null
@@ -1,1062 +0,0 @@
-/******************************************************************************
- *
- * Copyright (C) 2009-2012 Broadcom Corporation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- ******************************************************************************/
-
-/******************************************************************************
- *
- * Filename: hci_h4.c
- *
- * Description: Contains HCI transport send/receive functions
- *
- ******************************************************************************/
-
-#define LOG_TAG "bt_h4"
-
-#include <utils/Log.h>
-#include <stdlib.h>
-#include <fcntl.h>
-
-#include "bt_hci_bdroid.h"
-#include "btsnoop.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
-
-/* Table of HCI preamble sizes for the different HCI message types */
-static const uint8_t hci_preamble_table[] =
-{
- HCI_CMD_PREAMBLE_SIZE,
- HCI_ACL_PREAMBLE_SIZE,
- HCI_SCO_PREAMBLE_SIZE,
- HCI_EVT_PREAMBLE_SIZE
-};
-
-/* HCI H4 message type definitions */
-#define H4_TYPE_COMMAND 1
-#define H4_TYPE_ACL_DATA 2
-#define H4_TYPE_SCO_DATA 3
-#define H4_TYPE_EVENT 4
-
-static const uint16_t msg_evt_table[] =
-{
- MSG_HC_TO_STACK_HCI_ERR, /* H4_TYPE_COMMAND */
- MSG_HC_TO_STACK_HCI_ACL, /* H4_TYPE_ACL_DATA */
- MSG_HC_TO_STACK_HCI_SCO, /* H4_TYPE_SCO_DATA */
- MSG_HC_TO_STACK_HCI_EVT /* H4_TYPE_EVENT */
-};
-
-#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
-******************************************************************************/
-
-/* H4 Rx States */
-typedef enum {
- H4_RX_MSGTYPE_ST,
- H4_RX_LEN_ST,
- H4_RX_DATA_ST,
- H4_RX_IGNORE_ST
-} tHCI_H4_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;
-
-/* Control block for HCISU_H4 */
-typedef struct
-{
- HC_BT_HDR *p_rcv_msg; /* Buffer to hold current rx HCI message */
- uint16_t rcv_len; /* Size of current incoming message */
- uint8_t rcv_msg_type; /* Current incoming message type */
- tHCI_H4_RCV_STATE rcv_state; /* Receive state of current rx message */
- 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 */
- uint8_t preload_count; /* Count numbers of preload bytes */
- uint8_t preload_buffer[6]; /* HCI_ACL_PREAMBLE_SIZE + 2 */
- 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_H4_CB;
-
-/******************************************************************************
-** Externs
-******************************************************************************/
-
-uint8_t hci_h4_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_H4_CB h4_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)
- h4_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_h4_send_int_cmd(HCI_LE_READ_BUFFER_SIZE, p_buf, \
- get_acl_data_length_cback)) == FALSE)
- {
- bt_hc_cbacks->dealloc(p_buf);
- bt_hc_cbacks->postload_cb(NULL, BT_HC_POSTLOAD_SUCCESS);
- }
- }
- else if (opcode == HCI_LE_READ_BUFFER_SIZE)
- {
- if (status == 0)
- h4_cb.hc_ble_acl_data_size = (len) ? len : h4_cb.hc_acl_data_size;
-
- if (bt_hc_cbacks)
- {
- bt_hc_cbacks->dealloc(p_buf);
- ALOGE("vendor 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_H4_CB *p_cb = &h4_cb;
-
- p = (uint8_t *)(p_cb->p_rcv_msg + 1);
-
- event_code = *p++;
- len = *p++;
-
- if (event_code == HCI_COMMAND_COMPLETE_EVT)
- {
- num_hci_cmd_pkts = *p++;
-
- 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->p_rcv_msg);
- }
- else
- {
- // Missing cback function!
- // Release the p_rcv_msg buffer.
- if (bt_hc_cbacks)
- {
- bt_hc_cbacks->dealloc(p_cb->p_rcv_msg);
- }
- }
- 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)
- {
- num_hci_cmd_pkts = *(++p);
- }
-
- 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 H4 RX 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_H4_CB *p_cb = &h4_cb;
-
-
- p = p_cb->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_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("H4 - dropping incomplete ACL frame");
-
- utils_remove_from_queue(&(p_cb->acl_rx_q), p_return_buf);
-
- if (bt_hc_cbacks)
- {
- bt_hc_cbacks->dealloc(p_return_buf);
- }
- 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->preload_count;
- memcpy((uint8_t *)(p_return_buf + 1), p_cb->preload_buffer, \
- p_cb->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_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_H4_CB *p_cb = &h4_cb;
- uint8_t frame_end=TRUE;
-
- p_buf = p_cb->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 H4 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->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->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 H4 INTERFACE FUNCTIONS
-*****************************************************************************/
-
-/*******************************************************************************
-**
-** Function hci_h4_init
-**
-** Description Initialize H4 module
-**
-** Returns None
-**
-*******************************************************************************/
-void hci_h4_init(void)
-{
- HCIDBG("hci_h4_init");
-
- memset(&h4_cb, 0, sizeof(tHCI_H4_CB));
- utils_queue_init(&(h4_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
- */
- h4_cb.hc_acl_data_size = 1021;
- h4_cb.hc_ble_acl_data_size = 27;
-}
-
-/*******************************************************************************
-**
-** Function hci_h4_cleanup
-**
-** Description Clean H4 module
-**
-** Returns None
-**
-*******************************************************************************/
-void hci_h4_cleanup(void)
-{
- HCIDBG("hci_h4_cleanup");
-}
-
-/*******************************************************************************
-**
-** Function hci_h4_send_msg
-**
-** Description Determine message type, set HCI H4 packet indicator, and
-** send message through USERIAL driver
-**
-** Returns None
-**
-*******************************************************************************/
-void hci_h4_send_msg(HC_BT_HDR *p_msg)
-{
- uint8_t type = 0;
- uint16_t handle;
- uint16_t bytes_to_send, 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;
- uint16_t bytes_sent;
-
- /* wake up BT device if its in sleep mode */
- lpm_wake_assert();
-
- if (event == MSG_STACK_TO_HC_HCI_ACL)
- type = H4_TYPE_ACL_DATA;
- else if (event == MSG_STACK_TO_HC_HCI_SCO)
- type = H4_TYPE_SCO_DATA;
- else if (event == MSG_STACK_TO_HC_HCI_CMD)
- type = H4_TYPE_COMMAND;
-
- if (sub_event == LOCAL_BR_EDR_CONTROLLER_ID)
- {
- acl_data_size = h4_cb.hc_acl_data_size;
- acl_pkt_size = h4_cb.hc_acl_data_size + HCI_ACL_PREAMBLE_SIZE;
- }
- else
- {
- acl_data_size = h4_cb.hc_ble_acl_data_size;
- acl_pkt_size = h4_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)
- {
- /* remember layer_specific because uart borrow
- one byte from layer_specific for packet type */
- lay_spec = p_msg->layer_specific;
-
- p = ((uint8_t *)(p_msg + 1)) + p_msg->offset - 1;
- *p = type;
- bytes_to_send = acl_pkt_size + 1; /* packet_size + message type */
-
- 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->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;
- }
- }
- }
- }
-
-
- /* remember layer_specific because uart borrow
- one byte from layer_specific for packet type */
- lay_spec = p_msg->layer_specific;
-
- /* Put the HCI Transport packet type 1 byte before the message */
- p = ((uint8_t *)(p_msg + 1)) + p_msg->offset - 1;
- *p = type;
- bytes_to_send = p_msg->len + 1; /* message_size + message type */
-
- bytes_sent = userial_write(event,(uint8_t *) p, bytes_to_send);
-
- p_msg->layer_specific = lay_spec;
-
- if (event == MSG_STACK_TO_HC_HCI_CMD)
- {
- num_hci_cmd_pkts--;
-
- /* 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) && \
- (h4_cb.int_cmd_rsp_pending > 0) && \
- (p_msg->layer_specific == lay_spec))
- {
- /* dealloc buffer of internal command */
- bt_hc_cbacks->dealloc(p_msg);
- }
- else
- {
- bt_hc_cbacks->tx_result((TRANSAC) p_msg, (char *) (p_msg + 1), \
- BT_HC_TX_SUCCESS);
- }
- }
-
- lpm_tx_done(TRUE);
-
- return;
-}
-
-
-/*******************************************************************************
-**
-** Function hci_h4_receive_msg
-**
-** Description Construct HCI EVENT/ACL packets and send them to stack once
-** complete packet has been received.
-**
-** Returns Number of read bytes
-**
-*******************************************************************************/
-uint16_t hci_h4_receive_msg(void)
-{
- uint16_t bytes_read = 0;
- uint8_t byte;
- uint16_t msg_len, len;
- uint8_t msg_received;
- tHCI_H4_CB *p_cb=&h4_cb;
-
- while (TRUE)
- {
- /* Read one byte to see if there is anything waiting to be read */
- if (userial_read(0 /*dummy*/, &byte, 1) == 0)
- {
- break;
- }
-
- bytes_read++;
- msg_received = FALSE;
-
- switch (p_cb->rcv_state)
- {
- case H4_RX_MSGTYPE_ST:
- /* Start of new message */
- if ((byte < H4_TYPE_ACL_DATA) || (byte > H4_TYPE_EVENT))
- {
- /* Unknown HCI message type */
- /* Drop this byte */
- ALOGE("[h4] Unknown HCI message type drop this byte 0x%x", byte);
- break;
- }
-
- /* Initialize rx parameters */
- p_cb->rcv_msg_type = byte;
- p_cb->rcv_len = hci_preamble_table[byte-1];
- memset(p_cb->preload_buffer, 0 , 6);
- p_cb->preload_count = 0;
- // p_cb->p_rcv_msg = NULL;
- p_cb->rcv_state = H4_RX_LEN_ST; /* Next, wait for length to come */
- break;
-
- case H4_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)
- {
- if (p_cb->rcv_msg_type == H4_TYPE_ACL_DATA)
- {
- /* 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();
- }
- else
- {
- /* 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_evt_table[p_cb->rcv_msg_type-1];
- 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);
- }
- }
-
- if (p_cb->p_rcv_msg == NULL)
- {
- /* Unable to acquire message buffer. */
- ALOGE( \
- "H4: Unable to acquire buffer for incoming HCI message." \
- );
-
- if (msg_len == 0)
- {
- /* Wait for next message */
- p_cb->rcv_state = H4_RX_MSGTYPE_ST;
- }
- else
- {
- /* Ignore rest of the packet */
- p_cb->rcv_state = H4_RX_IGNORE_ST;
- }
-
- break;
- }
-
- /* Message length is valid */
- if (msg_len)
- {
- /* Read rest of message */
- p_cb->rcv_state = H4_RX_DATA_ST;
- }
- else
- {
- /* 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 */
-
- msg_received = TRUE;
-
- /* Next, wait for next message */
- p_cb->rcv_state = H4_RX_MSGTYPE_ST;
- }
- }
- break;
-
- case H4_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(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;
- 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 ((p_cb->rcv_msg_type == H4_TYPE_ACL_DATA) &&
- !acl_rx_frame_end_chk())
- {
- /* Not the end of packet yet. */
- /* Next, wait for next message */
- p_cb->rcv_state = H4_RX_MSGTYPE_ST;
- }
- else
- {
- msg_received = TRUE;
- /* Next, wait for next message */
- p_cb->rcv_state = H4_RX_MSGTYPE_ST;
- }
- }
- break;
-
-
- case H4_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 = H4_RX_MSGTYPE_ST;
- }
- break;
- }
-
-
- /* If we received entire message, then send it to the task */
- if (msg_received)
- {
- uint8_t intercepted = FALSE;
-
- /* 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)
- 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))
- {
- 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_h4_send_int_cmd
-**
-** Description Place the internal commands (issued internally by vendor lib)
-** in the tx_q.
-**
-** Returns TRUE/FALSE
-**
-*******************************************************************************/
-uint8_t hci_h4_send_int_cmd(uint16_t opcode, HC_BT_HDR *p_buf, \
- tINT_CMD_CBACK p_cback)
-{
- if (h4_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;
- }
-
- h4_cb.int_cmd_rsp_pending++;
- h4_cb.int_cmd[h4_cb.int_cmd_wrt_idx].opcode = opcode;
- h4_cb.int_cmd[h4_cb.int_cmd_wrt_idx].cback = p_cback;
- h4_cb.int_cmd_wrt_idx = ((h4_cb.int_cmd_wrt_idx+1) & INT_CMD_PKT_IDX_MASK);
-
- /* stamp signature to indicate an internal command */
- p_buf->layer_specific = opcode;
-
- bthc_tx(p_buf);
- return TRUE;
-}
-
-
-/*******************************************************************************
-**
-** Function hci_h4_get_acl_data_length
-**
-** Description Issue HCI_READ_BUFFER_SIZE command to retrieve Controller's
-** ACL data length setting
-**
-** Returns None
-**
-*******************************************************************************/
-void hci_h4_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_h4_send_int_cmd(HCI_READ_BUFFER_SIZE, p_buf, \
- get_acl_data_length_cback)) == FALSE)
- {
- bt_hc_cbacks->dealloc(p_buf);
- }
- else
- return;
- }
-
- if (bt_hc_cbacks)
- {
- ALOGE("vendor lib postload aborted");
- bt_hc_cbacks->postload_cb(NULL, BT_HC_POSTLOAD_FAIL);
- }
-}
-
-
-/******************************************************************************
-** 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_hal_h4.c b/hci/src/hci_hal_h4.c
new file mode 100644
index 000000000..35a939588
--- /dev/null
+++ b/hci/src/hci_hal_h4.c
@@ -0,0 +1,224 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "hci_hal_h4"
+
+#include <assert.h>
+#include <utils/Log.h>
+
+#include "eager_reader.h"
+#include "hci_hal.h"
+#include "osi.h"
+#include "reactor.h"
+#include "vendor.h"
+
+#define HCI_HAL_SERIAL_BUFFER_SIZE 1026
+
+// Our interface and modules we import
+static const hci_hal_interface_t interface;
+static const hci_hal_callbacks_t *callbacks;
+static const vendor_interface_t *vendor;
+
+static thread_t *thread; // Not owned by us
+
+static int uart_fd;
+static eager_reader_t *uart_stream;
+static serial_data_type_t current_data_type;
+static bool stream_has_interpretation;
+
+static void event_uart_has_bytes(eager_reader_t *reader, void *context);
+
+// Interface functions
+
+static bool hal_init(const hci_hal_callbacks_t *upper_callbacks, thread_t *upper_thread) {
+ assert(upper_callbacks != NULL);
+ assert(upper_thread != NULL);
+
+ callbacks = upper_callbacks;
+ thread = upper_thread;
+ return true;
+}
+
+static bool hal_open() {
+ // TODO(zachoverflow): close if already open / or don't reopen (maybe at the hci layer level)
+
+ int fd_array[CH_MAX];
+ int number_of_ports = vendor->send_command(VENDOR_OPEN_USERIAL, &fd_array);
+
+ if (number_of_ports != 1) {
+ ALOGE("%s opened the wrong number of ports: got %d, expected 1.", __func__, number_of_ports);
+ goto error;
+ }
+
+ uart_fd = fd_array[0];
+ if (uart_fd == -1) {
+ ALOGE("%s unable to open the uart serial port.", __func__);
+ goto error;
+ }
+
+ uart_stream = eager_reader_new(uart_fd, &allocator_malloc, HCI_HAL_SERIAL_BUFFER_SIZE, SIZE_MAX, "hci_single_channel");
+ if (!uart_stream) {
+ ALOGE("%s unable to create eager reader for the uart serial port.", __func__);
+ goto error;
+ }
+
+ stream_has_interpretation = false;
+ eager_reader_register(uart_stream, thread_get_reactor(thread), event_uart_has_bytes, NULL);
+
+ return true;
+
+error:
+ interface.close();
+ return false;
+}
+
+static void hal_close() {
+ eager_reader_free(uart_stream);
+ vendor->send_command(VENDOR_CLOSE_USERIAL, NULL);
+}
+
+static uint8_t read_byte(serial_data_type_t type) {
+ if (type < DATA_TYPE_ACL || type > DATA_TYPE_EVENT) {
+ ALOGE("%s invalid data type: %d", __func__, type);
+ return 0;
+ } else if (!stream_has_interpretation) {
+ ALOGE("%s read byte with no valid stream intepretation.", __func__);
+ return 0;
+ } else if (current_data_type != type) {
+ ALOGE("%s read byte with different type than existing interpretation.", __func__);
+ return 0;
+ }
+
+ return eager_reader_read_byte(uart_stream);
+}
+
+static bool has_byte(serial_data_type_t type) {
+ if (type < DATA_TYPE_ACL || type > DATA_TYPE_EVENT) {
+ ALOGE("%s invalid data type: %d", __func__, type);
+ return 0;
+ } else if (!stream_has_interpretation) {
+ ALOGE("%s has byte with no valid stream intepretation.", __func__);
+ return 0;
+ } else if (current_data_type != type) {
+ ALOGE("%s has byte with different type than existing interpretation.", __func__);
+ return 0;
+ }
+
+ return eager_reader_has_byte(uart_stream);
+}
+
+static void packet_finished(serial_data_type_t type) {
+ if (!stream_has_interpretation)
+ ALOGE("%s packet finished with no existing stream interpretation.", __func__);
+ else if (current_data_type != type)
+ ALOGE("%s packed finished with different type than existing interpretation.", __func__);
+
+ stream_has_interpretation = false;
+}
+
+static uint16_t transmit_data(serial_data_type_t type, uint8_t *data, uint16_t length) {
+ assert(data != NULL);
+ assert(length > 0);
+
+ if (type < DATA_TYPE_COMMAND || type > DATA_TYPE_SCO) {
+ ALOGE("%s invalid data type: %d", __func__, type);
+ return 0;
+ }
+
+ // Write the signal byte right before the data
+ --data;
+ uint8_t previous_byte = *data;
+ *(data) = type;
+ ++length;
+
+ uint16_t transmitted_length = 0;
+ while (length > 0) {
+ ssize_t ret = write(uart_fd, data + transmitted_length, length);
+ switch (ret) {
+ case -1:
+ ALOGE("In %s, error writing to the uart serial port: %s", __func__, strerror(errno));
+ goto done;
+ case 0:
+ // If we wrote nothing, don't loop more because we
+ // can't go to infinity or beyond
+ goto done;
+ default:
+ transmitted_length += ret;
+ length -= ret;
+ break;
+ }
+ }
+
+done:;
+ // Be nice and restore the old value of that byte
+ *(data) = previous_byte;
+
+ // Remove the signal byte from our transmitted length, if it was actually written
+ if (transmitted_length > 0)
+ --transmitted_length;
+
+ return transmitted_length;
+}
+
+// Internal functions
+
+// See what data is waiting, and notify the upper layer
+static void event_uart_has_bytes(eager_reader_t *reader, UNUSED_ATTR void *context) {
+ uint8_t type_byte;
+
+ if (stream_has_interpretation) {
+ // Reentry in the the case that the upper layer couldn't read the entire
+ // packet the first time around
+ type_byte = current_data_type;
+ }
+ else {
+ type_byte = eager_reader_read_byte(reader);
+ if (type_byte < DATA_TYPE_ACL || type_byte > DATA_TYPE_EVENT) {
+ ALOGE("[h4] Unknown HCI message type. Dropping this byte 0x%x, min %x, max %x", type_byte, DATA_TYPE_ACL, DATA_TYPE_EVENT);
+ return;
+ }
+
+ stream_has_interpretation = true;
+ current_data_type = type_byte;
+ }
+
+ if (has_byte(current_data_type))
+ callbacks->data_ready(type_byte);
+}
+
+static const hci_hal_interface_t interface = {
+ hal_init,
+
+ hal_open,
+ hal_close,
+
+ read_byte,
+ has_byte,
+ packet_finished,
+ transmit_data,
+};
+
+const hci_hal_interface_t *hci_hal_get_interface() {
+ vendor = vendor_get_interface();
+ return &interface;
+}
+
+const hci_hal_interface_t *hci_hal_get_test_interface(vendor_interface_t *vendor_interface) {
+ vendor = vendor_interface;
+ return &interface;
+}
diff --git a/hci/src/hci_inject.c b/hci/src/hci_inject.c
index af5ed704d..e894b73ff 100644
--- a/hci/src/hci_inject.c
+++ b/hci/src/hci_inject.c
@@ -22,9 +22,9 @@
#include <errno.h>
#include <utils/Log.h>
-#include "bt_hci_bdroid.h"
#include "bt_types.h"
#include "hci_inject.h"
+#include "hci_layer.h"
#include "list.h"
#include "osi.h"
#include "socket.h"
@@ -45,7 +45,9 @@ typedef struct {
static const port_t LISTEN_PORT = 8873;
-static const bt_hc_interface_t *hci;
+static const hci_inject_interface_t interface;
+static const hci_interface_t *hci;
+static const allocator_t *allocator;
static socket_t *listen_socket;
static thread_t *thread;
static list_t *clients;
@@ -55,12 +57,15 @@ static void accept_ready(socket_t *socket, void *context);
static void read_ready(socket_t *socket, void *context);
static void client_free(void *ptr);
-bool hci_inject_open(void) {
+bool hci_inject_open(const hci_interface_t *hci_interface, const allocator_t *buffer_allocator) {
assert(listen_socket == NULL);
assert(thread == NULL);
assert(clients == NULL);
+ assert(hci_interface != NULL);
+ assert(buffer_allocator != NULL);
- hci = bt_hc_get_interface();
+ hci = hci_interface;
+ allocator = buffer_allocator;
thread = thread_new("hci_inject");
if (!thread)
@@ -81,7 +86,7 @@ bool hci_inject_open(void) {
return true;
error:;
- hci_inject_close();
+ interface.close();
return false;
}
@@ -136,7 +141,6 @@ static void accept_ready(socket_t *socket, UNUSED_ATTR void *context) {
}
static void read_ready(UNUSED_ATTR socket_t *socket, void *context) {
- assert(bt_hc_cbacks != NULL);
assert(socket != NULL);
assert(context != NULL);
@@ -162,14 +166,14 @@ static void read_ready(UNUSED_ATTR socket_t *socket, void *context) {
// TODO(sharvil): once we have an HCI parser, we can eliminate
// the 2-byte size field since it will be contained in the packet.
- BT_HDR *buf = (BT_HDR *)bt_hc_cbacks->alloc(packet_len);
+ BT_HDR *buf = (BT_HDR *)allocator->alloc(packet_len);
if (buf) {
buf->event = hci_packet_to_event(packet_type);
buf->offset = 0;
buf->layer_specific = 0;
buf->len = packet_len;
memcpy(buf->data, buffer + 3, packet_len);
- hci->transmit_buf(buf, NULL, 0);
+ hci->transmit_downward(buf->event, buf);
} else {
ALOGE("%s dropping injected packet of length %zu", __func__, packet_len);
}
@@ -187,3 +191,12 @@ static void client_free(void *ptr) {
client_t *client = (client_t *)ptr;
socket_free(client->socket);
}
+
+static const hci_inject_interface_t interface = {
+ hci_inject_open,
+ hci_inject_close
+};
+
+const hci_inject_interface_t *hci_inject_get_interface() {
+ return &interface;
+}
diff --git a/hci/src/hci_layer.c b/hci/src/hci_layer.c
new file mode 100644
index 000000000..ed32e84b3
--- /dev/null
+++ b/hci/src/hci_layer.c
@@ -0,0 +1,677 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "hci_layer"
+
+#include <assert.h>
+#include <utils/Log.h>
+
+#include "alarm.h"
+#include "bt_types.h"
+#include "btsnoop.h"
+#include "fixed_queue.h"
+#include "hci_hal.h"
+#include "hci_internals.h"
+#include "hci_inject.h"
+#include "hci_layer.h"
+#include "low_power_manager.h"
+#include "osi.h"
+#include "packet_fragmenter.h"
+#include "reactor.h"
+#include "vendor.h"
+
+#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
+
+#define INBOUND_PACKET_TYPE_COUNT 3
+#define PACKET_TYPE_TO_INBOUND_INDEX(type) ((type) - 2)
+#define PACKET_TYPE_TO_INDEX(type) ((type) - 1)
+
+#define PREAMBLE_BUFFER_SIZE 4 // max preamble size, ACL
+#define RETRIEVE_ACL_LENGTH(preamble) ((((preamble)[3]) << 8) | (preamble)[2])
+
+#define MAX_WAITING_INTERNAL_COMMANDS 8
+
+static const uint8_t preamble_sizes[] = {
+ HCI_COMMAND_PREAMBLE_SIZE,
+ HCI_ACL_PREAMBLE_SIZE,
+ HCI_SCO_PREAMBLE_SIZE,
+ HCI_EVENT_PREAMBLE_SIZE
+};
+
+static const uint16_t outbound_event_types[] =
+{
+ MSG_HC_TO_STACK_HCI_ERR,
+ MSG_HC_TO_STACK_HCI_ACL,
+ MSG_HC_TO_STACK_HCI_SCO,
+ MSG_HC_TO_STACK_HCI_EVT
+};
+
+typedef enum {
+ BRAND_NEW,
+ PREAMBLE,
+ BODY,
+ IGNORE,
+ FINISHED
+} receive_state_t;
+
+typedef struct {
+ receive_state_t state;
+ uint16_t bytes_remaining;
+ uint8_t preamble[PREAMBLE_BUFFER_SIZE];
+ uint16_t index;
+ BT_HDR *buffer;
+} packet_receive_data_t;
+
+typedef struct {
+ uint16_t opcode;
+ internal_command_cb callback;
+} waiting_internal_command_t;
+
+static const uint32_t EPILOG_TIMEOUT_MS = 3000;
+
+// Our interface
+static bool interface_created;
+static hci_interface_t interface;
+
+// Modules we import and callbacks we export
+static const allocator_t *buffer_allocator;
+static const btsnoop_interface_t *btsnoop;
+static const hci_callbacks_t *callbacks;
+static const hci_hal_interface_t *hal;
+static const hci_hal_callbacks_t hal_callbacks;
+static const hci_inject_interface_t *hci_inject;
+static const low_power_manager_interface_t *low_power_manager;
+static const packet_fragmenter_interface_t *packet_fragmenter;
+static const packet_fragmenter_callbacks_t packet_fragmenter_callbacks;
+static const vendor_interface_t *vendor;
+
+static thread_t *thread; // We own this
+
+static volatile bool firmware_is_configured = false;
+static volatile bool has_cleaned_up = false;
+static alarm_t *epilog_alarm;
+
+// Outbound-related
+static int command_credits = 1;
+static fixed_queue_t *command_queue;
+static fixed_queue_t *packet_queue;
+
+// Inbound-related
+static fixed_queue_t *waiting_internal_commands;
+static packet_receive_data_t incoming_packets[INBOUND_PACKET_TYPE_COUNT];
+
+static void event_preload(void *context);
+static void event_postload(void *context);
+static void event_epilog(void *context);
+static void event_command_ready(fixed_queue_t *queue, void *context);
+static void event_packet_ready(fixed_queue_t *queue, void *context);
+
+static void firmware_config_callback(bool success);
+static void sco_config_callback(bool success);
+static void epilog_finished_callback(bool success);
+
+static void hal_says_data_ready(serial_data_type_t type);
+static bool send_internal_command(uint16_t opcode, BT_HDR *packet, internal_command_cb callback);
+static void start_epilog_wait_timer();
+
+// Interface functions
+
+static bool hci_init(
+ bdaddr_t local_bdaddr,
+ const allocator_t *upward_buffer_allocator,
+ const hci_callbacks_t *upper_callbacks) {
+ assert(local_bdaddr != NULL);
+ assert(upward_buffer_allocator != NULL);
+ assert(upper_callbacks != NULL);
+
+ ALOGI("%s", __func__);
+
+ // The host is only allowed to send at most one command initially,
+ // as per the Bluetooth spec, Volume 2, Part E, 4.4 (Command Flow Control)
+ // This value can change when you get a command complete or command status event.
+ command_credits = 1;
+ firmware_is_configured = false;
+ has_cleaned_up = false;
+
+ epilog_alarm = alarm_new();
+ if (!epilog_alarm) {
+ ALOGE("%s unable to create epilog alarm.", __func__);
+ goto error;
+ }
+
+ command_queue = fixed_queue_new(SIZE_MAX);
+ if (!command_queue) {
+ ALOGE("%s unable to create pending command queue.", __func__);
+ goto error;
+ }
+
+ packet_queue = fixed_queue_new(SIZE_MAX);
+ if (!packet_queue) {
+ ALOGE("%s unable to create pending packet queue.", __func__);
+ goto error;
+ }
+
+ thread = thread_new("hci_thread");
+ if (!thread) {
+ ALOGE("%s unable to create thread.", __func__);
+ goto error;
+ }
+
+ waiting_internal_commands = fixed_queue_new(MAX_WAITING_INTERNAL_COMMANDS);
+ if (!waiting_internal_commands) {
+ ALOGE("%s unable to create waiting internal command queue.", __func__);
+ goto error;
+ }
+
+ callbacks = upper_callbacks;
+ buffer_allocator = upward_buffer_allocator;
+ memset(incoming_packets, 0, sizeof(incoming_packets));
+
+ packet_fragmenter->init(&packet_fragmenter_callbacks, buffer_allocator);
+
+ fixed_queue_register_dequeue(command_queue, thread_get_reactor(thread), event_command_ready, NULL);
+ fixed_queue_register_dequeue(packet_queue, thread_get_reactor(thread), event_packet_ready, NULL);
+
+ vendor->open(local_bdaddr, buffer_allocator);
+ hal->init(&hal_callbacks, thread);
+ low_power_manager->init(thread);
+
+ vendor->set_callback(VENDOR_CONFIGURE_FIRMWARE, firmware_config_callback);
+ vendor->set_callback(VENDOR_CONFIGURE_SCO, sco_config_callback);
+ vendor->set_callback(VENDOR_DO_EPILOG, epilog_finished_callback);
+ vendor->set_send_internal_command_callback(send_internal_command);
+
+ if (!hci_inject->open(&interface, buffer_allocator)) {
+ // TODO(sharvil): gracefully propagate failures from this layer.
+ }
+
+ return true;
+error:;
+ interface.cleanup();
+ return false;
+}
+
+static void hci_cleanup() {
+ if (has_cleaned_up) {
+ ALOGW("%s already cleaned up for this session", __func__);
+ return;
+ }
+
+ ALOGI("%s", __func__);
+
+ hci_inject->close();
+
+ if (thread) {
+ if (firmware_is_configured) {
+ start_epilog_wait_timer();
+ thread_post(thread, event_epilog, NULL);
+ } else {
+ thread_stop(thread);
+ }
+
+ thread_join(thread);
+ }
+
+ fixed_queue_free(command_queue, buffer_allocator->free);
+ fixed_queue_free(packet_queue, buffer_allocator->free);
+ fixed_queue_free(waiting_internal_commands, buffer_allocator->free);
+
+ alarm_free(epilog_alarm);
+ epilog_alarm = NULL;
+
+ low_power_manager->cleanup();
+ hal->close();
+
+ interface.set_chip_power_on(false);
+ vendor->close();
+
+ thread_free(thread);
+ thread = NULL;
+ firmware_is_configured = false;
+ has_cleaned_up = true;
+}
+
+static void set_chip_power_on(bool value) {
+ ALOGD("%s setting bluetooth chip power on to: %d", __func__, value);
+
+ int power_state = value ? BT_VND_PWR_ON : BT_VND_PWR_OFF;
+ vendor->send_command(VENDOR_CHIP_POWER_CONTROL, &power_state);
+}
+
+static void do_preload() {
+ ALOGD("%s posting preload work item", __func__);
+ thread_post(thread, event_preload, NULL);
+}
+
+static void do_postload() {
+ ALOGD("%s posting postload work item", __func__);
+ thread_post(thread, event_postload, NULL);
+}
+
+static void turn_on_logging(const char *path) {
+ ALOGD("%s", __func__);
+
+ if (path != NULL)
+ btsnoop->open(path);
+ else
+ ALOGW("%s wanted to start logging, but path was NULL", __func__);
+}
+
+static void turn_off_logging() {
+ ALOGD("%s", __func__);
+ btsnoop->close();
+}
+
+static void transmit_downward(data_dispatcher_type_t type, void *data) {
+ if (type == MSG_STACK_TO_HC_HCI_CMD) {
+ fixed_queue_enqueue(command_queue, data);
+ } else {
+ fixed_queue_enqueue(packet_queue, data);
+ }
+}
+
+// Internal functions
+
+// Inspects an incoming event for interesting information, like how many
+// commands are now able to be sent. Returns true if the event should
+// not proceed to higher layers (i.e. was intercepted for internal use).
+static bool filter_incoming_event(BT_HDR *packet) {
+ uint8_t *stream = packet->data;
+ uint8_t event_code;
+
+ STREAM_TO_UINT8(event_code, stream);
+ STREAM_SKIP_UINT8(stream); // Skip the parameter total length field
+
+ if (event_code == HCI_COMMAND_COMPLETE_EVT) {
+ uint16_t opcode;
+
+ STREAM_TO_UINT8(command_credits, stream);
+ STREAM_TO_UINT16(opcode, stream);
+
+ // TODO make this look back in the commands rather than just the first one
+ waiting_internal_command_t *first_waiting = fixed_queue_try_peek(waiting_internal_commands);
+ if (first_waiting != NULL && opcode == first_waiting->opcode) {
+ fixed_queue_dequeue(waiting_internal_commands);
+
+ if (first_waiting->callback)
+ first_waiting->callback(packet);
+ else
+ buffer_allocator->free(packet);
+
+ free(first_waiting);
+ return true;
+ }
+
+ } else if (event_code == HCI_COMMAND_STATUS_EVT) {
+ STREAM_SKIP_UINT8(stream); // Skip the status field
+ STREAM_TO_UINT8(command_credits, stream);
+ }
+
+ return false;
+}
+
+// Send an internal command. Called by the vendor library, and also
+// internally by the HCI layer to fetch controller buffer sizes.
+static bool send_internal_command(uint16_t opcode, BT_HDR *packet, internal_command_cb callback) {
+ waiting_internal_command_t *wait_entry = (waiting_internal_command_t *)calloc(1, sizeof(waiting_internal_command_t));
+ if (!wait_entry) {
+ ALOGE("%s couldn't allocate space for wait entry.", __func__);
+ return false;
+ }
+
+ wait_entry->opcode = opcode;
+ wait_entry->callback = callback;
+
+ if (!fixed_queue_try_enqueue(waiting_internal_commands, wait_entry)) {
+ free(wait_entry);
+ ALOGE("%s too many waiting internal commands. Rejecting 0x%04X", __func__, opcode);
+ return false;
+ }
+
+ packet->layer_specific = opcode;
+ transmit_downward(packet->event, packet);
+ return true;
+}
+
+static void request_acl_buffer_size_callback(void *response) {
+ BT_HDR *packet = (BT_HDR *)response;
+ uint8_t *stream = packet->data;
+ uint16_t opcode;
+ uint8_t status;
+ uint16_t data_size = 0;
+
+ stream += 3; // Skip the event header fields, and the number of hci command packets field
+ STREAM_TO_UINT16(opcode, stream);
+ STREAM_TO_UINT8(status, stream);
+
+ if (status == 0)
+ STREAM_TO_UINT16(data_size, stream);
+
+ if (opcode == HCI_READ_BUFFER_SIZE) {
+ if (status == 0)
+ packet_fragmenter->set_acl_data_size(data_size);
+
+ // Now request the ble buffer size, using the same buffer
+ packet->event = HCI_LE_READ_BUFFER_SIZE;
+ packet->offset = 0;
+ packet->layer_specific = 0;
+ packet->len = HCI_COMMAND_PREAMBLE_SIZE;
+
+ stream = packet->data;
+ UINT16_TO_STREAM(stream, HCI_LE_READ_BUFFER_SIZE);
+ UINT8_TO_STREAM(stream, 0); // no parameters
+
+ if (!send_internal_command(HCI_LE_READ_BUFFER_SIZE, packet, request_acl_buffer_size_callback)) {
+ buffer_allocator->free(packet);
+ ALOGI("%s couldn't send ble read buffer command, so postload finished.", __func__);
+ }
+ } else if (opcode == HCI_LE_READ_BUFFER_SIZE) {
+ if (status == 0)
+ packet_fragmenter->set_ble_acl_data_size(data_size);
+
+ buffer_allocator->free(packet);
+ ALOGI("%s postload finished.", __func__);
+ } else {
+ ALOGE("%s unexpected opcode %d", __func__, opcode);
+ }
+}
+
+static void request_acl_buffer_size() {
+ ALOGI("%s", __func__);
+ BT_HDR *packet = (BT_HDR *)buffer_allocator->alloc(sizeof(BT_HDR) + HCI_COMMAND_PREAMBLE_SIZE);
+ if (!packet) {
+ ALOGE("%s couldn't get buffer for packet.", __func__);
+ return;
+ }
+
+ packet->event = MSG_STACK_TO_HC_HCI_CMD;
+ packet->offset = 0;
+ packet->layer_specific = 0;
+ packet->len = HCI_COMMAND_PREAMBLE_SIZE;
+
+ uint8_t *stream = packet->data;
+ UINT16_TO_STREAM(stream, HCI_READ_BUFFER_SIZE);
+ UINT8_TO_STREAM(stream, 0); // no parameters
+
+ if (!send_internal_command(HCI_READ_BUFFER_SIZE, packet, request_acl_buffer_size_callback)) {
+ buffer_allocator->free(packet);
+ ALOGE("%s couldn't send internal command, so postload aborted.", __func__);
+ }
+}
+
+static void sco_config_callback(UNUSED_ATTR bool success) {
+ request_acl_buffer_size();
+}
+
+static void firmware_config_callback(UNUSED_ATTR bool success) {
+ firmware_is_configured = true;
+ callbacks->preload_finished(true);
+}
+
+static void epilog_finished_callback(UNUSED_ATTR bool success) {
+ ALOGI("%s", __func__);
+ thread_stop(thread);
+}
+
+static void epilog_wait_timer_expired(UNUSED_ATTR void *context) {
+ ALOGI("%s", __func__);
+ thread_stop(thread);
+}
+
+static void start_epilog_wait_timer() {
+ alarm_set(epilog_alarm, EPILOG_TIMEOUT_MS, epilog_wait_timer_expired, NULL);
+}
+
+static void event_preload(UNUSED_ATTR void *context) {
+ ALOGI("%s", __func__);
+ hal->open();
+ vendor->send_async_command(VENDOR_CONFIGURE_FIRMWARE, NULL);
+}
+
+static void event_postload(UNUSED_ATTR void *context) {
+ ALOGI("%s", __func__);
+ if(vendor->send_async_command(VENDOR_CONFIGURE_SCO, NULL) == -1) {
+ // If couldn't configure sco, we won't get the sco configuration callback
+ // so go pretend to do it now
+ sco_config_callback(false);
+ }
+}
+
+static void event_epilog(UNUSED_ATTR void *context) {
+ vendor->send_async_command(VENDOR_DO_EPILOG, NULL);
+}
+
+static void event_command_ready(fixed_queue_t *queue, UNUSED_ATTR void *context) {
+ if (command_credits > 0) {
+ event_packet_ready(queue, context);
+ }
+}
+
+static void event_packet_ready(fixed_queue_t *queue, UNUSED_ATTR void *context) {
+ // The queue may be the command queue or the packet queue, we don't care
+ BT_HDR *packet = (BT_HDR *)fixed_queue_dequeue(queue);
+
+ low_power_manager->wake_assert();
+ packet_fragmenter->fragment_and_dispatch(packet);
+ low_power_manager->transmit_done();
+}
+
+// This function is not required to read all of a packet in one go, so
+// be wary of reentry. But this function must return after finishing a packet.
+static void hal_says_data_ready(serial_data_type_t type) {
+ packet_receive_data_t *incoming = &incoming_packets[PACKET_TYPE_TO_INBOUND_INDEX(type)];
+
+ while (hal->has_byte(type)) {
+ uint8_t byte = hal->read_byte(type);
+
+ switch (incoming->state) {
+ case BRAND_NEW:
+ // Initialize and prepare to jump to the preamble reading state
+ incoming->bytes_remaining = preamble_sizes[PACKET_TYPE_TO_INDEX(type)];
+ memset(incoming->preamble, 0, PREAMBLE_BUFFER_SIZE);
+ incoming->index = 0;
+ incoming->state = PREAMBLE;
+ // INTENTIONAL FALLTHROUGH
+ case PREAMBLE:
+ incoming->preamble[incoming->index] = byte;
+ incoming->index++;
+ incoming->bytes_remaining--;
+
+ if (incoming->bytes_remaining == 0) {
+ // For event and sco preambles, the last byte we read is the length
+ incoming->bytes_remaining = (type == DATA_TYPE_ACL) ? RETRIEVE_ACL_LENGTH(incoming->preamble) : byte;
+
+ size_t buffer_size = BT_HDR_SIZE + incoming->index + incoming->bytes_remaining;
+ incoming->buffer = (BT_HDR *)buffer_allocator->alloc(buffer_size);
+
+ if (!incoming->buffer) {
+ ALOGE("%s error getting buffer for incoming packet", __func__);
+ // Can't read any more of this current packet, so jump out
+ incoming->state = incoming->bytes_remaining == 0 ? BRAND_NEW : IGNORE;
+ break;
+ }
+
+ // Initialize the buffer
+ incoming->buffer->offset = 0;
+ incoming->buffer->layer_specific = 0;
+ incoming->buffer->event = outbound_event_types[PACKET_TYPE_TO_INDEX(type)];
+ memcpy(incoming->buffer->data, incoming->preamble, incoming->index);
+
+ incoming->state = incoming->bytes_remaining > 0 ? BODY : FINISHED;
+ }
+
+ break;
+ case BODY:
+ incoming->buffer->data[incoming->index] = byte;
+ incoming->index++;
+ incoming->bytes_remaining--;
+
+ // TODO(zachoverflow): consider reading in available bytes up to the length, instead of byte by byte
+
+ incoming->state = incoming->bytes_remaining == 0 ? FINISHED : incoming->state;
+ break;
+ case IGNORE:
+ incoming->bytes_remaining--;
+ incoming->state = incoming->bytes_remaining == 0 ? BRAND_NEW : incoming->state;
+ break;
+ case FINISHED:
+ ALOGE("%s the state machine should not have been left in the finished state.", __func__);
+ break;
+ }
+
+ if (incoming->state == FINISHED) {
+ incoming->buffer->len = incoming->index;
+ btsnoop->capture(incoming->buffer, true);
+
+ if (type != DATA_TYPE_EVENT || !filter_incoming_event(incoming->buffer)) {
+ packet_fragmenter->reassemble_and_dispatch(incoming->buffer);
+ }
+
+ // We don't control the buffer anymore
+ incoming->buffer = NULL;
+ incoming->state = BRAND_NEW;
+ hal->packet_finished(type);
+
+ // We return after a packet is finished for two reasons:
+ // 1. The type of the next packet could be different.
+ // 2. We don't want to hog cpu time.
+ return;
+ }
+ }
+}
+
+// TODO(zachoverflow): we seem to do this a couple places, like the HCI inject module. #centralize
+static serial_data_type_t event_to_data_type(uint16_t event) {
+ if (event == MSG_STACK_TO_HC_HCI_ACL)
+ return DATA_TYPE_ACL;
+ else if (event == MSG_STACK_TO_HC_HCI_SCO)
+ return DATA_TYPE_SCO;
+ else if (event == MSG_STACK_TO_HC_HCI_CMD)
+ return DATA_TYPE_COMMAND;
+ else
+ ALOGE("%s invalid event type, could not translate.", __func__);
+
+ return 0;
+}
+
+// Callback for the fragmenter to send a fragment
+static void transmit_fragment(BT_HDR *packet, bool send_transmit_finished) {
+ uint16_t opcode = 0;
+ uint8_t *stream = packet->data + packet->offset;
+ uint16_t event = packet->event & MSG_EVT_MASK;
+ serial_data_type_t type = event_to_data_type(event);
+
+ if (event == MSG_STACK_TO_HC_HCI_CMD) {
+ command_credits--;
+ STREAM_TO_UINT16(opcode, stream);
+ }
+
+ btsnoop->capture(packet, false);
+ hal->transmit_data(type, packet->data + packet->offset, packet->len);
+
+ if (event == MSG_STACK_TO_HC_HCI_CMD
+ && !fixed_queue_is_empty(waiting_internal_commands)
+ && packet->layer_specific == opcode) {
+ // This is an internal command, so nobody owns the buffer now
+ buffer_allocator->free(packet);
+ } else if (send_transmit_finished) {
+ callbacks->transmit_finished(packet, true);
+ }
+}
+
+// Callback for the fragmenter to dispatch up a completely reassembled packet
+static void dispatch_reassembled(BT_HDR *packet) {
+ data_dispatcher_dispatch(
+ interface.upward_dispatcher,
+ packet->event & MSG_EVT_MASK,
+ packet
+ );
+}
+
+static void fragmenter_transmit_finished(void *buffer, bool all_fragments_sent) {
+ callbacks->transmit_finished(buffer, all_fragments_sent);
+}
+
+static void init_layer_interface() {
+ if (!interface_created) {
+ interface.init = hci_init;
+ interface.cleanup = hci_cleanup;
+
+ interface.set_chip_power_on = set_chip_power_on;
+ interface.send_low_power_command = low_power_manager->post_command;
+ interface.do_preload = do_preload;
+ interface.do_postload = do_postload;
+ interface.turn_on_logging = turn_on_logging;
+ interface.turn_off_logging = turn_off_logging;
+
+ // It's probably ok for this to live forever. It's small and
+ // there's only one instance of the hci interface.
+ interface.upward_dispatcher = data_dispatcher_new("hci_layer");
+ if (!interface.upward_dispatcher) {
+ ALOGE("%s could not create upward dispatcher.", __func__);
+ return;
+ }
+
+ interface.transmit_downward = transmit_downward;
+ interface_created = true;
+ }
+}
+
+static const hci_hal_callbacks_t hal_callbacks = {
+ hal_says_data_ready
+};
+
+static const packet_fragmenter_callbacks_t packet_fragmenter_callbacks = {
+ transmit_fragment,
+ dispatch_reassembled,
+ fragmenter_transmit_finished
+};
+
+const hci_interface_t *hci_layer_get_interface() {
+ hal = hci_hal_get_interface();
+ btsnoop = btsnoop_get_interface();
+ hci_inject = hci_inject_get_interface();
+ packet_fragmenter = packet_fragmenter_get_interface();
+ vendor = vendor_get_interface();
+ low_power_manager = low_power_manager_get_interface();
+
+ init_layer_interface();
+ return &interface;
+}
+
+const hci_interface_t *hci_layer_get_test_interface(
+ const hci_hal_interface_t *hal_interface,
+ const btsnoop_interface_t *btsnoop_interface,
+ const hci_inject_interface_t *hci_inject_interface,
+ const packet_fragmenter_interface_t *packet_fragmenter_interface,
+ const vendor_interface_t *vendor_interface,
+ const low_power_manager_interface_t *low_power_manager_interface) {
+
+ hal = hal_interface;
+ btsnoop = btsnoop_interface;
+ hci_inject = hci_inject_interface;
+ packet_fragmenter = packet_fragmenter_interface;
+ vendor = vendor_interface;
+ low_power_manager = low_power_manager_interface;
+
+ init_layer_interface();
+ return &interface;
+}
diff --git a/hci/src/low_power_manager.c b/hci/src/low_power_manager.c
new file mode 100644
index 000000000..db09d50f9
--- /dev/null
+++ b/hci/src/low_power_manager.c
@@ -0,0 +1,242 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_low_power_manager"
+
+#include <assert.h>
+#include <stdint.h>
+#include <utils/Log.h>
+
+#include "alarm.h"
+#include "low_power_manager.h"
+#include "osi.h"
+#include "thread.h"
+#include "vendor.h"
+
+typedef enum {
+ LPM_DISABLED = 0,
+ LPM_ENABLED,
+ LPM_ENABLING,
+ LPM_DISABLING
+} low_power_mode_state_t;
+
+typedef enum {
+ LPM_WAKE_DEASSERTED = 0,
+ LPM_WAKE_W4_TX_DONE,
+ LPM_WAKE_W4_TIMEOUT,
+ LPM_WAKE_ASSERTED,
+} wake_state_t;
+
+// Our interface and modules we import
+static const low_power_manager_interface_t interface;
+static const vendor_interface_t *vendor;
+
+static void vendor_enable_disable_callback(bool success);
+
+static void event_disable(void *context);
+static void event_enable(void *context);
+static void event_wake_assert(void *context);
+static void event_allow_device_sleep(void *context);
+static void event_idle_timeout(void *context);
+
+static void reset_state();
+static void start_idle_timer();
+static void stop_idle_timer();
+
+static thread_fn event_functions[] = {
+ event_disable,
+ event_enable,
+ event_wake_assert,
+ event_allow_device_sleep
+};
+
+static thread_t *thread;
+static low_power_mode_state_t state;
+static wake_state_t wake_state;
+static uint32_t idle_timeout_ms;
+static alarm_t *idle_alarm;
+static bool transmit_is_done;
+
+// Interface functions
+
+static void init(thread_t *post_thread) {
+ assert(post_thread != NULL);
+ thread = post_thread;
+
+ vendor->set_callback(VENDOR_SET_LPM_MODE, vendor_enable_disable_callback);
+ vendor->send_command(VENDOR_GET_LPM_IDLE_TIMEOUT, &idle_timeout_ms);
+
+ idle_alarm = alarm_new();
+ if (!idle_alarm) {
+ ALOGE("%s could not create idle alarm.", __func__);
+ }
+
+ reset_state();
+}
+
+static void cleanup() {
+ reset_state();
+ alarm_free(idle_alarm);
+ idle_alarm = NULL;
+}
+
+static void post_command(low_power_command_t command) {
+ if (command > LPM_WAKE_DEASSERT) {
+ ALOGE("%s unknown low power command %d", __func__, command);
+ return;
+ }
+
+ thread_post(thread, event_functions[command], NULL);
+}
+
+static void wake_assert() {
+ if (state != LPM_DISABLED) {
+ stop_idle_timer();
+
+ uint8_t new_state = BT_VND_LPM_WAKE_ASSERT;
+ vendor->send_command(VENDOR_SET_LPM_WAKE_STATE, &new_state);
+ wake_state = LPM_WAKE_ASSERTED;
+ }
+
+ // TODO(zachoverflow): investigate this interaction. If someone above
+ // HCI asserts wake, we'll wait until we transmit before deasserting.
+ // That doesn't seem quite right.
+ transmit_is_done = false;
+}
+
+static void transmit_done() {
+ transmit_is_done = true;
+ if (wake_state == LPM_WAKE_W4_TX_DONE) {
+ wake_state = LPM_WAKE_W4_TIMEOUT;
+ start_idle_timer();
+ }
+}
+
+// Internal functions
+
+static void enable(bool enable) {
+ if (state == LPM_DISABLING) {
+ if (enable)
+ ALOGE("%s still processing prior disable request, cannot enable.", __func__);
+ else
+ ALOGW("%s still processing prior disable request, ignoring new request to disable.", __func__);
+ } else if (state == LPM_ENABLING) {
+ if (enable)
+ ALOGE("%s still processing prior enable request, ignoring new request to enable.", __func__);
+ else
+ ALOGW("%s still processing prior enable request, cannot disable.", __func__);
+ } else if (state == LPM_ENABLED && enable) {
+ ALOGI("%s already enabled.", __func__);
+ } else if (state == LPM_DISABLED && !enable) {
+ ALOGI("%s already disabled.", __func__);
+ } else {
+ uint8_t command = enable ? BT_VND_LPM_ENABLE : BT_VND_LPM_DISABLE;
+ state = enable ? LPM_ENABLING : LPM_DISABLING;
+ vendor->send_async_command(VENDOR_SET_LPM_MODE, &command);
+ }
+}
+
+static void allow_device_sleep() {
+ if (state == LPM_ENABLED && wake_state == LPM_WAKE_ASSERTED) {
+ if (transmit_is_done) {
+ wake_state = LPM_WAKE_W4_TIMEOUT;
+ start_idle_timer();
+ } else {
+ wake_state = LPM_WAKE_W4_TX_DONE;
+ }
+ }
+}
+
+static void wake_deassert() {
+ if (state == LPM_ENABLED && transmit_is_done) {
+ uint8_t new_state = BT_VND_LPM_WAKE_DEASSERT;
+ vendor->send_command(VENDOR_SET_LPM_WAKE_STATE, &new_state);
+ wake_state = LPM_WAKE_DEASSERTED;
+ }
+}
+
+static void reset_state() {
+ state = LPM_DISABLED;
+ wake_state = LPM_WAKE_DEASSERTED;
+ transmit_is_done = true;
+ stop_idle_timer();
+}
+
+static void idle_timer_expired(UNUSED_ATTR void *context) {
+ if (state == LPM_ENABLED && wake_state == LPM_WAKE_W4_TIMEOUT)
+ thread_post(thread, event_idle_timeout, NULL);
+}
+
+static void start_idle_timer() {
+ if (state == LPM_ENABLED) {
+ alarm_set(idle_alarm, idle_timeout_ms, idle_timer_expired, NULL);
+ }
+}
+
+static void stop_idle_timer() {
+ alarm_cancel(idle_alarm);
+}
+
+static void event_disable(UNUSED_ATTR void *context) {
+ enable(false);
+}
+
+static void event_enable(UNUSED_ATTR void *context) {
+ enable(true);
+}
+
+static void event_wake_assert(UNUSED_ATTR void *context) {
+ wake_assert();
+}
+
+static void event_allow_device_sleep(UNUSED_ATTR void *context) {
+ allow_device_sleep();
+}
+
+static void event_idle_timeout(UNUSED_ATTR void *context) {
+ wake_deassert();
+}
+
+static void vendor_enable_disable_callback(bool success) {
+ if (success)
+ state = (state == LPM_ENABLING) ? LPM_ENABLED : LPM_DISABLED;
+ else
+ state = (state == LPM_ENABLING) ? LPM_DISABLED : LPM_ENABLED;
+
+ if (state == LPM_DISABLED) {
+ reset_state();
+ }
+}
+
+static const low_power_manager_interface_t interface = {
+ init,
+ cleanup,
+ post_command,
+ wake_assert,
+ transmit_done
+};
+
+const low_power_manager_interface_t *low_power_manager_get_interface() {
+ vendor = vendor_get_interface();
+ return &interface;
+}
+
+const low_power_manager_interface_t *low_power_manager_get_test_interface(const vendor_interface_t *vendor_interface) {
+ vendor = vendor_interface;
+ return &interface;
+}
diff --git a/hci/src/lpm.c b/hci/src/lpm.c
deleted file mode 100644
index d8c7e363f..000000000
--- a/hci/src/lpm.c
+++ /dev/null
@@ -1,362 +0,0 @@
-/******************************************************************************
- *
- * Copyright (C) 2009-2012 Broadcom Corporation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- ******************************************************************************/
-
-/******************************************************************************
- *
- * Filename: lpm.c
- *
- * Description: Contains low power mode implementation
- *
- ******************************************************************************/
-
-#define LOG_TAG "bt_lpm"
-
-#include <utils/Log.h>
-
-#include "alarm.h"
-#include "bt_hci_bdroid.h"
-#include "bt_vendor_lib.h"
-#include "bt_utils.h"
-#include "osi.h"
-#include "vendor.h"
-
-/******************************************************************************
-** Constants & Macros
-******************************************************************************/
-
-#ifndef BTLPM_DBG
-#define BTLPM_DBG FALSE
-#endif
-
-#if (BTLPM_DBG == TRUE)
-#define BTLPMDBG(param, ...) {ALOGD(param, ## __VA_ARGS__);}
-#else
-#define BTLPMDBG(param, ...) {}
-#endif
-
-#ifndef DEFAULT_LPM_IDLE_TIMEOUT
-#define DEFAULT_LPM_IDLE_TIMEOUT 3000
-#endif
-
-/******************************************************************************
-** Externs
-******************************************************************************/
-
-/******************************************************************************
-** Local type definitions
-******************************************************************************/
-
-/* Low power mode state */
-enum {
- LPM_DISABLED = 0, /* initial state */
- LPM_ENABLED,
- LPM_ENABLING,
- LPM_DISABLING
-};
-
-/* LPM WAKE state */
-enum {
- LPM_WAKE_DEASSERTED = 0, /* initial state */
- LPM_WAKE_W4_TX_DONE,
- LPM_WAKE_W4_TIMEOUT,
- LPM_WAKE_ASSERTED
-};
-
-/* low power mode control block */
-typedef struct
-{
- uint8_t state; /* Low power mode state */
- uint8_t wake_state; /* LPM WAKE state */
- uint8_t no_tx_data;
- alarm_t *alarm;
- uint32_t timeout_ms;
-} bt_lpm_cb_t;
-
-
-/******************************************************************************
-** Static variables
-******************************************************************************/
-
-static bt_lpm_cb_t bt_lpm_cb;
-
-/******************************************************************************
-** LPM Static Functions
-******************************************************************************/
-
-/*******************************************************************************
-**
-** Function lpm_idle_timeout
-**
-** Description Timeout thread of transport idle timer
-**
-** Returns None
-**
-*******************************************************************************/
-static void lpm_idle_timeout(UNUSED_ATTR void *context)
-{
- BTLPMDBG("..lpm_idle_timeout..");
-
- if ((bt_lpm_cb.state == LPM_ENABLED) &&
- (bt_lpm_cb.wake_state == LPM_WAKE_W4_TIMEOUT))
- {
- bthc_idle_timeout();
- }
-}
-
-/*******************************************************************************
-**
-** Function lpm_start_transport_idle_timer
-**
-** Description Launch transport idle timer
-**
-** Returns None
-**
-*******************************************************************************/
-static void lpm_start_transport_idle_timer(void)
-{
- if (bt_lpm_cb.state != LPM_ENABLED)
- return;
-
- alarm_set(bt_lpm_cb.alarm, bt_lpm_cb.timeout_ms, lpm_idle_timeout, NULL);
-}
-
-/*******************************************************************************
-**
-** Function lpm_stop_transport_idle_timer
-**
-** Description Launch transport idle timer
-**
-** Returns None
-**
-*******************************************************************************/
-static void lpm_stop_transport_idle_timer(void)
-{
- alarm_cancel(bt_lpm_cb.alarm);
-}
-
-/*******************************************************************************
-**
-** Function lpm_vnd_cback
-**
-** Description Callback of vendor specific result for lpm enable/disable
-** rquest
-**
-** Returns None
-**
-*******************************************************************************/
-void lpm_vnd_cback(uint8_t vnd_result)
-{
- if (vnd_result == 0)
- {
- /* Status == Success */
- bt_lpm_cb.state = (bt_lpm_cb.state == LPM_ENABLING) ? \
- LPM_ENABLED : LPM_DISABLED;
- }
- else
- {
- bt_lpm_cb.state = (bt_lpm_cb.state == LPM_ENABLING) ? \
- LPM_DISABLED : LPM_ENABLED;
- }
-
- if (bt_hc_cbacks)
- {
- if (bt_lpm_cb.state == LPM_ENABLED)
- bt_hc_cbacks->lpm_cb(BT_HC_LPM_ENABLED);
- else
- bt_hc_cbacks->lpm_cb(BT_HC_LPM_DISABLED);
- }
-
- if (bt_lpm_cb.state == LPM_DISABLED)
- {
- alarm_free(bt_lpm_cb.alarm);
- memset(&bt_lpm_cb, 0, sizeof(bt_lpm_cb_t));
- }
-}
-
-
-/*****************************************************************************
-** Low Power Mode Interface Functions
-*****************************************************************************/
-
-/*******************************************************************************
-**
-** Function lpm_init
-**
-** Description Init LPM
-**
-** Returns None
-**
-*******************************************************************************/
-void lpm_init(void)
-{
- memset(&bt_lpm_cb, 0, sizeof(bt_lpm_cb_t));
- vendor_send_command(BT_VND_OP_GET_LPM_IDLE_TIMEOUT, &bt_lpm_cb.timeout_ms);
- bt_lpm_cb.alarm = alarm_new();
-}
-
-/*******************************************************************************
-**
-** Function lpm_cleanup
-**
-** Description Clean up
-**
-** Returns None
-**
-*******************************************************************************/
-void lpm_cleanup(void)
-{
- alarm_free(bt_lpm_cb.alarm);
- bt_lpm_cb.alarm = NULL;
-}
-
-/*******************************************************************************
-**
-** Function lpm_enable
-**
-** Description Enalbe/Disable LPM
-**
-** Returns None
-**
-*******************************************************************************/
-void lpm_enable(uint8_t turn_on)
-{
- if ((bt_lpm_cb.state!=LPM_DISABLED) && (bt_lpm_cb.state!=LPM_ENABLED))
- {
- ALOGW("Still busy on processing prior LPM enable/disable request...");
- return;
- }
-
- if ((turn_on == TRUE) && (bt_lpm_cb.state == LPM_ENABLED))
- {
- ALOGI("LPM is already on!!!");
- if (bt_hc_cbacks)
- bt_hc_cbacks->lpm_cb(BT_HC_LPM_ENABLED);
- }
- else if ((turn_on == FALSE) && (bt_lpm_cb.state == LPM_DISABLED))
- {
- ALOGI("LPM is already off!!!");
- if (bt_hc_cbacks)
- bt_hc_cbacks->lpm_cb(BT_HC_LPM_DISABLED);
- }
-
- uint8_t lpm_cmd = (turn_on) ? BT_VND_LPM_ENABLE : BT_VND_LPM_DISABLE;
- bt_lpm_cb.state = (turn_on) ? LPM_ENABLING : LPM_DISABLING;
- vendor_send_command(BT_VND_OP_LPM_SET_MODE, &lpm_cmd);
-}
-
-/*******************************************************************************
-**
-** Function lpm_tx_done
-**
-** Description This function is to inform the lpm module
-** if data is waiting in the Tx Q or not.
-**
-** IsTxDone: TRUE if All data in the Tx Q are gone
-** FALSE if any data is still in the Tx Q.
-** Typicaly this function must be called
-** before USERIAL Write and in the Tx Done routine
-**
-** Returns None
-**
-*******************************************************************************/
-void lpm_tx_done(uint8_t is_tx_done)
-{
- bt_lpm_cb.no_tx_data = is_tx_done;
-
- if ((bt_lpm_cb.wake_state==LPM_WAKE_W4_TX_DONE) && (is_tx_done==TRUE))
- {
- bt_lpm_cb.wake_state = LPM_WAKE_W4_TIMEOUT;
- lpm_start_transport_idle_timer();
- }
-}
-
-/*******************************************************************************
-**
-** Function lpm_wake_assert
-**
-** Description Called to wake up Bluetooth chip.
-** Normally this is called when there is data to be sent
-** over UART.
-**
-** Returns TRUE/FALSE
-**
-*******************************************************************************/
-void lpm_wake_assert(void)
-{
- if (bt_lpm_cb.state != LPM_DISABLED)
- {
- BTLPMDBG("LPM WAKE assert");
-
- /* Calling vendor-specific part */
- uint8_t state = BT_VND_LPM_WAKE_ASSERT;
- vendor_send_command(BT_VND_OP_LPM_WAKE_SET_STATE, &state);
-
- lpm_stop_transport_idle_timer();
-
- bt_lpm_cb.wake_state = LPM_WAKE_ASSERTED;
- }
-
- lpm_tx_done(FALSE);
-}
-
-/*******************************************************************************
-**
-** Function lpm_allow_bt_device_sleep
-**
-** Description Start LPM idle timer if allowed
-**
-** Returns None
-**
-*******************************************************************************/
-void lpm_allow_bt_device_sleep(void)
-{
- if ((bt_lpm_cb.state == LPM_ENABLED) && \
- (bt_lpm_cb.wake_state == LPM_WAKE_ASSERTED))
- {
- if(bt_lpm_cb.no_tx_data == TRUE)
- {
- bt_lpm_cb.wake_state = LPM_WAKE_W4_TIMEOUT;
- lpm_start_transport_idle_timer();
- }
- else
- {
- bt_lpm_cb.wake_state = LPM_WAKE_W4_TX_DONE;
- }
- }
-}
-
-/*******************************************************************************
-**
-** Function lpm_wake_deassert
-**
-** Description Deassert wake if allowed
-**
-** Returns None
-**
-*******************************************************************************/
-void lpm_wake_deassert(void)
-{
- if ((bt_lpm_cb.state == LPM_ENABLED) && (bt_lpm_cb.no_tx_data == TRUE))
- {
- BTLPMDBG("LPM WAKE deassert");
-
- uint8_t state = BT_VND_LPM_WAKE_DEASSERT;
- vendor_send_command(BT_VND_OP_LPM_WAKE_SET_STATE, &state);
- bt_lpm_cb.wake_state = LPM_WAKE_DEASSERTED;
- }
-}
diff --git a/hci/src/packet_fragmenter.c b/hci/src/packet_fragmenter.c
new file mode 100644
index 000000000..7e018a1ea
--- /dev/null
+++ b/hci/src/packet_fragmenter.c
@@ -0,0 +1,232 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "hci_hal_h4"
+
+#include <assert.h>
+#include <utils/Log.h>
+
+#include "hash_map.h"
+#include "hci_internals.h"
+#include "hci_layer.h"
+#include "packet_fragmenter.h"
+#include "osi.h"
+
+#define APPLY_CONTINUATION_FLAG(handle) (((handle) & 0xCFFF) | 0x1000)
+#define APPLY_START_FLAG(handle) (((handle) & 0xCFFF) | 0x2000)
+#define SUB_EVENT(event) ((event) & MSG_SUB_EVT_MASK)
+#define GET_BOUNDARY_FLAG(handle) (((handle) >> 12) & 0x0003)
+
+#define HANDLE_MASK 0x0FFF
+#define START_PACKET_BOUNDARY 2
+#define CONTINUATION_PACKET_BOUNDARY 1
+#define L2CAP_HEADER_SIZE 4
+
+// TODO(zachoverflow): find good value for this
+#define NUMBER_OF_BUCKETS 42
+
+// Our interface and callbacks
+static const packet_fragmenter_interface_t interface;
+static const allocator_t *allocator;
+static const packet_fragmenter_callbacks_t *callbacks;
+
+static uint16_t acl_data_size;
+static uint16_t ble_acl_data_size;
+static hash_map_t *partial_packets;
+
+static hash_index_t default_hash_function(const void *key);
+
+static void init(const packet_fragmenter_callbacks_t *result_callbacks, const allocator_t *buffer_allocator) {
+ allocator = buffer_allocator;
+ callbacks = result_callbacks;
+
+ // Give initial values for the data sizes, which will
+ // be updated when we talk to the actual controller
+ acl_data_size = 1021;
+ ble_acl_data_size = 27;
+
+ if (partial_packets)
+ hash_map_free(partial_packets);
+
+ partial_packets = hash_map_new(NUMBER_OF_BUCKETS, default_hash_function, NULL, NULL);
+}
+
+static void set_acl_data_size(uint16_t size) {
+ assert(size > 0);
+ acl_data_size = size;
+}
+
+static void set_ble_acl_data_size(uint16_t size) {
+ // If the ble acl data size is zero, the ble acl buffers are the same size
+ // as the normal ones.
+ ble_acl_data_size = size == 0 ? acl_data_size : size;
+}
+
+static void fragment_and_dispatch(BT_HDR *packet) {
+ assert(packet != NULL);
+
+ uint16_t remaining_length = packet->len;
+ uint16_t event = packet->event & MSG_EVT_MASK;
+ uint16_t max_data_size = SUB_EVENT(packet->event) == LOCAL_BR_EDR_CONTROLLER_ID ? acl_data_size : ble_acl_data_size;
+ uint16_t max_packet_size = max_data_size + HCI_ACL_PREAMBLE_SIZE;
+
+ uint8_t *stream = packet->data + packet->offset;
+
+ if (event == MSG_STACK_TO_HC_HCI_ACL && remaining_length > max_packet_size) {
+ uint16_t continuation_handle;
+ STREAM_TO_UINT16(continuation_handle, stream);
+ continuation_handle = APPLY_CONTINUATION_FLAG(continuation_handle);
+
+ while (remaining_length > max_packet_size) {
+ // Make sure we use the right ACL packet size
+ stream = packet->data + packet->offset;
+ STREAM_SKIP_UINT16(stream);
+ UINT16_TO_STREAM(stream, max_data_size);
+
+ packet->len = max_packet_size;
+ callbacks->fragmented(packet, false);
+
+ packet->offset += max_data_size;
+ remaining_length -= max_data_size;
+ packet->len = remaining_length;
+
+ // Write the ACL header for the next fragment
+ stream = packet->data + packet->offset;
+ UINT16_TO_STREAM(stream, continuation_handle);
+ UINT16_TO_STREAM(stream, remaining_length - HCI_ACL_PREAMBLE_SIZE);
+
+ // Apparently L2CAP can set layer_specific to a max number of segments to transmit
+ if (packet->layer_specific) {
+ packet->layer_specific--;
+
+ if (packet->layer_specific == 0) {
+ packet->event = MSG_HC_TO_STACK_L2C_SEG_XMIT;
+ callbacks->transmit_finished(packet, false);
+ return;
+ }
+ }
+ }
+ }
+
+ callbacks->fragmented(packet, true);
+}
+
+static void reassemble_and_dispatch(UNUSED_ATTR BT_HDR *packet) {
+ if ((packet->event & MSG_EVT_MASK) == MSG_HC_TO_STACK_HCI_ACL) {
+ uint8_t *stream = packet->data;
+ uint16_t handle;
+ uint16_t l2cap_length;
+ uint16_t acl_length;
+
+ STREAM_TO_UINT16(handle, stream);
+ STREAM_TO_UINT16(acl_length, stream);
+ STREAM_TO_UINT16(l2cap_length, stream);
+
+ assert(acl_length == packet->len - HCI_ACL_PREAMBLE_SIZE);
+
+ uint8_t boundary_flag = GET_BOUNDARY_FLAG(handle);
+ handle = handle & HANDLE_MASK;
+
+ BT_HDR *partial_packet = (BT_HDR *)hash_map_get(partial_packets, (void *)(uintptr_t)handle);
+
+ if (boundary_flag == START_PACKET_BOUNDARY) {
+ if (partial_packet) {
+ ALOGW("%s found unfinished packet for handle with start packet. Dropping old.", __func__);
+
+ hash_map_erase(partial_packets, (void *)(uintptr_t)handle);
+ allocator->free(partial_packet);
+ }
+
+ uint16_t full_length = l2cap_length + L2CAP_HEADER_SIZE + HCI_ACL_PREAMBLE_SIZE;
+ if (full_length <= packet->len) {
+ if (full_length < packet->len)
+ ALOGW("%s found l2cap full length %d less than the hci length %d.", __func__, l2cap_length, packet->len);
+
+ callbacks->reassembled(packet);
+ return;
+ }
+
+ partial_packet = (BT_HDR *)allocator->alloc(full_length + sizeof(BT_HDR));
+ partial_packet->event = packet->event;
+ partial_packet->len = full_length;
+ partial_packet->offset = packet->len;
+
+ memcpy(partial_packet->data, packet->data, packet->len);
+
+ // Update the ACL data size to indicate the full expected length
+ stream = partial_packet->data;
+ STREAM_SKIP_UINT16(stream); // skip the handle
+ UINT16_TO_STREAM(stream, full_length - HCI_ACL_PREAMBLE_SIZE);
+
+ hash_map_set(partial_packets, (void *)(uintptr_t)handle, partial_packet);
+ // Free the old packet buffer, since we don't need it anymore
+ allocator->free(packet);
+ } else {
+ if (!partial_packet) {
+ ALOGW("%s got continuation for unknown packet. Dropping it.", __func__);
+ allocator->free(packet);
+ return;
+ }
+
+ packet->offset = HCI_ACL_PREAMBLE_SIZE;
+ uint16_t projected_offset = partial_packet->offset + (packet->len - HCI_ACL_PREAMBLE_SIZE);
+ if (projected_offset > partial_packet->len) { // len stores the expected length
+ ALOGW("%s got packet which would exceed expected length of %d. Truncating.", __func__, partial_packet->len);
+ packet->len = partial_packet->len - partial_packet->offset;
+ projected_offset = partial_packet->len;
+ }
+
+ memcpy(
+ partial_packet->data + partial_packet->offset,
+ packet->data + packet->offset,
+ packet->len - packet->offset
+ );
+
+ // Free the old packet buffer, since we don't need it anymore
+ allocator->free(packet);
+ partial_packet->offset = projected_offset;
+
+ if (partial_packet->offset == partial_packet->len) {
+ hash_map_erase(partial_packets, (void *)(uintptr_t)handle);
+ partial_packet->offset = 0;
+ callbacks->reassembled(partial_packet);
+ }
+ }
+ } else {
+ callbacks->reassembled(packet);
+ }
+}
+
+static hash_index_t default_hash_function(const void *key) {
+ hash_index_t hash_key = (hash_index_t)key;
+ return hash_key;
+}
+
+static const packet_fragmenter_interface_t interface = {
+ init,
+
+ set_acl_data_size,
+ set_ble_acl_data_size,
+
+ fragment_and_dispatch,
+ reassemble_and_dispatch
+};
+
+const packet_fragmenter_interface_t *packet_fragmenter_get_interface() {
+ return &interface;
+}
diff --git a/hci/src/userial.c b/hci/src/userial.c
deleted file mode 100644
index e3f35578c..000000000
--- a/hci/src/userial.c
+++ /dev/null
@@ -1,418 +0,0 @@
-/******************************************************************************
- *
- * Copyright (C) 2009-2012 Broadcom Corporation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- ******************************************************************************/
-
-/******************************************************************************
- *
- * Filename: userial.c
- *
- * Description: Contains open/read/write/close functions on serial port
- *
- ******************************************************************************/
-
-#define LOG_TAG "bt_userial"
-
-#include <assert.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <pthread.h>
-#include <stdio.h>
-#include <sys/eventfd.h>
-#include <sys/prctl.h>
-#include <sys/socket.h>
-#include <utils/Log.h>
-
-#include "bt_hci_bdroid.h"
-#include "bt_utils.h"
-#include "bt_vendor_lib.h"
-#include "userial.h"
-#include "utils.h"
-#include "vendor.h"
-
-/******************************************************************************
-** Constants & Macros
-******************************************************************************/
-
-#ifndef USERIAL_DBG
-#define USERIAL_DBG TRUE
-#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)
-
-// The set of events one can send to the userial read thread.
-// Note that the values must be >= 0x8000000000000000 to guarantee delivery
-// of the message (see eventfd(2) for details on blocking behaviour).
-enum {
- USERIAL_RX_EXIT = 0x8000000000000000ULL
-};
-
-/******************************************************************************
-** Externs
-******************************************************************************/
-
-/******************************************************************************
-** Local type definitions
-******************************************************************************/
-
-typedef struct
-{
- int fd;
- 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;
-
-/*****************************************************************************
-** 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 event_fd = -1;
-
-static inline int add_event_fd(fd_set *set) {
- if (event_fd == -1) {
- event_fd = eventfd(0, 0);
- if (event_fd == -1) {
- ALOGE("%s unable to create event fd: %s", __func__, strerror(errno));
- return -1;
- }
- }
-
- FD_SET(event_fd, set);
- return event_fd;
-}
-
-static inline void send_event(uint64_t event_id) {
- assert(event_fd != -1);
- eventfd_write(event_fd, event_id);
-}
-
-static inline uint64_t read_event() {
- assert(event_fd != -1);
-
- uint64_t value = 0;
- eventfd_read(event_fd, &value);
- return value;
-}
-
-static inline bool is_event_available(fd_set *set) {
- assert(event_fd != -1);
- return !!FD_ISSET(event_fd, set);
-}
-
-/*******************************************************************************
-**
-** Function select_read
-**
-** Description check if fd is ready for reading and listen for termination
-** signal. need to use select in order to avoid collision
-** between read and close on the same fd
-**
-** Returns -1: termination
-** >=0: numbers of bytes read back from fd
-**
-*******************************************************************************/
-static int select_read(int fd, uint8_t *pbuf, int len)
-{
- fd_set input;
- int n = 0, ret = -1;
-
- while (userial_running)
- {
- /* Initialize the input fd set */
- FD_ZERO(&input);
- FD_SET(fd, &input);
- int fd_max = add_event_fd(&input);
- fd_max = fd_max > fd ? fd_max : fd;
-
- /* Do the select */
- n = select(fd_max+1, &input, NULL, NULL, NULL);
- if(is_event_available(&input))
- {
- uint64_t event = read_event();
- switch (event) {
- case USERIAL_RX_EXIT:
- USERIALDBG("RX termination");
- return -1;
- }
- }
-
- if (n > 0)
- {
- /* We might have input */
- if (FD_ISSET(fd, &input))
- {
- ret = read(fd, pbuf, (size_t)len);
- if (0 == ret)
- ALOGW( "read() returned 0!" );
-
- return ret;
- }
- }
- else if (n < 0)
- ALOGW( "select() Failed");
- else if (n == 0)
- ALOGW( "Got a select() TIMEOUT");
-
- }
-
- return ret;
-}
-
-static void *userial_read_thread(void *arg)
-{
- int rx_length = 0;
- HC_BT_HDR *p_buf = NULL;
- uint8_t *p;
- UNUSED(arg);
-
- USERIALDBG("Entering userial_read_thread()");
- prctl(PR_SET_NAME, (unsigned long)"userial_read", 0, 0, 0);
-
- userial_running = 1;
-
- raise_priority_a2dp(TASK_HIGH_USERIAL_READ);
-
- while (userial_running)
- {
- if (bt_hc_cbacks)
- {
- p_buf = (HC_BT_HDR *) bt_hc_cbacks->alloc(
- BT_HC_HDR_SIZE + HCI_MAX_FRAME_SIZE + 1); /* H4 HDR = 1 */
- }
- else
- p_buf = NULL;
-
- if (p_buf != NULL)
- {
- p_buf->offset = 0;
- p_buf->layer_specific = 0;
-
- p = (uint8_t *) (p_buf + 1);
- int userial_fd = userial_cb.fd;
- if (userial_fd != -1)
- rx_length = select_read(userial_fd, p, HCI_MAX_FRAME_SIZE + 1);
- else
- rx_length = 0;
- }
- else
- {
- rx_length = 0;
- utils_delay(100);
- ALOGW("userial_read_thread() failed to gain buffers");
- continue;
- }
-
-
- if (rx_length > 0)
- {
- p_buf->len = (uint16_t)rx_length;
- utils_enqueue(&(userial_cb.rx_q), p_buf);
- bthc_rx_ready();
- }
- else /* either 0 or < 0 */
- {
- ALOGW("select_read return size <=0:%d, exiting userial_read_thread",\
- rx_length);
- /* if we get here, we should have a buffer */
- bt_hc_cbacks->dealloc(p_buf);
- /* negative value means exit thread */
- break;
- }
- } /* for */
-
- userial_running = 0;
- USERIALDBG("Leaving userial_read_thread()");
- pthread_exit(NULL);
-
- return NULL; // Compiler friendly
-}
-
-
-/*****************************************************************************
-** Userial API Functions
-*****************************************************************************/
-
-bool userial_init(void)
-{
- USERIALDBG("userial_init");
- memset(&userial_cb, 0, sizeof(tUSERIAL_CB));
- userial_cb.fd = -1;
- utils_queue_init(&userial_cb.rx_q);
- return true;
-}
-
-bool userial_open(userial_port_t port) {
- if (port >= MAX_SERIAL_PORT) {
- ALOGE("%s serial port %d > %d (max).", __func__, port, MAX_SERIAL_PORT);
- return false;
- }
-
- if (userial_running) {
- userial_close();
- utils_delay(50);
- }
-
- // Call in to the vendor-specific library to open the serial port.
- int fd_array[CH_MAX];
- for (int i = 0; i < CH_MAX; i++)
- fd_array[i] = -1;
-
- int num_ports = vendor_send_command(BT_VND_OP_USERIAL_OPEN, &fd_array);
-
- if (num_ports != 1) {
- ALOGE("%s opened wrong number of ports: got %d, expected 1.", __func__, num_ports);
- goto error;
- }
-
- userial_cb.fd = fd_array[0];
- if (userial_cb.fd == -1) {
- ALOGE("%s unable to open serial port.", __func__);
- goto error;
- }
-
- userial_cb.port = port;
-
- if (pthread_create(&userial_cb.read_thread, NULL, userial_read_thread, NULL)) {
- ALOGE("%s unable to spawn read thread.", __func__);
- goto error;
- }
-
- return true;
-
-error:
- vendor_send_command(BT_VND_OP_USERIAL_CLOSE, NULL);
- return false;
-}
-
-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;
- uint8_t *p_data = NULL;
- UNUSED(msg_id);
-
- do
- {
- if(userial_cb.p_rx_hdr != NULL)
- {
- p_data = ((uint8_t *)(userial_cb.p_rx_hdr + 1)) + \
- (userial_cb.p_rx_hdr->offset);
-
- if((userial_cb.p_rx_hdr->len) <= (len - total_len))
- copy_len = userial_cb.p_rx_hdr->len;
- else
- copy_len = (len - total_len);
-
- memcpy((p_buffer + total_len), p_data, copy_len);
-
- total_len += copy_len;
-
- userial_cb.p_rx_hdr->offset += copy_len;
- userial_cb.p_rx_hdr->len -= copy_len;
-
- if(userial_cb.p_rx_hdr->len == 0)
- {
- if (bt_hc_cbacks)
- bt_hc_cbacks->dealloc(userial_cb.p_rx_hdr);
-
- userial_cb.p_rx_hdr = NULL;
- }
- }
-
- if(userial_cb.p_rx_hdr == NULL)
- {
- userial_cb.p_rx_hdr=(HC_BT_HDR *)utils_dequeue(&(userial_cb.rx_q));
- }
- } while ((userial_cb.p_rx_hdr != NULL) && (total_len < len));
-
- return total_len;
-}
-
-uint16_t userial_write(uint16_t msg_id, const uint8_t *p_data, uint16_t len) {
- UNUSED(msg_id);
-
- uint16_t total = 0;
- while (len) {
- ssize_t ret = write(userial_cb.fd, p_data + total, len);
- switch (ret) {
- case -1:
- ALOGE("%s error writing to serial port: %s", __func__, strerror(errno));
- return total;
- case 0: // don't loop forever in case write returns 0.
- return total;
- default:
- total += ret;
- len -= ret;
- break;
- }
- }
-
- return total;
-}
-
-void userial_close_reader(void) {
- // Join the reader thread if it is still running.
- if (userial_running) {
- send_event(USERIAL_RX_EXIT);
- int result = pthread_join(userial_cb.read_thread, NULL);
- USERIALDBG("%s Joined userial reader thread: %d", __func__, result);
- if (result)
- ALOGE("%s failed to join reader thread: %d", __func__, result);
- return;
- }
- ALOGW("%s Already closed userial reader thread", __func__);
-}
-
-void userial_close(void) {
- assert(bt_hc_cbacks != NULL);
-
- // Join the reader thread if it's still running.
- if (userial_running) {
- send_event(USERIAL_RX_EXIT);
- int result = pthread_join(userial_cb.read_thread, NULL);
- if (result)
- ALOGE("%s failed to join reader thread: %d", __func__, result);
- }
-
- // Ask the vendor-specific library to close the serial port.
- vendor_send_command(BT_VND_OP_USERIAL_CLOSE, NULL);
-
- // Free all buffers still waiting in the RX queue.
- // TODO: use list data structure and clean this up.
- void *buf;
- while ((buf = utils_dequeue(&userial_cb.rx_q)) != NULL)
- bt_hc_cbacks->dealloc(buf);
-
- userial_cb.fd = -1;
-}
diff --git a/hci/src/utils.c b/hci/src/utils.c
deleted file mode 100644
index 85304fa81..000000000
--- a/hci/src/utils.c
+++ /dev/null
@@ -1,309 +0,0 @@
-/******************************************************************************
- *
- * Copyright (C) 2009-2012 Broadcom Corporation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- ******************************************************************************/
-
-/******************************************************************************
- *
- * Filename: utils.c
- *
- * Description: Contains helper functions
- *
- ******************************************************************************/
-
-#include <errno.h>
-#include <pthread.h>
-#include <time.h>
-#include "bt_hci_bdroid.h"
-#include "utils.h"
-
-/******************************************************************************
-** Static variables
-******************************************************************************/
-
-static pthread_mutex_t utils_mutex;
-
-/*****************************************************************************
-** UTILS INTERFACE FUNCTIONS
-*****************************************************************************/
-
-/*******************************************************************************
-**
-** Function utils_init
-**
-** Description Utils initialization
-**
-** Returns None
-**
-*******************************************************************************/
-void utils_init (void)
-{
- pthread_mutex_init(&utils_mutex, NULL);
-}
-
-/*******************************************************************************
-**
-** Function utils_cleanup
-**
-** Description Utils cleanup
-**
-** Returns None
-**
-*******************************************************************************/
-void utils_cleanup (void)
-{
- pthread_mutex_destroy(&utils_mutex);
-}
-
-/*******************************************************************************
-**
-** Function utils_queue_init
-**
-** Description Initialize the given buffer queue
-**
-** Returns None
-**
-*******************************************************************************/
-void utils_queue_init (BUFFER_Q *p_q)
-{
- p_q->p_first = p_q->p_last = NULL;
- p_q->count = 0;
-}
-
-/*******************************************************************************
-**
-** Function utils_enqueue
-**
-** Description Enqueue a buffer at the tail of the given queue
-**
-** Returns None
-**
-*******************************************************************************/
-void utils_enqueue (BUFFER_Q *p_q, void *p_buf)
-{
- HC_BUFFER_HDR_T *p_hdr;
-
- p_hdr = (HC_BUFFER_HDR_T *) ((uint8_t *) p_buf - BT_HC_BUFFER_HDR_SIZE);
-
- pthread_mutex_lock(&utils_mutex);
-
- if (p_q->p_last)
- {
- HC_BUFFER_HDR_T *p_last_hdr = \
- (HC_BUFFER_HDR_T *)((uint8_t *)p_q->p_last - BT_HC_BUFFER_HDR_SIZE);
-
- p_last_hdr->p_next = p_hdr;
- }
- else
- p_q->p_first = p_buf;
-
- p_q->p_last = p_buf;
- p_q->count++;
-
- p_hdr->p_next = NULL;
-
- pthread_mutex_unlock(&utils_mutex);
-}
-/*******************************************************************************
-**
-** Function utils_dequeue
-**
-** Description Dequeues a buffer from the head of the given queue
-**
-** Returns NULL if queue is empty, else buffer
-**
-*******************************************************************************/
-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;
-
-
- if (!p_q || !p_q->count)
- {
- return (NULL);
- }
-
- p_hdr=(HC_BUFFER_HDR_T *)((uint8_t *)p_q->p_first-BT_HC_BUFFER_HDR_SIZE);
-
- if (p_hdr->p_next)
- p_q->p_first = ((uint8_t *)p_hdr->p_next + BT_HC_BUFFER_HDR_SIZE);
- else
- {
- p_q->p_first = NULL;
- p_q->p_last = NULL;
- }
-
- p_q->count--;
-
- p_hdr->p_next = NULL;
- return ((uint8_t *)p_hdr + BT_HC_BUFFER_HDR_SIZE);
-}
-
-/*******************************************************************************
-**
-** Function utils_getnext
-**
-** Description Return a pointer to the next buffer linked to the given
-** buffer
-**
-** Returns NULL if the given buffer does not point to any next buffer,
-** else next buffer address
-**
-*******************************************************************************/
-void *utils_getnext (void *p_buf)
-{
- HC_BUFFER_HDR_T *p_hdr;
-
- p_hdr = (HC_BUFFER_HDR_T *) ((uint8_t *) p_buf - BT_HC_BUFFER_HDR_SIZE);
-
- if (p_hdr->p_next)
- return ((uint8_t *)p_hdr->p_next + BT_HC_BUFFER_HDR_SIZE);
- else
- return (NULL);
-}
-
-/*******************************************************************************
-**
-** Function utils_remove_from_queue
-**
-** 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 (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;
-
-
- if (p_buf == p_q->p_first)
- {
- return (utils_dequeue_unlocked (p_q));
- }
-
- p_buf_hdr = (HC_BUFFER_HDR_T *)((uint8_t *)p_buf - BT_HC_BUFFER_HDR_SIZE);
- p_prev=(HC_BUFFER_HDR_T *)((uint8_t *)p_q->p_first-BT_HC_BUFFER_HDR_SIZE);
-
- for ( ; p_prev; p_prev = p_prev->p_next)
- {
- /* If the previous points to this one, move the pointers around */
- if (p_prev->p_next == p_buf_hdr)
- {
- p_prev->p_next = p_buf_hdr->p_next;
-
- /* If we are removing the last guy in the queue, update p_last */
- if (p_buf == p_q->p_last)
- p_q->p_last = p_prev + 1;
-
- /* One less in the queue */
- p_q->count--;
-
- /* The buffer is now unlinked */
- p_buf_hdr->p_next = NULL;
-
- return (p_buf);
- }
- }
- return (NULL);
-}
-
-/*******************************************************************************
-**
-** Function utils_delay
-**
-** Description sleep unconditionally for timeout milliseconds
-**
-** Returns None
-**
-*******************************************************************************/
-void utils_delay (uint32_t timeout)
-{
- struct timespec delay;
- int err;
-
- delay.tv_sec = timeout / 1000;
- delay.tv_nsec = 1000 * 1000 * (timeout%1000);
-
- /* [u]sleep can't be used because it uses SIGALRM */
- do {
- err = nanosleep(&delay, &delay);
- } while (err < 0 && errno ==EINTR);
-}
-
-/*******************************************************************************
-**
-** Function utils_lock
-**
-** Description application calls this function before entering critical
-** section
-**
-** Returns None
-**
-*******************************************************************************/
-void utils_lock (void)
-{
- pthread_mutex_lock(&utils_mutex);
-}
-
-/*******************************************************************************
-**
-** Function utils_unlock
-**
-** Description application calls this function when leaving critical
-** section
-**
-** Returns None
-**
-*******************************************************************************/
-void utils_unlock (void)
-{
- pthread_mutex_unlock(&utils_mutex);
-}
-
diff --git a/hci/src/vendor.c b/hci/src/vendor.c
index e6627a280..f287e12cb 100644
--- a/hci/src/vendor.c
+++ b/hci/src/vendor.c
@@ -22,45 +22,29 @@
#include <dlfcn.h>
#include <utils/Log.h>
-#include "bt_hci_bdroid.h"
#include "bt_vendor_lib.h"
-#include "hci.h"
#include "osi.h"
+#include "vendor.h"
-// TODO: eliminate these three.
-extern tHCI_IF *p_hci_if;
-extern bool fwcfg_acked;
-void lpm_vnd_cback(uint8_t vnd_result);
+#define LAST_VENDOR_OPCODE_VALUE VENDOR_DO_EPILOG
static const char *VENDOR_LIBRARY_NAME = "libbt-vendor.so";
static const char *VENDOR_LIBRARY_SYMBOL_NAME = "BLUETOOTH_VENDOR_LIB_INTERFACE";
+static const vendor_interface_t interface;
+static const allocator_t *allocator;
+static vendor_cb callbacks[LAST_VENDOR_OPCODE_VALUE + 1];
+static send_internal_command_cb send_internal_command_callback;
+
static void *lib_handle;
-static bt_vendor_interface_t *vendor_interface;
-
-static void firmware_config_cb(bt_vendor_op_result_t result);
-static void sco_config_cb(bt_vendor_op_result_t result);
-static void low_power_mode_cb(bt_vendor_op_result_t result);
-static void sco_audiostate_cb(bt_vendor_op_result_t result);
-static void *buffer_alloc_cb(int size);
-static void buffer_free_cb(void *buffer);
-static uint8_t transmit_cb(uint16_t opcode, void *buffer, tINT_CMD_CBACK callback);
-static void epilog_cb(bt_vendor_op_result_t result);
-
-static const bt_vendor_callbacks_t vendor_callbacks = {
- sizeof(vendor_callbacks),
- firmware_config_cb,
- sco_config_cb,
- low_power_mode_cb,
- sco_audiostate_cb,
- buffer_alloc_cb,
- buffer_free_cb,
- transmit_cb,
- epilog_cb
-};
+static bt_vendor_interface_t *lib_interface;
+static const bt_vendor_callbacks_t lib_callbacks;
+
+// Interface functions
-bool vendor_open(const uint8_t *local_bdaddr) {
+static bool vendor_open(const uint8_t *local_bdaddr, const allocator_t *buffer_allocator) {
assert(lib_handle == NULL);
+ allocator = buffer_allocator;
lib_handle = dlopen(VENDOR_LIBRARY_NAME, RTLD_NOW);
if (!lib_handle) {
@@ -68,13 +52,15 @@ bool vendor_open(const uint8_t *local_bdaddr) {
goto error;
}
- vendor_interface = (bt_vendor_interface_t *)dlsym(lib_handle, VENDOR_LIBRARY_SYMBOL_NAME);
- if (!vendor_interface) {
+ lib_interface = (bt_vendor_interface_t *)dlsym(lib_handle, VENDOR_LIBRARY_SYMBOL_NAME);
+ if (!lib_interface) {
ALOGE("%s unable to find symbol %s in %s: %s", __func__, VENDOR_LIBRARY_SYMBOL_NAME, VENDOR_LIBRARY_NAME, dlerror());
goto error;
}
- int status = vendor_interface->init(&vendor_callbacks, (unsigned char *)local_bdaddr);
+ ALOGI("alloc value %p", lib_callbacks.alloc);
+
+ int status = lib_interface->init(&lib_callbacks, (unsigned char *)local_bdaddr);
if (status) {
ALOGE("%s unable to initialize vendor library: %d", __func__, status);
goto error;
@@ -83,57 +69,70 @@ bool vendor_open(const uint8_t *local_bdaddr) {
return true;
error:;
- vendor_interface = NULL;
+ lib_interface = NULL;
if (lib_handle)
dlclose(lib_handle);
lib_handle = NULL;
return false;
}
-void vendor_close(void) {
- if (vendor_interface)
- vendor_interface->cleanup();
+static void vendor_close(void) {
+ if (lib_interface)
+ lib_interface->cleanup();
if (lib_handle)
dlclose(lib_handle);
- vendor_interface = NULL;
+ lib_interface = NULL;
lib_handle = NULL;
}
-int vendor_send_command(bt_vendor_opcode_t opcode, void *param) {
- assert(vendor_interface != NULL);
+static int send_command(vendor_opcode_t opcode, void *param) {
+ assert(lib_interface != NULL);
+ return lib_interface->op(opcode, param);
+}
- return vendor_interface->op(opcode, param);
+static int send_async_command(vendor_async_opcode_t opcode, void *param) {
+ assert(lib_interface != NULL);
+ return lib_interface->op(opcode, param);
}
+static void set_callback(vendor_async_opcode_t opcode, vendor_cb callback) {
+ callbacks[opcode] = callback;
+}
+
+static void set_send_internal_command_callback(send_internal_command_cb callback) {
+ send_internal_command_callback = callback;
+}
+
+// Internal functions
+
// Called back from vendor library when the firmware configuration
// completes.
static void firmware_config_cb(bt_vendor_op_result_t result) {
- assert(bt_hc_cbacks != NULL);
-
- fwcfg_acked = true;
-
- bt_hc_postload_result_t status = (result == BT_VND_OP_RESULT_SUCCESS)
- ? BT_HC_PRELOAD_SUCCESS
- : BT_HC_PRELOAD_FAIL;
- bt_hc_cbacks->preload_cb(NULL, status);
+ ALOGI("firmware callback");
+ vendor_cb callback = callbacks[VENDOR_CONFIGURE_FIRMWARE];
+ assert(callback != NULL);
+ callback(result == BT_VND_OP_RESULT_SUCCESS);
}
// Called back from vendor library to indicate status of previous
// SCO configuration request. This should only happen during the
// postload process.
-static void sco_config_cb(UNUSED_ATTR bt_vendor_op_result_t result) {
- assert(p_hci_if != NULL);
-
- // Continue the rest of the postload process.
- p_hci_if->get_acl_max_len();
+static void sco_config_cb(bt_vendor_op_result_t result) {
+ ALOGI("%s", __func__);
+ vendor_cb callback = callbacks[VENDOR_CONFIGURE_SCO];
+ assert(callback != NULL);
+ callback(result == BT_VND_OP_RESULT_SUCCESS);
}
// Called back from vendor library to indicate status of previous
// LPM enable/disable request.
static void low_power_mode_cb(bt_vendor_op_result_t result) {
- lpm_vnd_cback(result != BT_VND_OP_RESULT_SUCCESS);
+ ALOGI("%s", __func__);
+ vendor_cb callback = callbacks[VENDOR_SET_LPM_MODE];
+ assert(callback != NULL);
+ callback(result == BT_VND_OP_RESULT_SUCCESS);
}
/******************************************************************************
@@ -156,25 +155,52 @@ static void sco_audiostate_cb(bt_vendor_op_result_t result)
// Called by vendor library when it needs an HCI buffer.
static void *buffer_alloc_cb(int size) {
- assert(bt_hc_cbacks != NULL);
- return bt_hc_cbacks->alloc(size);
+ return allocator->alloc(size);
}
// Called by vendor library when it needs to free a buffer allocated with
// |buffer_alloc_cb|.
static void buffer_free_cb(void *buffer) {
- assert(bt_hc_cbacks != NULL);
- bt_hc_cbacks->dealloc(buffer);
+ allocator->free(buffer);
}
// Called back from vendor library when it wants to send an HCI command.
static uint8_t transmit_cb(uint16_t opcode, void *buffer, tINT_CMD_CBACK callback) {
- assert(p_hci_if != NULL);
- return p_hci_if->send_int_cmd(opcode, (HC_BT_HDR *)buffer, callback);
+ assert(send_internal_command_callback != NULL);
+ return send_internal_command_callback(opcode, (BT_HDR *)buffer, callback);
}
// Called back from vendor library when the epilog procedure has
// completed. It is safe to call vendor_interface->cleanup() after
// this callback has been received.
-static void epilog_cb(UNUSED_ATTR bt_vendor_op_result_t result) {
+static void epilog_cb(bt_vendor_op_result_t result) {
+ ALOGI("%s", __func__);
+ vendor_cb callback = callbacks[VENDOR_DO_EPILOG];
+ assert(callback != NULL);
+ callback(result == BT_VND_OP_RESULT_SUCCESS);
+}
+
+static const bt_vendor_callbacks_t lib_callbacks = {
+ sizeof(lib_callbacks),
+ firmware_config_cb,
+ sco_config_cb,
+ low_power_mode_cb,
+ sco_audiostate_cb,
+ buffer_alloc_cb,
+ buffer_free_cb,
+ transmit_cb,
+ epilog_cb
+};
+
+static const vendor_interface_t interface = {
+ vendor_open,
+ vendor_close,
+ send_command,
+ send_async_command,
+ set_callback,
+ set_send_internal_command_callback
+};
+
+const vendor_interface_t *vendor_get_interface() {
+ return &interface;
}
diff --git a/hci/test/hci_hal_h4_test.cpp b/hci/test/hci_hal_h4_test.cpp
new file mode 100644
index 000000000..582cda046
--- /dev/null
+++ b/hci/test/hci_hal_h4_test.cpp
@@ -0,0 +1,259 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#include <gtest/gtest.h>
+
+extern "C" {
+#include <stdint.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <unistd.h>
+#include <utils/Log.h>
+
+#include "hci_hal.h"
+#include "osi.h"
+#include "semaphore.h"
+#include "test_stubs.h"
+#include "vendor.h"
+}
+
+DECLARE_TEST_MODES(
+ init,
+ open,
+ close_fn,
+ transmit,
+ read_synchronous,
+ read_async_reentry,
+ type_byte_only
+);
+
+static char sample_data1[100] = "A point is that which has no part.";
+static char sample_data2[100] = "A line is breadthless length.";
+static char sample_data3[100] = "The ends of a line are points.";
+static char acl_data[100] = "A straight line is a line which lies evenly with the points on itself.";
+static char sco_data[100] = "A surface is that which has length and breadth only.";
+static char event_data[100] = "The edges of a surface are lines.";
+
+static const hci_hal_interface_t *hal;
+static int dummy_serial_fd;
+static int send_command_call_number;
+static int reentry_i = 0;
+
+static semaphore_t *done;
+static semaphore_t *reentry_semaphore;
+
+static void expect_packet_synchronous(serial_data_type_t type, char *packet_data) {
+ int length = strlen(packet_data);
+ for (int i = 0; i < length; i++) {
+ EXPECT_EQ(packet_data[i], hal->read_byte(type));
+ }
+
+ hal->packet_finished(type);
+}
+
+STUB_FUNCTION(int, vendor_send_command, (vendor_opcode_t opcode, void *param))
+ DURING(open) AT_CALL(0) {
+ EXPECT_EQ(VENDOR_OPEN_USERIAL, opcode);
+ // Give back the dummy fd and the number 1 to say we opened 1 port
+ ((int *)param)[0] = dummy_serial_fd;
+ return 1;
+ }
+
+ DURING(close_fn) AT_CALL(0) {
+ EXPECT_EQ(VENDOR_CLOSE_USERIAL, opcode);
+ return 0;
+ }
+
+ UNEXPECTED_CALL;
+ return 0;
+}
+
+STUB_FUNCTION(void, data_ready_callback, (serial_data_type_t type))
+ DURING(read_synchronous) {
+ AT_CALL(0) {
+ EXPECT_EQ(DATA_TYPE_ACL, type);
+ expect_packet_synchronous(type, acl_data);
+ return;
+ }
+ AT_CALL(1) {
+ EXPECT_EQ(DATA_TYPE_SCO, type);
+ expect_packet_synchronous(type, sco_data);
+ return;
+ }
+ AT_CALL(2) {
+ EXPECT_EQ(DATA_TYPE_EVENT, type);
+ expect_packet_synchronous(type, event_data);
+ semaphore_post(done);
+ return;
+ }
+ }
+
+ DURING(read_async_reentry) {
+ EXPECT_EQ(DATA_TYPE_ACL, type);
+
+ while (hal->has_byte(type)) {
+ EXPECT_EQ(sample_data3[reentry_i], hal->read_byte(type));
+ semaphore_post(reentry_semaphore);
+ reentry_i++;
+ if (reentry_i == (int)strlen(sample_data3)) {
+ hal->packet_finished(type);
+ return;
+ }
+ }
+
+ return;
+ }
+
+ UNEXPECTED_CALL;
+}
+
+void reset_for(TEST_MODES_T next) {
+ RESET_CALL_COUNT(vendor_send_command);
+ RESET_CALL_COUNT(data_ready_callback);
+ CURRENT_TEST_MODE = next;
+}
+
+class HciHalH4Test : public ::testing::Test {
+ protected:
+ virtual void SetUp() {
+ hal = hci_hal_get_test_interface(&vendor);
+ vendor.send_command = vendor_send_command;
+ callbacks.data_ready = data_ready_callback;
+
+ send_command_call_number = 0;
+
+ socketpair(AF_LOCAL, SOCK_STREAM, 0, sockfd);
+ dummy_serial_fd = sockfd[0];
+ done = semaphore_new(0);
+ thread = thread_new("hal_test");
+
+ reset_for(init);
+ EXPECT_TRUE(hal->init(&callbacks, thread));
+
+ reset_for(open);
+ EXPECT_TRUE(hal->open());
+ EXPECT_CALL_COUNT(vendor_send_command, 1);
+ }
+
+ virtual void TearDown() {
+ reset_for(close_fn);
+ hal->close();
+ EXPECT_CALL_COUNT(vendor_send_command, 1);
+
+ semaphore_free(done);
+ thread_free(thread);
+ }
+
+ int sockfd[2];
+ vendor_interface_t vendor;
+ thread_t *thread;
+ hci_hal_callbacks_t callbacks;
+};
+
+static void expect_socket_data(int fd, char first_byte, char *data) {
+ int length = strlen(data) + 1; // + 1 for data type code
+ int i;
+
+ for (i = 0; i < length; i++) {
+ fd_set read_fds;
+ FD_ZERO(&read_fds);
+ FD_SET(fd, &read_fds);
+ select(fd + 1, &read_fds, NULL, NULL, NULL);
+
+ char byte;
+ read(fd, &byte, 1);
+
+ EXPECT_EQ(i == 0 ? first_byte : data[i - 1], byte);
+ }
+}
+
+static void write_packet(int fd, char first_byte, char *data) {
+ write(fd, &first_byte, 1);
+ write(fd, data, strlen(data));
+}
+
+static void write_packet_reentry(int fd, char first_byte, char *data) {
+ write(fd, &first_byte, 1);
+
+ int length = strlen(data);
+ for (int i = 0; i < length; i++) {
+ write(fd, &data[i], 1);
+ semaphore_wait(reentry_semaphore);
+ }
+}
+
+TEST_F(HciHalH4Test, test_transmit) {
+ reset_for(transmit);
+
+ // Send a command packet
+ hal->transmit_data(DATA_TYPE_COMMAND, (uint8_t *)(sample_data1 + 1), strlen(sample_data1 + 1));
+ expect_socket_data(sockfd[1], DATA_TYPE_COMMAND, sample_data1 + 1);
+
+ // Send an acl packet
+ hal->transmit_data(DATA_TYPE_ACL, (uint8_t *)(sample_data2 + 1), strlen(sample_data2 + 1));
+ expect_socket_data(sockfd[1], DATA_TYPE_ACL, sample_data2 + 1);
+
+ // Send an sco packet
+ hal->transmit_data(DATA_TYPE_SCO, (uint8_t *)(sample_data3 + 1), strlen(sample_data3 + 1));
+ expect_socket_data(sockfd[1], DATA_TYPE_SCO, sample_data3 + 1);
+}
+
+TEST_F(HciHalH4Test, test_read_synchronous) {
+ reset_for(read_synchronous);
+
+ write_packet(sockfd[1], DATA_TYPE_ACL, acl_data);
+ write_packet(sockfd[1], DATA_TYPE_SCO, sco_data);
+ write_packet(sockfd[1], DATA_TYPE_EVENT, event_data);
+
+ // Wait for all data to be received before calling the test good
+ semaphore_wait(done);
+ EXPECT_CALL_COUNT(data_ready_callback, 3);
+}
+
+TEST_F(HciHalH4Test, test_read_async_reentry) {
+ reset_for(read_async_reentry);
+
+ reentry_semaphore = semaphore_new(0);
+ reentry_i = 0;
+
+ write_packet_reentry(sockfd[1], DATA_TYPE_ACL, sample_data3);
+
+ // write_packet_reentry ensures the data has been received
+ semaphore_free(reentry_semaphore);
+}
+
+TEST_F(HciHalH4Test, test_type_byte_only_must_not_signal_data_ready) {
+ reset_for(type_byte_only);
+
+ char byte = DATA_TYPE_ACL;
+ write(sockfd[1], &byte, 1);
+
+ fd_set read_fds;
+
+ // Wait until the byte we wrote was picked up
+ do {
+ FD_ZERO(&read_fds);
+ FD_SET(sockfd[0], &read_fds);
+
+ struct timeval timeout;
+ timeout.tv_sec = 0;
+ timeout.tv_usec = 0;
+
+ select(sockfd[0] + 1, &read_fds, NULL, NULL, &timeout);
+ } while(FD_ISSET(sockfd[0], &read_fds));
+}
diff --git a/hci/test/hci_layer_test.cpp b/hci/test/hci_layer_test.cpp
new file mode 100644
index 000000000..2ac9012d2
--- /dev/null
+++ b/hci/test/hci_layer_test.cpp
@@ -0,0 +1,584 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#include <gtest/gtest.h>
+
+extern "C" {
+#include <stdint.h>
+#include <utils/Log.h>
+
+#include "AlarmTestHarness.h"
+#include "btsnoop.h"
+#include "hci_hal.h"
+#include "hci_inject.h"
+#include "hci_layer.h"
+#include "low_power_manager.h"
+#include "osi.h"
+#include "packet_fragmenter.h"
+#include "semaphore.h"
+#include "test_stubs.h"
+#include "vendor.h"
+}
+
+DECLARE_TEST_MODES(
+ init,
+ cleanup,
+ cycle_power,
+ preload,
+ postload,
+ transmit_simple,
+ receive_simple,
+ send_internal_command,
+ turn_on_logging,
+ turn_off_logging
+);
+
+static const char *small_sample_data = "\"It is easy to see,\" replied Don Quixote";
+static const char *command_sample_data = "that thou art not used to this business of adventures; those are giants";
+
+static const char *logging_path = "this/is/a/test/logging/path";
+
+static const hci_interface_t *hci;
+static bdaddr_t test_addr = (bdaddr_t)"testaddress123";
+static const hci_hal_callbacks_t *hal_callbacks;
+static thread_t *internal_thread;
+static vendor_cb firmware_config_callback;
+static vendor_cb sco_config_callback;
+static vendor_cb epilog_callback;
+static send_internal_command_cb send_internal_command_callback;
+static semaphore_t *done;
+static const uint16_t test_handle = (0x1992 & 0xCFFF);
+static const uint16_t test_handle_continuation = (0x1992 & 0xCFFF) | 0x1000;
+static int packet_index;
+static unsigned int data_size_sum;
+static BT_HDR *data_to_receive;
+
+// TODO move this to a common packet testing helper
+static BT_HDR *manufacture_packet(uint16_t event, const char *data) {
+ uint16_t data_length = strlen(data);
+ uint16_t size = data_length;
+ if (event == MSG_STACK_TO_HC_HCI_ACL) {
+ size += 4; // 2 for the handle, 2 for the length;
+ }
+
+ BT_HDR *packet = (BT_HDR *)malloc(size + sizeof(BT_HDR));
+ packet->len = size;
+ packet->offset = 0;
+ packet->event = event;
+ packet->layer_specific = 0;
+ uint8_t *packet_data = packet->data;
+
+ if (event == MSG_STACK_TO_HC_HCI_ACL) {
+ UINT16_TO_STREAM(packet_data, test_handle);
+ UINT16_TO_STREAM(packet_data, data_length);
+ }
+
+ for (int i = 0; i < data_length; i++) {
+ packet_data[i] = data[i];
+ }
+
+ return packet;
+}
+
+static void expect_packet(uint16_t event, int max_acl_data_size, const uint8_t *data, uint16_t data_length, const char *expected_data) {
+ int expected_data_offset;
+ int length_to_check;
+
+ if (event == MSG_STACK_TO_HC_HCI_ACL) {
+ uint16_t handle;
+ uint16_t length;
+ STREAM_TO_UINT16(handle, data);
+ STREAM_TO_UINT16(length, data);
+
+ if (packet_index == 0)
+ EXPECT_EQ(test_handle, handle);
+ else
+ EXPECT_EQ(test_handle_continuation, handle);
+
+ int length_remaining = strlen(expected_data) - data_size_sum;
+ int packet_data_length = data_length - HCI_ACL_PREAMBLE_SIZE;
+ EXPECT_EQ(length_remaining, length);
+
+ if (length_remaining < max_acl_data_size)
+ EXPECT_EQ(length, packet_data_length);
+ else
+ EXPECT_EQ(max_acl_data_size, packet_data_length);
+
+ length_to_check = packet_data_length;
+ expected_data_offset = packet_index * max_acl_data_size;
+ packet_index++;
+ } else {
+ length_to_check = strlen(expected_data);
+ expected_data_offset = 0;
+ }
+
+ for (int i = 0; i < length_to_check; i++) {
+ EXPECT_EQ(expected_data[expected_data_offset + i], data[i]);
+ data_size_sum++;
+ }
+}
+
+STUB_FUNCTION(bool, hal_init, (const hci_hal_callbacks_t *callbacks, thread_t *working_thread))
+ DURING(init) AT_CALL(0) {
+ hal_callbacks = callbacks;
+ internal_thread = working_thread;
+ return true;
+ }
+
+ UNEXPECTED_CALL;
+ return false;
+}
+
+STUB_FUNCTION(bool, hal_open, ())
+ DURING(preload) AT_CALL(0) return true;
+ UNEXPECTED_CALL;
+ return false;
+}
+
+STUB_FUNCTION(void, hal_close, ())
+ DURING(cleanup) AT_CALL(0) return;
+ UNEXPECTED_CALL;
+}
+
+STUB_FUNCTION(uint16_t, hal_transmit_data, (serial_data_type_t type, uint8_t *data, uint16_t length))
+ DURING(transmit_simple) AT_CALL(0) {
+ EXPECT_EQ(DATA_TYPE_ACL, type);
+ expect_packet(MSG_STACK_TO_HC_HCI_ACL, 1021, data, length, small_sample_data);
+ return length;
+ }
+
+ DURING(send_internal_command) AT_CALL(0) {
+ EXPECT_EQ(DATA_TYPE_COMMAND, type);
+ expect_packet(MSG_STACK_TO_HC_HCI_CMD, 1021, data, length, command_sample_data);
+ return length;
+ }
+
+ UNEXPECTED_CALL;
+ return 0;
+}
+
+STUB_FUNCTION(uint8_t, hal_read_byte, (serial_data_type_t type))
+ DURING(receive_simple) {
+ EXPECT_EQ(DATA_TYPE_ACL, type);
+ if (data_to_receive->offset < data_to_receive->len) {
+ return data_to_receive->data[data_to_receive->offset++];
+ }
+ }
+
+ UNEXPECTED_CALL;
+ return 0;
+}
+
+STUB_FUNCTION(bool, hal_has_byte, (serial_data_type_t type))
+ DURING(receive_simple) {
+ EXPECT_EQ(DATA_TYPE_ACL, type);
+ return data_to_receive->offset < data_to_receive->len;
+ }
+
+ UNEXPECTED_CALL;
+ return false;
+}
+
+STUB_FUNCTION(void, hal_packet_finished, (serial_data_type_t type))
+ DURING(receive_simple) AT_CALL(0) {
+ EXPECT_EQ(DATA_TYPE_ACL, type);
+ return;
+ }
+
+ UNEXPECTED_CALL;
+}
+
+STUB_FUNCTION(void, btsnoop_open, (const char *path))
+ DURING(turn_on_logging) AT_CALL(0) {
+ EXPECT_EQ(logging_path, path);
+ return;
+ }
+
+ UNEXPECTED_CALL;
+}
+
+STUB_FUNCTION(void, btsnoop_close, ())
+ DURING(turn_off_logging) AT_CALL(0) return;
+ UNEXPECTED_CALL;
+}
+
+STUB_FUNCTION(bool, hci_inject_open, (
+ UNUSED_ATTR const hci_interface_t *hci_interface,
+ UNUSED_ATTR const allocator_t *buffer_allocator))
+ DURING(init) AT_CALL(0) return true;
+ UNEXPECTED_CALL;
+ return false;
+}
+
+STUB_FUNCTION(void, hci_inject_close, ())
+ DURING(cleanup) AT_CALL(0) return;
+ UNEXPECTED_CALL;
+}
+
+STUB_FUNCTION(void, btsnoop_capture, (const BT_HDR *buffer, bool is_received))
+ DURING(transmit_simple) AT_CALL(0) {
+ EXPECT_FALSE(is_received);
+ expect_packet(MSG_STACK_TO_HC_HCI_ACL, 1021, buffer->data + buffer->offset, buffer->len, small_sample_data);
+ packet_index = 0;
+ data_size_sum = 0;
+ return;
+ }
+
+ DURING(send_internal_command) AT_CALL(0) {
+ EXPECT_FALSE(is_received);
+ expect_packet(MSG_STACK_TO_HC_HCI_CMD, 1021, buffer->data + buffer->offset, buffer->len, command_sample_data);
+ packet_index = 0;
+ data_size_sum = 0;
+ return;
+ }
+
+ DURING(receive_simple) AT_CALL(0) {
+ EXPECT_TRUE(is_received);
+ EXPECT_TRUE(buffer->len == data_to_receive->len);
+ const uint8_t *buffer_base = buffer->data + buffer->offset;
+ const uint8_t *expected_base = data_to_receive->data;
+ for (int i = 0; i < buffer->len; i++) {
+ EXPECT_EQ(expected_base[i], buffer_base[i]);
+ }
+
+ return;
+ }
+
+ UNEXPECTED_CALL;
+}
+
+STUB_FUNCTION(void, low_power_init, (UNUSED_ATTR thread_t *thread))
+ DURING(init) AT_CALL(0) return;
+ UNEXPECTED_CALL;
+}
+
+STUB_FUNCTION(void, low_power_cleanup, ())
+ DURING(cleanup) AT_CALL(0) return;
+ UNEXPECTED_CALL;
+}
+
+STUB_FUNCTION(void, low_power_wake_assert, ())
+ DURING(transmit_simple) AT_CALL(0) return;
+ DURING(send_internal_command) AT_CALL(0) return;
+ UNEXPECTED_CALL;
+}
+
+STUB_FUNCTION(void, low_power_transmit_done, ())
+ DURING(transmit_simple) AT_CALL(0) return;
+ DURING(send_internal_command) AT_CALL(0) return;
+ UNEXPECTED_CALL;
+}
+
+STUB_FUNCTION(bool, vendor_open, (const uint8_t *addr, const allocator_t *allocator))
+ DURING(init) AT_CALL(0) {
+ EXPECT_EQ(test_addr, addr);
+ EXPECT_EQ(&allocator_malloc, allocator);
+ return true;
+ }
+
+ UNEXPECTED_CALL;
+ return true;
+}
+
+STUB_FUNCTION(void, vendor_close, ())
+ DURING(cleanup) AT_CALL(0) return;
+ UNEXPECTED_CALL;
+}
+
+STUB_FUNCTION(void, vendor_set_callback, (vendor_async_opcode_t opcode, UNUSED_ATTR vendor_cb callback))
+ DURING(init) {
+ AT_CALL(0) {
+ EXPECT_EQ(VENDOR_CONFIGURE_FIRMWARE, opcode);
+ firmware_config_callback = callback;
+ return;
+ }
+ AT_CALL(1) {
+ EXPECT_EQ(VENDOR_CONFIGURE_SCO, opcode);
+ sco_config_callback = callback;
+ return;
+ }
+ AT_CALL(2) {
+ EXPECT_EQ(VENDOR_DO_EPILOG, opcode);
+ epilog_callback = callback;
+ return;
+ }
+ }
+
+ UNEXPECTED_CALL;
+}
+
+STUB_FUNCTION(void, vendor_set_send_internal_command_callback, (UNUSED_ATTR send_internal_command_cb callback))
+ DURING(init) AT_CALL (0) {
+ EXPECT_TRUE(callback != NULL);
+ send_internal_command_callback = callback;
+ return;
+ }
+
+ UNEXPECTED_CALL;
+}
+
+STUB_FUNCTION(int, vendor_send_command, (vendor_opcode_t opcode, void *param))
+ DURING(cleanup) AT_CALL(0) {
+ EXPECT_EQ(VENDOR_CHIP_POWER_CONTROL, opcode);
+ EXPECT_EQ(BT_VND_PWR_OFF, *(int *)param);
+ return 0;
+ }
+
+ DURING(cycle_power) {
+ AT_CALL(0) {
+ EXPECT_EQ(VENDOR_CHIP_POWER_CONTROL, opcode);
+ EXPECT_EQ(BT_VND_PWR_ON, *(int *)param);
+ return 0;
+ }
+ AT_CALL(1) {
+ EXPECT_EQ(VENDOR_CHIP_POWER_CONTROL, opcode);
+ EXPECT_EQ(BT_VND_PWR_OFF, *(int *)param);
+ return 0;
+ }
+ }
+
+ UNEXPECTED_CALL;
+ return 0;
+}
+
+STUB_FUNCTION(int, vendor_send_async_command, (UNUSED_ATTR vendor_async_opcode_t opcode, UNUSED_ATTR void *param))
+ DURING(preload) AT_CALL(0) {
+ EXPECT_EQ(VENDOR_CONFIGURE_FIRMWARE, opcode);
+ return 0;
+ }
+
+ DURING(postload) AT_CALL(0) {
+ EXPECT_EQ(VENDOR_CONFIGURE_SCO, opcode);
+ return 0;
+ }
+
+ UNEXPECTED_CALL;
+ return 0;
+}
+
+STUB_FUNCTION(void, callback_transmit_finished, (UNUSED_ATTR void *buffer, bool all_fragments_sent))
+ DURING(transmit_simple) AT_CALL(0) {
+ EXPECT_TRUE(all_fragments_sent);
+ return;
+ }
+
+ DURING(send_internal_command) AT_CALL(0) {
+ EXPECT_TRUE(all_fragments_sent);
+ return;
+ }
+
+ UNEXPECTED_CALL;
+}
+
+STUB_FUNCTION(void, internal_command_response, (UNUSED_ATTR void *response))
+ UNEXPECTED_CALL;
+}
+
+static void reset_for(TEST_MODES_T next) {
+ RESET_CALL_COUNT(vendor_open);
+ RESET_CALL_COUNT(vendor_close);
+ RESET_CALL_COUNT(vendor_set_callback);
+ RESET_CALL_COUNT(vendor_set_send_internal_command_callback);
+ RESET_CALL_COUNT(vendor_send_command);
+ RESET_CALL_COUNT(vendor_send_async_command);
+ RESET_CALL_COUNT(hal_init);
+ RESET_CALL_COUNT(hal_open);
+ RESET_CALL_COUNT(hal_close);
+ RESET_CALL_COUNT(hal_read_byte);
+ RESET_CALL_COUNT(hal_has_byte);
+ RESET_CALL_COUNT(hal_packet_finished);
+ RESET_CALL_COUNT(hal_transmit_data);
+ RESET_CALL_COUNT(btsnoop_open);
+ RESET_CALL_COUNT(btsnoop_close);
+ RESET_CALL_COUNT(btsnoop_capture);
+ RESET_CALL_COUNT(hci_inject_open);
+ RESET_CALL_COUNT(hci_inject_close);
+ RESET_CALL_COUNT(low_power_init);
+ RESET_CALL_COUNT(low_power_cleanup);
+ RESET_CALL_COUNT(low_power_wake_assert);
+ RESET_CALL_COUNT(low_power_transmit_done);
+ RESET_CALL_COUNT(callback_transmit_finished);
+ RESET_CALL_COUNT(internal_command_response);
+ CURRENT_TEST_MODE = next;
+}
+
+class HciLayerTest : public AlarmTestHarness {
+ protected:
+ virtual void SetUp() {
+ AlarmTestHarness::SetUp();
+
+ hci = hci_layer_get_test_interface(
+ &hal,
+ &btsnoop,
+ &hci_inject,
+ packet_fragmenter_get_interface(),
+ &vendor,
+ &low_power_manager
+ );
+
+ packet_index = 0;
+ data_size_sum = 0;
+
+ vendor.open = vendor_open;
+ vendor.close = vendor_close;
+ vendor.set_callback = vendor_set_callback;
+ vendor.set_send_internal_command_callback = vendor_set_send_internal_command_callback;
+ vendor.send_command = vendor_send_command;
+ vendor.send_async_command = vendor_send_async_command;
+ hal.init = hal_init;
+ hal.open = hal_open;
+ hal.close = hal_close;
+ hal.read_byte = hal_read_byte;
+ hal.has_byte = hal_has_byte;
+ hal.packet_finished = hal_packet_finished;
+ hal.transmit_data = hal_transmit_data;
+ btsnoop.open = btsnoop_open;
+ btsnoop.close = btsnoop_close;
+ btsnoop.capture = btsnoop_capture;
+ hci_inject.open = hci_inject_open;
+ hci_inject.close = hci_inject_close;
+ low_power_manager.init = low_power_init;
+ low_power_manager.cleanup = low_power_cleanup;
+ low_power_manager.wake_assert = low_power_wake_assert;
+ low_power_manager.transmit_done = low_power_transmit_done;
+ callbacks.transmit_finished = callback_transmit_finished;
+
+ done = semaphore_new(0);
+
+ reset_for(init);
+ hci->init(test_addr, &allocator_malloc, &callbacks);
+
+ EXPECT_CALL_COUNT(vendor_open, 1);
+ EXPECT_CALL_COUNT(hal_init, 1);
+ EXPECT_CALL_COUNT(low_power_init, 1);
+ EXPECT_CALL_COUNT(vendor_set_callback, 3);
+ EXPECT_CALL_COUNT(vendor_set_send_internal_command_callback, 1);
+ }
+
+ virtual void TearDown() {
+ reset_for(cleanup);
+ hci->cleanup();
+
+ EXPECT_CALL_COUNT(low_power_cleanup, 1);
+ EXPECT_CALL_COUNT(hal_close, 1);
+ EXPECT_CALL_COUNT(vendor_send_command, 1);
+ EXPECT_CALL_COUNT(vendor_close, 1);
+
+ semaphore_free(done);
+ AlarmTestHarness::TearDown();
+ }
+
+ hci_hal_interface_t hal;
+ btsnoop_interface_t btsnoop;
+ hci_inject_interface_t hci_inject;
+ vendor_interface_t vendor;
+ low_power_manager_interface_t low_power_manager;
+ hci_callbacks_t callbacks;
+};
+
+static void signal_work_item(UNUSED_ATTR void *context) {
+ semaphore_post(done);
+}
+
+static void flush_thread(thread_t *thread) {
+ thread_post(thread, signal_work_item, NULL);
+ semaphore_wait(done);
+}
+
+TEST_F(HciLayerTest, test_cycle_power) {
+ reset_for(cycle_power);
+ hci->set_chip_power_on(true);
+ hci->set_chip_power_on(false);
+
+ EXPECT_CALL_COUNT(vendor_send_command, 2);
+}
+
+TEST_F(HciLayerTest, test_preload) {
+ reset_for(preload);
+ hci->do_preload();
+
+ flush_thread(internal_thread);
+ EXPECT_CALL_COUNT(hal_open, 1);
+ EXPECT_CALL_COUNT(vendor_send_async_command, 1);
+}
+
+TEST_F(HciLayerTest, test_postload) {
+ reset_for(postload);
+ hci->do_postload();
+
+ flush_thread(internal_thread);
+ EXPECT_CALL_COUNT(vendor_send_async_command, 1);
+}
+
+TEST_F(HciLayerTest, test_transmit_simple) {
+ reset_for(transmit_simple);
+ BT_HDR *packet = manufacture_packet(MSG_STACK_TO_HC_HCI_ACL, small_sample_data);
+ hci->transmit_downward(MSG_STACK_TO_HC_HCI_ACL, packet);
+
+ flush_thread(internal_thread);
+ EXPECT_CALL_COUNT(hal_transmit_data, 1);
+ EXPECT_CALL_COUNT(btsnoop_capture, 1);
+ EXPECT_CALL_COUNT(low_power_transmit_done, 1);
+ EXPECT_CALL_COUNT(low_power_wake_assert, 1);
+ EXPECT_CALL_COUNT(callback_transmit_finished, 1);
+
+ free(packet);
+}
+
+// TODO finish test
+TEST_F(HciLayerTest, test_receive_simple) {
+ reset_for(receive_simple);
+ data_to_receive = manufacture_packet(MSG_STACK_TO_HC_HCI_ACL, small_sample_data);
+
+ // Not running on the internal thread, unlike the real hal
+ hal_callbacks->data_ready(DATA_TYPE_ACL);
+ EXPECT_CALL_COUNT(hal_packet_finished, 1);
+ EXPECT_CALL_COUNT(btsnoop_capture, 1);
+
+ free(data_to_receive);
+}
+
+TEST_F(HciLayerTest, test_send_internal_command) {
+ // Send a test command
+ reset_for(send_internal_command);
+ data_to_receive = manufacture_packet(MSG_STACK_TO_HC_HCI_CMD, command_sample_data);
+ send_internal_command_callback(MSG_STACK_TO_HC_HCI_CMD, data_to_receive, internal_command_response);
+
+ flush_thread(internal_thread);
+ EXPECT_CALL_COUNT(hal_transmit_data, 1);
+ EXPECT_CALL_COUNT(btsnoop_capture, 1);
+ EXPECT_CALL_COUNT(low_power_transmit_done, 1);
+ EXPECT_CALL_COUNT(low_power_wake_assert, 1);
+ EXPECT_CALL_COUNT(callback_transmit_finished, 1);
+
+ // TODO send a response and make sure the response ends up at the callback
+
+ free(data_to_receive);
+}
+
+TEST_F(HciLayerTest, test_turn_on_logging) {
+ reset_for(turn_on_logging);
+ hci->turn_on_logging(logging_path);
+ EXPECT_CALL_COUNT(btsnoop_open, 1);
+}
+
+TEST_F(HciLayerTest, test_turn_off_logging) {
+ reset_for(turn_off_logging);
+ hci->turn_off_logging();
+ EXPECT_CALL_COUNT(btsnoop_close, 1);
+}
diff --git a/hci/test/low_power_manager_test.cpp b/hci/test/low_power_manager_test.cpp
new file mode 100644
index 000000000..c108038eb
--- /dev/null
+++ b/hci/test/low_power_manager_test.cpp
@@ -0,0 +1,140 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#include <gtest/gtest.h>
+
+extern "C" {
+#include <stdint.h>
+#include <utils/Log.h>
+
+#include "AlarmTestHarness.h"
+#include "low_power_manager.h"
+#include "osi.h"
+#include "semaphore.h"
+#include "test_stubs.h"
+#include "thread.h"
+#include "vendor.h"
+}
+
+DECLARE_TEST_MODES(
+ init,
+ cleanup,
+ enable_disable
+);
+
+static const low_power_manager_interface_t *manager;
+static thread_t *thread;
+static semaphore_t *done;
+
+static vendor_cb low_power_state_callback;
+
+static void flush_work_queue_item(UNUSED_ATTR void *context) {
+ semaphore_post(done);
+}
+
+STUB_FUNCTION(int, vendor_send_command, (vendor_opcode_t opcode, void *param))
+ DURING(init) AT_CALL(0) {
+ EXPECT_EQ(VENDOR_GET_LPM_IDLE_TIMEOUT, opcode);
+ *((uint32_t *)param) = 100;
+ return 0;
+ }
+
+ UNEXPECTED_CALL;
+ return 0;
+}
+
+STUB_FUNCTION(int, vendor_send_async_command, (vendor_async_opcode_t opcode, void *param))
+ DURING(enable_disable) {
+ AT_CALL(0) {
+ EXPECT_EQ(VENDOR_SET_LPM_MODE, opcode);
+ EXPECT_EQ(BT_VND_LPM_ENABLE, *(uint8_t *)param);
+ low_power_state_callback(true);
+ thread_post(thread, flush_work_queue_item, NULL);
+ return 0;
+ }
+ AT_CALL(1) {
+ EXPECT_EQ(VENDOR_SET_LPM_MODE, opcode);
+ EXPECT_EQ(BT_VND_LPM_DISABLE, *(uint8_t *)param);
+ low_power_state_callback(true);
+ thread_post(thread, flush_work_queue_item, NULL);
+ return 0;
+ }
+ }
+
+ UNEXPECTED_CALL;
+ return 0;
+}
+
+STUB_FUNCTION(void, vendor_set_callback, (vendor_async_opcode_t opcode, vendor_cb callback))
+ DURING(init) AT_CALL(0) {
+ EXPECT_EQ(VENDOR_SET_LPM_MODE, opcode);
+ low_power_state_callback = callback;
+ return;
+ }
+
+ UNEXPECTED_CALL;
+}
+
+static void reset_for(TEST_MODES_T next) {
+ RESET_CALL_COUNT(vendor_send_command);
+ RESET_CALL_COUNT(vendor_send_async_command);
+ RESET_CALL_COUNT(vendor_set_callback);
+ CURRENT_TEST_MODE = next;
+}
+
+class LowPowerManagerTest : public AlarmTestHarness {
+ protected:
+ virtual void SetUp() {
+ AlarmTestHarness::SetUp();
+ low_power_state_callback = NULL;
+ vendor.send_command = vendor_send_command;
+ vendor.send_async_command = vendor_send_async_command;
+ vendor.set_callback = vendor_set_callback;
+ manager = low_power_manager_get_test_interface(&vendor);
+ thread = thread_new("test_thread");
+ done = semaphore_new(0);
+
+ reset_for(init);
+ manager->init(thread);
+
+ EXPECT_CALL_COUNT(vendor_send_command, 1);
+ EXPECT_CALL_COUNT(vendor_set_callback, 1);
+ }
+
+ virtual void TearDown() {
+ reset_for(cleanup);
+ manager->cleanup();
+
+ semaphore_free(done);
+ thread_free(thread);
+ AlarmTestHarness::TearDown();
+ }
+
+ vendor_interface_t vendor;
+};
+
+TEST_F(LowPowerManagerTest, test_enable_disable) {
+ reset_for(enable_disable);
+ manager->post_command(LPM_ENABLE);
+ semaphore_wait(done);
+
+ manager->post_command(LPM_DISABLE);
+ semaphore_wait(done);
+
+ EXPECT_CALL_COUNT(vendor_send_async_command, 2);
+}
diff --git a/hci/test/packet_fragmenter_test.cpp b/hci/test/packet_fragmenter_test.cpp
new file mode 100644
index 000000000..1a9f4f371
--- /dev/null
+++ b/hci/test/packet_fragmenter_test.cpp
@@ -0,0 +1,367 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#include <gtest/gtest.h>
+
+extern "C" {
+#include <stdint.h>
+#include <utils/Log.h>
+
+#include "hci_internals.h"
+#include "packet_fragmenter.h"
+#include "osi.h"
+#include "test_stubs.h"
+}
+
+DECLARE_TEST_MODES(
+ init,
+ set_data_sizes,
+ no_fragmentation,
+ fragmentation,
+ ble_no_fragmentation,
+ ble_fragmentation,
+ non_acl_passthrough_fragmentation,
+ no_reassembly,
+ reassembly,
+ non_acl_passthrough_reassembly
+);
+
+#define LOCAL_BLE_CONTROLLER_ID 1
+
+static const char *sample_data =
+ "At this point they came in sight of thirty forty windmills that there are on plain, and "
+ "as soon as Don Quixote saw them he said to his squire, \"Fortune is arranging matters "
+ "for us better than we could have shaped our desires ourselves, for look there, friend "
+ "Sancho Panza, where thirty or more monstrous giants present themselves, all of whom I "
+ "mean to engage in battle and slay, and with whose spoils we shall begin to make our "
+ "fortunes; for this is righteous warfare, and it is God's good service to sweep so evil "
+ "a breed from off the face of the earth.\"";
+
+static const char *small_sample_data = "\"What giants?\" said Sancho Panza.";
+static const uint16_t test_handle_start = (0x1992 & 0xCFFF) | 0x2000;
+static const uint16_t test_handle_continuation = (0x1992 & 0xCFFF) | 0x1000;
+static int packet_index;
+static unsigned int data_size_sum;
+
+static const packet_fragmenter_interface_t *fragmenter;
+
+static BT_HDR *manufacture_packet_for_fragmentation(uint16_t event, const char *data) {
+ uint16_t data_length = strlen(data);
+ uint16_t size = data_length;
+ if (event == MSG_STACK_TO_HC_HCI_ACL) {
+ size += 4; // 2 for the handle, 2 for the length;
+ }
+
+ BT_HDR *packet = (BT_HDR *)malloc(size + sizeof(BT_HDR));
+ packet->len = size;
+ packet->offset = 0;
+ packet->event = event;
+ packet->layer_specific = 0;
+ uint8_t *packet_data = packet->data;
+
+ if (event == MSG_STACK_TO_HC_HCI_ACL) {
+ UINT16_TO_STREAM(packet_data, test_handle_start);
+ UINT16_TO_STREAM(packet_data, data_length);
+ }
+
+ memcpy(packet_data, data, data_length);
+ return packet;
+}
+
+static void expect_packet_fragmented(uint16_t event, int max_acl_data_size, BT_HDR *packet, const char *expected_data, bool send_complete) {
+ uint8_t *data = packet->data + packet->offset;
+ int expected_data_offset;
+ int length_to_check;
+
+ if (event == MSG_STACK_TO_HC_HCI_ACL) {
+ uint16_t handle;
+ uint16_t length;
+ STREAM_TO_UINT16(handle, data);
+ STREAM_TO_UINT16(length, data);
+
+ if (packet_index == 0)
+ EXPECT_EQ(test_handle_start, handle);
+ else
+ EXPECT_EQ(test_handle_continuation, handle);
+
+ int length_remaining = strlen(expected_data) - data_size_sum;
+ int packet_data_length = packet->len - HCI_ACL_PREAMBLE_SIZE;
+ EXPECT_EQ(packet_data_length, length);
+
+ if (length_remaining > max_acl_data_size)
+ EXPECT_EQ(max_acl_data_size, packet_data_length);
+
+ length_to_check = packet_data_length;
+ expected_data_offset = packet_index * max_acl_data_size;
+ packet_index++;
+ } else {
+ length_to_check = strlen(expected_data);
+ expected_data_offset = 0;
+ }
+
+ for (int i = 0; i < length_to_check; i++) {
+ EXPECT_EQ(expected_data[expected_data_offset + i], data[i]);
+ data_size_sum++;
+ }
+
+ if (event == MSG_STACK_TO_HC_HCI_ACL)
+ EXPECT_TRUE(send_complete == (data_size_sum == strlen(expected_data)));
+}
+
+static void manufacture_packet_and_then_reassemble(uint16_t event, uint16_t acl_size, const char *data) {
+ uint16_t data_length = strlen(data);
+
+ if (event == MSG_HC_TO_STACK_HCI_ACL) {
+ uint16_t total_length = data_length + 2; // 2 for l2cap length;
+ uint16_t length_sent = 0;
+ uint16_t l2cap_length = data_length - 2; // l2cap length field, 2 for the pretend channel id borrowed from the data
+
+ do {
+ int length_to_send = (length_sent + (acl_size - 4) < total_length) ? (acl_size - 4) : (total_length - length_sent);
+ BT_HDR *packet = (BT_HDR *)malloc(length_to_send + 4 + sizeof(BT_HDR));
+ packet->len = length_to_send + 4;
+ packet->offset = 0;
+ packet->event = event;
+ packet->layer_specific = 0;
+
+ uint8_t *packet_data = packet->data;
+ if (length_sent == 0) { // first packet
+ UINT16_TO_STREAM(packet_data, test_handle_start);
+ UINT16_TO_STREAM(packet_data, length_to_send);
+ UINT16_TO_STREAM(packet_data, l2cap_length);
+ memcpy(packet_data, data, length_to_send - 2);
+ } else {
+ UINT16_TO_STREAM(packet_data, test_handle_continuation);
+ UINT16_TO_STREAM(packet_data, length_to_send);
+ memcpy(packet_data, data + length_sent - 2, length_to_send);
+ }
+
+ length_sent += length_to_send;
+ fragmenter->reassemble_and_dispatch(packet);
+ } while (length_sent < total_length);
+ } else {
+ BT_HDR *packet = (BT_HDR *)malloc(data_length + sizeof(BT_HDR));
+ packet->len = data_length;
+ packet->offset = 0;
+ packet->event = event;
+ packet->layer_specific = 0;
+ memcpy(packet->data, data, data_length);
+
+ fragmenter->reassemble_and_dispatch(packet);
+ }
+}
+
+static void expect_packet_reassembled(uint16_t event, BT_HDR *packet, const char *expected_data) {
+ uint16_t expected_data_length = strlen(expected_data);
+ uint8_t *data = packet->data + packet->offset;
+
+ if (event == MSG_HC_TO_STACK_HCI_ACL) {
+ uint16_t handle;
+ uint16_t length;
+ uint16_t l2cap_length;
+ STREAM_TO_UINT16(handle, data);
+ STREAM_TO_UINT16(length, data);
+ STREAM_TO_UINT16(l2cap_length, data);
+
+ EXPECT_EQ(test_handle_start, handle);
+ EXPECT_EQ(expected_data_length + 2, length);
+ EXPECT_EQ(expected_data_length - 2, l2cap_length); // -2 for the pretend channel id
+ }
+
+
+ for (int i = 0; i < expected_data_length; i++) {
+ EXPECT_EQ(expected_data[i], data[i]);
+ data_size_sum++;
+ }
+}
+
+STUB_FUNCTION(void, fragmented_callback, (BT_HDR *packet, bool send_complete))
+ DURING(no_fragmentation) AT_CALL(0) {
+ expect_packet_fragmented(MSG_STACK_TO_HC_HCI_ACL, 42, packet, small_sample_data, send_complete);
+ return;
+ }
+
+ DURING(fragmentation) {
+ expect_packet_fragmented(MSG_STACK_TO_HC_HCI_ACL, 10, packet, sample_data, send_complete);
+ return;
+ }
+
+ DURING(ble_no_fragmentation) AT_CALL(0) {
+ expect_packet_fragmented(MSG_STACK_TO_HC_HCI_ACL, 42, packet, small_sample_data, send_complete);
+ return;
+ }
+
+ DURING(ble_fragmentation) {
+ expect_packet_fragmented(MSG_STACK_TO_HC_HCI_ACL, 10, packet, sample_data, send_complete);
+ return;
+ }
+
+ DURING(non_acl_passthrough_fragmentation) AT_CALL(0) {
+ expect_packet_fragmented(MSG_STACK_TO_HC_HCI_CMD, 10, packet, sample_data, send_complete);
+ return;
+ }
+
+ UNEXPECTED_CALL;
+}
+
+STUB_FUNCTION(void, reassembled_callback, (BT_HDR *packet))
+ DURING(no_reassembly) AT_CALL(0) {
+ expect_packet_reassembled(MSG_HC_TO_STACK_HCI_ACL, packet, small_sample_data);
+ return;
+ }
+
+ DURING(reassembly) AT_CALL(0) {
+ expect_packet_reassembled(MSG_HC_TO_STACK_HCI_ACL, packet, sample_data);
+ return;
+ }
+
+ DURING(non_acl_passthrough_reassembly) AT_CALL(0) {
+ expect_packet_reassembled(MSG_HC_TO_STACK_HCI_EVT, packet, sample_data);
+ return;
+ }
+
+ UNEXPECTED_CALL;
+}
+
+STUB_FUNCTION(void, transmit_finished_callback, (UNUSED_ATTR void *packet, UNUSED_ATTR bool sent_all_fragments))
+ UNEXPECTED_CALL;
+}
+
+static void reset_for(TEST_MODES_T next) {
+ RESET_CALL_COUNT(fragmented_callback);
+ RESET_CALL_COUNT(reassembled_callback);
+ RESET_CALL_COUNT(transmit_finished_callback);
+ CURRENT_TEST_MODE = next;
+}
+
+class PacketFragmenterTest : public ::testing::Test {
+ protected:
+ virtual void SetUp() {
+ fragmenter = packet_fragmenter_get_interface();
+ packet_index = 0;
+ data_size_sum = 0;
+
+ callbacks.fragmented = fragmented_callback;
+ callbacks.reassembled = reassembled_callback;
+ callbacks.transmit_finished = transmit_finished_callback;
+
+ reset_for(init);
+ fragmenter->init(&callbacks, &allocator_malloc);
+ }
+
+ virtual void TearDown() {
+ }
+
+ packet_fragmenter_callbacks_t callbacks;
+};
+
+TEST_F(PacketFragmenterTest, test_set_data_sizes) {
+ reset_for(set_data_sizes);
+ fragmenter->set_acl_data_size(1337);
+ fragmenter->set_ble_acl_data_size(42);
+}
+
+TEST_F(PacketFragmenterTest, test_no_fragment_necessary) {
+ reset_for(no_fragmentation);
+ fragmenter->set_acl_data_size(42);
+
+ BT_HDR *packet = manufacture_packet_for_fragmentation(MSG_STACK_TO_HC_HCI_ACL, small_sample_data);
+ fragmenter->fragment_and_dispatch(packet);
+ free(packet);
+
+ EXPECT_EQ(strlen(small_sample_data), data_size_sum);
+ EXPECT_CALL_COUNT(fragmented_callback, 1);
+}
+
+TEST_F(PacketFragmenterTest, test_fragment_necessary) {
+ reset_for(fragmentation);
+ fragmenter->set_acl_data_size(10);
+
+ BT_HDR *packet = manufacture_packet_for_fragmentation(MSG_STACK_TO_HC_HCI_ACL, sample_data);
+ fragmenter->fragment_and_dispatch(packet);
+ free(packet);
+
+ EXPECT_EQ(strlen(sample_data), data_size_sum);
+}
+
+TEST_F(PacketFragmenterTest, test_ble_no_fragment_necessary) {
+ reset_for(ble_no_fragmentation);
+ fragmenter->set_acl_data_size(1);
+ fragmenter->set_ble_acl_data_size(42);
+
+ BT_HDR *packet = manufacture_packet_for_fragmentation(MSG_STACK_TO_HC_HCI_ACL, small_sample_data);
+ packet->event |= LOCAL_BLE_CONTROLLER_ID;
+ fragmenter->fragment_and_dispatch(packet);
+ free(packet);
+
+ EXPECT_EQ(strlen(small_sample_data), data_size_sum);
+ EXPECT_CALL_COUNT(fragmented_callback, 1);
+}
+
+TEST_F(PacketFragmenterTest, test_ble_fragment_necessary) {
+ reset_for(ble_fragmentation);
+ fragmenter->set_acl_data_size(10000);
+ fragmenter->set_ble_acl_data_size(10);
+
+ BT_HDR *packet = manufacture_packet_for_fragmentation(MSG_STACK_TO_HC_HCI_ACL, sample_data);
+ packet->event |= LOCAL_BLE_CONTROLLER_ID;
+ fragmenter->fragment_and_dispatch(packet);
+ free(packet);
+
+ EXPECT_EQ(strlen(sample_data), data_size_sum);
+}
+
+TEST_F(PacketFragmenterTest, test_non_acl_passthrough_fragmentation) {
+ reset_for(non_acl_passthrough_fragmentation);
+ fragmenter->set_acl_data_size(42);
+ fragmenter->set_ble_acl_data_size(42);
+
+ BT_HDR *packet = manufacture_packet_for_fragmentation(MSG_STACK_TO_HC_HCI_CMD, sample_data);
+ fragmenter->fragment_and_dispatch(packet);
+ free(packet);
+
+ EXPECT_EQ(strlen(sample_data), data_size_sum);
+ EXPECT_CALL_COUNT(fragmented_callback, 1);
+}
+
+TEST_F(PacketFragmenterTest, test_no_reassembly_necessary) {
+ reset_for(no_reassembly);
+ fragmenter->set_acl_data_size(1337);
+ manufacture_packet_and_then_reassemble(MSG_HC_TO_STACK_HCI_ACL, 1337, small_sample_data);
+
+ EXPECT_EQ(strlen(small_sample_data), data_size_sum);
+ EXPECT_CALL_COUNT(reassembled_callback, 1);
+}
+
+TEST_F(PacketFragmenterTest, test_reassembly_necessary) {
+ reset_for(reassembly);
+ fragmenter->set_acl_data_size(42);
+ manufacture_packet_and_then_reassemble(MSG_HC_TO_STACK_HCI_ACL, 42, sample_data);
+
+ EXPECT_EQ(strlen(sample_data), data_size_sum);
+ EXPECT_CALL_COUNT(reassembled_callback, 1);
+}
+
+TEST_F(PacketFragmenterTest, test_non_acl_passthrough_reasseembly) {
+ reset_for(non_acl_passthrough_reassembly);
+ fragmenter->set_acl_data_size(42);
+ manufacture_packet_and_then_reassemble(MSG_HC_TO_STACK_HCI_EVT, 42, sample_data);
+
+ EXPECT_EQ(strlen(sample_data), data_size_sum);
+ EXPECT_CALL_COUNT(reassembled_callback, 1);
+}
diff --git a/main/bte_main.c b/main/bte_main.c
index 3b8964ff7..296263d9d 100755
--- a/main/bte_main.c
+++ b/main/bte_main.c
@@ -30,8 +30,7 @@
#include <signal.h>
#include <stdlib.h>
#include <time.h>
-#include <hardware/bluetooth.h>
-#include <cutils/properties.h>
+#include <utils/Log.h>
#include "alarm.h"
#include "bd.h"
@@ -39,10 +38,12 @@
#include "bt_hci_bdroid.h"
#include "bte.h"
#include "btu.h"
-#include "bt_hci_lib.h"
#include "bt_utils.h"
+#include "fixed_queue.h"
#include "gki.h"
+#include "hci_layer.h"
#include "osi.h"
+#include "thread.h"
/*******************************************************************************
** Constants & Macros
@@ -88,13 +89,18 @@ char hci_logfile[256] = HCI_LOGGING_FILENAME;
/*******************************************************************************
** Static variables
*******************************************************************************/
-static bt_hc_interface_t *bt_hc_if=NULL;
-static const bt_hc_callbacks_t hc_callbacks;
-static BOOLEAN lpm_enabled = FALSE;
+static const hci_interface_t *hci;
+static const hci_callbacks_t hci_callbacks;
+static const allocator_t buffer_allocator;
static bt_preload_retry_cb_t preload_retry_cb;
// Lock to serialize cleanup requests from upper layer.
static pthread_mutex_t cleanup_lock;
+// These are temporary so we can run the new HCI code
+// with the old upper stack.
+static fixed_queue_t *upbound_data;
+static thread_t *dispatch_thread;
+
/*******************************************************************************
** Static functions
*******************************************************************************/
@@ -102,6 +108,7 @@ static void bte_hci_enable(void);
static void bte_hci_disable(void);
static void preload_start_wait_timer(void);
static void preload_stop_wait_timer(void);
+static void dump_upbound_data_to_btu(fixed_queue_t *queue, void *context);
/*******************************************************************************
** Externs
@@ -141,8 +148,21 @@ void bte_main_boot_entry(void)
/* initialize OS */
GKI_init();
- if (!(bt_hc_if = (bt_hc_interface_t *)bt_hc_get_interface()))
- APPL_TRACE_ERROR("!!! Failed to get BtHostControllerInterface !!!");
+ hci = hci_layer_get_interface();
+ if (!hci)
+ ALOGE("%s could not get hci layer interface.", __func__);
+
+ upbound_data = fixed_queue_new(SIZE_MAX);
+ dispatch_thread = thread_new("hci_dispatch");
+
+ fixed_queue_register_dequeue(
+ upbound_data,
+ thread_get_reactor(dispatch_thread),
+ dump_upbound_data_to_btu,
+ NULL
+ );
+
+ data_dispatcher_register_default(hci->upward_dispatcher, upbound_data);
memset(&preload_retry_cb, 0, sizeof(bt_preload_retry_cb_t));
preload_retry_cb.alarm = alarm_new();
@@ -197,8 +217,6 @@ void bte_main_enable()
/* Initialize BTE control block */
BTE_Init();
- lpm_enabled = FALSE;
-
GKI_create_task((TASKPTR)btu_task, BTU_TASK, BTE_BTU_TASK_STR,
(UINT16 *) ((UINT8 *)bte_btu_stack + BTE_BTU_STACK_SIZE),
sizeof(bte_btu_stack));
@@ -241,19 +259,18 @@ void bte_main_config_hci_logging(BOOLEAN enable, BOOLEAN bt_disabled)
int old = (hci_logging_enabled == TRUE) || (hci_logging_config == TRUE);
int new;
- if (enable) {
- hci_logging_config = TRUE;
- } else {
- hci_logging_config = FALSE;
- }
+ hci_logging_config = enable;
new = (hci_logging_enabled == TRUE) || (hci_logging_config == TRUE);
- if ((old == new) || bt_disabled || (bt_hc_if == NULL)) {
+ if ((old == new) || bt_disabled) {
return;
}
- bt_hc_if->logging(new ? BT_HC_LOGGING_ON : BT_HC_LOGGING_OFF, hci_logfile, hci_save_log);
+ if (new)
+ hci->turn_on_logging(hci_logfile);
+ else
+ hci->turn_off_logging();
}
/******************************************************************************
@@ -271,38 +288,34 @@ static void bte_hci_enable(void)
preload_start_wait_timer();
- if (bt_hc_if)
- {
- int result = bt_hc_if->init(&hc_callbacks, btif_local_bd_addr.address);
- APPL_TRACE_EVENT("libbt-hci init returns %d", result);
+ bool success = hci->init(btif_local_bd_addr.address, &buffer_allocator, &hci_callbacks);
+ APPL_TRACE_EVENT("libbt-hci init returns %d", success);
- assert(result == BT_HC_STATUS_SUCCESS);
+ assert(success);
- if (hci_logging_enabled == TRUE || hci_logging_config == TRUE)
- bt_hc_if->logging(BT_HC_LOGGING_ON, hci_logfile, hci_save_log);
+ if (hci_logging_enabled == TRUE || hci_logging_config == TRUE)
+ hci->turn_on_logging(hci_logfile);
#if (defined (BT_CLEAN_TURN_ON_DISABLED) && BT_CLEAN_TURN_ON_DISABLED == TRUE)
- APPL_TRACE_DEBUG("%s Not Turninig Off the BT before Turninig ON", __FUNCTION__);
+ APPL_TRACE_DEBUG("%s not turning off the chip before turning it on", __FUNCTION__);
- /* Do not power off the chip before powering on if BT_CLEAN_TURN_ON_DISABLED flag
- is defined and set to TRUE to avoid below mentioned issue.
+ /* Do not power off the chip before powering on if BT_CLEAN_TURN_ON_DISABLED flag
+ is defined and set to TRUE to avoid below mentioned issue.
- Wingray kernel driver maintains a combined counter to keep track of
- BT-Wifi state. Invoking set_power(BT_HC_CHIP_PWR_OFF) when the BT is already
- in OFF state causes this counter to be incorrectly decremented and results in undesired
- behavior of the chip.
+ Wingray kernel driver maintains a combined counter to keep track of
+ BT-Wifi state. Invoking set_power(BT_HC_CHIP_PWR_OFF) when the BT is already
+ in OFF state causes this counter to be incorrectly decremented and results in undesired
+ behavior of the chip.
- This is only a workaround and when the issue is fixed in the kernel this work around
- should be removed. */
+ This is only a workaround and when the issue is fixed in the kernel this work around
+ should be removed. */
#else
- /* toggle chip power to ensure we will reset chip in case
- a previous stack shutdown wasn't completed gracefully */
- bt_hc_if->set_power(BT_HC_CHIP_PWR_OFF);
+ /* toggle chip power to ensure we will reset chip in case
+ a previous stack shutdown wasn't completed gracefully */
+ hci->set_chip_power_on(false);
#endif
- bt_hc_if->set_power(BT_HC_CHIP_PWR_ON);
-
- bt_hc_if->preload(NULL);
- }
+ hci->set_chip_power_on(true);
+ hci->do_preload();
}
/******************************************************************************
@@ -318,15 +331,15 @@ static void bte_hci_disable(void)
{
APPL_TRACE_DEBUG("%s", __FUNCTION__);
- if (!bt_hc_if)
+ if (!hci)
return;
// Cleanup is not thread safe and must be protected.
pthread_mutex_lock(&cleanup_lock);
if (hci_logging_enabled == TRUE || hci_logging_config == TRUE)
- bt_hc_if->logging(BT_HC_LOGGING_OFF, hci_logfile, hci_save_log);
- bt_hc_if->cleanup();
+ hci->turn_off_logging();
+ hci->cleanup();
pthread_mutex_unlock(&cleanup_lock);
}
@@ -403,8 +416,7 @@ static void preload_stop_wait_timer(void)
******************************************************************************/
void bte_main_postload_cfg(void)
{
- if (bt_hc_if)
- bt_hc_if->postload(NULL);
+ hci->do_postload();
}
#if (defined(HCILP_INCLUDED) && HCILP_INCLUDED == TRUE)
@@ -419,14 +431,7 @@ void bte_main_postload_cfg(void)
******************************************************************************/
void bte_main_enable_lpm(BOOLEAN enable)
{
- int result = -1;
-
- if (bt_hc_if)
- result = bt_hc_if->lpm( \
- (enable == TRUE) ? BT_HC_LPM_ENABLE : BT_HC_LPM_DISABLE \
- );
-
- APPL_TRACE_EVENT("HC lib lpm enable=%d return %d", enable, result);
+ hci->send_low_power_command(enable ? LPM_ENABLE : LPM_DISABLE);
}
/******************************************************************************
@@ -440,12 +445,7 @@ void bte_main_enable_lpm(BOOLEAN enable)
******************************************************************************/
void bte_main_lpm_allow_bt_device_sleep()
{
- int result = -1;
-
- if ((bt_hc_if) && (lpm_enabled == TRUE))
- result = bt_hc_if->lpm(BT_HC_LPM_WAKE_DEASSERT);
-
- APPL_TRACE_DEBUG("HC lib lpm deassertion return %d", result);
+ hci->send_low_power_command(LPM_WAKE_DEASSERT);
}
/******************************************************************************
@@ -459,12 +459,7 @@ void bte_main_lpm_allow_bt_device_sleep()
******************************************************************************/
void bte_main_lpm_wake_bt_device()
{
- int result = -1;
-
- if ((bt_hc_if) && (lpm_enabled == TRUE))
- result = bt_hc_if->lpm(BT_HC_LPM_WAKE_ASSERT);
-
- APPL_TRACE_DEBUG("HC lib lpm assertion return %d", result);
+ hci->send_low_power_command(LPM_WAKE_ASSERT);
}
#endif // HCILP_INCLUDED
@@ -520,10 +515,7 @@ int set_audio_state(UINT16 handle, UINT16 codec, UINT8 state, void *param)
/* layer_specific shall contain return path event! for BTA events!
* 0 means no return message is expected. */
p_msg->hdr.layer_specific = 0;
- if (bt_hc_if)
- {
- bt_hc_if->tx_cmd((TRANSAC)p_msg, (char *)(&p_msg->audio), sizeof(*p_msg));
- }
+ hci->transmit_downward(MSG_STACK_TO_HC_HCI_CMD, p_msg);
return result;
}
@@ -550,12 +542,7 @@ void bte_main_hci_send (BT_HDR *p_msg, UINT16 event)
if((sub_event == LOCAL_BR_EDR_CONTROLLER_ID) || \
(sub_event == LOCAL_BLE_CONTROLLER_ID))
{
- if (bt_hc_if)
- bt_hc_if->transmit_buf((TRANSAC)p_msg, \
- (char *) (p_msg + 1), \
- p_msg->len);
- else
- GKI_freebuf(p_msg);
+ hci->transmit_downward(event, p_msg);
}
else
{
@@ -595,13 +582,11 @@ void bte_main_post_reset_init()
** Returns None
**
******************************************************************************/
-static void preload_cb(TRANSAC transac, bt_hc_preload_result_t result)
+static void preload_cb(bool success)
{
- UNUSED(transac);
-
- APPL_TRACE_EVENT("HC preload_cb %d [0:SUCCESS 1:FAIL]", result);
+ APPL_TRACE_EVENT("HC preload_cb %d [1:SUCCESS 0:FAIL]", success);
- if (result == BT_HC_PRELOAD_SUCCESS)
+ if (success)
{
preload_stop_wait_timer();
@@ -612,54 +597,6 @@ static void preload_cb(TRANSAC transac, bt_hc_preload_result_t result)
/******************************************************************************
**
-** Function postload_cb
-**
-** Description HOST/CONTROLLER LIB CALLBACK API - This function is called
-** when the libbt-hci lib completed stack postload process
-**
-** Returns None
-**
-******************************************************************************/
-static void postload_cb(TRANSAC transac, bt_hc_postload_result_t result)
-{
- UNUSED(transac);
-
- APPL_TRACE_EVENT("HC postload_cb %d", result);
-}
-
-/******************************************************************************
-**
-** Function lpm_cb
-**
-** Description HOST/CONTROLLER LIB CALLBACK API - This function is called
-** back from the libbt-hci to indicate the current LPM state
-**
-** Returns None
-**
-******************************************************************************/
-static void lpm_cb(bt_hc_lpm_request_result_t result)
-{
- APPL_TRACE_EVENT("HC lpm_result_cb %d", result);
- lpm_enabled = (result == BT_HC_LPM_ENABLED) ? TRUE : FALSE;
-}
-
-/******************************************************************************
-**
-** Function hostwake_ind
-**
-** Description HOST/CONTROLLER LIB CALLOUT API - This function is called
-** from the libbt-hci to indicate the HostWake event
-**
-** Returns None
-**
-******************************************************************************/
-static void hostwake_ind(bt_hc_low_power_event_t event)
-{
- APPL_TRACE_EVENT("HC hostwake_ind %d", event);
-}
-
-/******************************************************************************
-**
** Function alloc
**
** Description HOST/CONTROLLER LIB CALLOUT API - This function is called
@@ -668,14 +605,8 @@ static void hostwake_ind(bt_hc_low_power_event_t event)
** Returns NULL / pointer to allocated buffer
**
******************************************************************************/
-static char *alloc(int size)
+static void *alloc(size_t size)
{
- BT_HDR *p_hdr = NULL;
-
- /*
- APPL_TRACE_DEBUG("HC alloc size=%d", size);
- */
-
/* Requested buffer size cannot exceed GKI_MAX_BUF_SIZE. */
if (size > GKI_MAX_BUF_SIZE)
{
@@ -684,14 +615,14 @@ static char *alloc(int size)
return NULL;
}
- p_hdr = (BT_HDR *) GKI_getbuf ((UINT16) size);
+ BT_HDR *p_hdr = (BT_HDR *) GKI_getbuf ((UINT16) size);
- if (p_hdr == NULL)
+ if (!p_hdr)
{
APPL_TRACE_WARNING("alloc returns NO BUFFER! (sz %d)", size);
}
- return ((char *) p_hdr);
+ return p_hdr;
}
/******************************************************************************
@@ -707,43 +638,13 @@ static char *alloc(int size)
** boundary.
**
******************************************************************************/
-static void dealloc(TRANSAC transac)
+static void dealloc(void *buffer)
{
- GKI_freebuf(transac);
+ GKI_freebuf(buffer);
}
-/******************************************************************************
-**
-** Function data_ind
-**
-** Description HOST/CONTROLLER LIB CALLOUT API - This function is called
-** from the libbt-hci to pass in the received HCI packets
-**
-** The core stack is responsible for releasing the data buffer
-** passed in from the libbt-hci once the core stack has done
-** with it.
-**
-** Bluedroid libbt-hci library uses 'transac' parameter to
-** pass data-path buffer/packet across bt_hci_lib interface
-** boundary. The 'p_buf' and 'len' parameters are not intended
-** to be used here but might point to data portion in data-
-** path buffer and length of valid data respectively.
-**
-** Returns bt_hc_status_t
-**
-******************************************************************************/
-static int data_ind(TRANSAC transac, char *p_buf, int len)
-{
- BT_HDR *p_msg = (BT_HDR *) transac;
- UNUSED(p_buf);
- UNUSED(len);
-
- /*
- APPL_TRACE_DEBUG("HC data_ind event=0x%04X (len=%d)", p_msg->event, len);
- */
-
- GKI_send_msg (BTU_TASK, BTU_HCI_RCV_MBOX, transac);
- return BT_HC_STATUS_SUCCESS;
+static void dump_upbound_data_to_btu(fixed_queue_t *queue, UNUSED_ATTR void *context) {
+ GKI_send_msg (BTU_TASK, BTU_HCI_RCV_MBOX, fixed_queue_dequeue(queue));
}
/******************************************************************************
@@ -766,38 +667,28 @@ static int data_ind(TRANSAC transac, char *p_buf, int len)
** Returns bt_hc_status_t
**
******************************************************************************/
-static int tx_result(TRANSAC transac, char *p_buf, bt_hc_transmit_result_t result)
+static void tx_result(void *p_buf, bool all_fragments_sent)
{
- UNUSED(p_buf);
- /*
- APPL_TRACE_DEBUG("HC tx_result %d (event=%04X)", result, \
- ((BT_HDR *)transac)->event);
- */
-
- if (result == BT_HC_TX_FRAGMENT)
+ if (!all_fragments_sent)
{
- GKI_send_msg (BTU_TASK, BTU_HCI_RCV_MBOX, transac);
+ GKI_send_msg (BTU_TASK, BTU_HCI_RCV_MBOX, p_buf);
}
else
{
- GKI_freebuf(transac);
+ GKI_freebuf(p_buf);
}
-
- return BT_HC_STATUS_SUCCESS;
}
/*****************************************************************************
** The libbt-hci Callback Functions Table
*****************************************************************************/
-static const bt_hc_callbacks_t hc_callbacks = {
- sizeof(bt_hc_callbacks_t),
+static const hci_callbacks_t hci_callbacks = {
preload_cb,
- postload_cb,
- lpm_cb,
- hostwake_ind,
- alloc,
- dealloc,
- data_ind,
tx_result
};
+static const allocator_t buffer_allocator = {
+ alloc,
+ dealloc
+};
+