From 2ba0839002159cd293bb1a3d85645f04010cf33b Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Thu, 10 Nov 2005 20:23:47 +0000 Subject: Add USB transport to the bccmd utility --- acinclude.m4 | 2 +- tools/Makefile.am | 4 +- tools/bccmd.c | 465 +++++++++++++++++++++++++++++------------------------- tools/csr.c | 4 +- tools/csr.h | 12 +- tools/csr_hci.c | 160 +++++++++++++++++++ tools/csr_usb.c | 173 ++++++++++++++++++++ 7 files changed, 597 insertions(+), 223 deletions(-) create mode 100644 tools/csr_hci.c create mode 100644 tools/csr_usb.c diff --git a/acinclude.m4 b/acinclude.m4 index 65ae27b3..8334785c 100644 --- a/acinclude.m4 +++ b/acinclude.m4 @@ -410,7 +410,7 @@ AC_DEFUN([AC_ARG_BLUEZ], [ AM_CONDITIONAL(CUPS, test "${cups_enable}" = "yes") AM_CONDITIONAL(PCMCIA, test "${pcmcia_enable}" = "yes") AM_CONDITIONAL(INITSCRIPTS, test "${initscripts_enable}" = "yes") - AM_CONDITIONAL(BCCMD, test "${bccmd_enable}" = "yes") + AM_CONDITIONAL(BCCMD, test "${bccmd_enable}" = "yes" && test "${usb_found}" = "yes") AM_CONDITIONAL(AVCTRL, test "${avctrl_enable}" = "yes" && test "${usb_found}" = "yes") AM_CONDITIONAL(HID2HCI, test "${hid2hci_enable}" = "yes" && test "${usb_found}" = "yes") AM_CONDITIONAL(DFUTOOL, test "${dfutool_enable}" = "yes" && test "${usb_found}" = "yes") diff --git a/tools/Makefile.am b/tools/Makefile.am index 238a2df1..9d7065b2 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -52,8 +52,8 @@ ciptool_LDADD = @BLUEZ_LIBS@ ppporc_LDADD = @BLUEZ_LIBS@ if BCCMD -bccmd_SOURCES = bccmd.c csr.h csr.c -bccmd_LDADD = @BLUEZ_LIBS@ +bccmd_SOURCES = bccmd.c csr.h csr.c csr_hci.c csr_usb.c +bccmd_LDADD = @USB_LIBS@ @BLUEZ_LIBS@ endif if AVCTRL diff --git a/tools/bccmd.c b/tools/bccmd.c index 357620f5..f39686eb 100644 --- a/tools/bccmd.c +++ b/tools/bccmd.c @@ -59,7 +59,56 @@ #define CSR_TYPE_ARRAY CSR_TYPE_COMPLEX #define CSR_TYPE_BDADDR CSR_TYPE_COMPLEX -static uint16_t seqnum = 0x0000; +static inline int transport_open(int transport, char *device) +{ + switch (transport) { + case CSR_TRANSPORT_HCI: + return csr_open_hci(device); + case CSR_TRANSPORT_USB: + return csr_open_usb(device); + default: + fprintf(stderr, "Unsupported transport\n"); + return -1; + } +} + +static inline void transport_close(int transport) +{ + switch (transport) { + case CSR_TRANSPORT_HCI: + csr_close_hci(); + break; + case CSR_TRANSPORT_USB: + csr_close_usb(); + break; + } +} + +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); + case CSR_TRANSPORT_USB: + return csr_read_usb(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); + case CSR_TRANSPORT_USB: + return csr_write_usb(varid, value, length); + default: + errno = EOPNOTSUPP; + return -1; + } +} static struct { uint16_t pskey; @@ -89,20 +138,6 @@ static struct { { 0x0000 }, }; -static int pskey_size(uint16_t pskey) -{ - switch (pskey) { - case CSR_PSKEY_BDADDR: - return 8; - case CSR_PSKEY_LOCAL_SUPPORTED_FEATURES: - return 8; - case CSR_PSKEY_LOCAL_SUPPORTED_COMMANDS: - return 18; - default: - return 64; - } -} - static char *storestostr(uint16_t stores) { switch (stores) { @@ -167,9 +202,9 @@ static int opt_help(int argc, char *argv[], int *help) argc -= optind; argv += optind; optind = 0; \ OPT_RANGE((range)) -static int cmd_builddef(int dd, int argc, char *argv[]) +static int cmd_builddef(int transport, int argc, char *argv[]) { - uint8_t buf[8]; + uint8_t array[8]; uint16_t def = 0x0000, nextdef = 0x0000; int err = 0; @@ -178,18 +213,17 @@ static int cmd_builddef(int dd, int argc, char *argv[]) printf("Build definitions:\n"); while (1) { - memset(buf, 0, sizeof(buf)); - buf[0] = def & 0xff; - buf[1] = def >> 8; + memset(array, 0, sizeof(array)); + array[0] = def & 0xff; + array[1] = def >> 8; - err = csr_read_varid_complex(dd, seqnum++, - CSR_VARID_GET_NEXT_BUILDDEF, buf, sizeof(buf)); + err = transport_read(transport, CSR_VARID_GET_NEXT_BUILDDEF, array, 8); if (err < 0) { errno = -err; break; } - nextdef = buf[2] | (buf[3] << 8); + nextdef = array[2] | (array[3] << 8); if (nextdef == 0x0000) break; @@ -202,9 +236,9 @@ static int cmd_builddef(int dd, int argc, char *argv[]) return err; } -static int cmd_keylen(int dd, int argc, char *argv[]) +static int cmd_keylen(int transport, int argc, char *argv[]) { - uint8_t buf[8]; + uint8_t array[8]; uint16_t handle, keylen; int err; @@ -212,120 +246,139 @@ static int cmd_keylen(int dd, int argc, char *argv[]) handle = atoi(argv[0]); - memset(buf, 0, sizeof(buf)); - buf[0] = handle & 0xff; - buf[1] = handle >> 8; + memset(array, 0, sizeof(array)); + array[0] = handle & 0xff; + array[1] = handle >> 8; - err = csr_read_varid_complex(dd, seqnum++, - CSR_VARID_CRYPT_KEY_LENGTH, buf, sizeof(buf)); + err = transport_read(transport, CSR_VARID_CRYPT_KEY_LENGTH, array, 8); if (err < 0) { errno = -err; return -1; } - handle = buf[0] | (buf[1] << 8); - keylen = buf[2] | (buf[3] << 8); + 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 dd, int argc, char *argv[]) +static int cmd_clock(int transport, int argc, char *argv[]) { - uint32_t clock = 0; + uint8_t array[8]; + uint32_t clock; int err; OPT_HELP(0, NULL); - err = csr_read_varid_uint32(dd, seqnum++, CSR_VARID_BT_CLOCK, &clock); + 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 dd, int argc, char *argv[]) +static int cmd_rand(int transport, int argc, char *argv[]) { - uint16_t rand = 0; + uint8_t array[8]; + uint16_t rand; int err; OPT_HELP(0, NULL); - err = csr_read_varid_uint16(dd, seqnum++, CSR_VARID_RAND, &rand); + 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_panicarg(int dd, int argc, char *argv[]) +static int cmd_panicarg(int transport, int argc, char *argv[]) { - uint16_t error = 0; + uint8_t array[8]; + uint16_t error; int err; OPT_HELP(0, NULL); - err = csr_read_varid_uint16(dd, seqnum++, CSR_VARID_PANIC_ARG, &error); + 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 dd, int argc, char *argv[]) +static int cmd_faultarg(int transport, int argc, char *argv[]) { - uint16_t error = 0; + uint8_t array[8]; + uint16_t error; int err; OPT_HELP(0, NULL); - err = csr_read_varid_uint16(dd, seqnum++, CSR_VARID_FAULT_ARG, &error); + 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 dd, int argc, char *argv[]) +static int cmd_coldreset(int transport, int argc, char *argv[]) { - return csr_write_varid_valueless(dd, seqnum++, CSR_VARID_COLD_RESET); + return transport_write(transport, CSR_VARID_COLD_RESET, NULL, 0); } -static int cmd_warmreset(int dd, int argc, char *argv[]) +static int cmd_warmreset(int transport, int argc, char *argv[]) { - return csr_write_varid_valueless(dd, seqnum++, CSR_VARID_WARM_RESET); + return transport_write(transport, CSR_VARID_WARM_RESET, NULL, 0); } -static int cmd_disabletx(int dd, int argc, char *argv[]) +static int cmd_disabletx(int transport, int argc, char *argv[]) { - return csr_write_varid_valueless(dd, seqnum++, CSR_VARID_DISABLE_TX); + return transport_write(transport, CSR_VARID_DISABLE_TX, NULL, 0); } -static int cmd_enabletx(int dd, int argc, char *argv[]) +static int cmd_enabletx(int transport, int argc, char *argv[]) { - return csr_write_varid_valueless(dd, seqnum++, CSR_VARID_ENABLE_TX); + return transport_write(transport, CSR_VARID_ENABLE_TX, NULL, 0); } -static int cmd_memtypes(int dd, int argc, char *argv[]) +static int cmd_memtypes(int transport, int argc, char *argv[]) { uint8_t array[8]; uint16_t type, stores[4] = { 0x0001, 0x0002, 0x0004, 0x0008 }; @@ -338,8 +391,7 @@ static int cmd_memtypes(int dd, int argc, char *argv[]) array[0] = stores[i] & 0xff; array[1] = stores[i] >> 8; - err = csr_read_varid_complex(dd, seqnum++, - CSR_VARID_PS_MEMORY_TYPE, array, sizeof(array)); + err = transport_read(transport, CSR_VARID_PS_MEMORY_TYPE, array, 8); if (err < 0) continue; @@ -412,12 +464,12 @@ static int opt_pskey(int argc, char *argv[], uint16_t *stores, int *reset, int * argc -= optind; argv += optind; optind = 0; \ OPT_RANGE((range)) -static int cmd_psget(int dd, int argc, char *argv[]) +static int cmd_psget(int transport, int argc, char *argv[]) { - uint8_t array[64]; + uint8_t array[128]; uint16_t pskey, length, value, stores = CSR_STORES_DEFAULT; uint32_t val32; - int i, err, size, reset = 0, type = CSR_TYPE_NULL; + int i, err, reset = 0; memset(array, 0, sizeof(array)); @@ -425,87 +477,74 @@ static int cmd_psget(int dd, int argc, char *argv[]) if (strncasecmp(argv[0], "0x", 2)) { pskey = atoi(argv[0]); - type = CSR_TYPE_COMPLEX; - size = sizeof(array); for (i = 0; storage[i].pskey; i++) { if (strcasecmp(storage[i].str, argv[0])) continue; pskey = storage[i].pskey; - type = storage[i].type; - size = storage[i].type; break; } - } else { + } else pskey = strtol(argv[0] + 2, NULL, 16); - type = CSR_TYPE_COMPLEX; - size = sizeof(array); - } - - switch (type) { - case CSR_TYPE_COMPLEX: - memset(array, 0, sizeof(array)); - array[0] = pskey & 0xff; - array[1] = pskey >> 8; - array[2] = stores & 0xff; - array[3] = stores >> 8; - err = csr_read_varid_complex(dd, seqnum++, - CSR_VARID_PS_SIZE, array, 8); - if (err < 0) - return err; - - length = array[2] + (array[3] << 8); - if (length > sizeof(array) / 2) - return -EIO; + memset(array, 0, sizeof(array)); + array[0] = pskey & 0xff; + array[1] = pskey >> 8; + array[2] = stores & 0xff; + array[3] = stores >> 8; - err = csr_read_pskey_complex(dd, seqnum++, pskey, stores, - array, length * 2); - if (err < 0) - return err; + err = transport_read(transport, CSR_VARID_PS_SIZE, array, 8); + if (err < 0) + return err; - printf("%s:", csr_pskeytostr(pskey)); - for (i = 0; i < length; i++) - printf(" 0x%02x%02x", array[i * 2], array[(i * 2) + 1]); - printf("\n"); - break; - - case CSR_TYPE_UINT8: - case CSR_TYPE_UINT16: - err = csr_read_pskey_uint16(dd, seqnum++, pskey, stores, &value); - if (err < 0) - return err; + length = array[2] + (array[3] << 8); + if (length + 6 > 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 CSR_TYPE_UINT32: - err = csr_read_pskey_uint32(dd, seqnum++, pskey, stores, &val32); - if (err < 0) - return err; - + 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: - errno = EFAULT; - err = -1; + 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 (!err && reset) - csr_write_varid_valueless(dd, seqnum++, CSR_VARID_WARM_RESET); + if (reset) + transport_write(transport, CSR_VARID_WARM_RESET, NULL, 0); return err; } -static int cmd_psset(int dd, int argc, char *argv[]) +static int cmd_psset(int transport, int argc, char *argv[]) { - uint8_t array[64]; - uint16_t pskey, value, stores = CSR_STORES_PSRAM; + uint8_t array[128]; + uint16_t pskey, length, value, stores = CSR_STORES_PSRAM; uint32_t val32; - int i, err, size, reset = 0, type = CSR_TYPE_NULL; + int i, err, reset = 0; memset(array, 0, sizeof(array)); @@ -513,48 +552,44 @@ static int cmd_psset(int dd, int argc, char *argv[]) if (strncasecmp(argv[0], "0x", 2)) { pskey = atoi(argv[0]); - type = CSR_TYPE_COMPLEX; - size = sizeof(array); for (i = 0; storage[i].pskey; i++) { if (strcasecmp(storage[i].str, argv[0])) continue; pskey = storage[i].pskey; - type = storage[i].type; - size = storage[i].type; break; } - } else { + } else pskey = strtol(argv[0] + 2, NULL, 16); - type = CSR_TYPE_COMPLEX; - size = sizeof(array); - } - argc--; - argv++; + memset(array, 0, sizeof(array)); + array[0] = pskey & 0xff; + array[1] = pskey >> 8; + array[2] = stores & 0xff; + array[3] = stores >> 8; - switch (type) { - case CSR_TYPE_COMPLEX: - size = pskey_size(pskey); + err = transport_read(transport, CSR_VARID_PS_SIZE, array, 8); + if (err < 0) + return err; - if (argc != size) { - errno = EINVAL; - return -1; - } + length = array[2] + (array[3] << 8); + if (length + 6 > sizeof(array) / 2) + return -EIO; - for (i = 0; i < size; i++) - if (!strncasecmp(argv[0], "0x", 2)) - array[i] = strtol(argv[i] + 2, NULL, 16); - else - array[i] = atoi(argv[i]); + 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 = csr_write_pskey_complex(dd, seqnum++, pskey, - stores, array, size); - break; + argc--; + argv++; - case CSR_TYPE_UINT8: - case CSR_TYPE_UINT16: + switch (length) { + case 1: if (argc != 1) { errno = E2BIG; return -1; @@ -565,10 +600,11 @@ static int cmd_psset(int dd, int argc, char *argv[]) else value = atoi(argv[0]); - err = csr_write_pskey_uint16(dd, seqnum++, pskey, stores, value); + array[6] = value & 0xff; + array[7] = value >> 8; break; - case CSR_TYPE_UINT32: + case 2: if (argc != 1) { errno = E2BIG; return -1; @@ -579,22 +615,37 @@ static int cmd_psset(int dd, int argc, char *argv[]) else val32 = atoi(argv[0]); - err = csr_write_pskey_uint32(dd, seqnum++, pskey, stores, val32); + array[6] = (val32 & 0xff0000) >> 16; + array[7] = val32 >> 24; + array[8] = val32 & 0xff; + array[9] = (val32 & 0xff00) >> 8; break; default: - errno = EFAULT; - err = -1; + 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; } - if (!err && reset) - csr_write_varid_valueless(dd, seqnum++, CSR_VARID_WARM_RESET); + 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 dd, int argc, char *argv[]) +static int cmd_psclr(int transport, int argc, char *argv[]) { uint8_t array[8]; uint16_t pskey, stores = CSR_STORES_PSRAM; @@ -621,16 +672,17 @@ static int cmd_psclr(int dd, int argc, char *argv[]) array[2] = stores & 0xff; array[3] = stores >> 8; - err = csr_write_varid_complex(dd, seqnum++, - CSR_VARID_PS_CLR_STORES, array, sizeof(array)); + err = transport_write(transport, CSR_VARID_PS_CLR_STORES, array, 8); + if (err < 0) + return err; - if (!err && reset) - csr_write_varid_valueless(dd, seqnum++, CSR_VARID_WARM_RESET); + if (reset) + transport_write(transport, CSR_VARID_WARM_RESET, NULL, 0); return err; } -static int cmd_pslist(int dd, int argc, char *argv[]) +static int cmd_pslist(int transport, int argc, char *argv[]) { uint8_t array[8]; uint16_t pskey = 0x0000, length, stores = CSR_STORES_DEFAULT; @@ -645,8 +697,7 @@ static int cmd_pslist(int dd, int argc, char *argv[]) array[2] = stores & 0xff; array[3] = stores >> 8; - err = csr_read_varid_complex(dd, seqnum++, - CSR_VARID_PS_NEXT, array, sizeof(array)); + err = transport_read(transport, CSR_VARID_PS_NEXT, array, 8); if (err < 0) break; @@ -660,8 +711,7 @@ static int cmd_pslist(int dd, int argc, char *argv[]) array[2] = stores & 0xff; array[3] = stores >> 8; - err = csr_read_varid_complex(dd, seqnum++, - CSR_VARID_PS_SIZE, array, sizeof(array)); + err = transport_read(transport, CSR_VARID_PS_SIZE, array, 8); if (err < 0) continue; @@ -672,12 +722,12 @@ static int cmd_pslist(int dd, int argc, char *argv[]) } if (reset) - csr_write_varid_valueless(dd, seqnum++, CSR_VARID_WARM_RESET); + transport_write(transport, CSR_VARID_WARM_RESET, NULL, 0); return 0; } -static int cmd_psread(int dd, int argc, char *argv[]) +static int cmd_psread(int transport, int argc, char *argv[]) { uint8_t array[256]; uint16_t pskey = 0x0000, length, stores = CSR_STORES_DEFAULT; @@ -693,8 +743,7 @@ static int cmd_psread(int dd, int argc, char *argv[]) array[2] = stores & 0xff; array[3] = stores >> 8; - err = csr_read_varid_complex(dd, seqnum++, - CSR_VARID_PS_NEXT, array, 8); + err = transport_read(transport, CSR_VARID_PS_NEXT, array, 8); if (err < 0) break; @@ -708,17 +757,23 @@ static int cmd_psread(int dd, int argc, char *argv[]) array[2] = stores & 0xff; array[3] = stores >> 8; - err = csr_read_varid_complex(dd, seqnum++, - CSR_VARID_PS_SIZE, array, 8); + err = transport_read(transport, CSR_VARID_PS_SIZE, array, 8); if (err < 0) continue; length = array[2] + (array[3] << 8); - if (length > sizeof(array) / 2) + if (length + 6 > sizeof(array) / 2) continue; - err = csr_read_pskey_complex(dd, seqnum++, pskey, - stores, array, length * 2); + 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; @@ -731,20 +786,20 @@ static int cmd_psread(int dd, int argc, char *argv[]) printf("// %s%s\n&%04x =", str ? "PSKEY_" : "", str ? str : val, pskey); for (i = 0; i < length; i++) - printf(" %02x%02x", array[i * 2 + 1], array[i * 2]); + printf(" %02x%02x", array[(i * 2) + 7], array[(i * 2) + 6]); printf("\n"); } if (reset) - csr_write_varid_valueless(dd, seqnum++, CSR_VARID_WARM_RESET); + transport_write(transport, CSR_VARID_WARM_RESET, NULL, 0); return 0; } -static int cmd_psload(int dd, int argc, char *argv[]) +static int cmd_psload(int transport, int argc, char *argv[]) { uint8_t array[256]; - uint16_t pskey, size, stores = CSR_STORES_PSRAM; + uint16_t pskey, length, size, stores = CSR_STORES_PSRAM; char *str, val[7]; int err, reset = 0; @@ -752,7 +807,10 @@ static int cmd_psload(int dd, int argc, char *argv[]) psr_read(argv[0]); - while (psr_get(&pskey, array, &size) == 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); @@ -763,19 +821,30 @@ static int cmd_psload(int dd, int argc, char *argv[]) str ? str : val); fflush(stdout); - err = csr_write_pskey_complex(dd, seqnum++, pskey, - stores, array, size); + 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) - csr_write_varid_valueless(dd, seqnum++, CSR_VARID_WARM_RESET); + transport_write(transport, CSR_VARID_WARM_RESET, NULL, 0); return 0; } -static int cmd_pscheck(int dd, int argc, char *argv[]) +static int cmd_pscheck(int transport, int argc, char *argv[]) { uint8_t array[256]; uint16_t pskey, size; @@ -797,7 +866,7 @@ static int cmd_pscheck(int dd, int argc, char *argv[]) static struct { char *str; - int (*func)(int dd, int argc, char *argv[]); + int (*func)(int transport, int argc, char *argv[]); char *arg; char *doc; } commands[] = { @@ -864,10 +933,8 @@ static struct option main_options[] = { int main(int argc, char *argv[]) { - struct hci_dev_info di; - struct hci_version ver; char *device = NULL; - int i, err, opt, dd, dev, transport = CSR_TRANSPORT_HCI; + int i, err, opt, transport = CSR_TRANSPORT_HCI; while ((opt=getopt_long(argc, argv, "+t:d:i:h", main_options, NULL)) != EOF) { switch (opt) { @@ -911,55 +978,19 @@ int main(int argc, char *argv[]) exit(1); } - if (transport != CSR_TRANSPORT_HCI) { - fprintf(stderr, "Unsupported transport\n"); + if (transport_open(transport, device) < 0) exit(1); - } - if (device) { - dev = hci_devid(device); - if (dev < 0) { - fprintf(stderr, "Device not available\n"); - exit(1); - } + if (device) free(device); - } else - dev = 0; - - dd = hci_open_dev(dev); - if (dd < 0) { - fprintf(stderr, "Can't open device hci%d: %s (%d)\n", - dev, strerror(errno), errno); - exit(1); - } - - if (hci_devinfo(dev, &di) < 0) { - fprintf(stderr, "Can't get device info for hci%d: %s (%d)\n", - dev, strerror(errno), errno); - hci_close_dev(dd); - exit(1); - } - - if (hci_read_local_version(dd, &ver, 1000) < 0) { - fprintf(stderr, "Can't read version info for hci%d: %s (%d)\n", - dev, strerror(errno), errno); - hci_close_dev(dd); - exit(1); - } - - if (ver.manufacturer != 10) { - fprintf(stderr, "Unsupported manufacturer\n"); - hci_close_dev(dd); - exit(1); - } for (i = 0; commands[i].str; i++) { if (strcasecmp(commands[i].str, argv[0])) continue; - err = commands[i].func(dd, argc, argv); + err = commands[i].func(transport, argc, argv); - hci_close_dev(dd); + transport_close(transport); if (err < 0) { fprintf(stderr, "Can't execute command: %s (%d)\n", @@ -972,7 +1003,7 @@ int main(int argc, char *argv[]) fprintf(stderr, "Unsupported command\n"); - hci_close_dev(dd); + transport_close(transport); exit(1); } diff --git a/tools/csr.c b/tools/csr.c index c101422b..10856749 100644 --- a/tools/csr.c +++ b/tools/csr.c @@ -2354,7 +2354,7 @@ int csr_write_varid_complex(int dd, uint16_t seqnum, uint16_t varid, uint8_t *va rq.ocf = 0x00; rq.event = EVT_VENDOR; rq.cparam = cp; - rq.clen = sizeof(cmd) + 1; + rq.clen = sizeof(cmd) + length + 1; rq.rparam = rp; rq.rlen = sizeof(rp); @@ -2393,7 +2393,7 @@ int csr_read_varid_complex(int dd, uint16_t seqnum, uint16_t varid, uint8_t *val rq.ocf = 0x00; rq.event = EVT_VENDOR; rq.cparam = cp; - rq.clen = sizeof(cmd) + 1; + rq.clen = sizeof(cmd) + length + 1; rq.rparam = rp; rq.rlen = sizeof(rp); diff --git a/tools/csr.h b/tools/csr.h index cd807c38..ec066b81 100644 --- a/tools/csr.h +++ b/tools/csr.h @@ -63,7 +63,7 @@ #define CSR_VARID_FAULT_ARG 0x6806 /* uint16 */ #define CSR_VARID_MAX_TX_POWER 0x6827 /* int8 */ #define CSR_VARID_DEFAULT_TX_POWER 0x682b /* int8 */ -#define CSR_VARID_PS 0x7002 /* complex */ +#define CSR_VARID_PS 0x7003 /* complex */ #define CSR_PSKEY_BDADDR 0x0001 /* bdaddr / uint16[] = { 0x00A5A5, 0x5b, 0x0002 } */ #define CSR_PSKEY_COUNTRYCODE 0x0002 /* uint16 */ @@ -502,6 +502,16 @@ char *csr_chipvertostr(uint16_t ver, uint16_t rev); char *csr_pskeytostr(uint16_t pskey); char *csr_pskeytoval(uint16_t pskey); +int csr_open_hci(char *device); +int csr_read_hci(uint16_t varid, uint8_t *value, uint16_t length); +int csr_write_hci(uint16_t varid, uint8_t *value, uint16_t length); +void csr_close_hci(void); + +int csr_open_usb(char *device); +int csr_read_usb(uint16_t varid, uint8_t *value, uint16_t length); +int csr_write_usb(uint16_t varid, uint8_t *value, uint16_t length); +void csr_close_usb(void); + int csr_write_varid_valueless(int dd, uint16_t seqnum, uint16_t varid); int csr_write_varid_complex(int dd, uint16_t seqnum, uint16_t varid, uint8_t *value, uint16_t length); int csr_read_varid_complex(int dd, uint16_t seqnum, uint16_t varid, uint8_t *value, uint16_t length); diff --git a/tools/csr_hci.c b/tools/csr_hci.c new file mode 100644 index 00000000..ebeb8aa7 --- /dev/null +++ b/tools/csr_hci.c @@ -0,0 +1,160 @@ +/* + * + * BlueZ - Bluetooth protocol stack for Linux + * + * Copyright (C) 2004-2005 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 "csr.h" + +static uint16_t seqnum = 0x0000; + +static int dd = -1; + +int csr_open_hci(char *device) +{ + struct hci_dev_info di; + struct hci_version ver; + int dev = 0; + + if (device) { + dev = hci_devid(device); + if (dev < 0) { + fprintf(stderr, "Device not available\n"); + return -1; + } + } + + dd = hci_open_dev(dev); + if (dd < 0) { + fprintf(stderr, "Can't open device hci%d: %s (%d)\n", + dev, strerror(errno), errno); + return -1; + } + + if (hci_devinfo(dev, &di) < 0) { + fprintf(stderr, "Can't get device info for hci%d: %s (%d)\n", + dev, strerror(errno), errno); + hci_close_dev(dd); + return -1; + } + + if (hci_read_local_version(dd, &ver, 1000) < 0) { + fprintf(stderr, "Can't read version info for hci%d: %s (%d)\n", + dev, strerror(errno), errno); + hci_close_dev(dd); + return -1; + } + + if (ver.manufacturer != 10) { + fprintf(stderr, "Unsupported manufacturer\n"); + hci_close_dev(dd); + return -1; + } + + return 0; +} + +static int do_command(uint16_t command, uint16_t seqnum, uint16_t varid, uint8_t *value, uint16_t length) +{ + unsigned char cp[254], rp[254]; + struct hci_request rq; + uint8_t cmd[10]; + uint16_t size; + + size = (length < 8) ? 9 : ((length + 1) / 2) + 5; + + cmd[0] = command & 0xff; + cmd[1] = command >> 8; + cmd[2] = size & 0xff; + cmd[3] = size >> 8; + cmd[4] = seqnum & 0xff; + cmd[5] = seqnum >> 8; + cmd[6] = varid & 0xff; + cmd[7] = varid >> 8; + cmd[8] = 0x00; + cmd[9] = 0x00; + + memset(cp, 0, sizeof(cp)); + cp[0] = 0xc2; + memcpy(cp + 1, cmd, sizeof(cmd)); + memcpy(cp + 11, value, length); + + switch (varid) { + case CSR_VARID_COLD_RESET: + case CSR_VARID_WARM_RESET: + case CSR_VARID_COLD_HALT: + case CSR_VARID_WARM_HALT: + return hci_send_cmd(dd, OGF_VENDOR_CMD, 0x00, (size * 2) + 1, cp); + } + + memset(&rq, 0, sizeof(rq)); + rq.ogf = OGF_VENDOR_CMD; + rq.ocf = 0x00; + rq.event = EVT_VENDOR; + rq.cparam = cp; + rq.clen = (size * 2) + 1; + rq.rparam = rp; + rq.rlen = sizeof(rp); + + if (hci_send_req(dd, &rq, 2000) < 0) + return -1; + + if (rp[0] != 0xc2) { + errno = EIO; + return -1; + } + + if ((rp[9] + (rp[10] << 8)) != 0) { + errno = ENXIO; + return -1; + } + + memcpy(value, rp + 11, length); + + return 0; +} + +int csr_read_hci(uint16_t varid, uint8_t *value, uint16_t length) +{ + return do_command(0x0000, seqnum++, varid, value, length); +} + +int csr_write_hci(uint16_t varid, uint8_t *value, uint16_t length) +{ + return do_command(0x0002, seqnum++, varid, value, length); +} + +void csr_close_hci(void) +{ + hci_close_dev(dd); +} diff --git a/tools/csr_usb.c b/tools/csr_usb.c new file mode 100644 index 00000000..2c29251f --- /dev/null +++ b/tools/csr_usb.c @@ -0,0 +1,173 @@ +/* + * + * BlueZ - Bluetooth protocol stack for Linux + * + * Copyright (C) 2004-2005 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 "csr.h" + +#ifdef NEED_USB_GET_BUSSES +static inline struct usb_bus *usb_get_busses(void) +{ + return usb_busses; +} +#endif + +#ifndef USB_DIR_OUT +#define USB_DIR_OUT 0x00 +#endif + +static uint16_t seqnum = 0x0000; + +static struct usb_dev_handle *udev = NULL; + +int csr_open_usb(char *device) +{ + struct usb_bus *bus; + struct usb_device *dev; + + usb_init(); + + usb_find_busses(); + usb_find_devices(); + + for (bus = usb_get_busses(); bus; bus = bus->next) { + for (dev = bus->devices; dev; dev = dev->next) { + if (dev->descriptor.bDeviceClass == USB_CLASS_HUB) + continue; + + if (dev->descriptor.idVendor != 0x0a12 || + dev->descriptor.idProduct != 0x0001) + continue; + + goto found; + } + } + + fprintf(stderr, "Device not available\n"); + + return -1; + +found: + udev = usb_open(dev); + if (!udev) { + fprintf(stderr, "Can't open device: %s (%d)\n", + strerror(errno), errno); + return -1; + } + + if (usb_claim_interface(udev, 0) < 0) { + fprintf(stderr, "Can't claim interface: %s (%d)\n", + strerror(errno), errno); + usb_close(udev); + return -1; + } + + return 0; +} + +static int do_command(uint16_t command, uint16_t seqnum, uint16_t varid, uint8_t *value, uint16_t length) +{ + unsigned char cp[254], rp[254]; + uint8_t cmd[10]; + uint16_t size; + int len, offset = 0; + + size = (length < 8) ? 9 : ((length + 1) / 2) + 5; + + cmd[0] = command & 0xff; + cmd[1] = command >> 8; + cmd[2] = size & 0xff; + cmd[3] = size >> 8; + cmd[4] = seqnum & 0xff; + cmd[5] = seqnum >> 8; + cmd[6] = varid & 0xff; + cmd[7] = varid >> 8; + cmd[8] = 0x00; + cmd[9] = 0x00; + + memset(cp, 0, sizeof(cp)); + cp[0] = 0x00; + cp[1] = 0xfc; + cp[2] = (size * 2) + 1; + cp[3] = 0xc2; + memcpy(cp + 4, cmd, sizeof(cmd)); + memcpy(cp + 14, value, length); + + usb_interrupt_read(udev, 0x81, (void *) rp, sizeof(rp), 2); + + if (usb_control_msg(udev, USB_TYPE_CLASS | USB_DIR_OUT | USB_RECIP_DEVICE, + 0, 0, 0, (void *) cp, (size * 2) + 4, 1000) < 0) + return -1; + + switch (varid) { + case CSR_VARID_COLD_RESET: + case CSR_VARID_WARM_RESET: + case CSR_VARID_COLD_HALT: + case CSR_VARID_WARM_HALT: + return 0; + } + + do { + len = usb_interrupt_read(udev, 0x81, + (void *) (rp + offset), sizeof(rp), 10); + offset += len; + } while (len > 0); + + if (rp[0] != 0xff || rp[2] != 0xc2) { + errno = EIO; + return -1; + } + + if ((rp[11] + (rp[12] << 8)) != 0) { + errno = ENXIO; + return -1; + } + + memcpy(value, rp + 13, length); + + return 0; +} + +int csr_read_usb(uint16_t varid, uint8_t *value, uint16_t length) +{ + return do_command(0x0000, seqnum++, varid, value, length); +} + +int csr_write_usb(uint16_t varid, uint8_t *value, uint16_t length) +{ + return do_command(0x0002, seqnum++, varid, value, length); +} + +void csr_close_usb(void) +{ + usb_release_interface(udev, 0); + usb_close(udev); +} -- cgit