brcm_patchram_plus.c revision 3a0f5331b257c95a69b077bd7ec8b5fdf5aeaa9e
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** mydroid/system/bluetooth/bluedroid/bluetooth.c. 49** 50** 51******************************************************************************/ 52 53// TODO: Integrate BCM support into Bluez hciattach 54 55#include <stdio.h> 56#include <getopt.h> 57#include <errno.h> 58 59#include <sys/types.h> 60#include <sys/stat.h> 61#include <fcntl.h> 62 63#include <stdlib.h> 64 65#ifdef ANDROID 66#include <termios.h> 67#else 68#include <sys/termios.h> 69#endif 70 71#include <string.h> 72#include <signal.h> 73 74#ifndef N_HCI 75#define N_HCI 15 76#endif 77 78#define HCIUARTSETPROTO _IOW('U', 200, int) 79#define HCIUARTGETPROTO _IOR('U', 201, int) 80#define HCIUARTGETDEVICE _IOR('U', 202, int) 81 82#define HCI_UART_H4 0 83#define HCI_UART_BCSP 1 84#define HCI_UART_3WIRE 2 85#define HCI_UART_H4DS 3 86#define HCI_UART_LL 4 87 88 89int uart_fd = -1; 90int hcdfile_fd = -1; 91int termios_baudrate = 0; 92int bdaddr_flag = 0; 93int enable_lpm = 0; 94int enable_hci = 0; 95int debug = 0; 96 97struct termios termios; 98unsigned char buffer[1024]; 99 100unsigned char hci_reset[] = { 0x01, 0x03, 0x0c, 0x00 }; 101 102unsigned char hci_download_minidriver[] = { 0x01, 0x2e, 0xfc, 0x00 }; 103 104unsigned char hci_update_baud_rate[] = { 0x01, 0x18, 0xfc, 0x06, 0x00, 0x00, 105 0x00, 0x00, 0x00, 0x00 }; 106 107unsigned char hci_write_bd_addr[] = { 0x01, 0x01, 0xfc, 0x06, 108 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 109 0x00 }; 110 111unsigned char hci_write_sleep_mode[] = { 0x01, 0x27, 0xfc, 0x0c, 112 0x01, 0x01, 0x01, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 113 0x00, 0x00 }; 114 115int 116parse_patchram(char *optarg) 117{ 118 char *p; 119 120 if (!(p = strrchr(optarg, '.'))) { 121 fprintf(stderr, "file %s not an HCD file\n", optarg); 122 exit(3); 123 } 124 125 p++; 126 127 if (strcasecmp("hcd", p) != 0) { 128 fprintf(stderr, "file %s not an HCD file\n", optarg); 129 exit(4); 130 } 131 132 if ((hcdfile_fd = open(optarg, O_RDONLY)) == -1) { 133 fprintf(stderr, "file %s could not be opened, error %d\n", optarg, errno); 134 exit(5); 135 } 136 137 return(0); 138} 139 140void 141BRCM_encode_baud_rate(uint baud_rate, unsigned char *encoded_baud) 142{ 143 if(baud_rate == 0 || encoded_baud == NULL) { 144 fprintf(stderr, "Baudrate not supported!"); 145 return; 146 } 147 148 encoded_baud[3] = (unsigned char)(baud_rate >> 24); 149 encoded_baud[2] = (unsigned char)(baud_rate >> 16); 150 encoded_baud[1] = (unsigned char)(baud_rate >> 8); 151 encoded_baud[0] = (unsigned char)(baud_rate & 0xFF); 152} 153 154typedef struct { 155 int baud_rate; 156 int termios_value; 157} tBaudRates; 158 159tBaudRates baud_rates[] = { 160 { 115200, B115200 }, 161 { 230400, B230400 }, 162 { 460800, B460800 }, 163 { 500000, B500000 }, 164 { 576000, B576000 }, 165 { 921600, B921600 }, 166 { 1000000, B1000000 }, 167 { 1152000, B1152000 }, 168 { 1500000, B1500000 }, 169 { 2000000, B2000000 }, 170 { 2500000, B2500000 }, 171 { 3000000, B3000000 }, 172#ifndef __CYGWIN__ 173 { 3500000, B3500000 }, 174 { 4000000, B4000000 } 175#endif 176}; 177 178int 179validate_baudrate(int baud_rate, int *value) 180{ 181 unsigned int i; 182 183 for (i = 0; i < (sizeof(baud_rates) / sizeof(tBaudRates)); i++) { 184 if (baud_rates[i].baud_rate == baud_rate) { 185 *value = baud_rates[i].termios_value; 186 return(1); 187 } 188 } 189 190 return(0); 191} 192 193int 194parse_baudrate(char *optarg) 195{ 196 int baudrate = atoi(optarg); 197 198 if (validate_baudrate(baudrate, &termios_baudrate)) { 199 BRCM_encode_baud_rate(baudrate, &hci_update_baud_rate[6]); 200 } 201 202 return(0); 203} 204 205int 206parse_bdaddr(char *optarg) 207{ 208 int bd_addr[6]; 209 int i; 210 211 sscanf(optarg, "%02x%02x%02x%02x%02x%02x", 212 &bd_addr[0], &bd_addr[1], &bd_addr[2], 213 &bd_addr[3], &bd_addr[4], &bd_addr[5]); 214 215 for (i = 0; i < 6; i++) { 216 hci_write_bd_addr[4 + i] = bd_addr[i]; 217 } 218 219 bdaddr_flag = 1; 220 221 return(0); 222} 223 224int 225parse_enable_lpm(char *optarg) 226{ 227 enable_lpm = 1; 228 return(0); 229} 230 231int 232parse_enable_hci(char *optarg) 233{ 234 enable_hci = 1; 235 return(0); 236} 237 238int 239parse_cmd_line(int argc, char **argv) 240{ 241 int c; 242 int digit_optind = 0; 243 244 typedef int (*PFI)(); 245 246 PFI parse_param[] = { parse_patchram, parse_baudrate, 247 parse_bdaddr, parse_enable_lpm, parse_enable_hci }; 248 249 while (1) 250 { 251 int this_option_optind = optind ? optind : 1; 252 int option_index = 0; 253 254 static struct option long_options[] = { 255 {"patchram", 1, 0, 0}, 256 {"baudrate", 1, 0, 0}, 257 {"bd_addr", 1, 0, 0}, 258 {"enable_lpm", 0, 0, 0}, 259 {"enable_hci", 0, 0, 0}, 260 {0, 0, 0, 0} 261 }; 262 263 c = getopt_long_only (argc, argv, "d", long_options, &option_index); 264 265 if (c == -1) { 266 break; 267 } 268 269 switch (c) { 270 case 0: 271 printf ("option %s", long_options[option_index].name); 272 273 if (optarg) { 274 printf (" with arg %s", optarg); 275 } 276 277 printf ("\n"); 278 279 (*parse_param[option_index])(optarg); 280 break; 281 282 case 'd': 283 debug = 1; 284 break; 285 286 case '?': 287 //nobreak 288 default: 289 290 printf("Usage %s:\n", argv[0]); 291 printf("\t<-d> to print a debug log\n"); 292 printf("\t<--patchram patchram_file>\n"); 293 printf("\t<--baudrate baud_rate>\n"); 294 printf("\t<--bd_addr bd_address>\n"); 295 printf("\t<--enable_lpm\n"); 296 printf("\t<--enable_hci\n"); 297 printf("\tuart_device_name\n"); 298 break; 299 300 } 301 } 302 303 if (optind < argc) { 304 if (optind < argc) { 305 printf ("%s ", argv[optind]); 306 307 if ((uart_fd = open(argv[optind], O_RDWR | O_NOCTTY)) == -1) { 308 fprintf(stderr, "port %s could not be opened, error %d\n", argv[2], errno); 309 } 310 } 311 312 printf ("\n"); 313 } 314 315 return(0); 316} 317 318void 319init_uart() 320{ 321 tcflush(uart_fd, TCIOFLUSH); 322 tcgetattr(uart_fd, &termios); 323 324#ifndef __CYGWIN__ 325 cfmakeraw(&termios); 326#else 327 termios.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP 328 | INLCR | IGNCR | ICRNL | IXON); 329 termios.c_oflag &= ~OPOST; 330 termios.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN); 331 termios.c_cflag &= ~(CSIZE | PARENB); 332 termios.c_cflag |= CS8; 333#endif 334 335 termios.c_cflag |= CRTSCTS; 336 tcsetattr(uart_fd, TCSANOW, &termios); 337 tcflush(uart_fd, TCIOFLUSH); 338 tcsetattr(uart_fd, TCSANOW, &termios); 339 tcflush(uart_fd, TCIOFLUSH); 340 tcflush(uart_fd, TCIOFLUSH); 341 cfsetospeed(&termios, B115200); 342 cfsetispeed(&termios, B115200); 343 tcsetattr(uart_fd, TCSANOW, &termios); 344} 345 346void 347dump(unsigned char *out, int len) 348{ 349 int i; 350 351 for (i = 0; i < len; i++) { 352 if (i && !(i % 16)) { 353 fprintf(stderr, "\n"); 354 } 355 356 fprintf(stderr, "%02x ", out[i]); 357 } 358 359 fprintf(stderr, "\n"); 360} 361 362void 363read_event(int fd, unsigned char *buffer) 364{ 365 int i = 0; 366 int len = 3; 367 int count; 368 369 while ((count = read(fd, &buffer[i], len)) < len) { 370 i += count; 371 len -= count; 372 } 373 374 i += count; 375 len = buffer[2]; 376 377 while ((count = read(fd, &buffer[i], len)) < len) { 378 i += count; 379 len -= count; 380 } 381 382 if (debug) { 383 count += i; 384 385 fprintf(stderr, "received %d\n", count); 386 dump(buffer, count); 387 } 388} 389 390void 391hci_send_cmd(unsigned char *buf, int len) 392{ 393 if (debug) { 394 fprintf(stderr, "writing\n"); 395 dump(buf, len); 396 } 397 398 write(uart_fd, buf, len); 399} 400 401void 402expired(int sig) 403{ 404 hci_send_cmd(hci_reset, sizeof(hci_reset)); 405 alarm(4); 406} 407 408void 409proc_reset() 410{ 411 signal(SIGALRM, expired); 412 413 414 hci_send_cmd(hci_reset, sizeof(hci_reset)); 415 416 alarm(4); 417 418 read_event(uart_fd, buffer); 419 420 alarm(0); 421} 422 423void 424proc_patchram() 425{ 426 int len; 427 428 hci_send_cmd(hci_download_minidriver, sizeof(hci_download_minidriver)); 429 430 read_event(uart_fd, buffer); 431 432 read(uart_fd, &buffer[0], 2); 433 434 while (read(hcdfile_fd, &buffer[1], 3)) { 435 buffer[0] = 0x01; 436 437 len = buffer[3]; 438 439 read(hcdfile_fd, &buffer[4], len); 440 441 hci_send_cmd(buffer, len + 4); 442 443 read_event(uart_fd, buffer); 444 } 445 446 proc_reset(); 447} 448 449void 450proc_baudrate() 451{ 452 hci_send_cmd(hci_update_baud_rate, sizeof(hci_update_baud_rate)); 453 454 read_event(uart_fd, buffer); 455 456 cfsetospeed(&termios, termios_baudrate); 457 cfsetispeed(&termios, termios_baudrate); 458 tcsetattr(uart_fd, TCSANOW, &termios); 459 460 if (debug) { 461 fprintf(stderr, "Done setting baudrate\n"); 462 } 463} 464 465void 466proc_bdaddr() 467{ 468 hci_send_cmd(hci_write_bd_addr, sizeof(hci_write_bd_addr)); 469 470 read_event(uart_fd, buffer); 471} 472 473void 474proc_enable_lpm() 475{ 476 hci_send_cmd(hci_write_sleep_mode, sizeof(hci_write_sleep_mode)); 477 478 read_event(uart_fd, buffer); 479} 480 481void 482proc_enable_hci() 483{ 484 int i = N_HCI; 485 int proto = HCI_UART_H4; 486 if (enable_lpm) { 487 proto = HCI_UART_LL; 488 } 489 if (ioctl(uart_fd, TIOCSETD, &i) < 0) { 490 fprintf(stderr, "Can't set line discipline\n"); 491 return; 492 } 493 494 if (ioctl(uart_fd, HCIUARTSETPROTO, proto) < 0) { 495 fprintf(stderr, "Can't set hci protocol\n"); 496 return; 497 } 498 fprintf(stderr, "Done setting line discpline\n"); 499 return; 500} 501 502int 503main (int argc, char **argv) 504{ 505 parse_cmd_line(argc, argv); 506 507 if (uart_fd < 0) { 508 exit(1); 509 } 510 511 init_uart(); 512 513 proc_reset(); 514 515 if (hcdfile_fd > 0) { 516 proc_patchram(); 517 } 518 519 if (termios_baudrate) { 520 proc_baudrate(); 521 } 522 523 if (bdaddr_flag) { 524 proc_bdaddr(); 525 } 526 527 if (enable_hci) { 528 proc_enable_hci(); 529 } 530 531 if (enable_lpm) { 532 proc_enable_lpm(); 533 } 534 535 if (enable_hci) { 536 while (1) { 537 sleep(UINT_MAX); 538 } 539 } 540 541 exit(0); 542} 543