Broadcom Bluetooth support

This patch contains a program to firmware file over UART and chip
initialization for Broadcom Bluetooth chipset. The patch also
contains -
1. Sample init script to start/stop brcm_patchram_plus
2. Test Bluetooth firmware file

Change-Id: Ia3aba77a6b9c82ce52d369e30bf5c21082b19b16
diff --git a/bluetooth/LICENSE.broadcom b/bluetooth/LICENSE.broadcom
new file mode 100644
index 0000000..315f379
--- /dev/null
+++ b/bluetooth/LICENSE.broadcom
@@ -0,0 +1,14 @@
+ Copyright (C) 2009-2014 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.
+
diff --git a/bluetooth/Makefile b/bluetooth/Makefile
new file mode 100644
index 0000000..b6363e3
--- /dev/null
+++ b/bluetooth/Makefile
@@ -0,0 +1,22 @@
+# Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
+# Copyright (C) 2009-2014 Broadcom Corporation
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+LDLIBS = -lbluetooth
+
+brcm_patchram_plus:	brcm_patchram_plus.c
+	$(CC) $(CFLAGS) $(CPPFLAGS)  $(LDFLAGS) -o $@ $< $(LDLIBS)
+
+$(DESTDIR)usr/sbin/brcm_patchram_plus:	brcm_patchram_plus
+	echo Installing to location  $(DESTDIR)usr/sbin
+	install --mode 555 -D -T $< $@
+
+all:	brcm_patchram_plus
+
+install:	$(DESTDIR)usr/sbin/brcm_patchram_plus
+
+clean:
+	rm -f brcm_patchram_plus *.o
+
+.PHONY:		all install clean
diff --git a/bluetooth/README.chromiumos b/bluetooth/README.chromiumos
new file mode 100644
index 0000000..adf4b31
--- /dev/null
+++ b/bluetooth/README.chromiumos
@@ -0,0 +1,24 @@
+# Copyright (C) 2014 Broadcom Corporation
+
+The program downloads firmware file over UART for Broadcom Bluetooth chipset.
+The patchram included in this path is a generic firmware for BCM4354 chipset.
+
+This module builds brcm_patchram_plus which uses the serial port to download
+the firmware, chip initialization and configuration. Once the chip is
+configured, brcm_patchram_plus will map the serial port to HCI and
+register as a HCI interface.
+
+The following are some important parameters to configure brcm_patchram_plus :
+
+-d                 : Enables debug logs for brcm_patchram_plus
+--enable_lpm       : Enables LPM mode
+--enable_bt_rfkill : Will use BT RFKILL interface to toggle BT power
+
+To configure brcm_patchram_plus, the parameters should be changed in
+brcm_bt.conf script.
+
+A sample brcm_bt.conf and default firmware file is also included in this
+module. These conf file has be modified for every platform and a new firmware
+file has to be added to the respective overlay-XXXX folder for every platform
+build.
+
diff --git a/bluetooth/brcm_patchram_plus.c b/bluetooth/brcm_patchram_plus.c
new file mode 100644
index 0000000..b4fa5a8
--- /dev/null
+++ b/bluetooth/brcm_patchram_plus.c
@@ -0,0 +1,950 @@
+/*******************************************************************************
+ *
+ *  Copyright (C) 2009-2014 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.>
+**						<--enable_bt_rfkill Enables BT over RFKILL.>
+**						<--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
+
+#ifndef N_BRCM_HCI
+#define N_BRCM_HCI	25
+#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
+#define HCI_UART_ATH3K	5
+#define HCI_UART_BCM_H4	6
+
+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;
+int enable_bt_over_rfkill = 0;
+
+int rfkill_id = -1;
+char *rfkill_state_path = NULL;
+
+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_enable_bt_rfkill(char *optarg)
+{
+	enable_bt_over_rfkill = 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("\t<--enable_bt_rfkill enables Bluetooth over RFKILL interface.>\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_enable_bt_rfkill, 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},
+            {"enable_bt_rfkill", 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);
+}
+
+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) {
+            fprintf(stderr, "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;
+}
+
+
+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;
+    printf("proc_enable_hci()  TIOCSETD for %d\n", N_HCI);
+    printf("proc_enable_hci()  HCIUARTSETPROTO for %d\n", HCI_UART_BCM_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;
+}
+
+void proc_bluetooth_power(int power)
+{
+    int sz;
+    int fd = -1;
+    int ret = -1;
+    const char buffer = (power ? '1' : '0');
+
+    if (rfkill_id == -1)
+    {
+        if (init_rfkill()) goto out;
+    }
+
+    fd = open(rfkill_state_path, O_WRONLY);
+    if (fd < 0)
+    {
+        fprintf(stderr, "open(%s) for write failed: %s (%d)",
+            rfkill_state_path, strerror(errno), errno);
+        goto out;
+    }
+    sz = write(fd, &buffer, 1);
+    if (sz < 0)
+    {
+        fprintf(stderr, "write(%s) failed: %s (%d)",
+            rfkill_state_path, strerror(errno), errno);
+        goto out;
+    }
+    ret = 0;
+
+out:
+    if (fd >= 0) close(fd);
+    if(ret != 0)
+    {
+        fprintf(stderr,
+            "Failed to enable Bluetooth power via RFKILL \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);
+	}
+    if(enable_bt_over_rfkill > 0) {
+        proc_bluetooth_power(1);
+    }
+
+	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);
+		}
+	}
+
+    if(enable_bt_over_rfkill > 0) {
+        proc_bluetooth_power(0);
+    }
+
+	exit(0);
+}
diff --git a/bluetooth/conf/brcm_bt.conf b/bluetooth/conf/brcm_bt.conf
new file mode 100644
index 0000000..9ff6f24
--- /dev/null
+++ b/bluetooth/conf/brcm_bt.conf
@@ -0,0 +1,28 @@
+# Copyright 2014 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+description   "Sample script to download Bluetooth firmware for BCM4354 chipset over UART interface only"
+author        "chromium-os-dev@chromium.org"
+
+start on starting bluetoothd
+stop on stopped bluetoothd
+
+respawn
+
+# The below pre-start block to ensure brcm_patchram_plus is executed only
+# when /dev/ttyUSB0 is up. This is only needed in cases where ttyUSB0
+# is not initialized when this script is executed (esp. when Bluetooth
+# chipset is connected over USB port)
+pre-start script
+  logger -t "$UPSTART_JOB"  "Waiting for /dev/ttyUSB0"
+  while [ ! -e /dev/ttyUSB0 ]; do
+    sleep 1
+  done
+  logger -t "$UPSTART_JOB"  "Wait Done"
+end script
+
+exec /usr/bin/brcm_patchram_plus --patchram \
+    /lib/firmware/brcm/BCM4354_003.001.012.0208.0000_UART_eLNA.hcd \
+    --no2bytes --enable_hci --baudrate 3000000 \
+    --use_baudrate_for_download --tosleep=50000 /dev/ttyUSB0
diff --git a/bluetooth/patchram/BCM4354_003.001.012.0208.0000_UART_eLNA.hcd b/bluetooth/patchram/BCM4354_003.001.012.0208.0000_UART_eLNA.hcd
new file mode 100755
index 0000000..7cbadf6
--- /dev/null
+++ b/bluetooth/patchram/BCM4354_003.001.012.0208.0000_UART_eLNA.hcd
Binary files differ