2010-02-10 12:39:45

by Vikram

[permalink] [raw]
Subject: [PATCH] Added Application Support for Atheros AR300X UART Bluetooth Chip


Signed-off-by: Suraj <[email protected]>

---
Makefile.tools | 2 +
tools/ar3kpsconfig.c | 455 ++++++++++++++++++++++++++++
tools/ar3kpsparser.c | 822 ++++++++++++++++++++++++++++++++++++++++++++++++++
tools/ar3kpsparser.h | 127 ++++++++
tools/hciattach.8 | 6 +
tools/hciattach.c | 158 ++++++++++-
tools/hciattach.h | 5 +-
7 files changed, 1572 insertions(+), 3 deletions(-)
create mode 100755 tools/ar3kpsconfig.c
create mode 100755 tools/ar3kpsparser.c
create mode 100755 tools/ar3kpsparser.h

diff --git a/Makefile.tools b/Makefile.tools
index 2735d68..72277f9 100644
--- a/Makefile.tools
+++ b/Makefile.tools
@@ -21,6 +21,8 @@ tools_rfcomm_LDADD = lib/libbluetooth.la
tools_l2ping_LDADD = lib/libbluetooth.la

tools_hciattach_SOURCES = tools/hciattach.c tools/hciattach.h \
+ tools/ar3kpsparser.c \
+ tools/ar3kpsconfig.c \
tools/hciattach_st.c \
tools/hciattach_ti.c \
tools/hciattach_tialt.c
diff --git a/tools/ar3kpsconfig.c b/tools/ar3kpsconfig.c
new file mode 100755
index 0000000..e94e4b5
--- /dev/null
+++ b/tools/ar3kpsconfig.c
@@ -0,0 +1,455 @@
+/*
+ * 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
+ *
+ */
+
+#include "ar3kpsparser.h"
+#include "hciattach.h"
+
+#define FW_PATH "/lib/firmware/"
+#define NUM_WAKEUP_RETRY 10
+
+uint32_t rom_version;
+uint32_t build_version;
+
+int wake_up_ar3001(int fd)
+{
+ struct termios ti;
+ int status;
+ int retrycount = 0;
+ if (tcgetattr(fd, &ti) < 0) {
+ perror("Can't get port settings");
+ return -1;
+ }
+ ioctl(fd, TIOCMGET, &status);
+ if (status & TIOCM_CTS)
+ return 0;
+
+ ti.c_cflag &= ~CRTSCTS;
+ if (tcsetattr(fd, TCSANOW, &ti) < 0) {
+ perror("Can't set port settings");
+ return -1;
+ }
+
+ do {
+ ioctl(fd, TIOCMGET, &status);
+
+ /* deassert */
+ status &= (~TIOCM_RTS);
+ ioctl(fd, TIOCMSET, &status);
+
+ /* read */
+ ioctl(fd, TIOCMGET, &status);
+
+ /* assert */
+ status |= (TIOCM_RTS);
+ ioctl(fd, TIOCMSET, &status);
+ usleep(200);
+
+ /* read */
+ ioctl(fd, TIOCMGET, &status);
+ retrycount++;
+ if (retrycount > NUM_WAKEUP_RETRY)
+ break;
+ } while (!(status & TIOCM_CTS));
+ if (!(status & TIOCM_CTS))
+ return -1;
+
+ ti.c_cflag |= CRTSCTS;
+ if (tcsetattr(fd, TCSANOW, &ti) < 0) {
+ perror("Can't set port settings");
+ return -1;
+ }
+ return 0;
+}
+
+/*
+ * This API is used to send the HCI command to controller and return
+ * with a HCI Command Complete event.
+ */
+int send_hci_cmd_wait_event(int dev,
+ uint8_t *hci_command,
+ int cmd_length,
+ uint8_t **event, uint8_t **buffer_to_free)
+{
+ int r;
+ uint8_t *hci_event;
+ uint8_t pktType = 0x01;
+ if (cmd_length == 0)
+ return -1;
+
+ /*
+ * Try to wake up the board if it is asleep
+ * The assumption here is that the board is asleep.
+ */
+ if (wake_up_ar3001(dev) < 0)
+ return -1;
+
+ if (write(dev, &pktType, 1) != 1)
+ return -1;
+
+ if (write(dev, (unsigned char *)hci_command, cmd_length) != cmd_length)
+ return -1;
+
+ hci_event = (uint8_t *) malloc(100);
+ r = read_hci_event(dev, (unsigned char *)hci_event, 100);
+ if (r > 0) {
+ *event = hci_event;
+ *buffer_to_free = hci_event;
+ } else {
+
+ /* Did not get an event from controller. return error */
+ free(hci_event);
+ *buffer_to_free = NULL;
+ return -1;
+ }
+ return 0;
+}
+
+int read_ps_event(uint8_t *data)
+{
+ if (data[5] == 0xFC && data[6] == 0x00) {
+ switch (data[4]) {
+ case 0x0B:
+ return 0;
+ break;
+ case 0x0C:
+
+ /* Change Baudrate */
+ return 0;
+ break;
+ case 0x04:
+ return 0;
+ break;
+ case 0x1E:
+ rom_version = data[10];
+ rom_version = ((rom_version << 8) | data[9]);
+ rom_version = ((rom_version << 8) | data[8]);
+ rom_version = ((rom_version << 8) | data[7]);
+ build_version = data[14];
+ build_version = ((build_version << 8) | data[13]);
+ build_version = ((build_version << 8) | data[12]);
+ build_version = ((build_version << 8) | data[11]);
+ return 0;
+ break;
+ }
+ }
+ return -1;
+}
+
+int get_ps_file_name(int devtype, char *path)
+{
+ char *filename;
+ int status = 0;
+ if (devtype == 0xdeadc0de) {
+ filename = PS_ASIC_FILE;
+ status = 1;
+ }
+
+ else {
+ filename = PS_FPGA_FILE;
+ status = 0;
+ }
+ sprintf(path, "%s%s", FW_PATH, filename);
+ return status;
+}
+
+int get_patch_file_name(int dev_type, int rom_version, int build_version,
+ char *path)
+{
+ if ((dev_type != 0) && (dev_type != 0xdeadc0de)
+ && (rom_version == 0x99999999) && (build_version == 1)) {
+ path[0] = '\0';
+ } else
+ sprintf(path, "%s%s", FW_PATH, PATCH_FILE);
+
+ return 0;
+}
+
+int get_device_type(int dev, uint32_t *code)
+{
+ uint8_t hciCommand[] = {
+ 0x05, 0xfc, 0x05, 0x00, 0x00, 0x00, 0x00, 0x04
+ };
+ uint8_t *event;
+ uint8_t *buffer_to_free = NULL;
+ uint32_t reg;
+ int result = -1;
+ *code = 0;
+ hciCommand[3] = (uint8_t) (FPGA_REGISTER & 0xFF);
+ hciCommand[4] = (uint8_t) ((FPGA_REGISTER >> 8) & 0xFF);
+ hciCommand[5] = (uint8_t) ((FPGA_REGISTER >> 16) & 0xFF);
+ hciCommand[6] = (uint8_t) ((FPGA_REGISTER >> 24) & 0xFF);
+ if (0 ==
+ send_hci_cmd_wait_event(dev, hciCommand,
+ sizeof(hciCommand), &event,
+ &buffer_to_free)) {
+ if (event[5] == 0xFC && event[6] == 0x00) {
+ switch (event[4]) {
+ case 0x05:
+ reg = event[10];
+ reg = ((reg << 8) | event[9]);
+ reg = ((reg << 8) | event[8]);
+ reg = ((reg << 8) | event[7]);
+ *code = reg;
+ result = 0;
+ break;
+ case 0x06:
+ break;
+ }
+ }
+ }
+ if (buffer_to_free != NULL)
+ free(buffer_to_free);
+
+ return result;
+}
+
+int read_ar3001_version(int pConfig)
+{
+ uint8_t hciCommand[] = {
+ 0x1E, 0xfc, 0x00
+ };
+ uint8_t *event;
+ uint8_t *buffer_to_free = NULL;
+ int result = -1;
+
+ if (0 ==
+ send_hci_cmd_wait_event(pConfig, hciCommand,
+ sizeof(hciCommand), &event,
+ &buffer_to_free)) {
+ result = read_ps_event(event);
+ }
+ if (buffer_to_free != NULL)
+ free(buffer_to_free);
+
+ return result;
+}
+
+int str2bdaddr(char *str_bdaddr, char *bdaddr)
+{
+ char bdbyte[3];
+ char *str_byte = str_bdaddr;
+ int i, j;
+ unsigned char colon_present = 0;
+
+ if (NULL != strstr(str_bdaddr, ":"))
+ colon_present = 1;
+
+ bdbyte[2] = '\0';
+
+ 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;
+ }
+ return 0;
+}
+
+int write_bdaddr(int pConfig, char *bdaddr)
+{
+ uint8_t bdaddr_cmd[] = { 0x0B, 0xFC, 0x0A, 0x01, 0x01,
+ 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+ };
+ uint8_t *event;
+ uint8_t *buffer_to_free = NULL;
+ int result = -1;
+
+ str2bdaddr(bdaddr, (char *)&bdaddr_cmd[7]);
+
+ if (0 == send_hci_cmd_wait_event(pConfig, bdaddr_cmd,
+ sizeof(bdaddr_cmd),
+ &event, &buffer_to_free)) {
+
+ if (event[5] == 0xFC && event[6] == 0x00) {
+ if (event[4] == 0x0B)
+ result = 0;
+ }
+
+ } else
+ perror(" Write failed \n");
+
+ if (buffer_to_free != NULL)
+ free(buffer_to_free);
+
+ return result;
+}
+
+int ath_ps_download(int hdev)
+{
+ int i;
+ int status;
+ struct ps_cmd_packet *HciCmdList; /* List storing the commands */
+ uint32_t numCmds;
+ uint8_t *event;
+ uint8_t *buffer_to_free;
+ uint32_t DevType;
+ char patchFileName[PATH_MAX];
+ char PsFileName[PATH_MAX];
+ char bdaddr_file_name[PATH_MAX];
+ FILE *stream;
+ char bdaddr[21];
+
+ status = 0;
+ HciCmdList = NULL;
+
+ /* First verify if the controller is an FPGA or ASIC,
+ *so depending on the device type the PS file to be written
+ * will be different.
+ */
+ do {
+ if (-1 == get_device_type(hdev, &DevType)) {
+ status = -1;
+ break;
+ }
+ if (-1 == read_ar3001_version(hdev)) {
+ status = -1;
+ break;
+ }
+ get_ps_file_name(DevType, PsFileName);
+ get_patch_file_name(DevType, rom_version, build_version,
+ patchFileName);
+
+ /* Read the PS file to a dynamically allocated buffer */
+ stream = fopen(PsFileName, "r");
+ if (stream == NULL) {
+ perror("firmware file open error\n");
+ status = -1;
+ break;
+ }
+ status = ath_parse_ps(stream);
+ fclose(stream);
+
+ /*
+ * It is not necessary that Patch file be available,
+ * continue with PS Operations if.
+ * failed.
+ */
+ if (patchFileName[0] == '\0')
+ status = 0;
+ stream = fopen(patchFileName, "r");
+ if (stream == NULL)
+ status = 0;
+ else {
+ /* parse and store the Patch file contents to
+ * a global variables
+ */
+ status = parse_patch_file(stream);
+ fclose(stream);
+ }
+
+ /* Create an HCI command list
+ * from the parsed PS and patch information */
+ ath_create_cmd_list(&HciCmdList, &numCmds);
+
+ /*
+ * First Send the CRC packet,
+ * We have to continue with the PS operations
+ * only if the CRC packet has been replied with
+ * a Command complete event with status Error.
+ */
+ if (send_hci_cmd_wait_event
+ (hdev, HciCmdList[0].Hcipacket,
+ HciCmdList[0].packetLen, &event, &buffer_to_free) == 0) {
+ if (read_ps_event(event) == 0) {
+ /* Exit if the status is success */
+ if (buffer_to_free != NULL)
+ free(buffer_to_free);
+
+ status = 0;
+ break;
+ }
+ if (buffer_to_free != NULL)
+ free(buffer_to_free);
+ } else {
+ status = -1;
+ break;
+ }
+ for (i = 1; i < numCmds; i++) {
+ if (send_hci_cmd_wait_event
+ (hdev, HciCmdList[i].Hcipacket,
+ HciCmdList[i].packetLen, &event,
+ &buffer_to_free) == 0) {
+ if (read_ps_event(event) < 0) {
+ /* Exit if the status is not success */
+ if (buffer_to_free != NULL)
+ free(buffer_to_free);
+
+ status = -1;
+ break;
+ }
+ if (buffer_to_free != NULL)
+ free(buffer_to_free);
+ } else {
+ status = 0;
+ break;
+ }
+ }
+ /* Read the PS file to a dynamically allocated buffer */
+ sprintf(bdaddr_file_name, "%s%s", FW_PATH, BDADDR_FILE);
+ stream = fopen(bdaddr_file_name, "r");
+ if (stream == NULL) {
+ status = 0;
+ break;
+ }
+ if (fgets(bdaddr, 20, stream) != NULL)
+ status = write_bdaddr(hdev, bdaddr);
+
+ fclose(stream);
+
+ } while (FALSE);
+ if (NULL != HciCmdList)
+ ath_free_command_list(&HciCmdList, numCmds);
+
+ return status;
+}
+
+int configure_sleep(int fd, unsigned char status)
+{
+ unsigned char cmd[6];
+ int r;
+
+ /* Send command to enable/disable Advanced power management featuresa*/
+ cmd[0] = HCI_COMMAND_PKT;
+ cmd[1] = 0x04;
+ cmd[2] = 0xFC;
+ cmd[3] = 0x01;
+ cmd[4] = status;
+
+ /* Send Sleep enable/disable command */
+ r = write(fd, cmd, 5);
+ if (r != 5) {
+ perror("Can't write Sleep Enable Cmd.");
+ return -1;
+ }
+ return 0;
+}
+
+/* Parser Section Begin */
+int ar3001_post(int fd)
+{
+ return configure_sleep(fd, 0x00);
+}
+
+int ar3001pm_post(int fd)
+{
+ return configure_sleep(fd, 0x01);
+}
diff --git a/tools/ar3kpsparser.c b/tools/ar3kpsparser.c
new file mode 100755
index 0000000..cb62bee
--- /dev/null
+++ b/tools/ar3kpsparser.c
@@ -0,0 +1,822 @@
+/*
+ * 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
+ *
+ */
+
+#include "ar3kpsparser.h"
+
+#define WRITE_PATCH 8
+#define ENABLE_PATCH 11
+#define PS_RESET 2
+#define PS_WRITE 1
+#define PS_VERIFY_CRC 9
+#define CHANGE_BDADDR 15
+
+#define HCI_CMD_HEADER_LEN 7
+#define HCI_EVENT_SIZE 7
+#define RAM_PS_REGION (1<<0)
+#define RAM_PATCH_REGION (1<<1)
+#define RAMPS_MAX_PS_TAGS_PER_FILE 50
+#define PS_MAX_LEN 500
+#define LINE_SIZE_MAX (PS_MAX_LEN * 2)
+/* Constant values used by parser */
+#define BYTES_OF_PS_DATA_PER_LINE 16
+#define INVALID_THRESHOLD 0xFF
+
+#define MAX_BYTE_LENGTH 244
+
+#define skip_space(str) while (*(str) == (' ')) ((str)++)
+#define IS_BETWEEN(x, lower, upper) (((lower) <= (x)) && ((x) <= (upper)))
+#define tohexval(c) (isdigit(c) ? ((c) - '0') : \
+ (IS_BETWEEN((c), 'A', 'Z') ? \
+ ((c) - 'A' + 10) : ((c) - 'a' + 10)))
+enum ps_entry_type {
+ hex_type,
+ decimal_type
+};
+struct ps_tag_entry {
+ uint32_t tag_id;
+ uint32_t tag_len;
+ uint8_t *tag_data;
+};
+
+struct ps_ram_patch {
+ int16_t Len;
+ uint8_t *Data;
+};
+struct ps_data_format {
+ enum ps_entry_type data_type;
+ unsigned char is_array;
+};
+struct st_read_status {
+ unsigned section;
+ unsigned line_count;
+ unsigned char_cnt;
+ unsigned byte_count;
+};
+struct brm_rxtx_pkt_sel_cfg {
+ unsigned int force_up_rate_threshold;
+ unsigned char edr_up_threshold[PKT_SEL_BUFFER_SIZE];
+ unsigned char edr_down_threshold[PKT_SEL_BUFFER_SIZE];
+ unsigned char rss_min_delta;
+ unsigned char per_min_delta;
+ unsigned char max_long_term_errors[PKT_SEL_BUFFER_SIZE];
+ unsigned char long_term_error_per_threshold;
+};
+
+uint8_t hci_rfcomm_down_cmd[] = {
+ 0x01, 0x32, 0xFC, 0x21, 0x00, 0x00 /* Param begin */ ,
+ 0x19, 0x00, 0x00, 0x00, /* force_up_rate_threshold */
+ /* EDR_PER_UP_THRESHOLDS_DEFAULT */
+ INVALID_THRESHOLD, /* ePktSel_EDR_Init */
+ 0x05, /* ePktSel_EDR_DM1 */
+ 0x05, /* ePktSel_EDR_2DH1 */
+ 0x05, /* ePktSel_EDR_2DH3 */
+ 0x05, /* ePktSel_EDR_2DH5 */
+ 0x05, /* ePktSel_EDR_3DH1 */
+ 0x05, /* ePktSel_EDR_3DH3 */
+ INVALID_THRESHOLD /* ePktSel_EDR_3DH5 */
+ ,
+ /* EDR_PER_DOWN_THRESHOLDS_DEFAULT */
+ INVALID_THRESHOLD, /* ePktSel_EDR_Init */
+ INVALID_THRESHOLD, /* ePktSel_EDR_DM1 */
+ 0x40, /* ePktSel_EDR_2DH1 */
+ 0x20, /* ePktSel_EDR_2DH3 */
+ 0x20, /* ePktSel_EDR_2DH5 */
+ 0x20, /* ePktSel_EDR_3DH1 */
+ 0x20, /* ePktSel_EDR_3DH3 */
+ 0x20 /* ePktSel_EDR_3DH5 */
+ ,
+
+ 0x04, /* rss_min_delta: */
+ 0x05, /* per_min_delta: */
+
+ /* EDR_MAX_LONG_TERM_ERRORS_DEFAULT */
+ INVALID_THRESHOLD, /* ePktSel_EDR_Init */
+ INVALID_THRESHOLD, /* ePktSel_EDR_DM1 */
+ 0x11, /* ePktSel_EDR_2DH1 */
+ 0x11, /* ePktSel_EDR_2DH3 */
+ 0x11, /* ePktSel_EDR_2DH5 */
+ 0x11, /* ePktSel_EDR_3DH1 */
+ 0x11, /* ePktSel_EDR_3DH3 */
+ 0x11 /* ePktSel_EDR_3DH5 */
+ ,
+ 0x01 /* long_term_error_per_threshold */
+};
+
+uint8_t hci_rfcomm_up_cmd[] = {
+ 0x01, 0x32, 0xFC, 0x21, 0x00, 0x00 /* Param begin */ ,
+ 0x32, 0x00, 0x00, 0x00, /* force_up_rate_threshold */
+ /* EDR_PER_UP_THRESHOLDS_CONSV */
+ INVALID_THRESHOLD, /* ePktSel_EDR_Init */
+ 0x05, /* ePktSel_EDR_DM1 */
+ 0x10, /* ePktSel_EDR_2DH1 */
+ 0x02, /* ePktSel_EDR_2DH3 */
+ 0x01, /* ePktSel_EDR_2DH5 */
+ 0x02, /* ePktSel_EDR_3DH1 */
+ 0x01, /* ePktSel_EDR_3DH3 */
+ INVALID_THRESHOLD /* ePktSel_EDR_3DH5 */
+ ,
+ /* EDR_PER_DOWN_THRESHOLDS_CONSV */
+ INVALID_THRESHOLD, /* ePktSel_EDR_Init */
+ INVALID_THRESHOLD, /* ePktSel_EDR_DM1 */
+ 0x50, /* ePktSel_EDR_2DH1 */
+ 0x50, /* ePktSel_EDR_2DH3 */
+ 0x02, /* ePktSel_EDR_2DH5 */
+ 0x03, /* ePktSel_EDR_3DH1 */
+ 0x03, /* ePktSel_EDR_3DH3 */
+ 0x02, /* ePktSel_EDR_3DH5 */
+
+ 0x04, /* rss_min_delta */
+ 0x05, /* per_min_delta */
+
+ /* EDR_MAX_LONG_TERM_ERRORS_CONSV */
+ INVALID_THRESHOLD, /* ePktSel_EDR_Init */
+ INVALID_THRESHOLD, /* ePktSel_EDR_DM1 */
+ 0x11, /* ePktSel_EDR_2DH1 */
+ 0x11, /* ePktSel_EDR_2DH3 */
+ 0x03, /* ePktSel_EDR_2DH5 */
+ 0x03, /* ePktSel_EDR_3DH1 */
+ 0x03, /* ePktSel_EDR_3DH3 */
+ 0x03, /* ePktSel_EDR_3DH5 */
+
+ 0x01 /* long_term_error_per_threshold */
+};
+
+/* Stores the number of PS Tags */
+static uint32_t tag_count;
+
+/* Stores the number of patch commands */
+static uint32_t patch_count;
+static uint32_t total_tag_len;
+
+struct ps_tag_entry ps_tag_entry[RAMPS_MAX_PS_TAGS_PER_FILE];
+struct ps_ram_patch ram_patch[MAX_NUM_PATCH_ENTRY];
+
+struct brm_rxtx_pkt_sel_cfg *packet_config_conserv;
+struct brm_rxtx_pkt_sel_cfg *packet_config_default;
+
+/* PS parser helper function */
+static void load_hci_header(uint8_t *hci_ps_cmd,
+ uint8_t opcode, int length, int index)
+{
+ hci_ps_cmd[0] = 0x0B;
+ hci_ps_cmd[1] = 0xFC;
+ hci_ps_cmd[2] = length + 4;
+ hci_ps_cmd[3] = opcode;
+ hci_ps_cmd[4] = (index & 0xFF);
+ hci_ps_cmd[5] = ((index >> 8) & 0xFF);
+ hci_ps_cmd[6] = length;
+}
+
+void parse_rx_tx_pkt_config(struct ps_tag_entry ps_tag)
+{
+ switch (ps_tag.tag_id) {
+ case PSTAG_EdrPerUpThresholds:
+ memcpy(packet_config_default->edr_up_threshold,
+ ps_tag.tag_data, 8);
+ break;
+ case PSTAG_EdrPerDownThresholds:
+ memcpy(packet_config_default->edr_down_threshold,
+ ps_tag.tag_data, 8);
+ break;
+ case PSTAG_RSSIMinDelta:
+ packet_config_default->rss_min_delta = ps_tag.tag_data[0];
+ break;
+ case PSTAG_PERMinDelta:
+ packet_config_default->per_min_delta = ps_tag.tag_data[0];
+ break;
+ case PSTAG_MaxLongTermError:
+ memcpy(packet_config_default->max_long_term_errors,
+ ps_tag.tag_data, 8);
+ break;
+ case PSTAG_LongTermPERThreshold:
+ packet_config_default->long_term_error_per_threshold =
+ ps_tag.tag_data[0];
+ break;
+ case PSTAG_ForceUpRateThreshold:
+ memcpy(&packet_config_default->force_up_rate_threshold,
+ ps_tag.tag_data, 4);
+ break;
+
+ case PSTAG_EdrPerUpThresholds_Consv:
+ memcpy(packet_config_conserv->edr_up_threshold,
+ ps_tag.tag_data, 8);
+ break;
+ case PSTAG_EdrPerDownThresholds_Consv:
+ memcpy(packet_config_conserv->edr_down_threshold,
+ ps_tag.tag_data, 8);
+ break;
+ case PSTAG_RSSIMinDelta_Consv:
+ packet_config_conserv->rss_min_delta = ps_tag.tag_data[0];
+ break;
+ case PSTAG_PERMinDelta_Consv:
+ packet_config_conserv->per_min_delta = ps_tag.tag_data[0];
+ break;
+ case PSTAG_MaxLongTermError_Consv:
+ memcpy(packet_config_conserv->max_long_term_errors,
+ ps_tag.tag_data, 8);
+ break;
+ case PSTAG_LongTermPERThreshold_Consv:
+ packet_config_conserv->long_term_error_per_threshold =
+ ps_tag.tag_data[0];
+ break;
+ case PSTAG_ForceUpRateThreshold_Consv:
+ memcpy(&packet_config_conserv->force_up_rate_threshold,
+ ps_tag.tag_data, 4);
+ break;
+
+ }
+}
+
+static int ath_create_ps_command(uint8_t opcode, uint32_t Param1,
+ struct ps_cmd_packet *ps_patch_packet,
+ uint32_t *index)
+{
+ uint8_t *hci_ps_cmd;
+ uint32_t Length;
+ int i, j;
+
+ hci_ps_cmd = NULL;
+ switch (opcode) {
+ case WRITE_PATCH:
+ for (i = 0; i < Param1; i++) {
+ hci_ps_cmd =
+ (uint8_t *) malloc(ram_patch[i].Len +
+ HCI_CMD_HEADER_LEN);
+ if (hci_ps_cmd == NULL)
+ return -1;
+
+ memset(hci_ps_cmd, 0,
+ ram_patch[i].Len + HCI_CMD_HEADER_LEN);
+ load_hci_header(hci_ps_cmd, opcode, ram_patch[i].Len,
+ i);
+ for (j = 0; j < ram_patch[i].Len; j++)
+ hci_ps_cmd[HCI_CMD_HEADER_LEN + j] =
+ ram_patch[i].Data[j];
+ ps_patch_packet[*index].Hcipacket = hci_ps_cmd;
+ ps_patch_packet[*index].packetLen =
+ ram_patch[i].Len + HCI_CMD_HEADER_LEN;
+ (*index)++;
+ }
+ break;
+ case ENABLE_PATCH:
+ Length = 0;
+ i = 0;
+ hci_ps_cmd = (uint8_t *) malloc(Length + HCI_CMD_HEADER_LEN);
+ if (hci_ps_cmd == NULL)
+ return -1;
+
+ memset(hci_ps_cmd, 0, Length + HCI_CMD_HEADER_LEN);
+ load_hci_header(hci_ps_cmd, opcode, Length, i);
+ ps_patch_packet[*index].Hcipacket = hci_ps_cmd;
+ ps_patch_packet[*index].packetLen
+ = Length + HCI_CMD_HEADER_LEN;
+ (*index)++;
+ break;
+ case PS_RESET:
+ Length = 0x06;
+ i = 0;
+ hci_ps_cmd = (uint8_t *) malloc(Length + HCI_CMD_HEADER_LEN);
+ if (hci_ps_cmd == NULL)
+ return -1;
+
+ memset(hci_ps_cmd, 0, Length + HCI_CMD_HEADER_LEN);
+ load_hci_header(hci_ps_cmd, opcode, Length, i);
+ hci_ps_cmd[7] = 0x00;
+ hci_ps_cmd[Length + HCI_CMD_HEADER_LEN - 2] = (Param1 & 0xFF);
+ hci_ps_cmd[Length + HCI_CMD_HEADER_LEN - 1] =
+ ((Param1 >> 8) & 0xFF);
+ ps_patch_packet[*index].Hcipacket = hci_ps_cmd;
+ ps_patch_packet[*index].packetLen
+ = Length + HCI_CMD_HEADER_LEN;
+ (*index)++;
+ break;
+ case PS_WRITE:
+ for (i = 0; i < Param1; i++) {
+ hci_ps_cmd =
+ (uint8_t *) malloc(ps_tag_entry[i].tag_len +
+ HCI_CMD_HEADER_LEN);
+ if (hci_ps_cmd == NULL)
+ return -1;
+ memset(hci_ps_cmd, 0,
+ ps_tag_entry[i].tag_len + HCI_CMD_HEADER_LEN);
+ load_hci_header(hci_ps_cmd, opcode,
+ ps_tag_entry[i].tag_len,
+ ps_tag_entry[i].tag_id);
+ for (j = 0; j < ps_tag_entry[i].tag_len; j++)
+ hci_ps_cmd[HCI_CMD_HEADER_LEN + j] =
+ ps_tag_entry[i].tag_data[j];
+
+ ps_patch_packet[*index].Hcipacket = hci_ps_cmd;
+ ps_patch_packet[*index].packetLen =
+ ps_tag_entry[i].tag_len + HCI_CMD_HEADER_LEN;
+ (*index)++;
+ }
+ break;
+ case PS_VERIFY_CRC:
+ Length = 0x0;
+ hci_ps_cmd = (uint8_t *) malloc(Length + HCI_CMD_HEADER_LEN);
+ if (hci_ps_cmd == NULL)
+ return -1;
+ memset(hci_ps_cmd, 0, Length + HCI_CMD_HEADER_LEN);
+ load_hci_header(hci_ps_cmd, opcode, Length, Param1);
+ ps_patch_packet[*index].Hcipacket = hci_ps_cmd;
+ ps_patch_packet[*index].packetLen
+ = Length + HCI_CMD_HEADER_LEN;
+ (*index)++;
+ break;
+ default:
+ break;
+ }
+ return 0;
+}
+
+unsigned int get_input_data_format(char *line,
+ struct ps_data_format *pst_format)
+{
+ if (line[0] != '[') {
+ pst_format->data_type = hex_type;
+ pst_format->is_array = TRUE;
+ return 0;
+ }
+ switch (line[1]) {
+ case 'H':
+ case 'h':
+ if (line[2] == ':') {
+ if ((line[3] == 'a') || (line[3] == 'A')) {
+ if (line[4] == ']') {
+ pst_format->data_type = hex_type;
+ pst_format->is_array = TRUE;
+ line += 5;
+ return 0;
+ } else
+ return 1;
+ }
+ if ((line[3] == 'S') || (line[3] == 's')) {
+ if (line[4] == ']') {
+ pst_format->data_type = hex_type;
+ pst_format->is_array = FALSE;
+ line += 5;
+ return 0;
+ } else
+ return 1;
+ }
+
+ else if (line[3] == ']') {
+ pst_format->data_type = hex_type;
+ pst_format->is_array = TRUE;
+ line += 4;
+ return 0;
+ } else
+ return 1;
+ }
+
+ else if (line[2] == ']') {
+ pst_format->data_type = hex_type;
+ pst_format->is_array = TRUE;
+ line += 3;
+ return 0;
+ }
+
+ else
+ return 1;
+ break;
+ case 'A':
+ case 'a':
+ if (line[2] == ':') {
+ if ((line[3] == 'h') || (line[3] == 'H')) {
+ if (line[4] == ']') {
+ pst_format->data_type = hex_type;
+ pst_format->is_array = TRUE;
+ line += 5;
+ return 0;
+ }
+
+ else
+ return 1;
+ }
+
+ else if (line[3] == ']') {
+ pst_format->data_type = hex_type;
+ pst_format->is_array = TRUE;
+ line += 4;
+ return 0;
+ }
+
+ else
+ return 1;
+ }
+
+ else if (line[2] == ']') {
+ pst_format->data_type = hex_type;
+ pst_format->is_array = TRUE;
+ line += 3;
+ return 0;
+ }
+
+ else
+ return 1;
+ break;
+ case 'S':
+ case 's':
+ if (line[2] == ':') {
+ if ((line[3] == 'h') || (line[3] == 'H')) {
+ if (line[4] == ']') {
+ pst_format->data_type = hex_type;
+ pst_format->is_array = TRUE;
+ line += 5;
+ return 0;
+ } else
+ return 1;
+ }
+
+ else if (line[3] == ']') {
+ pst_format->data_type = hex_type;
+ pst_format->is_array = TRUE;
+ line += 4;
+ return 0;
+ }
+
+ else
+ return 1;
+ }
+
+ else if (line[2] == ']') {
+ pst_format->data_type = hex_type;
+ pst_format->is_array = TRUE;
+ line += 3;
+ return 0;
+ } else
+ return 1;
+ break;
+ default:
+ return 1;
+ }
+}
+
+unsigned int read_data_in_section(char *line,
+ struct ps_data_format format_info)
+{
+ char *token_ptr = line;
+ if (token_ptr[0] == '[') {
+ while (token_ptr[0] != ']' && token_ptr[0] != '\0')
+ token_ptr++;
+
+ if (token_ptr[0] == '\0')
+ return 0x0FFF;
+ token_ptr++;
+ }
+ if (format_info.data_type == hex_type) {
+ if (format_info.is_array == TRUE)
+ return 0x0FFF;
+ else
+ return strtol(token_ptr, NULL, 16);
+ } else
+ return 0x0FFF;
+}
+
+int ath_parse_file(FILE *stream)
+{
+ char *buffer;
+ char *line;
+ uint8_t tag_cnt;
+ int16_t byte_count;
+ uint32_t pos;
+ int read_count;
+ struct ps_data_format stps_data_format;
+ int line_read = 0;
+ struct st_read_status read_status = {
+ 0, 0, 0, 0
+ };
+
+ pos = 0;
+ buffer = NULL;
+ if (stream == NULL) {
+ perror("Could not open config file .\n");
+ return -1;
+ }
+ tag_cnt = 0;
+ byte_count = 0;
+ buffer = malloc(LINE_SIZE_MAX + 1);
+ if (NULL == buffer)
+ return -1;
+
+ while ((line = fgets(buffer, LINE_SIZE_MAX, stream)) != NULL) {
+ skip_space(line);
+
+ if ((line[0] == '/') && (line[1] == '/'))
+ continue;
+
+ if ((line[0] == '#')) {
+ if (read_status.section != 0) {
+ perror("error\n");
+ if (buffer != NULL)
+ free(buffer);
+ return -1;
+ } else {
+ read_status.section = 1;
+ continue;
+ }
+ }
+ if ((line[0] == '/') && (line[1] == '*')) {
+ line += 2;
+ skip_space(line);
+ line_read = 0;
+ read_status.section = 0;
+ continue;
+ }
+ if (read_status.section == 1) {
+ skip_space(line);
+ if (get_input_data_format(line, &stps_data_format)) {
+ if (buffer != NULL)
+ free(buffer);
+ return -1;
+ }
+ ps_tag_entry[tag_cnt].tag_id =
+ read_data_in_section(line, stps_data_format);
+ read_status.section = 2;
+ }
+
+ else if (read_status.section == 2) {
+ if (get_input_data_format(line, &stps_data_format)) {
+ if (buffer != NULL)
+ free(buffer);
+ return -1;
+ }
+ byte_count =
+ read_data_in_section(line, stps_data_format);
+
+ if (byte_count > LINE_SIZE_MAX / 2) {
+ if (buffer != NULL)
+ free(buffer);
+
+ return -1;
+ }
+ ps_tag_entry[tag_cnt].tag_len = byte_count;
+ ps_tag_entry[tag_cnt].tag_data = (uint8_t *)
+ malloc(byte_count);
+ read_status.section = 3;
+ read_status.line_count = 0;
+ }
+
+ else if (read_status.section == 3) {
+ if (read_status.line_count == 0) {
+ if (get_input_data_format(line,
+ &stps_data_format)) {
+ if (buffer != NULL)
+ free(buffer);
+ return -1;
+ }
+ }
+ skip_space(line);
+ read_status.char_cnt = 0;
+ if (line[read_status.char_cnt]
+ == '[') {
+ while (line[read_status.char_cnt]
+ != ']' && line[read_status.char_cnt]
+ != '\0')
+ read_status.char_cnt++;
+ if (line[read_status.char_cnt]
+ == ']') {
+ read_status.char_cnt++;
+ } else {
+ read_status.char_cnt = 0;
+ }
+ }
+ read_count = (byte_count > BYTES_OF_PS_DATA_PER_LINE)
+ ? BYTES_OF_PS_DATA_PER_LINE : byte_count;
+
+ if ((stps_data_format.data_type == hex_type)
+ && stps_data_format.is_array == TRUE) {
+ while (read_count > 0) {
+ ps_tag_entry[tag_cnt].tag_data
+ [read_status.byte_count]
+ = (uint8_t)(tohexval
+ (line[read_status.char_cnt])
+ << 4)
+ | (uint8_t)(tohexval
+ (line[read_status.char_cnt + 1]));
+ ps_tag_entry[tag_cnt].tag_data
+ [read_status.byte_count
+ + 1] = (uint8_t)(tohexval
+ (line[read_status.char_cnt + 3])
+ << 4)
+
+ | (uint8_t)(tohexval
+ (line[read_status.char_cnt + 4]));
+ read_status.char_cnt += 6;
+ read_status.byte_count += 2;
+ read_count -= 2;
+ }
+
+ if (byte_count > BYTES_OF_PS_DATA_PER_LINE)
+ byte_count
+ -= BYTES_OF_PS_DATA_PER_LINE;
+ else
+ byte_count = 0;
+ }
+
+ read_status.line_count++;
+ if (byte_count == 0) {
+ read_status.section = 0;
+ read_status.char_cnt = 0;
+ read_status.line_count = 0;
+ read_status.byte_count = 0;
+ }
+
+ else
+ read_status.char_cnt = 0;
+ if ((read_status.section == 0)
+ && (++tag_cnt == RAMPS_MAX_PS_TAGS_PER_FILE)) {
+ if (buffer != NULL)
+ free(buffer);
+
+ return -1;
+ }
+ }
+ line_read++;
+ }
+ tag_count = tag_cnt;
+ if (tag_cnt > RAMPS_MAX_PS_TAGS_PER_FILE) {
+ if (buffer != NULL)
+ free(buffer);
+ return -1;
+ }
+ if (buffer != NULL)
+ free(buffer);
+
+ return 0;
+}
+
+int parse_patch_file(FILE *stream)
+{
+ char byte[3];
+ char line[MAX_BYTE_LENGTH + 1];
+ int byte_cnt, byte_cnt_org;
+ int count;
+ int i, j, k;
+ int data;
+ uint32_t filepos;
+
+ byte[2] = '\0';
+ j = 0;
+ filepos = 0;
+ while (NULL != fgets(line, MAX_BYTE_LENGTH, stream)) {
+ if (strlen(line) <= 1 || !isxdigit(line[0]))
+ continue;
+ else
+ break;
+ }
+ byte_cnt = strtol(line, NULL, 16);
+ byte_cnt_org = byte_cnt;
+ while (byte_cnt > MAX_BYTE_LENGTH) {
+
+ /* Handle case when the number of patch buffer is
+ * more than the 20K */
+ if (MAX_NUM_PATCH_ENTRY == patch_count) {
+ for (i = 0; i < patch_count; i++)
+ free(ram_patch[i].Data);
+ return -1;
+ }
+ ram_patch[patch_count].Len = MAX_BYTE_LENGTH;
+ ram_patch[patch_count].Data =
+ (uint8_t *) malloc(MAX_BYTE_LENGTH);
+ patch_count++;
+ byte_cnt = byte_cnt - MAX_BYTE_LENGTH;
+ }
+ ram_patch[patch_count].Len = (byte_cnt & 0xFF);
+ if (byte_cnt != 0) {
+ ram_patch[patch_count].Data = (uint8_t *) malloc(byte_cnt);
+ patch_count++;
+ }
+ count = 0;
+ while (byte_cnt_org > MAX_BYTE_LENGTH) {
+ for (i = 0, k = 0; i < MAX_BYTE_LENGTH * 2;
+ i += 2, k++, count += 2) {
+ if (fgets(byte, 2, stream) == NULL)
+ return -1;
+ data = strtoul(&byte[0], NULL, 16);
+ ram_patch[j].Data[k] = (data & 0xFF);
+ }
+ j++;
+ byte_cnt_org = byte_cnt_org - MAX_BYTE_LENGTH;
+ }
+ if (j == 0)
+ j++;
+ for (k = 0; k < byte_cnt_org; i += 2, k++, count += 2) {
+ if (fgets(byte, 2, stream) == NULL)
+ return -1;
+ data = strtoul(byte, NULL, 16);
+ ram_patch[j].Data[k] = (data & 0xFF);
+ }
+ return 0;
+}
+
+int ath_parse_ps(FILE *stream)
+{
+ int status;
+ int i;
+ unsigned char bdaddr_Present = 0;
+ status = -1;
+
+ packet_config_default =
+ (struct brm_rxtx_pkt_sel_cfg *)&hci_rfcomm_up_cmd[6];
+ packet_config_conserv =
+ (struct brm_rxtx_pkt_sel_cfg *)&hci_rfcomm_down_cmd[6];
+
+ if (NULL != stream)
+ status = ath_parse_file(stream);
+
+ if (tag_count == 0)
+ total_tag_len = 10;
+ else {
+ for (i = 0; i < tag_count; i++) {
+ if (ps_tag_entry[i].tag_id == 1)
+ bdaddr_Present = 1;
+ if (ps_tag_entry[i].tag_len % 2 == 1)
+ total_tag_len = total_tag_len
+ + ps_tag_entry[i].tag_len + 1;
+ else
+ total_tag_len =
+ total_tag_len + ps_tag_entry[i].tag_len;
+ parse_rx_tx_pkt_config(ps_tag_entry[i]);
+ }
+ }
+ if (tag_count > 0 && !bdaddr_Present)
+ total_tag_len = total_tag_len + 10;
+ total_tag_len = total_tag_len + 10 + (tag_count * 4);
+ return status;
+}
+
+int ath_create_cmd_list(struct ps_cmd_packet **hci_packet_list,
+ uint32_t *num_packets)
+{
+ uint8_t count;
+ uint32_t num_cmd_entry = 0;
+ uint32_t crc = 0;
+
+ *num_packets = 0;
+ if (patch_count > 0)
+ crc |= RAM_PATCH_REGION;
+ if (tag_count > 0)
+ crc |= RAM_PS_REGION;
+ if (patch_count || tag_count) {
+ /* CRC Packet + PS Reset Packet + Patch List + PS List */
+ num_cmd_entry += (2 + patch_count + tag_count);
+ if (patch_count > 0)
+ num_cmd_entry++; /* Patch Enable Command */
+
+ (*hci_packet_list) =
+ malloc(sizeof(struct ps_cmd_packet) * num_cmd_entry);
+ if (NULL == *hci_packet_list)
+ perror("memory allocation failed \r\n");
+
+ ath_create_ps_command(PS_VERIFY_CRC, crc, *hci_packet_list,
+ num_packets);
+ if (patch_count > 0) {
+ ath_create_ps_command(WRITE_PATCH, patch_count,
+ *hci_packet_list, num_packets);
+ ath_create_ps_command(ENABLE_PATCH, 0,
+ *hci_packet_list,
+ num_packets);
+ }
+ ath_create_ps_command(PS_RESET, total_tag_len,
+ *hci_packet_list, num_packets);
+ if (tag_count > 0)
+ ath_create_ps_command(PS_WRITE, tag_count,
+ *hci_packet_list, num_packets);
+ }
+ for (count = 0; count < patch_count; count++)
+ free(ram_patch[patch_count].Data);
+ for (count = 0; count < tag_count; count++)
+ free(ps_tag_entry[count].tag_data);
+
+ return *num_packets;
+}
+
+int ath_free_command_list(struct ps_cmd_packet **hci_packet_list,
+ uint32_t num_packets)
+{
+ int i;
+ if (*hci_packet_list == NULL)
+ return -1;
+ for (i = 0; i < num_packets; i++)
+ free((*hci_packet_list)[i].Hcipacket);
+ free(*hci_packet_list);
+ return 0;
+}
diff --git a/tools/ar3kpsparser.h b/tools/ar3kpsparser.h
new file mode 100755
index 0000000..351ae18
--- /dev/null
+++ b/tools/ar3kpsparser.h
@@ -0,0 +1,127 @@
+/*
+ * 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
+ *
+ */
+
+#ifndef __AR3KPSPARSER_H
+#define __AR3KPSPARSER_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <termios.h>
+#include <time.h>
+#include <sys/time.h>
+#include <sys/types.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"
+
+/* Helper data type declaration */
+
+#define FALSE 0
+#define TRUE 1
+
+/* The maximum number of bytes possible in a patch entry */
+#define MAX_PATCH_SIZE 20000
+
+/* Maximum HCI packets that will be formed from the Patch file */
+#define MAX_NUM_PATCH_ENTRY ((MAX_PATCH_SIZE/MAX_BYTE_LENGTH) + 1)
+
+/* This block is reserved for Bluetooth system's
+ * common componet, for example, PCM, LMP etc.
+ */
+#define PSTAG_SYSTEM_BLOCK_START (uint16_t)(1)
+
+#define PSTAG_EdrPerUpThresholds (uint16_t)(PSTAG_SYSTEM_BLOCK_START+38)
+#define PSTAG_EdrPerDownThresholds (uint16_t)(PSTAG_SYSTEM_BLOCK_START+39)
+#define PSTAG_RSSIMinDelta (uint16_t)(PSTAG_SYSTEM_BLOCK_START+40)
+#define PSTAG_PERMinDelta (uint16_t)(PSTAG_SYSTEM_BLOCK_START+41)
+#define PSTAG_MaxLongTermError (uint16_t)(PSTAG_SYSTEM_BLOCK_START+42)
+#define PSTAG_LongTermPERThreshold (uint16_t)(PSTAG_SYSTEM_BLOCK_START+43)
+#define PSTAG_ForceUpRateThreshold (uint16_t)(PSTAG_SYSTEM_BLOCK_START+44)
+
+#define PSTAG_EdrPerUpThresholds_Consv (uint16_t)\
+ (PSTAG_SYSTEM_BLOCK_START+45)
+#define PSTAG_EdrPerDownThresholds_Consv (uint16_t)\
+ (PSTAG_SYSTEM_BLOCK_START+46)
+#define PSTAG_RSSIMinDelta_Consv (uint16_t)\
+ (PSTAG_SYSTEM_BLOCK_START+47)
+#define PSTAG_PERMinDelta_Consv (uint16_t)\
+ (PSTAG_SYSTEM_BLOCK_START+48)
+#define PSTAG_MaxLongTermError_Consv (uint16_t)\
+ (PSTAG_SYSTEM_BLOCK_START+49)
+#define PSTAG_LongTermPERThreshold_Consv (uint16_t)\
+ (PSTAG_SYSTEM_BLOCK_START+50)
+#define PSTAG_ForceUpRateThreshold_Consv (uint16_t)\
+ (PSTAG_SYSTEM_BLOCK_START+51)
+
+#define PKT_SEL_BUFFER_SIZE 8
+
+#define PSTAG_RF_TEST_BLOCK_END (uint16_t)(349)
+
+#define FPGA_REGISTER 0x4FFC
+
+#define PS_ASIC_FILE "PS_ASIC.pst"
+#define PS_FPGA_FILE "PS_FPGA.pst"
+
+#define PATCH_FILE "RamPatch.txt"
+#define BDADDR_FILE "ar3kbdaddr.pst"
+
+struct ps_cmd_packet {
+ uint8_t *Hcipacket;
+ int packetLen;
+};
+
+/* Parses a Patch information buffer and store it in global structure */
+int parse_patch_file(FILE *);
+
+/* parses a PS information buffer and stores it in a global structure */
+int ath_parse_ps(FILE *);
+
+/*
+ * Uses the output of Both ath_parse_ps and AthDoParsePatch
+ * APIs to form HCI command array with
+ * all the PS and patch commands.
+ * The list will have the below mentioned commands in order.
+ * CRC command packet
+ * Download patch command(s)
+ * Enable patch Command
+ * PS Reset Command
+ * PS Tag Command(s)
+ *
+ */
+int ath_create_cmd_list(struct ps_cmd_packet **, uint32_t *);
+
+/* Cleanup the dynamically allicated HCI command list */
+int ath_free_command_list(struct ps_cmd_packet **HciPacketList,
+ uint32_t numPackets);
+
+#endif /* __AR3KPSPARSER_H */
diff --git a/tools/hciattach.8 b/tools/hciattach.8
index f750222..74ad0d0 100644
--- a/tools/hciattach.8
+++ b/tools/hciattach.8
@@ -49,6 +49,12 @@ specific identifier. Currently supported types are
.B any
Unspecified HCI_UART interface, no vendor specific options
.TP
+.B ar3001
+Atheros AR3001 based modules
+.TP
+.B ar3001pm
+Atheros AR3001 based modules with advanced power save feature enabled
+.TP
.B ericsson
Ericsson based modules
.TP
diff --git a/tools/hciattach.c b/tools/hciattach.c
index 364c5ff..82f0e69 100644
--- a/tools/hciattach.c
+++ b/tools/hciattach.c
@@ -146,7 +146,7 @@ int set_speed(int fd, struct termios *ti, int speed)
return tcsetattr(fd, TCSANOW, ti);
}

