brcm_patchram_plus.c revision fd8ee4744176894d5a8ee28645fa342b859f4893
1/*******************************************************************************
2 *
3 *  Copyright (C) 2009-2011 Broadcom Corporation
4 *
5 *  Licensed under the Apache License, Version 2.0 (the "License");
6 *  you may not use this file except in compliance with the License.
7 *  You may obtain a copy of the License at
8 *
9 *      http://www.apache.org/licenses/LICENSE-2.0
10 *
11 *  Unless required by applicable law or agreed to in writing, software
12 *  distributed under the License is distributed on an "AS IS" BASIS,
13 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 *  See the License for the specific language governing permissions and
15 *  limitations under the License.
16 *
17 ******************************************************************************/
18
19/*****************************************************************************
20**
21**  Name:          brcm_patchram_plus.c
22**
23**  Description:   This program downloads a patchram files in the HCD format
24**                 to Broadcom Bluetooth based silicon and combo chips and
25**				   and other utility functions.
26**
27**                 It can be invoked from the command line in the form
28**						<-d> to print a debug log
29**						<--patchram patchram_file>
30**						<--baudrate baud_rate>
31**						<--bd_addr bd_address>
32**						<--enable_lpm>
33**						<--enable_hci>
34**                                              <--pcm_role master|slave>
35**						<--use_baudrate_for_download>
36**						uart_device_name
37**
38**                 For example:
39**
40**                 brcm_patchram_plus -d --patchram  \
41**						BCM2045B2_002.002.011.0348.0349.hcd /dev/ttyHS0
42**
43**                 It will return 0 for success and a number greater than 0
44**                 for any errors.
45**
46**                 For Android, this program invoked using a
47**                 "system(2)" call from the beginning of the bt_enable
48**                 function inside the file
49**                 system/bluetooth/bluedroid/bluetooth.c.
50**
51**                 If the Android system property "ro.bt.bcm_bdaddr_path" is
52**                 set, then the bd_addr will be read from this path.
53**                 This is overridden by --bd_addr on the command line.
54**
55******************************************************************************/
56
57// TODO: Integrate BCM support into Bluez hciattach
58
59#include <stdio.h>
60#include <getopt.h>
61#include <errno.h>
62
63#include <sys/types.h>
64#include <sys/stat.h>
65#include <fcntl.h>
66
67#include <stdlib.h>
68
69#ifdef ANDROID
70#include <termios.h>
71#else
72#include <sys/termios.h>
73#endif
74
75#include <string.h>
76#include <signal.h>
77
78#include <cutils/properties.h>
79
80#ifdef ANDROID
81#define LOG_TAG "brcm_patchram_plus"
82#include <cutils/log.h>
83#undef printf
84#define printf LOGD
85#undef fprintf
86#define fprintf(x, ...) \
87  { if(x==stderr) LOGE(__VA_ARGS__); else fprintf(x, __VA_ARGS__); }
88
89#endif //ANDROID
90
91#ifndef N_HCI
92#define N_HCI	15
93#endif
94
95#define HCIUARTSETPROTO		_IOW('U', 200, int)
96#define HCIUARTGETPROTO		_IOR('U', 201, int)
97#define HCIUARTGETDEVICE	_IOR('U', 202, int)
98
99#define HCI_UART_H4		0
100#define HCI_UART_BCSP	1
101#define HCI_UART_3WIRE	2
102#define HCI_UART_H4DS	3
103#define HCI_UART_LL		4
104
105
106int uart_fd = -1;
107int hcdfile_fd = -1;
108int termios_baudrate = 0;
109int bdaddr_flag = 0;
110int enable_lpm = 0;
111int enable_hci = 0;
112int pcm_slave = 0;
113int pcm_master = 0;
114int use_baudrate_for_download = 0;
115int debug = 0;
116
117struct termios termios;
118unsigned char buffer[1024];
119
120unsigned char hci_reset[] = { 0x01, 0x03, 0x0c, 0x00 };
121
122unsigned char hci_download_minidriver[] = { 0x01, 0x2e, 0xfc, 0x00 };
123
124unsigned char hci_update_baud_rate[] = { 0x01, 0x18, 0xfc, 0x06, 0x00, 0x00,
125	0x00, 0x00, 0x00, 0x00 };
126
127unsigned char hci_write_bd_addr[] = { 0x01, 0x01, 0xfc, 0x06,
128	0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
129
130unsigned char hci_write_sleep_mode[] = { 0x01, 0x27, 0xfc, 0x0c,
131	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00,
132	0x00, 0x00 };
133
134// HCI_COMMAND_PKT = 0x01
135// unpacked ogf/ocf: 0x3F 0x1C
136// ... ((ocf & 0x03ff)|(ogf << 10)) => 0xFC1C (0x1C 0xFC)
137// packet data len: 0x5
138// Data for the Write_SCO_PCM_Int_Param Message:
139// 00 (Use PCM)
140// 0x (02== 512 KHz bit clock, 03==1024 KHz bit clock, 04==2048 KHz)
141// 01 (Long FS)
142// 00 (Slave frame sync)
143// 00 (Slave bit clock)
144unsigned char hci_write_pcm_slave_mode[] =
145	{ 0x01, 0x1C, 0xFC, 0x05, 0x00, 0x02, 0x00, 0x00, 0x00 };
146unsigned char hci_write_pcm_master_mode[] =
147	{ 0x01, 0x1C, 0xFC, 0x05, 0x00, 0x02, 0x00, 0x01, 0x01 };
148
149int
150parse_patchram(char *optarg)
151{
152	char *p;
153
154	if (!(p = strrchr(optarg, '.'))) {
155		fprintf(stderr, "file %s not an HCD file\n", optarg);
156		exit(3);
157	}
158
159	p++;
160
161	if (strcasecmp("hcd", p) != 0) {
162		fprintf(stderr, "file %s not an HCD file\n", optarg);
163		exit(4);
164	}
165
166	if ((hcdfile_fd = open(optarg, O_RDONLY)) == -1) {
167		fprintf(stderr, "file %s could not be opened, error %d\n", optarg, errno);
168		exit(5);
169	}
170
171	return(0);
172}
173
174void
175BRCM_encode_baud_rate(uint baud_rate, unsigned char *encoded_baud)
176{
177	if(baud_rate == 0 || encoded_baud == NULL) {
178		fprintf(stderr, "Baudrate not supported!");
179		return;
180	}
181
182	encoded_baud[3] = (unsigned char)(baud_rate >> 24);
183	encoded_baud[2] = (unsigned char)(baud_rate >> 16);
184	encoded_baud[1] = (unsigned char)(baud_rate >> 8);
185	encoded_baud[0] = (unsigned char)(baud_rate & 0xFF);
186}
187
188typedef struct {
189	int baud_rate;
190	int termios_value;
191} tBaudRates;
192
193tBaudRates baud_rates[] = {
194	{ 115200, B115200 },
195	{ 230400, B230400 },
196	{ 460800, B460800 },
197	{ 500000, B500000 },
198	{ 576000, B576000 },
199	{ 921600, B921600 },
200	{ 1000000, B1000000 },
201	{ 1152000, B1152000 },
202	{ 1500000, B1500000 },
203	{ 2000000, B2000000 },
204	{ 2500000, B2500000 },
205	{ 3000000, B3000000 },
206#ifndef __CYGWIN__
207	{ 3500000, B3500000 },
208	{ 4000000, B4000000 }
209#endif
210};
211
212int
213validate_baudrate(int baud_rate, int *value)
214{
215	unsigned int i;
216
217	for (i = 0; i < (sizeof(baud_rates) / sizeof(tBaudRates)); i++) {
218		if (baud_rates[i].baud_rate == baud_rate) {
219			*value = baud_rates[i].termios_value;
220			return(1);
221		}
222	}
223
224	return(0);
225}
226
227int
228parse_baudrate(char *optarg)
229{
230	int baudrate = atoi(optarg);
231
232	if (validate_baudrate(baudrate, &termios_baudrate)) {
233		BRCM_encode_baud_rate(baudrate, &hci_update_baud_rate[6]);
234	}
235
236	return(0);
237}
238
239int
240parse_bdaddr(char *optarg)
241{
242	int bd_addr[6];
243	int i;
244
245	sscanf(optarg, "%02X:%02X:%02X:%02X:%02X:%02X",
246		&bd_addr[5], &bd_addr[4], &bd_addr[3],
247		&bd_addr[2], &bd_addr[1], &bd_addr[0]);
248
249	for (i = 0; i < 6; i++) {
250		hci_write_bd_addr[4 + i] = bd_addr[i];
251	}
252
253	bdaddr_flag = 1;
254
255	return(0);
256}
257
258int
259parse_enable_lpm(char *optarg)
260{
261	enable_lpm = 1;
262	return(0);
263}
264
265int
266parse_use_baudrate_for_download(char *optarg)
267{
268	use_baudrate_for_download = 1;
269	return(0);
270}
271
272int
273parse_enable_hci(char *optarg)
274{
275	enable_hci = 1;
276	return(0);
277}
278
279int
280parse_pcm_role(char *optarg) {
281	if(!strcmp(optarg, "master")) {
282		pcm_master = 1;
283	} else if (!strcmp(optarg, "slave")) {
284		pcm_slave = 1;
285	} else {
286		printf("Unknown PCM Role received: %s\n", optarg);
287	}
288	if (pcm_master && pcm_slave) {
289		fprintf(stderr, "Illegal command line- pcm role master && slave\n");
290		exit(6);
291	}
292	return(0);
293}
294
295int
296parse_cmd_line(int argc, char **argv)
297{
298	int c;
299	int digit_optind = 0;
300
301	typedef int (*PFI)();
302
303	PFI parse_param[] = { parse_patchram, parse_baudrate,
304		parse_bdaddr, parse_enable_lpm, parse_enable_hci,
305		parse_pcm_role, parse_use_baudrate_for_download};
306
307   	while (1)
308    	{
309		int this_option_optind = optind ? optind : 1;
310		int option_index = 0;
311
312		static struct option long_options[] = {
313			{"patchram", 1, 0, 0},
314			{"baudrate", 1, 0, 0},
315			{"bd_addr", 1, 0, 0},
316			{"enable_lpm", 0, 0, 0},
317			{"enable_hci", 0, 0, 0},
318			{"pcm_role", 1, 0, 0},
319			{"use_baudrate_for_download", 0, 0, 0},
320			{0, 0, 0, 0}
321		};
322
323		c = getopt_long_only (argc, argv, "d", long_options,
324				&option_index);
325
326		if (c == -1) {
327			break;
328		}
329
330		switch (c) {
331			case 0:
332				if (debug) {
333					printf ("option %s",
334						long_options[option_index].name);
335					if (optarg)
336						printf (" with arg %s", optarg);
337					printf ("\n");
338				}
339				(*parse_param[option_index])(optarg);
340				break;
341			case 'd':
342				debug = 1;
343				break;
344
345			case '?':
346				//nobreak
347			default:
348				printf("Usage %s:\n", argv[0]);
349				printf("\t<-d> to print a debug log\n");
350				printf("\t<--patchram patchram_file>\n");
351				printf("\t<--baudrate baud_rate>\n");
352				printf("\t<--bd_addr bd_address>\n");
353				printf("\t<--enable_lpm>\n");
354				printf("\t<--enable_hci>\n");
355				printf("\t<--pcm_role slave|master>\n");
356				printf("\t<--use_baudrate_for_download> - Uses the\
357						baudrate for downloading the\
358						firmware\n");
359				printf("\tuart_device_name\n");
360				break;
361		}
362	}
363	if (optind < argc) {
364		if (debug)
365			printf ("%s \n", argv[optind]);
366		if ((uart_fd = open(argv[optind], O_RDWR | O_NOCTTY)) == -1) {
367			fprintf(stderr, "port %s could not be opened, error %d\n",
368					argv[2], errno);
369		}
370	}
371
372	return(0);
373}
374
375void
376init_uart()
377{
378	tcflush(uart_fd, TCIOFLUSH);
379	tcgetattr(uart_fd, &termios);
380
381#ifndef __CYGWIN__
382	cfmakeraw(&termios);
383#else
384	termios.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP
385                | INLCR | IGNCR | ICRNL | IXON);
386	termios.c_oflag &= ~OPOST;
387	termios.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
388	termios.c_cflag &= ~(CSIZE | PARENB);
389	termios.c_cflag |= CS8;
390#endif
391
392	termios.c_cflag |= CRTSCTS;
393	tcsetattr(uart_fd, TCSANOW, &termios);
394	tcflush(uart_fd, TCIOFLUSH);
395	tcsetattr(uart_fd, TCSANOW, &termios);
396	tcflush(uart_fd, TCIOFLUSH);
397	tcflush(uart_fd, TCIOFLUSH);
398	cfsetospeed(&termios, B115200);
399	cfsetispeed(&termios, B115200);
400	tcsetattr(uart_fd, TCSANOW, &termios);
401}
402
403void
404dump(unsigned char *out, int len)
405{
406	int i;
407
408	for (i = 0; i < len; i++) {
409		if (i && !(i % 16)) {
410			fprintf(stderr, "\n");
411		}
412
413		fprintf(stderr, "%02x ", out[i]);
414	}
415
416	fprintf(stderr, "\n");
417}
418
419void
420read_event(int fd, unsigned char *buffer)
421{
422	int i = 0;
423	int len = 3;
424	int count;
425
426	while ((count = read(fd, &buffer[i], len)) < len) {
427		i += count;
428		len -= count;
429	}
430
431	i += count;
432	len = buffer[2];
433
434	while ((count = read(fd, &buffer[i], len)) < len) {
435		i += count;
436		len -= count;
437	}
438
439	if (debug) {
440		count += i;
441
442		fprintf(stderr, "received %d\n", count);
443		dump(buffer, count);
444	}
445}
446
447void
448hci_send_cmd(unsigned char *buf, int len)
449{
450	if (debug) {
451		fprintf(stderr, "writing\n");
452		dump(buf, len);
453	}
454
455	write(uart_fd, buf, len);
456}
457
458void
459expired(int sig)
460{
461	hci_send_cmd(hci_reset, sizeof(hci_reset));
462	alarm(4);
463}
464
465void
466proc_reset()
467{
468	signal(SIGALRM, expired);
469
470
471	hci_send_cmd(hci_reset, sizeof(hci_reset));
472
473	alarm(4);
474
475	read_event(uart_fd, buffer);
476
477	alarm(0);
478}
479
480void
481proc_patchram()
482{
483	int len;
484
485	hci_send_cmd(hci_download_minidriver, sizeof(hci_download_minidriver));
486
487	read_event(uart_fd, buffer);
488
489	read(uart_fd, &buffer[0], 2);
490
491	usleep(50000);
492
493	while (read(hcdfile_fd, &buffer[1], 3)) {
494		buffer[0] = 0x01;
495
496		len = buffer[3];
497
498		read(hcdfile_fd, &buffer[4], len);
499
500		hci_send_cmd(buffer, len + 4);
501
502		read_event(uart_fd, buffer);
503	}
504
505	proc_reset();
506}
507
508void
509proc_baudrate()
510{
511	hci_send_cmd(hci_update_baud_rate, sizeof(hci_update_baud_rate));
512
513	read_event(uart_fd, buffer);
514
515	cfsetospeed(&termios, termios_baudrate);
516	cfsetispeed(&termios, termios_baudrate);
517	tcsetattr(uart_fd, TCSANOW, &termios);
518
519	if (debug) {
520		fprintf(stderr, "Done setting baudrate\n");
521	}
522}
523
524void
525proc_bdaddr()
526{
527	hci_send_cmd(hci_write_bd_addr, sizeof(hci_write_bd_addr));
528
529	read_event(uart_fd, buffer);
530}
531
532void
533proc_enable_lpm()
534{
535	hci_send_cmd(hci_write_sleep_mode, sizeof(hci_write_sleep_mode));
536
537	read_event(uart_fd, buffer);
538}
539
540void
541proc_pcm_slave()
542{
543	if (debug)
544		printf("Configuring PCM Interface as slave.\n");
545	hci_send_cmd(hci_write_pcm_slave_mode, sizeof(hci_write_pcm_slave_mode));
546}
547
548void
549proc_pcm_master()
550{
551	if (debug)
552		printf("Configuring PCM Interface as master.\n");
553	hci_send_cmd(hci_write_pcm_master_mode, sizeof(hci_write_pcm_master_mode));
554}
555
556void
557proc_enable_hci()
558{
559	int i = N_HCI;
560	int proto = HCI_UART_H4;
561	if (ioctl(uart_fd, TIOCSETD, &i) < 0) {
562		fprintf(stderr, "Can't set line discipline\n");
563		return;
564	}
565
566	if (ioctl(uart_fd, HCIUARTSETPROTO, proto) < 0) {
567		fprintf(stderr, "Can't set hci protocol\n");
568		return;
569	}
570	fprintf(stderr, "Done setting line discpline\n");
571	return;
572}
573
574void
575read_default_bdaddr()
576{
577	int sz;
578	int fd;
579	char path[PROPERTY_VALUE_MAX];
580	char bdaddr[18];
581	int len = 17;
582	memset(bdaddr, 0, (len + 1) * sizeof(char));
583
584	property_get("ro.bt.bdaddr_path", path, "");
585	if (path[0] == 0)
586		return;
587
588	fd = open(path, O_RDONLY);
589	if (fd < 0) {
590		fprintf(stderr, "open(%s) failed: %s (%d)", path, strerror(errno),
591				errno);
592		return;
593	}
594
595	sz = read(fd, bdaddr, len);
596	if (sz < 0) {
597		fprintf(stderr, "read(%s) failed: %s (%d)", path, strerror(errno),
598				errno);
599		close(fd);
600		return;
601	} else if (sz != len) {
602		fprintf(stderr, "read(%s) unexpected size %d", path, sz);
603		close(fd);
604		return;
605	}
606
607	if (debug)
608		printf("Read default bdaddr of %s\n", bdaddr);
609	parse_bdaddr(bdaddr);
610}
611
612int
613main (int argc, char **argv)
614{
615	read_default_bdaddr();
616
617	parse_cmd_line(argc, argv);
618
619	if (uart_fd < 0) {
620		exit(1);
621	}
622
623	init_uart();
624
625	proc_reset();
626
627	if (use_baudrate_for_download) {
628		if (termios_baudrate) {
629			proc_baudrate();
630		}
631
632		if (hcdfile_fd > 0) {
633			proc_patchram();
634		}
635	} else {
636		if (hcdfile_fd > 0) {
637			proc_patchram();
638		}
639
640		if (termios_baudrate) {
641			proc_baudrate();
642		}
643	}
644
645	if (bdaddr_flag) {
646		proc_bdaddr();
647	}
648
649	if (enable_lpm) {
650		proc_enable_lpm();
651	}
652
653	if (pcm_slave) {
654		proc_pcm_slave();
655	} else if (pcm_master) {
656		proc_pcm_master();
657	}
658
659	if (enable_hci) {
660		proc_enable_hci();
661		while (1) {
662			sleep(UINT_MAX);
663		}
664	}
665
666	exit(0);
667}
668