Home | History | Annotate | Download | only in tools
      1 /*
      2  *
      3  *  BlueZ - Bluetooth protocol stack for Linux
      4  *
      5  *  Copyright (C) 2004-2010  Marcel Holtmann <marcel (at) 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 
     62 static inline int transport_open(int transport, char *device)
     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);
     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 
     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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
   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 
   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 
   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-h, --help         Display help\n"
   1113 		"\n");
   1114 
   1115 	printf("Transports:\n"
   1116 		"\tHCI USB BCSP H4 3WIRE\n\n");
   1117 
   1118 	printf("Commands:\n");
   1119 	for (i = 0; commands[i].str; i++)
   1120 		printf("\t%-10s %-20s\t%s\n", commands[i].str,
   1121 		commands[i].arg ? commands[i].arg : " ",
   1122 		commands[i].doc);
   1123 	printf("\n");
   1124 
   1125 	printf("Keys:\n\t");
   1126 	for (i = 0; storage[i].pskey; i++) {
   1127 		printf("%s ", storage[i].str);
   1128 		pos += strlen(storage[i].str) + 1;
   1129 		if (pos > 60) {
   1130 			printf("\n\t");
   1131 			pos = 0;
   1132 		}
   1133 	}
   1134 	printf("\n");
   1135 }
   1136 
   1137 static struct option main_options[] = {
   1138 	{ "transport",	1, 0, 't' },
   1139 	{ "device",	1, 0, 'd' },
   1140 	{ "help",	0, 0, 'h' },
   1141 	{ 0, 0, 0, 0 }
   1142 };
   1143 
   1144 int main(int argc, char *argv[])
   1145 {
   1146 	char *device = NULL;
   1147 	int i, err, opt, transport = CSR_TRANSPORT_HCI;
   1148 
   1149 	while ((opt=getopt_long(argc, argv, "+t:d:i:h", main_options, NULL)) != EOF) {
   1150 		switch (opt) {
   1151 		case 't':
   1152 			if (!strcasecmp(optarg, "hci"))
   1153 				transport = CSR_TRANSPORT_HCI;
   1154 			else if (!strcasecmp(optarg, "usb"))
   1155 				transport = CSR_TRANSPORT_USB;
   1156 			else if (!strcasecmp(optarg, "bcsp"))
   1157 				transport = CSR_TRANSPORT_BCSP;
   1158 			else if (!strcasecmp(optarg, "h4"))
   1159 				transport = CSR_TRANSPORT_H4;
   1160 			else if (!strcasecmp(optarg, "h5"))
   1161 				transport = CSR_TRANSPORT_3WIRE;
   1162 			else if (!strcasecmp(optarg, "3wire"))
   1163 				transport = CSR_TRANSPORT_3WIRE;
   1164 			else if (!strcasecmp(optarg, "twutl"))
   1165 				transport = CSR_TRANSPORT_3WIRE;
   1166 			else
   1167 				transport = CSR_TRANSPORT_UNKNOWN;
   1168 			break;
   1169 
   1170 		case 'd':
   1171 		case 'i':
   1172 			device = strdup(optarg);
   1173 			break;
   1174 
   1175 		case 'h':
   1176 		default:
   1177 			usage();
   1178 			exit(0);
   1179 		}
   1180 	}
   1181 
   1182 	argc -= optind;
   1183 	argv += optind;
   1184 	optind = 0;
   1185 
   1186 	if (argc < 1) {
   1187 		usage();
   1188 		exit(1);
   1189 	}
   1190 
   1191 	if (transport_open(transport, device) < 0)
   1192 		exit(1);
   1193 
   1194 	if (device)
   1195 		free(device);
   1196 
   1197 	for (i = 0; commands[i].str; i++) {
   1198 		if (strcasecmp(commands[i].str, argv[0]))
   1199 			continue;
   1200 
   1201 		err = commands[i].func(transport, argc, argv);
   1202 
   1203 		transport_close(transport);
   1204 
   1205 		if (err < 0) {
   1206 			fprintf(stderr, "Can't execute command: %s (%d)\n",
   1207 							strerror(errno), errno);
   1208 			exit(1);
   1209 		}
   1210 
   1211 		exit(0);
   1212 	}
   1213 
   1214 	fprintf(stderr, "Unsupported command\n");
   1215 
   1216 	transport_close(transport);
   1217 
   1218 	exit(1);
   1219 }
   1220