Linux bluetooth development
 help / color / mirror / Atom feed
* [PATCH v4] Bluetooth: host level Support for Atheros AR300x device
From: Suraj Sumangala @ 2010-08-18  9:29 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Suraj Sumangala

Implements support for Atheros AR300x Bluetooth chip in
hciattach application. Supports configuration download
and power management configure feature.
---
 Makefile.tools          |    3 +-
 tools/hciattach.8       |    3 +
 tools/hciattach.c       |   12 +
 tools/hciattach.h       |    3 +
 tools/hciattach_ath3k.c |  953 +++++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 973 insertions(+), 1 deletions(-)
 create mode 100644 tools/hciattach_ath3k.c

diff --git a/Makefile.tools b/Makefile.tools
index 2dbf925..8ee1972 100644
--- a/Makefile.tools
+++ b/Makefile.tools
@@ -23,7 +23,8 @@ tools_l2ping_LDADD = lib/libbluetooth.la
 tools_hciattach_SOURCES = tools/hciattach.c tools/hciattach.h \
 						tools/hciattach_st.c \
 						tools/hciattach_ti.c \
-						tools/hciattach_tialt.c
+						tools/hciattach_tialt.c \
+						tools/hciattach_ath3k.c
 tools_hciattach_LDADD = lib/libbluetooth.la
 
 tools_hciconfig_SOURCES = tools/hciconfig.c tools/csr.h tools/csr.c \
diff --git a/tools/hciattach.8 b/tools/hciattach.8
index f443dff..e0e2730 100644
--- a/tools/hciattach.8
+++ b/tools/hciattach.8
@@ -86,6 +86,9 @@ Silicon Wave kits
 .TP
 .B bcsp
 Serial adapters using CSR chips with BCSP serial protocol
+.TP
+.B ath3k
+Atheros AR300x based serial Bluetooth device
 .RE
 
 Supported IDs are (manufacturer id, product id)
diff --git a/tools/hciattach.c b/tools/hciattach.c
index 8616899..5662f57 100644
--- a/tools/hciattach.c
+++ b/tools/hciattach.c
@@ -302,6 +302,16 @@ static int texasalt(int fd, struct uart_t *u, struct termios *ti)
 	return texasalt_init(fd, u->speed, ti);
 }
 
