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