summaryrefslogtreecommitdiffstats
path: root/hci/src/hci_hal_h4.c
diff options
context:
space:
mode:
Diffstat (limited to 'hci/src/hci_hal_h4.c')
-rw-r--r--hci/src/hci_hal_h4.c224
1 files changed, 224 insertions, 0 deletions
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;
+}