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