1 /*
2 *
3 * BlueZ - Bluetooth protocol stack for Linux
4 *
5 * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
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 <stdlib.h>
31 #include <getopt.h>
32 #include <sys/socket.h>
33
34 #include <bluetooth/bluetooth.h>
35 #include <bluetooth/hci.h>
36 #include <bluetooth/hci_lib.h>
37
38 #include "csr.h"
39
40 #define CSR_TRANSPORT_UNKNOWN 0
41 #define CSR_TRANSPORT_HCI 1
42 #define CSR_TRANSPORT_USB 2
43 #define CSR_TRANSPORT_BCSP 3
44 #define CSR_TRANSPORT_H4 4
45 #define CSR_TRANSPORT_3WIRE 5
46
47 #define CSR_STORES_PSI (0x0001)
48 #define CSR_STORES_PSF (0x0002)
49 #define CSR_STORES_PSROM (0x0004)
50 #define CSR_STORES_PSRAM (0x0008)
51 #define CSR_STORES_DEFAULT (CSR_STORES_PSI | CSR_STORES_PSF)
52
53 #define CSR_TYPE_NULL 0
54 #define CSR_TYPE_COMPLEX 1
55 #define CSR_TYPE_UINT8 2
56 #define CSR_TYPE_UINT16 3
57 #define CSR_TYPE_UINT32 4
58
59 #define CSR_TYPE_ARRAY CSR_TYPE_COMPLEX
60 #define CSR_TYPE_BDADDR CSR_TYPE_COMPLEX
61
transport_open(int transport,char * device,speed_t bcsp_rate)62 static inline int transport_open(int transport, char *device, speed_t bcsp_rate)
63 {
64 switch (transport) {
65 case CSR_TRANSPORT_HCI:
66 return csr_open_hci(device);
67 #ifdef HAVE_LIBUSB
68 case CSR_TRANSPORT_USB:
69 return csr_open_usb(device);
70 #endif
71 case CSR_TRANSPORT_BCSP:
72 return csr_open_bcsp(device, bcsp_rate);
73 case CSR_TRANSPORT_H4:
74 return csr_open_h4(device);
75 case CSR_TRANSPORT_3WIRE:
76 return csr_open_3wire(device);
77 default:
78 fprintf(stderr, "Unsupported transport\n");
79 return -1;
80 }
81 }
82
transport_read(int transport,uint16_t varid,uint8_t * value,uint16_t length)83 static inline int transport_read(int transport, uint16_t varid, uint8_t *value, uint16_t length)
84 {
85 switch (transport) {
86 case CSR_TRANSPORT_HCI:
87 return csr_read_hci(varid, value, length);
88 #ifdef HAVE_LIBUSB
89 case CSR_TRANSPORT_USB:
90 return csr_read_usb(varid, value, length);
91 #endif
92 case CSR_TRANSPORT_BCSP:
93 return csr_read_bcsp(varid, value, length);
94 case CSR_TRANSPORT_H4:
95 return csr_read_h4(varid, value, length);
96 case CSR_TRANSPORT_3WIRE:
97 return csr_read_3wire(varid, value, length);
98 default:
99 errno = EOPNOTSUPP;
100 return -1;
101 }
102 }
103
transport_write(int transport,uint16_t varid,uint8_t * value,uint16_t length)104 static inline int transport_write(int transport, uint16_t varid, uint8_t *value, uint16_t length)
105 {
106 switch (transport) {
107 case CSR_TRANSPORT_HCI:
108 return csr_write_hci(varid, value, length);
109 #ifdef HAVE_LIBUSB
110 case CSR_TRANSPORT_USB:
111 return csr_write_usb(varid, value, length);
112 #endif
113 case CSR_TRANSPORT_BCSP:
114 return csr_write_bcsp(varid, value, length);
115 case CSR_TRANSPORT_H4:
116 return csr_write_h4(varid, value, length);
117 case CSR_TRANSPORT_3WIRE:
118 return csr_write_3wire(varid, value, length);
119 default:
120 errno = EOPNOTSUPP;
121 return -1;
122 }
123 }
124
transport_close(int transport)125 static inline void transport_close(int transport)
126 {
127 switch (transport) {
128 case CSR_TRANSPORT_HCI:
129 csr_close_hci();
130 break;
131 #ifdef HAVE_LIBUSB
132 case CSR_TRANSPORT_USB:
133 csr_close_usb();
134 break;
135 #endif
136 case CSR_TRANSPORT_BCSP:
137 csr_close_bcsp();
138 break;
139 case CSR_TRANSPORT_H4:
140 csr_close_h4();
141 break;
142 case CSR_TRANSPORT_3WIRE:
143 csr_close_3wire();
144 break;
145 }
146 }
147
148 static struct {
149 uint16_t pskey;
150 int type;
151 int size;
152 char *str;
153 } storage[] = {
154 { CSR_PSKEY_BDADDR, CSR_TYPE_BDADDR, 8, "bdaddr" },
155 { CSR_PSKEY_COUNTRYCODE, CSR_TYPE_UINT16, 0, "country" },
156 { CSR_PSKEY_CLASSOFDEVICE, CSR_TYPE_UINT32, 0, "devclass" },
157 { CSR_PSKEY_ENC_KEY_LMIN, CSR_TYPE_UINT16, 0, "keymin" },
158 { CSR_PSKEY_ENC_KEY_LMAX, CSR_TYPE_UINT16, 0, "keymax" },
159 { CSR_PSKEY_LOCAL_SUPPORTED_FEATURES, CSR_TYPE_ARRAY, 8, "features" },
160 { CSR_PSKEY_LOCAL_SUPPORTED_COMMANDS, CSR_TYPE_ARRAY, 18, "commands" },
161 { CSR_PSKEY_HCI_LMP_LOCAL_VERSION, CSR_TYPE_UINT16, 0, "version" },
162 { CSR_PSKEY_LMP_REMOTE_VERSION, CSR_TYPE_UINT8, 0, "remver" },
163 { CSR_PSKEY_HOSTIO_USE_HCI_EXTN, CSR_TYPE_UINT16, 0, "hciextn" },
164 { CSR_PSKEY_HOSTIO_MAP_SCO_PCM, CSR_TYPE_UINT16, 0, "mapsco" },
165 { CSR_PSKEY_UART_BAUDRATE, CSR_TYPE_UINT16, 0, "baudrate" },
166 { CSR_PSKEY_HOST_INTERFACE, CSR_TYPE_UINT16, 0, "hostintf" },
167 { CSR_PSKEY_ANA_FREQ, CSR_TYPE_UINT16, 0, "anafreq" },
168 { CSR_PSKEY_ANA_FTRIM, CSR_TYPE_UINT16, 0, "anaftrim" },
169 { CSR_PSKEY_USB_VENDOR_ID, CSR_TYPE_UINT16, 0, "usbvid" },
170 { CSR_PSKEY_USB_PRODUCT_ID, CSR_TYPE_UINT16, 0, "usbpid" },
171 { CSR_PSKEY_USB_DFU_PRODUCT_ID, CSR_TYPE_UINT16, 0, "dfupid" },
172 { CSR_PSKEY_INITIAL_BOOTMODE, CSR_TYPE_UINT16, 0, "bootmode" },
173 { 0x0000 },
174 };
175
storestostr(uint16_t stores)176 static char *storestostr(uint16_t stores)
177 {
178 switch (stores) {
179 case 0x0000:
180 return "Default";
181 case 0x0001:
182 return "psi";
183 case 0x0002:
184 return "psf";
185 case 0x0004:
186 return "psrom";
187 case 0x0008:
188 return "psram";
189 default:
190 return "Unknown";
191 }
192 }
193
memorytostr(uint16_t type)194 static char *memorytostr(uint16_t type)
195 {
196 switch (type) {
197 case 0x0000:
198 return "Flash memory";
199 case 0x0001:
200 return "EEPROM";
201 case 0x0002:
202 return "RAM (transient)";
203 case 0x0003:
204 return "ROM (or \"read-only\" flash memory)";
205 default:
206 return "Unknown";
207 }
208 }
209
210 #define OPT_RANGE(min, max) \
211 if (argc < (min)) { errno = EINVAL; return -1; } \
212 if (argc > (max)) { errno = E2BIG; return -1; }
213
214 static struct option help_options[] = {
215 { "help", 0, 0, 'h' },
216 { 0, 0, 0, 0 }
217 };
218
opt_help(int argc,char * argv[],int * help)219 static int opt_help(int argc, char *argv[], int *help)
220 {
221 int opt;
222
223 while ((opt=getopt_long(argc, argv, "+h", help_options, NULL)) != EOF) {
224 switch (opt) {
225 case 'h':
226 if (help)
227 *help = 1;
228 break;
229 }
230 }
231
232 return optind;
233 }
234
235 #define OPT_HELP(range, help) \
236 opt_help(argc, argv, (help)); \
237 argc -= optind; argv += optind; optind = 0; \
238 OPT_RANGE((range), (range))
239
cmd_builddef(int transport,int argc,char * argv[])240 static int cmd_builddef(int transport, int argc, char *argv[])
241 {
242 uint8_t array[8];
243 uint16_t def = 0x0000, nextdef = 0x0000;
244 int err = 0;
245
246 OPT_HELP(0, NULL);
247
248 printf("Build definitions:\n");
249
250 while (1) {
251 memset(array, 0, sizeof(array));
252 array[0] = def & 0xff;
253 array[1] = def >> 8;
254
255 err = transport_read(transport, CSR_VARID_GET_NEXT_BUILDDEF, array, 8);
256 if (err < 0) {
257 errno = -err;
258 break;
259 }
260
261 nextdef = array[2] | (array[3] << 8);
262
263 if (nextdef == 0x0000)
264 break;
265
266 def = nextdef;
267
268 printf("0x%04x - %s\n", def, csr_builddeftostr(def));
269 }
270
271 return err;
272 }
273
cmd_keylen(int transport,int argc,char * argv[])274 static int cmd_keylen(int transport, int argc, char *argv[])
275 {
276 uint8_t array[8];
277 uint16_t handle, keylen;
278 int err;
279
280 OPT_HELP(1, NULL);
281
282 handle = atoi(argv[0]);
283
284 memset(array, 0, sizeof(array));
285 array[0] = handle & 0xff;
286 array[1] = handle >> 8;
287
288 err = transport_read(transport, CSR_VARID_CRYPT_KEY_LENGTH, array, 8);
289 if (err < 0) {
290 errno = -err;
291 return -1;
292 }
293
294 handle = array[0] | (array[1] << 8);
295 keylen = array[2] | (array[3] << 8);
296
297 printf("Crypt key length: %d bit\n", keylen * 8);
298
299 return 0;
300 }
301
cmd_clock(int transport,int argc,char * argv[])302 static int cmd_clock(int transport, int argc, char *argv[])
303 {
304 uint8_t array[8];
305 uint32_t clock;
306 int err;
307
308 OPT_HELP(0, NULL);
309
310 memset(array, 0, sizeof(array));
311
312 err = transport_read(transport, CSR_VARID_BT_CLOCK, array, 8);
313 if (err < 0) {
314 errno = -err;
315 return -1;
316 }
317
318 clock = array[2] | (array[3] << 8) | (array[0] << 16) | (array[1] << 24);
319
320 printf("Bluetooth clock: 0x%04x (%d)\n", clock, clock);
321
322 return 0;
323 }
324
cmd_rand(int transport,int argc,char * argv[])325 static int cmd_rand(int transport, int argc, char *argv[])
326 {
327 uint8_t array[8];
328 uint16_t rand;
329 int err;
330
331 OPT_HELP(0, NULL);
332
333 memset(array, 0, sizeof(array));
334
335 err = transport_read(transport, CSR_VARID_RAND, array, 8);
336 if (err < 0) {
337 errno = -err;
338 return -1;
339 }
340
341 rand = array[0] | (array[1] << 8);
342
343 printf("Random number: 0x%02x (%d)\n", rand, rand);
344
345 return 0;
346 }
347
cmd_chiprev(int transport,int argc,char * argv[])348 static int cmd_chiprev(int transport, int argc, char *argv[])
349 {
350 uint8_t array[8];
351 uint16_t rev;
352 char *str;
353 int err;
354
355 OPT_HELP(0, NULL);
356
357 memset(array, 0, sizeof(array));
358
359 err = transport_read(transport, CSR_VARID_CHIPREV, array, 8);
360 if (err < 0) {
361 errno = -err;
362 return -1;
363 }
364
365 rev = array[0] | (array[1] << 8);
366
367 switch (rev) {
368 case 0x64:
369 str = "BC1 ES";
370 break;
371 case 0x65:
372 str = "BC1";
373 break;
374 case 0x89:
375 str = "BC2-External A";
376 break;
377 case 0x8a:
378 str = "BC2-External B";
379 break;
380 case 0x28:
381 str = "BC2-ROM";
382 break;
383 case 0x43:
384 str = "BC3-Multimedia";
385 break;
386 case 0x15:
387 str = "BC3-ROM";
388 break;
389 case 0xe2:
390 str = "BC3-Flash";
391 break;
392 case 0x26:
393 str = "BC4-External";
394 break;
395 case 0x30:
396 str = "BC4-ROM";
397 break;
398 default:
399 str = "NA";
400 break;
401 }
402
403 printf("Chip revision: 0x%04x (%s)\n", rev, str);
404
405 return 0;
406 }
407
cmd_buildname(int transport,int argc,char * argv[])408 static int cmd_buildname(int transport, int argc, char *argv[])
409 {
410 uint8_t array[130];
411 char name[64];
412 unsigned int i;
413 int err;
414
415 OPT_HELP(0, NULL);
416
417 memset(array, 0, sizeof(array));
418
419 err = transport_read(transport, CSR_VARID_READ_BUILD_NAME, array, 128);
420 if (err < 0) {
421 errno = -err;
422 return -1;
423 }
424
425 for (i = 0; i < sizeof(name); i++)
426 name[i] = array[(i * 2) + 4];
427
428 printf("Build name: %s\n", name);
429
430 return 0;
431 }
432
cmd_panicarg(int transport,int argc,char * argv[])433 static int cmd_panicarg(int transport, int argc, char *argv[])
434 {
435 uint8_t array[8];
436 uint16_t error;
437 int err;
438
439 OPT_HELP(0, NULL);
440
441 memset(array, 0, sizeof(array));
442
443 err = transport_read(transport, CSR_VARID_PANIC_ARG, array, 8);
444 if (err < 0) {
445 errno = -err;
446 return -1;
447 }
448
449 error = array[0] | (array[1] << 8);
450
451 printf("Panic code: 0x%02x (%s)\n", error,
452 error < 0x100 ? "valid" : "invalid");
453
454 return 0;
455 }
456
cmd_faultarg(int transport,int argc,char * argv[])457 static int cmd_faultarg(int transport, int argc, char *argv[])
458 {
459 uint8_t array[8];
460 uint16_t error;
461 int err;
462
463 OPT_HELP(0, NULL);
464
465 memset(array, 0, sizeof(array));
466
467 err = transport_read(transport, CSR_VARID_FAULT_ARG, array, 8);
468 if (err < 0) {
469 errno = -err;
470 return -1;
471 }
472
473 error = array[0] | (array[1] << 8);
474
475 printf("Fault code: 0x%02x (%s)\n", error,
476 error < 0x100 ? "valid" : "invalid");
477
478 return 0;
479 }
480
cmd_coldreset(int transport,int argc,char * argv[])481 static int cmd_coldreset(int transport, int argc, char *argv[])
482 {
483 return transport_write(transport, CSR_VARID_COLD_RESET, NULL, 0);
484 }
485
cmd_warmreset(int transport,int argc,char * argv[])486 static int cmd_warmreset(int transport, int argc, char *argv[])
487 {
488 return transport_write(transport, CSR_VARID_WARM_RESET, NULL, 0);
489 }
490
cmd_disabletx(int transport,int argc,char * argv[])491 static int cmd_disabletx(int transport, int argc, char *argv[])
492 {
493 return transport_write(transport, CSR_VARID_DISABLE_TX, NULL, 0);
494 }
495
cmd_enabletx(int transport,int argc,char * argv[])496 static int cmd_enabletx(int transport, int argc, char *argv[])
497 {
498 return transport_write(transport, CSR_VARID_ENABLE_TX, NULL, 0);
499 }
500
cmd_singlechan(int transport,int argc,char * argv[])501 static int cmd_singlechan(int transport, int argc, char *argv[])
502 {
503 uint8_t array[8];
504 uint16_t channel;
505
506 OPT_HELP(1, NULL);
507
508 channel = atoi(argv[0]);
509
510 if (channel > 2401 && channel < 2481)
511 channel -= 2402;
512
513 if (channel > 78) {
514 errno = EINVAL;
515 return -1;
516 }
517
518 memset(array, 0, sizeof(array));
519 array[0] = channel & 0xff;
520 array[1] = channel >> 8;
521
522 return transport_write(transport, CSR_VARID_SINGLE_CHAN, array, 8);
523 }
524
cmd_hoppingon(int transport,int argc,char * argv[])525 static int cmd_hoppingon(int transport, int argc, char *argv[])
526 {
527 return transport_write(transport, CSR_VARID_HOPPING_ON, NULL, 0);
528 }
529
cmd_rttxdata1(int transport,int argc,char * argv[])530 static int cmd_rttxdata1(int transport, int argc, char *argv[])
531 {
532 uint8_t array[8];
533 uint16_t freq, level;
534
535 OPT_HELP(2, NULL);
536
537 freq = atoi(argv[0]);
538
539 if (!strncasecmp(argv[1], "0x", 2))
540 level = strtol(argv[1], NULL, 16);
541 else
542 level = atoi(argv[1]);
543
544 memset(array, 0, sizeof(array));
545 array[0] = 0x04;
546 array[1] = 0x00;
547 array[2] = freq & 0xff;
548 array[3] = freq >> 8;
549 array[4] = level & 0xff;
550 array[5] = level >> 8;
551
552 return transport_write(transport, CSR_VARID_RADIOTEST, array, 8);
553 }
554
cmd_radiotest(int transport,int argc,char * argv[])555 static int cmd_radiotest(int transport, int argc, char *argv[])
556 {
557 uint8_t array[8];
558 uint16_t freq, level, test;
559
560 OPT_HELP(3, NULL);
561
562 freq = atoi(argv[0]);
563
564 if (!strncasecmp(argv[1], "0x", 2))
565 level = strtol(argv[1], NULL, 16);
566 else
567 level = atoi(argv[1]);
568
569 test = atoi(argv[2]);
570
571 memset(array, 0, sizeof(array));
572 array[0] = test & 0xff;
573 array[1] = test >> 8;
574 array[2] = freq & 0xff;
575 array[3] = freq >> 8;
576 array[4] = level & 0xff;
577 array[5] = level >> 8;
578
579 return transport_write(transport, CSR_VARID_RADIOTEST, array, 8);
580 }
581
cmd_memtypes(int transport,int argc,char * argv[])582 static int cmd_memtypes(int transport, int argc, char *argv[])
583 {
584 uint8_t array[8];
585 uint16_t type, stores[4] = { 0x0001, 0x0002, 0x0004, 0x0008 };
586 int i, err;
587
588 OPT_HELP(0, NULL);
589
590 for (i = 0; i < 4; i++) {
591 memset(array, 0, sizeof(array));
592 array[0] = stores[i] & 0xff;
593 array[1] = stores[i] >> 8;
594
595 err = transport_read(transport, CSR_VARID_PS_MEMORY_TYPE, array, 8);
596 if (err < 0)
597 continue;
598
599 type = array[2] + (array[3] << 8);
600
601 printf("%s (0x%04x) = %s (%d)\n", storestostr(stores[i]),
602 stores[i], memorytostr(type), type);
603 }
604
605 return 0;
606 }
607
608 static struct option pskey_options[] = {
609 { "stores", 1, 0, 's' },
610 { "reset", 0, 0, 'r' },
611 { "help", 0, 0, 'h' },
612 { 0, 0, 0, 0 }
613 };
614
opt_pskey(int argc,char * argv[],uint16_t * stores,int * reset,int * help)615 static int opt_pskey(int argc, char *argv[], uint16_t *stores, int *reset, int *help)
616 {
617 int opt;
618
619 while ((opt=getopt_long(argc, argv, "+s:rh", pskey_options, NULL)) != EOF) {
620 switch (opt) {
621 case 's':
622 if (!stores)
623 break;
624 if (!strcasecmp(optarg, "default"))
625 *stores = 0x0000;
626 else if (!strcasecmp(optarg, "implementation"))
627 *stores = 0x0001;
628 else if (!strcasecmp(optarg, "factory"))
629 *stores = 0x0002;
630 else if (!strcasecmp(optarg, "rom"))
631 *stores = 0x0004;
632 else if (!strcasecmp(optarg, "ram"))
633 *stores = 0x0008;
634 else if (!strcasecmp(optarg, "psi"))
635 *stores = 0x0001;
636 else if (!strcasecmp(optarg, "psf"))
637 *stores = 0x0002;
638 else if (!strcasecmp(optarg, "psrom"))
639 *stores = 0x0004;
640 else if (!strcasecmp(optarg, "psram"))
641 *stores = 0x0008;
642 else if (!strncasecmp(optarg, "0x", 2))
643 *stores = strtol(optarg, NULL, 16);
644 else
645 *stores = atoi(optarg);
646 break;
647
648 case 'r':
649 if (reset)
650 *reset = 1;
651 break;
652
653 case 'h':
654 if (help)
655 *help = 1;
656 break;
657 }
658 }
659
660 return optind;
661 }
662
663 #define OPT_PSKEY(min, max, stores, reset, help) \
664 opt_pskey(argc, argv, (stores), (reset), (help)); \
665 argc -= optind; argv += optind; optind = 0; \
666 OPT_RANGE((min), (max))
667
cmd_psget(int transport,int argc,char * argv[])668 static int cmd_psget(int transport, int argc, char *argv[])
669 {
670 uint8_t array[128];
671 uint16_t pskey, length, value, stores = CSR_STORES_DEFAULT;
672 uint32_t val32;
673 int i, err, reset = 0;
674
675 memset(array, 0, sizeof(array));
676
677 OPT_PSKEY(1, 1, &stores, &reset, NULL);
678
679 if (strncasecmp(argv[0], "0x", 2)) {
680 pskey = atoi(argv[0]);
681
682 for (i = 0; storage[i].pskey; i++) {
683 if (strcasecmp(storage[i].str, argv[0]))
684 continue;
685
686 pskey = storage[i].pskey;
687 break;
688 }
689 } else
690 pskey = strtol(argv[0] + 2, NULL, 16);
691
692 memset(array, 0, sizeof(array));
693 array[0] = pskey & 0xff;
694 array[1] = pskey >> 8;
695 array[2] = stores & 0xff;
696 array[3] = stores >> 8;
697
698 err = transport_read(transport, CSR_VARID_PS_SIZE, array, 8);
699 if (err < 0)
700 return err;
701
702 length = array[2] + (array[3] << 8);
703 if (length + 6 > (int) sizeof(array) / 2)
704 return -EIO;
705
706 memset(array, 0, sizeof(array));
707 array[0] = pskey & 0xff;
708 array[1] = pskey >> 8;
709 array[2] = length & 0xff;
710 array[3] = length >> 8;
711 array[4] = stores & 0xff;
712 array[5] = stores >> 8;
713
714 err = transport_read(transport, CSR_VARID_PS, array, (length + 3) * 2);
715 if (err < 0)
716 return err;
717
718 switch (length) {
719 case 1:
720 value = array[6] | (array[7] << 8);
721 printf("%s: 0x%04x (%d)\n", csr_pskeytostr(pskey), value, value);
722 break;
723
724 case 2:
725 val32 = array[8] | (array[9] << 8) | (array[6] << 16) | (array[7] << 24);
726 printf("%s: 0x%08x (%d)\n", csr_pskeytostr(pskey), val32, val32);
727 break;
728
729 default:
730 printf("%s:", csr_pskeytostr(pskey));
731 for (i = 0; i < length; i++)
732 printf(" 0x%02x%02x", array[(i * 2) + 6], array[(i * 2) + 7]);
733 printf("\n");
734 break;
735 }
736
737 if (reset)
738 transport_write(transport, CSR_VARID_WARM_RESET, NULL, 0);
739
740 return err;
741 }
742
cmd_psset(int transport,int argc,char * argv[])743 static int cmd_psset(int transport, int argc, char *argv[])
744 {
745 uint8_t array[128];
746 uint16_t pskey, length, value, stores = CSR_STORES_PSRAM;
747 uint32_t val32;
748 int i, err, reset = 0;
749
750 memset(array, 0, sizeof(array));
751
752 OPT_PSKEY(2, 81, &stores, &reset, NULL);
753
754 if (strncasecmp(argv[0], "0x", 2)) {
755 pskey = atoi(argv[0]);
756
757 for (i = 0; storage[i].pskey; i++) {
758 if (strcasecmp(storage[i].str, argv[0]))
759 continue;
760
761 pskey = storage[i].pskey;
762 break;
763 }
764 } else
765 pskey = strtol(argv[0] + 2, NULL, 16);
766
767 memset(array, 0, sizeof(array));
768 array[0] = pskey & 0xff;
769 array[1] = pskey >> 8;
770 array[2] = stores & 0xff;
771 array[3] = stores >> 8;
772
773 err = transport_read(transport, CSR_VARID_PS_SIZE, array, 8);
774 if (err < 0)
775 return err;
776
777 length = array[2] + (array[3] << 8);
778 if (length + 6 > (int) sizeof(array) / 2)
779 return -EIO;
780
781 memset(array, 0, sizeof(array));
782 array[0] = pskey & 0xff;
783 array[1] = pskey >> 8;
784 array[2] = length & 0xff;
785 array[3] = length >> 8;
786 array[4] = stores & 0xff;
787 array[5] = stores >> 8;
788
789 argc--;
790 argv++;
791
792 switch (length) {
793 case 1:
794 if (argc != 1) {
795 errno = E2BIG;
796 return -1;
797 }
798
799 if (!strncasecmp(argv[0], "0x", 2))
800 value = strtol(argv[0] + 2, NULL, 16);
801 else
802 value = atoi(argv[0]);
803
804 array[6] = value & 0xff;
805 array[7] = value >> 8;
806 break;
807
808 case 2:
809 if (argc != 1) {
810 errno = E2BIG;
811 return -1;
812 }
813
814 if (!strncasecmp(argv[0], "0x", 2))
815 val32 = strtol(argv[0] + 2, NULL, 16);
816 else
817 val32 = atoi(argv[0]);
818
819 array[6] = (val32 & 0xff0000) >> 16;
820 array[7] = val32 >> 24;
821 array[8] = val32 & 0xff;
822 array[9] = (val32 & 0xff00) >> 8;
823 break;
824
825 default:
826 if (argc != length * 2) {
827 errno = EINVAL;
828 return -1;
829 }
830
831 for (i = 0; i < length * 2; i++)
832 if (!strncasecmp(argv[0], "0x", 2))
833 array[i + 6] = strtol(argv[i] + 2, NULL, 16);
834 else
835 array[i + 6] = atoi(argv[i]);
836 break;
837 }
838
839 err = transport_write(transport, CSR_VARID_PS, array, (length + 3) * 2);
840 if (err < 0)
841 return err;
842
843 if (reset)
844 transport_write(transport, CSR_VARID_WARM_RESET, NULL, 0);
845
846 return err;
847 }
848
cmd_psclr(int transport,int argc,char * argv[])849 static int cmd_psclr(int transport, int argc, char *argv[])
850 {
851 uint8_t array[8];
852 uint16_t pskey, stores = CSR_STORES_PSRAM;
853 int i, err, reset = 0;
854
855 OPT_PSKEY(1, 1, &stores, &reset, NULL);
856
857 if (strncasecmp(argv[0], "0x", 2)) {
858 pskey = atoi(argv[0]);
859
860 for (i = 0; storage[i].pskey; i++) {
861 if (strcasecmp(storage[i].str, argv[0]))
862 continue;
863
864 pskey = storage[i].pskey;
865 break;
866 }
867 } else
868 pskey = strtol(argv[0] + 2, NULL, 16);
869
870 memset(array, 0, sizeof(array));
871 array[0] = pskey & 0xff;
872 array[1] = pskey >> 8;
873 array[2] = stores & 0xff;
874 array[3] = stores >> 8;
875
876 err = transport_write(transport, CSR_VARID_PS_CLR_STORES, array, 8);
877 if (err < 0)
878 return err;
879
880 if (reset)
881 transport_write(transport, CSR_VARID_WARM_RESET, NULL, 0);
882
883 return err;
884 }
885
cmd_pslist(int transport,int argc,char * argv[])886 static int cmd_pslist(int transport, int argc, char *argv[])
887 {
888 uint8_t array[8];
889 uint16_t pskey = 0x0000, length, stores = CSR_STORES_DEFAULT;
890 int err, reset = 0;
891
892 OPT_PSKEY(0, 0, &stores, &reset, NULL);
893
894 while (1) {
895 memset(array, 0, sizeof(array));
896 array[0] = pskey & 0xff;
897 array[1] = pskey >> 8;
898 array[2] = stores & 0xff;
899 array[3] = stores >> 8;
900
901 err = transport_read(transport, CSR_VARID_PS_NEXT, array, 8);
902 if (err < 0)
903 break;
904
905 pskey = array[4] + (array[5] << 8);
906 if (pskey == 0x0000)
907 break;
908
909 memset(array, 0, sizeof(array));
910 array[0] = pskey & 0xff;
911 array[1] = pskey >> 8;
912 array[2] = stores & 0xff;
913 array[3] = stores >> 8;
914
915 err = transport_read(transport, CSR_VARID_PS_SIZE, array, 8);
916 if (err < 0)
917 continue;
918
919 length = array[2] + (array[3] << 8);
920
921 printf("0x%04x - %s (%d bytes)\n", pskey,
922 csr_pskeytostr(pskey), length * 2);
923 }
924
925 if (reset)
926 transport_write(transport, CSR_VARID_WARM_RESET, NULL, 0);
927
928 return 0;
929 }
930
cmd_psread(int transport,int argc,char * argv[])931 static int cmd_psread(int transport, int argc, char *argv[])
932 {
933 uint8_t array[256];
934 uint16_t pskey = 0x0000, length, stores = CSR_STORES_DEFAULT;
935 char *str, val[7];
936 int i, err, reset = 0;
937
938 OPT_PSKEY(0, 0, &stores, &reset, NULL);
939
940 while (1) {
941 memset(array, 0, sizeof(array));
942 array[0] = pskey & 0xff;
943 array[1] = pskey >> 8;
944 array[2] = stores & 0xff;
945 array[3] = stores >> 8;
946
947 err = transport_read(transport, CSR_VARID_PS_NEXT, array, 8);
948 if (err < 0)
949 break;
950
951 pskey = array[4] + (array[5] << 8);
952 if (pskey == 0x0000)
953 break;
954
955 memset(array, 0, sizeof(array));
956 array[0] = pskey & 0xff;
957 array[1] = pskey >> 8;
958 array[2] = stores & 0xff;
959 array[3] = stores >> 8;
960
961 err = transport_read(transport, CSR_VARID_PS_SIZE, array, 8);
962 if (err < 0)
963 continue;
964
965 length = array[2] + (array[3] << 8);
966 if (length + 6 > (int) sizeof(array) / 2)
967 continue;
968
969 memset(array, 0, sizeof(array));
970 array[0] = pskey & 0xff;
971 array[1] = pskey >> 8;
972 array[2] = length & 0xff;
973 array[3] = length >> 8;
974 array[4] = stores & 0xff;
975 array[5] = stores >> 8;
976
977 err = transport_read(transport, CSR_VARID_PS, array, (length + 3) * 2);
978 if (err < 0)
979 continue;
980
981 str = csr_pskeytoval(pskey);
982 if (!strcasecmp(str, "UNKNOWN")) {
983 sprintf(val, "0x%04x", pskey);
984 str = NULL;
985 }
986
987 printf("// %s%s\n&%04x =", str ? "PSKEY_" : "",
988 str ? str : val, pskey);
989 for (i = 0; i < length; i++)
990 printf(" %02x%02x", array[(i * 2) + 7], array[(i * 2) + 6]);
991 printf("\n");
992 }
993
994 if (reset)
995 transport_write(transport, CSR_VARID_WARM_RESET, NULL, 0);
996
997 return 0;
998 }
999
cmd_psload(int transport,int argc,char * argv[])1000 static int cmd_psload(int transport, int argc, char *argv[])
1001 {
1002 uint8_t array[256];
1003 uint16_t pskey, length, size, stores = CSR_STORES_PSRAM;
1004 char *str, val[7];
1005 int err, reset = 0;
1006
1007 OPT_PSKEY(1, 1, &stores, &reset, NULL);
1008
1009 psr_read(argv[0]);
1010
1011 memset(array, 0, sizeof(array));
1012 size = sizeof(array) - 6;
1013
1014 while (psr_get(&pskey, array + 6, &size) == 0) {
1015 str = csr_pskeytoval(pskey);
1016 if (!strcasecmp(str, "UNKNOWN")) {
1017 sprintf(val, "0x%04x", pskey);
1018 str = NULL;
1019 }
1020
1021 printf("Loading %s%s ... ", str ? "PSKEY_" : "",
1022 str ? str : val);
1023 fflush(stdout);
1024
1025 length = size / 2;
1026
1027 array[0] = pskey & 0xff;
1028 array[1] = pskey >> 8;
1029 array[2] = length & 0xff;
1030 array[3] = length >> 8;
1031 array[4] = stores & 0xff;
1032 array[5] = stores >> 8;
1033
1034 err = transport_write(transport, CSR_VARID_PS, array, size + 6);
1035
1036 printf("%s\n", err < 0 ? "failed" : "done");
1037
1038 memset(array, 0, sizeof(array));
1039 size = sizeof(array) - 6;
1040 }
1041
1042 if (reset)
1043 transport_write(transport, CSR_VARID_WARM_RESET, NULL, 0);
1044
1045 return 0;
1046 }
1047
cmd_pscheck(int transport,int argc,char * argv[])1048 static int cmd_pscheck(int transport, int argc, char *argv[])
1049 {
1050 uint8_t array[256];
1051 uint16_t pskey, size;
1052 int i;
1053
1054 OPT_HELP(1, NULL);
1055
1056 psr_read(argv[0]);
1057
1058 while (psr_get(&pskey, array, &size) == 0) {
1059 printf("0x%04x =", pskey);
1060 for (i = 0; i < size; i++)
1061 printf(" 0x%02x", array[i]);
1062 printf("\n");
1063 }
1064
1065 return 0;
1066 }
1067
1068 static struct {
1069 char *str;
1070 int (*func)(int transport, int argc, char *argv[]);
1071 char *arg;
1072 char *doc;
1073 } commands[] = {
1074 { "builddef", cmd_builddef, "", "Get build definitions" },
1075 { "keylen", cmd_keylen, "<handle>", "Get current crypt key length" },
1076 { "clock", cmd_clock, "", "Get local Bluetooth clock" },
1077 { "rand", cmd_rand, "", "Get random number" },
1078 { "chiprev", cmd_chiprev, "", "Get chip revision" },
1079 { "buildname", cmd_buildname, "", "Get the full build name" },
1080 { "panicarg", cmd_panicarg, "", "Get panic code argument" },
1081 { "faultarg", cmd_faultarg, "", "Get fault code argument" },
1082 { "coldreset", cmd_coldreset, "", "Perform cold reset" },
1083 { "warmreset", cmd_warmreset, "", "Perform warm reset" },
1084 { "disabletx", cmd_disabletx, "", "Disable TX on the device" },
1085 { "enabletx", cmd_enabletx, "", "Enable TX on the device" },
1086 { "singlechan",cmd_singlechan,"<channel>", "Lock radio on specific channel" },
1087 { "hoppingon", cmd_hoppingon, "", "Revert to channel hopping" },
1088 { "rttxdata1", cmd_rttxdata1, "<freq> <level>", "TXData1 radio test" },
1089 { "radiotest", cmd_radiotest, "<freq> <level> <id>", "Run radio tests" },
1090 { "memtypes", cmd_memtypes, NULL, "Get memory types" },
1091 { "psget", cmd_psget, "<key>", "Get value for PS key" },
1092 { "psset", cmd_psset, "<key> <value>", "Set value for PS key" },
1093 { "psclr", cmd_psclr, "<key>", "Clear value for PS key" },
1094 { "pslist", cmd_pslist, NULL, "List all PS keys" },
1095 { "psread", cmd_psread, NULL, "Read all PS keys" },
1096 { "psload", cmd_psload, "<file>", "Load all PS keys from PSR file" },
1097 { "pscheck", cmd_pscheck, "<file>", "Check PSR file" },
1098 { NULL }
1099 };
1100
usage(void)1101 static void usage(void)
1102 {
1103 int i, pos = 0;
1104
1105 printf("bccmd - Utility for the CSR BCCMD interface\n\n");
1106 printf("Usage:\n"
1107 "\tbccmd [options] <command>\n\n");
1108
1109 printf("Options:\n"
1110 "\t-t <transport> Select the transport\n"
1111 "\t-d <device> Select the device\n"
1112 "\t-b <bcsp rate> Select the bcsp transfer rate\n"
1113 "\t-h, --help Display help\n"
1114 "\n");
1115
1116 printf("Transports:\n"
1117 "\tHCI USB BCSP H4 3WIRE\n\n");
1118
1119 printf("Commands:\n");
1120 for (i = 0; commands[i].str; i++)
1121 printf("\t%-10s %-20s\t%s\n", commands[i].str,
1122 commands[i].arg ? commands[i].arg : " ",
1123 commands[i].doc);
1124 printf("\n");
1125
1126 printf("Keys:\n\t");
1127 for (i = 0; storage[i].pskey; i++) {
1128 printf("%s ", storage[i].str);
1129 pos += strlen(storage[i].str) + 1;
1130 if (pos > 60) {
1131 printf("\n\t");
1132 pos = 0;
1133 }
1134 }
1135 printf("\n");
1136 }
1137
1138 static struct option main_options[] = {
1139 { "transport", 1, 0, 't' },
1140 { "device", 1, 0, 'd' },
1141 { "bcsprate", 1, 0, 'b'},
1142 { "help", 0, 0, 'h' },
1143 { 0, 0, 0, 0 }
1144 };
1145
main(int argc,char * argv[])1146 int main(int argc, char *argv[])
1147 {
1148 char *device = NULL;
1149 int i, err, opt, transport = CSR_TRANSPORT_HCI;
1150 speed_t bcsp_rate = B38400;
1151
1152 while ((opt=getopt_long(argc, argv, "+t:d:i:b:h", main_options, NULL)) != EOF) {
1153 switch (opt) {
1154 case 't':
1155 if (!strcasecmp(optarg, "hci"))
1156 transport = CSR_TRANSPORT_HCI;
1157 else if (!strcasecmp(optarg, "usb"))
1158 transport = CSR_TRANSPORT_USB;
1159 else if (!strcasecmp(optarg, "bcsp"))
1160 transport = CSR_TRANSPORT_BCSP;
1161 else if (!strcasecmp(optarg, "h4"))
1162 transport = CSR_TRANSPORT_H4;
1163 else if (!strcasecmp(optarg, "h5"))
1164 transport = CSR_TRANSPORT_3WIRE;
1165 else if (!strcasecmp(optarg, "3wire"))
1166 transport = CSR_TRANSPORT_3WIRE;
1167 else if (!strcasecmp(optarg, "twutl"))
1168 transport = CSR_TRANSPORT_3WIRE;
1169 else
1170 transport = CSR_TRANSPORT_UNKNOWN;
1171 break;
1172
1173 case 'd':
1174 case 'i':
1175 device = strdup(optarg);
1176 break;
1177 case 'b':
1178 switch (atoi(optarg)) {
1179 case 9600: bcsp_rate = B9600; break;
1180 case 19200: bcsp_rate = B19200; break;
1181 case 38400: bcsp_rate = B38400; break;
1182 case 57600: bcsp_rate = B57600; break;
1183 case 115200: bcsp_rate = B115200; break;
1184 case 230400: bcsp_rate = B230400; break;
1185 case 460800: bcsp_rate = B460800; break;
1186 case 500000: bcsp_rate = B500000; break;
1187 case 576000: bcsp_rate = B576000; break;
1188 case 921600: bcsp_rate = B921600; break;
1189 case 1000000: bcsp_rate = B1000000; break;
1190 case 1152000: bcsp_rate = B1152000; break;
1191 case 1500000: bcsp_rate = B1500000; break;
1192 case 2000000: bcsp_rate = B2000000; break;
1193 #ifdef B2500000
1194 case 2500000: bcsp_rate = B2500000; break;
1195 #endif
1196 #ifdef B3000000
1197 case 3000000: bcsp_rate = B3000000; break;
1198 #endif
1199 #ifdef B3500000
1200 case 3500000: bcsp_rate = B3500000; break;
1201 #endif
1202 #ifdef B4000000
1203 case 4000000: bcsp_rate = B4000000; break;
1204 #endif
1205 default:
1206 printf("Unknown BCSP baud rate specified, defaulting to 38400bps\n");
1207 bcsp_rate = B38400;
1208 }
1209 break;
1210 case 'h':
1211 default:
1212 usage();
1213 exit(0);
1214 }
1215 }
1216
1217 argc -= optind;
1218 argv += optind;
1219 optind = 0;
1220
1221 if (argc < 1) {
1222 usage();
1223 exit(1);
1224 }
1225
1226 if (transport_open(transport, device, bcsp_rate) < 0)
1227 exit(1);
1228
1229 free(device);
1230
1231 for (i = 0; commands[i].str; i++) {
1232 if (strcasecmp(commands[i].str, argv[0]))
1233 continue;
1234
1235 err = commands[i].func(transport, argc, argv);
1236
1237 transport_close(transport);
1238
1239 if (err < 0) {
1240 fprintf(stderr, "Can't execute command: %s (%d)\n",
1241 strerror(errno), errno);
1242 exit(1);
1243 }
1244
1245 exit(0);
1246 }
1247
1248 fprintf(stderr, "Unsupported command\n");
1249
1250 transport_close(transport);
1251
1252 exit(1);
1253 }
1254