• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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