1 /* 2 ** Copyright 2007, The Android Open Source Project 3 ** 4 ** Licensed under the Apache License, Version 2.0 (the "License"); 5 ** you may not use this file except in compliance with the License. 6 ** You may obtain a copy of the License at 7 ** 8 ** http://www.apache.org/licenses/LICENSE-2.0 9 ** 10 ** Unless required by applicable law or agreed to in writing, software 11 ** distributed under the License is distributed on an "AS IS" BASIS, 12 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 ** See the License for the specific language governing permissions and 14 ** limitations under the License. 15 */ 16 17 #include <stdio.h> 18 #include <unistd.h> 19 #include <stdlib.h> 20 #include <string.h> 21 #include <errno.h> 22 #include <ctype.h> 23 24 #define FAILIF(x, args...) do { \ 25 if (x) { \ 26 fprintf(stderr, ##args); \ 27 exit(1); \ 28 } \ 29 } while(0) 30 31 static void usage() { 32 printf("Usage: brfpatch INPUT OUTPUT\n" 33 "\n" 34 "\tGenerates bluetooth firmware\n" 35 "\n" 36 "INPUT: Bluetooth script in ASCII format.\n" 37 " For TI BRF chips this can be generated from .bts files using the TI Bluetooth\n" 38 " script pad to save as .txt. This txt file can be used as input.\n" 39 " Alternately, run strings on the .bts and manually edit to change decimal\n" 40 " arguments into hex of the appropriate number of octets.\n" 41 " FORMAT: Send_HCI_xxxx OPCODE DATA1 DATA2 DATA3 ...\n" 42 " where OPCODE, DATA1 etc are one of:\n" 43 " 0x12 (1 byte)\n" 44 " 0x1234 (2 byte)\n" 45 " 0x12345678 (4 byte)\n" 46 " \"0123456789ABCDEF0123\" (multibyte)\n" 47 " \"01:23:45:67:89:AB:CD:EF:01:23\" (multibyte)\n" 48 "\n" 49 "OUTPUT: Binary firmware\n" 50 " FORMAT: 0x01 OPCODE DATA_LEN DATA\n"); 51 exit(1); 52 } 53 54 static void dump_record(FILE *fpo, unsigned short opcode, unsigned char len, 55 unsigned char *data) { 56 57 unsigned char prefix = 0x01; // H4 UART command packet 58 fwrite(&prefix, 1, 1, fpo); 59 fwrite(&opcode, 2, 1, fpo); // opcode 60 fwrite(&len, 1, 1, fpo); // data length 61 fwrite(data, len, 1, fpo); // data 62 } 63 64 // advance beyond next whitespace. Return -1 if end of string reached 65 static int advance(char **buf) { 66 char *b = *buf; 67 while (*b && !isspace(*b)) 68 b++; 69 while (*b && isspace(*b)) 70 b++; 71 *buf = b; 72 if (!(*b)) 73 return -1; 74 return 0; 75 } 76 77 static void process_line(FILE *file_out, char *buf, char *buffer) { 78 FAILIF(strncmp(buf, "Send_", 5) != 0, "Not expecting: %s\n", buffer); 79 80 81 unsigned int opcode; 82 83 FAILIF(advance(&buf), "Could not find opcode in: %s\n", buffer); 84 FAILIF(sscanf(buf, "0x%04x\n", &opcode) != 1, 85 "Could not find opcode in: %s\n", buffer); 86 87 88 unsigned char data[1024]; 89 unsigned char *dp = data; 90 91 while (!advance(&buf)) { 92 switch (*buf) { 93 case '"': 94 buf++; 95 while (*buf != '"' && *buf != 0) { 96 FAILIF(dp > data + sizeof(data), 97 "Too much data: %s\n", buffer); 98 FAILIF(sscanf(buf, "%02x", (unsigned int *)dp) != 1, 99 "Error parsing (%d): %s\n", __LINE__, buffer); 100 dp++; 101 buf += 2; 102 if (*buf == ':') 103 buf++; 104 } 105 break; 106 case '0': 107 buf++; 108 FAILIF(*buf != 'x', "Error parsing: %s\n", buffer); 109 buf++; 110 111 // find length of this piece of data 112 char *end = buf; 113 while (isalnum(*end)) 114 end++; 115 116 // switch on length 117 switch ((unsigned int)end - (unsigned int)buf) { 118 case 2: 119 FAILIF(sscanf(buf, "%02x", (unsigned int *)dp) != 1, 120 "Error parsing (%d): %s\n", __LINE__, buffer); 121 buf += 2; 122 dp += 1; 123 break; 124 case 4: 125 FAILIF(sscanf(buf, "%04x", (unsigned int *)dp) != 1, 126 "Error parsing (%d): %s\n", __LINE__, buffer); 127 buf += 4; 128 dp += 2; 129 break; 130 case 6: 131 FAILIF(sscanf(buf, "%06x", (unsigned int *)dp) != 1, 132 "Error parsing (%d): %s\n", __LINE__, buffer); 133 buf += 6; 134 dp += 3; 135 break; 136 case 8: 137 FAILIF(sscanf(buf, "%08x", (unsigned int *)dp) != 1, 138 "Error parsing (%d): %s\n", __LINE__, buffer); 139 buf += 8; 140 dp += 4; 141 break; 142 case 16: 143 dp += 4; 144 FAILIF(sscanf(buf, "%08x", (unsigned int *)dp) != 1, 145 "Error parsing (%d): %s\n", __LINE__, buffer); 146 buf += 8; 147 dp -= 4; 148 FAILIF(sscanf(buf, "%08x", (unsigned int *)dp) != 1, 149 "Error parsing (%d): %s\n", __LINE__, buffer); 150 buf += 8; 151 dp += 8; 152 break; 153 default: 154 FAILIF(1, "Error parsing (%d): %s\n", __LINE__, buffer); 155 } 156 break; 157 default: 158 FAILIF(1, "Error parsing (%d): %s\n", __LINE__, buffer); 159 } 160 } 161 162 dump_record(file_out, opcode, dp - data, data); 163 } 164 165 166 int main(int argc, char **argv) { 167 168 if (argc != 3) 169 usage(); 170 171 FILE *file_in = fopen(argv[1], "r"); 172 FAILIF(!file_in, "Could not open %s: %s\n", argv[1], strerror(errno)); 173 174 FILE *file_out = fopen(argv[2], "w+"); 175 FAILIF(!file_out, "Could not open %s: %s\n", argv[2], strerror(errno)); 176 177 char buffer[1024]; 178 char *buf; 179 180 while (fgets(buffer, 1024, file_in) != NULL) { 181 buf = buffer; 182 while (*buf && isspace(*buf)) 183 buf++; 184 switch (*buf) { 185 case 'S': 186 process_line(file_out, buf, buffer); 187 break; 188 case 'W': // Wait_HCI_Command... meta-data, not needed 189 case '#': 190 case 0: 191 continue; 192 default: 193 FAILIF(1, "Don't know what to do with: %s\n", buffer); 194 } 195 } 196 197 fclose(file_in); 198 fclose(file_out); 199 200 return 0; 201 } 202