From 799757ccf1d03c33c75bc597cd5ef77741dcb6a7 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Fri, 3 Jun 2011 09:17:04 +0000 Subject: Imported upstream 4.91 --- tools/bccmd.c | 1254 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1254 insertions(+) create mode 100644 tools/bccmd.c (limited to 'tools/bccmd.c') diff --git a/tools/bccmd.c b/tools/bccmd.c new file mode 100644 index 0000000..5cb9255 --- /dev/null +++ b/tools/bccmd.c @@ -0,0 +1,1254 @@ +/* + * + * BlueZ - Bluetooth protocol stack for Linux + * + * Copyright (C) 2004-2010 Marcel Holtmann + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "csr.h" + +#define CSR_TRANSPORT_UNKNOWN 0 +#define CSR_TRANSPORT_HCI 1 +#define CSR_TRANSPORT_USB 2 +#define CSR_TRANSPORT_BCSP 3 +#define CSR_TRANSPORT_H4 4 +#define CSR_TRANSPORT_3WIRE 5 + +#define CSR_STORES_PSI (0x0001) +#define CSR_STORES_PSF (0x0002) +#define CSR_STORES_PSROM (0x0004) +#define CSR_STORES_PSRAM (0x0008) +#define CSR_STORES_DEFAULT (CSR_STORES_PSI | CSR_STORES_PSF) + +#define CSR_TYPE_NULL 0 +#define CSR_TYPE_COMPLEX 1 +#define CSR_TYPE_UINT8 2 +#define CSR_TYPE_UINT16 3 +#define CSR_TYPE_UINT32 4 + +#define CSR_TYPE_ARRAY CSR_TYPE_COMPLEX +#define CSR_TYPE_BDADDR CSR_TYPE_COMPLEX + +static inline int transport_open(int transport, char *device, speed_t bcsp_rate) +{ + switch (transport) { + case CSR_TRANSPORT_HCI: + return csr_open_hci(device); +#ifdef HAVE_LIBUSB + case CSR_TRANSPORT_USB: + return csr_open_usb(device); +#endif + case CSR_TRANSPORT_BCSP: + return csr_open_bcsp(device, bcsp_rate); + case CSR_TRANSPORT_H4: + return csr_open_h4(device); + case CSR_TRANSPORT_3WIRE: + return csr_open_3wire(device); + default: + fprintf(stderr, "Unsupported transport\n"); + return -1; + } +} + +static inline int transport_read(int transport, uint16_t varid, uint8_t *value, uint16_t length) +{ + switch (transport) { + case CSR_TRANSPORT_HCI: + return csr_read_hci(varid, value, length); +#ifdef HAVE_LIBUSB + case CSR_TRANSPORT_USB: + return csr_read_usb(varid, value, length); +#endif + case CSR_TRANSPORT_BCSP: + return csr_read_bcsp(varid, value, length); + case CSR_TRANSPORT_H4: + return csr_read_h4(varid, value, length); + case CSR_TRANSPORT_3WIRE: + return csr_read_3wire(varid, value, length); + default: + errno = EOPNOTSUPP; + return -1; + } +} + +static inline int transport_write(int transport, uint16_t varid, uint8_t *value, uint16_t length) +{ + switch (transport) { + case CSR_TRANSPORT_HCI: + return csr_write_hci(varid, value, length); +#ifdef HAVE_LIBUSB + case CSR_TRANSPORT_USB: + return csr_write_usb(varid, value, length); +#endif + case CSR_TRANSPORT_BCSP: + return csr_write_bcsp(varid, value, length); + case CSR_TRANSPORT_H4: + return csr_write_h4(varid, value, length); + case CSR_TRANSPORT_3WIRE: + return csr_write_3wire(varid, value, length); + default: + errno = EOPNOTSUPP; + return -1; + } +} + +static inline void transport_close(int transport) +{ + switch (transport) { + case CSR_TRANSPORT_HCI: + csr_close_hci(); + break; +#ifdef HAVE_LIBUSB + case CSR_TRANSPORT_USB: + csr_close_usb(); + break; +#endif + case CSR_TRANSPORT_BCSP: + csr_close_bcsp(); + break; + case CSR_TRANSPORT_H4: + csr_close_h4(); + break; + case CSR_TRANSPORT_3WIRE: + csr_close_3wire(); + break; + } +} + +static struct { + uint16_t pskey; + int type; + int size; + char *str; +} storage[] = { + { CSR_PSKEY_BDADDR, CSR_TYPE_BDADDR, 8, "bdaddr" }, + { CSR_PSKEY_COUNTRYCODE, CSR_TYPE_UINT16, 0, "country" }, + { CSR_PSKEY_CLASSOFDEVICE, CSR_TYPE_UINT32, 0, "devclass" }, + { CSR_PSKEY_ENC_KEY_LMIN, CSR_TYPE_UINT16, 0, "keymin" }, + { CSR_PSKEY_ENC_KEY_LMAX, CSR_TYPE_UINT16, 0, "keymax" }, + { CSR_PSKEY_LOCAL_SUPPORTED_FEATURES, CSR_TYPE_ARRAY, 8, "features" }, + { CSR_PSKEY_LOCAL_SUPPORTED_COMMANDS, CSR_TYPE_ARRAY, 18, "commands" }, + { CSR_PSKEY_HCI_LMP_LOCAL_VERSION, CSR_TYPE_UINT16, 0, "version" }, + { CSR_PSKEY_LMP_REMOTE_VERSION, CSR_TYPE_UINT8, 0, "remver" }, + { CSR_PSKEY_HOSTIO_USE_HCI_EXTN, CSR_TYPE_UINT16, 0, "hciextn" }, + { CSR_PSKEY_HOSTIO_MAP_SCO_PCM, CSR_TYPE_UINT16, 0, "mapsco" }, + { CSR_PSKEY_UART_BAUDRATE, CSR_TYPE_UINT16, 0, "baudrate" }, + { CSR_PSKEY_HOST_INTERFACE, CSR_TYPE_UINT16, 0, "hostintf" }, + { CSR_PSKEY_ANA_FREQ, CSR_TYPE_UINT16, 0, "anafreq" }, + { CSR_PSKEY_ANA_FTRIM, CSR_TYPE_UINT16, 0, "anaftrim" }, + { CSR_PSKEY_USB_VENDOR_ID, CSR_TYPE_UINT16, 0, "usbvid" }, + { CSR_PSKEY_USB_PRODUCT_ID, CSR_TYPE_UINT16, 0, "usbpid" }, + { CSR_PSKEY_USB_DFU_PRODUCT_ID, CSR_TYPE_UINT16, 0, "dfupid" }, + { CSR_PSKEY_INITIAL_BOOTMODE, CSR_TYPE_UINT16, 0, "bootmode" }, + { 0x0000 }, +}; + +static char *storestostr(uint16_t stores) +{ + switch (stores) { + case 0x0000: + return "Default"; + case 0x0001: + return "psi"; + case 0x0002: + return "psf"; + case 0x0004: + return "psrom"; + case 0x0008: + return "psram"; + default: + return "Unknown"; + } +} + +static char *memorytostr(uint16_t type) +{ + switch (type) { + case 0x0000: + return "Flash memory"; + case 0x0001: + return "EEPROM"; + case 0x0002: + return "RAM (transient)"; + case 0x0003: + return "ROM (or \"read-only\" flash memory)"; + default: + return "Unknown"; + } +} + +#define OPT_RANGE(min, max) \ + if (argc < (min)) { errno = EINVAL; return -1; } \ + if (argc > (max)) { errno = E2BIG; return -1; } + +static struct option help_options[] = { + { "help", 0, 0, 'h' }, + { 0, 0, 0, 0 } +}; + +static int opt_help(int argc, char *argv[], int *help) +{ + int opt; + + while ((opt=getopt_long(argc, argv, "+h", help_options, NULL)) != EOF) { + switch (opt) { + case 'h': + if (help) + *help = 1; + break; + } + } + + return optind; +} + +#define OPT_HELP(range, help) \ + opt_help(argc, argv, (help)); \ + argc -= optind; argv += optind; optind = 0; \ + OPT_RANGE((range), (range)) + +static int cmd_builddef(int transport, int argc, char *argv[]) +{ + uint8_t array[8]; + uint16_t def = 0x0000, nextdef = 0x0000; + int err = 0; + + OPT_HELP(0, NULL); + + printf("Build definitions:\n"); + + while (1) { + memset(array, 0, sizeof(array)); + array[0] = def & 0xff; + array[1] = def >> 8; + + err = transport_read(transport, CSR_VARID_GET_NEXT_BUILDDEF, array, 8); + if (err < 0) { + errno = -err; + break; + } + + nextdef = array[2] | (array[3] << 8); + + if (nextdef == 0x0000) + break; + + def = nextdef; + + printf("0x%04x - %s\n", def, csr_builddeftostr(def)); + } + + return err; +} + +static int cmd_keylen(int transport, int argc, char *argv[]) +{ + uint8_t array[8]; + uint16_t handle, keylen; + int err; + + OPT_HELP(1, NULL); + + handle = atoi(argv[0]); + + memset(array, 0, sizeof(array)); + array[0] = handle & 0xff; + array[1] = handle >> 8; + + err = transport_read(transport, CSR_VARID_CRYPT_KEY_LENGTH, array, 8); + if (err < 0) { + errno = -err; + return -1; + } + + handle = array[0] | (array[1] << 8); + keylen = array[2] | (array[3] << 8); + + printf("Crypt key length: %d bit\n", keylen * 8); + + return 0; +} + +static int cmd_clock(int transport, int argc, char *argv[]) +{ + uint8_t array[8]; + uint32_t clock; + int err; + + OPT_HELP(0, NULL); + + memset(array, 0, sizeof(array)); + + err = transport_read(transport, CSR_VARID_BT_CLOCK, array, 8); + if (err < 0) { + errno = -err; + return -1; + } + + clock = array[2] | (array[3] << 8) | (array[0] << 16) | (array[1] << 24); + + printf("Bluetooth clock: 0x%04x (%d)\n", clock, clock); + + return 0; +} + +static int cmd_rand(int transport, int argc, char *argv[]) +{ + uint8_t array[8]; + uint16_t rand; + int err; + + OPT_HELP(0, NULL); + + memset(array, 0, sizeof(array)); + + err = transport_read(transport, CSR_VARID_RAND, array, 8); + if (err < 0) { + errno = -err; + return -1; + } + + rand = array[0] | (array[1] << 8); + + printf("Random number: 0x%02x (%d)\n", rand, rand); + + return 0; +} + +static int cmd_chiprev(int transport, int argc, char *argv[]) +{ + uint8_t array[8]; + uint16_t rev; + char *str; + int err; + + OPT_HELP(0, NULL); + + memset(array, 0, sizeof(array)); + + err = transport_read(transport, CSR_VARID_CHIPREV, array, 8); + if (err < 0) { + errno = -err; + return -1; + } + + rev = array[0] | (array[1] << 8); + + switch (rev) { + case 0x64: + str = "BC1 ES"; + break; + case 0x65: + str = "BC1"; + break; + case 0x89: + str = "BC2-External A"; + break; + case 0x8a: + str = "BC2-External B"; + break; + case 0x28: + str = "BC2-ROM"; + break; + case 0x43: + str = "BC3-Multimedia"; + break; + case 0x15: + str = "BC3-ROM"; + break; + case 0xe2: + str = "BC3-Flash"; + break; + case 0x26: + str = "BC4-External"; + break; + case 0x30: + str = "BC4-ROM"; + break; + default: + str = "NA"; + break; + } + + printf("Chip revision: 0x%04x (%s)\n", rev, str); + + return 0; +} + +static int cmd_buildname(int transport, int argc, char *argv[]) +{ + uint8_t array[130]; + char name[64]; + unsigned int i; + int err; + + OPT_HELP(0, NULL); + + memset(array, 0, sizeof(array)); + + err = transport_read(transport, CSR_VARID_READ_BUILD_NAME, array, 128); + if (err < 0) { + errno = -err; + return -1; + } + + for (i = 0; i < sizeof(name); i++) + name[i] = array[(i * 2) + 4]; + + printf("Build name: %s\n", name); + + return 0; +} + +static int cmd_panicarg(int transport, int argc, char *argv[]) +{ + uint8_t array[8]; + uint16_t error; + int err; + + OPT_HELP(0, NULL); + + memset(array, 0, sizeof(array)); + + err = transport_read(transport, CSR_VARID_PANIC_ARG, array, 8); + if (err < 0) { + errno = -err; + return -1; + } + + error = array[0] | (array[1] << 8); + + printf("Panic code: 0x%02x (%s)\n", error, + error < 0x100 ? "valid" : "invalid"); + + return 0; +} + +static int cmd_faultarg(int transport, int argc, char *argv[]) +{ + uint8_t array[8]; + uint16_t error; + int err; + + OPT_HELP(0, NULL); + + memset(array, 0, sizeof(array)); + + err = transport_read(transport, CSR_VARID_FAULT_ARG, array, 8); + if (err < 0) { + errno = -err; + return -1; + } + + error = array[0] | (array[1] << 8); + + printf("Fault code: 0x%02x (%s)\n", error, + error < 0x100 ? "valid" : "invalid"); + + return 0; +} + +static int cmd_coldreset(int transport, int argc, char *argv[]) +{ + return transport_write(transport, CSR_VARID_COLD_RESET, NULL, 0); +} + +static int cmd_warmreset(int transport, int argc, char *argv[]) +{ + return transport_write(transport, CSR_VARID_WARM_RESET, NULL, 0); +} + +static int cmd_disabletx(int transport, int argc, char *argv[]) +{ + return transport_write(transport, CSR_VARID_DISABLE_TX, NULL, 0); +} + +static int cmd_enabletx(int transport, int argc, char *argv[]) +{ + return transport_write(transport, CSR_VARID_ENABLE_TX, NULL, 0); +} + +static int cmd_singlechan(int transport, int argc, char *argv[]) +{ + uint8_t array[8]; + uint16_t channel; + + OPT_HELP(1, NULL); + + channel = atoi(argv[0]); + + if (channel > 2401 && channel < 2481) + channel -= 2402; + + if (channel > 78) { + errno = EINVAL; + return -1; + } + + memset(array, 0, sizeof(array)); + array[0] = channel & 0xff; + array[1] = channel >> 8; + + return transport_write(transport, CSR_VARID_SINGLE_CHAN, array, 8); +} + +static int cmd_hoppingon(int transport, int argc, char *argv[]) +{ + return transport_write(transport, CSR_VARID_HOPPING_ON, NULL, 0); +} + +static int cmd_rttxdata1(int transport, int argc, char *argv[]) +{ + uint8_t array[8]; + uint16_t freq, level; + + OPT_HELP(2, NULL); + + freq = atoi(argv[0]); + + if (!strncasecmp(argv[1], "0x", 2)) + level = strtol(argv[1], NULL, 16); + else + level = atoi(argv[1]); + + memset(array, 0, sizeof(array)); + array[0] = 0x04; + array[1] = 0x00; + array[2] = freq & 0xff; + array[3] = freq >> 8; + array[4] = level & 0xff; + array[5] = level >> 8; + + return transport_write(transport, CSR_VARID_RADIOTEST, array, 8); +} + +static int cmd_radiotest(int transport, int argc, char *argv[]) +{ + uint8_t array[8]; + uint16_t freq, level, test; + + OPT_HELP(3, NULL); + + freq = atoi(argv[0]); + + if (!strncasecmp(argv[1], "0x", 2)) + level = strtol(argv[1], NULL, 16); + else + level = atoi(argv[1]); + + test = atoi(argv[2]); + + memset(array, 0, sizeof(array)); + array[0] = test & 0xff; + array[1] = test >> 8; + array[2] = freq & 0xff; + array[3] = freq >> 8; + array[4] = level & 0xff; + array[5] = level >> 8; + + return transport_write(transport, CSR_VARID_RADIOTEST, array, 8); +} + +static int cmd_memtypes(int transport, int argc, char *argv[]) +{ + uint8_t array[8]; + uint16_t type, stores[4] = { 0x0001, 0x0002, 0x0004, 0x0008 }; + int i, err; + + OPT_HELP(0, NULL); + + for (i = 0; i < 4; i++) { + memset(array, 0, sizeof(array)); + array[0] = stores[i] & 0xff; + array[1] = stores[i] >> 8; + + err = transport_read(transport, CSR_VARID_PS_MEMORY_TYPE, array, 8); + if (err < 0) + continue; + + type = array[2] + (array[3] << 8); + + printf("%s (0x%04x) = %s (%d)\n", storestostr(stores[i]), + stores[i], memorytostr(type), type); + } + + return 0; +} + +static struct option pskey_options[] = { + { "stores", 1, 0, 's' }, + { "reset", 0, 0, 'r' }, + { "help", 0, 0, 'h' }, + { 0, 0, 0, 0 } +}; + +static int opt_pskey(int argc, char *argv[], uint16_t *stores, int *reset, int *help) +{ + int opt; + + while ((opt=getopt_long(argc, argv, "+s:rh", pskey_options, NULL)) != EOF) { + switch (opt) { + case 's': + if (!stores) + break; + if (!strcasecmp(optarg, "default")) + *stores = 0x0000; + else if (!strcasecmp(optarg, "implementation")) + *stores = 0x0001; + else if (!strcasecmp(optarg, "factory")) + *stores = 0x0002; + else if (!strcasecmp(optarg, "rom")) + *stores = 0x0004; + else if (!strcasecmp(optarg, "ram")) + *stores = 0x0008; + else if (!strcasecmp(optarg, "psi")) + *stores = 0x0001; + else if (!strcasecmp(optarg, "psf")) + *stores = 0x0002; + else if (!strcasecmp(optarg, "psrom")) + *stores = 0x0004; + else if (!strcasecmp(optarg, "psram")) + *stores = 0x0008; + else if (!strncasecmp(optarg, "0x", 2)) + *stores = strtol(optarg, NULL, 16); + else + *stores = atoi(optarg); + break; + + case 'r': + if (reset) + *reset = 1; + break; + + case 'h': + if (help) + *help = 1; + break; + } + } + + return optind; +} + +#define OPT_PSKEY(min, max, stores, reset, help) \ + opt_pskey(argc, argv, (stores), (reset), (help)); \ + argc -= optind; argv += optind; optind = 0; \ + OPT_RANGE((min), (max)) + +static int cmd_psget(int transport, int argc, char *argv[]) +{ + uint8_t array[128]; + uint16_t pskey, length, value, stores = CSR_STORES_DEFAULT; + uint32_t val32; + int i, err, reset = 0; + + memset(array, 0, sizeof(array)); + + OPT_PSKEY(1, 1, &stores, &reset, NULL); + + if (strncasecmp(argv[0], "0x", 2)) { + pskey = atoi(argv[0]); + + for (i = 0; storage[i].pskey; i++) { + if (strcasecmp(storage[i].str, argv[0])) + continue; + + pskey = storage[i].pskey; + break; + } + } else + pskey = strtol(argv[0] + 2, NULL, 16); + + memset(array, 0, sizeof(array)); + array[0] = pskey & 0xff; + array[1] = pskey >> 8; + array[2] = stores & 0xff; + array[3] = stores >> 8; + + err = transport_read(transport, CSR_VARID_PS_SIZE, array, 8); + if (err < 0) + return err; + + length = array[2] + (array[3] << 8); + if (length + 6 > (int) sizeof(array) / 2) + return -EIO; + + memset(array, 0, sizeof(array)); + array[0] = pskey & 0xff; + array[1] = pskey >> 8; + array[2] = length & 0xff; + array[3] = length >> 8; + array[4] = stores & 0xff; + array[5] = stores >> 8; + + err = transport_read(transport, CSR_VARID_PS, array, (length + 3) * 2); + if (err < 0) + return err; + + switch (length) { + case 1: + value = array[6] | (array[7] << 8); + printf("%s: 0x%04x (%d)\n", csr_pskeytostr(pskey), value, value); + break; + + case 2: + val32 = array[8] | (array[9] << 8) | (array[6] << 16) | (array[7] << 24); + printf("%s: 0x%08x (%d)\n", csr_pskeytostr(pskey), val32, val32); + break; + + default: + printf("%s:", csr_pskeytostr(pskey)); + for (i = 0; i < length; i++) + printf(" 0x%02x%02x", array[(i * 2) + 6], array[(i * 2) + 7]); + printf("\n"); + break; + } + + if (reset) + transport_write(transport, CSR_VARID_WARM_RESET, NULL, 0); + + return err; +} + +static int cmd_psset(int transport, int argc, char *argv[]) +{ + uint8_t array[128]; + uint16_t pskey, length, value, stores = CSR_STORES_PSRAM; + uint32_t val32; + int i, err, reset = 0; + + memset(array, 0, sizeof(array)); + + OPT_PSKEY(2, 81, &stores, &reset, NULL); + + if (strncasecmp(argv[0], "0x", 2)) { + pskey = atoi(argv[0]); + + for (i = 0; storage[i].pskey; i++) { + if (strcasecmp(storage[i].str, argv[0])) + continue; + + pskey = storage[i].pskey; + break; + } + } else + pskey = strtol(argv[0] + 2, NULL, 16); + + memset(array, 0, sizeof(array)); + array[0] = pskey & 0xff; + array[1] = pskey >> 8; + array[2] = stores & 0xff; + array[3] = stores >> 8; + + err = transport_read(transport, CSR_VARID_PS_SIZE, array, 8); + if (err < 0) + return err; + + length = array[2] + (array[3] << 8); + if (length + 6 > (int) sizeof(array) / 2) + return -EIO; + + memset(array, 0, sizeof(array)); + array[0] = pskey & 0xff; + array[1] = pskey >> 8; + array[2] = length & 0xff; + array[3] = length >> 8; + array[4] = stores & 0xff; + array[5] = stores >> 8; + + argc--; + argv++; + + switch (length) { + case 1: + if (argc != 1) { + errno = E2BIG; + return -1; + } + + if (!strncasecmp(argv[0], "0x", 2)) + value = strtol(argv[0] + 2, NULL, 16); + else + value = atoi(argv[0]); + + array[6] = value & 0xff; + array[7] = value >> 8; + break; + + case 2: + if (argc != 1) { + errno = E2BIG; + return -1; + } + + if (!strncasecmp(argv[0], "0x", 2)) + val32 = strtol(argv[0] + 2, NULL, 16); + else + val32 = atoi(argv[0]); + + array[6] = (val32 & 0xff0000) >> 16; + array[7] = val32 >> 24; + array[8] = val32 & 0xff; + array[9] = (val32 & 0xff00) >> 8; + break; + + default: + if (argc != length * 2) { + errno = EINVAL; + return -1; + } + + for (i = 0; i < length * 2; i++) + if (!strncasecmp(argv[0], "0x", 2)) + array[i + 6] = strtol(argv[i] + 2, NULL, 16); + else + array[i + 6] = atoi(argv[i]); + break; + } + + err = transport_write(transport, CSR_VARID_PS, array, (length + 3) * 2); + if (err < 0) + return err; + + if (reset) + transport_write(transport, CSR_VARID_WARM_RESET, NULL, 0); + + return err; +} + +static int cmd_psclr(int transport, int argc, char *argv[]) +{ + uint8_t array[8]; + uint16_t pskey, stores = CSR_STORES_PSRAM; + int i, err, reset = 0; + + OPT_PSKEY(1, 1, &stores, &reset, NULL); + + if (strncasecmp(argv[0], "0x", 2)) { + pskey = atoi(argv[0]); + + for (i = 0; storage[i].pskey; i++) { + if (strcasecmp(storage[i].str, argv[0])) + continue; + + pskey = storage[i].pskey; + break; + } + } else + pskey = strtol(argv[0] + 2, NULL, 16); + + memset(array, 0, sizeof(array)); + array[0] = pskey & 0xff; + array[1] = pskey >> 8; + array[2] = stores & 0xff; + array[3] = stores >> 8; + + err = transport_write(transport, CSR_VARID_PS_CLR_STORES, array, 8); + if (err < 0) + return err; + + if (reset) + transport_write(transport, CSR_VARID_WARM_RESET, NULL, 0); + + return err; +} + +static int cmd_pslist(int transport, int argc, char *argv[]) +{ + uint8_t array[8]; + uint16_t pskey = 0x0000, length, stores = CSR_STORES_DEFAULT; + int err, reset = 0; + + OPT_PSKEY(0, 0, &stores, &reset, NULL); + + while (1) { + memset(array, 0, sizeof(array)); + array[0] = pskey & 0xff; + array[1] = pskey >> 8; + array[2] = stores & 0xff; + array[3] = stores >> 8; + + err = transport_read(transport, CSR_VARID_PS_NEXT, array, 8); + if (err < 0) + break; + + pskey = array[4] + (array[5] << 8); + if (pskey == 0x0000) + break; + + memset(array, 0, sizeof(array)); + array[0] = pskey & 0xff; + array[1] = pskey >> 8; + array[2] = stores & 0xff; + array[3] = stores >> 8; + + err = transport_read(transport, CSR_VARID_PS_SIZE, array, 8); + if (err < 0) + continue; + + length = array[2] + (array[3] << 8); + + printf("0x%04x - %s (%d bytes)\n", pskey, + csr_pskeytostr(pskey), length * 2); + } + + if (reset) + transport_write(transport, CSR_VARID_WARM_RESET, NULL, 0); + + return 0; +} + +static int cmd_psread(int transport, int argc, char *argv[]) +{ + uint8_t array[256]; + uint16_t pskey = 0x0000, length, stores = CSR_STORES_DEFAULT; + char *str, val[7]; + int i, err, reset = 0; + + OPT_PSKEY(0, 0, &stores, &reset, NULL); + + while (1) { + memset(array, 0, sizeof(array)); + array[0] = pskey & 0xff; + array[1] = pskey >> 8; + array[2] = stores & 0xff; + array[3] = stores >> 8; + + err = transport_read(transport, CSR_VARID_PS_NEXT, array, 8); + if (err < 0) + break; + + pskey = array[4] + (array[5] << 8); + if (pskey == 0x0000) + break; + + memset(array, 0, sizeof(array)); + array[0] = pskey & 0xff; + array[1] = pskey >> 8; + array[2] = stores & 0xff; + array[3] = stores >> 8; + + err = transport_read(transport, CSR_VARID_PS_SIZE, array, 8); + if (err < 0) + continue; + + length = array[2] + (array[3] << 8); + if (length + 6 > (int) sizeof(array) / 2) + continue; + + memset(array, 0, sizeof(array)); + array[0] = pskey & 0xff; + array[1] = pskey >> 8; + array[2] = length & 0xff; + array[3] = length >> 8; + array[4] = stores & 0xff; + array[5] = stores >> 8; + + err = transport_read(transport, CSR_VARID_PS, array, (length + 3) * 2); + if (err < 0) + continue; + + str = csr_pskeytoval(pskey); + if (!strcasecmp(str, "UNKNOWN")) { + sprintf(val, "0x%04x", pskey); + str = NULL; + } + + printf("// %s%s\n&%04x =", str ? "PSKEY_" : "", + str ? str : val, pskey); + for (i = 0; i < length; i++) + printf(" %02x%02x", array[(i * 2) + 7], array[(i * 2) + 6]); + printf("\n"); + } + + if (reset) + transport_write(transport, CSR_VARID_WARM_RESET, NULL, 0); + + return 0; +} + +static int cmd_psload(int transport, int argc, char *argv[]) +{ + uint8_t array[256]; + uint16_t pskey, length, size, stores = CSR_STORES_PSRAM; + char *str, val[7]; + int err, reset = 0; + + OPT_PSKEY(1, 1, &stores, &reset, NULL); + + psr_read(argv[0]); + + memset(array, 0, sizeof(array)); + size = sizeof(array) - 6; + + while (psr_get(&pskey, array + 6, &size) == 0) { + str = csr_pskeytoval(pskey); + if (!strcasecmp(str, "UNKNOWN")) { + sprintf(val, "0x%04x", pskey); + str = NULL; + } + + printf("Loading %s%s ... ", str ? "PSKEY_" : "", + str ? str : val); + fflush(stdout); + + length = size / 2; + + array[0] = pskey & 0xff; + array[1] = pskey >> 8; + array[2] = length & 0xff; + array[3] = length >> 8; + array[4] = stores & 0xff; + array[5] = stores >> 8; + + err = transport_write(transport, CSR_VARID_PS, array, size + 6); + + printf("%s\n", err < 0 ? "failed" : "done"); + + memset(array, 0, sizeof(array)); + size = sizeof(array) - 6; + } + + if (reset) + transport_write(transport, CSR_VARID_WARM_RESET, NULL, 0); + + return 0; +} + +static int cmd_pscheck(int transport, int argc, char *argv[]) +{ + uint8_t array[256]; + uint16_t pskey, size; + int i; + + OPT_HELP(1, NULL); + + psr_read(argv[0]); + + while (psr_get(&pskey, array, &size) == 0) { + printf("0x%04x =", pskey); + for (i = 0; i < size; i++) + printf(" 0x%02x", array[i]); + printf("\n"); + } + + return 0; +} + +static struct { + char *str; + int (*func)(int transport, int argc, char *argv[]); + char *arg; + char *doc; +} commands[] = { + { "builddef", cmd_builddef, "", "Get build definitions" }, + { "keylen", cmd_keylen, "", "Get current crypt key length" }, + { "clock", cmd_clock, "", "Get local Bluetooth clock" }, + { "rand", cmd_rand, "", "Get random number" }, + { "chiprev", cmd_chiprev, "", "Get chip revision" }, + { "buildname", cmd_buildname, "", "Get the full build name" }, + { "panicarg", cmd_panicarg, "", "Get panic code argument" }, + { "faultarg", cmd_faultarg, "", "Get fault code argument" }, + { "coldreset", cmd_coldreset, "", "Perform cold reset" }, + { "warmreset", cmd_warmreset, "", "Perform warm reset" }, + { "disabletx", cmd_disabletx, "", "Disable TX on the device" }, + { "enabletx", cmd_enabletx, "", "Enable TX on the device" }, + { "singlechan",cmd_singlechan,"", "Lock radio on specific channel" }, + { "hoppingon", cmd_hoppingon, "", "Revert to channel hopping" }, + { "rttxdata1", cmd_rttxdata1, " ", "TXData1 radio test" }, + { "radiotest", cmd_radiotest, " ", "Run radio tests" }, + { "memtypes", cmd_memtypes, NULL, "Get memory types" }, + { "psget", cmd_psget, "", "Get value for PS key" }, + { "psset", cmd_psset, " ", "Set value for PS key" }, + { "psclr", cmd_psclr, "", "Clear value for PS key" }, + { "pslist", cmd_pslist, NULL, "List all PS keys" }, + { "psread", cmd_psread, NULL, "Read all PS keys" }, + { "psload", cmd_psload, "", "Load all PS keys from PSR file" }, + { "pscheck", cmd_pscheck, "", "Check PSR file" }, + { NULL } +}; + +static void usage(void) +{ + int i, pos = 0; + + printf("bccmd - Utility for the CSR BCCMD interface\n\n"); + printf("Usage:\n" + "\tbccmd [options] \n\n"); + + printf("Options:\n" + "\t-t Select the transport\n" + "\t-d Select the device\n" + "\t-b Select the bcsp transfer rate\n" + "\t-h, --help Display help\n" + "\n"); + + printf("Transports:\n" + "\tHCI USB BCSP H4 3WIRE\n\n"); + + printf("Commands:\n"); + for (i = 0; commands[i].str; i++) + printf("\t%-10s %-20s\t%s\n", commands[i].str, + commands[i].arg ? commands[i].arg : " ", + commands[i].doc); + printf("\n"); + + printf("Keys:\n\t"); + for (i = 0; storage[i].pskey; i++) { + printf("%s ", storage[i].str); + pos += strlen(storage[i].str) + 1; + if (pos > 60) { + printf("\n\t"); + pos = 0; + } + } + printf("\n"); +} + +static struct option main_options[] = { + { "transport", 1, 0, 't' }, + { "device", 1, 0, 'd' }, + { "bcsprate", 1, 0, 'b'}, + { "help", 0, 0, 'h' }, + { 0, 0, 0, 0 } +}; + +int main(int argc, char *argv[]) +{ + char *device = NULL; + int i, err, opt, transport = CSR_TRANSPORT_HCI; + speed_t bcsp_rate = B38400; + + while ((opt=getopt_long(argc, argv, "+t:d:i:b:h", main_options, NULL)) != EOF) { + switch (opt) { + case 't': + if (!strcasecmp(optarg, "hci")) + transport = CSR_TRANSPORT_HCI; + else if (!strcasecmp(optarg, "usb")) + transport = CSR_TRANSPORT_USB; + else if (!strcasecmp(optarg, "bcsp")) + transport = CSR_TRANSPORT_BCSP; + else if (!strcasecmp(optarg, "h4")) + transport = CSR_TRANSPORT_H4; + else if (!strcasecmp(optarg, "h5")) + transport = CSR_TRANSPORT_3WIRE; + else if (!strcasecmp(optarg, "3wire")) + transport = CSR_TRANSPORT_3WIRE; + else if (!strcasecmp(optarg, "twutl")) + transport = CSR_TRANSPORT_3WIRE; + else + transport = CSR_TRANSPORT_UNKNOWN; + break; + + case 'd': + case 'i': + device = strdup(optarg); + break; + case 'b': + switch (atoi(optarg)) { + case 9600: bcsp_rate = B9600; break; + case 19200: bcsp_rate = B19200; break; + case 38400: bcsp_rate = B38400; break; + case 57600: bcsp_rate = B57600; break; + case 115200: bcsp_rate = B115200; break; + case 230400: bcsp_rate = B230400; break; + case 460800: bcsp_rate = B460800; break; + case 500000: bcsp_rate = B500000; break; + case 576000: bcsp_rate = B576000; break; + case 921600: bcsp_rate = B921600; break; + case 1000000: bcsp_rate = B1000000; break; + case 1152000: bcsp_rate = B1152000; break; + case 1500000: bcsp_rate = B1500000; break; + case 2000000: bcsp_rate = B2000000; break; +#ifdef B2500000 + case 2500000: bcsp_rate = B2500000; break; +#endif +#ifdef B3000000 + case 3000000: bcsp_rate = B3000000; break; +#endif +#ifdef B3500000 + case 3500000: bcsp_rate = B3500000; break; +#endif +#ifdef B4000000 + case 4000000: bcsp_rate = B4000000; break; +#endif + default: + printf("Unknown BCSP baud rate specified, defaulting to 38400bps\n"); + bcsp_rate = B38400; + } + break; + case 'h': + default: + usage(); + exit(0); + } + } + + argc -= optind; + argv += optind; + optind = 0; + + if (argc < 1) { + usage(); + exit(1); + } + + if (transport_open(transport, device, bcsp_rate) < 0) + exit(1); + + if (device) + free(device); + + for (i = 0; commands[i].str; i++) { + if (strcasecmp(commands[i].str, argv[0])) + continue; + + err = commands[i].func(transport, argc, argv); + + transport_close(transport); + + if (err < 0) { + fprintf(stderr, "Can't execute command: %s (%d)\n", + strerror(errno), errno); + exit(1); + } + + exit(0); + } + + fprintf(stderr, "Unsupported command\n"); + + transport_close(transport); + + exit(1); +} -- cgit v1.2.3