+static int ath3k_ps(int fd, struct uart_t *u, struct termios *ti)
+{
+	return ath3k_init(fd, u->bdaddr, u->speed);
+}
+
+static int ath3k_pm(int fd, struct uart_t *u, struct termios *ti)
+{
+	return ath3k_post(fd, u->pm);
+}
+
 static int read_check(int fd, void *buf, int count)
 {
 	int res;
@@ -1104,6 +1114,8 @@ struct uart_t uart[] = {
 	{ "bcm2035",    0x0A5C, 0x2035, HCI_UART_H4,   115200, 460800,
 				FLOW_CTL, DISABLE_PM, NULL, bcm2035  },
 
+	{ "ath3k",    0x0000, 0x0000, HCI_UART_ATH3K, 115200, 115200,
+			FLOW_CTL, DISABLE_PM, NULL, ath3k_ps, ath3k_pm  },
 	{ NULL, 0 }
 };
 
diff --git a/tools/hciattach.h b/tools/hciattach.h
index c0b80a1..c133321 100644
--- a/tools/hciattach.h
+++ b/tools/hciattach.h
@@ -38,6 +38,7 @@
 #define HCI_UART_3WIRE	2
 #define HCI_UART_H4DS	3
 #define HCI_UART_LL	4
+#define HCI_UART_ATH3K  5
 
 #define HCI_UART_RAW_DEVICE	0
 
@@ -49,3 +50,5 @@ int texas_post(int fd, struct termios *ti);
 int texasalt_init(int fd, int speed, struct termios *ti);
 int stlc2500_init(int fd, bdaddr_t *bdaddr);
 int bgb2xx_init(int dd, bdaddr_t *bdaddr);
+int ath3k_init(int fd, char *bdaddr, int speed);
+int ath3k_post(int fd, int pm);
diff --git a/tools/hciattach_ath3k.c b/tools/hciattach_ath3k.c
new file mode 100644
index 0000000..afa3f93
--- /dev/null
+++ b/tools/hciattach_ath3k.c
@@ -0,0 +1,953 @@
+/*
+ *  Copyright (c) 2009-2010 Atheros Communications Inc.
+ *
+ *  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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <time.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/ioctl.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/hci.h>
+#include <bluetooth/hci_lib.h>
+
+#include "hciattach.h"
+
+#define TRUE    1
+#define FALSE   0
+
+#define FW_PATH "/lib/firmware/ar3k/"
+
+struct ps_cfg_entry {
+	uint32_t id;
+	uint32_t len;
+	uint8_t *data;
+};
+
+struct ps_entry_type {
+	unsigned char type;
+	unsigned char array;
+};
+
+#define MAX_TAGS              50
+#define PS_HDR_LEN            4
+#define HCI_VENDOR_CMD_OGF    0x3F
+#define HCI_PS_CMD_OCF        0x0B
+
+struct ps_cfg_entry ps_list[MAX_TAGS];
+
+static void load_hci_ps_hdr(uint8_t *cmd, uint8_t ps_op, int len, int index)
+{
+	hci_command_hdr *ch = (void *)cmd;
+
+	ch->opcode = htobs(cmd_opcode_pack(HCI_VENDOR_CMD_OGF,
+						HCI_PS_CMD_OCF));
+	ch->plen = len + PS_HDR_LEN;
+	cmd += HCI_COMMAND_HDR_SIZE;
+
+	cmd[0] = ps_op;
+	cmd[1] = index;
+	cmd[2] = index >> 8;
+	cmd[3] = len;
+}
+
+#define PS_EVENT_LEN 100
+
+/*
+ * Send HCI command and wait for command complete event.
+ * The event buffer has to be freed by the caller.
+ */
+static int send_hci_cmd_sync(int dev, uint8_t *cmd, int len, uint8_t **event)
+{
+	int err;
+	uint8_t *hci_event;
+	uint8_t pkt_type = HCI_COMMAND_PKT;
+
+	if (len == 0)
+		return len;
+
+	if (write(dev, &pkt_type, 1) != 1)
+		return -EILSEQ;
+	if (write(dev, (unsigned char *)cmd, len) != len)
+		return -EILSEQ;
+
+	hci_event = (uint8_t *)malloc(PS_EVENT_LEN);
+	if (!hci_event)
+		return -ENOMEM;
+
+	err = read_hci_event(dev, (unsigned char *)hci_event, PS_EVENT_LEN);
+	if (err > 0) {
+		*event = hci_event;
+	} else {
+		free(hci_event);
+		return -EILSEQ;
+	}
+
+	return len;
+}
+
+#define HCI_EV_SUCCESS        0x00
+
+static int read_ps_event(uint8_t *event, uint16_t ocf)
+{
+	hci_event_hdr *eh;
+	uint16_t opcode = htobs(cmd_opcode_pack(HCI_VENDOR_CMD_OGF, ocf));
+
+	event++;
+
+	eh = (void *)event;
+	event += HCI_EVENT_HDR_SIZE;
+
+	if (eh->evt == EVT_CMD_COMPLETE) {
+		evt_cmd_complete *cc = (void *)event;
+
+		event += EVT_CMD_COMPLETE_SIZE;
+
+		if (cc->opcode == opcode && event[0] == HCI_EV_SUCCESS)
+			return 0;
+		else
+			return -EILSEQ;
+	}
+
+	return -EILSEQ;
+}
+
+static int write_cmd(int fd, uint8_t *buffer, int len)
+{
+	uint8_t *event;
+	int err;
+
+	err = send_hci_cmd_sync(fd, buffer, len, &event);
+	if (err < 0)
+		return err;
+
+	err = read_ps_event(event, HCI_PS_CMD_OCF);
+	if (event)
+		free(event);
+
+	return err;
+}
+
+#define PS_WRITE           1
+#define PS_RESET           2
+#define WRITE_PATCH        8
+#define ENABLE_PATCH       11
+
+#define HCI_PS_CMD_HDR_LEN 7
+
+#define PS_RESET_PARAM_LEN 6
+#define HCI_MAX_CMD_SIZE   260
+#define PS_RESET_CMD_LEN   (HCI_PS_CMD_HDR_LEN + PS_RESET_PARAM_LEN)
+
+#define PS_ID_MASK         0xFF
+
+/* Sends PS commands using vendor specficic HCI commands */
+static int write_ps_cmd(int fd, uint8_t opcode, uint32_t ps_param)
+{
+	uint8_t cmd[HCI_MAX_CMD_SIZE];
+	uint32_t i;
+
+	switch (opcode) {
+	case ENABLE_PATCH:
+		load_hci_ps_hdr(cmd, opcode, 0, 0x00);
+
+		if (write_cmd(fd, cmd, HCI_PS_CMD_HDR_LEN) < 0)
+			return -EILSEQ;
+		break;
+
+	case PS_RESET:
+		load_hci_ps_hdr(cmd, opcode, PS_RESET_PARAM_LEN, 0x00);
+
+		cmd[7] = 0x00;
+		cmd[PS_RESET_CMD_LEN - 2] = ps_param & PS_ID_MASK;
+		cmd[PS_RESET_CMD_LEN - 1] = (ps_param >> 8) & PS_ID_MASK;
+
+		if (write_cmd(fd, cmd, PS_RESET_CMD_LEN) < 0)
+			return -EILSEQ;
+		break;
+
+	case PS_WRITE:
+		for (i = 0; i < ps_param; i++) {
+			load_hci_ps_hdr(cmd, opcode, ps_list[i].len,
+							ps_list[i].id);
+
+			memcpy(&cmd[HCI_PS_CMD_HDR_LEN], ps_list[i].data,
+							ps_list[i].len);
+
+			if (write_cmd(fd, cmd, ps_list[i].len +
+						HCI_PS_CMD_HDR_LEN) < 0)
+				return -EILSEQ;
+		}
+		break;
+	}
+
+	return 0;
+}
+
+#define __is_delim(ch) ((ch) == ':')
+#define MAX_PREAMBLE_LEN 4
+
+/* Parse PS entry preamble of format [X:X] for main type and subtype */
+static int get_ps_type(char *ptr, int index, char *type, char *sub_type)
+{
+	int i;
+	int delim = FALSE;
+
+	if (index > MAX_PREAMBLE_LEN)
+		return -EILSEQ;
+
+	for (i = 1; i < index; i++) {
+		if (__is_delim(ptr[i])) {
+			delim = TRUE;
+			continue;
+		}
+
+		if (isalpha(ptr[i])) {
+			if (delim == FALSE)
+				(*type) = toupper(ptr[i]);
+			else
+				(*sub_type) = toupper(ptr[i]);
+		}
+	}
+
+	return 0;
+}
+
+#define ARRAY   'A'
+#define STRING  'S'
+#define DECIMAL 'D'
+#define BINARY  'B'
+
+#define PS_HEX           0
+#define PS_DEC           1
+
+static int get_input_format(char *buf, struct ps_entry_type *format)
+{
+	char *ptr = NULL;
+	char type = '\0';
+	char sub_type = '\0';
+
+	format->type = PS_HEX;
+	format->array = TRUE;
+
+	if (strstr(buf, "[") != buf)
+		return 0;
+
+	ptr = strstr(buf, "]");
+	if (!ptr)
+		return -EILSEQ;
+
+	if (get_ps_type(buf, ptr - buf, &type, &sub_type) < 0)
+		return -EILSEQ;
+
+	/* Check is data type is of array */
+	if (type == ARRAY || sub_type == ARRAY)
+		format->array = TRUE;
+
+	if (type == STRING || sub_type == STRING)
+		format->array = FALSE;
+
+	if (type == DECIMAL || type == BINARY)
+		format->type = PS_DEC;
+	else
+		format->type = PS_HEX;
+
+	return 0;
+}
+
+#define UNDEFINED 0xFFFF
+
+static unsigned int read_data_in_section(char *buf, struct ps_entry_type type)
+{
+	char *ptr = buf;
+
+	if (!buf)
+		return UNDEFINED;
+
+	if (buf == strstr(buf, "[")) {
+		ptr = strstr(buf, "]");
+		if (!ptr)
+			return UNDEFINED;
+
+		ptr++;
+	}
+
+	if (type.type == PS_HEX && type.array != TRUE)
+		return strtol(ptr, NULL, 16);
+
+	return UNDEFINED;
+}
+
+struct tag_info {
+	unsigned section;
+	unsigned line_count;
+	unsigned char_cnt;
+	unsigned byte_count;
+};
+
+static inline int update_char_count(const char *buf)
+{
+	char *end_ptr;
+
+	if (strstr(buf, "[") == buf) {
+		end_ptr = strstr(buf, "]");
+		if (!end_ptr)
+			return 0;
+		else
+			return (end_ptr - buf) + 1;
+	}
+
+	return 0;
+}
+
+/* Read PS entries as string, convert and add to Hex array */
+static void update_tag_data(struct ps_cfg_entry *tag,
+			    struct tag_info *info, const char *ptr)
+{
+	char buf[3];
+
+	buf[2] = '\0';
+
+	strncpy(buf, &ptr[info->char_cnt], 2);
+	tag->data[info->byte_count] = strtol(buf, NULL, 16);
+	info->char_cnt += 3;
+	info->byte_count++;
+
+	strncpy(buf, &ptr[info->char_cnt], 2);
+	tag->data[info->byte_count] = strtol(buf, NULL, 16);
+	info->char_cnt += 3;
+	info->byte_count++;
+}
+
+#define PS_UNDEF   0
+#define PS_ID      1
+#define PS_LEN     2
+#define PS_DATA    3
+
+#define PS_MAX_LEN         500
+#define LINE_SIZE_MAX      (PS_MAX_LEN * 2)
+#define ENTRY_PER_LINE     16
+
+#define __check_comment(buf) (((buf)[0] == '/') && ((buf)[1] == '/'))
+#define __skip_space(str)      while (*(str) == ' ') ((str)++)
+
+static int ath_parse_ps(FILE *stream)
+{
+	char buf[LINE_SIZE_MAX + 1];
+	char *ptr;
+	uint8_t tag_cnt = 0;
+	int16_t byte_count = 0;
+	struct ps_entry_type format;
+	struct tag_info status = { 0, 0, 0, 0 };
+
+	do {
+		int read_count;
+		struct ps_cfg_entry *tag;
+
+		ptr = fgets(buf, LINE_SIZE_MAX, stream);
+		if (!ptr)
+			break;
+
+		__skip_space(ptr);
+		if (__check_comment(ptr))
+			continue;
+
+		/* Lines with a '#' will be followed by new PS entry */
+		if (ptr == strstr(ptr, "#")) {
+			if (status.section != PS_UNDEF) {
+				return -EILSEQ;
+			} else {
+				status.section = PS_ID;
+				continue;
+			}
+		}
+
+		tag = &ps_list[tag_cnt];
+
+		switch (status.section) {
+		case PS_ID:
+			if (get_input_format(ptr, &format) < 0)
+				return -EILSEQ;
+
+			tag->id = read_data_in_section(ptr, format);
+			status.section = PS_LEN;
+			break;
+
+		case PS_LEN:
+			if (get_input_format(ptr, &format) < 0)
+				return -EILSEQ;
+
+			byte_count = read_data_in_section(ptr, format);
+			if (byte_count > PS_MAX_LEN)
+				return -EILSEQ;
+
+			tag->len = byte_count;
+			tag->data = (uint8_t *)malloc(byte_count);
+
+			status.section = PS_DATA;
+			status.line_count = 0;
+			break;
+
+		case PS_DATA:
+			if (status.line_count == 0)
+				if (get_input_format(ptr, &format) < 0)
+					return -EILSEQ;
+
+			__skip_space(ptr);
+
+			status.char_cnt = update_char_count(ptr);
+
+			read_count = (byte_count > ENTRY_PER_LINE) ?
+					ENTRY_PER_LINE : byte_count;
+
+			if (format.type == PS_HEX && format.array == TRUE) {
+				while (read_count > 0) {
+					update_tag_data(tag, &status, ptr);
+					read_count -= 2;
+				}
+
+				if (byte_count > ENTRY_PER_LINE)
+					byte_count -= ENTRY_PER_LINE;
+				else
+					byte_count = 0;
+			}
+
+			status.line_count++;
+
+			if (byte_count == 0)
+				memset(&status, 0x00, sizeof(struct tag_info));
+
+			if (status.section == PS_UNDEF)
+				tag_cnt++;
+
+			if (tag_cnt == MAX_TAGS)
+				return -EILSEQ;
+			break;
+		}
+	} while (ptr);
+
+	return tag_cnt;
+}
+
+#define MAX_PATCH_CMD 244
+struct patch_entry {
+	int16_t len;
+	uint8_t data[MAX_PATCH_CMD];
+};
+
+static int ps_patch_download(int fd, FILE *stream)
+{
+	char byte[3];
+	char ptr[MAX_PATCH_CMD + 1];
+	int byte_cnt;
+	int patch_count = 0;
+
+	byte[2] = '\0';
+
+	while (fgets(ptr, MAX_PATCH_CMD, stream)) {
+		if (strlen(ptr) <= 1 || !isxdigit(ptr[0]))
+			continue;
+		else
+			break;
+	}
+
+	byte_cnt = strtol(ptr, NULL, 16);
+
+	while (byte_cnt > 0) {
+		int i;
+		uint8_t cmd[HCI_MAX_CMD_SIZE];
+		struct patch_entry patch;
+
+		if (byte_cnt > MAX_PATCH_CMD)
+			patch.len = MAX_PATCH_CMD;
+		else
+			patch.len = byte_cnt;
+
+		for (i = 0; i < patch.len; i++) {
+			if (!fgets(byte, 3, stream))
+				return -1;
+
+			patch.data[i] = strtoul(byte, NULL, 16);
+		}
+
+		load_hci_ps_hdr(cmd, WRITE_PATCH, patch.len, patch_count);
+		memcpy(&cmd[HCI_PS_CMD_HDR_LEN], patch.data, patch.len);
+
+		if (write_cmd(fd, cmd, patch.len + HCI_PS_CMD_HDR_LEN) < 0)
+			return -1;
+
+		patch_count++;
+		byte_cnt = byte_cnt - MAX_PATCH_CMD;
+	}
+
+	if (write_ps_cmd(fd, ENABLE_PATCH, 0) < 0)
+		return -1;
+
+	return patch_count;
+}
+
+#define PS_RAM_SIZE 2048
+
+static int ps_config_download(int fd, int tag_count)
+{
+	if (write_ps_cmd(fd, PS_RESET, PS_RAM_SIZE) < 0)
+		return -1;
+
+	if (tag_count > 0)
+		if (write_ps_cmd(fd, PS_WRITE, tag_count) < 0)
+			return -1;
+	return 0;
+}
+
+#define PS_ASIC_FILE			"PS_ASIC.pst"
+#define PS_FPGA_FILE			"PS_FPGA.pst"
+
+static void get_ps_file_name(uint32_t devtype, uint32_t rom_version,
+							char *path)
+{
+	char *filename;
+
+	if (devtype == 0xdeadc0de)
+		filename = PS_ASIC_FILE;
+	else
+		filename = PS_FPGA_FILE;
+
+	snprintf(path, MAXPATHLEN, "%s%x/%s", FW_PATH, rom_version, filename);
+}
+
+#define PATCH_FILE        "RamPatch.txt"
+#define FPGA_ROM_VERSION  0x99999999
+#define ROM_DEV_TYPE      0xdeadc0de
+
+static void get_patch_file_name(uint32_t dev_type, uint32_t rom_version,
+				uint32_t build_version, char *path)
+{
+	if (rom_version == FPGA_ROM_VERSION && dev_type != ROM_DEV_TYPE &&
+					dev_type != 0 && build_version == 1)
+		path[0] = '\0';
+	else
+		snprintf(path, MAXPATHLEN, "%s%x/%s",
+				FW_PATH, rom_version, PATCH_FILE);
+}
+
+#define VERIFY_CRC   9
+#define PS_REGION    1
+#define PATCH_REGION 2
+
+static int get_ath3k_crc(int dev)
+{
+	uint8_t cmd[7];
+	uint8_t *event;
+	int err;
+
+	load_hci_ps_hdr(cmd, VERIFY_CRC, 0, PS_REGION | PATCH_REGION);
+
+	err = send_hci_cmd_sync(dev, cmd, sizeof(cmd), &event);
+	if (err < 0)
+		return err;
+	/* Send error code if CRC check patched */
+	if (read_ps_event(event, HCI_PS_CMD_OCF) >= 0)
+		err = -EILSEQ;
+
+	if (!event)
+		free(event);
+
+	return err;
+}
+
+#define DEV_REGISTER      0x4FFC
+#define GET_DEV_TYPE_OCF  0x05
+
+static int get_device_type(int dev, uint32_t *code)
+{
+	uint8_t cmd[8];
+	uint8_t *event;
+	uint32_t reg;
+	int err;
+	uint8_t *ptr = cmd;
+	hci_command_hdr *ch = (void *)cmd;
+
+	ch->opcode = htobs(cmd_opcode_pack(HCI_VENDOR_CMD_OGF,
+						GET_DEV_TYPE_OCF));
+	ch->plen = 5;
+	ptr += HCI_COMMAND_HDR_SIZE;
+
+	ptr[0] = (uint8_t)DEV_REGISTER;
+	ptr[1] = (uint8_t)DEV_REGISTER >> 8;
+	ptr[2] = (uint8_t)DEV_REGISTER >> 16;
+	ptr[3] = (uint8_t)DEV_REGISTER >> 24;
+	ptr[4] = 0x04;
+
+	err = send_hci_cmd_sync(dev, cmd, sizeof(cmd), &event);
+	if (err < 0)
+		return err;
+
+	err = read_ps_event(event, GET_DEV_TYPE_OCF);
+	if (err < 0)
+		goto cleanup;
+
+	reg = event[10];
+	reg = (reg << 8) | event[9];
+	reg = (reg << 8) | event[8];
+	reg = (reg << 8) | event[7];
+	*code = reg;
+
+cleanup:
+	if (event)
+		free(event);
+
+	return err;
+}
+
+#define GET_VERSION_OCF 0x1E
+
+static int read_ath3k_version(int pConfig, uint32_t *rom_version,
+					uint32_t *build_version)
+{
+	uint8_t cmd[3];
+	uint8_t *event;
+	int err;
+	int status;
+	hci_command_hdr *ch = (void *)cmd;
+
+	ch->opcode = htobs(cmd_opcode_pack(HCI_VENDOR_CMD_OGF,
+						GET_VERSION_OCF));
+	ch->plen = 0;
+
+	err = send_hci_cmd_sync(pConfig, cmd, sizeof(cmd), &event);
+	if (err < 0)
+		return err;
+
+	err = read_ps_event(event, GET_VERSION_OCF);
+	if (err < 0)
+		goto cleanup;
+
+	status = event[10];
+	status = (status << 8) | event[9];
+	status = (status << 8) | event[8];
+	status = (status << 8) | event[7];
+	*rom_version = status;
+
+	status = event[14];
+	status = (status << 8) | event[13];
+	status = (status << 8) | event[12];
+	status = (status << 8) | event[11];
+	*build_version = status;
+
+cleanup:
+	if (event)
+		free(event);
+
+	return err;
+}
+
+static void convert_bdaddr(char *str_bdaddr, char *bdaddr)
+{
+	char bdbyte[3];
+	char *str_byte = str_bdaddr;
+	int i, j;
+	int colon_present = 0;
+
+	if (strstr(str_bdaddr, ":"))
+		colon_present = 1;
+
+	bdbyte[2] = '\0';
+
+	/* Reverse the BDADDR to LSB first */
+	for (i = 0, j = 5; i < 6; i++, j--) {
+		bdbyte[0] = str_byte[0];
+		bdbyte[1] = str_byte[1];
+		bdaddr[j] = strtol(bdbyte, NULL, 16);
+
+		if (colon_present == 1)
+			str_byte += 3;
+		else
+			str_byte += 2;
+	}
+}
+
+static int write_bdaddr(int pConfig, char *bdaddr)
+{
+	uint8_t *event;
+	int err;
+	uint8_t cmd[13];
+	uint8_t *ptr = cmd;
+	hci_command_hdr *ch = (void *)cmd;
+
+	memset(cmd, 0, sizeof(cmd));
+
+	ch->opcode = htobs(cmd_opcode_pack(HCI_VENDOR_CMD_OGF,
+						HCI_PS_CMD_OCF));
+	ch->plen = 10;
+	ptr += HCI_COMMAND_HDR_SIZE;
+
+	ptr[0] = 0x01;
+	ptr[1] = 0x01;
+	ptr[2] = 0x00;
+	ptr[3] = 0x06;
+
+	convert_bdaddr(bdaddr, (char *)&ptr[4]);
+
+	err = send_hci_cmd_sync(pConfig, cmd, sizeof(cmd), &event);
+	if (err < 0)
+		return err;
+
+	err = read_ps_event(event, HCI_PS_CMD_OCF);
+
+	if (event)
+		free(event);
+
+	return err;
+}
+
+#define BDADDR_FILE "ar3kbdaddr.pst"
+
+static void write_bdaddr_from_file(int rom_version, int fd)
+{
+	FILE *stream;
+	char bdaddr[PATH_MAX];
+	char bdaddr_file[PATH_MAX];
+
+	snprintf(bdaddr_file, MAXPATHLEN, "%s%x/%s",
+			FW_PATH, rom_version, BDADDR_FILE);
+
+	stream = fopen(bdaddr_file, "r");
+	if (!stream)
+		return;
+
+	if (fgets(bdaddr, PATH_MAX - 1, stream))
+		write_bdaddr(fd, bdaddr);
+
+	fclose(stream);
+}
+
+static int ath_ps_download(int fd)
+{
+	int err = 0;
+	int tag_count;
+	int patch_count = 0;
+	uint32_t rom_version = 0;
+	uint32_t build_version = 0;
+	uint32_t dev_type = 0;
+	char patch_file[PATH_MAX];
+	char ps_file[PATH_MAX];
+	FILE *stream;
+
+	/*
+	 * Verfiy firmware version. depending on it select the PS
+	 * config file to download.
+	 */
+	if (get_device_type(fd, &dev_type) < 0) {
+		err = -EILSEQ;
+		goto download_cmplete;
+	}
+
+	if (read_ath3k_version(fd, &rom_version, &build_version) < 0) {
+		err = -EILSEQ;
+		goto download_cmplete;
+	}
+
+	/* Do not download configuration if CRC passes */
+	if (get_ath3k_crc(fd) < 0) {
+		err = 0;
+		goto download_cmplete;
+	}
+
+	get_ps_file_name(dev_type, rom_version, ps_file);
+	get_patch_file_name(dev_type, rom_version, build_version, patch_file);
+
+	stream = fopen(ps_file, "r");
+	if (!stream) {
+		perror("firmware file open error\n");
+		err = -EILSEQ;
+		goto download_cmplete;
+	}
+	tag_count = ath_parse_ps(stream);
+
+	fclose(stream);
+
+	if (tag_count < 0) {
+		err = -EILSEQ;
+		goto download_cmplete;
+	}
+
+	/*
+	 * It is not necessary that Patch file be available,
+	 * continue with PS Operations if patch file is not available.
+	 */
+	if (patch_file[0] == '\0')
+		err = 0;
+
+	stream = fopen(patch_file, "r");
+	if (!stream)
+		err = 0;
+	else {
+		patch_count = ps_patch_download(fd, stream);
+		fclose(stream);
+
+		if (patch_count < 0) {
+			err = -EILSEQ;
+			goto download_cmplete;
+		}
+	}
+
+	err = ps_config_download(fd, tag_count);
+
+download_cmplete:
+	if (!err)
+		write_bdaddr_from_file(rom_version, fd);
+
+	return err;
+}
+
+#define HCI_SLEEP_CMD_OCF     0x04
+
+/*
+ * Atheros AR300x specific initialization post callback
+ */
+int ath3k_post(int fd, int pm)
+{
+	int dev_id, dd;
+	struct timespec tm = { 0, 50000 };
+
+	dev_id = ioctl(fd, HCIUARTGETDEVICE, 0);
+	if (dev_id < 0) {
+		perror("cannot get device id");
+		return dev_id;
+	}
+
+	dd = hci_open_dev(dev_id);
+	if (dd < 0) {
+		perror("HCI device open failed");
+		return dd;
+	}
+
+	sleep(2);
+
+	/* send vendor specific command with Sleep feature Enabled */
+	if (hci_send_cmd(dd, OGF_VENDOR_CMD, HCI_SLEEP_CMD_OCF,	1, &pm) < 0)
+		perror("Power management Disabled");
+
+	nanosleep(&tm, NULL);
+	hci_close_dev(dd);
+
+	return 0;
+}
+
+#define HCI_VENDOR_CMD_OGF    0x3F
+#define HCI_PS_CMD_OCF        0x0B
+#define HCI_CHG_BAUD_CMD_OCF  0x0C
+
+#define WRITE_BDADDR_CMD_LEN 14
+#define WRITE_BAUD_CMD_LEN   6
+#define MAX_CMD_LEN          WRITE_BDADDR_CMD_LEN
+
+/*
+ * Atheros AR300x specific initialization and configuration file
+ * download
+ */
+int ath3k_init(int fd, char *bdaddr, int speed)
+{
+	int r;
+	int baud;
+	struct timespec tm = { 0, 500000 };
+	unsigned char cmd[MAX_CMD_LEN], rsp[HCI_MAX_EVENT_SIZE];
+	unsigned char *ptr = cmd + 1;
+	hci_command_hdr *ch = (void *)ptr;
+
+	cmd[0] = HCI_COMMAND_PKT;
+
+	/* Download PS and patch */
+	r = ath_ps_download(fd);
+	if (r < 0) {
+		perror("Failed to Download configuration");
+		return -ETIMEDOUT;
+	}
+
+	/* Write BDADDR */
+	if (bdaddr) {
+		ch->opcode = htobs(cmd_opcode_pack(HCI_VENDOR_CMD_OGF,
+							HCI_PS_CMD_OCF));
+		ch->plen = 10;
+		ptr += HCI_COMMAND_HDR_SIZE;
+
+		ptr[0] = 0x01;
+		ptr[1] = 0x01;
+		ptr[2] = 0x00;
+		ptr[3] = 0x06;
+		str2ba(bdaddr, (bdaddr_t *)(ptr + 4));
+
+		if (write(fd, cmd, WRITE_BDADDR_CMD_LEN) !=
+					WRITE_BDADDR_CMD_LEN) {
+			perror("Failed to write BD_ADDR command\n");
+			return -ETIMEDOUT;
+		}
+
+		if (read_hci_event(fd, rsp, sizeof(rsp)) < 0) {
+			perror("Failed to set BD_ADDR\n");
+			return -ETIMEDOUT;
+		}
+	}
+
+	/* Send HCI Reset */
+	cmd[1] = 0x03;
+	cmd[2] = 0x0C;
+	cmd[3] = 0x00;
+
+	r = write(fd, cmd, 4);
+	if (r != 4)
+		return -ETIMEDOUT;
+
+	nanosleep(&tm, NULL);
+	if (read_hci_event(fd, rsp, sizeof(rsp)) < 0)
+		return -ETIMEDOUT;
+
+	/* set controller baud rate to user specified value */
+	ptr = cmd + 1;
+	ch->opcode = htobs(cmd_opcode_pack(HCI_VENDOR_CMD_OGF,
+						HCI_CHG_BAUD_CMD_OCF));
+	ch->plen = 2;
+	ptr += HCI_COMMAND_HDR_SIZE;
+
+	baud = speed/100;
+	ptr[0] = (char)baud;
+	ptr[1] = (char)(baud >> 8);
+
+	if (write(fd, cmd, WRITE_BAUD_CMD_LEN) != WRITE_BAUD_CMD_LEN) {
+		perror("Failed to write change baud rate command");
+		return -ETIMEDOUT;
+	}
+
+	nanosleep(&tm, NULL);
+
+	if (read_hci_event(fd, rsp, sizeof(rsp)) < 0)
+		return -ETIMEDOUT;
+
+	return 0;
+}
-- 
1.7.0.4


^ permalink raw reply related

* [PATCH] sdp: Remove sdp_general_inquiry API
From: Zhenhua Zhang @ 2010-08-18 10:13 UTC (permalink / raw)
  To: linux-bluetooth

So that sdp.c won't include hci.h and hci_lib.h. The inquiry operation
could be done by simply invoking hci_inquiry().
---
 lib/sdp.c       |   16 ----------------
 lib/sdp_lib.h   |    5 -----
 tools/sdptool.c |    6 ++++--
 3 files changed, 4 insertions(+), 23 deletions(-)

diff --git a/lib/sdp.c b/lib/sdp.c
index 8a31b55..76695af 100644
--- a/lib/sdp.c
+++ b/lib/sdp.c
@@ -43,8 +43,6 @@
 #include <netinet/in.h>
 
 #include "bluetooth.h"
-#include "hci.h"
-#include "hci_lib.h"
 #include "l2cap.h"
 #include "sdp.h"
 #include "sdp_lib.h"
@@ -4523,20 +4521,6 @@ end:
 	return status;
 }
 