-/*
+/*
* Read an HCI event from the given file descriptor.
*/
int read_hci_event(int fd, unsigned char* buf, int size)
@@ -653,7 +653,153 @@ static int csr(int fd, struct uart_t *u, struct termios *ti)
}

/*
- * Silicon Wave specific initialization
+ * Atheros AR3001 specific initialization code with power management disabled.
+ * Suraj Sumangala <[email protected]>
+ */
+static int ar3001post(int fd, struct uart_t *u, struct termios *ti)
+{
+ 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 -1;
+ }
+
+
+ dd = hci_open_dev(dev_id);
+ if (dd < 0) {
+ perror("HCI device open failed");
+ return -1;
+ }
+ sleep(1);
+ /* send command with Sleep feature disabled */
+ ar3001_post(dd);
+
+ nanosleep(&tm, NULL);
+ hci_close_dev(dd);
+
+ return 0;
+
+}
+/*
+ * Atheros AR3001 specific initialization post callback
+ * with power management enabled
+ * Suraj Sumangala <[email protected]>
+ */
+static int ar3001pmpost(int fd, struct uart_t *u, struct termios *ti)
+{
+ int dev_id, dd;
+ struct timespec tm = {0, 50000};
+
+ sleep(1);
+
+ dev_id = ioctl(fd, HCIUARTGETDEVICE, 0);
+ if (dev_id < 0) {
+ perror("cannot get device id");
+ return -1;
+ }
+
+
+ dd = hci_open_dev(dev_id);
+ if (dd < 0) {
+ perror("HCI device open failed");
+ return -1;
+ }
+
+ /* send command with Sleep feature enabled */
+ ar3001pm_post(dd);
+ nanosleep(&tm, NULL);
+ hci_close_dev(dd);
+
+ return 0;
+}
+/*
+ * Atheros AR3001 specific initialization
+ * Suraj Sumangala <[email protected]>
+ */
+static int ar3001(int fd, struct uart_t *u, struct termios *ti)
+{
+ struct timespec tm = { 0, 500000 };
+ unsigned char cmd[14], rsp[100];
+ int r;
+ int baud;
+
+ /* Download PS and patch */
+ r = ath_ps_download(fd);
+ if (r < 0) {
+ perror("Failed to Download configuration");
+ return -1;
+ }
+ /* Write BDADDR if user has provided any */
+ if (u->bdaddr != NULL) {
+ /* Set BD_ADDR */
+ memset(cmd, 0, sizeof(cmd));
+ memset(rsp, 0, sizeof(rsp));
+ cmd[0] = HCI_COMMAND_PKT;
+ cmd[1] = 0x0B;
+ cmd[2] = 0xfc;
+ cmd[3] = 0x0A;
+ cmd[4] = 0x01;
+ cmd[5] = 0x01;
+ cmd[6] = 0x00;
+ cmd[7] = 0x06;
+ str2ba(u->bdaddr, (bdaddr_t *) (cmd + 8));
+
+ /* Send command */
+ if (write(fd, cmd, 14) != 14) {
+ fprintf(stderr, "Failed to write BD_ADDR command\n");
+ return -1;
+ }
+
+ /* Read reply */
+ if (read_hci_event(fd, rsp, 10) < 0) {
+ fprintf(stderr, "Failed to set BD_ADDR\n");
+ return -1;
+ }
+ }
+
+ /* Send HCI Reset to write the configuration */
+ cmd[0] = HCI_COMMAND_PKT;
+ cmd[1] = 0x03;
+ cmd[2] = 0x0c;
+ cmd[3] = 0x00;
+ /* Send reset command */
+ r = write(fd, cmd, 4);
+
+ if (r != 4)
+ return -1;
+
+ nanosleep(&tm, NULL);
+ if (read_hci_event(fd, rsp, sizeof(rsp)) < 0)
+ return -1;
+
+ /* Set baud rate command,
+ * set controller baud rate to user specified value */
+ cmd[0] = HCI_COMMAND_PKT;
+ cmd[1] = 0x0C;
+ cmd[2] = 0xfc;
+ cmd[3] = 0x02;
+ baud = u->speed/100;
+ cmd[4] = (char)baud;
+ cmd[5] = (char)(baud >> 8);
+
+ if (write(fd, cmd, 6) != 6) {
+ perror("Failed to write init command");
+ return -1;
+ }
+
+ /* Wait for the command complete event for Baud rate change Command */
+ nanosleep(&tm, NULL);
+ if (read_hci_event(fd, rsp, sizeof(rsp)) < 0)
+ return -1;
+
+ return 0;
+}
+/*
+ * Silicon Wave specific initialization
* Thomas Moser <[email protected]>
*/
static int swave(int fd, struct uart_t *u, struct termios *ti)
@@ -1071,6 +1217,14 @@ struct uart_t uart[] = {
/* Broadcom BCM2035 */
{ "bcm2035", 0x0A5C, 0x2035, HCI_UART_H4, 115200, 460800, FLOW_CTL, NULL, bcm2035 },

+ /* ATHEROS AR3001 */
+ { "ar3001", 0x0000, 0x0000, HCI_UART_ATH,
+ 115200, 115200, FLOW_CTL, NULL, ar3001, ar3001post },
+
+ { "ar3001pm", 0x0000, 0x0000, HCI_UART_ATH,
+ 115200, 115200, FLOW_CTL, NULL, ar3001, ar3001pmpost },
+
+
{ NULL, 0 }
};

diff --git a/tools/hciattach.h b/tools/hciattach.h
index 867563b..6f6469f 100644
--- a/tools/hciattach.h
+++ b/tools/hciattach.h
@@ -36,7 +36,7 @@
#define HCI_UART_3WIRE 2
#define HCI_UART_H4DS 3
#define HCI_UART_LL 4
-
+#define HCI_UART_ATH 5
int read_hci_event(int fd, unsigned char* buf, int size);
int set_speed(int fd, struct termios *ti, int speed);

@@ -45,3 +45,6 @@ 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_ps_download(int fd);
+int ar3001_post(int fd);
+int ar3001pm_post(int fd);
--
1.6.3.3