2005-05-16 19:51:27 +08:00
|
|
|
/*
|
|
|
|
*
|
|
|
|
* BlueZ - Bluetooth protocol stack for Linux
|
|
|
|
*
|
|
|
|
* Copyright (C) 2004-2005 Marcel Holtmann <marcel@holtmann.org>
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License version 2 as
|
|
|
|
* published by the Free Software Foundation;
|
|
|
|
*
|
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
|
|
|
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
|
|
|
|
* IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
|
|
|
|
* CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
|
|
|
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
|
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
|
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
|
|
*
|
|
|
|
* ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
|
|
|
|
* COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
|
|
|
|
* SOFTWARE IS DISCLAIMED.
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* $Id$
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
#include <config.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <getopt.h>
|
|
|
|
#include <sys/socket.h>
|
|
|
|
|
|
|
|
#include <bluetooth/bluetooth.h>
|
|
|
|
#include <bluetooth/hci.h>
|
|
|
|
#include <bluetooth/hci_lib.h>
|
|
|
|
|
|
|
|
#include "csr.h"
|
|
|
|
|
|
|
|
static int cmd_keylen(int dd, int argc, char *argv[])
|
|
|
|
{
|
|
|
|
uint8_t buf[8];
|
|
|
|
uint16_t handle, keylen;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
if (argc < 1) {
|
|
|
|
errno = EINVAL;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (argc > 1) {
|
|
|
|
errno = E2BIG;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
handle = atoi(argv[0]);
|
|
|
|
|
|
|
|
memset(buf, 0, sizeof(buf));
|
|
|
|
buf[0] = handle & 0xff;
|
|
|
|
buf[1] = handle >> 8;
|
|
|
|
|
|
|
|
err = csr_read_varid_complex(dd, 0x4711,
|
|
|
|
CSR_VARID_CRYPT_KEY_LENGTH, buf, sizeof(buf));
|
|
|
|
if (err < 0) {
|
|
|
|
errno = -err;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
handle = buf[0] | (buf[1] << 8);
|
|
|
|
keylen = buf[2] | (buf[3] << 8);
|
|
|
|
|
|
|
|
printf("Crypt key length: %d bit\n", keylen * 8);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2005-07-03 18:10:34 +08:00
|
|
|
static int cmd_clock(int dd, int argc, char *argv[])
|
|
|
|
{
|
|
|
|
uint32_t clock = 0;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = csr_read_varid_uint32(dd, 0x4711, CSR_VARID_BT_CLOCK, &clock);
|
|
|
|
if (err < 0) {
|
|
|
|
errno = -err;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
printf("Bluetooth clock: 0x%04x (%d)\n", clock, clock);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2005-08-23 04:38:18 +08:00
|
|
|
static int cmd_rand(int dd, int argc, char *argv[])
|
|
|
|
{
|
|
|
|
uint16_t rand = 0;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = csr_read_varid_uint16(dd, 5, CSR_VARID_RAND, &rand);
|
|
|
|
if (err < 0) {
|
|
|
|
errno = -err;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
printf("Random number: 0x%02x (%d)\n", rand, rand);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2005-07-03 21:13:17 +08:00
|
|
|
static int cmd_panicarg(int dd, int argc, char *argv[])
|
|
|
|
{
|
|
|
|
uint16_t error = 0;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = csr_read_varid_uint16(dd, 5, CSR_VARID_PANIC_ARG, &error);
|
|
|
|
if (err < 0) {
|
|
|
|
errno = -err;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
printf("Panic code: 0x%02x (%s)\n", error,
|
|
|
|
error < 0x100 ? "valid" : "invalid");
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int cmd_faultarg(int dd, int argc, char *argv[])
|
|
|
|
{
|
|
|
|
uint16_t error = 0;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = csr_read_varid_uint16(dd, 5, CSR_VARID_FAULT_ARG, &error);
|
|
|
|
if (err < 0) {
|
|
|
|
errno = -err;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
printf("Fault code: 0x%02x (%s)\n", error,
|
|
|
|
error < 0x100 ? "valid" : "invalid");
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2005-08-23 04:38:18 +08:00
|
|
|
static int cmd_coldreset(int dd, int argc, char *argv[])
|
|
|
|
{
|
|
|
|
return csr_write_varid_valueless(dd, 0, CSR_VARID_COLD_RESET);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int cmd_warmreset(int dd, int argc, char *argv[])
|
|
|
|
{
|
|
|
|
return csr_write_varid_valueless(dd, 0, CSR_VARID_WARM_RESET);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int cmd_disabletx(int dd, int argc, char *argv[])
|
|
|
|
{
|
|
|
|
return csr_write_varid_valueless(dd, 0, CSR_VARID_DISABLE_TX);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int cmd_enabletx(int dd, int argc, char *argv[])
|
|
|
|
{
|
|
|
|
return csr_write_varid_valueless(dd, 0, CSR_VARID_ENABLE_TX);
|
|
|
|
}
|
|
|
|
|
2005-05-16 19:51:27 +08:00
|
|
|
static struct {
|
|
|
|
char *str;
|
|
|
|
int (*func)(int dd, int argc, char **argv);
|
|
|
|
char *arg;
|
|
|
|
char *doc;
|
|
|
|
} commands[] = {
|
2005-08-23 04:38:18 +08:00
|
|
|
{ "keylen", cmd_keylen, "<handle>", "Get current crypt key length" },
|
|
|
|
{ "clock", cmd_clock, "", "Get local Bluetooth clock" },
|
|
|
|
{ "rand", cmd_rand, "", "Get random number" },
|
|
|
|
{ "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" },
|
2005-05-16 19:51:27 +08:00
|
|
|
{ NULL },
|
|
|
|
};
|
|
|
|
|
|
|
|
static void usage(void)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
printf("bccmd - Utility for the CSR BCCMD interface\n\n");
|
|
|
|
printf("Usage:\n"
|
|
|
|
"\tbccmd [-i <dev>] <command>\n\n");
|
|
|
|
|
|
|
|
printf("Commands:\n");
|
|
|
|
for (i = 0; commands[i].str; i++)
|
2005-07-03 21:13:17 +08:00
|
|
|
printf("\t%-10s%-8s\t%s\n", commands[i].str,
|
2005-05-16 19:51:27 +08:00
|
|
|
commands[i].arg, commands[i].doc);
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct option main_options[] = {
|
|
|
|
{ "help", 0, 0, 'h' },
|
|
|
|
{ "device", 1, 0, 'i' },
|
|
|
|
{ 0, 0, 0, 0 }
|
|
|
|
};
|
|
|
|
|
|
|
|
int main(int argc, char *argv[])
|
|
|
|
{
|
|
|
|
struct hci_dev_info di;
|
|
|
|
struct hci_version ver;
|
|
|
|
int i, err, dd, opt, dev = 0;
|
|
|
|
|
|
|
|
while ((opt=getopt_long(argc, argv, "+i:h", main_options, NULL)) != -1) {
|
|
|
|
switch (opt) {
|
|
|
|
case 'i':
|
|
|
|
dev = hci_devid(optarg);
|
|
|
|
if (dev < 0) {
|
|
|
|
perror("Invalid device");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'h':
|
|
|
|
default:
|
|
|
|
usage();
|
|
|
|
exit(0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
argc -= optind;
|
|
|
|
argv += optind;
|
|
|
|
optind = 0;
|
|
|
|
|
|
|
|
if (argc < 1) {
|
|
|
|
usage();
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
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 - 1, argv + 1);
|
|
|
|
|
|
|
|
hci_close_dev(dd);
|
|
|
|
|
|
|
|
if (err < 0) {
|
|
|
|
fprintf(stderr, "Can't execute command: %s (%d)\n",
|
|
|
|
strerror(errno), errno);
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
exit(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
fprintf(stderr, "Unsupported command\n");
|
|
|
|
|
|
|
|
hci_close_dev(dd);
|
|
|
|
|
|
|
|
exit(1);
|
|
|
|
}
|