blob: 0e7db9c6506ca4fc43176de681096b5912b06dba [file] [log] [blame]
/******************************************************************************
*
* 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 <assert.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#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
static bool hal_init(const hci_hal_callbacks_t* upper_callbacks,
thread_t* upper_thread);
static bool hal_open(void);
static void hal_close(void);
static size_t read_data(serial_data_type_t type, uint8_t* buffer,
size_t max_size);
static void packet_finished(UNUSED_ATTR serial_data_type_t type);
static uint16_t transmit_data(serial_data_type_t type, uint8_t* data,
uint16_t length);
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);
// Our interface and modules we import
static const hci_hal_t interface = {
hal_init, hal_open, hal_close, read_data, packet_finished, transmit_data,
};
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;
// 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(void) {
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(void) {
LOG_INFO(LOG_TAG, "%s", __func__);
eager_reader_free(event_stream);
event_stream = NULL;
eager_reader_free(acl_stream);
acl_stream = NULL;
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);
}
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;
}