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
vendor_sleep(int fd)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
vendor_high_priority(int fd,unsigned char acl)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
get_hci_sock()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
get_acl_handle(int fd,bdaddr_t bdaddr)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
do_sleep(int argc,char ** argv)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
do_high_priority(int argc,char ** argv)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
do_high_priority_address(int argc,char ** argv)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
usage()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
main(int argc,char ** argv)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