/*
* Copyright (C) 2009 The Android Open Source Project
*
* 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.
*/
/** Bluetooth configuration for Passion (debug only) */
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <sys/uio.h>
#include <unistd.h>
#include <bluetooth/bluetooth.h>
#include <bluetooth/hci.h>
#include <bluetooth/hci_lib.h>
#include <bluetooth/sco.h>
#include <bluedroid/bluetooth.h>
static void usage(void);
int vendor_sleep(int fd) {
unsigned char hci_sleep_cmd[] = {
0x01, // HCI command packet
0x27, 0xfc, // HCI_Set_Sleep_Mode_Param
0x0c, // 12 arguments
0x01, // ??
0x01, // idle threshold Host (x300ms)
0x01, // idle threadhold HC (x300ms)
0x01, // WAKE active high
0x01, // HOST_WAKE active high
0x01, // Allow host sleep during SCO
0x01, // Combine sleep mode and LPM
0x00, // Enable tristate control of uart TX
0x00, 0x00, 0x00, 0x00,
};
int ret = write(fd, hci_sleep_cmd, sizeof(hci_sleep_cmd));
if (ret < 0) {
printf("write(): %s (%d)]\n", strerror(errno), errno);
return -1;
} else if (ret != sizeof(hci_sleep_cmd)) {
printf("write(): unexpected length %d\n", ret);
return -1;
}
return 0;
}
int vendor_high_priority(int fd, unsigned char acl) {
unsigned char hci_sleep_cmd[] = {
0x01, // HCI command packet
0x57, 0xfc, // HCI_Write_High_Priority_Connection
0x02, // Length
0x00, 0x00 // Handle
};
hci_sleep_cmd[4] = acl;
int ret = write(fd, hci_sleep_cmd, sizeof(hci_sleep_cmd));
if (ret < 0) {
printf("write(): %s (%d)]\n", strerror(errno), errno);
return -1;
} else if (ret != sizeof(hci_sleep_cmd)) {
printf("write(): unexpected length %d\n", ret);
return -1;
}
return 0;
}
int get_hci_sock() {
int sock = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
struct sockaddr_hci addr;
int opt;
if(sock < 0) {
printf("Can't create raw socket!\n");
return -1;
}
opt = 1;
printf("Setting data direction.\n");
if (setsockopt(sock, SOL_HCI, HCI_DATA_DIR, &opt, sizeof(opt)) < 0) {
printf("Error setting data direction\n");
return -1;
}
/* Bind socket to the HCI device */
addr.hci_family = AF_BLUETOOTH;
addr.hci_dev = 0; // hci0
printf("Binding to HCI device.\n");
if(bind(sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
printf("Can't attach to device hci0. %s(%d)\n",
strerror(errno),
errno);
return -1;
}
return sock;
}
static int get_acl_handle(int fd, bdaddr_t bdaddr) {
int i;
int ret = -1;
struct hci_conn_list_req *conn_list;
struct hci_conn_info *conn_info;
int max_conn = 10;
conn_list = malloc(max_conn * (
sizeof(struct hci_conn_list_req) + sizeof(struct hci_conn_info)));
if (!conn_list) {
printf("Out of memory in %s\n", __FUNCTION__);
return -1;
}
conn_list->dev_id = 0; /* hardcoded to HCI device 0 */
conn_list->conn_num = max_conn;
if (ioctl(fd, HCIGETCONNLIST, (void *)conn_list)) {
printf("Failed to get connection list\n");
goto out;
}
for (i=0; i < conn_list->conn_num; i++) {
conn_info = &conn_list->conn_info[i];
if (conn_info->type == ACL_LINK &&
!memcmp((void *)&conn_info->bdaddr, (void *)&bdaddr,
sizeof(bdaddr_t))) {
ret = conn_info->handle;
goto out;
}
}
ret = 0;
out:
free(conn_list);
return ret;
}
static int do_sleep(int argc, char **argv) {
int ret;
int sock = get_hci_sock();
if (sock < 0)
return sock;
ret = vendor_sleep(sock);
close(sock);
return ret;
}
static int do_high_priority(int argc, char **argv) {
int ret;
int sock = get_hci_sock();
unsigned char acl;
if (sock < 0)
return sock;
if (argc != 1) {
usage();
return -1;
}
acl = (unsigned char)atoi(argv[0]);
ret = vendor_high_priority(sock, acl);
close(sock);
return ret;
}
static int do_high_priority_address(int argc, char **argv) {
int ret;
int sock = get_hci_sock();
unsigned char acl;
bdaddr_t bdaddr;
if (sock < 0)
return sock;
if (argc != 1) {
usage();
return -1;
}
str2ba(argv[0], &bdaddr);
ret = get_acl_handle(sock, bdaddr);
if (ret < 0) goto out;
ret = vendor_high_priority(sock, ret);
out:
close(sock);
return ret;
}
struct {
char *name;
int (*ptr)(int argc, char **argv);
} function_table[] = {
{"sleep", do_sleep},
{"pri", do_high_priority},
{"pri_addr", do_high_priority_address},
{"", do_sleep},
{NULL, NULL},
};
static void usage() {
int i;
printf("Usage:\n");
for (i = 0; function_table[i].name; i++) {
printf("\tbtconfig %s\n", function_table[i].name);
}
}
int main(int argc, char **argv) {
int i;
if (argc < 2) {
usage();
return -1;
}
for (i = 0; function_table[i].name; i++) {
if (!strcmp(argv[1], function_table[i].name)) {
printf("%s\n", function_table[i].name);
return (*function_table[i].ptr)(argc - 2, &argv[2]);
}
}
usage();
return -1;
}