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