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 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 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 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 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 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 229 parse_enable_lpm(char *optarg) 230 { 231 enable_lpm = 1; 232 return(0); 233 } 234 235 int 236 parse_enable_hci(char *optarg) 237 { 238 enable_hci = 1; 239 return(0); 240 } 241 242 int 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 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 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 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 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 406 expired(int sig) 407 { 408 hci_send_cmd(hci_reset, sizeof(hci_reset)); 409 alarm(4); 410 } 411 412 void 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 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 usleep(50000); 439 440 while (read(hcdfile_fd, &buffer[1], 3)) { 441 buffer[0] = 0x01; 442 443 len = buffer[3]; 444 445 read(hcdfile_fd, &buffer[4], len); 446 447 hci_send_cmd(buffer, len + 4); 448 449 read_event(uart_fd, buffer); 450 } 451 452 proc_reset(); 453 } 454 455 void 456 proc_baudrate() 457 { 458 hci_send_cmd(hci_update_baud_rate, sizeof(hci_update_baud_rate)); 459 460 read_event(uart_fd, buffer); 461 462 cfsetospeed(&termios, termios_baudrate); 463 cfsetispeed(&termios, termios_baudrate); 464 tcsetattr(uart_fd, TCSANOW, &termios); 465 466 if (debug) { 467 fprintf(stderr, "Done setting baudrate\n"); 468 } 469 } 470 471 void 472 proc_bdaddr() 473 { 474 hci_send_cmd(hci_write_bd_addr, sizeof(hci_write_bd_addr)); 475 476 read_event(uart_fd, buffer); 477 } 478 479 void 480 proc_enable_lpm() 481 { 482 hci_send_cmd(hci_write_sleep_mode, sizeof(hci_write_sleep_mode)); 483 484 read_event(uart_fd, buffer); 485 } 486 487 void 488 proc_enable_hci() 489 { 490 int i = N_HCI; 491 int proto = HCI_UART_H4; 492 if (ioctl(uart_fd, TIOCSETD, &i) < 0) { 493 fprintf(stderr, "Can't set line discipline\n"); 494 return; 495 } 496 497 if (ioctl(uart_fd, HCIUARTSETPROTO, proto) < 0) { 498 fprintf(stderr, "Can't set hci protocol\n"); 499 return; 500 } 501 fprintf(stderr, "Done setting line discpline\n"); 502 return; 503 } 504 505 void 506 read_default_bdaddr() 507 { 508 int sz; 509 int fd; 510 char path[PROPERTY_VALUE_MAX]; 511 char bdaddr[18]; 512 513 property_get("ro.bt.bdaddr_path", path, ""); 514 if (path[0] == 0) 515 return; 516 517 fd = open(path, O_RDONLY); 518 if (fd < 0) { 519 fprintf(stderr, "open(%s) failed: %s (%d)", path, strerror(errno), 520 errno); 521 return; 522 } 523 524 sz = read(fd, bdaddr, sizeof(bdaddr)); 525 if (sz < 0) { 526 fprintf(stderr, "read(%s) failed: %s (%d)", path, strerror(errno), 527 errno); 528 close(fd); 529 return; 530 } else if (sz != sizeof(bdaddr)) { 531 fprintf(stderr, "read(%s) unexpected size %d", path, sz); 532 close(fd); 533 return; 534 } 535 536 printf("Read default bdaddr of %s\n", bdaddr); 537 parse_bdaddr(bdaddr); 538 } 539 540 int 541 main (int argc, char **argv) 542 { 543 read_default_bdaddr(); 544 545 parse_cmd_line(argc, argv); 546 547 if (uart_fd < 0) { 548 exit(1); 549 } 550 551 init_uart(); 552 553 proc_reset(); 554 555 if (hcdfile_fd > 0) { 556 proc_patchram(); 557 } 558 559 if (termios_baudrate) { 560 proc_baudrate(); 561 } 562 563 if (bdaddr_flag) { 564 proc_bdaddr(); 565 } 566 567 if (enable_lpm) { 568 proc_enable_lpm(); 569 } 570 571 if (enable_hci) { 572 proc_enable_hci(); 573 while (1) { 574 sleep(UINT_MAX); 575 } 576 } 577 578 exit(0); 579 } 580