Home | History | Annotate | Download | only in tools
      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