/****************************************************************************** * * 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_hci_mct" #include #include #include #include #include "bt_vendor_lib.h" #include "hci_hal.h" #include "osi/include/eager_reader.h" #include "osi/include/log.h" #include "osi/include/osi.h" #include "osi/include/reactor.h" #include "vendor.h" #define HCI_HAL_SERIAL_BUFFER_SIZE 1026 // Our interface and modules we import static const hci_hal_t interface; static const hci_hal_callbacks_t *callbacks; static const vendor_t *vendor; static thread_t *thread; // Not owned by us static int uart_fds[CH_MAX]; static eager_reader_t *event_stream; static eager_reader_t *acl_stream; static uint16_t transmit_data_on(int fd, uint8_t *data, uint16_t length); static void event_event_stream_has_bytes(eager_reader_t *reader, void *context); static void event_acl_stream_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() { LOG_INFO(LOG_TAG, "%s", __func__); // TODO(zachoverflow): close if already open / or don't reopen (maybe at the hci layer level) int number_of_ports = vendor->send_command(VENDOR_OPEN_USERIAL, &uart_fds); if (number_of_ports != 2 && number_of_ports != 4) { LOG_ERROR(LOG_TAG, "%s opened the wrong number of ports: got %d, expected 2 or 4.", __func__, number_of_ports); goto error; } LOG_INFO(LOG_TAG, "%s got uart fds: CMD=%d, EVT=%d, ACL_OUT=%d, ACL_IN=%d", __func__, uart_fds[CH_CMD], uart_fds[CH_EVT], uart_fds[CH_ACL_OUT], uart_fds[CH_ACL_IN]); if (uart_fds[CH_CMD] == INVALID_FD) { LOG_ERROR(LOG_TAG, "%s unable to open the command uart serial port.", __func__); goto error; } if (uart_fds[CH_EVT] == INVALID_FD) { LOG_ERROR(LOG_TAG, "%s unable to open the event uart serial port.", __func__); goto error; } if (uart_fds[CH_ACL_OUT] == INVALID_FD) { LOG_ERROR(LOG_TAG, "%s unable to open the acl-out uart serial port.", __func__); goto error; } if (uart_fds[CH_ACL_IN] == INVALID_FD) { LOG_ERROR(LOG_TAG, "%s unable to open the acl-in uart serial port.", __func__); goto error; } event_stream = eager_reader_new(uart_fds[CH_EVT], &allocator_malloc, HCI_HAL_SERIAL_BUFFER_SIZE, SIZE_MAX, "hci_mct"); if (!event_stream) { LOG_ERROR(LOG_TAG, "%s unable to create eager reader for the event uart serial port.", __func__); goto error; } acl_stream = eager_reader_new(uart_fds[CH_ACL_IN], &allocator_malloc, HCI_HAL_SERIAL_BUFFER_SIZE, SIZE_MAX, "hci_mct"); if (!acl_stream) { LOG_ERROR(LOG_TAG, "%s unable to create eager reader for the acl-in uart serial port.", __func__); goto error; } eager_reader_register(event_stream, thread_get_reactor(thread), event_event_stream_has_bytes, NULL); eager_reader_register(acl_stream, thread_get_reactor(thread), event_acl_stream_has_bytes, NULL); return true; error:; interface.close(); return false; } static void hal_close() { LOG_INFO(LOG_TAG, "%s", __func__); eager_reader_free(event_stream); eager_reader_free(acl_stream); vendor->send_command(VENDOR_CLOSE_USERIAL, NULL); for (int i = 0; i < CH_MAX; i++) uart_fds[i] = INVALID_FD; } static size_t read_data(serial_data_type_t type, uint8_t *buffer, size_t max_size) { if (type == DATA_TYPE_ACL) { return eager_reader_read(acl_stream, buffer, max_size); } else if (type == DATA_TYPE_EVENT) { return eager_reader_read(event_stream, buffer, max_size); } LOG_ERROR(LOG_TAG, "%s invalid data type: %d", __func__, type); return 0; } static void packet_finished(UNUSED_ATTR serial_data_type_t type) { // not needed by this protocol } static uint16_t transmit_data(serial_data_type_t type, uint8_t *data, uint16_t length) { if (type == DATA_TYPE_ACL) { return transmit_data_on(uart_fds[CH_ACL_OUT], data, length); } else if (type == DATA_TYPE_COMMAND) { return transmit_data_on(uart_fds[CH_CMD], data, length); } LOG_ERROR(LOG_TAG, "%s invalid data type: %d", __func__, type); return 0; } // Internal functions static uint16_t transmit_data_on(int fd, uint8_t *data, uint16_t length) { assert(data != NULL); assert(length > 0); uint16_t transmitted_length = 0; while (length > 0) { ssize_t ret; OSI_NO_INTR(ret = write(fd, data + transmitted_length, length)); switch (ret) { case -1: LOG_ERROR(LOG_TAG, "In %s, error writing to the serial port with fd %d: %s", __func__, fd, strerror(errno)); return transmitted_length; case 0: // If we wrote nothing, don't loop more because we // can't go to infinity or beyond return transmitted_length; default: transmitted_length += ret; length -= ret; break; } } return transmitted_length; } static void event_event_stream_has_bytes(UNUSED_ATTR eager_reader_t *reader, UNUSED_ATTR void *context) { callbacks->data_ready(DATA_TYPE_EVENT); } static void event_acl_stream_has_bytes(UNUSED_ATTR eager_reader_t *reader, UNUSED_ATTR void *context) { // No real concept of incoming SCO typed data, just ACL callbacks->data_ready(DATA_TYPE_ACL); } static const hci_hal_t interface = { hal_init, hal_open, hal_close, read_data, packet_finished, transmit_data, }; const hci_hal_t *hci_hal_mct_get_interface() { vendor = vendor_get_interface(); return &interface; } const hci_hal_t *hci_hal_mct_get_test_interface(vendor_t *vendor_interface) { vendor = vendor_interface; return &interface; }