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