| /* |
| * 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; |
| } |