Upgrade bluez5_37 :Merge the code from private
[platform/upstream/bluez.git] / tools / nokfw.c
1 /*
2  *
3  *  BlueZ - Bluetooth protocol stack for Linux
4  *
5  *  Copyright (C) 2012-2013  Intel Corporation
6  *
7  *
8  *  This program is free software; you can redistribute it and/or modify
9  *  it under the terms of the GNU General Public License as published by
10  *  the Free Software Foundation; either version 2 of the License, or
11  *  (at your option) any later version.
12  *
13  *  This program is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *  GNU General Public License for more details.
17  *
18  *  You should have received a copy of the GNU General Public License
19  *  along with this program; if not, write to the Free Software
20  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
21  *
22  */
23
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
27
28 #include <stdio.h>
29 #include <errno.h>
30 #include <fcntl.h>
31 #include <unistd.h>
32 #include <string.h>
33 #include <getopt.h>
34 #include <stdlib.h>
35 #include <stdint.h>
36 #include <sys/stat.h>
37 #include <sys/mman.h>
38
39 struct neg_cmd {
40         uint8_t  ack;
41         uint16_t baud;
42         uint16_t unused1;
43         uint8_t  proto;
44         uint16_t sys_clk;
45         uint16_t unused2;
46 } __attribute__ ((packed));
47
48 struct alive_pkt {
49         uint8_t  mid;
50         uint8_t  unused;
51 } __attribute__ ((packed));
52
53 static void print_cmd(uint16_t opcode, const uint8_t *buf, uint8_t plen)
54 {
55         switch (opcode) {
56         case 0x0c43:
57                 printf(" Write_Inquiry_Scan_Type [type=%u]", buf[0]);
58                 break;
59         case 0x0c47:
60                 printf(" Write_Page_Scan_Type [type=%u]", buf[0]);
61                 break;
62         case 0xfc01:
63                 printf(" Write_BD_ADDR [bdaddr=%02x:%02x:%02x:%02x:%02x:%02x]",
64                         buf[5], buf[4], buf[3], buf[2], buf[1], buf[0]);
65                 break;
66         case 0xfc0b:
67                 printf(" Write_Local_Supported_Features");
68                 printf(" [features=%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x]",
69                                         buf[0], buf[1], buf[2], buf[3],
70                                         buf[4], buf[5], buf[6], buf[7]);
71                 break;
72         case 0xfc0a:
73                 printf(" Super_Peek_Poke [type=%u]", buf[0]);
74                 break;
75         case 0xfc15:
76                 printf(" FM_RDS_Command [register=0x%02x,mode=%u]",
77                                                         buf[0], buf[1]);
78                 break;
79         case 0xfc18:
80                 printf(" Update_UART_Baud_Rate");
81                 break;
82         case 0xfc1c:
83                 printf(" Write_SCO_PCM_Int_Param");
84                 break;
85         case 0xfc1e:
86                 printf(" Write_PCM_Data_Format_Param");
87                 break;
88         case 0xfc22:
89                 printf(" Write_SCO_Time_Slot [slot=%u]", buf[0]);
90                 break;
91         case 0xfc41:
92                 printf(" Write_Collaboration_Mode");
93                 break;
94         case 0xfc4c:
95                 printf(" Write_RAM [address=0x%08x]",
96                         buf[0] | buf[1] << 8 | buf[2] << 16 | buf[3] << 24);
97                 break;
98         case 0xfc4e:
99                 printf(" Launch_RAM [address=0x%08x]",
100                         buf[0] | buf[1] << 8 | buf[2] << 16 | buf[3] << 24);
101                 break;
102         case 0xfc61:
103                 printf(" Write_PCM_Pins");
104                 break;
105         }
106 }
107
108 static void analyze_memory(const uint8_t *buf, size_t len)
109 {
110         const uint8_t *ptr = buf;
111         const struct neg_cmd *neg;
112         const struct alive_pkt *alive;
113         uint16_t pkt_len, opcode;
114         uint8_t pkt_type, plen;
115
116         while (ptr < buf + len) {
117                 pkt_len = ptr[0] | ptr[1] << 8;
118                 pkt_type = ptr[2];
119
120                 printf("len=%-3u type=%u,", pkt_len, pkt_type);
121
122                 switch (pkt_type) {
123                 case 0x01:
124                         opcode = ptr[3] | ptr[4] << 8;
125                         plen = ptr[5];
126                         printf("%-5s opcode=0x%04x plen=%-3u", "cmd",
127                                                         opcode, plen);
128                         print_cmd(opcode, ptr + 6, plen);
129                         break;
130                 case 0x06:
131                         plen = ptr[3];
132                         printf("%-5s plen=%-2u", "neg", plen);
133                         neg = (void *) (ptr + 4);
134                         printf(" [ack=%u baud=%u proto=0x%02x sys_clk=%u]",
135                                 neg->ack, neg->baud, neg->proto, neg->sys_clk);
136                         break;
137                 case 0x07:
138                         plen = ptr[3];
139                         printf("%-5s plen=%-2u", "alive", plen);
140                         alive = (void *) (ptr + 4);
141                         printf(" [mid=0x%02x]", alive->mid);
142                         break;
143                 case 0x08:
144                         opcode = ptr[3] | ptr[4] << 8;
145                         plen = ptr[5];
146                         printf("%-5s opcode=0x%04x plen=%-3u", "radio",
147                                                         opcode, plen);
148                         print_cmd(opcode, ptr + 6, plen);
149                         break;
150                 default:
151                         printf("unknown");
152                         break;
153                 }
154
155                 printf("\n");
156
157                 ptr += pkt_len + 2;
158         }
159 }
160
161 static void analyze_file(const char *pathname)
162 {
163         struct stat st;
164         void *map;
165         int fd;
166
167         printf("Analyzing %s\n", pathname);
168
169         fd = open(pathname, O_RDONLY | O_CLOEXEC);
170         if (fd < 0) {
171                 perror("Failed to open file");
172                 return;
173         }
174
175         if (fstat(fd, &st) < 0) {
176                 fprintf(stderr, "Failed get file size\n");
177                 close(fd);
178                 return;
179         }
180
181         if (st.st_size == 0) {
182                 fprintf(stderr, "Empty file\n");
183                 close(fd);
184                 return;
185         }
186
187         map = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0);
188         if (!map || map == MAP_FAILED) {
189                 fprintf(stderr, "Failed to map file\n");
190                 close(fd);
191                 return;
192         }
193
194         analyze_memory(map, st.st_size);
195
196         munmap(map, st.st_size);
197         close(fd);
198 }
199
200 static void usage(void)
201 {
202         printf("Nokia Bluetooth firmware analyzer\n"
203                 "Usage:\n");
204         printf("\tnokfw [options] <file>\n");
205         printf("Options:\n"
206                 "\t-h, --help             Show help options\n");
207 }
208
209 static const struct option main_options[] = {
210         { "version", no_argument,       NULL, 'v' },
211         { "help",    no_argument,       NULL, 'h' },
212         { }
213 };
214
215 int main(int argc, char *argv[])
216 {
217         int i;
218
219         for (;;) {
220                 int opt;
221
222                 opt = getopt_long(argc, argv, "vh", main_options, NULL);
223                 if (opt < 0)
224                         break;
225
226                 switch (opt) {
227                 case 'v':
228                         printf("%s\n", VERSION);
229                         return EXIT_SUCCESS;
230                 case 'h':
231                         usage();
232                         return EXIT_SUCCESS;
233                 default:
234                         return EXIT_FAILURE;
235                 }
236         }
237
238         if (argc - optind < 1) {
239                 fprintf(stderr, "No input firmware files provided\n");
240                 return EXIT_FAILURE;
241         }
242
243         for (i = optind; i < argc; i++)
244                 analyze_file(argv[i]);
245
246         return EXIT_SUCCESS;
247 }