diff options
Diffstat (limited to 'tools/hciattach_st.c')
| -rw-r--r-- | tools/hciattach_st.c | 276 | 
1 files changed, 276 insertions, 0 deletions
diff --git a/tools/hciattach_st.c b/tools/hciattach_st.c new file mode 100644 index 00000000..2c7d7438 --- /dev/null +++ b/tools/hciattach_st.c @@ -0,0 +1,276 @@ +/* + * + *  BlueZ - Bluetooth protocol stack for Linux + * + *  Copyright (C) 2005-2008  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 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 <config.h> +#endif + +#include <stdio.h> +#include <errno.h> +#include <fcntl.h> +#include <unistd.h> +#include <stdlib.h> +#include <stdint.h> +#include <string.h> +#include <dirent.h> +#include <sys/param.h> + +#include <bluetooth/bluetooth.h> + +static int debug = 0; + +static int do_command(int fd, uint8_t ogf, uint16_t ocf, +			uint8_t *cparam, int clen, uint8_t *rparam, int rlen) +{ +	//uint16_t opcode = (uint16_t) ((ocf & 0x03ff) | (ogf << 10)); +	unsigned char cp[260], rp[260]; +	int len, size, offset = 3; + +	cp[0] = 0x01; +	cp[1] = ocf & 0xff; +	cp[2] = ogf << 2 | ocf >> 8; +	cp[3] = clen; + +	if (clen > 0) +		memcpy(cp + 4, cparam, clen); + +	if (debug) { +		int i; +		printf("[<"); +		for (i = 0; i < clen + 4; i++) +			printf(" %02x", cp[i]); +		printf("]\n"); +	} + +	if (write(fd, cp, clen + 4) < 0) +		return -1; + +	do { +		if (read(fd, rp, 1) < 1) +			return -1; +	} while (rp[0] != 0x04); + +	if (read(fd, rp + 1, 2) < 2) +		return -1; + +	do { +		len = read(fd, rp + offset, sizeof(rp) - offset); +		offset += len; +	} while (offset < rp[2] + 3); + +	if (debug) { +		int i; +		printf("[>"); +		for (i = 0; i < offset; i++) +			printf(" %02x", rp[i]); +		printf("]\n"); +	} + +	if (rp[0] != 0x04) { +		errno = EIO; +		return -1; +	} + +	switch (rp[1]) { +	case 0x0e:	/* command complete */ +		if (rp[6] != 0x00) +			return -ENXIO; +		offset = 3 + 4; +		size = rp[2] - 4; +		break; +	case 0x0f:	/* command status */ +		/* fall through */ +	default: +		offset = 3; +		size = rp[2]; +		break; +	} + +	if (!rparam || rlen < size) +		return -ENXIO; + +	memcpy(rparam, rp + offset, size); + +	return size; +} + +static int load_file(int dd, uint16_t version, const char *suffix) +{ +	DIR *dir; +	struct dirent *d; +	char pathname[PATH_MAX], filename[NAME_MAX], prefix[20]; +	unsigned char cmd[256]; +	unsigned char buf[256]; +	uint8_t seqnum = 0; +	int fd, size, len, found_fw_file; + +	memset(filename, 0, sizeof(filename)); + +	snprintf(prefix, sizeof(prefix), "STLC2500_R%d_%02d_", +						version >> 8, version & 0xff); + +	strcpy(pathname, "/lib/firmware"); +	dir = opendir(pathname); +	if (!dir) { +		strcpy(pathname, "."); +		dir = opendir(pathname); +		if (!dir) +			return -errno; +	} + +	found_fw_file = 0;	 +	while (1) { +		d = readdir(dir); +		if (!d) +			break; + +		if (strncmp(d->d_name + strlen(d->d_name) - strlen(suffix), +						suffix, strlen(suffix))) +			continue; + +		if (strncmp(d->d_name, prefix, strlen(prefix))) +			continue; + +		snprintf(filename, sizeof(filename), "%s/%s", +							pathname, d->d_name); +		found_fw_file = 1; +	} + +	closedir(dir); + +	if (!found_fw_file) +		return -ENOENT; + +	printf("Loading file %s\n", filename); + +	fd = open(filename, O_RDONLY); +	if (fd < 0) { +		perror("Can't open firmware file"); +		return -errno; +	} + +	while (1) { +		size = read(fd, cmd + 1, 254); +		if (size <= 0) +			break; + +		cmd[0] = seqnum; + +		len = do_command(dd, 0xff, 0x002e, cmd, size + 1, buf, sizeof(buf)); +		if (len < 1) +			break; + +		if (buf[0] != seqnum) { +			fprintf(stderr, "Sequence number mismatch\n"); +			break; +		} + +		seqnum++; +	} + +	close(fd); + +	return 0; +} + +int stlc2500_init(int dd, bdaddr_t *bdaddr) +{ +	unsigned char cmd[16]; +	unsigned char buf[254]; +	uint16_t version; +	int len; +	int err; + +	/* Hci_Cmd_Ericsson_Read_Revision_Information */	 +	len = do_command(dd, 0xff, 0x000f, NULL, 0, buf, sizeof(buf)); +	if (len < 0) +		return -1; + +	printf("%s\n", buf); + +	/* HCI_Read_Local_Version_Information */	 +	len = do_command(dd, 0x04, 0x0001, NULL, 0, buf, sizeof(buf)); +	if (len < 0) +		return -1; + +	version = buf[2] << 8 | buf[1]; + +	err = load_file(dd, version, ".ptc"); +	if (err < 0) { +		if (err == -ENOENT) 	 +			fprintf(stderr, "No ROM patch file loaded.\n"); +		else +			return -1; +	} + +	err = load_file(dd, buf[2] << 8 | buf[1], ".ssf"); +	if (err < 0) { +		if (err == -ENOENT) 	 +			fprintf(stderr, "No static settings file loaded.\n"); +		else +			return -1; +	} + +	cmd[0] = 0xfe; +	cmd[1] = 0x06; +	bacpy((bdaddr_t *) (cmd + 2), bdaddr); + +	/* Hci_Cmd_ST_Store_In_NVDS */	 +	len = do_command(dd, 0xff, 0x0022, cmd, 8, buf, sizeof(buf)); +	if (len < 0) +		return -1; + +	/* HCI_Reset : applies parameters*/ +	len = do_command(dd, 0x03, 0x0003, NULL, 0, buf, sizeof(buf)); +	if (len < 0) +		return -1; + +	return 0; +} + +int bgb2xx_init(int dd, bdaddr_t *bdaddr) +{ +	unsigned char cmd[16]; +	unsigned char buf[254]; +	int len; + +	len = do_command(dd, 0xff, 0x000f, NULL, 0, buf, sizeof(buf)); +	if (len < 0) +		return -1; + +	printf("%s\n", buf); + +	cmd[0] = 0xfe; +	cmd[1] = 0x06; +	bacpy((bdaddr_t *) (cmd + 2), bdaddr); + +	len = do_command(dd, 0xff, 0x0022, cmd, 8, buf, sizeof(buf)); +	if (len < 0) +		return -1; + +	len = do_command(dd, 0x03, 0x0003, NULL, 0, buf, sizeof(buf)); +	if (len < 0) +		return -1; + +	return 0; +}  | 
