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
usage()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
dump_record(FILE * fpo,unsigned short opcode,unsigned char len,unsigned char * data)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
advance(char ** buf)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
process_line(FILE * file_out,char * buf,char * buffer)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
main(int argc,char ** argv)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