1/****************************************************************************** 2 * 3 * Copyright (C) 2014 Google, Inc. 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at: 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 * 17 ******************************************************************************/ 18 19#define LOG_TAG "bt_hci_mct" 20 21#include <assert.h> 22#include <errno.h> 23#include <string.h> 24 25#include "bt_vendor_lib.h" 26#include "osi/include/eager_reader.h" 27#include "hci_hal.h" 28#include "osi/include/osi.h" 29#include "osi/include/log.h" 30#include "osi/include/reactor.h" 31#include "vendor.h" 32 33#define HCI_HAL_SERIAL_BUFFER_SIZE 1026 34 35// Our interface and modules we import 36static const hci_hal_t interface; 37static const hci_hal_callbacks_t *callbacks; 38static const vendor_t *vendor; 39 40static thread_t *thread; // Not owned by us 41 42static int uart_fds[CH_MAX]; 43static eager_reader_t *event_stream; 44static eager_reader_t *acl_stream; 45 46static uint16_t transmit_data_on(int fd, uint8_t *data, uint16_t length); 47static void event_event_stream_has_bytes(eager_reader_t *reader, void *context); 48static void event_acl_stream_has_bytes(eager_reader_t *reader, void *context); 49 50// Interface functions 51 52static bool hal_init(const hci_hal_callbacks_t *upper_callbacks, thread_t *upper_thread) { 53 assert(upper_callbacks != NULL); 54 assert(upper_thread != NULL); 55 56 callbacks = upper_callbacks; 57 thread = upper_thread; 58 return true; 59} 60 61static bool hal_open() { 62 LOG_INFO("%s", __func__); 63 // TODO(zachoverflow): close if already open / or don't reopen (maybe at the hci layer level) 64 65 int number_of_ports = vendor->send_command(VENDOR_OPEN_USERIAL, &uart_fds); 66 67 if (number_of_ports != 2 && number_of_ports != 4) { 68 LOG_ERROR("%s opened the wrong number of ports: got %d, expected 2 or 4.", __func__, number_of_ports); 69 goto error; 70 } 71 72 LOG_INFO("%s got uart fds: CMD=%d, EVT=%d, ACL_OUT=%d, ACL_IN=%d", 73 __func__, uart_fds[CH_CMD], uart_fds[CH_EVT], uart_fds[CH_ACL_OUT], uart_fds[CH_ACL_IN]); 74 75 if (uart_fds[CH_CMD] == INVALID_FD) { 76 LOG_ERROR("%s unable to open the command uart serial port.", __func__); 77 goto error; 78 } 79 80 if (uart_fds[CH_EVT] == INVALID_FD) { 81 LOG_ERROR("%s unable to open the event uart serial port.", __func__); 82 goto error; 83 } 84 85 if (uart_fds[CH_ACL_OUT] == INVALID_FD) { 86 LOG_ERROR("%s unable to open the acl-out uart serial port.", __func__); 87 goto error; 88 } 89 90 if (uart_fds[CH_ACL_IN] == INVALID_FD) { 91 LOG_ERROR("%s unable to open the acl-in uart serial port.", __func__); 92 goto error; 93 } 94 95 event_stream = eager_reader_new(uart_fds[CH_EVT], &allocator_malloc, HCI_HAL_SERIAL_BUFFER_SIZE, SIZE_MAX, "hci_mct"); 96 if (!event_stream) { 97 LOG_ERROR("%s unable to create eager reader for the event uart serial port.", __func__); 98 goto error; 99 } 100 101 acl_stream = eager_reader_new(uart_fds[CH_ACL_IN], &allocator_malloc, HCI_HAL_SERIAL_BUFFER_SIZE, SIZE_MAX, "hci_mct"); 102 if (!event_stream) { 103 LOG_ERROR("%s unable to create eager reader for the acl-in uart serial port.", __func__); 104 goto error; 105 } 106 107 eager_reader_register(event_stream, thread_get_reactor(thread), event_event_stream_has_bytes, NULL); 108 eager_reader_register(acl_stream, thread_get_reactor(thread), event_acl_stream_has_bytes, NULL); 109 110 return true; 111 112error:; 113 interface.close(); 114 return false; 115} 116 117static void hal_close() { 118 LOG_INFO("%s", __func__); 119 120 eager_reader_free(event_stream); 121 eager_reader_free(acl_stream); 122 vendor->send_command(VENDOR_CLOSE_USERIAL, NULL); 123 124 for (int i = 0; i < CH_MAX; i++) 125 uart_fds[i] = INVALID_FD; 126} 127 128static size_t read_data(serial_data_type_t type, uint8_t *buffer, size_t max_size, bool block) { 129 if (type == DATA_TYPE_ACL) { 130 return eager_reader_read(acl_stream, buffer, max_size, block); 131 } else if (type == DATA_TYPE_EVENT) { 132 return eager_reader_read(event_stream, buffer, max_size, block); 133 } 134 135 LOG_ERROR("%s invalid data type: %d", __func__, type); 136 return 0; 137} 138 139static void packet_finished(UNUSED_ATTR serial_data_type_t type) { 140 // not needed by this protocol 141} 142 143static uint16_t transmit_data(serial_data_type_t type, uint8_t *data, uint16_t length) { 144 if (type == DATA_TYPE_ACL) { 145 return transmit_data_on(uart_fds[CH_ACL_OUT], data, length); 146 } else if (type == DATA_TYPE_COMMAND) { 147 return transmit_data_on(uart_fds[CH_CMD], data, length); 148 } 149 150 LOG_ERROR("%s invalid data type: %d", __func__, type); 151 return 0; 152} 153 154// Internal functions 155 156static uint16_t transmit_data_on(int fd, uint8_t *data, uint16_t length) { 157 assert(data != NULL); 158 assert(length > 0); 159 160 uint16_t transmitted_length = 0; 161 while (length > 0) { 162 ssize_t ret = write(fd, data + transmitted_length, length); 163 switch (ret) { 164 case -1: 165 LOG_ERROR("In %s, error writing to the serial port with fd %d: %s", __func__, fd, strerror(errno)); 166 return transmitted_length; 167 case 0: 168 // If we wrote nothing, don't loop more because we 169 // can't go to infinity or beyond 170 return transmitted_length; 171 default: 172 transmitted_length += ret; 173 length -= ret; 174 break; 175 } 176 } 177 178 return transmitted_length; 179} 180 181static void event_event_stream_has_bytes(UNUSED_ATTR eager_reader_t *reader, UNUSED_ATTR void *context) { 182 callbacks->data_ready(DATA_TYPE_EVENT); 183} 184 185static void event_acl_stream_has_bytes(UNUSED_ATTR eager_reader_t *reader, UNUSED_ATTR void *context) { 186 // No real concept of incoming SCO typed data, just ACL 187 callbacks->data_ready(DATA_TYPE_ACL); 188} 189 190static const hci_hal_t interface = { 191 hal_init, 192 193 hal_open, 194 hal_close, 195 196 read_data, 197 packet_finished, 198 transmit_data, 199}; 200 201const hci_hal_t *hci_hal_mct_get_interface() { 202 vendor = vendor_get_interface(); 203 return &interface; 204} 205 206const hci_hal_t *hci_hal_mct_get_test_interface(vendor_t *vendor_interface) { 207 vendor = vendor_interface; 208 return &interface; 209} 210