OSDN Git Service

Initial Contribution
authorThe Android Open Source Project <initial-contribution@android.com>
Tue, 21 Oct 2008 14:00:00 +0000 (07:00 -0700)
committerThe Android Open Source Project <initial-contribution@android.com>
Tue, 21 Oct 2008 14:00:00 +0000 (07:00 -0700)
bluedroid/Android.mk [new file with mode: 0644]
bluedroid/bluetooth.c [new file with mode: 0644]
bluedroid/bttest.c [new file with mode: 0644]
bluedroid/include/bluedroid/bluetooth.h [new file with mode: 0644]
brfpatch/Android.mk [new file with mode: 0644]
brfpatch/brfpatch.c [new file with mode: 0644]

diff --git a/bluedroid/Android.mk b/bluedroid/Android.mk
new file mode 100644 (file)
index 0000000..2563c54
--- /dev/null
@@ -0,0 +1,43 @@
+ifeq ($(BOARD_HAVE_BLUETOOTH),true)
+
+#
+# libbluedroid
+#
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+       bluetooth.c
+
+LOCAL_C_INCLUDES := \
+       $(call include-path-for, bluez-libs)
+
+LOCAL_SHARED_LIBRARIES := \
+       libcutils
+
+LOCAL_MODULE := libbluedroid
+
+include $(BUILD_SHARED_LIBRARY)
+
+
+#
+# bttest
+#
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := bttest.c
+
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
+
+LOCAL_SHARED_LIBRARIES := libbluedroid
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
+LOCAL_MODULE_TAGS := eng
+LOCAL_MODULE := bttest
+
+include $(BUILD_EXECUTABLE)
+
+endif
diff --git a/bluedroid/bluetooth.c b/bluedroid/bluetooth.c
new file mode 100644 (file)
index 0000000..dfcaa2a
--- /dev/null
@@ -0,0 +1,320 @@
+/*
+ * Copyright (C) 2008 Google Inc.
+ *
+ * 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.
+ */
+
+#define LOG_TAG "bluedroid"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <cutils/log.h>
+#include <cutils/properties.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/hci.h>
+#include <bluetooth/hci_lib.h>
+
+#include <bluedroid/bluetooth.h>
+
+#ifndef HCI_DEV_ID
+#define HCI_DEV_ID 0
+#endif
+
+#define HCID_START_DELAY_SEC   5
+#define HCID_STOP_DELAY_USEC 500000
+
+#define MIN(x,y) (((x)<(y))?(x):(y))
+
+#define USE_UGLY_POWER_INTERFACE 1
+#if USE_UGLY_POWER_INTERFACE
+
+#define BLUETOOTH_POWER_PATH "/sys/module/board_trout/parameters/bluetooth_power_on"
+
+static int set_bluetooth_power(int on) {
+    int ret = -1;
+    int sz;
+    const char buffer = (on ? 'Y' : 'N');
+    int fd = open(BLUETOOTH_POWER_PATH, O_WRONLY);
+
+    if (fd == -1) {
+        LOGE("Can't open %s for write: %s (%d)", BLUETOOTH_POWER_PATH,
+             strerror(errno), errno);
+        goto out;
+    }
+    sz = write(fd, &buffer, 1);
+    if (sz != 1) {
+        LOGE("Can't write to %s: %s (%d)", BLUETOOTH_POWER_PATH,
+             strerror(errno), errno);
+        goto out;
+    }
+    ret = 0;
+
+out:
+    if (fd >= 0) close(fd);
+    return ret;
+}
+
+static int check_bluetooth_power() {
+    int ret = -1;
+    int sz;
+    char buffer;
+    int fd = open(BLUETOOTH_POWER_PATH, O_RDONLY);
+
+    if (fd == -1) {
+        LOGE("Can't open %s for read: %s (%d)", BLUETOOTH_POWER_PATH,
+             strerror(errno), errno);
+        goto out;
+    }
+    sz = read(fd, &buffer, 1);
+    if (sz != 1) {
+        LOGE("Can't read from %s: %s (%d)", BLUETOOTH_POWER_PATH,
+             strerror(errno), errno);
+        goto out;
+    }
+
+    switch (buffer) {
+    case 'Y':
+        ret = 1;
+        break;
+    case 'N':
+        ret = 0;
+        break;
+    }
+
+out:
+    if (fd >= 0) close(fd);
+    return ret;
+}
+
+#else
+
+static int rfkill_id = -1;
+static char *rfkill_state_path = NULL;
+
+
+static int init_rfkill() {
+    char path[64];
+    char buf[16];
+    int fd;
+    int sz;
+    int id;
+    for (id = 0; ; id++) {
+        snprintf(path, sizeof(path), "/sys/class/rfkill/rfkill%d/type", id);
+        fd = open(path, O_RDONLY);
+        if (fd < 0) {
+            LOGW("open(%s) failed: %s (%d)\n", path, strerror(errno), errno);
+            return -1;
+        }
+        sz = read(fd, &buf, sizeof(buf));
+        close(fd);
+        if (sz >= 9 && memcmp(buf, "bluetooth", 9) == 0) {
+            rfkill_id = id;
+            break;
+        }
+    }
+
+    asprintf(&rfkill_state_path, "/sys/class/rfkill/rfkill%d/state", rfkill_id);
+    return 0;
+}
+
+static int check_bluetooth_power() {
+    int sz;
+    int fd = -1;
+    int ret = -1;
+    char buffer;
+
+    if (rfkill_id == -1) {
+        if (init_rfkill()) goto out;
+    }
+
+    fd = open(rfkill_state_path, O_RDONLY);
+    if (fd < 0) {
+        LOGE("open(%s) failed: %s (%d)", rfkill_state_path, strerror(errno),
+             errno);
+        goto out;
+    }
+    sz = read(fd, &buffer, 1);
+    if (sz != 1) {
+        LOGE("read(%s) failed: %s (%d)", rfkill_state_path, strerror(errno),
+             errno);
+        goto out;
+    }
+
+    switch (buffer) {
+    case '1':
+        ret = 1;
+        break;
+    case '0':
+        ret = 0;
+        break;
+    }
+
+out:
+    if (fd >= 0) close(fd);
+    return ret;
+}
+
+static int set_bluetooth_power(int on) {
+    int sz;
+    int fd = -1;
+    int ret = -1;
+    const char buffer = (on ? '1' : '0');
+
+    if (rfkill_id == -1) {
+        if (init_rfkill()) goto out;
+    }
+
+    fd = open(rfkill_state_path, O_WRONLY);
+    if (fd < 0) {
+        LOGE("open(%s) for write failed: %s (%d)", rfkill_state_path,
+             strerror(errno), errno);
+        goto out;
+    }
+    sz = write(fd, &buffer, 1);
+    if (sz < 0) {
+        LOGE("write(%s) failed: %s (%d)", rfkill_state_path, strerror(errno),
+             errno);
+        goto out;
+    }
+    ret = 0;
+
+out:
+    if (fd >= 0) close(fd);
+    return ret;
+}
+#endif
+
+static inline int create_hci_sock() {
+    int sk = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
+    if (sk < 0) {
+        LOGE("Failed to create bluetooth hci socket: %s (%d)",
+             strerror(errno), errno);
+    }
+    return sk;
+}
+
+int bt_enable() {
+    LOGV(__FUNCTION__);
+
+    int ret = -1;
+    int hci_sock = -1;
+    int attempt;
+
+    if (set_bluetooth_power(1) < 0) goto out;
+
+    LOGI("Starting hciattach daemon");
+    if (property_set("ctl.start", "hciattach") < 0) {
+        LOGE("Failed to start hciattach");
+        goto out;
+    }
+
+    // Try for 10 seconds, this can only succeed once hciattach has sent the
+    // firmware and then turned on hci device via HCIUARTSETPROTO ioctl
+    for (attempt = 1000; attempt > 0;  attempt--) {
+        hci_sock = create_hci_sock();
+        if (hci_sock < 0) goto out;
+
+        if (!ioctl(hci_sock, HCIDEVUP, HCI_DEV_ID)) {
+            break;
+        }
+        close(hci_sock);
+        usleep(10000);  // 10 ms retry delay
+    }
+    if (attempt == 0) {
+        LOGE("%s: Timeout waiting for HCI device to come up", __FUNCTION__);
+        goto out;
+    }
+
+    LOGI("Starting hcid deamon");
+    if (property_set("ctl.start", "hcid") < 0) {
+        LOGE("Failed to start hcid");
+        goto out;
+    }
+    sleep(HCID_START_DELAY_SEC);
+
+    ret = 0;
+
+out:
+    if (hci_sock >= 0) close(hci_sock);
+    return ret;
+}
+
+int bt_disable() {
+    LOGV(__FUNCTION__);
+
+    int ret = -1;
+    int hci_sock = -1;
+
+    LOGI("Stopping hcid deamon");
+    if (property_set("ctl.stop", "hcid") < 0) {
+        LOGE("Error stopping hcid");
+        goto out;
+    }
+    usleep(HCID_STOP_DELAY_USEC);
+
+    hci_sock = create_hci_sock();
+    if (hci_sock < 0) goto out;
+    ioctl(hci_sock, HCIDEVDOWN, HCI_DEV_ID);
+
+    LOGI("Stopping hciattach deamon");
+    if (property_set("ctl.stop", "hciattach") < 0) {
+        LOGE("Error stopping hciattach");
+        goto out;
+    }
+
+    if (set_bluetooth_power(0) < 0) {
+        goto out;
+    }
+    ret = 0;
+
+out:
+    if (hci_sock >= 0) close(hci_sock);
+    return ret;
+}
+
+int bt_is_enabled() {
+    LOGV(__FUNCTION__);
+
+    int hci_sock = -1;
+    int ret = -1;
+    struct hci_dev_info dev_info;
+
+
+    // Check power first
+    ret = check_bluetooth_power();
+    if (ret == -1 || ret == 0) goto out;
+
+    ret = -1;
+
+    // Power is on, now check if the HCI interface is up
+    hci_sock = create_hci_sock();
+    if (hci_sock < 0) goto out;
+
+    dev_info.dev_id = HCI_DEV_ID;
+    if (ioctl(hci_sock, HCIGETDEVINFO, (void *)&dev_info) < 0) {
+        ret = 0;
+        goto out;
+    }
+
+    ret = hci_test_bit(HCI_UP, &dev_info.flags);
+
+out:
+    if (hci_sock >= 0) close(hci_sock);
+    return ret;
+}
diff --git a/bluedroid/bttest.c b/bluedroid/bttest.c
new file mode 100644 (file)
index 0000000..25cd892
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+** Copyright 2008 Google Inc.
+**
+** 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.
+*/
+
+/** Bluedroid testing  */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <sys/uio.h>
+#include <unistd.h>
+
+#include <bluedroid/bluetooth.h>
+
+static int do_enable() {
+    int ret;
+    ret = bt_enable();
+    printf("= %d\n", ret);
+    return ret;
+}
+
+static int do_disable() {
+    int ret;
+    ret = bt_disable();
+    printf("= %d\n", ret);
+    return ret;
+}
+
+static int do_is_enabled() {
+    int ret;
+    ret = bt_is_enabled();
+    printf("= %d\n", ret);
+    return ret;
+}
+
+struct {
+    char *name;
+    int (*ptr)();
+} function_table[]  = {
+    {"enable", do_enable},
+    {"disable", do_disable},
+    {"is_enabled", do_is_enabled},
+    {NULL, NULL},
+};
+
+static void usage() {
+    int i;
+
+    printf("Usage:\n");
+    for (i = 0; function_table[i].name; i++) {
+        printf("\tbttest %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)();
+        }
+    }
+    usage();
+    return -1;
+}
diff --git a/bluedroid/include/bluedroid/bluetooth.h b/bluedroid/include/bluedroid/bluetooth.h
new file mode 100644 (file)
index 0000000..64603e9
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2008 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.
+ */
+
+#ifndef __BLUEDROID_BLUETOOTH_H__
+#define __BLUEDROID_BLUETOOTH_H__
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Enable the bluetooth interface.
+ *
+ * Responsible for power on, bringing up HCI interface, and starting daemons.
+ * Will block until the HCI interface and bluetooth daemons are ready to
+ * use.
+ *
+ * Returns 0 on success, -ve on error */
+int bt_enable();
+
+/* Disable the bluetooth interface.
+ *
+ * Responsbile for stopping daemons, pulling down the HCI interface, and
+ * powering down the chip. Will block until power down is complete, and it
+ * is safe to immediately call enable().
+ *
+ * Returns 0 on success, -ve on error */
+int bt_disable();
+
+/* Returns 1 if enabled, 0 if disabled, and -ve on error */
+int bt_is_enabled();
+
+#ifdef __cplusplus
+}
+#endif
+#endif //__BLUEDROID_BLUETOOTH_H__
diff --git a/brfpatch/Android.mk b/brfpatch/Android.mk
new file mode 100644 (file)
index 0000000..95189fd
--- /dev/null
@@ -0,0 +1,15 @@
+# Copyright 2007 The Android Open Source Project
+#
+# Utility to create Android bluetooth firmware from Texas Instruments .bts
+# scripts
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+       brfpatch.c
+
+LOCAL_MODULE_TAGS := eng
+LOCAL_MODULE := brfpatch
+
+include $(BUILD_HOST_EXECUTABLE)
diff --git a/brfpatch/brfpatch.c b/brfpatch/brfpatch.c
new file mode 100644 (file)
index 0000000..3f306e8
--- /dev/null
@@ -0,0 +1,184 @@
+/*
+** Copyright 2007, 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.
+*/
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+
+#define FAILIF(x, args...) do {          \
+    if (x) {                             \
+        fprintf(stderr, ##args);         \
+        exit(1);                         \
+    }                                    \
+} while(0)
+
+static void usage() {
+    printf("Usage: brfpatch INPUT OUTPUT\n"
+           "\n"
+           "\tGenerates bluetooth firmware\n"
+           "\n"
+           "INPUT: Bluetooth script in ASCII format.\n"
+           "       For TI BRF chips this can be generated from .bts files using the TI Bluetooth\n"
+           "       script pad to save as .txt. This txt file can be used as input.\n"
+           "       Alternately, run strings on the .bts and manually edit to change decimal\n"
+           "       arguments into hex of the appropriate number of octets.\n"
+           "       FORMAT: Send_HCI_xxxx OPCODE DATA1 DATA2 DATA3 ...\n"
+           "       where OPCODE, DATA1 etc are one of:\n"
+           "       0x12          (1 byte)\n"
+           "       0x1234        (2 byte)\n"
+           "       0x12345678    (4 byte)\n"
+           "       \"0123456789ABCDEF0123\"            (multibyte)\n"
+           "       \"01:23:45:67:89:AB:CD:EF:01:23\"   (multibyte)\n"
+           "\n"
+           "OUTPUT: Binary firmware\n"
+           "        FORMAT: 0x01 OPCODE DATA_LEN DATA\n");
+    exit(1);
+}
+
+static void dump_record(FILE *fpo, unsigned short opcode, unsigned char len,
+                        unsigned char *data) {
+
+    unsigned char prefix = 0x01;  // H4 UART command packet
+    fwrite(&prefix, 1, 1, fpo);
+    fwrite(&opcode, 2, 1, fpo);  // opcode
+    fwrite(&len, 1, 1, fpo);     // data length
+    fwrite(data, len, 1, fpo);   // data
+}
+
+// advance beyond next whitespace. Return -1 if end of string reached
+static int advance(char **buf) {
+    char *b = *buf;
+    while (*b && !isspace(*b))
+        b++;
+    while (*b && isspace(*b))
+        b++;
+    *buf = b;
+    if (!(*b))
+        return -1;
+    return 0;
+}
+
+static void process_line(FILE *file_out, char *buf, char *buffer) {
+    FAILIF(strncmp(buf, "Send_", 5) != 0, "Not expecting: %s\n", buffer);
+
+
+    unsigned int opcode;
+
+    FAILIF(advance(&buf), "Could not find opcode in: %s\n", buffer);
+    FAILIF(sscanf(buf, "0x%04x\n", &opcode) != 1,
+           "Could not find opcode in: %s\n", buffer);
+
+
+    unsigned char data[1024];
+    unsigned char *dp = data;
+
+    while (!advance(&buf)) {
+        switch (*buf) {
+        case '"':
+            buf++;
+            while (*buf != '"' && *buf != 0) {
+                FAILIF(dp > data + sizeof(data),
+                       "Too much data: %s\n", buffer);
+                FAILIF(sscanf(buf, "%02x", (unsigned int *)dp) != 1,
+                       "Error parsing (%d): %s\n", __LINE__, buffer);
+                dp++;
+                buf += 2;
+                if (*buf == ':')
+                    buf++;
+            }
+            break;
+        case '0':
+            buf++;
+            FAILIF(*buf != 'x', "Error parsing: %s\n", buffer);
+            buf++;
+
+            // find length of this piece of data
+            char *end = buf;
+            while (isalnum(*end))
+                end++;
+
+            // switch on length
+            switch ((unsigned int)end - (unsigned int)buf) {
+            case 2:
+                FAILIF(sscanf(buf, "%02x", (unsigned int *)dp) != 1,
+                       "Error parsing (%d): %s\n", __LINE__, buffer);
+                buf += 2;
+                dp += 1;
+                break;
+            case 4:
+                FAILIF(sscanf(buf, "%04x", (unsigned int *)dp) != 1,
+                       "Error parsing (%d): %s\n", __LINE__, buffer);
+                buf += 4;
+                dp += 2;
+                break;
+            case 8:
+                FAILIF(sscanf(buf, "%08x", (unsigned int *)dp) != 1,
+                       "Error parsing (%d): %s\n", __LINE__, buffer);
+                buf += 8;
+                dp += 4;
+                break;
+            default:
+                FAILIF(1, "Error parsing (%d): %s\n", __LINE__, buffer);
+            }
+            break;
+        default:
+            FAILIF(1, "Error parsing (%d): %s\n", __LINE__, buffer);
+        }
+    }
+
+    dump_record(file_out, opcode, dp - data, data);
+}
+
+
+int main(int argc, char **argv) {
+
+    if (argc != 3)
+        usage();
+
+    FILE *file_in = fopen(argv[1], "r");
+    FAILIF(!file_in, "Could not open %s: %s\n", argv[1], strerror(errno));
+
+    FILE *file_out = fopen(argv[2], "w+");
+    FAILIF(!file_out, "Could not open %s: %s\n", argv[2], strerror(errno));
+
+    char buffer[1024];
+    char *buf;
+
+    while (fgets(buffer, 1024, file_in) != NULL) {
+        buf = buffer;
+        while (*buf && isspace(*buf))
+            buf++;
+        switch (*buf) {
+        case 'S':
+            process_line(file_out, buf, buffer);
+            break;
+        case 'W':  // Wait_HCI_Command... meta-data, not needed
+        case '#':
+        case 0:
+            continue;
+        default:
+            FAILIF(1, "Don't know what to do with: %s\n", buffer);
+        }
+    }
+
+    fclose(file_in);
+    fclose(file_out);
+
+    return 0;
+}