hciattach_qualcomm.c 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. *
  4. * BlueZ - Bluetooth protocol stack for Linux
  5. *
  6. * Copyright (C) 2005-2010 Marcel Holtmann <marcel@holtmann.org>
  7. * Copyright (c) 2010, Code Aurora Forum. All rights reserved.
  8. *
  9. *
  10. */
  11. #ifdef HAVE_CONFIG_H
  12. #include <config.h>
  13. #endif
  14. #define _GNU_SOURCE
  15. #include <stdio.h>
  16. #include <errno.h>
  17. #include <fcntl.h>
  18. #include <unistd.h>
  19. #include <stdlib.h>
  20. #include <string.h>
  21. #include <signal.h>
  22. #include <syslog.h>
  23. #include <termios.h>
  24. #include <time.h>
  25. #include <poll.h>
  26. #include <sys/time.h>
  27. #include <sys/param.h>
  28. #include <sys/ioctl.h>
  29. #include <sys/uio.h>
  30. #include "lib/bluetooth.h"
  31. #include "lib/hci.h"
  32. #include "lib/hci_lib.h"
  33. #include "hciattach.h"
  34. #define FAILIF(x, args...) do { \
  35. if (x) { \
  36. fprintf(stderr, ##args); \
  37. return -1; \
  38. } \
  39. } while (0)
  40. typedef struct {
  41. uint8_t uart_prefix;
  42. hci_event_hdr hci_hdr;
  43. evt_cmd_complete cmd_complete;
  44. uint8_t status;
  45. uint8_t data[16];
  46. } __attribute__((packed)) command_complete_t;
  47. static int read_command_complete(int fd,
  48. unsigned short opcode,
  49. unsigned char len)
  50. {
  51. command_complete_t resp;
  52. unsigned char vsevent[512];
  53. int n;
  54. /* Read reply. */
  55. n = read_hci_event(fd, vsevent, sizeof(vsevent));
  56. FAILIF(n < 0, "Failed to read response");
  57. FAILIF(vsevent[1] != 0xFF, "Failed to read response");
  58. n = read_hci_event(fd, (unsigned char *)&resp, sizeof(resp));
  59. FAILIF(n < 0, "Failed to read response");
  60. /* event must be event-complete */
  61. FAILIF(resp.hci_hdr.evt != EVT_CMD_COMPLETE,
  62. "Error in response: not a cmd-complete event, "
  63. "but 0x%02x!\n", resp.hci_hdr.evt);
  64. FAILIF(resp.hci_hdr.plen < 4, /* plen >= 4 for EVT_CMD_COMPLETE */
  65. "Error in response: plen is not >= 4, but 0x%02x!\n",
  66. resp.hci_hdr.plen);
  67. /* cmd-complete event: opcode */
  68. FAILIF(resp.cmd_complete.opcode != 0,
  69. "Error in response: opcode is 0x%04x, not 0!",
  70. resp.cmd_complete.opcode);
  71. return resp.status == 0 ? 0 : -1;
  72. }
  73. static int qualcomm_load_firmware(int fd, const char *firmware, const char *bdaddr_s)
  74. {
  75. int fw = open(firmware, O_RDONLY);
  76. fprintf(stdout, "Opening firmware file: %s\n", firmware);
  77. FAILIF(fw < 0,
  78. "Could not open firmware file %s: %s (%d).\n",
  79. firmware, strerror(errno), errno);
  80. fprintf(stdout, "Uploading firmware...\n");
  81. do {
  82. /* Read each command and wait for a response. */
  83. unsigned char data[1024];
  84. unsigned char cmdp[1 + sizeof(hci_command_hdr)];
  85. hci_command_hdr *cmd = (hci_command_hdr *) (cmdp + 1);
  86. int nr;
  87. nr = read(fw, cmdp, sizeof(cmdp));
  88. if (!nr)
  89. break;
  90. FAILIF(nr != sizeof(cmdp),
  91. "Could not read H4 + HCI header!\n");
  92. FAILIF(*cmdp != HCI_COMMAND_PKT,
  93. "Command is not an H4 command packet!\n");
  94. FAILIF(read(fw, data, cmd->plen) != cmd->plen,
  95. "Could not read %d bytes of data \
  96. for command with opcode %04x!\n",
  97. cmd->plen, cmd->opcode);
  98. if ((data[0] == 1) && (data[1] == 2) && (data[2] == 6)) {
  99. bdaddr_t bdaddr;
  100. if (bdaddr_s != NULL) {
  101. str2ba(bdaddr_s, &bdaddr);
  102. memcpy(&data[3], &bdaddr, sizeof(bdaddr_t));
  103. }
  104. }
  105. {
  106. int nw;
  107. struct iovec iov_cmd[2];
  108. iov_cmd[0].iov_base = cmdp;
  109. iov_cmd[0].iov_len = sizeof(cmdp);
  110. iov_cmd[1].iov_base = data;
  111. iov_cmd[1].iov_len = cmd->plen;
  112. nw = writev(fd, iov_cmd, 2);
  113. FAILIF(nw != (int) sizeof(cmdp) + cmd->plen,
  114. "Could not send entire command \
  115. (sent only %d bytes)!\n",
  116. nw);
  117. }
  118. /* Wait for response */
  119. if (read_command_complete(fd, cmd->opcode, cmd->plen) < 0)
  120. return -1;
  121. } while (1);
  122. fprintf(stdout, "Firmware upload successful.\n");
  123. close(fw);
  124. return 0;
  125. }
  126. int qualcomm_init(int fd, int speed, struct termios *ti, const char *bdaddr)
  127. {
  128. struct timespec tm = {0, 50000};
  129. char cmd[5];
  130. unsigned char resp[100]; /* Response */
  131. char fw[100];
  132. int n;
  133. memset(resp, 0, 100);
  134. /* Get Manufacturer and LMP version */
  135. cmd[0] = HCI_COMMAND_PKT;
  136. cmd[1] = 0x01;
  137. cmd[2] = 0x10;
  138. cmd[3] = 0x00;
  139. do {
  140. n = write(fd, cmd, 4);
  141. if (n < 4) {
  142. perror("Failed to write init command");
  143. return -1;
  144. }
  145. /* Read reply. */
  146. if (read_hci_event(fd, resp, 100) < 0) {
  147. perror("Failed to read init response");
  148. return -1;
  149. }
  150. /* Wait for command complete event for our Opcode */
  151. } while (resp[4] != cmd[1] && resp[5] != cmd[2]);
  152. /* Verify manufacturer */
  153. if ((resp[11] & 0xFF) != 0x1d)
  154. fprintf(stderr,
  155. "WARNING : module's manufacturer is not Qualcomm\n");
  156. /* Print LMP version */
  157. fprintf(stderr,
  158. "Qualcomm module LMP version : 0x%02x\n", resp[10] & 0xFF);
  159. /* Print LMP subversion */
  160. {
  161. unsigned short lmp_subv = resp[13] | (resp[14] << 8);
  162. fprintf(stderr, "Qualcomm module LMP sub-version : 0x%04x\n",
  163. lmp_subv);
  164. }
  165. /* Get SoC type */
  166. cmd[0] = HCI_COMMAND_PKT;
  167. cmd[1] = 0x00;
  168. cmd[2] = 0xFC;
  169. cmd[3] = 0x01;
  170. cmd[4] = 0x06;
  171. do {
  172. n = write(fd, cmd, 5);
  173. if (n < 5) {
  174. perror("Failed to write vendor init command");
  175. return -1;
  176. }
  177. /* Read reply. */
  178. if ((n = read_hci_event(fd, resp, 100)) < 0) {
  179. perror("Failed to read vendor init response");
  180. return -1;
  181. }
  182. } while (resp[3] != 0 && resp[4] != 2);
  183. snprintf(fw, sizeof(fw), "/etc/firmware/%c%c%c%c%c%c_%c%c%c%c.bin",
  184. resp[18], resp[19], resp[20], resp[21],
  185. resp[22], resp[23],
  186. resp[32], resp[33], resp[34], resp[35]);
  187. /* Wait for command complete event for our Opcode */
  188. if (read_hci_event(fd, resp, 100) < 0) {
  189. perror("Failed to read init response");
  190. return -1;
  191. }
  192. qualcomm_load_firmware(fd, fw, bdaddr);
  193. /* Reset */
  194. cmd[0] = HCI_COMMAND_PKT;
  195. cmd[1] = 0x03;
  196. cmd[2] = 0x0C;
  197. cmd[3] = 0x00;
  198. do {
  199. n = write(fd, cmd, 4);
  200. if (n < 4) {
  201. perror("Failed to write reset command");
  202. return -1;
  203. }
  204. /* Read reply. */
  205. if ((n = read_hci_event(fd, resp, 100)) < 0) {
  206. perror("Failed to read reset response");
  207. return -1;
  208. }
  209. } while (resp[4] != cmd[1] && resp[5] != cmd[2]);
  210. nanosleep(&tm, NULL);
  211. return 0;
  212. }