1 /* 2 * Copyright (C) 2009 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 /** Bluetooth configuration for Passion (debug only) */ 18 19 #include <stdlib.h> 20 #include <stdio.h> 21 #include <errno.h> 22 #include <sys/uio.h> 23 #include <unistd.h> 24 25 #include <bluetooth/bluetooth.h> 26 #include <bluetooth/hci.h> 27 #include <bluetooth/hci_lib.h> 28 #include <bluetooth/sco.h> 29 30 #include <bluedroid/bluetooth.h> 31 32 static void usage(void); 33 34 int vendor_sleep(int fd) { 35 unsigned char hci_sleep_cmd[] = { 36 0x01, // HCI command packet 37 0x27, 0xfc, // HCI_Set_Sleep_Mode_Param 38 0x0c, // 12 arguments 39 0x01, // ?? 40 0x01, // idle threshold Host (x300ms) 41 0x01, // idle threadhold HC (x300ms) 42 0x01, // WAKE active high 43 0x01, // HOST_WAKE active high 44 0x01, // Allow host sleep during SCO 45 0x01, // Combine sleep mode and LPM 46 0x00, // Enable tristate control of uart TX 47 0x00, 0x00, 0x00, 0x00, 48 }; 49 50 int ret = write(fd, hci_sleep_cmd, sizeof(hci_sleep_cmd)); 51 if (ret < 0) { 52 printf("write(): %s (%d)]\n", strerror(errno), errno); 53 return -1; 54 } else if (ret != sizeof(hci_sleep_cmd)) { 55 printf("write(): unexpected length %d\n", ret); 56 return -1; 57 } 58 return 0; 59 } 60 61 int vendor_high_priority(int fd, unsigned char acl) { 62 unsigned char hci_sleep_cmd[] = { 63 0x01, // HCI command packet 64 0x57, 0xfc, // HCI_Write_High_Priority_Connection 65 0x02, // Length 66 0x00, 0x00 // Handle 67 }; 68 69 hci_sleep_cmd[4] = acl; 70 71 int ret = write(fd, hci_sleep_cmd, sizeof(hci_sleep_cmd)); 72 if (ret < 0) { 73 printf("write(): %s (%d)]\n", strerror(errno), errno); 74 return -1; 75 } else if (ret != sizeof(hci_sleep_cmd)) { 76 printf("write(): unexpected length %d\n", ret); 77 return -1; 78 } 79 return 0; 80 } 81 82 int get_hci_sock() { 83 int sock = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI); 84 struct sockaddr_hci addr; 85 int opt; 86 87 if(sock < 0) { 88 printf("Can't create raw socket!\n"); 89 return -1; 90 } 91 92 opt = 1; 93 printf("Setting data direction.\n"); 94 if (setsockopt(sock, SOL_HCI, HCI_DATA_DIR, &opt, sizeof(opt)) < 0) { 95 printf("Error setting data direction\n"); 96 return -1; 97 } 98 99 /* Bind socket to the HCI device */ 100 addr.hci_family = AF_BLUETOOTH; 101 addr.hci_dev = 0; // hci0 102 printf("Binding to HCI device.\n"); 103 if(bind(sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) { 104 printf("Can't attach to device hci0. %s(%d)\n", 105 strerror(errno), 106 errno); 107 return -1; 108 } 109 return sock; 110 } 111 112 static int get_acl_handle(int fd, bdaddr_t bdaddr) { 113 int i; 114 int ret = -1; 115 struct hci_conn_list_req *conn_list; 116 struct hci_conn_info *conn_info; 117 int max_conn = 10; 118 119 conn_list = malloc(max_conn * ( 120 sizeof(struct hci_conn_list_req) + sizeof(struct hci_conn_info))); 121 if (!conn_list) { 122 printf("Out of memory in %s\n", __FUNCTION__); 123 return -1; 124 } 125 126 conn_list->dev_id = 0; /* hardcoded to HCI device 0 */ 127 conn_list->conn_num = max_conn; 128 129 if (ioctl(fd, HCIGETCONNLIST, (void *)conn_list)) { 130 printf("Failed to get connection list\n"); 131 goto out; 132 } 133 134 for (i=0; i < conn_list->conn_num; i++) { 135 conn_info = &conn_list->conn_info[i]; 136 if (conn_info->type == ACL_LINK && 137 !memcmp((void *)&conn_info->bdaddr, (void *)&bdaddr, 138 sizeof(bdaddr_t))) { 139 ret = conn_info->handle; 140 goto out; 141 } 142 } 143 ret = 0; 144 145 out: 146 free(conn_list); 147 return ret; 148 } 149 150 static int do_sleep(int argc, char **argv) { 151 int ret; 152 int sock = get_hci_sock(); 153 154 if (sock < 0) 155 return sock; 156 157 ret = vendor_sleep(sock); 158 close(sock); 159 160 return ret; 161 } 162 163 static int do_high_priority(int argc, char **argv) { 164 int ret; 165 int sock = get_hci_sock(); 166 unsigned char acl; 167 168 if (sock < 0) 169 return sock; 170 171 if (argc != 1) { 172 usage(); 173 return -1; 174 } 175 176 acl = (unsigned char)atoi(argv[0]); 177 178 ret = vendor_high_priority(sock, acl); 179 close(sock); 180 181 return ret; 182 } 183 184 static int do_high_priority_address(int argc, char **argv) { 185 int ret; 186 int sock = get_hci_sock(); 187 unsigned char acl; 188 bdaddr_t bdaddr; 189 190 if (sock < 0) 191 return sock; 192 193 if (argc != 1) { 194 usage(); 195 return -1; 196 } 197 198 str2ba(argv[0], &bdaddr); 199 200 ret = get_acl_handle(sock, bdaddr); 201 if (ret < 0) goto out; 202 203 ret = vendor_high_priority(sock, ret); 204 205 out: 206 close(sock); 207 208 return ret; 209 } 210 211 struct { 212 char *name; 213 int (*ptr)(int argc, char **argv); 214 } function_table[] = { 215 {"sleep", do_sleep}, 216 {"pri", do_high_priority}, 217 {"pri_addr", do_high_priority_address}, 218 {"", do_sleep}, 219 {NULL, NULL}, 220 }; 221 222 static void usage() { 223 int i; 224 225 printf("Usage:\n"); 226 for (i = 0; function_table[i].name; i++) { 227 printf("\tbtconfig %s\n", function_table[i].name); 228 } 229 } 230 231 int main(int argc, char **argv) { 232 int i; 233 234 if (argc < 2) { 235 usage(); 236 return -1; 237 } 238 for (i = 0; function_table[i].name; i++) { 239 if (!strcmp(argv[1], function_table[i].name)) { 240 printf("%s\n", function_table[i].name); 241 return (*function_table[i].ptr)(argc - 2, &argv[2]); 242 } 243 } 244 usage(); 245 return -1; 246 } 247