summaryrefslogtreecommitdiff
path: root/package
diff options
context:
space:
mode:
authorWaldemar Brodkorb <wbx@openadk.org>2014-04-28 14:34:24 +0200
committerWaldemar Brodkorb <wbx@openadk.org>2014-04-28 14:34:24 +0200
commitf2ca4c1e61103a90c3c19b3ccaf1ac765705fccb (patch)
treeb496cbb77986eaf6540da5a4c68be3661cd2a377 /package
parenta50e4ba4f3033b9cb8941f8f1b52fbf245e51e66 (diff)
add bluetooth firmware
Diffstat (limited to 'package')
-rw-r--r--package/brcm-bluetooth/Makefile34
-rw-r--r--package/brcm-bluetooth/src/bcm4329.hcdbin0 -> 17332 bytes
-rw-r--r--package/brcm-bluetooth/src/bcm4330.hcdbin0 -> 38001 bytes
-rw-r--r--package/brcm-bluetooth/src/brcm_patchram.c854
4 files changed, 888 insertions, 0 deletions
diff --git a/package/brcm-bluetooth/Makefile b/package/brcm-bluetooth/Makefile
new file mode 100644
index 000000000..d5551e826
--- /dev/null
+++ b/package/brcm-bluetooth/Makefile
@@ -0,0 +1,34 @@
+# This file is part of the OpenADK project. OpenADK is copyrighted
+# material, please see the LICENCE file in the top-level directory.
+
+include ${TOPDIR}/rules.mk
+
+PKG_NAME:= brcm-bluetooth
+PKG_VERSION:= 1.0
+PKG_RELEASE:= 1
+PKG_MD5SUM:= 85a7d1d1386143fad312a5a82c422380
+PKG_DESCR:= firmware for broadcom bluetooth chips
+PKG_SECTION:= wifi
+
+NO_DISTFILES:= 1
+
+include ${TOPDIR}/mk/package.mk
+
+$(eval $(call PKG_template,BRCM_BLUETOOTH,brcm-bluetooth,${PKG_VERSION}-${PKG_RELEASE},${PKG_DEPENDS},${PKG_DESCR},${PKG_SECTION}))
+
+CONFIG_STYLE:= manual
+BUILD_STYLE:= manual
+INSTALL_STYLE:= manual
+
+do-build:
+ ${TARGET_CC} ${TARGET_CPPFLAGS} ${TARGET_CFLAGS} ${TARGET_LDFLAGS} \
+ -o ${WRKBUILD}/brcm_patchram ${WRKBUILD}/brcm_patchram.c
+
+do-install:
+ ${INSTALL_DIR} ${IDIR_BRCM_BLUETOOTH}/lib/firmware/brcm
+ ${CP} ${WRKBUILD}/*.hcd ${IDIR_BRCM_BLUETOOTH}/lib/firmware/brcm
+ ${INSTALL_DIR} ${IDIR_BRCM_BLUETOOTH}/sbin
+ ${INSTALL_BIN} ${WRKBUILD}/brcm_patchram \
+ ${IDIR_BRCM_BLUETOOTH}/sbin/brcm_patchram
+
+include ${TOPDIR}/mk/pkg-bottom.mk
diff --git a/package/brcm-bluetooth/src/bcm4329.hcd b/package/brcm-bluetooth/src/bcm4329.hcd
new file mode 100644
index 000000000..b7c5762b1
--- /dev/null
+++ b/package/brcm-bluetooth/src/bcm4329.hcd
Binary files differ
diff --git a/package/brcm-bluetooth/src/bcm4330.hcd b/package/brcm-bluetooth/src/bcm4330.hcd
new file mode 100644
index 000000000..42f0c9253
--- /dev/null
+++ b/package/brcm-bluetooth/src/bcm4330.hcd
Binary files differ
diff --git a/package/brcm-bluetooth/src/brcm_patchram.c b/package/brcm-bluetooth/src/brcm_patchram.c
new file mode 100644
index 000000000..9aa2d93f6
--- /dev/null
+++ b/package/brcm-bluetooth/src/brcm_patchram.c
@@ -0,0 +1,854 @@
+/*******************************************************************************
+ *
+ * Copyright (C) 2009-2011 Broadcom Corporation
+ *
+ * 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.
+ *
+ ******************************************************************************/
+
+/*****************************************************************************
+**
+** Name: brcm_patchram_plus.c
+**
+** Description: This program downloads a patchram files in the HCD format
+** to Broadcom Bluetooth based silicon and combo chips and
+** and other utility functions.
+**
+** It can be invoked from the command line in the form
+** <-d> to print a debug log
+** <--patchram patchram_file>
+** <--baudrate baud_rate>
+** <--bd_addr bd_address>
+** <--enable_lpm>
+** <--enable_hci>
+** <--use_baudrate_for_download>
+** <--scopcm=sco_routing,pcm_interface_rate,frame_type,
+** sync_mode,clock_mode,lsb_first,fill_bits,
+** fill_method,fill_num,right_justify>
+**
+** Where
+**
+** sco_routing is 0 for PCM, 1 for Transport,
+** 2 for Codec and 3 for I2S,
+**
+** pcm_interface_rate is 0 for 128KBps, 1 for
+** 256 KBps, 2 for 512KBps, 3 for 1024KBps,
+** and 4 for 2048Kbps,
+**
+** frame_type is 0 for short and 1 for long,
+**
+** sync_mode is 0 for slave and 1 for master,
+**
+** clock_mode is 0 for slabe and 1 for master,
+**
+** lsb_first is 0 for false aand 1 for true,
+**
+** fill_bits is the value in decimal for unused bits,
+**
+** fill_method is 0 for 0's and 1 for 1's, 2 for
+** signed and 3 for programmable,
+**
+** fill_num is the number or bits to fill,
+**
+** right_justify is 0 for false and 1 for true
+**
+** <--i2s=i2s_enable,is_master,sample_rate,clock_rate>
+**
+** Where
+**
+** i2s_enable is 0 for disable and 1 for enable,
+**
+** is_master is 0 for slave and 1 for master,
+**
+** sample_rate is 0 for 8KHz, 1 for 16Khz and
+** 2 for 4 KHz,
+**
+** clock_rate is 0 for 128KHz, 1 for 256KHz, 3 for
+** 1024 KHz and 4 for 2048 KHz.
+**
+** <--no2bytes skips waiting for two byte confirmation
+** before starting patchram download. Newer chips
+** do not generate these two bytes.>
+** <--tosleep=number of microsseconds to sleep before
+** patchram download begins.>
+** uart_device_name
+**
+** For example:
+**
+** brcm_patchram_plus -d --patchram \
+** BCM2045B2_002.002.011.0348.0349.hcd /dev/ttyHS0
+**
+** It will return 0 for success and a number greater than 0
+** for any errors.
+**
+** For Android, this program invoked using a
+** "system(2)" call from the beginning of the bt_enable
+** function inside the file
+** system/bluetooth/bluedroid/bluetooth.c.
+**
+** If the Android system property "ro.bt.bcm_bdaddr_path" is
+** set, then the bd_addr will be read from this path.
+** This is overridden by --bd_addr on the command line.
+**
+******************************************************************************/
+
+#include <stdio.h>
+#include <getopt.h>
+#include <errno.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include <stdlib.h>
+
+#ifdef ANDROID
+#include <termios.h>
+#else
+#include <sys/termios.h>
+#include <sys/ioctl.h>
+#include <limits.h>
+#endif
+
+#include <string.h>
+#include <signal.h>
+
+#ifdef ANDROID
+#include <cutils/properties.h>
+#define LOG_TAG "brcm_patchram_plus"
+#include <cutils/log.h>
+#undef printf
+#define printf LOGD
+#undef fprintf
+#define fprintf(x, ...) \
+ { if(x==stderr) LOGE(__VA_ARGS__); else fprintf(x, __VA_ARGS__); }
+
+#endif //ANDROID
+
+#ifndef N_HCI
+#define N_HCI 15
+#endif
+
+#define HCIUARTSETPROTO _IOW('U', 200, int)
+#define HCIUARTGETPROTO _IOR('U', 201, int)
+#define HCIUARTGETDEVICE _IOR('U', 202, int)
+
+#define HCI_UART_H4 0
+#define HCI_UART_BCSP 1
+#define HCI_UART_3WIRE 2
+#define HCI_UART_H4DS 3
+#define HCI_UART_LL 4
+
+typedef unsigned char uchar;
+
+int uart_fd = -1;
+int hcdfile_fd = -1;
+int termios_baudrate = 0;
+int bdaddr_flag = 0;
+int enable_lpm = 0;
+int enable_hci = 0;
+int use_baudrate_for_download = 0;
+int debug = 0;
+int scopcm = 0;
+int i2s = 0;
+int no2bytes = 0;
+int tosleep = 0;
+int baudrate = 0;
+
+struct termios termios;
+uchar buffer[1024];
+
+uchar hci_reset[] = { 0x01, 0x03, 0x0c, 0x00 };
+
+uchar hci_download_minidriver[] = { 0x01, 0x2e, 0xfc, 0x00 };
+
+uchar hci_update_baud_rate[] = { 0x01, 0x18, 0xfc, 0x06, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00 };
+
+uchar hci_write_bd_addr[] = { 0x01, 0x01, 0xfc, 0x06,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+uchar hci_write_sleep_mode[] = { 0x01, 0x27, 0xfc, 0x0c,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00 };
+
+uchar hci_write_sco_pcm_int[] =
+ { 0x01, 0x1C, 0xFC, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+uchar hci_write_pcm_data_format[] =
+ { 0x01, 0x1e, 0xFC, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+uchar hci_write_i2spcm_interface_param[] =
+ { 0x01, 0x6d, 0xFC, 0x04, 0x00, 0x00, 0x00, 0x00 };
+
+uchar hci_write_uart_clock_setting_48Mhz[] =
+ { 0x01, 0x45, 0xfc, 0x01, 0x01 };
+
+int
+parse_patchram(char *optarg)
+{
+ char *p;
+
+ if (!(p = strrchr(optarg, '.'))) {
+ fprintf(stderr, "file %s not an HCD file\n", optarg);
+ exit(3);
+ }
+
+ p++;
+
+ if (strcasecmp("hcd", p) != 0) {
+ fprintf(stderr, "file %s not an HCD file\n", optarg);
+ exit(4);
+ }
+
+ if ((hcdfile_fd = open(optarg, O_RDONLY)) == -1) {
+ fprintf(stderr, "file %s could not be opened, error %d\n", optarg, errno);
+ exit(5);
+ }
+
+ return(0);
+}
+
+void
+BRCM_encode_baud_rate(uint baud_rate, uchar *encoded_baud)
+{
+ if(baud_rate == 0 || encoded_baud == NULL) {
+ fprintf(stderr, "Baudrate not supported!");
+ return;
+ }
+
+ encoded_baud[3] = (uchar)(baud_rate >> 24);
+ encoded_baud[2] = (uchar)(baud_rate >> 16);
+ encoded_baud[1] = (uchar)(baud_rate >> 8);
+ encoded_baud[0] = (uchar)(baud_rate & 0xFF);
+}
+
+typedef struct {
+ int baud_rate;
+ int termios_value;
+} tBaudRates;
+
+tBaudRates baud_rates[] = {
+ { 115200, B115200 },
+ { 230400, B230400 },
+ { 460800, B460800 },
+ { 500000, B500000 },
+ { 576000, B576000 },
+ { 921600, B921600 },
+ { 1000000, B1000000 },
+ { 1152000, B1152000 },
+ { 1500000, B1500000 },
+ { 2000000, B2000000 },
+ { 2500000, B2500000 },
+ { 3000000, B3000000 },
+#ifndef __CYGWIN__
+ { 3500000, B3500000 },
+ { 4000000, B4000000 }
+#endif
+};
+
+int
+validate_baudrate(int baud_rate, int *value)
+{
+ unsigned int i;
+
+ for (i = 0; i < (sizeof(baud_rates) / sizeof(tBaudRates)); i++) {
+ if (baud_rates[i].baud_rate == baud_rate) {
+ *value = baud_rates[i].termios_value;
+ return(1);
+ }
+ }
+
+ return(0);
+}
+
+int
+parse_baudrate(char *optarg)
+{
+ baudrate = atoi(optarg);
+
+ if (validate_baudrate(baudrate, &termios_baudrate)) {
+ BRCM_encode_baud_rate(baudrate, &hci_update_baud_rate[6]);
+ } else {
+ return(1);
+ }
+
+ return(0);
+}
+
+int
+parse_bdaddr(char *optarg)
+{
+ int bd_addr[6];
+ int i;
+
+ sscanf(optarg, "%02X:%02X:%02X:%02X:%02X:%02X",
+ &bd_addr[5], &bd_addr[4], &bd_addr[3],
+ &bd_addr[2], &bd_addr[1], &bd_addr[0]);
+
+ for (i = 0; i < 6; i++) {
+ hci_write_bd_addr[4 + i] = bd_addr[i];
+ }
+
+ bdaddr_flag = 1;
+
+ return(0);
+}
+
+int
+parse_enable_lpm(char *optarg)
+{
+ enable_lpm = 1;
+ return(0);
+}
+
+int
+parse_use_baudrate_for_download(char *optarg)
+{
+ use_baudrate_for_download = 1;
+ return(0);
+}
+
+int
+parse_enable_hci(char *optarg)
+{
+ enable_hci = 1;
+ return(0);
+}
+
+int
+parse_scopcm(char *optarg)
+{
+ int param[10];
+ int ret;
+ int i;
+
+ ret = sscanf(optarg, "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d",
+ &param[0], &param[1], &param[2], &param[3], &param[4],
+ &param[5], &param[6], &param[7], &param[8], &param[9]);
+
+ if (ret != 10) {
+ return(1);
+ }
+
+ scopcm = 1;
+
+ for (i = 0; i < 5; i++) {
+ hci_write_sco_pcm_int[4 + i] = param[i];
+ }
+
+ for (i = 0; i < 5; i++) {
+ hci_write_pcm_data_format[4 + i] = param[5 + i];
+ }
+
+ return(0);
+}
+
+int
+parse_i2s(char *optarg)
+{
+ int param[4];
+ int ret;
+ int i;
+
+ ret = sscanf(optarg, "%d,%d,%d,%d", &param[0], &param[1], &param[2],
+ &param[3]);
+
+ if (ret != 4) {
+ return(1);
+ }
+
+ i2s = 1;
+
+ for (i = 0; i < 4; i++) {
+ hci_write_i2spcm_interface_param[4 + i] = param[i];
+ }
+
+ return(0);
+}
+
+int
+parse_no2bytes(char *optarg)
+{
+ no2bytes = 1;
+ return(0);
+}
+
+int
+parse_tosleep(char *optarg)
+{
+ tosleep = atoi(optarg);
+
+ if (tosleep <= 0) {
+ return(1);
+ }
+
+ return(0);
+}
+
+void
+usage(char *argv0)
+{
+ printf("Usage %s:\n", argv0);
+ printf("\t<-d> to print a debug log\n");
+ printf("\t<--patchram patchram_file>\n");
+ printf("\t<--baudrate baud_rate>\n");
+ printf("\t<--bd_addr bd_address>\n");
+ printf("\t<--enable_lpm>\n");
+ printf("\t<--enable_hci>\n");
+ printf("\t<--use_baudrate_for_download> - Uses the\n");
+ printf("\t\tbaudrate for downloading the firmware\n");
+ printf("\t<--scopcm=sco_routing,pcm_interface_rate,frame_type,\n");
+ printf("\t\tsync_mode,clock_mode,lsb_first,fill_bits,\n");
+ printf("\t\tfill_method,fill_num,right_justify>\n");
+ printf("\n\t\tWhere\n");
+ printf("\n\t\tsco_routing is 0 for PCM, 1 for Transport,\n");
+ printf("\t\t2 for Codec and 3 for I2S,\n");
+ printf("\n\t\tpcm_interface_rate is 0 for 128KBps, 1 for\n");
+ printf("\t\t256 KBps, 2 for 512KBps, 3 for 1024KBps,\n");
+ printf("\t\tand 4 for 2048Kbps,\n");
+ printf("\n\t\tframe_type is 0 for short and 1 for long,\n");
+ printf("\t\tsync_mode is 0 for slave and 1 for master,\n");
+ printf("\n\t\tclock_mode is 0 for slabe and 1 for master,\n");
+ printf("\n\t\tlsb_first is 0 for false aand 1 for true,\n");
+ printf("\n\t\tfill_bits is the value in decimal for unused bits,\n");
+ printf("\n\t\tfill_method is 0 for 0's and 1 for 1's, 2 for\n");
+ printf("\t\tsigned and 3 for programmable,\n");
+ printf("\n\t\tfill_num is the number or bits to fill,\n");
+ printf("\n\t\tright_justify is 0 for false and 1 for true\n");
+ printf("\n\t<--i2s=i2s_enable,is_master,sample_rate,clock_rate>\n");
+ printf("\n\t\tWhere\n");
+ printf("\n\t\ti2s_enable is 0 for disable and 1 for enable,\n");
+ printf("\n\t\tis_master is 0 for slave and 1 for master,\n");
+ printf("\n\t\tsample_rate is 0 for 8KHz, 1 for 16Khz and\n");
+ printf("\t\t2 for 4 KHz,\n");
+ printf("\n\t\tclock_rate is 0 for 128KHz, 1 for 256KHz, 3 for\n");
+ printf("\t\t1024 KHz and 4 for 2048 KHz.\n\n");
+ printf("\t<--no2bytes skips waiting for two byte confirmation\n");
+ printf("\t\tbefore starting patchram download. Newer chips\n");
+ printf("\t\tdo not generate these two bytes.>\n");
+ printf("\t<--tosleep=microseconds>\n");
+ printf("\tuart_device_name\n");
+}
+
+int
+parse_cmd_line(int argc, char **argv)
+{
+ int c;
+ int ret = 0;
+
+ typedef int (*PFI)();
+
+ PFI parse[] = { parse_patchram, parse_baudrate,
+ parse_bdaddr, parse_enable_lpm, parse_enable_hci,
+ parse_use_baudrate_for_download,
+ parse_scopcm, parse_i2s, parse_no2bytes, parse_tosleep};
+
+ while (1) {
+ int this_option_optind = optind ? optind : 1;
+ int option_index = 0;
+
+ static struct option long_options[] = {
+ {"patchram", 1, 0, 0},
+ {"baudrate", 1, 0, 0},
+ {"bd_addr", 1, 0, 0},
+ {"enable_lpm", 0, 0, 0},
+ {"enable_hci", 0, 0, 0},
+ {"use_baudrate_for_download", 0, 0, 0},
+ {"scopcm", 1, 0, 0},
+ {"i2s", 1, 0, 0},
+ {"no2bytes", 0, 0, 0},
+ {"tosleep", 1, 0, 0},
+ {0, 0, 0, 0}
+ };
+
+ c = getopt_long_only (argc, argv, "d", long_options,
+ &option_index);
+
+ if (c == -1) {
+ break;
+ }
+
+ switch (c) {
+ case 0:
+ if (debug) {
+ printf ("option %s",
+ long_options[option_index].name);
+ if (optarg)
+ printf (" with arg %s", optarg);
+ printf ("\n");
+ }
+
+ ret = (*parse[option_index])(optarg);
+
+ break;
+ case 'd':
+ debug = 1;
+ break;
+
+ case '?':
+ //nobreak
+ default:
+ usage(argv[0]);
+ break;
+ }
+
+ if (ret) {
+ usage(argv[0]);
+ break;
+ }
+ }
+
+ if (ret) {
+ return(1);
+ }
+
+ if (optind < argc) {
+ if (debug)
+ printf ("%s \n", argv[optind]);
+ if ((uart_fd = open(argv[optind], O_RDWR | O_NOCTTY)) == -1) {
+ fprintf(stderr, "port %s could not be opened, error %d\n",
+ argv[optind], errno);
+ }
+ }
+
+ return(0);
+}
+
+void
+init_uart()
+{
+ tcflush(uart_fd, TCIOFLUSH);
+ tcgetattr(uart_fd, &termios);
+
+#ifndef __CYGWIN__
+ cfmakeraw(&termios);
+#else
+ termios.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP
+ | INLCR | IGNCR | ICRNL | IXON);
+ termios.c_oflag &= ~OPOST;
+ termios.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
+ termios.c_cflag &= ~(CSIZE | PARENB);
+ termios.c_cflag |= CS8;
+#endif
+
+ termios.c_cflag |= CRTSCTS;
+ tcsetattr(uart_fd, TCSANOW, &termios);
+ tcflush(uart_fd, TCIOFLUSH);
+ tcsetattr(uart_fd, TCSANOW, &termios);
+ tcflush(uart_fd, TCIOFLUSH);
+ tcflush(uart_fd, TCIOFLUSH);
+ cfsetospeed(&termios, B115200);
+ cfsetispeed(&termios, B115200);
+ tcsetattr(uart_fd, TCSANOW, &termios);
+}
+
+void
+dump(uchar *out, int len)
+{
+ int i;
+
+ for (i = 0; i < len; i++) {
+ if (i && !(i % 16)) {
+ fprintf(stderr, "\n");
+ }
+
+ fprintf(stderr, "%02x ", out[i]);
+ }
+
+ fprintf(stderr, "\n");
+}
+
+void
+read_event(int fd, uchar *buffer)
+{
+ int i = 0;
+ int len = 3;
+ int count;
+
+ while ((count = read(fd, &buffer[i], len)) < len) {
+ i += count;
+ len -= count;
+ }
+
+ i += count;
+ len = buffer[2];
+
+ while ((count = read(fd, &buffer[i], len)) < len) {
+ i += count;
+ len -= count;
+ }
+
+ if (debug) {
+ count += i;
+
+ fprintf(stderr, "received %d\n", count);
+ dump(buffer, count);
+ }
+}
+
+void
+hci_send_cmd(uchar *buf, int len)
+{
+ if (debug) {
+ fprintf(stderr, "writing\n");
+ dump(buf, len);
+ }
+
+ write(uart_fd, buf, len);
+}
+
+void
+expired(int sig)
+{
+ hci_send_cmd(hci_reset, sizeof(hci_reset));
+ alarm(4);
+}
+
+void
+proc_reset()
+{
+ signal(SIGALRM, expired);
+
+
+ hci_send_cmd(hci_reset, sizeof(hci_reset));
+
+ alarm(4);
+
+ read_event(uart_fd, buffer);
+
+ alarm(0);
+}
+
+void
+proc_patchram()
+{
+ int len;
+
+ hci_send_cmd(hci_download_minidriver, sizeof(hci_download_minidriver));
+
+ read_event(uart_fd, buffer);
+
+ if (!no2bytes) {
+ read(uart_fd, &buffer[0], 2);
+ }
+
+ if (tosleep) {
+ usleep(tosleep);
+ }
+
+ while (read(hcdfile_fd, &buffer[1], 3)) {
+ buffer[0] = 0x01;
+
+ len = buffer[3];
+
+ read(hcdfile_fd, &buffer[4], len);
+
+ hci_send_cmd(buffer, len + 4);
+
+ read_event(uart_fd, buffer);
+ }
+
+ if (use_baudrate_for_download) {
+ cfsetospeed(&termios, B115200);
+ cfsetispeed(&termios, B115200);
+ tcsetattr(uart_fd, TCSANOW, &termios);
+ }
+ proc_reset();
+}
+
+void
+proc_baudrate()
+{
+
+ if (baudrate > 3000000) {
+ hci_send_cmd(hci_write_uart_clock_setting_48Mhz,
+ sizeof(hci_write_uart_clock_setting_48Mhz));
+
+ read_event(uart_fd, buffer);
+ }
+
+ hci_send_cmd(hci_update_baud_rate, sizeof(hci_update_baud_rate));
+
+ read_event(uart_fd, buffer);
+
+ cfsetospeed(&termios, termios_baudrate);
+ cfsetispeed(&termios, termios_baudrate);
+ tcsetattr(uart_fd, TCSANOW, &termios);
+
+ if (debug) {
+ fprintf(stderr, "Done setting baudrate\n");
+ }
+}
+
+void
+proc_bdaddr()
+{
+ hci_send_cmd(hci_write_bd_addr, sizeof(hci_write_bd_addr));
+
+ read_event(uart_fd, buffer);
+}
+
+void
+proc_enable_lpm()
+{
+ hci_send_cmd(hci_write_sleep_mode, sizeof(hci_write_sleep_mode));
+
+ read_event(uart_fd, buffer);
+}
+
+void
+proc_scopcm()
+{
+ hci_send_cmd(hci_write_sco_pcm_int,
+ sizeof(hci_write_sco_pcm_int));
+
+ read_event(uart_fd, buffer);
+
+ hci_send_cmd(hci_write_pcm_data_format,
+ sizeof(hci_write_pcm_data_format));
+
+ read_event(uart_fd, buffer);
+}
+
+void
+proc_i2s()
+{
+ hci_send_cmd(hci_write_i2spcm_interface_param,
+ sizeof(hci_write_i2spcm_interface_param));
+
+ read_event(uart_fd, buffer);
+}
+
+void
+proc_enable_hci()
+{
+ int i = N_HCI;
+ int proto = HCI_UART_H4;
+ if (ioctl(uart_fd, TIOCSETD, &i) < 0) {
+ fprintf(stderr, "Can't set line discipline\n");
+ return;
+ }
+
+ if (ioctl(uart_fd, HCIUARTSETPROTO, proto) < 0) {
+ fprintf(stderr, "Can't set hci protocol\n");
+ return;
+ }
+ fprintf(stderr, "Done setting line discpline\n");
+ return;
+}
+
+#ifdef ANDROID
+void
+read_default_bdaddr()
+{
+ int sz;
+ int fd;
+
+ char path[PROPERTY_VALUE_MAX];
+
+ char bdaddr[18];
+ int len = 17;
+ memset(bdaddr, 0, (len + 1) * sizeof(char));
+
+ property_get("ro.bt.bdaddr_path", path, "");
+ if (path[0] == 0)
+ return;
+
+ fd = open(path, O_RDONLY);
+ if (fd < 0) {
+ fprintf(stderr, "open(%s) failed: %s (%d)", path, strerror(errno),
+ errno);
+ return;
+ }
+
+ sz = read(fd, bdaddr, len);
+ if (sz < 0) {
+ fprintf(stderr, "read(%s) failed: %s (%d)", path, strerror(errno),
+ errno);
+ close(fd);
+ return;
+ } else if (sz != len) {
+ fprintf(stderr, "read(%s) unexpected size %d", path, sz);
+ close(fd);
+ return;
+ }
+
+ if (debug) {
+ printf("Read default bdaddr of %s\n", bdaddr);
+ }
+
+ parse_bdaddr(bdaddr);
+}
+#endif
+
+
+int
+main (int argc, char **argv)
+{
+#ifdef ANDROID
+ read_default_bdaddr();
+#endif
+
+ if (parse_cmd_line(argc, argv)) {
+ exit(1);
+ }
+
+ if (uart_fd < 0) {
+ exit(2);
+ }
+
+ init_uart();
+
+ proc_reset();
+
+ if (use_baudrate_for_download) {
+ if (termios_baudrate) {
+ proc_baudrate();
+ }
+ }
+
+ if (hcdfile_fd > 0) {
+ proc_patchram();
+ }
+
+ if (termios_baudrate) {
+ proc_baudrate();
+ }
+
+ if (bdaddr_flag) {
+ proc_bdaddr();
+ }
+
+ if (enable_lpm) {
+ proc_enable_lpm();
+ }
+
+ if (scopcm) {
+ proc_scopcm();
+ }
+
+ if (i2s) {
+ proc_i2s();
+ }
+
+ if (enable_hci) {
+ proc_enable_hci();
+
+ while (1) {
+ sleep(UINT_MAX);
+ }
+ }
+
+ exit(0);
+}