* [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
* Re: [PATCH] Additional contact's field handled in VCARD structure
From: Johan Hedberg @ 2010-08-18 9:15 UTC (permalink / raw)
To: Rafal Michalski; +Cc: linux-bluetooth
In-Reply-To: <1282117176-28912-1-git-send-email-michalski.raf@gmail.com>
Hi Rafal,
On Wed, Aug 18, 2010, Rafal Michalski wrote:
> After pulling contacts some fields weren't present in downloaded
> VCARD structure in spite of that these fields existed (not empty).
>
> I added handling fields: BDAY, NICKNAME, URL, PHOTO and three fields
> grouped under ORG tag (Company, Department, Job Title).
> To solve this problem extending number of columns and queries of database
> was needed especially. Of course fields mentioned above were added to
> phonebook_contact structure as char * type to save gained data
First of all, could we try to get the commit message format consistent
with the rest of the git tree. I.e. keep the summary line as "Add
handling of ..." and don't speak in the first person, i.e. instead of "I
added ..." write "This patch adds ...". Just look at the commit history
of bluez and obexd if you need examples.
It's a rather small patch, but if possible could you still split it into
smaller chunks. When your commit message says "This patch adds X and Y
and Z" it's a good hint that there should be a separate patch for each
feature, epecially if the features arent interdependent.
> + "nco:postalcode(?p) nco:country(?p) ?f nco:birthDate(?c) " \
There's an extra space before the tab at the end of the line.
> + "nmo:receivedDate(?call) nmo:isSent(?call) " \
Same here.
> + "nco:postalcode(?p) nco:country(?p) ?f nco:birthDate(?c) " \
And here.
> + "nmo:receivedDate(?call) nmo:isSent(?call) " \
And here.
Enable whitespace visualisation in your editor to catch these. If you
need hints for how to do this in vim (which I use myself) let me know.
> +static void vcard_printf_bday(GString *vcards, const char *birthday)
> +{
> + int len = 0;
> +
> + if (birthday)
> + len = strlen(birthday);
> +
> + if (len)
> + vcard_printf(vcards, "BDAY:%s", birthday);
> +}
Instead of structuring the logic like this, could you simply do:
if (birthday == NULL || strlen(birthday) == 0)
return;
vcard_printf(...);
The same applies for your other printf functions (though in some of them
you'll need to preserve the len variable for calling the add_slash
function).
> +static void vcard_printf_nickname(GString *vcards, const char *nickname)
> +{
> + int len = 0;
> +
> + if (nickname)
> + len = strlen(nickname);
> +
> + if (len) {
> + char field[LEN_MAX];
> + add_slash(field, nickname, LEN_MAX, len);
> + vcard_printf(vcards, "NICKNAME:%s", field);
> + }
> +}
> +
> +static void vcard_printf_url(GString *vcards, const char *website)
> +{
> + int len = 0;
> +
> + if (website)
> + len = strlen(website);
> +
> + if (len) {
> + char field[LEN_MAX];
> + add_slash(field, website, LEN_MAX, len);
> + vcard_printf(vcards, "URL;TYPE=INTERNET:%s", field);
> + }
> +}
These functions look very similar in logic. Are there others in the
existing code too? If so, you might want to consider creating a
generalized function which takes the type and value as input parameters
instead of having a separate function for each type.
Johan
^ permalink raw reply
* [PATCH] Additional contact's field handled in VCARD structure
From: Rafal Michalski @ 2010-08-18 7:39 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Rafal Michalski
After pulling contacts some fields weren't present in downloaded
VCARD structure in spite of that these fields existed (not empty).
I added handling fields: BDAY, NICKNAME, URL, PHOTO and three fields
grouped under ORG tag (Company, Department, Job Title).
To solve this problem extending number of columns and queries of database
was needed especially. Of course fields mentioned above were added to
phonebook_contact structure as char * type to save gained data
---
plugins/phonebook-tracker.c | 102 ++++++++++++++++++++++++++----------------
plugins/vcard.c | 96 ++++++++++++++++++++++++++++++++++++++++
plugins/vcard.h | 7 +++
3 files changed, 166 insertions(+), 39 deletions(-)
diff --git a/plugins/phonebook-tracker.c b/plugins/phonebook-tracker.c
index 618ce8d..2bccdfc 100644
--- a/plugins/phonebook-tracker.c
+++ b/plugins/phonebook-tracker.c
@@ -43,14 +43,14 @@
#define TRACKER_RESOURCES_INTERFACE "org.freedesktop.Tracker1.Resources"
#define TRACKER_DEFAULT_CONTACT_ME "http://www.semanticdesktop.org/ontologies/2007/03/22/nco#default-contact-me"
-#define CONTACTS_ID_COL 20
-#define PULL_QUERY_COL_AMOUNT 21
+#define CONTACTS_ID_COL 27
+#define PULL_QUERY_COL_AMOUNT 28
#define COL_HOME_NUMBER 0
#define COL_WORK_NUMBER 8
#define COL_FAX_NUMBER 16
-#define COL_DATE 17
-#define COL_SENT 18
-#define COL_ANSWERED 19
+#define COL_DATE 24
+#define COL_SENT 25
+#define COL_ANSWERED 26
#define CONTACTS_QUERY_ALL \
"SELECT ?v nco:fullname(?c) " \
@@ -59,8 +59,10 @@
"nco:nameHonorificSuffix(?c) nco:emailAddress(?e) " \
"nco:phoneNumber(?w) nco:pobox(?p) nco:extendedAddress(?p) " \
"nco:streetAddress(?p) nco:locality(?p) nco:region(?p) " \
- "nco:postalcode(?p) nco:country(?p) ?f \"NOTACALL\" \"false\" " \
- "\"false\" ?c " \
+ "nco:postalcode(?p) nco:country(?p) ?f nco:birthDate(?c) " \
+ "nco:nickname(?c) nco:websiteUrl(?c) nco:photo(?c) " \
+ "nco:fullname(?o) nco:department(?a) nco:role(?a) " \
+ "\"NOTACALL\" \"false\" \"false\" ?c " \
"WHERE { " \
"?c a nco:PersonContact . " \
"OPTIONAL { ?c nco:hasPhoneNumber ?h . \
@@ -75,9 +77,9 @@
"}" \
"OPTIONAL { ?c nco:hasEmailAddress ?e . } " \
"OPTIONAL { ?c nco:hasPostalAddress ?p . } " \
- "OPTIONAL { " \
- "?c nco:hasAffiliation ?a . " \
- "?a nco:hasPhoneNumber ?w . " \
+ "OPTIONAL { ?c nco:hasAffiliation ?a . " \
+ "OPTIONAL { ?a nco:hasPhoneNumber ?w . } " \
+ "OPTIONAL { ?a nco:org ?o . } " \
"} " \
"}"
@@ -102,8 +104,11 @@
"nco:nameHonorificSuffix(?c) nco:emailAddress(?e) " \
"nco:phoneNumber(?w) nco:pobox(?p) nco:extendedAddress(?p) " \
"nco:streetAddress(?p) nco:locality(?p) nco:region(?p) " \
- "nco:postalcode(?p) nco:country(?p) ?f nmo:receivedDate(?call) "\
- "nmo:isSent(?call) nmo:isAnswered(?call) ?c " \
+ "nco:postalcode(?p) nco:country(?p) ?f nco:birthDate(?c) " \
+ "nco:nickname(?c) nco:websiteUrl(?c) nco:photo(?c) " \
+ "nco:fullname(?o) nco:department(?a) nco:role(?a) " \
+ "nmo:receivedDate(?call) nmo:isSent(?call) " \
+ "nmo:isAnswered(?call) ?c " \
"WHERE { " \
"?call a nmo:Call ; " \
"nmo:from ?c ; " \
@@ -118,9 +123,9 @@
"} " \
"OPTIONAL { ?c nco:hasEmailAddress ?e . } " \
"OPTIONAL { ?c nco:hasPostalAddress ?p . } " \
- "OPTIONAL { " \
- "?c nco:hasAffiliation ?a . " \
- "?a nco:hasPhoneNumber ?w . " \
+ "OPTIONAL { ?c nco:hasAffiliation ?a . " \
+ "OPTIONAL { ?a nco:hasPhoneNumber ?w . } " \
+ "OPTIONAL { ?a nco:org ?o . } " \
"} " \
"} ORDER BY DESC(nmo:receivedDate(?call))"
@@ -145,8 +150,11 @@
"nco:nameHonorificSuffix(?c) nco:emailAddress(?e) " \
"nco:phoneNumber(?w) nco:pobox(?p) nco:extendedAddress(?p) " \
"nco:streetAddress(?p) nco:locality(?p) nco:region(?p) " \
- "nco:postalcode(?p) nco:country(?p) ?f nmo:receivedDate(?call) "\
- "nmo:isSent(?call) nmo:isAnswered(?call) ?c " \
+ "nco:postalcode(?p) nco:country(?p) ?f nco:birthDate(?c) " \
+ "nco:nickname(?c) nco:websiteUrl(?c) nco:photo(?c) " \
+ "nco:fullname(?o) nco:department(?a) nco:role(?a) " \
+ "nmo:receivedDate(?call) nmo:isSent(?call) " \
+ "nmo:isAnswered(?call) ?c " \
"WHERE { " \
"?call a nmo:Call ; " \
"nmo:from ?c ; " \
@@ -161,9 +169,9 @@
"} " \
"OPTIONAL { ?c nco:hasEmailAddress ?e . } " \
"OPTIONAL { ?c nco:hasPostalAddress ?p . } " \
- "OPTIONAL { " \
- "?c nco:hasAffiliation ?a . " \
- "?a nco:hasPhoneNumber ?w . " \
+ "OPTIONAL { ?c nco:hasAffiliation ?a . " \
+ "OPTIONAL { ?a nco:hasPhoneNumber ?w . } " \
+ "OPTIONAL { ?a nco:org ?o . } " \
"} " \
"} ORDER BY DESC(nmo:receivedDate(?call))"
@@ -188,8 +196,11 @@
"nco:nameHonorificSuffix(?c) nco:emailAddress(?e) " \
"nco:phoneNumber(?w) nco:pobox(?p) nco:extendedAddress(?p) " \
"nco:streetAddress(?p) nco:locality(?p) nco:region(?p) " \
- "nco:postalcode(?p) nco:country(?p) ?f nmo:receivedDate(?call) "\
- "nmo:isSent(?call) nmo:isAnswered(?call) ?c " \
+ "nco:postalcode(?p) nco:country(?p) ?f nco:birthDate(?c) " \
+ "nco:nickname(?c) nco:websiteUrl(?c) nco:photo(?c) " \
+ "nco:fullname(?o) nco:department(?a) nco:role(?a) " \
+ "nmo:receivedDate(?call) nmo:isSent(?call) " \
+ "nmo:isAnswered(?call) ?c " \
"WHERE { " \
"?call a nmo:Call ; " \
"nmo:to ?c ; " \
@@ -203,9 +214,9 @@
"} " \
"OPTIONAL { ?c nco:hasEmailAddress ?e . } " \
"OPTIONAL { ?c nco:hasPostalAddress ?p . } " \
- "OPTIONAL { " \
- "?c nco:hasAffiliation ?a . " \
- "?a nco:hasPhoneNumber ?w . " \
+ "OPTIONAL { ?c nco:hasAffiliation ?a . " \
+ "OPTIONAL { ?a nco:hasPhoneNumber ?w . } " \
+ "OPTIONAL { ?a nco:org ?o . } " \
"} " \
"} ORDER BY DESC(nmo:sentDate(?call))"
@@ -229,8 +240,11 @@
"nco:nameHonorificSuffix(?c) nco:emailAddress(?e) " \
"nco:phoneNumber(?w) nco:pobox(?p) nco:extendedAddress(?p) " \
"nco:streetAddress(?p) nco:locality(?p) nco:region(?p) " \
- "nco:postalcode(?p) nco:country(?p) ?f nmo:receivedDate(?call) "\
- "nmo:isSent(?call) nmo:isAnswered(?call) ?c " \
+ "nco:postalcode(?p) nco:country(?p) ?f nco:birthDate(?c) " \
+ "nco:nickname(?c) nco:websiteUrl(?c) nco:photo(?c) " \
+ "nco:fullname(?o) nco:department(?a) nco:role(?a) " \
+ "nmo:receivedDate(?call) nmo:isSent(?call) " \
+ "nmo:isAnswered(?call) ?c " \
"WHERE { " \
"{ " \
"?call a nmo:Call ; " \
@@ -245,9 +259,9 @@
"} " \
"OPTIONAL { ?c nco:hasEmailAddress ?e . } " \
"OPTIONAL { ?c nco:hasPostalAddress ?p . } " \
- "OPTIONAL { " \
- "?c nco:hasAffiliation ?a . " \
- "?a nco:hasPhoneNumber ?w . " \
+ "OPTIONAL { ?c nco:hasAffiliation ?a . " \
+ "OPTIONAL { ?a nco:hasPhoneNumber ?w . } " \
+ "OPTIONAL { ?a nco:org ?o . } " \
"} " \
"} UNION { " \
"?call a nmo:Call ; " \
@@ -262,9 +276,9 @@
"} " \
"OPTIONAL { ?c nco:hasEmailAddress ?e . } " \
"OPTIONAL { ?c nco:hasPostalAddress ?p . } " \
- "OPTIONAL { " \
- "?c nco:hasAffiliation ?a . " \
- "?a nco:hasPhoneNumber ?w . " \
+ "OPTIONAL { ?c nco:hasAffiliation ?a . " \
+ "OPTIONAL { ?a nco:hasPhoneNumber ?w . } " \
+ "OPTIONAL { ?a nco:org ?o . } " \
"} " \
"} } ORDER BY DESC(nmo:receivedDate(?call))"
@@ -295,8 +309,10 @@
"nco:nameHonorificSuffix(<%s>) nco:emailAddress(?e) " \
"nco:phoneNumber(?w) nco:pobox(?p) nco:extendedAddress(?p) " \
"nco:streetAddress(?p) nco:locality(?p) nco:region(?p) " \
- "nco:postalcode(?p) nco:country(?p) ?f \"NOTACALL\" \"false\" " \
- "\"false\" <%s> " \
+ "nco:postalcode(?p) nco:country(?p) ?f nco:birthDate(<%s>) " \
+ "nco:nickname(<%s>) nco:websiteUrl(<%s>) nco:photo(<%s>) " \
+ "nco:fullname(?o) nco:department(?a) nco:role(?a) " \
+ "\"NOTACALL\" \"false\" \"false\" <%s> " \
"WHERE { " \
"<%s> a nco:Contact . " \
"OPTIONAL { <%s> nco:hasPhoneNumber ?h . \
@@ -311,9 +327,9 @@
"}" \
"OPTIONAL { <%s> nco:hasEmailAddress ?e . } " \
"OPTIONAL { <%s> nco:hasPostalAddress ?p . } " \
- "OPTIONAL { " \
- "<%s> nco:hasAffiliation ?a . " \
- "?a nco:hasPhoneNumber ?w . " \
+ "OPTIONAL { <%s> nco:hasAffiliation ?a . " \
+ "OPTIONAL { ?a nco:hasPhoneNumber ?w . } " \
+ "OPTIONAL { ?a nco:org ?o . } " \
"} " \
"}"
@@ -741,6 +757,13 @@ add_entry:
contact->region = g_strdup(reply[13]);
contact->postal = g_strdup(reply[14]);
contact->country = g_strdup(reply[15]);
+ contact->birthday = g_strdup(reply[17]);
+ contact->nickname = g_strdup(reply[18]);
+ contact->website = g_strdup(reply[19]);
+ contact->photo = g_strdup(reply[20]);
+ contact->company = g_strdup(reply[21]);
+ contact->department = g_strdup(reply[22]);
+ contact->title = g_strdup(reply[23]);
set_call_type(contact, reply[COL_DATE], reply[COL_SENT],
reply[COL_ANSWERED]);
@@ -941,7 +964,8 @@ int phonebook_get_entry(const char *folder, const char *id,
data->vcardentry = TRUE;
query = g_strdup_printf(CONTACTS_QUERY_FROM_URI, id, id, id, id, id,
- id, id, id, id, id, id, id);
+ id, id, id, id, id, id, id,
+ id, id, id, id);
ret = query_tracker(query, PULL_QUERY_COL_AMOUNT, pull_contacts, data);
diff --git a/plugins/vcard.c b/plugins/vcard.c
index af00cb5..0439506 100644
--- a/plugins/vcard.c
+++ b/plugins/vcard.c
@@ -271,6 +271,80 @@ static void vcard_printf_email(GString *vcards, const char *email)
}
}
+static void vcard_printf_bday(GString *vcards, const char *birthday)
+{
+ int len = 0;
+
+ if (birthday)
+ len = strlen(birthday);
+
+ if (len)
+ vcard_printf(vcards, "BDAY:%s", birthday);
+}
+
+static void vcard_printf_nickname(GString *vcards, const char *nickname)
+{
+ int len = 0;
+
+ if (nickname)
+ len = strlen(nickname);
+
+ if (len) {
+ char field[LEN_MAX];
+ add_slash(field, nickname, LEN_MAX, len);
+ vcard_printf(vcards, "NICKNAME:%s", field);
+ }
+}
+
+static void vcard_printf_url(GString *vcards, const char *website)
+{
+ int len = 0;
+
+ if (website)
+ len = strlen(website);
+
+ if (len) {
+ char field[LEN_MAX];
+ add_slash(field, website, LEN_MAX, len);
+ vcard_printf(vcards, "URL;TYPE=INTERNET:%s", field);
+ }
+}
+
+static void vcard_printf_photo(GString *vcards, const char *photo)
+{
+ int len = 0;
+
+ if (photo)
+ len = strlen(photo);
+
+ if (len)
+ vcard_printf(vcards, "PHOTO:%s", photo);
+}
+
+static gboolean org_fields_present(struct phonebook_contact *contact)
+{
+ if (contact->company && strlen(contact->company))
+ return TRUE;
+
+ if (contact->department && strlen(contact->department))
+ return TRUE;
+
+ if (contact->title && strlen(contact->title))
+ return TRUE;
+
+ return FALSE;
+}
+
+static void vcard_printf_org(GString *vcards,
+ struct phonebook_contact *contact)
+{
+ if (org_fields_present(contact) == FALSE)
+ return;
+
+ vcard_printf(vcards, "ORG:%s;%s;%s", contact->company,
+ contact->department, contact->title);
+}
+
static void vcard_printf_adr(GString *vcards, struct phonebook_contact *contact)
{
if (address_fields_present(contact) == FALSE) {
@@ -350,6 +424,21 @@ void phonebook_add_contact(GString *vcards, struct phonebook_contact *contact,
if (filter & FILTER_ADR)
vcard_printf_adr(vcards, contact);
+ if (filter & FILTER_BDAY)
+ vcard_printf_bday(vcards, contact->birthday);
+
+ if (filter & FILTER_NICKNAME)
+ vcard_printf_nickname(vcards, contact->nickname);
+
+ if (filter & FILTER_URL)
+ vcard_printf_url(vcards, contact->website);
+
+ if (filter & FILTER_PHOTO)
+ vcard_printf_photo(vcards, contact->photo);
+
+ if (filter & FILTER_ORG)
+ vcard_printf_org(vcards, contact);
+
if (filter & FILTER_X_IRMC_CALL_DATETIME)
vcard_printf_datetime(vcards, contact);
@@ -386,6 +475,13 @@ void phonebook_contact_free(struct phonebook_contact *contact)
g_free(contact->region);
g_free(contact->postal);
g_free(contact->country);
+ g_free(contact->birthday);
+ g_free(contact->nickname);
+ g_free(contact->website);
+ g_free(contact->photo);
+ g_free(contact->company);
+ g_free(contact->department);
+ g_free(contact->title);
g_free(contact->datetime);
g_free(contact);
}
diff --git a/plugins/vcard.h b/plugins/vcard.h
index 06bcd35..8484a5d 100644
--- a/plugins/vcard.h
+++ b/plugins/vcard.h
@@ -55,6 +55,13 @@ struct phonebook_contact {
char *region;
char *postal;
char *country;
+ char *birthday;
+ char *nickname;
+ char *website;
+ char *photo;
+ char *company;
+ char *department;
+ char *title;
char *datetime;
int calltype;
};
--
1.6.3.3
^ permalink raw reply related
* Re: [PATCH v3] Bluetooth: host level Support for Atheros AR300x device
From: Marcel Holtmann @ 2010-08-18 6:51 UTC (permalink / raw)
To: Suraj Sumangala; +Cc: linux-bluetooth
In-Reply-To: <1282113672-16360-1-git-send-email-suraj@atheros.com>
Hi Suraj,
> Implements support for Atheros AR300x Bluetooth chip in
> hciattach application. Supports configuration download
> and power management configure feature.
> ---
> Makefile.tools | 7 +-
> tools/hciattach.8 | 3 +
> tools/hciattach.c | 105 ++++++
> tools/hciattach.h | 3 +
> tools/hciattach_ar3k.c | 859 ++++++++++++++++++++++++++++++++++++++++++++++++
> 5 files changed, 974 insertions(+), 3 deletions(-)
> create mode 100644 tools/hciattach_ar3k.c
>
> diff --git a/Makefile.tools b/Makefile.tools
> index 2dbf925..e568bd7 100644
> --- a/Makefile.tools
> +++ b/Makefile.tools
> @@ -21,9 +21,10 @@ tools_rfcomm_LDADD = lib/libbluetooth.la
> 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_st.c \
> + tools/hciattach_ti.c \
> + tools/hciattach_tialt.c \
> + tools/hciattach_ar3k.c
> tools_hciattach_LDADD = lib/libbluetooth.la
please stop introducing new whitespaces in between. None of the
Makefile.am to do this.
> Supported IDs are (manufacturer id, product id)
> diff --git a/tools/hciattach.c b/tools/hciattach.c
> index 8616899..6cc92c1 100644
> --- a/tools/hciattach.c
> +++ b/tools/hciattach.c
> @@ -657,6 +657,109 @@ static int csr(int fd, struct uart_t *u, struct termios *ti)
> return 0;
> }
>
> +#define SLEEP_ENABLE 1
> +#define SLEEP_DISABLE 0
> +
> +/*
> + * Atheros AR300x specific initialization post callback
> + */
> +static int ath3kpost(int fd, struct uart_t *u, struct termios *ti)
> +{
> + return ath_configure_sleep(fd, u->pm);
> +}
> +
> +#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 configureation file
> + * download
> + */
> +static int ath3kinit(int fd, struct uart_t *u, struct termios *ti)
> +{
> + 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 (u->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(u->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 = u->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;
> +}
> +
Why is this in hciattach.c if you create your own file for the ar3k
anyway. Please move it all into that file.
Regards
Marcel
^ permalink raw reply
* [PATCH v3] Bluetooth: host level Support for Atheros AR300x device
From: Suraj Sumangala @ 2010-08-18 6:41 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 | 7 +-
tools/hciattach.8 | 3 +
tools/hciattach.c | 105 ++++++
tools/hciattach.h | 3 +
tools/hciattach_ar3k.c | 859 ++++++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 974 insertions(+), 3 deletions(-)
create mode 100644 tools/hciattach_ar3k.c
diff --git a/Makefile.tools b/Makefile.tools
index 2dbf925..e568bd7 100644
--- a/Makefile.tools
+++ b/Makefile.tools
@@ -21,9 +21,10 @@ tools_rfcomm_LDADD = lib/libbluetooth.la
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_st.c \
+ tools/hciattach_ti.c \
+ tools/hciattach_tialt.c \
+ tools/hciattach_ar3k.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..6cc92c1 100644
--- a/tools/hciattach.c
+++ b/tools/hciattach.c
@@ -657,6 +657,109 @@ static int csr(int fd, struct uart_t *u, struct termios *ti)
return 0;
}
+#define SLEEP_ENABLE 1
+#define SLEEP_DISABLE 0
+
+/*
+ * Atheros AR300x specific initialization post callback
+ */
+static int ath3kpost(int fd, struct uart_t *u, struct termios *ti)
+{
+ return ath_configure_sleep(fd, u->pm);
+}
+
+#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 configureation file
+ * download
+ */
+static int ath3kinit(int fd, struct uart_t *u, struct termios *ti)
+{
+ 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 (u->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(u->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 = u->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;
+}
+
/*
* Silicon Wave specific initialization
* Thomas Moser <thomas.moser@tmoser.ch>
@@ -1104,6 +1207,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, ath3kinit, ath3kpost },
{ NULL, 0 }
};
diff --git a/tools/hciattach.h b/tools/hciattach.h
index c0b80a1..ca31731 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 ath_configure_sleep(int fd, int sleep_stat);
+int ath_ps_download(int fd);
diff --git a/tools/hciattach_ar3k.c b/tools/hciattach_ar3k.c
new file mode 100644
index 0000000..b646924
--- /dev/null
+++ b/tools/hciattach_ar3k.c
@@ -0,0 +1,859 @@
+/*
+ * 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_ar3k_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_ar3k_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 HCI_SLEEP_CMD_OCF 0x04
+
+int ath_configure_sleep(int fd, int sleep_stat)
+{
+ 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, &sleep_stat) < 0)
+ perror("Power management Disabled");
+
+ nanosleep(&tm, NULL);
+ hci_close_dev(dd);
+
+ return 0;
+}
+
+#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);
+}
+
+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_ar3k_version(fd, &rom_version, &build_version) < 0) {
+ err = -EILSEQ;
+ goto download_cmplete;
+ }
+
+ /* Do not download configuration if CRC passes */
+ if (get_ar3k_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;
+}
--
1.7.0.4
^ permalink raw reply related
* Re: [PATCH v2 2/2] Bluetooth: host level Support for Atheros AR300x device
From: Johan Hedberg @ 2010-08-18 5:55 UTC (permalink / raw)
To: Suraj; +Cc: linux-bluetooth, Jothikumar.Mothilal
In-Reply-To: <4C6B6E03.7080600@Atheros.com>
Hi Suraj,
On Wed, Aug 18, 2010, Suraj wrote:
> Sorry about that,
>
> I did do a fresh
>
> ./bootstrap-configure
> ./configure
> make
>
> and strangely my compiler did not catch anyone of these and it
> compiled without any warning.
>
> Is there any flag I have to enable for this?
>
> My gcc version says,
>
> gcc 4.4.3
bootstrap-configure already runs configure for you (hence the name) with
the appropriate parameters (such as --enable-maintainer-mode). When you
run configure a second time it will overwrite these. So running
"./bootstrap-configure && make" should be enough.
Johan
^ permalink raw reply
* Re: [PATCH v2 2/2] Bluetooth: host level Support for Atheros AR300x device
From: Suraj @ 2010-08-18 5:22 UTC (permalink / raw)
To: linux-bluetooth, Jothikumar.Mothilal
In-Reply-To: <20100817143236.GB19862@jh-x301>
Hi Johan,
On 8/17/2010 8:02 PM, Johan Hedberg wrote:
> Hi,
>
> On Fri, Aug 13, 2010, Suraj Sumangala wrote:
>> Implements support for Atheros AR300x Bluetooth chip in
>> hciattach application. Supports configuration download
>> and power management configure feature.
>> ---
>> Makefile.tools | 7 +-
>> tools/hciattach.8 | 3 +
>> tools/hciattach.c | 105 ++++++
>> tools/hciattach.h | 3 +
>> tools/hciattach_ar3k.c | 859 ++++++++++++++++++++++++++++++++++++++++++++++++
>> 5 files changed, 974 insertions(+), 3 deletions(-)
>> create mode 100644 tools/hciattach_ar3k.c
>
> This patch produces several errors:
>
> tools/hciattach_ar3k.c: In function ‘write_ps_cmd’:
> tools/hciattach_ar3k.c:196: error: comparison between signed and unsigned integer expressions
> tools/hciattach_ar3k.c: In function ‘get_ps_file_name’:
> tools/hciattach_ar3k.c:536: error: comparison between signed and unsigned integer expressions
> tools/hciattach_ar3k.c: In function ‘get_patch_file_name’:
> tools/hciattach_ar3k.c:552: error: comparison between signed and unsigned integer expressions
> tools/hciattach_ar3k.c:552: error: comparison between signed and unsigned integer expressions
> make[1]: *** [tools/hciattach_ar3k.o] Error 1
>
> Please fix those and always check that your patches compile cleanly with
> ./bootstrap-configure before sending them upstream. Thanks.
>
> Johan
Sorry about that,
I did do a fresh
./bootstrap-configure
./configure
make
and strangely my compiler did not catch anyone of these and it compiled
without any warning.
Is there any flag I have to enable for this?
My gcc version says,
gcc 4.4.3
Regards
Suraj
^ permalink raw reply
* [PATCH 0/3] Parsing of AMP related HCI commands and events
From: Inga Stotland @ 2010-08-18 3:55 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/1] Bluetooth: Add socket option definitions for AMP
From: Mat Martineau @ 2010-08-17 23:07 UTC (permalink / raw)
To: linux-bluetooth; +Cc: marcel, rshaffer, linux-arm-msm, Mat Martineau
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:
BT_AMP_REQUIRE_BR_EDR
* Default
* AMP controllers cannot be used
* Channel move requests from the remote device are denied
* If the L2CAP channel is currently using AMP, move the channel to
BR/EDR
BT_AMP_PREFER_AMP
* Allow use of AMP controllers
* If the L2CAP channel is currently on BR/EDR and AMP controller
resources are available, initiate a channel move to AMP
* Channel move requests from the remote device are allowed
* If the L2CAP socket has not been connected yet, try to create
and configure the channel directly on an AMP controller rather
than BR/EDR
BT_AMP_PREFER_BR_EDR
* Allow use of AMP controllers
* If the L2CAP channel is currently on AMP, move it to BR/EDR
* Channel move requests from the remote device are allowed
Signed-off-by: Mat Martineau <mathewm@codeaurora.org>
---
include/net/bluetooth/bluetooth.h | 5 +++++
1 files changed, 5 insertions(+), 0 deletions(-)
diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h
index 27a902d..0d41b99 100644
--- a/include/net/bluetooth/bluetooth.h
+++ b/include/net/bluetooth/bluetooth.h
@@ -64,6 +64,11 @@ struct bt_security {
#define BT_DEFER_SETUP 7
+#define BT_AMP 8
+#define BT_AMP_REQUIRE_BR_EDR 0
+#define BT_AMP_PREFER_AMP 1
+#define BT_AMP_PREFER_BR_EDR 2
+
#define BT_INFO(fmt, arg...) printk(KERN_INFO "Bluetooth: " fmt "\n" , ## arg)
#define BT_ERR(fmt, arg...) printk(KERN_ERR "%s: " fmt "\n" , __func__ , ## arg)
#define BT_DBG(fmt, arg...) pr_debug("%s: " fmt "\n" , __func__ , ## arg)
--
1.7.1
--
Mat Martineau
Employee of Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum
^ permalink raw reply related
* Re: [PATCH 4/5] Add set fast connectable to audio manager
From: Johan Hedberg @ 2010-08-17 14:43 UTC (permalink / raw)
To: Dmitriy Paliy; +Cc: linux-bluetooth
In-Reply-To: <1282053934-19445-5-git-send-email-dmitriy.paliy@nokia.com>
Hi Dmitriy,
On Tue, Aug 17, 2010, Dmitriy Paliy wrote:
> + 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) );
> + }
Same coding style issues I already mentioned for the other patch: no
braces for one-line if-statements and no space after ( or before ).
Johan
^ permalink raw reply
* Re: [PATCH 2/5] Add fast connectable to hciops
From: Johan Hedberg @ 2010-08-17 14:41 UTC (permalink / raw)
To: Dmitriy Paliy; +Cc: linux-bluetooth
In-Reply-To: <1282053934-19445-3-git-send-email-dmitriy.paliy@nokia.com>
Hi Dmitry,
On Tue, Aug 17, 2010, Dmitriy Paliy wrote:
> + 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;
> + }
A few coding style issues: no braces for one-line if-statements and
remove the spaces after ( and before ) should be removed.
Johan
^ permalink raw reply
* Re: [PATCH v2 2/2] Bluetooth: host level Support for Atheros AR300x device
From: Johan Hedberg @ 2010-08-17 14:32 UTC (permalink / raw)
To: Suraj Sumangala; +Cc: linux-bluetooth, Jothikumar.Mothilal
In-Reply-To: <1281681408-27376-2-git-send-email-suraj@atheros.com>
Hi,
On Fri, Aug 13, 2010, Suraj Sumangala wrote:
> Implements support for Atheros AR300x Bluetooth chip in
> hciattach application. Supports configuration download
> and power management configure feature.
> ---
> Makefile.tools | 7 +-
> tools/hciattach.8 | 3 +
> tools/hciattach.c | 105 ++++++
> tools/hciattach.h | 3 +
> tools/hciattach_ar3k.c | 859 ++++++++++++++++++++++++++++++++++++++++++++++++
> 5 files changed, 974 insertions(+), 3 deletions(-)
> create mode 100644 tools/hciattach_ar3k.c
This patch produces several errors:
tools/hciattach_ar3k.c: In function ‘write_ps_cmd’:
tools/hciattach_ar3k.c:196: error: comparison between signed and unsigned integer expressions
tools/hciattach_ar3k.c: In function ‘get_ps_file_name’:
tools/hciattach_ar3k.c:536: error: comparison between signed and unsigned integer expressions
tools/hciattach_ar3k.c: In function ‘get_patch_file_name’:
tools/hciattach_ar3k.c:552: error: comparison between signed and unsigned integer expressions
tools/hciattach_ar3k.c:552: error: comparison between signed and unsigned integer expressions
make[1]: *** [tools/hciattach_ar3k.o] Error 1
Please fix those and always check that your patches compile cleanly with
./bootstrap-configure before sending them upstream. Thanks.
Johan
^ permalink raw reply
* Re: [PATCH v2 1/2] Bluetooth: Option to enable power management from host
From: Johan Hedberg @ 2010-08-17 14:30 UTC (permalink / raw)
To: Suraj Sumangala; +Cc: linux-bluetooth, Jothikumar.Mothilal
In-Reply-To: <1281681408-27376-1-git-send-email-suraj@atheros.com>
Hi,
On Fri, Aug 13, 2010, Suraj Sumangala wrote:
> This provides a new option for hciattach to enable hardware specific
> power management from host.
> This option by default will be disabled for existing devices
> ---
> tools/hciattach.8 | 13 ++++++++
> tools/hciattach.c | 88 ++++++++++++++++++++++++++++++++++++++---------------
> 2 files changed, 76 insertions(+), 25 deletions(-)
This patch has been pushed upstream. Thanks.
Johan
^ permalink raw reply
* Re: Support for HCI commands and events related to AMP functionality
From: Johan Hedberg @ 2010-08-17 14:26 UTC (permalink / raw)
To: Inga Stotland; +Cc: linux-bluetooth, rshaffer, marcel
In-Reply-To: <1281485576-32715-1-git-send-email-ingas@codeaurora.org>
Hi Inga,
On Tue, Aug 10, 2010, Inga Stotland wrote:
> Added new HCI commands and events constructs for AMP related development.
> Will be used in updated testing tools for AMP.
Both patches have been pushed upstream. Thanks.
Johan
^ permalink raw reply
* Re: [PATCH 0/5] Fast connectable mode for HFP
From: Johan Hedberg @ 2010-08-17 14:20 UTC (permalink / raw)
To: Dmitriy Paliy; +Cc: linux-bluetooth, marcel
In-Reply-To: <1282053934-19445-1-git-send-email-dmitriy.paliy@nokia.com>
Hi Dmitriy,
On Tue, Aug 17, 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
> possible 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.
In general these patches seem fine to me, however I'd like a second
opinion from Marcel before pushing upstream.
Johan
^ permalink raw reply
* Re: [PATCH 2/2] gwobex: fix misuse of OBEX_SetCustomData/OBEX_GetCustomData
From: Johan Hedberg @ 2010-08-17 14:19 UTC (permalink / raw)
To: Luiz Augusto von Dentz; +Cc: linux-bluetooth
In-Reply-To: <1282053510-18102-2-git-send-email-luiz.dentz@gmail.com>
Hi Luiz,
On Tue, Aug 17, 2010, Luiz Augusto von Dentz wrote:
> From: Luiz Augusto von Dentz <luiz.dentz-von@nokia.com>
>
> Those function should only be used in case of custom transport which is
> not the case since we are using fd transport here.
>
> To fix that it now uses OBEX_SetUserData/OBEX_GetUserData which are not
> associate with any transport in particular.
> ---
> gwobex/gw-obex.c | 2 +-
> gwobex/obex-priv.c | 2 +-
> 2 files changed, 2 insertions(+), 2 deletions(-)
This one has also been pushed to the obexd upstream tree. Also remember
to update the upstream gwobex tree at gitorious.org.
Johan
^ permalink raw reply
* Re: [PATCH 1/2] Fix aborting capability scripts making them zombies processes
From: Johan Hedberg @ 2010-08-17 14:18 UTC (permalink / raw)
To: Luiz Augusto von Dentz; +Cc: linux-bluetooth
In-Reply-To: <1282053510-18102-1-git-send-email-luiz.dentz@gmail.com>
Hi Luiz,
On Tue, Aug 17, 2010, Luiz Augusto von Dentz wrote:
> From: Luiz Augusto von Dentz <luiz.dentz-von@nokia.com>
>
> When using G_SPAWN_DO_NOT_REAP_CHILD the watch cannot be removed since it
> basically replaces the use of waitpid which does prevent the child
> process to became 'zombie' when terminated, a more detailed explanation
> can be found in waitpid manpage.
> ---
> plugins/filesystem.c | 28 ++++++++++++++++++----------
> 1 files changed, 18 insertions(+), 10 deletions(-)
Thanks. The patch is now upstream.
Johan
^ permalink raw reply
* [PATCH 5/5] Add fast connectable support to HFP
From: Dmitriy Paliy @ 2010-08-17 14:05 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Dmitriy Paliy
In-Reply-To: <1282053934-19445-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
* [PATCH 4/5] Add set fast connectable to audio manager
From: Dmitriy Paliy @ 2010-08-17 14:05 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Dmitriy Paliy
In-Reply-To: <1282053934-19445-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..b885929 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 3/5] Add set fast connectable to adapter
From: Dmitriy Paliy @ 2010-08-17 14:05 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Dmitriy Paliy
In-Reply-To: <1282053934-19445-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 2/5] Add fast connectable to hciops
From: Dmitriy Paliy @ 2010-08-17 14:05 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Dmitriy Paliy
In-Reply-To: <1282053934-19445-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 | 34 ++++++++++++++++++++++++++++++++++
src/adapter.h | 1 +
2 files changed, 35 insertions(+), 0 deletions(-)
diff --git a/plugins/hciops.c b/plugins/hciops.c
index 9c97c5a..652830a 100644
--- a/plugins/hciops.c
+++ b/plugins/hciops.c
@@ -716,6 +716,39 @@ 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 +765,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 1/5] Add STANDARD and INTERLACED page scan definitions
From: Dmitriy Paliy @ 2010-08-17 14:05 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Dmitriy Paliy
In-Reply-To: <1282053934-19445-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 0/5] Fast connectable mode for HFP
From: Dmitriy Paliy @ 2010-08-17 14:05 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
possible 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 2/2] gwobex: fix misuse of OBEX_SetCustomData/OBEX_GetCustomData
From: Luiz Augusto von Dentz @ 2010-08-17 13:58 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1282053510-18102-1-git-send-email-luiz.dentz@gmail.com>
From: Luiz Augusto von Dentz <luiz.dentz-von@nokia.com>
Those function should only be used in case of custom transport which is
not the case since we are using fd transport here.
To fix that it now uses OBEX_SetUserData/OBEX_GetUserData which are not
associate with any transport in particular.
---
gwobex/gw-obex.c | 2 +-
gwobex/obex-priv.c | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/gwobex/gw-obex.c b/gwobex/gw-obex.c
index e656692..4481212 100644
--- a/gwobex/gw-obex.c
+++ b/gwobex/gw-obex.c
@@ -343,7 +343,7 @@ GwObex *gw_obex_setup_fd(int fd, const gchar *uuid, gint uuid_len,
ctx->mutex = g_mutex_new();
#endif
- OBEX_SetCustomData(handle, ctx);
+ OBEX_SetUserData(handle, ctx);
debug("Connecting to OBEX service\n");
if (!gw_obex_connect(ctx, uuid, uuid_len)) {
diff --git a/gwobex/obex-priv.c b/gwobex/obex-priv.c
index 76a9599..aba7dd7 100644
--- a/gwobex/obex-priv.c
+++ b/gwobex/obex-priv.c
@@ -514,7 +514,7 @@ static void obex_writestream(GwObex *ctx, obex_object_t *object) {
static void obex_event_handler(obex_t *handle, obex_object_t *object, int mode,
int event, int obex_cmd, int obex_rsp) {
- GwObex *ctx = OBEX_GetCustomData(handle);
+ GwObex *ctx = OBEX_GetUserData(handle);
switch (event) {
case OBEX_EV_ABORT:
debug("OBEX_EV_ABORT\n");
--
1.7.0.4
^ permalink raw reply related
* [PATCH 1/2] Fix aborting capability scripts making them zombies processes
From: Luiz Augusto von Dentz @ 2010-08-17 13:58 UTC (permalink / raw)
To: linux-bluetooth
From: Luiz Augusto von Dentz <luiz.dentz-von@nokia.com>
When using G_SPAWN_DO_NOT_REAP_CHILD the watch cannot be removed since it
basically replaces the use of waitpid which does prevent the child
process to became 'zombie' when terminated, a more detailed explanation
can be found in waitpid manpage.
---
plugins/filesystem.c | 28 ++++++++++++++++++----------
1 files changed, 18 insertions(+), 10 deletions(-)
diff --git a/plugins/filesystem.c b/plugins/filesystem.c
index f0e5bbe..bf00ac2 100644
--- a/plugins/filesystem.c
+++ b/plugins/filesystem.c
@@ -237,7 +237,7 @@ struct capability_object {
int pid;
int output;
int err;
- unsigned int watch;
+ gboolean aborted;
GString *buffer;
};
@@ -247,10 +247,20 @@ static void script_exited(GPid pid, int status, void *data)
char buf[128];
object->pid = -1;
- object->watch = 0;
DBG("pid: %d status: %d", pid, status);
+ g_spawn_close_pid(pid);
+
+ /* free the object if aborted */
+ if (object->aborted) {
+ if (object->buffer != NULL)
+ g_string_free(object->buffer, TRUE);
+
+ g_free(object);
+ return;
+ }
+
if (WEXITSTATUS(status) != EXIT_SUCCESS) {
memset(buf, 0, sizeof(buf));
if (read(object->err, buf, sizeof(buf)) > 0)
@@ -258,8 +268,6 @@ static void script_exited(GPid pid, int status, void *data)
obex_object_set_io_flags(data, G_IO_ERR, -EPERM);
} else
obex_object_set_io_flags(data, G_IO_IN, 0);
-
- g_spawn_close_pid(pid);
}
static int capability_exec(const char **argv, int *output, int *err)
@@ -321,7 +329,8 @@ static void *capability_open(const char *name, int oflag, mode_t mode,
if (object->pid < 0)
goto fail;
- object->watch = g_child_watch_add(object->pid, script_exited, object);
+ /* Watch cannot be removed while the process is still running */
+ g_child_watch_add(object->pid, script_exited, object);
done:
if (err)
@@ -519,18 +528,17 @@ static int capability_close(void *object)
if (obj->pid < 0)
goto done;
- if (obj->watch)
- g_source_remove(obj->watch);
-
- g_spawn_close_pid(obj->pid);
-
DBG("kill: pid %d", obj->pid);
err = kill(obj->pid, SIGTERM);
if (err < 0) {
err = -errno;
error("kill: %s (%d)", strerror(-err), -err);
+ goto done;
}
+ obj->aborted = TRUE;
+ return 0;
+
done:
if (obj->buffer != NULL)
g_string_free(obj->buffer, TRUE);
--
1.7.0.4
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox