PageRenderTime 22ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/brcm_patchram_plus/brcm_patchram_plus.c

https://github.com/MIPS/system-bluetooth
C | 582 lines | 407 code | 121 blank | 54 comment | 49 complexity | f3614357665325baaba74affe2b01ae2 MD5 | raw file
  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. ** Name: brcm_patchram_plus.c
  21. **
  22. ** Description: This program downloads a patchram files in the HCD format
  23. ** to Broadcom Bluetooth based silicon and combo chips and
  24. ** and other utility functions.
  25. **
  26. ** It can be invoked from the command line in the form
  27. ** <-d> to print a debug log
  28. ** <--patchram patchram_file>
  29. ** <--baudrate baud_rate>
  30. ** <--bd_addr bd_address>
  31. ** <--enable_lpm>
  32. ** <--enable_hci>
  33. ** uart_device_name
  34. **
  35. ** For example:
  36. **
  37. ** brcm_patchram_plus -d --patchram \
  38. ** BCM2045B2_002.002.011.0348.0349.hcd /dev/ttyHS0
  39. **
  40. ** It will return 0 for success and a number greater than 0
  41. ** for any errors.
  42. **
  43. ** For Android, this program invoked using a
  44. ** "system(2)" call from the beginning of the bt_enable
  45. ** function inside the file
  46. ** system/bluetooth/bluedroid/bluetooth.c.
  47. **
  48. ** If the Android system property "ro.bt.bcm_bdaddr_path" is
  49. ** set, then the bd_addr will be read from this path.
  50. ** This is overridden by --bd_addr on the command line.
  51. **
  52. ******************************************************************************/
  53. // TODO: Integrate BCM support into Bluez hciattach
  54. #include <stdio.h>
  55. #include <getopt.h>
  56. #include <errno.h>
  57. #include <sys/types.h>
  58. #include <sys/stat.h>
  59. #include <fcntl.h>
  60. #include <stdlib.h>
  61. #ifdef ANDROID
  62. #include <termios.h>
  63. #else
  64. #include <sys/termios.h>
  65. #endif
  66. #include <string.h>
  67. #include <signal.h>
  68. #include <cutils/properties.h>
  69. #ifndef N_HCI
  70. #define N_HCI 15
  71. #endif
  72. #define HCIUARTSETPROTO _IOW('U', 200, int)
  73. #define HCIUARTGETPROTO _IOR('U', 201, int)
  74. #define HCIUARTGETDEVICE _IOR('U', 202, int)
  75. #define HCI_UART_H4 0
  76. #define HCI_UART_BCSP 1
  77. #define HCI_UART_3WIRE 2
  78. #define HCI_UART_H4DS 3
  79. #define HCI_UART_LL 4
  80. int uart_fd = -1;
  81. int hcdfile_fd = -1;
  82. int termios_baudrate = 0;
  83. int bdaddr_flag = 0;
  84. int enable_lpm = 0;
  85. int enable_hci = 0;
  86. int debug = 0;
  87. struct termios termios;
  88. unsigned char buffer[1024];
  89. unsigned char hci_reset[] = { 0x01, 0x03, 0x0c, 0x00 };
  90. unsigned char hci_download_minidriver[] = { 0x01, 0x2e, 0xfc, 0x00 };
  91. unsigned char hci_update_baud_rate[] = { 0x01, 0x18, 0xfc, 0x06, 0x00, 0x00,
  92. 0x00, 0x00, 0x00, 0x00 };
  93. unsigned char hci_write_bd_addr[] = { 0x01, 0x01, 0xfc, 0x06,
  94. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
  95. unsigned char hci_write_sleep_mode[] = { 0x01, 0x27, 0xfc, 0x0c,
  96. 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00,
  97. 0x00, 0x00 };
  98. int
  99. parse_patchram(char *optarg)
  100. {
  101. char *p;
  102. if (!(p = strrchr(optarg, '.'))) {
  103. fprintf(stderr, "file %s not an HCD file\n", optarg);
  104. exit(3);
  105. }
  106. p++;
  107. if (strcasecmp("hcd", p) != 0) {
  108. fprintf(stderr, "file %s not an HCD file\n", optarg);
  109. exit(4);
  110. }
  111. if ((hcdfile_fd = open(optarg, O_RDONLY)) == -1) {
  112. fprintf(stderr, "file %s could not be opened, error %d\n", optarg, errno);
  113. exit(5);
  114. }
  115. return(0);
  116. }
  117. void
  118. BRCM_encode_baud_rate(uint baud_rate, unsigned char *encoded_baud)
  119. {
  120. if(baud_rate == 0 || encoded_baud == NULL) {
  121. fprintf(stderr, "Baudrate not supported!");
  122. return;
  123. }
  124. encoded_baud[3] = (unsigned char)(baud_rate >> 24);
  125. encoded_baud[2] = (unsigned char)(baud_rate >> 16);
  126. encoded_baud[1] = (unsigned char)(baud_rate >> 8);
  127. encoded_baud[0] = (unsigned char)(baud_rate & 0xFF);
  128. }
  129. typedef struct {
  130. int baud_rate;
  131. int termios_value;
  132. } tBaudRates;
  133. tBaudRates baud_rates[] = {
  134. { 115200, B115200 },
  135. { 230400, B230400 },
  136. { 460800, B460800 },
  137. { 500000, B500000 },
  138. { 576000, B576000 },
  139. { 921600, B921600 },
  140. { 1000000, B1000000 },
  141. { 1152000, B1152000 },
  142. { 1500000, B1500000 },
  143. { 2000000, B2000000 },
  144. { 2500000, B2500000 },
  145. { 3000000, B3000000 },
  146. #ifndef __CYGWIN__
  147. { 3500000, B3500000 },
  148. { 4000000, B4000000 }
  149. #endif
  150. };
  151. int
  152. validate_baudrate(int baud_rate, int *value)
  153. {
  154. unsigned int i;
  155. for (i = 0; i < (sizeof(baud_rates) / sizeof(tBaudRates)); i++) {
  156. if (baud_rates[i].baud_rate == baud_rate) {
  157. *value = baud_rates[i].termios_value;
  158. return(1);
  159. }
  160. }
  161. return(0);
  162. }
  163. int
  164. parse_baudrate(char *optarg)
  165. {
  166. int baudrate = atoi(optarg);
  167. if (validate_baudrate(baudrate, &termios_baudrate)) {
  168. BRCM_encode_baud_rate(baudrate, &hci_update_baud_rate[6]);
  169. }
  170. return(0);
  171. }
  172. int
  173. parse_bdaddr(char *optarg)
  174. {
  175. int bd_addr[6];
  176. int i;
  177. sscanf(optarg, "%02X:%02X:%02X:%02X:%02X:%02X",
  178. &bd_addr[5], &bd_addr[4], &bd_addr[3],
  179. &bd_addr[2], &bd_addr[1], &bd_addr[0]);
  180. for (i = 0; i < 6; i++) {
  181. hci_write_bd_addr[4 + i] = bd_addr[i];
  182. }
  183. bdaddr_flag = 1;
  184. return(0);
  185. }
  186. int
  187. parse_enable_lpm(char *optarg)
  188. {
  189. enable_lpm = 1;
  190. return(0);
  191. }
  192. int
  193. parse_enable_hci(char *optarg)
  194. {
  195. enable_hci = 1;
  196. return(0);
  197. }
  198. int
  199. parse_cmd_line(int argc, char **argv)
  200. {
  201. int c;
  202. int digit_optind = 0;
  203. typedef int (*PFI)();
  204. PFI parse_param[] = { parse_patchram, parse_baudrate,
  205. parse_bdaddr, parse_enable_lpm, parse_enable_hci };
  206. while (1)
  207. {
  208. int this_option_optind = optind ? optind : 1;
  209. int option_index = 0;
  210. static struct option long_options[] = {
  211. {"patchram", 1, 0, 0},
  212. {"baudrate", 1, 0, 0},
  213. {"bd_addr", 1, 0, 0},
  214. {"enable_lpm", 0, 0, 0},
  215. {"enable_hci", 0, 0, 0},
  216. {0, 0, 0, 0}
  217. };
  218. c = getopt_long_only (argc, argv, "d", long_options, &option_index);
  219. if (c == -1) {
  220. break;
  221. }
  222. switch (c) {
  223. case 0:
  224. printf ("option %s", long_options[option_index].name);
  225. if (optarg) {
  226. printf (" with arg %s", optarg);
  227. }
  228. printf ("\n");
  229. (*parse_param[option_index])(optarg);
  230. break;
  231. case 'd':
  232. debug = 1;
  233. break;
  234. case '?':
  235. //nobreak
  236. default:
  237. printf("Usage %s:\n", argv[0]);
  238. printf("\t<-d> to print a debug log\n");
  239. printf("\t<--patchram patchram_file>\n");
  240. printf("\t<--baudrate baud_rate>\n");
  241. printf("\t<--bd_addr bd_address>\n");
  242. printf("\t<--enable_lpm\n");
  243. printf("\t<--enable_hci\n");
  244. printf("\tuart_device_name\n");
  245. break;
  246. }
  247. }
  248. if (optind < argc) {
  249. if (optind < argc) {
  250. printf ("%s ", argv[optind]);
  251. if ((uart_fd = open(argv[optind], O_RDWR | O_NOCTTY)) == -1) {
  252. fprintf(stderr, "port %s could not be opened, error %d\n", argv[2], errno);
  253. }
  254. }
  255. printf ("\n");
  256. }
  257. return(0);
  258. }
  259. void
  260. init_uart()
  261. {
  262. tcflush(uart_fd, TCIOFLUSH);
  263. tcgetattr(uart_fd, &termios);
  264. #ifndef __CYGWIN__
  265. cfmakeraw(&termios);
  266. #else
  267. termios.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP
  268. | INLCR | IGNCR | ICRNL | IXON);
  269. termios.c_oflag &= ~OPOST;
  270. termios.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
  271. termios.c_cflag &= ~(CSIZE | PARENB);
  272. termios.c_cflag |= CS8;
  273. #endif
  274. termios.c_cflag |= CRTSCTS;
  275. tcsetattr(uart_fd, TCSANOW, &termios);
  276. tcflush(uart_fd, TCIOFLUSH);
  277. tcsetattr(uart_fd, TCSANOW, &termios);
  278. tcflush(uart_fd, TCIOFLUSH);
  279. tcflush(uart_fd, TCIOFLUSH);
  280. cfsetospeed(&termios, B115200);
  281. cfsetispeed(&termios, B115200);
  282. tcsetattr(uart_fd, TCSANOW, &termios);
  283. }
  284. void
  285. dump(unsigned char *out, int len)
  286. {
  287. int i;
  288. for (i = 0; i < len; i++) {
  289. if (i && !(i % 16)) {
  290. fprintf(stderr, "\n");
  291. }
  292. fprintf(stderr, "%02x ", out[i]);
  293. }
  294. fprintf(stderr, "\n");
  295. }
  296. void
  297. read_event(int fd, unsigned char *buffer)
  298. {
  299. int i = 0;
  300. int len = 3;
  301. int count;
  302. while ((count = read(fd, &buffer[i], len)) < len) {
  303. i += count;
  304. len -= count;
  305. }
  306. i += count;
  307. len = buffer[2];
  308. while ((count = read(fd, &buffer[i], len)) < len) {
  309. i += count;
  310. len -= count;
  311. }
  312. if (debug) {
  313. count += i;
  314. fprintf(stderr, "received %d\n", count);
  315. dump(buffer, count);
  316. }
  317. }
  318. void
  319. hci_send_cmd(unsigned char *buf, int len)
  320. {
  321. if (debug) {
  322. fprintf(stderr, "writing\n");
  323. dump(buf, len);
  324. }
  325. write(uart_fd, buf, len);
  326. }
  327. void
  328. expired(int sig)
  329. {
  330. hci_send_cmd(hci_reset, sizeof(hci_reset));
  331. alarm(4);
  332. }
  333. void
  334. proc_reset()
  335. {
  336. signal(SIGALRM, expired);
  337. hci_send_cmd(hci_reset, sizeof(hci_reset));
  338. alarm(4);
  339. read_event(uart_fd, buffer);
  340. alarm(0);
  341. }
  342. void
  343. proc_patchram()
  344. {
  345. int len;
  346. hci_send_cmd(hci_download_minidriver, sizeof(hci_download_minidriver));
  347. read_event(uart_fd, buffer);
  348. read(uart_fd, &buffer[0], 2);
  349. usleep(50000);
  350. while (read(hcdfile_fd, &buffer[1], 3)) {
  351. buffer[0] = 0x01;
  352. len = buffer[3];
  353. read(hcdfile_fd, &buffer[4], len);
  354. hci_send_cmd(buffer, len + 4);
  355. read_event(uart_fd, buffer);
  356. }
  357. proc_reset();
  358. }
  359. void
  360. proc_baudrate()
  361. {
  362. hci_send_cmd(hci_update_baud_rate, sizeof(hci_update_baud_rate));
  363. read_event(uart_fd, buffer);
  364. cfsetospeed(&termios, termios_baudrate);
  365. cfsetispeed(&termios, termios_baudrate);
  366. tcsetattr(uart_fd, TCSANOW, &termios);
  367. if (debug) {
  368. fprintf(stderr, "Done setting baudrate\n");
  369. }
  370. }
  371. void
  372. proc_bdaddr()
  373. {
  374. hci_send_cmd(hci_write_bd_addr, sizeof(hci_write_bd_addr));
  375. read_event(uart_fd, buffer);
  376. }
  377. void
  378. proc_enable_lpm()
  379. {
  380. hci_send_cmd(hci_write_sleep_mode, sizeof(hci_write_sleep_mode));
  381. read_event(uart_fd, buffer);
  382. }
  383. void
  384. proc_enable_hci()
  385. {
  386. int i = N_HCI;
  387. int proto = HCI_UART_H4;
  388. if (enable_lpm) {
  389. proto = HCI_UART_LL;
  390. }
  391. if (ioctl(uart_fd, TIOCSETD, &i) < 0) {
  392. fprintf(stderr, "Can't set line discipline\n");
  393. return;
  394. }
  395. if (ioctl(uart_fd, HCIUARTSETPROTO, proto) < 0) {
  396. fprintf(stderr, "Can't set hci protocol\n");
  397. return;
  398. }
  399. fprintf(stderr, "Done setting line discpline\n");
  400. return;
  401. }
  402. void
  403. read_default_bdaddr()
  404. {
  405. int sz;
  406. int fd;
  407. char path[PROPERTY_VALUE_MAX];
  408. char bdaddr[18];
  409. property_get("ro.bt.bdaddr_path", path, "");
  410. if (path[0] == 0)
  411. return;
  412. fd = open(path, O_RDONLY);
  413. if (fd < 0) {
  414. fprintf(stderr, "open(%s) failed: %s (%d)", path, strerror(errno),
  415. errno);
  416. return;
  417. }
  418. sz = read(fd, bdaddr, sizeof(bdaddr));
  419. if (sz < 0) {
  420. fprintf(stderr, "read(%s) failed: %s (%d)", path, strerror(errno),
  421. errno);
  422. close(fd);
  423. return;
  424. } else if (sz != sizeof(bdaddr)) {
  425. fprintf(stderr, "read(%s) unexpected size %d", path, sz);
  426. close(fd);
  427. return;
  428. }
  429. printf("Read default bdaddr of %s\n", bdaddr);
  430. parse_bdaddr(bdaddr);
  431. }
  432. int
  433. main (int argc, char **argv)
  434. {
  435. read_default_bdaddr();
  436. parse_cmd_line(argc, argv);
  437. if (uart_fd < 0) {
  438. exit(1);
  439. }
  440. init_uart();
  441. proc_reset();
  442. if (hcdfile_fd > 0) {
  443. proc_patchram();
  444. }
  445. if (termios_baudrate) {
  446. proc_baudrate();
  447. }
  448. if (bdaddr_flag) {
  449. proc_bdaddr();
  450. }
  451. if (enable_lpm) {
  452. proc_enable_lpm();
  453. }
  454. if (enable_hci) {
  455. proc_enable_hci();
  456. while (1) {
  457. sleep(UINT_MAX);
  458. }
  459. }
  460. exit(0);
  461. }