/* * Copyright (C) 2013 Intel 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. * */ #include #include #include #include #include #include "hal-log.h" #include "hal.h" #include "hal-msg.h" #include "ipc-common.h" #include "hal-ipc.h" #include "hal-utils.h" #define MODE_PROPERTY_NAME "persist.sys.bluetooth.mode" static const bt_callbacks_t *bt_hal_cbacks = NULL; #define enum_prop_to_hal(prop, hal_prop, type) do { \ static type e; \ prop.val = &e; \ prop.len = sizeof(e); \ e = *((uint8_t *) (hal_prop->val)); \ } while (0) #define enum_prop_from_hal(prop, hal_len, hal_val, enum_type) do { \ enum_type e; \ if (prop->len != sizeof(e)) { \ error("invalid HAL property %u (%u vs %zu), aborting ", \ prop->type, prop->len, sizeof(e)); \ exit(EXIT_FAILURE); \ } \ memcpy(&e, prop->val, sizeof(e)); \ *((uint8_t *) hal_val) = e; /* enums are mapped to 1 byte */ \ *hal_len = 1; \ } while (0) static void handle_adapter_state_changed(void *buf, uint16_t len) { struct hal_ev_adapter_state_changed *ev = buf; DBG("state: %s", bt_state_t2str(ev->state)); if (bt_hal_cbacks->adapter_state_changed_cb) bt_hal_cbacks->adapter_state_changed_cb(ev->state); } static void adapter_props_to_hal(bt_property_t *send_props, struct hal_property *prop, uint8_t num_props, uint16_t len) { void *buf = prop; uint8_t i; for (i = 0; i < num_props; i++) { if (sizeof(*prop) + prop->len > len) { error("invalid adapter properties(%zu > %u), aborting", sizeof(*prop) + prop->len, len); exit(EXIT_FAILURE); } send_props[i].type = prop->type; switch (prop->type) { case HAL_PROP_ADAPTER_TYPE: enum_prop_to_hal(send_props[i], prop, bt_device_type_t); break; case HAL_PROP_ADAPTER_SCAN_MODE: enum_prop_to_hal(send_props[i], prop, bt_scan_mode_t); break; case HAL_PROP_ADAPTER_SERVICE_REC: default: send_props[i].len = prop->len; send_props[i].val = prop->val; break; } DBG("prop[%d]: %s", i, btproperty2str(&send_props[i])); len -= sizeof(*prop) + prop->len; buf += sizeof(*prop) + prop->len; prop = buf; } if (!len) return; error("invalid adapter properties (%u bytes left), aborting", len); exit(EXIT_FAILURE); } static void adapter_prop_from_hal(const bt_property_t *property, uint8_t *type, uint16_t *len, void *val) { /* type match IPC type */ *type = property->type; switch (property->type) { case HAL_PROP_ADAPTER_SCAN_MODE: enum_prop_from_hal(property, len, val, bt_scan_mode_t); break; default: *len = property->len; memcpy(val, property->val, property->len); break; } } static void device_props_to_hal(bt_property_t *send_props, struct hal_property *prop, uint8_t num_props, uint16_t len) { void *buf = prop; uint8_t i; for (i = 0; i < num_props; i++) { if (sizeof(*prop) + prop->len > len) { error("invalid device properties (%zu > %u), aborting", sizeof(*prop) + prop->len, len); exit(EXIT_FAILURE); } send_props[i].type = prop->type; switch (prop->type) { case HAL_PROP_DEVICE_TYPE: enum_prop_to_hal(send_props[i], prop, bt_device_type_t); break; case HAL_PROP_DEVICE_VERSION_INFO: { static bt_remote_version_t e; const struct hal_prop_device_info *p; send_props[i].val = &e; send_props[i].len = sizeof(e); p = (struct hal_prop_device_info *) prop->val; e.manufacturer = p->manufacturer; e.sub_ver = p->sub_version; e.version = p->version; } break; case HAL_PROP_DEVICE_SERVICE_REC: { static bt_service_record_t e; const struct hal_prop_device_service_rec *p; send_props[i].val = &e; send_props[i].len = sizeof(e); p = (struct hal_prop_device_service_rec *) prop->val; memset(&e, 0, sizeof(e)); memcpy(&e.channel, &p->channel, sizeof(e.channel)); memcpy(e.uuid.uu, p->uuid, sizeof(e.uuid.uu)); memcpy(e.name, p->name, p->name_len); } break; default: send_props[i].len = prop->len; send_props[i].val = prop->val; break; } len -= sizeof(*prop) + prop->len; buf += sizeof(*prop) + prop->len; prop = buf; DBG("prop[%d]: %s", i, btproperty2str(&send_props[i])); } if (!len) return; error("invalid device properties (%u bytes left), aborting", len); exit(EXIT_FAILURE); } static void handle_adapter_props_changed(void *buf, uint16_t len) { struct hal_ev_adapter_props_changed *ev = buf; bt_property_t props[ev->num_props]; DBG(""); if (!bt_hal_cbacks->adapter_properties_cb) return; len -= sizeof(*ev); adapter_props_to_hal(props, ev->props, ev->num_props, len); bt_hal_cbacks->adapter_properties_cb(ev->status, ev->num_props, props); } static void handle_bond_state_change(void *buf, uint16_t len) { struct hal_ev_bond_state_changed *ev = buf; bt_bdaddr_t *addr = (bt_bdaddr_t *) ev->bdaddr; DBG("state %u", ev->state); if (bt_hal_cbacks->bond_state_changed_cb) bt_hal_cbacks->bond_state_changed_cb(ev->status, addr, ev->state); } static void handle_pin_request(void *buf, uint16_t len) { struct hal_ev_pin_request *ev = buf; /* Those are declared as packed, so it's safe to assign pointers */ bt_bdaddr_t *addr = (bt_bdaddr_t *) ev->bdaddr; bt_bdname_t *name = (bt_bdname_t *) ev->name; DBG(""); if (bt_hal_cbacks->pin_request_cb) bt_hal_cbacks->pin_request_cb(addr, name, ev->class_of_dev); } static void handle_ssp_request(void *buf, uint16_t len) { struct hal_ev_ssp_request *ev = buf; /* Those are declared as packed, so it's safe to assign pointers */ bt_bdaddr_t *addr = (bt_bdaddr_t *) ev->bdaddr; bt_bdname_t *name = (bt_bdname_t *) ev->name; DBG(""); if (bt_hal_cbacks->ssp_request_cb) bt_hal_cbacks->ssp_request_cb(addr, name, ev->class_of_dev, ev->pairing_variant, ev->passkey); } void bt_thread_associate(void) { if (bt_hal_cbacks->thread_evt_cb) bt_hal_cbacks->thread_evt_cb(ASSOCIATE_JVM); } void bt_thread_disassociate(void) { if (bt_hal_cbacks->thread_evt_cb) bt_hal_cbacks->thread_evt_cb(DISASSOCIATE_JVM); } static bool interface_ready(void) { return bt_hal_cbacks != NULL; } static void handle_discovery_state_changed(void *buf, uint16_t len) { struct hal_ev_discovery_state_changed *ev = buf; DBG(""); if (bt_hal_cbacks->discovery_state_changed_cb) bt_hal_cbacks->discovery_state_changed_cb(ev->state); } static void handle_device_found(void *buf, uint16_t len) { struct hal_ev_device_found *ev = buf; bt_property_t props[ev->num_props]; DBG(""); if (!bt_hal_cbacks->device_found_cb) return; len -= sizeof(*ev); device_props_to_hal(props, ev->props, ev->num_props, len); bt_hal_cbacks->device_found_cb(ev->num_props, props); } static void handle_device_state_changed(void *buf, uint16_t len) { struct hal_ev_remote_device_props *ev = buf; bt_property_t props[ev->num_props]; DBG(""); if (!bt_hal_cbacks->remote_device_properties_cb) return; len -= sizeof(*ev); device_props_to_hal(props, ev->props, ev->num_props, len); bt_hal_cbacks->remote_device_properties_cb(ev->status, (bt_bdaddr_t *)ev->bdaddr, ev->num_props, props); } static void handle_acl_state_changed(void *buf, uint16_t len) { struct hal_ev_acl_state_changed *ev = buf; bt_bdaddr_t *addr = (bt_bdaddr_t *) ev->bdaddr; DBG("state %u", ev->state); if (bt_hal_cbacks->acl_state_changed_cb) bt_hal_cbacks->acl_state_changed_cb(ev->status, addr, ev->state); } static void handle_dut_mode_receive(void *buf, uint16_t len) { struct hal_ev_dut_mode_receive *ev = buf; DBG(""); if (len != sizeof(*ev) + ev->len) { error("invalid dut mode receive event (%u), aborting", len); exit(EXIT_FAILURE); } if (bt_hal_cbacks->dut_mode_recv_cb) bt_hal_cbacks->dut_mode_recv_cb(ev->opcode, ev->data, ev->len); } static void handle_le_test_mode(void *buf, uint16_t len) { struct hal_ev_le_test_mode *ev = buf; DBG(""); if (bt_hal_cbacks->le_test_mode_cb) bt_hal_cbacks->le_test_mode_cb(ev->status, ev->num_packets); } /* * handlers will be called from notification thread context, * index in table equals to 'opcode - HAL_MINIMUM_EVENT' */ static const struct hal_ipc_handler ev_handlers[] = { { /* HAL_EV_ADAPTER_STATE_CHANGED */ .handler = handle_adapter_state_changed, .var_len = false, .data_len = sizeof(struct hal_ev_adapter_state_changed) }, { /* HAL_EV_ADAPTER_PROPS_CHANGED */ .handler = handle_adapter_props_changed, .var_len = true, .data_len = sizeof(struct hal_ev_adapter_props_changed) + sizeof(struct hal_property), }, { /* HAL_EV_REMOTE_DEVICE_PROPS */ .handler = handle_device_state_changed, .var_len = true, .data_len = sizeof(struct hal_ev_remote_device_props) + sizeof(struct hal_property), }, { /* HAL_EV_DEVICE_FOUND */ .handler = handle_device_found, .var_len = true, .data_len = sizeof(struct hal_ev_device_found) + sizeof(struct hal_property), }, { /* HAL_EV_DISCOVERY_STATE_CHANGED */ .handler = handle_discovery_state_changed, .var_len = false, .data_len = sizeof(struct hal_ev_discovery_state_changed), }, { /* HAL_EV_PIN_REQUEST */ .handler = handle_pin_request, .var_len = false, .data_len = sizeof(struct hal_ev_pin_request), }, { /* HAL_EV_SSP_REQUEST */ .handler = handle_ssp_request, .var_len = false, .data_len = sizeof(struct hal_ev_ssp_request), }, { /* HAL_EV_BOND_STATE_CHANGED */ .handler = handle_bond_state_change, .var_len = false, .data_len = sizeof(struct hal_ev_bond_state_changed), }, { /* HAL_EV_ACL_STATE_CHANGED */ .handler = handle_acl_state_changed, .var_len = false, .data_len = sizeof(struct hal_ev_acl_state_changed), }, { /* HAL_EV_DUT_MODE_RECEIVE */ .handler = handle_dut_mode_receive, .var_len = true, .data_len = sizeof(struct hal_ev_dut_mode_receive), }, { /* HAL_EV_LE_TEST_MODE */ .handler = handle_le_test_mode, .var_len = false, .data_len = sizeof(struct hal_ev_le_test_mode), } }; static uint8_t get_mode(void) { char value[PROPERTY_VALUE_MAX]; if (property_get(MODE_PROPERTY_NAME, value, "") > 0 && (!strcasecmp(value, "bredr"))) return HAL_MODE_BREDR; if (property_get(MODE_PROPERTY_NAME, value, "") > 0 && (!strcasecmp(value, "le"))) return HAL_MODE_LE; return HAL_MODE_DEFAULT; } static int init(bt_callbacks_t *callbacks) { struct hal_cmd_register_module cmd; int status; DBG(""); if (interface_ready()) return BT_STATUS_DONE; bt_hal_cbacks = callbacks; hal_ipc_register(HAL_SERVICE_ID_BLUETOOTH, ev_handlers, sizeof(ev_handlers)/sizeof(ev_handlers[0])); if (!hal_ipc_init()) { bt_hal_cbacks = NULL; return BT_STATUS_FAIL; } cmd.service_id = HAL_SERVICE_ID_BLUETOOTH; cmd.mode = get_mode(); status = hal_ipc_cmd(HAL_SERVICE_ID_CORE, HAL_OP_REGISTER_MODULE, sizeof(cmd), &cmd, NULL, NULL, NULL); if (status != BT_STATUS_SUCCESS) { error("Failed to register 'bluetooth' service"); goto fail; } cmd.service_id = HAL_SERVICE_ID_SOCKET; cmd.mode = HAL_MODE_DEFAULT; status = hal_ipc_cmd(HAL_SERVICE_ID_CORE, HAL_OP_REGISTER_MODULE, sizeof(cmd), &cmd, NULL, NULL, NULL); if (status != BT_STATUS_SUCCESS) { error("Failed to register 'socket' service"); goto fail; } return status; fail: hal_ipc_cleanup(); bt_hal_cbacks = NULL; hal_ipc_unregister(HAL_SERVICE_ID_BLUETOOTH); return status; } static int enable(void) { DBG(""); if (!interface_ready()) return BT_STATUS_NOT_READY; return hal_ipc_cmd(HAL_SERVICE_ID_BLUETOOTH, HAL_OP_ENABLE, 0, NULL, 0, NULL, NULL); } static int disable(void) { DBG(""); if (!interface_ready()) return BT_STATUS_NOT_READY; return hal_ipc_cmd(HAL_SERVICE_ID_BLUETOOTH, HAL_OP_DISABLE, 0, NULL, 0, NULL, NULL); } static void cleanup(void) { DBG(""); if (!interface_ready()) return; hal_ipc_cleanup(); bt_hal_cbacks = NULL; hal_ipc_unregister(HAL_SERVICE_ID_BLUETOOTH); } static int get_adapter_properties(void) { DBG(""); if (!interface_ready()) return BT_STATUS_NOT_READY; return hal_ipc_cmd(HAL_SERVICE_ID_BLUETOOTH, HAL_OP_GET_ADAPTER_PROPS, 0, NULL, 0, NULL, NULL); } static int get_adapter_property(bt_property_type_t type) { struct hal_cmd_get_adapter_prop cmd; DBG("prop: %s (%d)", bt_property_type_t2str(type), type); if (!interface_ready()) return BT_STATUS_NOT_READY; /* type match IPC type */ cmd.type = type; return hal_ipc_cmd(HAL_SERVICE_ID_BLUETOOTH, HAL_OP_GET_ADAPTER_PROP, sizeof(cmd), &cmd, 0, NULL, NULL); } static int set_adapter_property(const bt_property_t *property) { char buf[IPC_MTU]; struct hal_cmd_set_adapter_prop *cmd = (void *) buf; size_t len; DBG("prop: %s", btproperty2str(property)); if (!interface_ready()) return BT_STATUS_NOT_READY; adapter_prop_from_hal(property, &cmd->type, &cmd->len, cmd->val); len = sizeof(*cmd) + cmd->len; return hal_ipc_cmd(HAL_SERVICE_ID_BLUETOOTH, HAL_OP_SET_ADAPTER_PROP, len, cmd, 0, NULL, NULL); } static int get_remote_device_properties(bt_bdaddr_t *remote_addr) { struct hal_cmd_get_remote_device_props cmd; DBG("bdaddr: %s", bdaddr2str(remote_addr)); if (!interface_ready()) return BT_STATUS_NOT_READY; memcpy(cmd.bdaddr, remote_addr, sizeof(cmd.bdaddr)); return hal_ipc_cmd(HAL_SERVICE_ID_BLUETOOTH, HAL_OP_GET_REMOTE_DEVICE_PROPS, sizeof(cmd), &cmd, 0, NULL, NULL); } static int get_remote_device_property(bt_bdaddr_t *remote_addr, bt_property_type_t type) { struct hal_cmd_get_remote_device_prop cmd; DBG("bdaddr: %s prop: %s", bdaddr2str(remote_addr), bt_property_type_t2str(type)); if (!interface_ready()) return BT_STATUS_NOT_READY; memcpy(cmd.bdaddr, remote_addr, sizeof(cmd.bdaddr)); /* type match IPC type */ cmd.type = type; return hal_ipc_cmd(HAL_SERVICE_ID_BLUETOOTH, HAL_OP_GET_REMOTE_DEVICE_PROP, sizeof(cmd), &cmd, 0, NULL, NULL); } static int set_remote_device_property(bt_bdaddr_t *remote_addr, const bt_property_t *property) { char buf[IPC_MTU]; struct hal_cmd_set_remote_device_prop *cmd = (void *) buf; size_t len; DBG("bdaddr: %s prop: %s", bdaddr2str(remote_addr), bt_property_type_t2str(property->type)); if (!interface_ready()) return BT_STATUS_NOT_READY; memcpy(cmd->bdaddr, remote_addr, sizeof(cmd->bdaddr)); /* type match IPC type */ cmd->type = property->type; cmd->len = property->len; memcpy(cmd->val, property->val, property->len); len = sizeof(*cmd) + cmd->len; return hal_ipc_cmd(HAL_SERVICE_ID_BLUETOOTH, HAL_OP_SET_REMOTE_DEVICE_PROP, len, cmd, 0, NULL, NULL); } static int get_remote_service_record(bt_bdaddr_t *remote_addr, bt_uuid_t *uuid) { struct hal_cmd_get_remote_service_rec cmd; DBG("bdaddr: %s", bdaddr2str(remote_addr)); if (!interface_ready()) return BT_STATUS_NOT_READY; memcpy(cmd.bdaddr, remote_addr, sizeof(cmd.bdaddr)); memcpy(cmd.uuid, uuid, sizeof(cmd.uuid)); return hal_ipc_cmd(HAL_SERVICE_ID_BLUETOOTH, HAL_OP_GET_REMOTE_SERVICE_REC, sizeof(cmd), &cmd, 0, NULL, NULL); } static int get_remote_services(bt_bdaddr_t *remote_addr) { struct hal_cmd_get_remote_services cmd; DBG("bdaddr: %s", bdaddr2str(remote_addr)); if (!interface_ready()) return BT_STATUS_NOT_READY; memcpy(cmd.bdaddr, remote_addr, sizeof(cmd.bdaddr)); return hal_ipc_cmd(HAL_SERVICE_ID_BLUETOOTH, HAL_OP_GET_REMOTE_SERVICES, sizeof(cmd), &cmd, 0, NULL, NULL); } static int start_discovery(void) { DBG(""); if (!interface_ready()) return BT_STATUS_NOT_READY; return hal_ipc_cmd(HAL_SERVICE_ID_BLUETOOTH, HAL_OP_START_DISCOVERY, 0, NULL, 0, NULL, NULL); } static int cancel_discovery(void) { DBG(""); if (!interface_ready()) return BT_STATUS_NOT_READY; return hal_ipc_cmd(HAL_SERVICE_ID_BLUETOOTH, HAL_OP_CANCEL_DISCOVERY, 0, NULL, 0, NULL, NULL); } static int create_bond(const bt_bdaddr_t *bd_addr) { struct hal_cmd_create_bond cmd; DBG("bdaddr: %s", bdaddr2str(bd_addr)); if (!interface_ready()) return BT_STATUS_NOT_READY; memcpy(cmd.bdaddr, bd_addr, sizeof(cmd.bdaddr)); return hal_ipc_cmd(HAL_SERVICE_ID_BLUETOOTH, HAL_OP_CREATE_BOND, sizeof(cmd), &cmd, 0, NULL, NULL); } static int cancel_bond(const bt_bdaddr_t *bd_addr) { struct hal_cmd_cancel_bond cmd; DBG("bdaddr: %s", bdaddr2str(bd_addr)); if (!interface_ready()) return BT_STATUS_NOT_READY; memcpy(cmd.bdaddr, bd_addr, sizeof(cmd.bdaddr)); return hal_ipc_cmd(HAL_SERVICE_ID_BLUETOOTH, HAL_OP_CANCEL_BOND, sizeof(cmd), &cmd, 0, NULL, NULL); } static int remove_bond(const bt_bdaddr_t *bd_addr) { struct hal_cmd_remove_bond cmd; DBG("bdaddr: %s", bdaddr2str(bd_addr)); if (!interface_ready()) return BT_STATUS_NOT_READY; memcpy(cmd.bdaddr, bd_addr, sizeof(cmd.bdaddr)); return hal_ipc_cmd(HAL_SERVICE_ID_BLUETOOTH, HAL_OP_REMOVE_BOND, sizeof(cmd), &cmd, 0, NULL, NULL); } static int pin_reply(const bt_bdaddr_t *bd_addr, uint8_t accept, uint8_t pin_len, bt_pin_code_t *pin_code) { struct hal_cmd_pin_reply cmd; DBG("bdaddr: %s", bdaddr2str(bd_addr)); if (!interface_ready()) return BT_STATUS_NOT_READY; memcpy(cmd.bdaddr, bd_addr, sizeof(cmd.bdaddr)); cmd.accept = accept; cmd.pin_len = pin_len; memcpy(cmd.pin_code, pin_code, sizeof(cmd.pin_code)); return hal_ipc_cmd(HAL_SERVICE_ID_BLUETOOTH, HAL_OP_PIN_REPLY, sizeof(cmd), &cmd, 0, NULL, NULL); } static int ssp_reply(const bt_bdaddr_t *bd_addr, bt_ssp_variant_t variant, uint8_t accept, uint32_t passkey) { struct hal_cmd_ssp_reply cmd; DBG("bdaddr: %s", bdaddr2str(bd_addr)); if (!interface_ready()) return BT_STATUS_NOT_READY; memcpy(cmd.bdaddr, bd_addr, sizeof(cmd.bdaddr)); /* type match IPC type */ cmd.ssp_variant = variant; cmd.accept = accept; cmd.passkey = passkey; return hal_ipc_cmd(HAL_SERVICE_ID_BLUETOOTH, HAL_OP_SSP_REPLY, sizeof(cmd), &cmd, 0, NULL, NULL); } static const void *get_profile_interface(const char *profile_id) { DBG("%s", profile_id); if (!interface_ready()) return NULL; if (!strcmp(profile_id, BT_PROFILE_SOCKETS_ID)) return bt_get_socket_interface(); if (!strcmp(profile_id, BT_PROFILE_HIDHOST_ID)) return bt_get_hidhost_interface(); if (!strcmp(profile_id, BT_PROFILE_PAN_ID)) return bt_get_pan_interface(); if (!strcmp(profile_id, BT_PROFILE_ADVANCED_AUDIO_ID)) return bt_get_a2dp_interface(); if (!strcmp(profile_id, BT_PROFILE_AV_RC_ID)) return bt_get_avrcp_interface(); if (!strcmp(profile_id, BT_PROFILE_HANDSFREE_ID)) return bt_get_handsfree_interface(); if (!strcmp(profile_id, BT_PROFILE_GATT_ID)) return bt_get_gatt_interface(); if (!strcmp(profile_id, BT_PROFILE_HEALTH_ID)) return bt_get_health_interface(); return NULL; } static int dut_mode_configure(uint8_t enable) { struct hal_cmd_dut_mode_conf cmd; DBG("enable %u", enable); if (!interface_ready()) return BT_STATUS_NOT_READY; cmd.enable = enable; return hal_ipc_cmd(HAL_SERVICE_ID_BLUETOOTH, HAL_OP_DUT_MODE_CONF, sizeof(cmd), &cmd, 0, NULL, NULL); } static int dut_mode_send(uint16_t opcode, uint8_t *buf, uint8_t buf_len) { char cmd_buf[IPC_MTU]; struct hal_cmd_dut_mode_send *cmd = (void *) cmd_buf; size_t len; DBG("opcode %u len %u", opcode, buf_len); if (!interface_ready()) return BT_STATUS_NOT_READY; cmd->opcode = opcode; cmd->len = buf_len; memcpy(cmd->data, buf, cmd->len); len = sizeof(*cmd) + cmd->len; return hal_ipc_cmd(HAL_SERVICE_ID_BLUETOOTH, HAL_OP_DUT_MODE_SEND, len, cmd, 0, NULL, NULL); } static int le_test_mode(uint16_t opcode, uint8_t *buf, uint8_t buf_len) { char cmd_buf[IPC_MTU]; struct hal_cmd_le_test_mode *cmd = (void *) cmd_buf; size_t len; DBG("opcode %u len %u", opcode, buf_len); if (!interface_ready()) return BT_STATUS_NOT_READY; cmd->opcode = opcode; cmd->len = buf_len; memcpy(cmd->data, buf, cmd->len); len = sizeof(*cmd) + cmd->len; return hal_ipc_cmd(HAL_SERVICE_ID_BLUETOOTH, HAL_OP_LE_TEST_MODE, len, cmd, 0, NULL, NULL); } static int config_hci_snoop_log(uint8_t enable) { const char *property; DBG("enable %u", enable); property = enable ? "bluetooth.start" : "bluetooth.stop"; if (property_set(property, "snoop") < 0) { error("Failed to set %s=snoop", property); return BT_STATUS_FAIL; } return BT_STATUS_SUCCESS; } static const bt_interface_t bluetooth_if = { .size = sizeof(bt_interface_t), .init = init, .enable = enable, .disable = disable, .cleanup = cleanup, .get_adapter_properties = get_adapter_properties, .get_adapter_property = get_adapter_property, .set_adapter_property = set_adapter_property, .get_remote_device_properties = get_remote_device_properties, .get_remote_device_property = get_remote_device_property, .set_remote_device_property = set_remote_device_property, .get_remote_service_record = get_remote_service_record, .get_remote_services = get_remote_services, .start_discovery = start_discovery, .cancel_discovery = cancel_discovery, .create_bond = create_bond, .remove_bond = remove_bond, .cancel_bond = cancel_bond, .pin_reply = pin_reply, .ssp_reply = ssp_reply, .get_profile_interface = get_profile_interface, .dut_mode_configure = dut_mode_configure, .dut_mode_send = dut_mode_send, .le_test_mode = le_test_mode, .config_hci_snoop_log = config_hci_snoop_log, }; static const bt_interface_t *get_bluetooth_interface(void) { DBG(""); return &bluetooth_if; } static int close_bluetooth(struct hw_device_t *device) { DBG(""); cleanup(); free(device); return 0; } static int open_bluetooth(const struct hw_module_t *module, char const *name, struct hw_device_t **device) { bluetooth_device_t *dev = malloc(sizeof(bluetooth_device_t)); DBG(""); memset(dev, 0, sizeof(bluetooth_device_t)); dev->common.tag = HARDWARE_DEVICE_TAG; dev->common.version = 0; dev->common.module = (struct hw_module_t *) module; dev->common.close = close_bluetooth; dev->get_bluetooth_interface = get_bluetooth_interface; *device = (struct hw_device_t *) dev; return 0; } static struct hw_module_methods_t bluetooth_module_methods = { .open = open_bluetooth, }; struct hw_module_t HAL_MODULE_INFO_SYM = { .tag = HARDWARE_MODULE_TAG, .version_major = 1, .version_minor = 0, .id = BT_HARDWARE_MODULE_ID, .name = "BlueZ Bluetooth stack", .author = "Intel Corporation", .methods = &bluetooth_module_methods };