-/*
- * Find devices in the piconet.
- */
-int sdp_general_inquiry(inquiry_info *ii, int num_dev, int duration, uint8_t *found)
-{
-	int n = hci_inquiry(-1, 10, num_dev, NULL, &ii, 0);
-	if (n < 0) {
-		SDPERR("Inquiry failed:%s", strerror(errno));
-		return -1;
-	}
-	*found = n;
-	return 0;
-}
-
 int sdp_close(sdp_session_t *session)
 {
 	struct sdp_transaction *t;
diff --git a/lib/sdp_lib.h b/lib/sdp_lib.h
index e506ac1..5ad4b56 100644
--- a/lib/sdp_lib.h
+++ b/lib/sdp_lib.h
@@ -146,11 +146,6 @@ int sdp_service_search_attr_async(sdp_session_t *session, const sdp_list_t *sear
 
 uint16_t sdp_gen_tid(sdp_session_t *session);
 
-/*
- * find all devices in the piconet
- */
-int sdp_general_inquiry(inquiry_info *ii, int dev_num, int duration, uint8_t *found);
-
 /* flexible extraction of basic attributes - Jean II */
 int sdp_get_int_attr(const sdp_record_t *rec, uint16_t attr, int *value);
 int sdp_get_string_attr(const sdp_record_t *rec, uint16_t attr, char *value, int valuelen);
diff --git a/tools/sdptool.c b/tools/sdptool.c
index d06b159..3ce0fc3 100644
--- a/tools/sdptool.c
+++ b/tools/sdptool.c
@@ -3733,11 +3733,13 @@ static int cmd_del(int argc, char **argv)
 static void inquiry(handler_t handler, void *arg)
 {
 	inquiry_info ii[20];
-	uint8_t count = 0;
+	int count = 0;
 	int i;
 
 	printf("Inquiring ...\n");
-	if (sdp_general_inquiry(ii, 20, 8, &count) < 0) {
+
+	count = hci_inquiry(-1, 10, 20, NULL, (inquiry_info **) &ii, 0);
+	if (count < 0) {
 		printf("Inquiry failed\n");
 		return;
 	}
-- 
1.7.0.4


^ permalink raw reply related

* Re: [PATCH v4] Bluetooth: host level Support for Atheros AR300x device
From: Johan Hedberg @ 2010-08-18 10:30 UTC (permalink / raw)
  To: Suraj Sumangala; +Cc: linux-bluetooth
In-Reply-To: <1282123768-27981-1-git-send-email-suraj@atheros.com>

Hi Suraj,

On Wed, Aug 18, 2010, Suraj Sumangala wrote:
> Implements support for Atheros AR300x Bluetooth chip in
> hciattach application. Supports configuration download
> and power management configure feature.
> ---
>  Makefile.tools          |    3 +-
>  tools/hciattach.8       |    3 +
>  tools/hciattach.c       |   12 +
>  tools/hciattach.h       |    3 +
>  tools/hciattach_ath3k.c |  953 +++++++++++++++++++++++++++++++++++++++++++++++
>  5 files changed, 973 insertions(+), 1 deletions(-)
>  create mode 100644 tools/hciattach_ath3k.c

Thanks. The patch is now pushed upstream with a minor cleanup of the
commit message as well as the following coding style issue:

> +static void update_tag_data(struct ps_cfg_entry *tag,
> +			    struct tag_info *info, const char *ptr)

The second line uses mixed tabs and spaces for indentation (it should
only be tabs).

Johan

^ permalink raw reply

* [PATCH 0/5] Fast connectable mode for HFP (update)
From: Dmitriy Paliy @ 2010-08-18 10:35 UTC (permalink / raw)
  To: linux-bluetooth

Hi,

The following patches are implementation of fast connectable mode for HFP.
Such mode means significantly shorter page scan interval and interlaced
page scan type. As a result, HFP connection typically is created much faster.
The fast connectable mode can be activated by incomming call indicator and
deactivated by answer or reject call indicator. Such speeds up connectability
of a headset when there is an incomming call. Retransmisions in eSCO are
possiblle to be paused for in-band ring tone when the mode is enabled during
given above period of time. eSCO is not affected during call since page scan
settings are returned to their default values immidiately after call is
accepted (or rejected).

Use of the mode can be enabled by changing FastConnectable in audio.conf
configuration file. It is disabled by default. Also, it doesn't affect and
doesn't change any other interfaces.

Br,
Dmitriy



^ permalink raw reply

* [PATCH 1/5] Add STANDARD and INTERLACED page scan definitions
From: Dmitriy Paliy @ 2010-08-18 10:35 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Dmitriy Paliy
In-Reply-To: <1282127760-12655-1-git-send-email-dmitriy.paliy@nokia.com>

Added standard and interlaced page scan type definitions. Used for
both read and write page scan type HCI commands.
---
 lib/hci.h |    2 ++
 1 files changed, 2 insertions(+), 0 deletions(-)

diff --git a/lib/hci.h b/lib/hci.h
index f31918d..0369ee2 100644
--- a/lib/hci.h
+++ b/lib/hci.h
@@ -992,6 +992,8 @@ typedef struct {
 #define OCF_READ_PAGE_SCAN_TYPE		0x0046
 
 #define OCF_WRITE_PAGE_SCAN_TYPE	0x0047
+	#define PAGE_SCAN_TYPE_STANDARD		0x00
+	#define PAGE_SCAN_TYPE_INTERLACED	0x01
 
 #define OCF_READ_AFH_MODE		0x0048
 typedef struct {
-- 
1.7.0.4


^ permalink raw reply related

* [PATCH 2/5] Add fast connectable to hciops
From: Dmitriy Paliy @ 2010-08-18 10:35 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Dmitriy Paliy
In-Reply-To: <1282127760-12655-1-git-send-email-dmitriy.paliy@nokia.com>

Fast connectable switches between two sets of parameters to enable
or disable fast page scan mode. Page scan interval and page scan
type are changed to speed up connectabily when needed. When
disabled it sets default values. List of btd_adapter_ops is updated
respectively.
---
 plugins/hciops.c |   33 +++++++++++++++++++++++++++++++++
 src/adapter.h    |    1 +
 2 files changed, 34 insertions(+), 0 deletions(-)

diff --git a/plugins/hciops.c b/plugins/hciops.c
index 9c97c5a..f1e9f69 100644
--- a/plugins/hciops.c
+++ b/plugins/hciops.c
@@ -716,6 +716,38 @@ static int hciops_cancel_resolve_name(int index, bdaddr_t *bdaddr)
 	return err;
 }
 
+static int hciops_fast_connectable(int index, gboolean enable)
+{
+	int dd, err = 0;
+	write_page_activity_cp cp;
+	uint8_t type;
+
+	if (enable) {
+		type = PAGE_SCAN_TYPE_INTERLACED;
+		cp.interval = 0x0024;	/* 22.5 msec page scan interval */
+	} else {
+		type = PAGE_SCAN_TYPE_STANDARD;	/* default */
+		cp.interval = 0x0800;	/* default 1.28 sec page scan */
+	}
+
+	cp.window = 0x0012;	/* default 11.25 msec page scan window */
+
+	dd = hci_open_dev(index);
+	if (dd < 0)
+		return -EIO;
+
+	if (hci_send_cmd(dd, OGF_HOST_CTL, OCF_WRITE_PAGE_ACTIVITY,
+					WRITE_PAGE_ACTIVITY_CP_SIZE, &cp) < 0)
+		err = -errno;
+	else if (hci_send_cmd(dd, OGF_HOST_CTL, OCF_WRITE_PAGE_SCAN_TYPE,
+								1, &type) < 0)
+		err = -errno;
+
+	hci_close_dev(dd);
+
+	return err;
+}
+
 static struct btd_adapter_ops hci_ops = {
 	.setup = hciops_setup,
 	.cleanup = hciops_cleanup,
@@ -732,6 +764,7 @@ static struct btd_adapter_ops hci_ops = {
 	.set_name = hciops_set_name,
 	.read_name = hciops_read_name,
 	.set_class = hciops_set_class,
+	.set_fast_connectable = hciops_fast_connectable,
 };
 
 static int hciops_init(void)
diff --git a/src/adapter.h b/src/adapter.h
index 58853ac..657e035 100644
--- a/src/adapter.h
+++ b/src/adapter.h
@@ -183,6 +183,7 @@ struct btd_adapter_ops {
 	int (*set_name) (int index, const char *name);
 	int (*read_name) (int index);
 	int (*set_class) (int index, uint32_t class);
+	int (*set_fast_connectable) (int index, gboolean enable);
 };
 
 int btd_register_adapter_ops(struct btd_adapter_ops *btd_adapter_ops);
-- 
1.7.0.4


^ permalink raw reply related

* [PATCH 3/5] Add set fast connectable to adapter
From: Dmitriy Paliy @ 2010-08-18 10:35 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Dmitriy Paliy
In-Reply-To: <1282127760-12655-1-git-send-email-dmitriy.paliy@nokia.com>

Set fast connectable added to adapter interface. Enables or disables
faster page scanning. It does not interfere with any other adapter's
interfaces.
---
 src/adapter.c |   12 ++++++++++++
 src/adapter.h |    6 ++++++
 2 files changed, 18 insertions(+), 0 deletions(-)

diff --git a/src/adapter.c b/src/adapter.c
index 4ad4165..b023c01 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -3454,3 +3454,15 @@ void btd_adapter_unregister_powered_callback(struct btd_adapter *adapter,
 	adapter->powered_callbacks =
 			g_slist_remove(adapter->powered_callbacks, cb);
 }
+
+int btd_adapter_set_fast_connectable(struct btd_adapter *adapter,
+							gboolean enable)
+{
+	if (!adapter_ops)
+		return -EINVAL;
+
+	if (!adapter->up)
+		return -EINVAL;
+
+	return adapter_ops->set_fast_connectable(adapter->dev_id, enable);
+}
diff --git a/src/adapter.h b/src/adapter.h
index 657e035..5352731 100644
--- a/src/adapter.h
+++ b/src/adapter.h
@@ -196,3 +196,9 @@ void btd_adapter_register_powered_callback(struct btd_adapter *adapter,
 						btd_adapter_powered_cb cb);
 void btd_adapter_unregister_powered_callback(struct btd_adapter *adapter,
 						btd_adapter_powered_cb cb);
+
+/* If TRUE, enables fast connectabe, i.e. reduces page scan interval and changes
+ * type. If FALSE, disables fast connectable, i.e. sets page scan interval and
+ * type to default values. Valid for both connectable and discoverable modes. */
+int btd_adapter_set_fast_connectable(struct btd_adapter *adapter,
+							gboolean enable);
-- 
1.7.0.4


^ permalink raw reply related

* [PATCH 4/5] Add set fast connectable to audio manager
From: Dmitriy Paliy @ 2010-08-18 10:35 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Dmitriy Paliy
In-Reply-To: <1282127760-12655-1-git-send-email-dmitriy.paliy@nokia.com>

Set fast connectable added to audio manager interface. Enables
fast connectable mode for all audio adapters or sets respective
values to default when disabled. It does not interfere with any
other audio manager's interfaces, modes, or states.
---
 audio/manager.c |   14 ++++++++++++++
 audio/manager.h |    4 ++++
 2 files changed, 18 insertions(+), 0 deletions(-)

diff --git a/audio/manager.c b/audio/manager.c
index 6dd0f87..3db5987 100644
--- a/audio/manager.c
+++ b/audio/manager.c
@@ -1290,3 +1290,17 @@ gboolean manager_allow_headset_connection(struct audio_device *device)
 
 	return TRUE;
 }
+
+void manager_set_fast_connectable(gboolean enable)
+{
+	GSList *l;
+
+	for (l = adapters; l != NULL; l = l->next) {
+		struct audio_adapter *adapter = l->data;
+
+		if (btd_adapter_set_fast_connectable(adapter->btd_adapter,
+								enable))
+			error("Changing fast connectable for hci%d failed",
+				adapter_get_dev_id(adapter->btd_adapter));
+	}
+}
diff --git a/audio/manager.h b/audio/manager.h
index 8e1abf4..90fe6f0 100644
--- a/audio/manager.h
+++ b/audio/manager.h
@@ -48,3 +48,7 @@ struct audio_device *manager_get_device(const bdaddr_t *src,
 					gboolean create);
 
 gboolean manager_allow_headset_connection(struct audio_device *device);
+
+/* TRUE to enable fast connectable and FALSE to disable fast connectable for all
+ * audio adapters. */
+void manager_set_fast_connectable(gboolean enable);
-- 
1.7.0.4


^ permalink raw reply related

* [PATCH 5/5] Add fast connectable support to HFP
From: Dmitriy Paliy @ 2010-08-18 10:36 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Dmitriy Paliy
In-Reply-To: <1282127760-12655-1-git-send-email-dmitriy.paliy@nokia.com>

Audio.conf is updated to support fast connectable mode. Set
FastConnectable to true to enable and to false to disable. Headset
initialization and call indicators are updated respectively. It is
disabled by default.
---
 audio/audio.conf |    7 +++++++
 audio/headset.c  |   20 ++++++++++++++++++++
 2 files changed, 27 insertions(+), 0 deletions(-)

diff --git a/audio/audio.conf b/audio/audio.conf
index a64fb66..302e046 100644
--- a/audio/audio.conf
+++ b/audio/audio.conf
@@ -32,6 +32,13 @@ HFP=true
 # Maximum number of connected HSP/HFP devices per adapter. Defaults to 1
 MaxConnected=1
 
+# Set to true to enable use of fast connectable mode (faster page scanning)
+# for HFP when incomming call starts. Default settings are restored after
+# call is answered or rejected. Page scan interval is much shorter and page
+# scan type changed to interlaced. Such allows faster connection initiated
+# by a headset.
+FastConnectable=false
+
 # Just an example of potential config options for the other interfaces
 #[A2DP]
 #SBCSources=1
diff --git a/audio/headset.c b/audio/headset.c
index 99d4c7a..cdb3370 100644
--- a/audio/headset.c
+++ b/audio/headset.c
@@ -95,6 +95,7 @@ static struct {
 };
 
 static gboolean sco_hci = TRUE;
+static gboolean fast_connectable = FALSE;
 
 static GSList *active_devices = NULL;
 
@@ -2262,6 +2263,19 @@ uint32_t headset_config_init(GKeyFile *config)
 		g_free(str);
 	}
 
+	/* Init fast connectable option */
+	str = g_key_file_get_string(config, "Headset", "FastConnectable",
+					&err);
+	if (err) {
+		DBG("audio.conf: %s", err->message);
+		g_clear_error(&err);
+	} else {
+		fast_connectable = strcmp(str, "true") == 0;
+		if (fast_connectable)
+			manager_set_fast_connectable(FALSE);
+		g_free(str);
+	}
+
 	return ag.features;
 }
 
@@ -2743,6 +2757,9 @@ int telephony_incoming_call_ind(const char *number, int type)
 	struct headset *hs;
 	struct headset_slc *slc;
 
+	if (fast_connectable)
+		manager_set_fast_connectable(TRUE);
+
 	if (!active_devices)
 		return -ENODEV;
 
@@ -2782,6 +2799,9 @@ int telephony_calling_stopped_ind(void)
 {
 	struct audio_device *dev;
 
+	if (fast_connectable)
+		manager_set_fast_connectable(FALSE);
+
 	if (ag.ring_timer) {
 		g_source_remove(ag.ring_timer);
 		ag.ring_timer = 0;
-- 
1.7.0.4


^ permalink raw reply related

* Re: [PATCH 0/5] Fast connectable mode for HFP (update)
From: Johan Hedberg @ 2010-08-18 11:15 UTC (permalink / raw)
  To: Dmitriy Paliy; +Cc: linux-bluetooth
In-Reply-To: <1282127760-12655-1-git-send-email-dmitriy.paliy@nokia.com>

Hi Dmitry,

On Wed, Aug 18, 2010, Dmitriy Paliy wrote:
> The following patches are implementation of fast connectable mode for HFP.
> Such mode means significantly shorter page scan interval and interlaced
> page scan type. As a result, HFP connection typically is created much faster.
> The fast connectable mode can be activated by incomming call indicator and
> deactivated by answer or reject call indicator. Such speeds up connectability
> of a headset when there is an incomming call. Retransmisions in eSCO are
> possiblle to be paused for in-band ring tone when the mode is enabled during
> given above period of time. eSCO is not affected during call since page scan
> settings are returned to their default values immidiately after call is
> accepted (or rejected).
> 
> Use of the mode can be enabled by changing FastConnectable in audio.conf
> configuration file. It is disabled by default. Also, it doesn't affect and
> doesn't change any other interfaces.

Thanks for the patches. They've all been pushed upstream.

One thing that still needs discussing/consideration is the safeguard for
setting the correct mode if bluetoothd crashed while we were in the fast
connectable mode. Right now your patches take care of this in the audio
plugin but in the future if other users of this new core daemon API come
up the proper intialization should (imho) be inside the core daemon. We
already do this for things like periodic inquiry where bluetoothd always
sends the HCI_Exit_Periodic_Inquiry_Mode command when it starts up (in
case bluetoothd previously crashed while discovering devices).

Johan

^ permalink raw reply

* Re: [PATCH 3/3] Maemo6 MCE: handle race condition at startup
From: Daniel Örstadius @ 2010-08-18 11:25 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <AANLkTikOj==zpA90bNAY0wVgXwQs1=a279RY8MNuz_KF@mail.gmail.com>

[-- Attachment #1: Type: text/plain, Size: 558 bytes --]

On Fri, Aug 13, 2010 at 12:19 PM, Daniel Örstadius
<daniel.orstadius@gmail.com> wrote:
> Since bluetoothd power cycles the adapter at startup, it is possible
> that the plugin gets a reply from reading the state of the MCE and
> tries to power the adapter before it is down. The patch checks for
> that situation and if it occurs postpones powering the adapter to
> the mode change callback. The off_requested member of btd_adapter
> is used for the check, so it is set to FALSE when the adapter is
> down.
>

Attaching updated patch.

/Daniel

[-- Attachment #2: 0001-Maemo6-MCE-handle-race-condition-at-startup.patch --]
[-- Type: text/x-patch, Size: 2533 bytes --]

From ab1249f50673d6da226c1d8f490b962d999fd890 Mon Sep 17 00:00:00 2001
From: Daniel Orstadius <daniel.orstadius@nokia.com>
Date: Wed, 18 Aug 2010 14:22:31 +0300
Subject: [PATCH] Maemo6 MCE: handle race condition at startup

Since bluetoothd power cycles the adapter at startup, it is possible
that the plugin gets a reply from reading the state of the MCE and
tries to power the adapter before it is down. The patch checks for
that situation and if it occurs postpones powering the adapter to
the powered state callback. The off_requested member of btd_adapter
is used for the check, so it is set to FALSE when the adapter is
down.
---
 plugins/maemo6.c |   22 ++++++++++++++++++++++
 src/adapter.c    |    1 +
 2 files changed, 23 insertions(+), 0 deletions(-)

diff --git a/plugins/maemo6.c b/plugins/maemo6.c
index 55ea508..ad86c30 100644
--- a/plugins/maemo6.c
+++ b/plugins/maemo6.c
@@ -50,6 +50,7 @@
 static guint watch_id;
 static DBusConnection *conn = NULL;
 static gboolean mce_bt_set = FALSE;
+static gboolean collision = FALSE;
 
 static gboolean mce_signal_callback(DBusConnection *connection,
 					DBusMessage *message, void *user_data)
@@ -112,6 +113,14 @@ static void read_radio_states_cb(DBusPendingCall *call, void *user_data)
 
 	mce_bt_set = radio_states & MCE_RADIO_STATE_BLUETOOTH;
 
+	/* check if the adapter has not completed the initial power
+	   cycle, if so delay action to mce_notify_powered */
+
+	collision = mce_bt_set && adapter_powering_down(adapter);
+
+	if (collision)
+		goto done;
+
 	if (mce_bt_set)
 		btd_adapter_switch_online(adapter);
 	else
@@ -129,6 +138,19 @@ static void adapter_powered(struct btd_adapter *adapter, gboolean powered)
 
 	DBG("adapter_powered called with %d", powered);
 
+	/* check if the plugin got the get_radio_states reply from the
+	   mce when the adapter was not yet down during the power
+	   cycling when bluetoothd is started */
+	if (collision) {
+		error("maemo6: powered state collision");
+		collision = FALSE;
+
+		if (mce_bt_set)
+			btd_adapter_switch_online(adapter);
+
+		return;
+	}
+
 	/* nothing to do if the states match */
 	if (mce_bt_set == powered)
 		return;
diff --git a/src/adapter.c b/src/adapter.c
index 4ad4165..98db2d5 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -2502,6 +2502,7 @@ int adapter_stop(struct btd_adapter *adapter)
 	adapter->state = DISCOVER_TYPE_NONE;
 	adapter->cache_enable = TRUE;
 	adapter->pending_cod = 0;
+	adapter->off_requested = FALSE;
 
 	call_adapter_powered_callbacks(adapter, FALSE);
 
-- 
1.6.0.4


^ permalink raw reply related

* Re: [PATCH] sdp: Remove sdp_general_inquiry API
From: Marcel Holtmann @ 2010-08-18 11:59 UTC (permalink / raw)
  To: Zhenhua Zhang; +Cc: linux-bluetooth
In-Reply-To: <1282126410-6157-1-git-send-email-zhenhua.zhang@intel.com>

Hi Zhenhua,

> So that sdp.c won't include hci.h and hci_lib.h. The inquiry operation
> could be done by simply invoking hci_inquiry().
> ---
>  lib/sdp.c       |   16 ----------------
>  lib/sdp_lib.h   |    5 -----
>  tools/sdptool.c |    6 ++++--
>  3 files changed, 4 insertions(+), 23 deletions(-)
> 
> diff --git a/lib/sdp.c b/lib/sdp.c
> index 8a31b55..76695af 100644
> --- a/lib/sdp.c
> +++ b/lib/sdp.c
> @@ -43,8 +43,6 @@
>  #include <netinet/in.h>
>  
>  #include "bluetooth.h"
> -#include "hci.h"
> -#include "hci_lib.h"
>  #include "l2cap.h"
>  #include "sdp.h"
>  #include "sdp_lib.h"
> @@ -4523,20 +4521,6 @@ end:
>  	return status;
>  }
>  
> -/*
> - * Find devices in the piconet.
> - */
> -int sdp_general_inquiry(inquiry_info *ii, int num_dev, int duration, uint8_t *found)
> -{
> -	int n = hci_inquiry(-1, 10, num_dev, NULL, &ii, 0);
> -	if (n < 0) {
> -		SDPERR("Inquiry failed:%s", strerror(errno));
> -		return -1;
> -	}
> -	*found = n;
> -	return 0;
> -}
> -

this breaks API and ABI compatibility. Even if most likely nobody in the
world uses this function, we should keep it for now.

>  int sdp_close(sdp_session_t *session)
>  {
>  	struct sdp_transaction *t;
> diff --git a/lib/sdp_lib.h b/lib/sdp_lib.h
> index e506ac1..5ad4b56 100644
> --- a/lib/sdp_lib.h
> +++ b/lib/sdp_lib.h
> @@ -146,11 +146,6 @@ int sdp_service_search_attr_async(sdp_session_t *session, const sdp_list_t *sear
>  
>  uint16_t sdp_gen_tid(sdp_session_t *session);
>  
> -/*
> - * find all devices in the piconet
> - */
> -int sdp_general_inquiry(inquiry_info *ii, int dev_num, int duration, uint8_t *found);
> -
>  /* flexible extraction of basic attributes - Jean II */
>  int sdp_get_int_attr(const sdp_record_t *rec, uint16_t attr, int *value);
>  int sdp_get_string_attr(const sdp_record_t *rec, uint16_t attr, char *value, int valuelen);
> diff --git a/tools/sdptool.c b/tools/sdptool.c
> index d06b159..3ce0fc3 100644
> --- a/tools/sdptool.c
> +++ b/tools/sdptool.c
> @@ -3733,11 +3733,13 @@ static int cmd_del(int argc, char **argv)
>  static void inquiry(handler_t handler, void *arg)
>  {
>  	inquiry_info ii[20];
> -	uint8_t count = 0;
> +	int count = 0;
>  	int i;
>  
>  	printf("Inquiring ...\n");
> -	if (sdp_general_inquiry(ii, 20, 8, &count) < 0) {
> +
> +	count = hci_inquiry(-1, 10, 20, NULL, (inquiry_info **) &ii, 0);
> +	if (count < 0) {
>  		printf("Inquiry failed\n");
>  		return;
>  	}

This change is fine btw. Send a separate patch for this.

Regards

Marcel




^ permalink raw reply

* [PATCH] Clear the off_requested flag
From: Daniel Örstadius @ 2010-08-18 12:54 UTC (permalink / raw)
  To: linux-bluetooth

[-- Attachment #1: Type: text/plain, Size: 244 bytes --]

Set the off_requested flag in struct btd_adapter to false when
receiving confirmation that the adapter is off. The flag is used
to indicate that the adapter is in the powering down state and
should be cleared when it is actually down.

/Daniel

[-- Attachment #2: 0001-Clear-the-off_requested-flag.patch --]
[-- Type: text/x-patch, Size: 903 bytes --]

From f863528e4d12eaa3b504eb739d15cdf04e412179 Mon Sep 17 00:00:00 2001
From: Daniel Orstadius <daniel.orstadius@nokia.com>
Date: Wed, 18 Aug 2010 15:46:11 +0300
Subject: [PATCH] Clear the off_requested flag

Set the off_requested flag in struct btd_adapter to false when
receiving confirmation that the adapter is off. The flag is used
to indicate that the adapter is in the powering down state and
should be cleared when it is actually down.
---
 src/adapter.c |    1 +
 1 files changed, 1 insertions(+), 0 deletions(-)

diff --git a/src/adapter.c b/src/adapter.c
index b023c01..d5574e8 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -2502,6 +2502,7 @@ int adapter_stop(struct btd_adapter *adapter)
 	adapter->state = DISCOVER_TYPE_NONE;
 	adapter->cache_enable = TRUE;
 	adapter->pending_cod = 0;
+	adapter->off_requested = FALSE;
 
 	call_adapter_powered_callbacks(adapter, FALSE);
 
-- 
1.6.0.4


^ permalink raw reply related

* Re: [PATCH] Clear the off_requested flag
From: Johan Hedberg @ 2010-08-18 13:16 UTC (permalink / raw)
  To: Daniel Örstadius; +Cc: linux-bluetooth
In-Reply-To: <AANLkTimJAT2+gxQCOXwBmyF7a_9BU2FQW2uQn0KiLcgx@mail.gmail.com>

Hi Daniel,

On Wed, Aug 18, 2010, Daniel Örstadius wrote:
> From: Daniel Orstadius <daniel.orstadius@nokia.com>
> Date: Wed, 18 Aug 2010 15:46:11 +0300
> Subject: [PATCH] Clear the off_requested flag
> 
> Set the off_requested flag in struct btd_adapter to false when
> receiving confirmation that the adapter is off. The flag is used
> to indicate that the adapter is in the powering down state and
> should be cleared when it is actually down.
> ---
>  src/adapter.c |    1 +
>  1 files changed, 1 insertions(+), 0 deletions(-)

Thanks. The patch is now upstream.

Johan

^ permalink raw reply

* Re: [PATCH 3/3] Maemo6 MCE: handle race condition at startup
From: Daniel Örstadius @ 2010-08-18 13:20 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <AANLkTimfQxLOTFVW64qrQLHYVjwsmDkxvuBkL-_eBKHR@mail.gmail.com>

[-- Attachment #1: Type: text/plain, Size: 705 bytes --]

On Wed, Aug 18, 2010 at 2:25 PM, Daniel Örstadius
<daniel.orstadius@gmail.com> wrote:
> On Fri, Aug 13, 2010 at 12:19 PM, Daniel Örstadius
> <daniel.orstadius@gmail.com> wrote:
>> Since bluetoothd power cycles the adapter at startup, it is possible
>> that the plugin gets a reply from reading the state of the MCE and
>> tries to power the adapter before it is down. The patch checks for
>> that situation and if it occurs postpones powering the adapter to
>> the mode change callback. The off_requested member of btd_adapter
>> is used for the check, so it is set to FALSE when the adapter is
>> down.
>>
>
> Attaching updated patch.
>

Patch without the off_requested part.

/Daniel

[-- Attachment #2: 0001-Maemo6-MCE-handle-race-condition-at-startup.patch --]
[-- Type: text/x-patch, Size: 2027 bytes --]

From 3160d36371fe7c95ecd5a4eb3e167ac374dbc4d4 Mon Sep 17 00:00:00 2001
From: Daniel Orstadius <daniel.orstadius@nokia.com>
Date: Wed, 18 Aug 2010 15:48:28 +0300
Subject: [PATCH] Maemo6 MCE: handle race condition at startup

Since bluetoothd power cycles the adapter at startup, it is possible
that the plugin gets a reply from reading the state of the MCE and
tries to power the adapter before it is down. The patch checks for
that situation and if it occurs postpones powering the adapter to
the powered state callback.
---
 plugins/maemo6.c |   22 ++++++++++++++++++++++
 1 files changed, 22 insertions(+), 0 deletions(-)

diff --git a/plugins/maemo6.c b/plugins/maemo6.c
index 55ea508..ad86c30 100644
--- a/plugins/maemo6.c
+++ b/plugins/maemo6.c
@@ -50,6 +50,7 @@
 static guint watch_id;
 static DBusConnection *conn = NULL;
 static gboolean mce_bt_set = FALSE;
+static gboolean collision = FALSE;
 
 static gboolean mce_signal_callback(DBusConnection *connection,
 					DBusMessage *message, void *user_data)
@@ -112,6 +113,14 @@ static void read_radio_states_cb(DBusPendingCall *call, void *user_data)
 
 	mce_bt_set = radio_states & MCE_RADIO_STATE_BLUETOOTH;
 
+	/* check if the adapter has not completed the initial power
+	   cycle, if so delay action to mce_notify_powered */
+
+	collision = mce_bt_set && adapter_powering_down(adapter);
+
+	if (collision)
+		goto done;
+
 	if (mce_bt_set)
 		btd_adapter_switch_online(adapter);
 	else
@@ -129,6 +138,19 @@ static void adapter_powered(struct btd_adapter *adapter, gboolean powered)
 
 	DBG("adapter_powered called with %d", powered);
 
+	/* check if the plugin got the get_radio_states reply from the
+	   mce when the adapter was not yet down during the power
+	   cycling when bluetoothd is started */
+	if (collision) {
+		error("maemo6: powered state collision");
+		collision = FALSE;
+
+		if (mce_bt_set)
+			btd_adapter_switch_online(adapter);
+
+		return;
+	}
+
 	/* nothing to do if the states match */
 	if (mce_bt_set == powered)
 		return;
-- 
1.6.0.4


^ permalink raw reply related

* Re: [PATCH 3/3] Maemo6 MCE: handle race condition at startup
From: Johan Hedberg @ 2010-08-18 13:33 UTC (permalink / raw)
  To: Daniel Örstadius; +Cc: linux-bluetooth
In-Reply-To: <AANLkTinmYUw=_BuaOE5MgEMvF9qU3Kr-=X52cQ5v-bfy@mail.gmail.com>

Hi Daniel,

On Wed, Aug 18, 2010, Daniel Örstadius wrote:
> Patch without the off_requested part.
> 
> /Daniel
>
> From 3160d36371fe7c95ecd5a4eb3e167ac374dbc4d4 Mon Sep 17 00:00:00 2001
> From: Daniel Orstadius <daniel.orstadius@nokia.com>
> Date: Wed, 18 Aug 2010 15:48:28 +0300
> Subject: [PATCH] Maemo6 MCE: handle race condition at startup
> 
> Since bluetoothd power cycles the adapter at startup, it is possible
> that the plugin gets a reply from reading the state of the MCE and
> tries to power the adapter before it is down. The patch checks for
> that situation and if it occurs postpones powering the adapter to
> the powered state callback.
> ---
>  plugins/maemo6.c |   22 ++++++++++++++++++++++
>  1 files changed, 22 insertions(+), 0 deletions(-)

Thanks. This one is now also upstream.

Johan

^ permalink raw reply

* Re: [PATCH 1/1] Bluetooth:  Add socket option definitions for AMP
From: David Vrabel @ 2010-08-18 13:45 UTC (permalink / raw)
  To: Mat Martineau; +Cc: linux-bluetooth, marcel, rshaffer, linux-arm-msm
In-Reply-To: <1282086426-8423-1-git-send-email-mathewm@codeaurora.org>

Mat Martineau wrote:
> This adds a new BT_AMP socket option to control the use of AMP channels.
> It is for use with the SOL_BLUETOOTH option level on L2CAP sockets.
> 
> Available option values are defined as:
> 
> [lots of nice documentation]

Why is none of this documentation in the code?

I believe we also agreed that this policy could be changed at any point
in the life time of the channel so this should be documented as well.

> +#define BT_AMP		8

Suggest BT_AMP_POLICY, BT_AMP_POLICY_REQUIRE_BR_EDR etc.  Just in case
there are other AMP related socket options in the future.

> +#define BT_AMP_REQUIRE_BR_EDR	0
> +#define BT_AMP_PREFER_AMP	1
> +#define BT_AMP_PREFER_BR_EDR	2

David
-- 
David Vrabel, Senior Software Engineer, Drivers
CSR, Churchill House, Cambridge Business Park,  Tel: +44 (0)1223 692562
Cowley Road, Cambridge, CB4 0WZ                 http://www.csr.com/


Member of the CSR plc group of companies. CSR plc registered in England and Wales, registered number 4187346, registered office Churchill House, Cambridge Business Park, Cowley Road, Cambridge, CB4 0WZ, United Kingdom

^ permalink raw reply

* Re: [PATCH v2] Firmware download for Qualcomm Bluetooth devices
From: Ron Shaffer @ 2010-08-18 15:40 UTC (permalink / raw)
  To: Matthew Wilson; +Cc: linux-bluetooth, marcel, johan.hedberg
In-Reply-To: <1281713636-24955-1-git-send-email-mtwilson@codeaurora.org>

On 8/13/2010 10:33 AM, Matthew Wilson wrote:
> Configures device address from hciattach parameter.
> UART speed limited to 115200.
> Requires separate device specific firmware.
> ---
>  Makefile.tools             |    3 +-
>  tools/hciattach.c          |    8 ++
>  tools/hciattach.h          |    1 +
>  tools/hciattach_qualcomm.c |  279 ++++++++++++++++++++++++++++++++++++++++++++
>  4 files changed, 290 insertions(+), 1 deletions(-)
>  create mode 100644 tools/hciattach_qualcomm.c
> 
> diff --git a/Makefile.tools b/Makefile.tools
> index 2dbf925..0ce7b75 100644
> --- a/Makefile.tools
> +++ b/Makefile.tools
> @@ -23,7 +23,8 @@ tools_l2ping_LDADD = lib/libbluetooth.la
>  tools_hciattach_SOURCES = tools/hciattach.c tools/hciattach.h \
>  						tools/hciattach_st.c \
>  						tools/hciattach_ti.c \
> -						tools/hciattach_tialt.c
> +						tools/hciattach_tialt.c \
> +						tools/hciattach_qualcomm.c
>  tools_hciattach_LDADD = lib/libbluetooth.la
>  
>  tools_hciconfig_SOURCES = tools/hciconfig.c tools/csr.h tools/csr.c \
> diff --git a/tools/hciattach.c b/tools/hciattach.c
> index 81aea7b..4d4b0a1 100644
> --- a/tools/hciattach.c
> +++ b/tools/hciattach.c
> @@ -299,6 +299,11 @@ static int texasalt(int fd, struct uart_t *u, struct termios *ti)
>  	return texasalt_init(fd, u->speed, ti);
>  }
>  
> +static int qualcomm(int fd, struct uart_t *u, struct termios *ti)
> +{
> +	return qualcomm_init(fd, u->speed, ti, u->bdaddr);
> +}
> +
>  static int read_check(int fd, void *buf, int count)
>  {
>  	int res;
> @@ -1073,6 +1078,9 @@ struct uart_t uart[] = {
>  	/* Broadcom BCM2035 */
>  	{ "bcm2035",    0x0A5C, 0x2035, HCI_UART_H4,   115200, 460800, FLOW_CTL, NULL, bcm2035  },
>  
> +	/* QUALCOMM BTS */
> +	{ "qualcomm",   0x0000, 0x0000, HCI_UART_H4,   115200, 115200, FLOW_CTL, NULL, qualcomm },
> +
>  	{ NULL, 0 }
>  };
>  
> diff --git a/tools/hciattach.h b/tools/hciattach.h
> index c0b80a1..3d5605b 100644
> --- a/tools/hciattach.h
> +++ b/tools/hciattach.h
> @@ -49,3 +49,4 @@ int texas_post(int fd, struct termios *ti);
>  int texasalt_init(int fd, int speed, struct termios *ti);
>  int stlc2500_init(int fd, bdaddr_t *bdaddr);
>  int bgb2xx_init(int dd, bdaddr_t *bdaddr);
> +int qualcomm_init(int fd, int speed, struct termios *ti, const char *bdaddr);
> diff --git a/tools/hciattach_qualcomm.c b/tools/hciattach_qualcomm.c
> new file mode 100644
> index 0000000..31ca3c8
> --- /dev/null
> +++ b/tools/hciattach_qualcomm.c
> @@ -0,0 +1,279 @@
> +/*
> + *
> + *  BlueZ - Bluetooth protocol stack for Linux
> + *
> + *  Copyright (C) 2005-2010  Marcel Holtmann <marcel@holtmann.org>
> + *  Copyright (c) 2010, Code Aurora Forum. All rights reserved.
> + *
> + *
> + *  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 <string.h>
> +#include <signal.h>
> +#include <syslog.h>
> +#include <termios.h>
> +#include <time.h>
> +#include <sys/time.h>
> +#include <sys/poll.h>
> +#include <sys/param.h>
> +#include <sys/ioctl.h>
> +#include <sys/socket.h>
> +#include <sys/uio.h>
> +
> +#include <bluetooth/bluetooth.h>
> +#include <bluetooth/hci.h>
> +#include <bluetooth/hci_lib.h>
> +
> +#include "hciattach.h"
> +
> +#define FAILIF(x, args...) do {   \
> +	if (x) {					  \
> +		fprintf(stderr, ##args);  \
> +		return -1;				  \
> +	}							  \
> +} while(0)
> +
> +typedef struct {
> +	uint8_t uart_prefix;
> +	hci_event_hdr hci_hdr;
> +	evt_cmd_complete cmd_complete;
> +	uint8_t status;
> +	uint8_t data[16];
> +} __attribute__((packed)) command_complete_t;
> +
> +
> +static int read_command_complete(int fd, unsigned short opcode, unsigned char len) {
> +	command_complete_t resp;
> +	unsigned char vsevent[512];
> +	int n;
> +
> +	/* Read reply. */
> +	n = read_hci_event(fd, vsevent, sizeof(vsevent));
> +	FAILIF(n < 0, "Failed to read response");
> +
> +	FAILIF(vsevent[1] != 0xFF, "Failed to read response");
> +
> +	n = read_hci_event(fd, (unsigned char *)&resp, sizeof(resp));
> +	FAILIF(n < 0, "Failed to read response");
> +
> +	FAILIF(resp.hci_hdr.evt != EVT_CMD_COMPLETE, /* event must be event-complete */
> +		   "Error in response: not a cmd-complete event, "
> +		   "but 0x%02x!\n", resp.hci_hdr.evt);
> +
> +	FAILIF(resp.hci_hdr.plen < 4, /* plen >= 4 for EVT_CMD_COMPLETE */
> +		   "Error in response: plen is not >= 4, but 0x%02x!\n",
> +		   resp.hci_hdr.plen);
> +
> +	/* cmd-complete event: opcode */
> +	FAILIF(resp.cmd_complete.opcode != 0,
> +		   "Error in response: opcode is 0x%04x, not 0!",
> +		   resp.cmd_complete.opcode);
> +
> +	return resp.status == 0 ? 0 : -1;
> +}
> +
> +static int qualcomm_load_firmware(int fd, const char *firmware, const char *bdaddr_s) {
> +
> +	int fw = open(firmware, O_RDONLY);
> +
> +	fprintf(stdout, "Opening firmware file: %s\n", firmware);
> +
> +	FAILIF(fw < 0,
> +		   "Could not open firmware file %s: %s (%d).\n",
> +		   firmware, strerror(errno), errno);
> +
> +	fprintf(stdout, "Uploading firmware...\n");
> +	do {
> +		/* Read each command and wait for a response. */
> +		unsigned char data[1024];
> +		unsigned char cmdp[1 + sizeof(hci_command_hdr)];
> +		hci_command_hdr *cmd = (hci_command_hdr *)(cmdp + 1);
> +		int nr;
> +		nr = read(fw, cmdp, sizeof(cmdp));
> +		if (!nr)
> +			break;
> +		FAILIF(nr != sizeof(cmdp), "Could not read H4 + HCI header!\n");
> +		FAILIF(*cmdp != HCI_COMMAND_PKT, "Command is not an H4 command packet!\n");
> +
> +		FAILIF(read(fw, data, cmd->plen) != cmd->plen,
> +			   "Could not read %d bytes of data for command with opcode %04x!\n",
> +			   cmd->plen,
> +			   cmd->opcode);
> +
> +		if ((data[0] == 1) && (data[1] == 2) && (data[2] == 6)) {
> +			bdaddr_t bdaddr;
> +			if (bdaddr_s != NULL) {
> +				(void) str2ba(bdaddr_s, &bdaddr);
> +				memcpy(&data[3], &bdaddr, sizeof(bdaddr_t));
> +			}
> +		}
> +
> +		{
> +			int nw;
> +			struct iovec iov_cmd[2];
> +			iov_cmd[0].iov_base = cmdp;
> +			iov_cmd[0].iov_len	= sizeof(cmdp);
> +			iov_cmd[1].iov_base = data;
> +			iov_cmd[1].iov_len	= cmd->plen;
> +			nw = writev(fd, iov_cmd, 2);
> +			FAILIF(nw != (int) sizeof(cmdp) + cmd->plen,
> +				   "Could not send entire command (sent only %d bytes)!\n",
> +				   nw);
> +		}
> +
> +		/* Wait for response */
> +		if (read_command_complete(fd,
> +					  cmd->opcode,
> +					  cmd->plen) < 0) {
> +			return -1;
> +		}
> +
> +	} while(1);
> +	fprintf(stdout, "Firmware upload successful.\n");
> +
> +	close(fw);
> +	return 0;
> +}
> +
> +int qualcomm_init(int fd, int speed, struct termios *ti, const char *bdaddr)
> +{
> +	struct timespec tm = {0, 50000};
> +	char cmd[5];
> +	unsigned char resp[100];		/* Response */
> +	char fw[100];
> +	int n;
> +
> +	memset(resp,'\0', 100);
> +
> +	/* Get Manufacturer and LMP version */
> +	cmd[0] = HCI_COMMAND_PKT;
> +	cmd[1] = 0x01;
> +	cmd[2] = 0x10;
> +	cmd[3] = 0x00;
> +
> +	do {
> +		n = write(fd, cmd, 4);
> +		if (n < 0) {
> +			perror("Failed to write init command (READ_LOCAL_VERSION_INFORMATION)");
> +			return -1;
> +		}
> +		if (n < 4) {
> +			fprintf(stderr, "Wanted to write 4 bytes, could only write %d. Stop\n", n);
> +			return -1;
> +		}
> +
> +		/* Read reply. */
> +		if (read_hci_event(fd, resp, 100) < 0) {
> +			perror("Failed to read init response (READ_LOCAL_VERSION_INFORMATION)");
> +			return -1;
> +		}
> +
> +		/* Wait for command complete event for our Opcode */
> +	} while (resp[4] != cmd[1] && resp[5] != cmd[2]);
> +
> +	/* Verify manufacturer */
> +	if ((resp[11] & 0xFF) != 0x1d)
> +		fprintf(stderr,"WARNING : module's manufacturer is not Qualcomm\n");
> +
> +	/* Print LMP version */
> +	fprintf(stderr, "Qualcomm module LMP version : 0x%02x\n", resp[10] & 0xFF);
> +
> +	/* Print LMP subversion */
> +	{
> +		unsigned short lmp_subv = resp[13] | (resp[14] << 8);
> +
> +		fprintf(stderr, "Qualcomm module LMP sub-version : 0x%04x\n", lmp_subv);
> +
> +	}
> +
> +	/* Get SoC type */
> +	cmd[0] = HCI_COMMAND_PKT;
> +	cmd[1] = 0x00;
> +	cmd[2] = 0xFC;
> +	cmd[3] = 0x01;
> +	cmd[4] = 0x06;
> +
> +	do {
> +		n = write(fd, cmd, 5);
> +		if (n < 0) {
> +			perror("Failed to write init command");
> +			return -1;
> +		}
> +		if (n < 5) {
> +			fprintf(stderr, "Wanted to write 5 bytes, could only write %d. Stop\n", n);
> +			return -1;
> +		}
> +
> +		/* Read reply. */
> +		if ((n = read_hci_event(fd, resp, 100)) < 0) {
> +			perror("Failed to read init response");
> +			return -1;
> +		}
> +
> +	} while (resp[3] != 0 && resp[4] != 2);
> +
> +	snprintf(fw, sizeof(fw),
> +		"/etc/firmware/%c%c%c%c%c%c_%c%c%c%c.bin",
> +		resp[18], resp[19], resp[20], resp[21],
> +		resp[22], resp[23],
> +		resp[32], resp[33], resp[34], resp[35]);
> +
> +	/* Wait for command complete event for our Opcode */
> +	if (read_hci_event(fd, resp, 100) < 0) {
> +		perror("Failed to read init response");
> +		return -1;
> +	}
> +
> +	qualcomm_load_firmware(fd, fw, bdaddr);
> +
> +	/* Reset */
> +	cmd[0] = HCI_COMMAND_PKT;
> +	cmd[1] = 0x03;
> +	cmd[2] = 0x0C;
> +	cmd[3] = 0x00;
> +
> +	do {
> +		n = write(fd, cmd, 4);
> +		if (n < 0) {
> +			perror("Failed to write reset command");
> +			return -1;
> +		}
> +		if (n < 4) {
> +			fprintf(stderr, "Wanted to write 4 bytes, could only write %d. Stop\n", n);
> +			return -1;
> +		}
> +
> +		/* Read reply. */
> +		if ((n = read_hci_event(fd, resp, 100)) < 0) {
> +			perror("Failed to read reset response");
> +			return -1;
> +		}
> +
> +	} while (resp[4] != cmd[1] && resp[5] != cmd[2]);
> +
> +	nanosleep(&tm, NULL);
> +	return 0;
> +}

Ping

-- 
Ron Shaffer
Employee of the Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.

^ permalink raw reply

* BlueZ's A2DP sink role
From: Pavan Savoy @ 2010-08-18 20:22 UTC (permalink / raw)
  To: linux-bluetooth

As I understand, the A2DP sink role is @ audio/source.c and A2DP
source role is at sink.c ? (or what is called as the interfaces?..)
Also How do I test out a2dp sink role in BlueZ, any test audio-server
I can run ?

Thanks in advance.

^ permalink raw reply

* Re: [PATCH v2] Firmware download for Qualcomm Bluetooth devices
From: Johan Hedberg @ 2010-08-18 22:35 UTC (permalink / raw)
  To: Ron Shaffer; +Cc: Matthew Wilson, linux-bluetooth, marcel
In-Reply-To: <4C6BFF05.5040506@codeaurora.org>

Hi Ron,

On Wed, Aug 18, 2010, Ron Shaffer wrote:
> On 8/13/2010 10:33 AM, Matthew Wilson wrote:
> > Configures device address from hciattach parameter.
> > UART speed limited to 115200.
> > Requires separate device specific firmware.
> > ---
> >  Makefile.tools             |    3 +-
> >  tools/hciattach.c          |    8 ++
> >  tools/hciattach.h          |    1 +
> >  tools/hciattach_qualcomm.c |  279 ++++++++++++++++++++++++++++++++++++++++++++
> >  4 files changed, 290 insertions(+), 1 deletions(-)
> >  create mode 100644 tools/hciattach_qualcomm.c
<snip>
> Ping

Sorry about forgetting about this one. Unfortunately it doesn't apply
anymore to bluez.git due to the ath3k patches that got merged earlier
today. So you'll need to fix the conflicts and resubmit. Other than that
the patch seems fine to me.

Johan

^ permalink raw reply

* [PATCH 0/3] Parsing of AMP related HCI commands and events
From: Inga Stotland @ 2010-08-18 23:38 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: rshaffer, johan.hedberg, marcel

Added support for interpreting of the following HCI commands:

Create Physical Link,
Accept Physical Link,
Disconnect Physical Link,
Create Logical Link,
Accept Logical Link,
Disconnect Logical Link,
Logical Link Cancel,
Flow Spec Modify,
Read Encryption Key Size,
Read Local AMP Info,
Read Local AMP ASSOC,
Write Remote AMP ASSOC

and HCI events:

Physical Link Complete,
Disconnect Physical Link Complete,
Physical Link Loss Early Warning,
Physical Link Recovery,
Logical Link Complete,
Disconnect Logical Link Complete,
Flow Spec Modify Complete

 
-- 
Inga Stotland
Sent by an employee of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.

^ permalink raw reply

* [PATCH 1/3] Add parsing of AMP related HCI commands
From: Inga Stotland @ 2010-08-18 23:38 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: rshaffer, johan.hedberg, marcel, Inga Stotland
In-Reply-To: <1282174734-1314-1-git-send-email-ingas@codeaurora.org>

---
 parser/hci.c |   64 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 62 insertions(+), 2 deletions(-)

diff --git a/parser/hci.c b/parser/hci.c
index b9e8d28..b768a98 100644
--- a/parser/hci.c
+++ b/parser/hci.c
@@ -141,7 +141,7 @@ static char *ev_le_meta_str[LE_EV_NUM + 1] = {
 	"LE Long Term Key Request",
 };
 
-#define CMD_LINKCTL_NUM 52
+#define CMD_LINKCTL_NUM 60
 static char *cmd_linkctl_str[CMD_LINKCTL_NUM + 1] = {
 	"Unknown",
 	"Inquiry",
@@ -196,6 +196,14 @@ static char *cmd_linkctl_str[CMD_LINKCTL_NUM + 1] = {
 	"Unknown",
 	"Remote OOB Data Request Negative Reply",
 	"IO Capability Request Negative Reply",
+	"Create Physical Link",
+	"Accept Physical Link",
+	"Disconnect Physical Link",
+	"Create Logical Link",
+	"Accept Logical Link",
+	"Disconnect Logical Link",
+	"Logical Link Cancel",
+	"Flow Spec Modify",
 };
 
 #define CMD_LINKPOL_NUM 17
@@ -348,7 +356,7 @@ static char *cmd_info_str[CMD_INFO_NUM + 1] = {
 	"Read BD ADDR",
 };
 
-#define CMD_STATUS_NUM 7
+#define CMD_STATUS_NUM 11
 static char *cmd_status_str[CMD_STATUS_NUM + 1] = {
 	"Unknown",
 	"Read Failed Contact Counter",
@@ -358,6 +366,10 @@ static char *cmd_status_str[CMD_STATUS_NUM + 1] = {
 	"Read RSSI",
 	"Read AFH Channel Map",
 	"Read Clock",
+	"Read Encryption Key Size",
+	"Read Local AMP Info",
+	"Read Local AMP ASSOC",
+	"Write Remote AMP ASSOC"
 };
 
 #define CMD_TESTING_NUM 4
@@ -1003,6 +1015,39 @@ static inline void setup_sync_conn_dump(int level, struct frame *frm)
 		btohs(cp->pkt_type));
 }
 
+static inline void create_physical_link_dump(int level, struct frame *frm)
+{
+	create_physical_link_cp *cp = frm->ptr;
+	int i;
+
+	p_indent(level, frm);
+
+	printf("handle %d key length %d key type %d\n",
+		cp->handle, cp->key_length, cp->key_type);
+	printf("key ");
+
+	for (i = 0; i < cp->key_length && cp->key_length < 32; i++)
+		printf("%2.2x", cp->key[i]);
+	printf("\n");
+}
+
+static inline void create_logical_link_dump(int level, struct frame *frm)
+{
+	create_logical_link_cp *cp = frm->ptr;
+	int i;
+
+	p_indent(level, frm);
+
+	printf("handle %d\n", cp->handle);
+	printf("tx_flow ");
+	for (i = 0; i < 16; i++)
+		printf("%2.2x", cp->tx_flow[i]);
+	printf("\nrx_flow ");
+	for (i = 0; i < 16; i++)
+		printf("%2.2x", cp->rx_flow[i]);
+	printf("\n");
+}
+
 static inline void hold_mode_dump(int level, struct frame *frm)
 {
 	hold_mode_cp *cp = frm->ptr;
@@ -1523,6 +1568,7 @@ static inline void command_dump(int level, struct frame *frm)
 		case OCF_READ_REMOTE_VERSION:
 		case OCF_READ_CLOCK_OFFSET:
 		case OCF_READ_LMP_HANDLE:
+		case OCF_DISCONNECT_LOGICAL_LINK:
 			generic_command_dump(level + 1, frm);
 			return;
 		case OCF_MASTER_LINK_KEY:
@@ -1537,6 +1583,14 @@ static inline void command_dump(int level, struct frame *frm)
 		case OCF_SETUP_SYNC_CONN:
 			setup_sync_conn_dump(level + 1, frm);
 			return;
+		case OCF_CREATE_PHYSICAL_LINK:
+		case OCF_ACCEPT_PHYSICAL_LINK:
+			create_physical_link_dump(level + 1, frm);
+			return;
+		case OCF_CREATE_LOGICAL_LINK:
+		case OCF_ACCEPT_LOGICAL_LINK:
+			create_logical_link_dump(level + 1, frm);
+			return;
 		}
 		break;
 
@@ -1581,6 +1635,7 @@ static inline void command_dump(int level, struct frame *frm)
 		case OCF_CREATE_NEW_UNIT_KEY:
 			return;
 		case OCF_SET_EVENT_MASK:
+		case OCF_SET_EVENT_MASK_PAGE_2:
 			set_event_mask_dump(level + 1, frm);
 			return;
 		case OCF_SET_EVENT_FLT:
@@ -1613,6 +1668,7 @@ static inline void command_dump(int level, struct frame *frm)
 		case OCF_SET_CONTROLLER_TO_HOST_FC:
 			write_scan_enable_dump(level + 1, frm);
 			return;
+		case OCF_WRITE_LOGICAL_LINK_ACCEPT_TIMEOUT:
 		case OCF_WRITE_CONN_ACCEPT_TIMEOUT:
 		case OCF_WRITE_PAGE_TIMEOUT:
 			write_page_timeout_dump(level + 1, frm);
@@ -1644,6 +1700,7 @@ static inline void command_dump(int level, struct frame *frm)
 		case OCF_FLUSH:
 		case OCF_READ_LINK_SUPERVISION_TIMEOUT:
 		case OCF_REFRESH_ENCRYPTION_KEY:
+		case OCF_READ_BEST_EFFORT_FLUSH_TIMEOUT:
 			generic_command_dump(level + 1, frm);
 			return;
 		case OCF_WRITE_LINK_SUPERVISION_TIMEOUT:
@@ -1653,6 +1710,7 @@ static inline void command_dump(int level, struct frame *frm)
 			write_ext_inquiry_response_dump(level + 1, frm);
 			return;
 		case OCF_WRITE_SIMPLE_PAIRING_MODE:
+		case OCF_WRITE_FLOW_CONTROL_MODE:
 			generic_write_mode_dump(level + 1, frm);
 			return;
 		case OCF_WRITE_INQUIRY_TRANSMIT_POWER_LEVEL:
@@ -2435,6 +2493,7 @@ static inline void cmd_complete_dump(int level, struct frame *frm)
 			read_local_oob_data_dump(level, frm);
 			return;
 		case OCF_READ_SIMPLE_PAIRING_MODE:
+		case OCF_READ_FLOW_CONTROL_MODE:
 			status_mode_dump(level, frm);
 			return;
 		case OCF_FLUSH:
@@ -2469,6 +2528,7 @@ static inline void cmd_complete_dump(int level, struct frame *frm)
 		case OCF_HOST_BUFFER_SIZE:
 		case OCF_REFRESH_ENCRYPTION_KEY:
 		case OCF_SEND_KEYPRESS_NOTIFY:
+		case OCF_WRITE_LOCATION_DATA:
 			status_response_dump(level, frm);
 			return;
 		}
-- 
1.7.2

-- 
Inga Stotland
Sent by an employee of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.

^ permalink raw reply related

* [PATCH 2/3] Parse Command Complete events corresponding to AMP related HCI commands
From: Inga Stotland @ 2010-08-18 23:38 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: rshaffer, johan.hedberg, marcel, Inga Stotland
In-Reply-To: <1282174734-1314-1-git-send-email-ingas@codeaurora.org>

---
 parser/hci.c |   80 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 80 insertions(+), 0 deletions(-)

diff --git a/parser/hci.c b/parser/hci.c
index b768a98..5de5128 100644
--- a/parser/hci.c
+++ b/parser/hci.c
@@ -2360,6 +2360,71 @@ static inline void read_clock_dump(int level, struct frame *frm)
 	}
 }
 
+static inline void read_local_amp_info_dump(int level, struct frame *frm)
+{
+	read_local_amp_info_rp *rp = frm->ptr;
+
+	p_indent(level, frm);
+	printf("status 0x%2.2x amp status 0x%2.2x\n",
+			rp->status, rp->amp_status);
+	if (rp->status > 0) {
+		p_indent(level, frm);
+		printf("Error: %s\n", status2str(rp->status));
+	} else {
+		p_indent(level, frm);
+		printf("total bandwidth %d, max guaranteed bandwidth %d\n",
+			btohl(rp->total_bandwidth),
+			btohl(rp->max_guaranteed_bandwidth));
+		p_indent(level, frm);
+		printf("min latency %d, max PDU %d, controller type 0x%2.2x\n",
+			btohl(rp->min_latency), btohl(rp->max_pdu_size),
+			rp->controller_type);
+		p_indent(level, frm);
+		printf("pal caps 0x%4.4x, max assoc len %d\n",
+			btohs(rp->pal_caps), btohs(rp->max_amp_assoc_length));
+		p_indent(level, frm);
+		printf("max flush timeout %d, best effort flush timeout %d\n",
+			btohl(rp->max_flush_timeout),
+			btohl(rp->best_effort_flush_timeout));
+	}
+}
+
+static inline void read_local_amp_assoc_dump(int level, struct frame *frm)
+{
+	read_local_amp_assoc_rp *rp = frm->ptr;
+	uint16_t len = btohs(rp->length);
+	int i;
+
+	p_indent(level, frm);
+	printf("status 0x%2.2x handle 0x%2.2x length %d\n",
+			rp->status, rp->handle, len);
+	if (rp->status > 0) {
+		p_indent(level, frm);
+		printf("Error: %s\n", status2str(rp->status));
+	} else {
+		for (i = 0; i < len; i++) {
+			if (!(i % 16)) {
+				printf("\n");
+				p_indent(level, frm);
+			}
+			printf("%2.2x ", rp->fragment[i]);
+		}
+		printf("\n");
+	}
+}
+
+static inline void write_remote_amp_assoc_dump(int level, struct frame *frm)
+{
+	write_remote_amp_assoc_rp *rp = frm->ptr;
+
+	p_indent(level, frm);
+	printf("status 0x%2.2x handle 0x%2.2x\n", rp->status, rp->handle);
+	if (rp->status > 0) {
+		p_indent(level, frm);
+		printf("Error: %s\n", status2str(rp->status));
+	}
+}
+
 static inline void cmd_complete_dump(int level, struct frame *frm)
 {
 	evt_cmd_complete *evt = frm->ptr;
@@ -2460,6 +2525,7 @@ static inline void cmd_complete_dump(int level, struct frame *frm)
 			return;
 		case OCF_READ_CONN_ACCEPT_TIMEOUT:
 		case OCF_READ_PAGE_TIMEOUT:
+		case OCF_READ_LOGICAL_LINK_ACCEPT_TIMEOUT:
 			read_page_timeout_dump(level, frm);
 			return;
 		case OCF_READ_PAGE_ACTIVITY:
@@ -2528,7 +2594,12 @@ static inline void cmd_complete_dump(int level, struct frame *frm)
 		case OCF_HOST_BUFFER_SIZE:
 		case OCF_REFRESH_ENCRYPTION_KEY:
 		case OCF_SEND_KEYPRESS_NOTIFY:
+		case OCF_WRITE_LOGICAL_LINK_ACCEPT_TIMEOUT:
+		case OCF_SET_EVENT_MASK_PAGE_2:
 		case OCF_WRITE_LOCATION_DATA:
+		case OCF_WRITE_FLOW_CONTROL_MODE:
+		case OCF_READ_BEST_EFFORT_FLUSH_TIMEOUT:
+		case OCF_WRITE_BEST_EFFORT_FLUSH_TIMEOUT:
 			status_response_dump(level, frm);
 			return;
 		}
@@ -2575,6 +2646,15 @@ static inline void cmd_complete_dump(int level, struct frame *frm)
 		case OCF_READ_CLOCK:
 			read_clock_dump(level, frm);
 			return;
+		case OCF_READ_LOCAL_AMP_INFO:
+			read_local_amp_info_dump(level, frm);
+			return;
+		case OCF_READ_LOCAL_AMP_ASSOC:
+			read_local_amp_assoc_dump(level, frm);
+			return;
+		case OCF_WRITE_REMOTE_AMP_ASSOC:
+			write_remote_amp_assoc_dump(level, frm);
+			return;
 		}
 		break;
 
-- 
1.7.2

-- 
Inga Stotland
Sent by an employee of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.

^ permalink raw reply related

* [PATCH 3/3] Parsing of AMP specific HCI events
From: Inga Stotland @ 2010-08-18 23:38 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: rshaffer, johan.hedberg, marcel, Inga Stotland
In-Reply-To: <1282174734-1314-1-git-send-email-ingas@codeaurora.org>

---
 parser/hci.c |   94 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 94 insertions(+), 0 deletions(-)

diff --git a/parser/hci.c b/parser/hci.c
index 5de5128..250ba58 100644
--- a/parser/hci.c
+++ b/parser/hci.c
@@ -3265,6 +3265,80 @@ static inline void le_meta_ev_dump(int level, struct frame *frm)
 	}
 }
 
+static inline void phys_link_complete_dump(int level, struct frame *frm)
+{
+	evt_physical_link_complete *evt = frm->ptr;
+
+	p_indent(level, frm);
+	printf("status 0x%2.2x handle %d\n", evt->status, evt->handle);
+
+	if (evt->status > 0) {
+		p_indent(level, frm);
+		printf("Error: %s\n", status2str(evt->status));
+	}
+}
+
+static inline void disconn_phys_link_complete_dump(int level, struct frame *frm)
+{
+	evt_disconn_physical_link_complete *evt = frm->ptr;
+
+	p_indent(level, frm);
+	printf("status 0x%2.2x handle %d reason 0x%2.2x\n",
+				evt->status, evt->handle, evt->reason);
+
+	if (evt->status > 0) {
+		p_indent(level, frm);
+		printf("Error: %s\n", status2str(evt->status));
+	} else if (evt->reason > 0) {
+		p_indent(level, frm);
+		printf("Reason: %s\n", status2str(evt->reason));
+	}
+}
+
+static inline void phys_link_loss_warning_dump(int level, struct frame *frm)
+{
+	evt_physical_link_loss_warning *evt = frm->ptr;
+
+	p_indent(level, frm);
+	printf("handle %d reason 0x%2.2x\n", evt->handle, evt->reason);
+}
+
+static inline void phys_link_handle_dump(int level, struct frame *frm)
+{
+	evt_physical_link_recovery *evt = frm->ptr;
+
+	p_indent(level, frm);
+	printf("handle %d\n", evt->handle);
+}
+
+static inline void logical_link_complete_dump(int level, struct frame *frm)
+{
+	evt_logical_link_complete *evt = frm->ptr;
+
+	p_indent(level, frm);
+	printf("status 0x%2.2x log_handle %d handle %d tx_flow_id %d\n",
+			evt->status, btohs(evt->log_handle), evt->handle,
+			evt->tx_flow_id);
+
+	if (evt->status > 0) {
+		p_indent(level, frm);
+		printf("Error: %s\n", status2str(evt->status));
+	}
+}
+
+static inline void flow_spec_modify_dump(int level, struct frame *frm)
+{
+	evt_flow_spec_modify_complete *evt = frm->ptr;
+
+	p_indent(level, frm);
+	printf("status 0x%2.2x handle %d\n", evt->status, btohs(evt->handle));
+
+	if (evt->status > 0) {
+		p_indent(level, frm);
+		printf("Error: %s\n", status2str(evt->status));
+	}
+}
+
 static inline void event_dump(int level, struct frame *frm)
 {
 	hci_event_hdr *hdr = frm->ptr;
@@ -3361,6 +3435,7 @@ static inline void event_dump(int level, struct frame *frm)
 		conn_request_dump(level + 1, frm);
 		break;
 	case EVT_DISCONN_COMPLETE:
+	case EVT_DISCONNECT_LOGICAL_LINK_COMPLETE:
 		disconn_complete_dump(level + 1, frm);
 		break;
 	case EVT_AUTH_COMPLETE:
@@ -3471,6 +3546,25 @@ static inline void event_dump(int level, struct frame *frm)
 	case EVT_LE_META_EVENT:
 		le_meta_ev_dump(level + 1, frm);
 		break;
+	case EVT_PHYSICAL_LINK_COMPLETE:
+		phys_link_complete_dump(level + 1, frm);
+		break;
+	case EVT_DISCONNECT_PHYSICAL_LINK_COMPLETE:
+		disconn_phys_link_complete_dump(level + 1, frm);
+		break;
+	case EVT_PHYSICAL_LINK_LOSS_EARLY_WARNING:
+		phys_link_loss_warning_dump(level + 1, frm);
+		break;
+	case EVT_PHYSICAL_LINK_RECOVERY:
+	case EVT_CHANNEL_SELECTED:
+		phys_link_handle_dump(level + 1, frm);
+		break;
+	case EVT_LOGICAL_LINK_COMPLETE:
+		logical_link_complete_dump(level + 1, frm);
+		break;
+	case EVT_FLOW_SPEC_MODIFY_COMPLETE:
+		flow_spec_modify_dump(level + 1, frm);
+		break;
 	default:
 		raw_dump(level, frm);
 		break;
-- 
1.7.2

-- 
Inga Stotland
Sent by an employee of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.

^ permalink raw reply related

* [PATCH 1/2] bluetooth: Add support Bluetooth controller of MacbookPro 6,2
From: Nobuhiro Iwamatsu @ 2010-08-19  5:54 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: stable, Nobuhiro Iwamatsu

Bluetooth controller of MacbookPro 6,2 does not work.
Because Device Class of these controllers was set 255 (Vendor Sepecific Class).

Signed-off-by: Nobuhiro Iwamatsu <iwamatsu@nigauri.org>
---
 drivers/bluetooth/btusb.c |    3 +++
 1 files changed, 3 insertions(+), 0 deletions(-)

diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index d22ce3c..9fb8635 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -62,6 +62,9 @@ static struct usb_device_id btusb_table[] = {
 	/* Apple iMac11,1 */
 	{ USB_DEVICE(0x05ac, 0x8215) },
 
+	/* Apple MacBookPro6,2 */
+	{ USB_DEVICE(0x05ac, 0x8218) },
+
 	/* AVM BlueFRITZ! USB v2.0 */
 	{ USB_DEVICE(0x057c, 0x3800) },
 
-- 
1.7.1


^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox