hex2hcd.c 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. *
  4. * BlueZ - Bluetooth protocol stack for Linux
  5. *
  6. * Copyright (C) 2012-2013 Intel Corporation
  7. *
  8. *
  9. */
  10. #ifdef HAVE_CONFIG_H
  11. #include <config.h>
  12. #endif
  13. #define _GNU_SOURCE
  14. #include <stdio.h>
  15. #include <errno.h>
  16. #include <fcntl.h>
  17. #include <unistd.h>
  18. #include <string.h>
  19. #include <getopt.h>
  20. #include <dirent.h>
  21. #include <stdint.h>
  22. #include <stdlib.h>
  23. #include <stdbool.h>
  24. #include <sys/stat.h>
  25. static ssize_t process_record(int fd, const char *line, uint16_t *upper_addr)
  26. {
  27. const char *ptr = line + 1;
  28. char str[3];
  29. size_t len;
  30. uint8_t *buf;
  31. uint32_t addr;
  32. uint8_t sum = 0;
  33. int n = 0;
  34. if (line[0] != ':') {
  35. fprintf(stderr, "Invalid record start code (%c)\n", line[0]);
  36. return -EINVAL;
  37. }
  38. len = strlen(line);
  39. if (len < 11) {
  40. fprintf(stderr, "Record information is too short\n");
  41. return -EILSEQ;
  42. }
  43. buf = malloc((len / 2) + 3);
  44. if (!buf) {
  45. fprintf(stderr, "Failed to allocate memory for record data\n");
  46. return -ENOMEM;
  47. }
  48. while (1) {
  49. str[0] = *ptr++;
  50. str[1] = *ptr++;
  51. str[2] = '\0';
  52. buf[3 + n] = strtol(str, NULL, 16);
  53. if (*ptr == '\r' || *ptr == '\n')
  54. break;
  55. sum += buf[3 + n++];
  56. }
  57. sum = 0x100 - (sum & 0xff);
  58. if (n < 4 || buf[3] + 4 != n) {
  59. fprintf(stderr, "Record length is not matching data\n");
  60. free(buf);
  61. return -EILSEQ;
  62. }
  63. if (buf[3 + n] != sum) {
  64. fprintf(stderr, "Checksum mismatch\n");
  65. free(buf);
  66. return -EILSEQ;
  67. }
  68. switch (buf[6]) {
  69. case 0x00:
  70. addr = (*upper_addr << 16) + (buf[4] << 8) + buf[5];
  71. buf[0] = 0x4c;
  72. buf[1] = 0xfc;
  73. buf[2] = n;
  74. buf[3] = (addr & 0x000000ff);
  75. buf[4] = (addr & 0x0000ff00) >> 8;
  76. buf[5] = (addr & 0x00ff0000) >> 16;
  77. buf[6] = (addr & 0xff000000) >> 24;
  78. if (write(fd, buf, n + 3) < 0) {
  79. perror("Failed to write data record");
  80. free(buf);
  81. return -errno;
  82. }
  83. break;
  84. case 0x01:
  85. buf[0] = 0x4e;
  86. buf[1] = 0xfc;
  87. buf[2] = 0x04;
  88. buf[3] = 0xff;
  89. buf[4] = 0xff;
  90. buf[5] = 0xff;
  91. buf[6] = 0xff;
  92. if (write(fd, buf, 7) < 0) {
  93. perror("Failed to write end record");
  94. free(buf);
  95. return -errno;
  96. }
  97. break;
  98. case 0x04:
  99. *upper_addr = (buf[7] << 8) + buf[8];
  100. break;
  101. default:
  102. fprintf(stderr, "Unsupported record type (%02X)\n", buf[3]);
  103. free(buf);
  104. return -EILSEQ;
  105. }
  106. free(buf);
  107. return len;
  108. }
  109. static void convert_file(const char *input_path, const char *output_path)
  110. {
  111. uint16_t upper_addr = 0x0000;
  112. size_t line_size = 1024;
  113. char line_buffer[line_size];
  114. char *path;
  115. const char *ptr;
  116. FILE *fp;
  117. struct stat st;
  118. off_t cur = 0;
  119. int fd;
  120. if (output_path) {
  121. path = strdup(output_path);
  122. if (!path) {
  123. perror("Failed to allocate string");
  124. return;
  125. }
  126. } else {
  127. ptr = strrchr(input_path, '.');
  128. if (ptr) {
  129. path = malloc(ptr - input_path + 6);
  130. if (!path) {
  131. perror("Failed to allocate string");
  132. return;
  133. }
  134. strncpy(path, input_path, ptr - input_path);
  135. strcpy(path + (ptr - input_path), ".hcd");
  136. } else {
  137. if (asprintf(&path, "%s.hcd", input_path) < 0) {
  138. perror("Failed to allocate string");
  139. return;
  140. }
  141. }
  142. }
  143. printf("Converting %s to %s\n", input_path, path);
  144. fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
  145. free(path);
  146. if (fd < 0) {
  147. perror("Failed to create output file");
  148. return;
  149. }
  150. if (stat(input_path, &st) < 0) {
  151. fprintf(stderr, "Failed get file size\n");
  152. close(fd);
  153. return;
  154. }
  155. if (st.st_size == 0) {
  156. fprintf(stderr, "Empty file\n");
  157. close(fd);
  158. return;
  159. }
  160. fp = fopen(input_path, "r");
  161. if (!fp) {
  162. fprintf(stderr, "Failed to open input file\n");
  163. close(fd);
  164. return;
  165. }
  166. while (1) {
  167. char *str;
  168. ssize_t len;
  169. str = fgets(line_buffer, line_size - 1, fp);
  170. if (!str)
  171. break;
  172. len = process_record(fd, str, &upper_addr);
  173. if (len < 0)
  174. goto done;
  175. cur += len;
  176. }
  177. if (cur != st.st_size) {
  178. fprintf(stderr, "Data length does not match file length\n");
  179. goto done;
  180. }
  181. done:
  182. fclose(fp);
  183. close(fd);
  184. }
  185. struct ver_data {
  186. uint16_t num;
  187. char name[20];
  188. char major[4];
  189. char minor[4];
  190. char build[4];
  191. struct ver_data *next;
  192. };
  193. static struct ver_data *ver_list = NULL;
  194. static void ver_parse_file(const char *pathname)
  195. {
  196. struct ver_data *ver, *tmp, *prev;
  197. char dummy1[5], dummy2[5];
  198. if (strlen(pathname) < 7)
  199. return;
  200. if (strncmp(pathname, "BCM", 3))
  201. return;
  202. ver = malloc(sizeof(*ver));
  203. if (!ver)
  204. return;
  205. memset(ver, 0, sizeof(*ver));
  206. if (sscanf(pathname, "%[A-Z0-9]_%3c.%3c.%3c.%4c.%4c.hex",
  207. ver->name, ver->major, ver->minor,
  208. ver->build, dummy1, dummy2) != 6) {
  209. printf("\t/* failed to parse %s */\n", pathname);
  210. free(ver);
  211. return;
  212. }
  213. ver->num = atoi(ver->build) + (atoi(ver->minor) << 8) +
  214. (atoi(ver->major) << 13);
  215. if (!ver_list) {
  216. ver_list = ver;
  217. return;
  218. }
  219. for (tmp = ver_list, prev = NULL; tmp; prev = tmp, tmp = tmp->next) {
  220. if (ver->num == tmp->num) {
  221. free(ver);
  222. return;
  223. }
  224. if (ver->num < tmp->num) {
  225. if (prev) {
  226. prev->next = ver;
  227. ver->next = tmp;
  228. } else {
  229. ver->next = ver_list;
  230. ver_list = ver;
  231. }
  232. return;
  233. }
  234. }
  235. prev->next = ver;
  236. }
  237. static void ver_parse_entry(const char *pathname)
  238. {
  239. struct stat st;
  240. int fd;
  241. fd = open(pathname, O_RDONLY);
  242. if (fd < 0) {
  243. printf("\t/* failed to open %s */\n", pathname);
  244. return;
  245. }
  246. if (fstat(fd, &st) < 0) {
  247. printf("\t/* failed to stat %s */\n", pathname);
  248. goto done;
  249. }
  250. if (S_ISREG(st.st_mode)) {
  251. ver_parse_file(basename(pathname));
  252. goto done;
  253. }
  254. if (S_ISDIR(st.st_mode)) {
  255. DIR *dir;
  256. dir = fdopendir(fd);
  257. if (!dir)
  258. goto done;
  259. while (1) {
  260. struct dirent *d;
  261. d = readdir(dir);
  262. if (!d)
  263. break;
  264. if (d->d_type == DT_REG)
  265. ver_parse_file(d->d_name);
  266. }
  267. closedir(dir);
  268. }
  269. done:
  270. close(fd);
  271. }
  272. static void ver_print_table(int argc, char *argv[])
  273. {
  274. struct ver_data *ver;
  275. printf("static const struct {\n");
  276. printf("\tuint16_t ver;\n");
  277. printf("\tconst char *str\n");
  278. printf("} table[] = {\n");
  279. if (argc > 0) {
  280. int i;
  281. for (i = 0; i < argc; i++)
  282. ver_parse_entry(argv[i]);
  283. } else
  284. ver_parse_entry(".");
  285. for (ver = ver_list; ver; ) {
  286. struct ver_data *tmp = ver;
  287. printf("\t{ 0x%4.4x, \"%s\"\t},\t/* %s.%s.%s */\n",
  288. ver->num, ver->name,
  289. ver->major, ver->minor, ver->build);
  290. ver = ver->next;
  291. free(tmp);
  292. }
  293. printf(" { }\n");
  294. printf("};\n");
  295. }
  296. static void usage(void)
  297. {
  298. printf("Broadcom Bluetooth firmware converter\n"
  299. "Usage:\n");
  300. printf("\thex2hcd [options] <file>\n");
  301. printf("Options:\n"
  302. "\t-o, --output <file> Provide firmware output file\n"
  303. "\t-h, --help Show help options\n");
  304. }
  305. static const struct option main_options[] = {
  306. { "table", no_argument, NULL, 'T' },
  307. { "output", required_argument, NULL, 'o' },
  308. { "version", no_argument, NULL, 'v' },
  309. { "help", no_argument, NULL, 'h' },
  310. { }
  311. };
  312. int main(int argc, char *argv[])
  313. {
  314. const char *output_path = NULL;
  315. bool print_table = false;
  316. int i;
  317. for (;;) {
  318. int opt;
  319. opt = getopt_long(argc, argv, "To:vh", main_options, NULL);
  320. if (opt < 0)
  321. break;
  322. switch (opt) {
  323. case 'T':
  324. print_table = true;
  325. break;
  326. case 'o':
  327. output_path = optarg;
  328. break;
  329. case 'v':
  330. printf("%s\n", VERSION);
  331. return EXIT_SUCCESS;
  332. case 'h':
  333. usage();
  334. return EXIT_SUCCESS;
  335. default:
  336. return EXIT_FAILURE;
  337. }
  338. }
  339. if (print_table) {
  340. ver_print_table(argc - optind, argv + optind);
  341. return EXIT_SUCCESS;
  342. }
  343. if (argc - optind < 1) {
  344. fprintf(stderr, "No input firmware files provided\n");
  345. return EXIT_FAILURE;
  346. }
  347. if (output_path && argc - optind > 1) {
  348. fprintf(stderr, "Only single input firmware supported\n");
  349. return EXIT_FAILURE;
  350. }
  351. for (i = optind; i < argc; i++)
  352. convert_file(argv[i], output_path);
  353. return EXIT_SUCCESS;
  354. }