• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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