brcm_patchram_plus.c revision d4397861e745c5b6ae99fe547b841df9babf3085
1ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly/**
2ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly * brcm_patchram_plus.c
3ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly *
4ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly * Copyright (C) 2009 Broadcom Corporation.
5ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly *
6ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly * This software is licensed under the terms of the GNU General Public License,
7ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly * version 2, as published by the Free Software Foundation (the "GPL"), and may
8ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly * be copied, distributed, and modified under those terms.
9ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly *
10ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly * This program is distributed in the hope that it will be useful, but WITHOUT
11ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly * FITNESS FOR A PARTICULAR PURPOSE. See the GPL for more details.
13ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly *
14ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly * A copy of the GPL is available at http://www.broadcom.com/licenses/GPLv2.php
15ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly * or by writing to the Free Software Foundation, Inc.,
16ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
17ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly */
18ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly
19ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly
20ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly/*****************************************************************************
21ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly**
22ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly**  Name:          brcm_patchram_plus.c
23ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly**
24ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly**  Description:   This program downloads a patchram files in the HCD format
25ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly**                 to Broadcom Bluetooth based silicon and combo chips and
26ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly**				   and other utility functions.
27ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly**
28ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly**                 It can be invoked from the command line in the form
29ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly**						<-d> to print a debug log
30ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly**						<--patchram patchram_file>
31ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly**						<--baudrate baud_rate>
32ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly**						<--bd_addr bd_address>
33ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly**						<--enable_lpm>
34ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly**						<--enable_hci>
35ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly**						uart_device_name
36ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly**
37ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly**                 For example:
38ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly**
39ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly**                 brcm_patchram_plus -d --patchram  \
40ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly**						BCM2045B2_002.002.011.0348.0349.hcd /dev/ttyHS0
41ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly**
42ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly**                 It will return 0 for success and a number greater than 0
43ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly**                 for any errors.
44ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly**
45ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly**                 For Android, this program invoked using a
46ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly**                 "system(2)" call from the beginning of the bt_enable
47ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly**                 function inside the file
48db5ccf71519a49fbb36b915dba551aa0b3fa0db8Nick Pelly**                 system/bluetooth/bluedroid/bluetooth.c.
49ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly**
50db5ccf71519a49fbb36b915dba551aa0b3fa0db8Nick Pelly**                 If the Android system property "ro.bt.bcm_bdaddr_path" is
51db5ccf71519a49fbb36b915dba551aa0b3fa0db8Nick Pelly**                 set, then the bd_addr will be read from this path.
52db5ccf71519a49fbb36b915dba551aa0b3fa0db8Nick Pelly**                 This is overridden by --bd_addr on the command line.
53ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly**
54ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly******************************************************************************/
55ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly
56ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly// TODO: Integrate BCM support into Bluez hciattach
57ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly
58ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly#include <stdio.h>
59ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly#include <getopt.h>
60ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly#include <errno.h>
61ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly
62ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly#include <sys/types.h>
63ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly#include <sys/stat.h>
64ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly#include <fcntl.h>
65ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly
66ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly#include <stdlib.h>
67ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly
68ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly#ifdef ANDROID
69ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly#include <termios.h>
70ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly#else
71ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly#include <sys/termios.h>
72ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly#endif
73ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly
74ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly#include <string.h>
75ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly#include <signal.h>
76ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly
77db5ccf71519a49fbb36b915dba551aa0b3fa0db8Nick Pelly#include <cutils/properties.h>
78db5ccf71519a49fbb36b915dba551aa0b3fa0db8Nick Pelly
79ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly#ifndef N_HCI
80ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly#define N_HCI	15
81ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly#endif
82ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly
83ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly#define HCIUARTSETPROTO		_IOW('U', 200, int)
84ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly#define HCIUARTGETPROTO		_IOR('U', 201, int)
85ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly#define HCIUARTGETDEVICE	_IOR('U', 202, int)
86ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly
87ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly#define HCI_UART_H4		0
88ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly#define HCI_UART_BCSP	1
89ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly#define HCI_UART_3WIRE	2
90ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly#define HCI_UART_H4DS	3
91ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly#define HCI_UART_LL		4
92ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly
93ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly
94ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pellyint uart_fd = -1;
95ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pellyint hcdfile_fd = -1;
96ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pellyint termios_baudrate = 0;
97ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pellyint bdaddr_flag = 0;
98ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pellyint enable_lpm = 0;
99ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pellyint enable_hci = 0;
100ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pellyint debug = 0;
101ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly
102ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pellystruct termios termios;
103ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pellyunsigned char buffer[1024];
104ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly
105ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pellyunsigned char hci_reset[] = { 0x01, 0x03, 0x0c, 0x00 };
106ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly
107ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pellyunsigned char hci_download_minidriver[] = { 0x01, 0x2e, 0xfc, 0x00 };
108ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly
109ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pellyunsigned char hci_update_baud_rate[] = { 0x01, 0x18, 0xfc, 0x06, 0x00, 0x00,
110ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	0x00, 0x00, 0x00, 0x00 };
111ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly
112ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pellyunsigned char hci_write_bd_addr[] = { 0x01, 0x01, 0xfc, 0x06,
113db5ccf71519a49fbb36b915dba551aa0b3fa0db8Nick Pelly	0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
114ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly
115ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pellyunsigned char hci_write_sleep_mode[] = { 0x01, 0x27, 0xfc, 0x0c,
116d4397861e745c5b6ae99fe547b841df9babf3085Nick Pelly	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00,
117ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	0x00, 0x00 };
118ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly
119ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pellyint
120ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pellyparse_patchram(char *optarg)
121ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly{
122ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	char *p;
123ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly
124ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	if (!(p = strrchr(optarg, '.'))) {
125ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly		fprintf(stderr, "file %s not an HCD file\n", optarg);
126ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly		exit(3);
127ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	}
128ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly
129ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	p++;
130ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly
131ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	if (strcasecmp("hcd", p) != 0) {
132ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly		fprintf(stderr, "file %s not an HCD file\n", optarg);
133ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly		exit(4);
134ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	}
135ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly
136ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	if ((hcdfile_fd = open(optarg, O_RDONLY)) == -1) {
137ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly		fprintf(stderr, "file %s could not be opened, error %d\n", optarg, errno);
138ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly		exit(5);
139ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	}
140ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly
141ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	return(0);
142ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly}
143ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly
144ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pellyvoid
145ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick PellyBRCM_encode_baud_rate(uint baud_rate, unsigned char *encoded_baud)
146ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly{
147ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	if(baud_rate == 0 || encoded_baud == NULL) {
148ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly		fprintf(stderr, "Baudrate not supported!");
149ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly		return;
150ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	}
151ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly
152ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	encoded_baud[3] = (unsigned char)(baud_rate >> 24);
153ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	encoded_baud[2] = (unsigned char)(baud_rate >> 16);
154ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	encoded_baud[1] = (unsigned char)(baud_rate >> 8);
155ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	encoded_baud[0] = (unsigned char)(baud_rate & 0xFF);
156ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly}
157ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly
158ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pellytypedef struct {
159ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	int baud_rate;
160ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	int termios_value;
161ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly} tBaudRates;
162ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly
163ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick PellytBaudRates baud_rates[] = {
164ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	{ 115200, B115200 },
165ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	{ 230400, B230400 },
166ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	{ 460800, B460800 },
167ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	{ 500000, B500000 },
168ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	{ 576000, B576000 },
169ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	{ 921600, B921600 },
170ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	{ 1000000, B1000000 },
171ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	{ 1152000, B1152000 },
172ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	{ 1500000, B1500000 },
173ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	{ 2000000, B2000000 },
174ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	{ 2500000, B2500000 },
175ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	{ 3000000, B3000000 },
176ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly#ifndef __CYGWIN__
177ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	{ 3500000, B3500000 },
178ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	{ 4000000, B4000000 }
179ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly#endif
180ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly};
181ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly
182ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pellyint
183ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pellyvalidate_baudrate(int baud_rate, int *value)
184ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly{
185ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	unsigned int i;
186ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly
187ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	for (i = 0; i < (sizeof(baud_rates) / sizeof(tBaudRates)); i++) {
188ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly		if (baud_rates[i].baud_rate == baud_rate) {
189ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly			*value = baud_rates[i].termios_value;
190ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly			return(1);
191ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly		}
192ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	}
193ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly
194ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	return(0);
195ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly}
196ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly
197ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pellyint
198ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pellyparse_baudrate(char *optarg)
199ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly{
200ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	int baudrate = atoi(optarg);
201ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly
202ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	if (validate_baudrate(baudrate, &termios_baudrate)) {
203ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly		BRCM_encode_baud_rate(baudrate, &hci_update_baud_rate[6]);
204ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	}
205ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly
206ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	return(0);
207ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly}
208ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly
209ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pellyint
210ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pellyparse_bdaddr(char *optarg)
211ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly{
212ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	int bd_addr[6];
213ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	int i;
214ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly
215db5ccf71519a49fbb36b915dba551aa0b3fa0db8Nick Pelly	sscanf(optarg, "%02X:%02X:%02X:%02X:%02X:%02X",
216db5ccf71519a49fbb36b915dba551aa0b3fa0db8Nick Pelly		&bd_addr[5], &bd_addr[4], &bd_addr[3],
217db5ccf71519a49fbb36b915dba551aa0b3fa0db8Nick Pelly		&bd_addr[2], &bd_addr[1], &bd_addr[0]);
218ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly
219ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	for (i = 0; i < 6; i++) {
220ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly		hci_write_bd_addr[4 + i] = bd_addr[i];
221ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	}
222ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly
223ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	bdaddr_flag = 1;
224ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly
225ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	return(0);
226ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly}
227ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly
228ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pellyint
229ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pellyparse_enable_lpm(char *optarg)
230ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly{
231ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	enable_lpm = 1;
232ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	return(0);
233ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly}
234ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly
235ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pellyint
236ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pellyparse_enable_hci(char *optarg)
237ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly{
238ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	enable_hci = 1;
239ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	return(0);
240ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly}
241ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly
242ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pellyint
243ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pellyparse_cmd_line(int argc, char **argv)
244ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly{
245ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	int c;
246ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	int digit_optind = 0;
247ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly
248ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	typedef int (*PFI)();
249ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly
250ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	PFI parse_param[] = { parse_patchram, parse_baudrate,
251ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly		parse_bdaddr, parse_enable_lpm, parse_enable_hci };
252ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly
253ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly    while (1)
254ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly    {
255ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly    	int this_option_optind = optind ? optind : 1;
256ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly        int option_index = 0;
257ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly
258ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly       	static struct option long_options[] = {
259ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly         {"patchram", 1, 0, 0},
260ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly         {"baudrate", 1, 0, 0},
261ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly         {"bd_addr", 1, 0, 0},
262ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly         {"enable_lpm", 0, 0, 0},
263ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly         {"enable_hci", 0, 0, 0},
264ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly         {0, 0, 0, 0}
265ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly       	};
266ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly
267ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly       	c = getopt_long_only (argc, argv, "d", long_options, &option_index);
268ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly
269ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly       	if (c == -1) {
270ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly      		break;
271ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly		}
272ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly
273ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly       	switch (c) {
274ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly        case 0:
275ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly        	printf ("option %s", long_options[option_index].name);
276ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly
277ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly        	if (optarg) {
278ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly           		printf (" with arg %s", optarg);
279ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly			}
280ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly
281ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly           	printf ("\n");
282ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly
283ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly			(*parse_param[option_index])(optarg);
284ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly		break;
285ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly
286ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly		case 'd':
287ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly			debug = 1;
288ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly		break;
289ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly
290ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly        case '?':
291ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly			//nobreak
292ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly        default:
293ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly
294ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly			printf("Usage %s:\n", argv[0]);
295ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly			printf("\t<-d> to print a debug log\n");
296ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly			printf("\t<--patchram patchram_file>\n");
297ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly			printf("\t<--baudrate baud_rate>\n");
298ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly			printf("\t<--bd_addr bd_address>\n");
299ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly			printf("\t<--enable_lpm\n");
300ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly			printf("\t<--enable_hci\n");
301ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly			printf("\tuart_device_name\n");
302ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly           	break;
303ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly
304ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly        }
305ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	}
306ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly
307ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly   	if (optind < argc) {
308ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly       	if (optind < argc) {
309ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly       		printf ("%s ", argv[optind]);
310ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly
311ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly			if ((uart_fd = open(argv[optind], O_RDWR | O_NOCTTY)) == -1) {
312ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly				fprintf(stderr, "port %s could not be opened, error %d\n", argv[2], errno);
313ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly			}
314ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly		}
315ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly
316ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly       	printf ("\n");
317ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly    }
318ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly
319ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	return(0);
320ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly}
321ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly
322ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pellyvoid
323ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pellyinit_uart()
324ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly{
325ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	tcflush(uart_fd, TCIOFLUSH);
326ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	tcgetattr(uart_fd, &termios);
327ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly
328ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly#ifndef __CYGWIN__
329ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	cfmakeraw(&termios);
330ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly#else
331ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	termios.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP
332ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly                | INLCR | IGNCR | ICRNL | IXON);
333ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	termios.c_oflag &= ~OPOST;
334ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	termios.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
335ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	termios.c_cflag &= ~(CSIZE | PARENB);
336ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	termios.c_cflag |= CS8;
337ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly#endif
338ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly
339ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	termios.c_cflag |= CRTSCTS;
340ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	tcsetattr(uart_fd, TCSANOW, &termios);
341ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	tcflush(uart_fd, TCIOFLUSH);
342ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	tcsetattr(uart_fd, TCSANOW, &termios);
343ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	tcflush(uart_fd, TCIOFLUSH);
344ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	tcflush(uart_fd, TCIOFLUSH);
345ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	cfsetospeed(&termios, B115200);
346ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	cfsetispeed(&termios, B115200);
347ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	tcsetattr(uart_fd, TCSANOW, &termios);
348ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly}
349ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly
350ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pellyvoid
351ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pellydump(unsigned char *out, int len)
352ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly{
353ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	int i;
354ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly
355ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	for (i = 0; i < len; i++) {
356ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly		if (i && !(i % 16)) {
357ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly			fprintf(stderr, "\n");
358ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly		}
359ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly
360ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly		fprintf(stderr, "%02x ", out[i]);
361ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	}
362ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly
363ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	fprintf(stderr, "\n");
364ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly}
365ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly
366ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pellyvoid
367ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pellyread_event(int fd, unsigned char *buffer)
368ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly{
369ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	int i = 0;
370ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	int len = 3;
371ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	int count;
372ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly
373ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	while ((count = read(fd, &buffer[i], len)) < len) {
374ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly		i += count;
375ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly		len -= count;
376ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	}
377ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly
378ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	i += count;
379ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	len = buffer[2];
380ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly
381ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	while ((count = read(fd, &buffer[i], len)) < len) {
382ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly		i += count;
383ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly		len -= count;
384ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	}
385ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly
386ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	if (debug) {
387ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly		count += i;
388ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly
389ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly		fprintf(stderr, "received %d\n", count);
390ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly		dump(buffer, count);
391ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	}
392ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly}
393ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly
394ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pellyvoid
395ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pellyhci_send_cmd(unsigned char *buf, int len)
396ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly{
397ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	if (debug) {
398ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly		fprintf(stderr, "writing\n");
399ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly		dump(buf, len);
400ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	}
401ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly
402ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	write(uart_fd, buf, len);
403ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly}
404ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly
405ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pellyvoid
406ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pellyexpired(int sig)
407ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly{
408ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	hci_send_cmd(hci_reset, sizeof(hci_reset));
409ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	alarm(4);
410ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly}
411ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly
412ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pellyvoid
413ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pellyproc_reset()
414ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly{
415ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	signal(SIGALRM, expired);
416ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly
417ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly
418ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	hci_send_cmd(hci_reset, sizeof(hci_reset));
419ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly
420ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	alarm(4);
421ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly
422ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	read_event(uart_fd, buffer);
423ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly
424ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	alarm(0);
425ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly}
426ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly
427ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pellyvoid
428ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pellyproc_patchram()
429ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly{
430ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	int len;
431ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly
432ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	hci_send_cmd(hci_download_minidriver, sizeof(hci_download_minidriver));
433ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly
434ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	read_event(uart_fd, buffer);
435ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly
436ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	read(uart_fd, &buffer[0], 2);
437ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly
438ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	while (read(hcdfile_fd, &buffer[1], 3)) {
439ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly		buffer[0] = 0x01;
440ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly
441ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly		len = buffer[3];
442ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly
443ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly		read(hcdfile_fd, &buffer[4], len);
444ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly
445ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly		hci_send_cmd(buffer, len + 4);
446ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly
447ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly		read_event(uart_fd, buffer);
448ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	}
449ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly
450ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	proc_reset();
451ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly}
452ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly
453ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pellyvoid
454ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pellyproc_baudrate()
455ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly{
456ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	hci_send_cmd(hci_update_baud_rate, sizeof(hci_update_baud_rate));
457ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly
458ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	read_event(uart_fd, buffer);
459ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly
460ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	cfsetospeed(&termios, termios_baudrate);
461ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	cfsetispeed(&termios, termios_baudrate);
462ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	tcsetattr(uart_fd, TCSANOW, &termios);
463ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly
464ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	if (debug) {
465ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly		fprintf(stderr, "Done setting baudrate\n");
466ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	}
467ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly}
468ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly
469ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pellyvoid
470ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pellyproc_bdaddr()
471ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly{
472ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	hci_send_cmd(hci_write_bd_addr, sizeof(hci_write_bd_addr));
473ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly
474ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	read_event(uart_fd, buffer);
475ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly}
476ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly
477ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pellyvoid
478ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pellyproc_enable_lpm()
479ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly{
480ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	hci_send_cmd(hci_write_sleep_mode, sizeof(hci_write_sleep_mode));
481ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly
482ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	read_event(uart_fd, buffer);
483ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly}
484ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly
485ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pellyvoid
486ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pellyproc_enable_hci()
487ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly{
488ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	int i = N_HCI;
489ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	int proto = HCI_UART_H4;
490ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	if (enable_lpm) {
491ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly		proto = HCI_UART_LL;
492ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	}
493ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	if (ioctl(uart_fd, TIOCSETD, &i) < 0) {
494ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly		fprintf(stderr, "Can't set line discipline\n");
495ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly		return;
496ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	}
497ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly
498ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	if (ioctl(uart_fd, HCIUARTSETPROTO, proto) < 0) {
499ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly		fprintf(stderr, "Can't set hci protocol\n");
500ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly		return;
501ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	}
502ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	fprintf(stderr, "Done setting line discpline\n");
503ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	return;
504ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly}
505ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly
506db5ccf71519a49fbb36b915dba551aa0b3fa0db8Nick Pellyvoid
507db5ccf71519a49fbb36b915dba551aa0b3fa0db8Nick Pellyread_default_bdaddr()
508db5ccf71519a49fbb36b915dba551aa0b3fa0db8Nick Pelly{
509db5ccf71519a49fbb36b915dba551aa0b3fa0db8Nick Pelly	int sz;
510db5ccf71519a49fbb36b915dba551aa0b3fa0db8Nick Pelly	int fd;
511db5ccf71519a49fbb36b915dba551aa0b3fa0db8Nick Pelly	char path[PROPERTY_VALUE_MAX];
512db5ccf71519a49fbb36b915dba551aa0b3fa0db8Nick Pelly	char bdaddr[18];
513db5ccf71519a49fbb36b915dba551aa0b3fa0db8Nick Pelly
514db5ccf71519a49fbb36b915dba551aa0b3fa0db8Nick Pelly	property_get("ro.bt.bdaddr_path", path, "");
515db5ccf71519a49fbb36b915dba551aa0b3fa0db8Nick Pelly	if (path[0] == 0)
516db5ccf71519a49fbb36b915dba551aa0b3fa0db8Nick Pelly		return;
517db5ccf71519a49fbb36b915dba551aa0b3fa0db8Nick Pelly
518db5ccf71519a49fbb36b915dba551aa0b3fa0db8Nick Pelly	fd = open(path, O_RDONLY);
519db5ccf71519a49fbb36b915dba551aa0b3fa0db8Nick Pelly	if (fd < 0) {
520db5ccf71519a49fbb36b915dba551aa0b3fa0db8Nick Pelly		fprintf(stderr, "open(%s) failed: %s (%d)", path, strerror(errno),
521db5ccf71519a49fbb36b915dba551aa0b3fa0db8Nick Pelly				errno);
522db5ccf71519a49fbb36b915dba551aa0b3fa0db8Nick Pelly		return;
523db5ccf71519a49fbb36b915dba551aa0b3fa0db8Nick Pelly	}
524db5ccf71519a49fbb36b915dba551aa0b3fa0db8Nick Pelly
525db5ccf71519a49fbb36b915dba551aa0b3fa0db8Nick Pelly	sz = read(fd, bdaddr, sizeof(bdaddr));
526db5ccf71519a49fbb36b915dba551aa0b3fa0db8Nick Pelly	if (sz < 0) {
527db5ccf71519a49fbb36b915dba551aa0b3fa0db8Nick Pelly		fprintf(stderr, "read(%s) failed: %s (%d)", path, strerror(errno),
528db5ccf71519a49fbb36b915dba551aa0b3fa0db8Nick Pelly				errno);
529db5ccf71519a49fbb36b915dba551aa0b3fa0db8Nick Pelly		close(fd);
530db5ccf71519a49fbb36b915dba551aa0b3fa0db8Nick Pelly		return;
531db5ccf71519a49fbb36b915dba551aa0b3fa0db8Nick Pelly	} else if (sz != sizeof(bdaddr)) {
532db5ccf71519a49fbb36b915dba551aa0b3fa0db8Nick Pelly		fprintf(stderr, "read(%s) unexpected size %d", path, sz);
533db5ccf71519a49fbb36b915dba551aa0b3fa0db8Nick Pelly		close(fd);
534db5ccf71519a49fbb36b915dba551aa0b3fa0db8Nick Pelly		return;
535db5ccf71519a49fbb36b915dba551aa0b3fa0db8Nick Pelly	}
536db5ccf71519a49fbb36b915dba551aa0b3fa0db8Nick Pelly
537db5ccf71519a49fbb36b915dba551aa0b3fa0db8Nick Pelly	printf("Read default bdaddr of %s\n", bdaddr);
538db5ccf71519a49fbb36b915dba551aa0b3fa0db8Nick Pelly	parse_bdaddr(bdaddr);
539db5ccf71519a49fbb36b915dba551aa0b3fa0db8Nick Pelly}
540db5ccf71519a49fbb36b915dba551aa0b3fa0db8Nick Pelly
541ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pellyint
542ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pellymain (int argc, char **argv)
543ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly{
544db5ccf71519a49fbb36b915dba551aa0b3fa0db8Nick Pelly	read_default_bdaddr();
545db5ccf71519a49fbb36b915dba551aa0b3fa0db8Nick Pelly
546ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	parse_cmd_line(argc, argv);
547ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly
548ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	if (uart_fd < 0) {
549ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly		exit(1);
550ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	}
551ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly
552ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	init_uart();
553ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly
554ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	proc_reset();
555ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly
556ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	if (hcdfile_fd > 0) {
557ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly		proc_patchram();
558ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	}
559ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly
560ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	if (termios_baudrate) {
561ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly		proc_baudrate();
562ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	}
563ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly
564ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	if (bdaddr_flag) {
565ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly		proc_bdaddr();
566ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	}
567ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly
568ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	if (enable_lpm) {
569ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly		proc_enable_lpm();
570ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	}
571ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly
572ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	if (enable_hci) {
573d4397861e745c5b6ae99fe547b841df9babf3085Nick Pelly		proc_enable_hci();
574ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly		while (1) {
575ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly			sleep(UINT_MAX);
576ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly		}
577ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	}
578ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly
579ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly	exit(0);
580ac8c432d8eea5f875f672c2a7755c40a76a3c8cdNick Pelly}
581